diff options
Diffstat (limited to 'lib')
-rw-r--r-- | lib/Kconfig | 24 | ||||
-rw-r--r-- | lib/Makefile | 1 | ||||
-rw-r--r-- | lib/aes/aes-encrypt.c | 3 | ||||
-rw-r--r-- | lib/blake2/blake2-impl.h | 163 | ||||
-rw-r--r-- | lib/blake2/blake2b.c | 311 | ||||
-rw-r--r-- | lib/ecdsa/ecdsa-libcrypto.c | 2 | ||||
-rw-r--r-- | lib/efi/efi.c | 101 | ||||
-rw-r--r-- | lib/efi/efi_app.c | 261 | ||||
-rw-r--r-- | lib/efi/efi_stub.c | 102 | ||||
-rw-r--r-- | lib/efi_driver/efi_block_device.c | 8 | ||||
-rw-r--r-- | lib/efi_driver/efi_uclass.c | 8 | ||||
-rw-r--r-- | lib/efi_loader/Kconfig | 2 | ||||
-rw-r--r-- | lib/efi_loader/efi_boottime.c | 9 | ||||
-rw-r--r-- | lib/efi_loader/efi_dt_fixup.c | 33 | ||||
-rw-r--r-- | lib/efi_loader/efi_firmware.c | 7 | ||||
-rw-r--r-- | lib/efi_loader/efi_image_loader.c | 13 | ||||
-rw-r--r-- | lib/efi_loader/efi_setup.c | 4 | ||||
-rw-r--r-- | lib/efi_loader/efi_tcg2.c | 626 | ||||
-rw-r--r-- | lib/efi_loader/efi_variable_tee.c | 16 | ||||
-rw-r--r-- | lib/fdtdec.c | 141 | ||||
-rw-r--r-- | lib/image-sparse.c | 69 | ||||
-rw-r--r-- | lib/rsa/Kconfig | 10 | ||||
-rw-r--r-- | lib/rsa/rsa-sign.c | 4 | ||||
-rw-r--r-- | lib/time.c | 1 | ||||
-rw-r--r-- | lib/tpm-v2.c | 12 | ||||
-rw-r--r-- | lib/vsprintf.c | 9 |
26 files changed, 1672 insertions, 268 deletions
diff --git a/lib/Kconfig b/lib/Kconfig index 807a4c6ade0..38051ccdd36 100644 --- a/lib/Kconfig +++ b/lib/Kconfig @@ -15,6 +15,16 @@ config SYS_NUM_ADDR_MAP help Sets the number of entries in the virtual-physical mapping table. +config PHYSMEM + bool "Access to physical memory region (> 4G)" + help + Some basic support is provided for operations on memory not + normally accessible to 32-bit U-Boot - e.g. some architectures + support access to more than 4G of memory on 32-bit + machines using physical address extension or similar. + Enable this to access this basic support, which only supports clearing + the memory. + config BCH bool "Enable Software based BCH ECC" help @@ -42,7 +52,7 @@ config CC_OPTIMIZE_LIBS_FOR_SPEED config CHARSET bool - default y if UT_UNICODE || EFI_LOADER || UFS + default y if UT_UNICODE || EFI_LOADER || UFS || EFI_APP help Enables support for various conversions between different character sets, such as between unicode representations and @@ -357,6 +367,14 @@ endmenu menu "Hashing Support" +config BLAKE2 + bool "Enable BLAKE2 support" + help + This option enables support of hashing using BLAKE2B algorithm. + The hash is calculated in software. + The BLAKE2 algorithm produces a hash value (digest) between 1 and + 64 bytes. + config SHA1 bool "Enable SHA1 support" help @@ -827,11 +845,11 @@ config LMB_RESERVED_REGIONS Define the number of supported reserved regions in the library logical memory blocks. -endmenu - config PHANDLE_CHECK_SEQ bool "Enable phandle check while getting sequence number" help When there are multiple device tree nodes with same name, enable this config option to distinguish them using phandles in fdtdec_get_alias_seq() function. + +endmenu diff --git a/lib/Makefile b/lib/Makefile index 5ddbc77ed6d..7950e847a9e 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -63,6 +63,7 @@ obj-$(CONFIG_$(SPL_)MD5) += md5.o obj-$(CONFIG_ECDSA) += ecdsa/ obj-$(CONFIG_$(SPL_)RSA) += rsa/ obj-$(CONFIG_HASH) += hash-checksum.o +obj-$(CONFIG_BLAKE2) += blake2/blake2b.o obj-$(CONFIG_SHA1) += sha1.o obj-$(CONFIG_SHA256) += sha256.o obj-$(CONFIG_SHA512) += sha512.o diff --git a/lib/aes/aes-encrypt.c b/lib/aes/aes-encrypt.c index a6d1720f303..e74e35eaa28 100644 --- a/lib/aes/aes-encrypt.c +++ b/lib/aes/aes-encrypt.c @@ -2,6 +2,9 @@ /* * Copyright (c) 2019,Softathome */ + +#define OPENSSL_API_COMPAT 0x10101000L + #include "mkimage.h" #include <stdio.h> #include <string.h> diff --git a/lib/blake2/blake2-impl.h b/lib/blake2/blake2-impl.h new file mode 100644 index 00000000000..7ee52fdf5ad --- /dev/null +++ b/lib/blake2/blake2-impl.h @@ -0,0 +1,163 @@ +/* SPDX-License-Identifier: CC0-1.0 */ +/* + BLAKE2 reference source code package - reference C implementations + + Copyright 2012, Samuel Neves <sneves@dei.uc.pt>. You may use this under the + terms of the CC0, the OpenSSL Licence, or the Apache Public License 2.0, at + your option. The terms of these licenses can be found at: + + - CC0 1.0 Universal : http://creativecommons.org/publicdomain/zero/1.0 + - OpenSSL license : https://www.openssl.org/source/license.html + - Apache 2.0 : http://www.apache.org/licenses/LICENSE-2.0 + + More information about the BLAKE2 hash function can be found at + https://blake2.net. +*/ + +/* + * Cross-ported from BLAKE2 (https://github.com/BLAKE2/BLAKE2). + * Modifications includes: + * + * - Remove unsupported compilers like MSC/CPP + * - Use u-boot library functions/macros + */ +#ifndef BLAKE2_IMPL_H +#define BLAKE2_IMPL_H + +#include <stdint.h> +#include <string.h> + +#define BLAKE2_INLINE inline + +#ifdef __LITTLE_ENDIAN +# define NATIVE_LITTLE_ENDIAN +#endif + +static BLAKE2_INLINE uint32_t load32( const void *src ) +{ +#if defined(NATIVE_LITTLE_ENDIAN) + uint32_t w; + memcpy(&w, src, sizeof w); + return w; +#else + const uint8_t *p = ( const uint8_t * )src; + return (( uint32_t )( p[0] ) << 0) | + (( uint32_t )( p[1] ) << 8) | + (( uint32_t )( p[2] ) << 16) | + (( uint32_t )( p[3] ) << 24) ; +#endif +} + +static BLAKE2_INLINE uint64_t load64( const void *src ) +{ +#if defined(NATIVE_LITTLE_ENDIAN) + uint64_t w; + memcpy(&w, src, sizeof w); + return w; +#else + const uint8_t *p = ( const uint8_t * )src; + return (( uint64_t )( p[0] ) << 0) | + (( uint64_t )( p[1] ) << 8) | + (( uint64_t )( p[2] ) << 16) | + (( uint64_t )( p[3] ) << 24) | + (( uint64_t )( p[4] ) << 32) | + (( uint64_t )( p[5] ) << 40) | + (( uint64_t )( p[6] ) << 48) | + (( uint64_t )( p[7] ) << 56) ; +#endif +} + +static BLAKE2_INLINE uint16_t load16( const void *src ) +{ +#if defined(NATIVE_LITTLE_ENDIAN) + uint16_t w; + memcpy(&w, src, sizeof w); + return w; +#else + const uint8_t *p = ( const uint8_t * )src; + return ( uint16_t )((( uint32_t )( p[0] ) << 0) | + (( uint32_t )( p[1] ) << 8)); +#endif +} + +static BLAKE2_INLINE void store16( void *dst, uint16_t w ) +{ +#if defined(NATIVE_LITTLE_ENDIAN) + memcpy(dst, &w, sizeof w); +#else + uint8_t *p = ( uint8_t * )dst; + *p++ = ( uint8_t )w; w >>= 8; + *p++ = ( uint8_t )w; +#endif +} + +static BLAKE2_INLINE void store32( void *dst, uint32_t w ) +{ +#if defined(NATIVE_LITTLE_ENDIAN) + memcpy(dst, &w, sizeof w); +#else + uint8_t *p = ( uint8_t * )dst; + p[0] = (uint8_t)(w >> 0); + p[1] = (uint8_t)(w >> 8); + p[2] = (uint8_t)(w >> 16); + p[3] = (uint8_t)(w >> 24); +#endif +} + +static BLAKE2_INLINE void store64( void *dst, uint64_t w ) +{ +#if defined(NATIVE_LITTLE_ENDIAN) + memcpy(dst, &w, sizeof w); +#else + uint8_t *p = ( uint8_t * )dst; + p[0] = (uint8_t)(w >> 0); + p[1] = (uint8_t)(w >> 8); + p[2] = (uint8_t)(w >> 16); + p[3] = (uint8_t)(w >> 24); + p[4] = (uint8_t)(w >> 32); + p[5] = (uint8_t)(w >> 40); + p[6] = (uint8_t)(w >> 48); + p[7] = (uint8_t)(w >> 56); +#endif +} + +static BLAKE2_INLINE uint64_t load48( const void *src ) +{ + const uint8_t *p = ( const uint8_t * )src; + return (( uint64_t )( p[0] ) << 0) | + (( uint64_t )( p[1] ) << 8) | + (( uint64_t )( p[2] ) << 16) | + (( uint64_t )( p[3] ) << 24) | + (( uint64_t )( p[4] ) << 32) | + (( uint64_t )( p[5] ) << 40) ; +} + +static BLAKE2_INLINE void store48( void *dst, uint64_t w ) +{ + uint8_t *p = ( uint8_t * )dst; + p[0] = (uint8_t)(w >> 0); + p[1] = (uint8_t)(w >> 8); + p[2] = (uint8_t)(w >> 16); + p[3] = (uint8_t)(w >> 24); + p[4] = (uint8_t)(w >> 32); + p[5] = (uint8_t)(w >> 40); +} + +static BLAKE2_INLINE uint32_t rotr32( const uint32_t w, const unsigned c ) +{ + return ( w >> c ) | ( w << ( 32 - c ) ); +} + +static BLAKE2_INLINE uint64_t rotr64( const uint64_t w, const unsigned c ) +{ + return ( w >> c ) | ( w << ( 64 - c ) ); +} + +/* prevents compiler optimizing out memset() */ +static BLAKE2_INLINE void secure_zero_memory(void *v, size_t n) +{ + static void *(*const volatile memset_v)(void *, int, size_t) = &memset; + memset_v(v, 0, n); +} + +#endif diff --git a/lib/blake2/blake2b.c b/lib/blake2/blake2b.c new file mode 100644 index 00000000000..686138ef24b --- /dev/null +++ b/lib/blake2/blake2b.c @@ -0,0 +1,311 @@ +/* SPDX-License-Identifier: CC0-1.0 */ +/* + BLAKE2 reference source code package - reference C implementations + + Copyright 2012, Samuel Neves <sneves@dei.uc.pt>. You may use this under the + terms of the CC0, the OpenSSL Licence, or the Apache Public License 2.0, at + your option. The terms of these licenses can be found at: + + - CC0 1.0 Universal : http://creativecommons.org/publicdomain/zero/1.0 + - OpenSSL license : https://www.openssl.org/source/license.html + - Apache 2.0 : http://www.apache.org/licenses/LICENSE-2.0 + + More information about the BLAKE2 hash function can be found at + https://blake2.net. +*/ + +/* + * Cross-ported from BLAKE2 (https://github.com/BLAKE2/BLAKE2). + * Modifications includes: + * + * - Remove unused features like selftest + * - Use u-boot library functions/macros + */ +#include <stdint.h> +#include <string.h> +#include <stdio.h> +#include <u-boot/blake2.h> +#include "blake2-impl.h" + +static const uint64_t blake2b_IV[8] = +{ + 0x6a09e667f3bcc908ULL, 0xbb67ae8584caa73bULL, + 0x3c6ef372fe94f82bULL, 0xa54ff53a5f1d36f1ULL, + 0x510e527fade682d1ULL, 0x9b05688c2b3e6c1fULL, + 0x1f83d9abfb41bd6bULL, 0x5be0cd19137e2179ULL +}; + +static const uint8_t blake2b_sigma[12][16] = +{ + { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 } , + { 14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3 } , + { 11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4 } , + { 7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8 } , + { 9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13 } , + { 2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9 } , + { 12, 5, 1, 15, 14, 13, 4, 10, 0, 7, 6, 3, 9, 2, 8, 11 } , + { 13, 11, 7, 14, 12, 1, 3, 9, 5, 0, 15, 4, 8, 6, 2, 10 } , + { 6, 15, 14, 9, 11, 3, 0, 8, 12, 2, 13, 7, 1, 4, 10, 5 } , + { 10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13 , 0 } , + { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 } , + { 14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3 } +}; + + +static void blake2b_set_lastnode( blake2b_state *S ) +{ + S->f[1] = (uint64_t)-1; +} + +/* Some helper functions, not necessarily useful */ +static int blake2b_is_lastblock( const blake2b_state *S ) +{ + return S->f[0] != 0; +} + +static void blake2b_set_lastblock( blake2b_state *S ) +{ + if( S->last_node ) blake2b_set_lastnode( S ); + + S->f[0] = (uint64_t)-1; +} + +static void blake2b_increment_counter( blake2b_state *S, const uint64_t inc ) +{ + S->t[0] += inc; + S->t[1] += ( S->t[0] < inc ); +} + +static void blake2b_init0( blake2b_state *S ) +{ + size_t i; + memset( S, 0, sizeof( blake2b_state ) ); + + for( i = 0; i < 8; ++i ) S->h[i] = blake2b_IV[i]; +} + +/* init xors IV with input parameter block */ +int blake2b_init_param( blake2b_state *S, const blake2b_param *P ) +{ + const uint8_t *p = ( const uint8_t * )( P ); + size_t i; + + blake2b_init0( S ); + + /* IV XOR ParamBlock */ + for( i = 0; i < 8; ++i ) + S->h[i] ^= load64( p + sizeof( S->h[i] ) * i ); + + S->outlen = P->digest_length; + return 0; +} + + + +int blake2b_init( blake2b_state *S, size_t outlen ) +{ + blake2b_param P[1]; + + if ( ( !outlen ) || ( outlen > BLAKE2B_OUTBYTES ) ) return -1; + + P->digest_length = (uint8_t)outlen; + P->key_length = 0; + P->fanout = 1; + P->depth = 1; + store32( &P->leaf_length, 0 ); + store32( &P->node_offset, 0 ); + store32( &P->xof_length, 0 ); + P->node_depth = 0; + P->inner_length = 0; + memset( P->reserved, 0, sizeof( P->reserved ) ); + memset( P->salt, 0, sizeof( P->salt ) ); + memset( P->personal, 0, sizeof( P->personal ) ); + return blake2b_init_param( S, P ); +} + + +int blake2b_init_key( blake2b_state *S, size_t outlen, const void *key, size_t keylen ) +{ + blake2b_param P[1]; + + if ( ( !outlen ) || ( outlen > BLAKE2B_OUTBYTES ) ) return -1; + + if ( !key || !keylen || keylen > BLAKE2B_KEYBYTES ) return -1; + + P->digest_length = (uint8_t)outlen; + P->key_length = (uint8_t)keylen; + P->fanout = 1; + P->depth = 1; + store32( &P->leaf_length, 0 ); + store32( &P->node_offset, 0 ); + store32( &P->xof_length, 0 ); + P->node_depth = 0; + P->inner_length = 0; + memset( P->reserved, 0, sizeof( P->reserved ) ); + memset( P->salt, 0, sizeof( P->salt ) ); + memset( P->personal, 0, sizeof( P->personal ) ); + + if( blake2b_init_param( S, P ) < 0 ) return -1; + + { + uint8_t block[BLAKE2B_BLOCKBYTES]; + memset( block, 0, BLAKE2B_BLOCKBYTES ); + memcpy( block, key, keylen ); + blake2b_update( S, block, BLAKE2B_BLOCKBYTES ); + secure_zero_memory( block, BLAKE2B_BLOCKBYTES ); /* Burn the key from stack */ + } + return 0; +} + +#define G(r,i,a,b,c,d) \ + do { \ + a = a + b + m[blake2b_sigma[r][2*i+0]]; \ + d = rotr64(d ^ a, 32); \ + c = c + d; \ + b = rotr64(b ^ c, 24); \ + a = a + b + m[blake2b_sigma[r][2*i+1]]; \ + d = rotr64(d ^ a, 16); \ + c = c + d; \ + b = rotr64(b ^ c, 63); \ + } while(0) + +#define R(r) \ + do { \ + G(r,0,v[ 0],v[ 4],v[ 8],v[12]); \ + G(r,1,v[ 1],v[ 5],v[ 9],v[13]); \ + G(r,2,v[ 2],v[ 6],v[10],v[14]); \ + G(r,3,v[ 3],v[ 7],v[11],v[15]); \ + G(r,4,v[ 0],v[ 5],v[10],v[15]); \ + G(r,5,v[ 1],v[ 6],v[11],v[12]); \ + G(r,6,v[ 2],v[ 7],v[ 8],v[13]); \ + G(r,7,v[ 3],v[ 4],v[ 9],v[14]); \ + } while(0) + +static void blake2b_compress( blake2b_state *S, const uint8_t block[BLAKE2B_BLOCKBYTES] ) +{ + uint64_t m[16]; + uint64_t v[16]; + size_t i; + + for( i = 0; i < 16; ++i ) { + m[i] = load64( block + i * sizeof( m[i] ) ); + } + + for( i = 0; i < 8; ++i ) { + v[i] = S->h[i]; + } + + v[ 8] = blake2b_IV[0]; + v[ 9] = blake2b_IV[1]; + v[10] = blake2b_IV[2]; + v[11] = blake2b_IV[3]; + v[12] = blake2b_IV[4] ^ S->t[0]; + v[13] = blake2b_IV[5] ^ S->t[1]; + v[14] = blake2b_IV[6] ^ S->f[0]; + v[15] = blake2b_IV[7] ^ S->f[1]; + + R( 0 ); + R( 1 ); + R( 2 ); + R( 3 ); + R( 4 ); + R( 5 ); + R( 6 ); + R( 7 ); + R( 8 ); + R( 9 ); + R( 10 ); + R( 11 ); + + for( i = 0; i < 8; ++i ) { + S->h[i] = S->h[i] ^ v[i] ^ v[i + 8]; + } +} + +#undef G +#undef R + +int blake2b_update( blake2b_state *S, const void *pin, size_t inlen ) +{ + const unsigned char * in = (const unsigned char *)pin; + if( inlen > 0 ) + { + size_t left = S->buflen; + size_t fill = BLAKE2B_BLOCKBYTES - left; + if( inlen > fill ) + { + S->buflen = 0; + memcpy( S->buf + left, in, fill ); /* Fill buffer */ + blake2b_increment_counter( S, BLAKE2B_BLOCKBYTES ); + blake2b_compress( S, S->buf ); /* Compress */ + in += fill; inlen -= fill; + while(inlen > BLAKE2B_BLOCKBYTES) { + blake2b_increment_counter(S, BLAKE2B_BLOCKBYTES); + blake2b_compress( S, in ); + in += BLAKE2B_BLOCKBYTES; + inlen -= BLAKE2B_BLOCKBYTES; + } + } + memcpy( S->buf + S->buflen, in, inlen ); + S->buflen += inlen; + } + return 0; +} + +int blake2b_final( blake2b_state *S, void *out, size_t outlen ) +{ + uint8_t buffer[BLAKE2B_OUTBYTES] = {0}; + size_t i; + + if( out == NULL || outlen < S->outlen ) + return -1; + + if( blake2b_is_lastblock( S ) ) + return -1; + + blake2b_increment_counter( S, S->buflen ); + blake2b_set_lastblock( S ); + memset( S->buf + S->buflen, 0, BLAKE2B_BLOCKBYTES - S->buflen ); /* Padding */ + blake2b_compress( S, S->buf ); + + for( i = 0; i < 8; ++i ) /* Output full hash to temp buffer */ + store64( buffer + sizeof( S->h[i] ) * i, S->h[i] ); + + memcpy( out, buffer, S->outlen ); + secure_zero_memory(buffer, sizeof(buffer)); + return 0; +} + +/* inlen, at least, should be uint64_t. Others can be size_t. */ +int blake2b( void *out, size_t outlen, const void *in, size_t inlen, const void *key, size_t keylen ) +{ + blake2b_state S[1]; + + /* Verify parameters */ + if ( NULL == in && inlen > 0 ) return -1; + + if ( NULL == out ) return -1; + + if( NULL == key && keylen > 0 ) return -1; + + if( !outlen || outlen > BLAKE2B_OUTBYTES ) return -1; + + if( keylen > BLAKE2B_KEYBYTES ) return -1; + + if( keylen > 0 ) + { + if( blake2b_init_key( S, outlen, key, keylen ) < 0 ) return -1; + } + else + { + if( blake2b_init( S, outlen ) < 0 ) return -1; + } + + blake2b_update( S, ( const uint8_t * )in, inlen ); + blake2b_final( S, out, outlen ); + return 0; +} + +int blake2( void *out, size_t outlen, const void *in, size_t inlen, const void *key, size_t keylen ) { + return blake2b(out, outlen, in, inlen, key, keylen); +} diff --git a/lib/ecdsa/ecdsa-libcrypto.c b/lib/ecdsa/ecdsa-libcrypto.c index 1757a145623..ae6dfa0ba97 100644 --- a/lib/ecdsa/ecdsa-libcrypto.c +++ b/lib/ecdsa/ecdsa-libcrypto.c @@ -18,6 +18,8 @@ * Copyright (c) 2020,2021, Alexandru Gagniuc <mr.nuke.me@gmail.com> */ +#define OPENSSL_API_COMPAT 0x10101000L + #include <u-boot/ecdsa.h> #include <u-boot/fdt-libcrypto.h> #include <openssl/ssl.h> diff --git a/lib/efi/efi.c b/lib/efi/efi.c index 69e52e45748..aa42f1842f3 100644 --- a/lib/efi/efi.c +++ b/lib/efi/efi.c @@ -1,5 +1,7 @@ // SPDX-License-Identifier: GPL-2.0+ /* + * Functions shared by the app and stub + * * Copyright (c) 2015 Google, Inc * * EFI information obtained here: @@ -17,6 +19,33 @@ #include <efi.h> #include <efi_api.h> +static struct efi_priv *global_priv; + +struct efi_priv *efi_get_priv(void) +{ + return global_priv; +} + +void efi_set_priv(struct efi_priv *priv) +{ + global_priv = priv; +} + +struct efi_system_table *efi_get_sys_table(void) +{ + return global_priv->sys_table; +} + +struct efi_boot_services *efi_get_boot(void) +{ + return global_priv->boot; +} + +unsigned long efi_get_ram_base(void) +{ + return global_priv->ram_base; +} + /* * Global declaration of gd. * @@ -106,3 +135,75 @@ void efi_free(struct efi_priv *priv, void *ptr) boot->free_pool(ptr); } + +int efi_store_memory_map(struct efi_priv *priv) +{ + struct efi_boot_services *boot = priv->sys_table->boottime; + efi_uintn_t size, desc_size; + efi_status_t ret; + + /* Get the memory map so we can switch off EFI */ + size = 0; + ret = boot->get_memory_map(&size, NULL, &priv->memmap_key, + &priv->memmap_desc_size, + &priv->memmap_version); + if (ret != EFI_BUFFER_TOO_SMALL) { + /* + * Note this function avoids using printf() since it is not + * available in the stub + */ + printhex2(EFI_BITS_PER_LONG); + putc(' '); + printhex2(ret); + puts(" No memory map\n"); + return ret; + } + /* + * Since doing a malloc() may change the memory map and also we want to + * be able to read the memory map in efi_call_exit_boot_services() + * below, after more changes have happened + */ + priv->memmap_alloc = size + 1024; + priv->memmap_size = priv->memmap_alloc; + priv->memmap_desc = efi_malloc(priv, size, &ret); + if (!priv->memmap_desc) { + printhex2(ret); + puts(" No memory for memory descriptor\n"); + return ret; + } + + ret = boot->get_memory_map(&priv->memmap_size, priv->memmap_desc, + &priv->memmap_key, &desc_size, + &priv->memmap_version); + if (ret) { + printhex2(ret); + puts(" Can't get memory map\n"); + return ret; + } + + return 0; +} + +int efi_call_exit_boot_services(void) +{ + struct efi_priv *priv = efi_get_priv(); + const struct efi_boot_services *boot = priv->boot; + efi_uintn_t size; + u32 version; + efi_status_t ret; + + size = priv->memmap_alloc; + ret = boot->get_memory_map(&size, priv->memmap_desc, + &priv->memmap_key, + &priv->memmap_desc_size, &version); + if (ret) { + printhex2(ret); + puts(" Can't get memory map\n"); + return ret; + } + ret = boot->exit_boot_services(priv->parent_image, priv->memmap_key); + if (ret) + return ret; + + return 0; +} diff --git a/lib/efi/efi_app.c b/lib/efi/efi_app.c index f61665686c5..6980933d7ea 100644 --- a/lib/efi/efi_app.c +++ b/lib/efi/efi_app.c @@ -21,29 +21,91 @@ #include <efi.h> #include <efi_api.h> #include <sysreset.h> +#include <dm/device-internal.h> +#include <dm/lists.h> +#include <dm/root.h> DECLARE_GLOBAL_DATA_PTR; -static struct efi_priv *global_priv; - -struct efi_system_table *efi_get_sys_table(void) +int efi_info_get(enum efi_entry_t type, void **datap, int *sizep) { - return global_priv->sys_table; + return -ENOSYS; } -struct efi_boot_services *efi_get_boot(void) +int efi_get_mmap(struct efi_mem_desc **descp, int *sizep, uint *keyp, + int *desc_sizep, uint *versionp) { - return global_priv->boot; -} + struct efi_priv *priv = efi_get_priv(); + struct efi_boot_services *boot = priv->sys_table->boottime; + efi_uintn_t size, desc_size, key; + struct efi_mem_desc *desc; + efi_status_t ret; + u32 version; -unsigned long efi_get_ram_base(void) -{ - return global_priv->ram_base; + /* Get the memory map so we can switch off EFI */ + size = 0; + ret = boot->get_memory_map(&size, NULL, &key, &desc_size, &version); + if (ret != EFI_BUFFER_TOO_SMALL) + return log_msg_ret("get", -ENOMEM); + + desc = malloc(size); + if (!desc) + return log_msg_ret("mem", -ENOMEM); + + ret = boot->get_memory_map(&size, desc, &key, &desc_size, &version); + if (ret) + return log_msg_ret("get", -EINVAL); + + *descp = desc; + *sizep = size; + *desc_sizep = desc_size; + *versionp = version; + *keyp = key; + + return 0; } -int efi_info_get(enum efi_entry_t type, void **datap, int *sizep) +/** + * efi_bind_block() - bind a new block device to an EFI device + * + * Binds a new top-level EFI_MEDIA device as well as a child block device so + * that the block device can be accessed in U-Boot. + * + * The device can then be accessed using 'part list efi 0', 'fat ls efi 0:1', + * for example, just like any other interface type. + * + * @handle: handle of the controller on which this driver is installed + * @blkio: block io protocol proxied by this driver + * @device_path: EFI device path structure for this + * @len: Length of @device_path in bytes + * @devp: Returns the bound device + * @return 0 if OK, -ve on error + */ +int efi_bind_block(efi_handle_t handle, struct efi_block_io *blkio, + struct efi_device_path *device_path, int len, + struct udevice **devp) { - return -ENOSYS; + struct efi_media_plat plat; + struct udevice *dev; + char name[18]; + int ret; + + plat.handle = handle; + plat.blkio = blkio; + plat.device_path = malloc(device_path->length); + if (!plat.device_path) + return log_msg_ret("path", -ENOMEM); + memcpy(plat.device_path, device_path, device_path->length); + ret = device_bind(dm_root(), DM_DRIVER_GET(efi_media), "efi_media", + &plat, ofnode_null(), &dev); + if (ret) + return log_msg_ret("bind", ret); + + snprintf(name, sizeof(name), "efi_media_%x", dev_seq(dev)); + device_set_name(dev, name); + *devp = dev; + + return 0; } static efi_status_t setup_memory(struct efi_priv *priv) @@ -77,13 +139,14 @@ static efi_status_t setup_memory(struct efi_priv *priv) ret = boot->allocate_pages(EFI_ALLOCATE_MAX_ADDRESS, priv->image_data_type, pages, &addr); if (ret) { - printf("(using pool %lx) ", ret); + log_info("(using pool %lx) ", ret); priv->ram_base = (ulong)efi_malloc(priv, CONFIG_EFI_RAM_SIZE, &ret); if (!priv->ram_base) return ret; priv->use_pool_for_malloc = true; } else { + log_info("(using allocated RAM address %lx) ", (ulong)addr); priv->ram_base = addr; } gd->ram_size = pages << 12; @@ -91,6 +154,14 @@ static efi_status_t setup_memory(struct efi_priv *priv) return 0; } +/** + * free_memory() - Free memory used by the U-Boot app + * + * This frees memory allocated in setup_memory(), in preparation for returning + * to UEFI. It also zeroes the global_data pointer. + * + * @priv: Private EFI data + */ static void free_memory(struct efi_priv *priv) { struct efi_boot_services *boot = priv->boot; @@ -106,6 +177,150 @@ static void free_memory(struct efi_priv *priv) } /** + * devpath_is_partition() - Figure out if a device path is a partition + * + * Checks if a device path refers to a partition on some media device. This + * works by checking for a valid partition number in a hard-driver media device + * as the final component of the device path. + * + * @path: device path + * Return: true if a partition, false if not + * (e.g. it might be media which contains partitions) + */ +static bool devpath_is_partition(const struct efi_device_path *path) +{ + const struct efi_device_path *p; + bool was_part; + + for (p = path; p->type != DEVICE_PATH_TYPE_END; + p = (void *)p + p->length) { + was_part = false; + if (p->type == DEVICE_PATH_TYPE_MEDIA_DEVICE && + p->sub_type == DEVICE_PATH_SUB_TYPE_HARD_DRIVE_PATH) { + struct efi_device_path_hard_drive_path *hd = + (void *)path; + + if (hd->partition_number) + was_part = true; + } + } + + return was_part; +} + +/** + * setup_block() - Find all block devices and setup EFI devices for them + * + * Partitions are ignored, since U-Boot has partition handling. Errors with + * particular devices produce a warning but execution continues to try to + * find others. + * + * Return: 0 if found, -ENOSYS if there is no boot-services table, -ENOTSUPP + * if a required protocol is not supported + */ +static int setup_block(void) +{ + efi_guid_t efi_blkio_guid = EFI_BLOCK_IO_PROTOCOL_GUID; + efi_guid_t efi_devpath_guid = EFI_DEVICE_PATH_PROTOCOL_GUID; + efi_guid_t efi_pathutil_guid = EFI_DEVICE_PATH_UTILITIES_PROTOCOL_GUID; + efi_guid_t efi_pathtext_guid = EFI_DEVICE_PATH_TO_TEXT_PROTOCOL_GUID; + struct efi_boot_services *boot = efi_get_boot(); + struct efi_device_path_utilities_protocol *util; + struct efi_device_path_to_text_protocol *text; + struct efi_device_path *path; + struct efi_block_io *blkio; + efi_uintn_t num_handles; + efi_handle_t *handle; + int ret, i; + + if (!boot) + return log_msg_ret("sys", -ENOSYS); + + /* Find all devices which support the block I/O protocol */ + ret = boot->locate_handle_buffer(BY_PROTOCOL, &efi_blkio_guid, NULL, + &num_handles, &handle); + if (ret) + return log_msg_ret("loc", -ENOTSUPP); + log_debug("Found %d handles:\n", (int)num_handles); + + /* We need to look up the path size and convert it to text */ + ret = boot->locate_protocol(&efi_pathutil_guid, NULL, (void **)&util); + if (ret) + return log_msg_ret("util", -ENOTSUPP); + ret = boot->locate_protocol(&efi_pathtext_guid, NULL, (void **)&text); + if (ret) + return log_msg_ret("text", -ENOTSUPP); + + for (i = 0; i < num_handles; i++) { + struct udevice *dev; + const u16 *name; + bool is_part; + int len; + + ret = boot->handle_protocol(handle[i], &efi_devpath_guid, + (void **)&path); + if (ret) { + log_warning("- devpath %d failed (ret=%d)\n", i, ret); + continue; + } + + ret = boot->handle_protocol(handle[i], &efi_blkio_guid, + (void **)&blkio); + if (ret) { + log_warning("- blkio %d failed (ret=%d)\n", i, ret); + continue; + } + + name = text->convert_device_path_to_text(path, true, false); + is_part = devpath_is_partition(path); + + if (!is_part) { + len = util->get_device_path_size(path); + ret = efi_bind_block(handle[i], blkio, path, len, &dev); + if (ret) { + log_warning("- blkio bind %d failed (ret=%d)\n", + i, ret); + continue; + } + } else { + dev = NULL; + } + + /* + * Show the device name if we created one. Otherwise indicate + * that it is a partition. + */ + printf("%2d: %-12s %ls\n", i, dev ? dev->name : "<partition>", + name); + } + boot->free_pool(handle); + + return 0; +} + +/** + * dm_scan_other() - Scan for UEFI devices that should be available to U-Boot + * + * This sets up block devices within U-Boot for those found in UEFI. With this, + * U-Boot can access those devices + * + * @pre_reloc_only: true to only bind pre-relocation devices (ignored) + * Returns: 0 on success, -ve on error + */ +int dm_scan_other(bool pre_reloc_only) +{ + if (gd->flags & GD_FLG_RELOC) { + int ret; + + ret = setup_block(); + if (ret) + return ret; + } + + return 0; +} + +/** * efi_main() - Start an EFI image * * This function is called by our EFI start-up code. It handles running @@ -119,9 +334,12 @@ efi_status_t EFIAPI efi_main(efi_handle_t image, efi_status_t ret; /* Set up access to EFI data structures */ - efi_init(priv, "App", image, sys_table); - - global_priv = priv; + ret = efi_init(priv, "App", image, sys_table); + if (ret) { + printf("Failed to set up U-Boot: err=%lx\n", ret); + return ret; + } + efi_set_priv(priv); /* * Set up the EFI debug UART so that printf() works. This is @@ -136,6 +354,15 @@ efi_status_t EFIAPI efi_main(efi_handle_t image, return ret; } + /* + * We could store the EFI memory map here, but it changes all the time, + * so this is only useful for debugging. + * + * ret = efi_store_memory_map(priv); + * if (ret) + * return ret; + */ + printf("starting\n"); board_init_f(GD_FLG_SKIP_RELOC); @@ -147,7 +374,7 @@ efi_status_t EFIAPI efi_main(efi_handle_t image, static void efi_exit(void) { - struct efi_priv *priv = global_priv; + struct efi_priv *priv = efi_get_priv(); free_memory(priv); printf("U-Boot EFI exiting\n"); diff --git a/lib/efi/efi_stub.c b/lib/efi/efi_stub.c index b3393e47fae..646cde3214c 100644 --- a/lib/efi/efi_stub.c +++ b/lib/efi/efi_stub.c @@ -31,7 +31,6 @@ #error "This file needs to be ported for use on architectures" #endif -static struct efi_priv *global_priv; static bool use_uart; struct __packed desctab_info { @@ -63,6 +62,8 @@ void _debug_uart_init(void) void putc(const char ch) { + struct efi_priv *priv = efi_get_priv(); + if (ch == '\n') putc('\r'); @@ -73,7 +74,7 @@ void putc(const char ch) ; outb(ch, (ulong)&com_port->thr); } else { - efi_putc(global_priv, ch); + efi_putc(priv, ch); } } @@ -225,6 +226,22 @@ static int get_codeseg32(void) return cs32; } +/** + * setup_info_table() - sets up a table containing information from EFI + * + * We must call exit_boot_services() before jumping out of the stub into U-Boot + * proper, so that U-Boot has full control of peripherals, memory, etc. + * + * Once we do this, we cannot call any boot-services functions so we must find + * out everything we need to before doing that. + * + * Set up a struct efi_info_hdr table which can hold various records (e.g. + * struct efi_entry_memmap) with information obtained from EFI. + * + * @priv: Pointer to our private information which contains the list + * @size: Size of the table to allocate + * Return: 0 if OK, non-zero on error + */ static int setup_info_table(struct efi_priv *priv, int size) { struct efi_info_hdr *info; @@ -248,6 +265,19 @@ static int setup_info_table(struct efi_priv *priv, int size) return 0; } +/** + * add_entry_addr() - Add a new entry to the efi_info list + * + * This adds an entry, consisting of a tag and two lots of data. This avoids the + * caller having to coalesce the data first + * + * @priv: Pointer to our private information which contains the list + * @type: Type of the entry to add + * @ptr1: Pointer to first data block to add + * @size1: Size of first data block in bytes (can be 0) + * @ptr2: Pointer to second data block to add + * @size2: Size of second data block in bytes (can be 0) + */ static void add_entry_addr(struct efi_priv *priv, enum efi_entry_t type, void *ptr1, int size1, void *ptr2, int size2) { @@ -274,15 +304,12 @@ efi_status_t EFIAPI efi_main(efi_handle_t image, { struct efi_priv local_priv, *priv = &local_priv; struct efi_boot_services *boot = sys_table->boottime; - struct efi_mem_desc *desc; struct efi_entry_memmap map; struct efi_gop *gop; struct efi_entry_gopmode mode; struct efi_entry_systable table; efi_guid_t efi_gop_guid = EFI_GRAPHICS_OUTPUT_PROTOCOL_GUID; - efi_uintn_t key, desc_size, size; efi_status_t ret; - u32 version; int cs32; ret = efi_init(priv, "Payload", image, sys_table); @@ -291,30 +318,17 @@ efi_status_t EFIAPI efi_main(efi_handle_t image, puts(" efi_init() failed\n"); return ret; } - global_priv = priv; + efi_set_priv(priv); cs32 = get_codeseg32(); if (cs32 < 0) return EFI_UNSUPPORTED; - /* Get the memory map so we can switch off EFI */ - size = 0; - ret = boot->get_memory_map(&size, NULL, &key, &desc_size, &version); - if (ret != EFI_BUFFER_TOO_SMALL) { - printhex2(EFI_BITS_PER_LONG); - putc(' '); - printhex2(ret); - puts(" No memory map\n"); - return ret; - } - size += 1024; /* Since doing a malloc() may change the memory map! */ - desc = efi_malloc(priv, size, &ret); - if (!desc) { - printhex2(ret); - puts(" No memory for memory descriptor\n"); + ret = efi_store_memory_map(priv); + if (ret) return ret; - } - ret = setup_info_table(priv, size + 128); + + ret = setup_info_table(priv, priv->memmap_size + 128); if (ret) return ret; @@ -330,48 +344,20 @@ efi_status_t EFIAPI efi_main(efi_handle_t image, sizeof(struct efi_gop_mode_info)); } - ret = boot->get_memory_map(&size, desc, &key, &desc_size, &version); - if (ret) { - printhex2(ret); - puts(" Can't get memory map\n"); - return ret; - } - table.sys_table = (ulong)sys_table; add_entry_addr(priv, EFIET_SYS_TABLE, &table, sizeof(table), NULL, 0); - ret = boot->exit_boot_services(image, key); - if (ret) { - /* - * Unfortunately it happens that we cannot exit boot services - * the first time. But the second time it work. I don't know - * why but this seems to be a repeatable problem. To get - * around it, just try again. - */ - printhex2(ret); - puts(" Can't exit boot services\n"); - size = sizeof(desc); - ret = boot->get_memory_map(&size, desc, &key, &desc_size, - &version); - if (ret) { - printhex2(ret); - puts(" Can't get memory map\n"); - return ret; - } - ret = boot->exit_boot_services(image, key); - if (ret) { - printhex2(ret); - puts(" Can't exit boot services 2\n"); - return ret; - } - } + ret = efi_call_exit_boot_services(); + if (ret) + return ret; /* The EFI UART won't work now, switch to a debug one */ use_uart = true; - map.version = version; - map.desc_size = desc_size; - add_entry_addr(priv, EFIET_MEMORY_MAP, &map, sizeof(map), desc, size); + map.version = priv->memmap_version; + map.desc_size = priv->memmap_desc_size; + add_entry_addr(priv, EFIET_MEMORY_MAP, &map, sizeof(map), + priv->memmap_desc, priv->memmap_size); add_entry_addr(priv, EFIET_END, NULL, 0, 0, 0); memcpy((void *)CONFIG_SYS_TEXT_BASE, _binary_u_boot_bin_start, diff --git a/lib/efi_driver/efi_block_device.c b/lib/efi_driver/efi_block_device.c index 0937e3595a4..04cb3ef0d4e 100644 --- a/lib/efi_driver/efi_block_device.c +++ b/lib/efi_driver/efi_block_device.c @@ -147,7 +147,7 @@ static int efi_bl_bind(efi_handle_t handle, void *interface) if (!obj) return -ENOENT; - devnum = blk_find_max_devnum(IF_TYPE_EFI); + devnum = blk_find_max_devnum(IF_TYPE_EFI_LOADER); if (devnum == -ENODEV) devnum = 0; else if (devnum < 0) @@ -159,8 +159,8 @@ static int efi_bl_bind(efi_handle_t handle, void *interface) sprintf(name, "efiblk#%d", devnum); /* Create driver model udevice for the EFI block io device */ - ret = blk_create_device(parent, "efi_blk", name, IF_TYPE_EFI, devnum, - io->media->block_size, + ret = blk_create_device(parent, "efi_blk", name, IF_TYPE_EFI_LOADER, + devnum, io->media->block_size, (lbaint_t)io->media->last_block, &bdev); if (ret) return ret; @@ -209,6 +209,6 @@ static const struct efi_driver_ops driver_ops = { /* Identify as EFI driver */ U_BOOT_DRIVER(efi_block) = { .name = "EFI block driver", - .id = UCLASS_EFI, + .id = UCLASS_EFI_LOADER, .ops = &driver_ops, }; diff --git a/lib/efi_driver/efi_uclass.c b/lib/efi_driver/efi_uclass.c index 382c2b477f4..b01ce89c84e 100644 --- a/lib/efi_driver/efi_uclass.c +++ b/lib/efi_driver/efi_uclass.c @@ -308,7 +308,7 @@ efi_status_t efi_driver_init(void) log_debug("Initializing EFI driver framework\n"); for (drv = ll_entry_start(struct driver, driver); drv < ll_entry_end(struct driver, driver); ++drv) { - if (drv->id == UCLASS_EFI) { + if (drv->id == UCLASS_EFI_LOADER) { ret = efi_add_driver(drv); if (ret != EFI_SUCCESS) { log_err("Failed to add EFI driver %s\n", @@ -328,7 +328,7 @@ efi_status_t efi_driver_init(void) */ static int efi_uc_init(struct uclass *class) { - log_debug("Initializing UCLASS_EFI\n"); + log_debug("Initializing UCLASS_EFI_LOADER\n"); return 0; } @@ -340,13 +340,13 @@ static int efi_uc_init(struct uclass *class) */ static int efi_uc_destroy(struct uclass *class) { - log_debug("Destroying UCLASS_EFI\n"); + log_debug("Destroying UCLASS_EFI_LOADER\n"); return 0; } UCLASS_DRIVER(efi) = { .name = "efi", - .id = UCLASS_EFI, + .id = UCLASS_EFI_LOADER, .init = efi_uc_init, .destroy = efi_uc_destroy, }; diff --git a/lib/efi_loader/Kconfig b/lib/efi_loader/Kconfig index 700dc838ddb..24f9a2bb757 100644 --- a/lib/efi_loader/Kconfig +++ b/lib/efi_loader/Kconfig @@ -308,6 +308,8 @@ config EFI_TCG2_PROTOCOL bool "EFI_TCG2_PROTOCOL support" default y depends on TPM_V2 + # Sandbox TPM currently fails on GetCapabilities needed for TCG2 + depends on !SANDBOX select SHA1 select SHA256 select SHA384 diff --git a/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c index 8492b732f38..20b69699fe9 100644 --- a/lib/efi_loader/efi_boottime.c +++ b/lib/efi_loader/efi_boottime.c @@ -3016,9 +3016,12 @@ efi_status_t EFIAPI efi_start_image(efi_handle_t image_handle, if (IS_ENABLED(CONFIG_EFI_TCG2_PROTOCOL)) { if (image_obj->image_type == IMAGE_SUBSYSTEM_EFI_APPLICATION) { ret = efi_tcg2_measure_efi_app_invocation(image_obj); - if (ret != EFI_SUCCESS) { - log_warning("tcg2 measurement fails(0x%lx)\n", - ret); + if (ret == EFI_SECURITY_VIOLATION) { + /* + * TCG2 Protocol is installed but no TPM device found, + * this is not expected. + */ + return EFI_EXIT(EFI_SECURITY_VIOLATION); } } } diff --git a/lib/efi_loader/efi_dt_fixup.c b/lib/efi_loader/efi_dt_fixup.c index b6fe5d2e5a3..d3923e5dba1 100644 --- a/lib/efi_loader/efi_dt_fixup.c +++ b/lib/efi_loader/efi_dt_fixup.c @@ -8,6 +8,7 @@ #include <common.h> #include <efi_dt_fixup.h> #include <efi_loader.h> +#include <efi_rng.h> #include <fdtdec.h> #include <mapmem.h> @@ -41,6 +42,38 @@ static void efi_reserve_memory(u64 addr, u64 size, bool nomap) } /** + * efi_try_purge_kaslr_seed() - Remove unused kaslr-seed + * + * Kernel's EFI STUB only relies on EFI_RNG_PROTOCOL for randomization + * and completely ignores the kaslr-seed for its own randomness needs + * (i.e the randomization of the physical placement of the kernel). + * Weed it out from the DTB we hand over, which would mess up our DTB + * TPM measurements as well. + * + * @fdt: Pointer to device tree + */ +void efi_try_purge_kaslr_seed(void *fdt) +{ + const efi_guid_t efi_guid_rng_protocol = EFI_RNG_PROTOCOL_GUID; + struct efi_handler *handler; + efi_status_t ret; + int nodeoff = 0; + int err = 0; + + ret = efi_search_protocol(efi_root, &efi_guid_rng_protocol, &handler); + if (ret != EFI_SUCCESS) + return; + + nodeoff = fdt_path_offset(fdt, "/chosen"); + if (nodeoff < 0) + return; + + err = fdt_delprop(fdt, nodeoff, "kaslr-seed"); + if (err < 0 && err != -FDT_ERR_NOTFOUND) + log_err("Error deleting kaslr-seed\n"); +} + +/** * efi_carve_out_dt_rsv() - Carve out DT reserved memory ranges * * The mem_rsv entries of the FDT are added to the memory map. Any failures are diff --git a/lib/efi_loader/efi_firmware.c b/lib/efi_loader/efi_firmware.c index a1b88dbfc28..519a47267ca 100644 --- a/lib/efi_loader/efi_firmware.c +++ b/lib/efi_loader/efi_firmware.c @@ -128,8 +128,11 @@ static efi_status_t efi_get_dfu_info( size_t names_len, total_size; int dfu_num, i; u16 *name, *next; + int ret; - dfu_init_env_entities(NULL, NULL); + ret = dfu_init_env_entities(NULL, NULL); + if (ret) + return EFI_SUCCESS; names_len = 0; dfu_num = 0; @@ -138,7 +141,7 @@ static efi_status_t efi_get_dfu_info( dfu_num++; } if (!dfu_num) { - log_warning("Probably dfu_alt_info not defined\n"); + log_warning("No entities in dfu_alt_info\n"); *image_info_size = 0; dfu_free_entities(); diff --git a/lib/efi_loader/efi_image_loader.c b/lib/efi_loader/efi_image_loader.c index eb95580538c..773bd0677c0 100644 --- a/lib/efi_loader/efi_image_loader.c +++ b/lib/efi_loader/efi_image_loader.c @@ -934,9 +934,16 @@ efi_status_t efi_load_pe(struct efi_loaded_image_obj *handle, #if CONFIG_IS_ENABLED(EFI_TCG2_PROTOCOL) /* Measure an PE/COFF image */ - if (tcg2_measure_pe_image(efi, efi_size, handle, - loaded_image_info)) - log_err("PE image measurement failed\n"); + ret = tcg2_measure_pe_image(efi, efi_size, handle, loaded_image_info); + if (ret == EFI_SECURITY_VIOLATION) { + /* + * TCG2 Protocol is installed but no TPM device found, + * this is not expected. + */ + log_err("PE image measurement failed, no tpm device found\n"); + goto err; + } + #endif /* Copy PE headers */ diff --git a/lib/efi_loader/efi_setup.c b/lib/efi_loader/efi_setup.c index 1aba71cd962..49172e35798 100644 --- a/lib/efi_loader/efi_setup.c +++ b/lib/efi_loader/efi_setup.c @@ -241,6 +241,10 @@ efi_status_t efi_init_obj_list(void) ret = efi_tcg2_register(); if (ret != EFI_SUCCESS) goto out; + + ret = efi_tcg2_do_initial_measurement(); + if (ret == EFI_SECURITY_VIOLATION) + goto out; } /* Secure boot */ diff --git a/lib/efi_loader/efi_tcg2.c b/lib/efi_loader/efi_tcg2.c index 8c1f22e3377..0ae07ef0839 100644 --- a/lib/efi_loader/efi_tcg2.c +++ b/lib/efi_loader/efi_tcg2.c @@ -153,6 +153,15 @@ static u16 alg_to_len(u16 hash_alg) return 0; } +static bool is_tcg2_protocol_installed(void) +{ + struct efi_handler *handler; + efi_status_t ret; + + ret = efi_search_protocol(efi_root, &efi_guid_tcg2_protocol, &handler); + return ret == EFI_SUCCESS; +} + static u32 tcg_event_final_size(struct tpml_digest_values *digest_list) { u32 len; @@ -199,6 +208,44 @@ static efi_status_t tcg2_pcr_extend(struct udevice *dev, u32 pcr_index, return EFI_SUCCESS; } +/* tcg2_pcr_read - Read PCRs for a TPM2 device for a given tpml_digest_values + * + * @dev: device + * @pcr_index: PCR index + * @digest_list: list of digest algorithms to extend + * + * @Return: status code + */ +static efi_status_t tcg2_pcr_read(struct udevice *dev, u32 pcr_index, + struct tpml_digest_values *digest_list) +{ + struct tpm_chip_priv *priv; + unsigned int updates, pcr_select_min; + u32 rc; + size_t i; + + priv = dev_get_uclass_priv(dev); + if (!priv) + return EFI_DEVICE_ERROR; + + pcr_select_min = priv->pcr_select_min; + + for (i = 0; i < digest_list->count; i++) { + u16 hash_alg = digest_list->digests[i].hash_alg; + u8 *digest = (u8 *)&digest_list->digests[i].digest; + + rc = tpm2_pcr_read(dev, pcr_index, pcr_select_min, + hash_alg, digest, alg_to_len(hash_alg), + &updates); + if (rc) { + EFI_PRINT("Failed to read PCR\n"); + return EFI_DEVICE_ERROR; + } + } + + return EFI_SUCCESS; +} + /* put_event - Append an agile event to an eventlog * * @pcr_index: PCR index @@ -325,6 +372,45 @@ __weak efi_status_t platform_get_tpm2_device(struct udevice **dev) } /** + * platform_get_eventlog() - retrieve the eventlog address and size + * + * This function retrieves the eventlog address and size if the underlying + * firmware has done some measurements and passed them. + * + * This function may be overridden based on platform specific method of + * passing the eventlog address and size. + * + * @dev: udevice + * @addr: eventlog address + * @sz: eventlog size + * Return: status code + */ +__weak efi_status_t platform_get_eventlog(struct udevice *dev, u64 *addr, + u32 *sz) +{ + const u64 *basep; + const u32 *sizep; + + basep = dev_read_prop(dev, "tpm_event_log_addr", NULL); + if (!basep) + return EFI_NOT_FOUND; + + *addr = be64_to_cpup((__force __be64 *)basep); + + sizep = dev_read_prop(dev, "tpm_event_log_size", NULL); + if (!sizep) + return EFI_NOT_FOUND; + + *sz = be32_to_cpup((__force __be32 *)sizep); + if (*sz == 0) { + log_debug("event log empty\n"); + return EFI_NOT_FOUND; + } + + return EFI_SUCCESS; +} + +/** * tpm2_get_max_command_size() - get the supported max command size * * @dev: TPM device @@ -886,9 +972,12 @@ efi_status_t tcg2_measure_pe_image(void *efi, u64 efi_size, IMAGE_NT_HEADERS32 *nt; struct efi_handler *handler; + if (!is_tcg2_protocol_installed()) + return EFI_SUCCESS; + ret = platform_get_tpm2_device(&dev); if (ret != EFI_SUCCESS) - return ret; + return EFI_SECURITY_VIOLATION; switch (handle->image_type) { case IMAGE_SUBSYSTEM_EFI_APPLICATION: @@ -1182,6 +1271,318 @@ static const struct efi_tcg2_protocol efi_tcg2_protocol = { }; /** + * parse_event_log_header() - Parse and verify the event log header fields + * + * @buffer: Pointer to the start of the eventlog + * @size: Size of the eventlog + * @pos: Return offset of the next event in buffer right + * after the event header i.e specID + * + * Return: status code + */ +static efi_status_t parse_event_log_header(void *buffer, u32 size, u32 *pos) +{ + struct tcg_pcr_event *event_header = (struct tcg_pcr_event *)buffer; + int i = 0; + + if (size < sizeof(*event_header)) + return EFI_COMPROMISED_DATA; + + if (get_unaligned_le32(&event_header->pcr_index) != 0 || + get_unaligned_le32(&event_header->event_type) != EV_NO_ACTION) + return EFI_COMPROMISED_DATA; + + for (i = 0; i < sizeof(event_header->digest); i++) { + if (event_header->digest[i]) + return EFI_COMPROMISED_DATA; + } + + *pos += sizeof(*event_header); + + return EFI_SUCCESS; +} + +/** + * parse_specid_event() - Parse and verify the specID Event in the eventlog + * + * @dev: udevice + * @buffer: Pointer to the start of the eventlog + * @log_size: Size of the eventlog + * @pos: [in] Offset of specID event in the eventlog buffer + * [out] Return offset of the next event in the buffer + * after the specID + * @digest_list: list of digests in the event + * + * Return: status code + * @pos Offset in the eventlog where the specID event ends + * @digest_list: list of digests in the event + */ +static efi_status_t parse_specid_event(struct udevice *dev, void *buffer, + u32 log_size, u32 *pos, + struct tpml_digest_values *digest_list) +{ + struct tcg_efi_spec_id_event *spec_event; + struct tcg_pcr_event *event_header = (struct tcg_pcr_event *)buffer; + size_t spec_event_size; + u32 active = 0, supported = 0, pcr_count = 0, alg_count = 0; + u32 spec_active = 0; + u16 hash_alg; + u8 vendor_sz; + int err, i; + + if (*pos >= log_size || (*pos + sizeof(*spec_event)) > log_size) + return EFI_COMPROMISED_DATA; + + /* Check specID event data */ + spec_event = (struct tcg_efi_spec_id_event *)((uintptr_t)buffer + *pos); + /* Check for signature */ + if (memcmp(spec_event->signature, TCG_EFI_SPEC_ID_EVENT_SIGNATURE_03, + sizeof(TCG_EFI_SPEC_ID_EVENT_SIGNATURE_03))) { + log_err("specID Event: Signature mismatch\n"); + return EFI_COMPROMISED_DATA; + } + + if (spec_event->spec_version_minor != + TCG_EFI_SPEC_ID_EVENT_SPEC_VERSION_MINOR_TPM2 || + spec_event->spec_version_major != + TCG_EFI_SPEC_ID_EVENT_SPEC_VERSION_MAJOR_TPM2) + return EFI_COMPROMISED_DATA; + + if (spec_event->number_of_algorithms > MAX_HASH_COUNT || + spec_event->number_of_algorithms < 1) { + log_err("specID Event: Number of algorithms incorrect\n"); + return EFI_COMPROMISED_DATA; + } + + alg_count = spec_event->number_of_algorithms; + + err = tpm2_get_pcr_info(dev, &supported, &active, &pcr_count); + if (err) + return EFI_DEVICE_ERROR; + + digest_list->count = 0; + /* + * We have to take care that the sequence of algorithms that we record + * in digest_list matches the sequence in eventlog. + */ + for (i = 0; i < alg_count; i++) { + hash_alg = + get_unaligned_le16(&spec_event->digest_sizes[i].algorithm_id); + + if (!(supported & alg_to_mask(hash_alg))) { + log_err("specID Event: Unsupported algorithm\n"); + return EFI_COMPROMISED_DATA; + } + digest_list->digests[digest_list->count++].hash_alg = hash_alg; + + spec_active |= alg_to_mask(hash_alg); + } + + /* + * TCG specification expects the event log to have hashes for all + * active PCR's + */ + if (spec_active != active) { + /* + * Previous stage bootloader should know all the active PCR's + * and use them in the Eventlog. + */ + log_err("specID Event: All active hash alg not present\n"); + return EFI_COMPROMISED_DATA; + } + + /* + * the size of the spec event and placement of vendor_info_size + * depends on supported algoriths + */ + spec_event_size = + offsetof(struct tcg_efi_spec_id_event, digest_sizes) + + alg_count * sizeof(spec_event->digest_sizes[0]); + + if (*pos + spec_event_size >= log_size) + return EFI_COMPROMISED_DATA; + + vendor_sz = *(uint8_t *)((uintptr_t)buffer + *pos + spec_event_size); + + spec_event_size += sizeof(vendor_sz) + vendor_sz; + *pos += spec_event_size; + + if (get_unaligned_le32(&event_header->event_size) != spec_event_size) { + log_err("specID event: header event size mismatch\n"); + /* Right way to handle this can be to call SetActive PCR's */ + return EFI_COMPROMISED_DATA; + } + + return EFI_SUCCESS; +} + +/** + * tcg2_parse_event() - Parse the event in the eventlog + * + * @dev: udevice + * @buffer: Pointer to the start of the eventlog + * @log_size: Size of the eventlog + * @offset: [in] Offset of the event in the eventlog buffer + * [out] Return offset of the next event in the buffer + * @digest_list: list of digests in the event + * @pcr Index of the PCR in the event + * + * Return: status code + */ +static efi_status_t tcg2_parse_event(struct udevice *dev, void *buffer, + u32 log_size, u32 *offset, + struct tpml_digest_values *digest_list, + u32 *pcr) +{ + struct tcg_pcr_event2 *event = NULL; + u32 count, size, event_size; + size_t pos; + + event_size = tcg_event_final_size(digest_list); + if (*offset >= log_size || *offset + event_size > log_size) { + log_err("Event exceeds log size\n"); + return EFI_COMPROMISED_DATA; + } + + event = (struct tcg_pcr_event2 *)((uintptr_t)buffer + *offset); + *pcr = get_unaligned_le32(&event->pcr_index); + + /* get the count */ + count = get_unaligned_le32(&event->digests.count); + if (count != digest_list->count) + return EFI_COMPROMISED_DATA; + + pos = offsetof(struct tcg_pcr_event2, digests); + pos += offsetof(struct tpml_digest_values, digests); + + for (int i = 0; i < digest_list->count; i++) { + u16 alg; + u16 hash_alg = digest_list->digests[i].hash_alg; + u8 *digest = (u8 *)&digest_list->digests[i].digest; + + alg = get_unaligned_le16((void *)((uintptr_t)event + pos)); + + if (alg != hash_alg) + return EFI_COMPROMISED_DATA; + + pos += offsetof(struct tpmt_ha, digest); + memcpy(digest, (void *)((uintptr_t)event + pos), alg_to_len(hash_alg)); + pos += alg_to_len(hash_alg); + } + + size = get_unaligned_le32((void *)((uintptr_t)event + pos)); + event_size += size; + pos += sizeof(u32); /* tcg_pcr_event2 event_size*/ + pos += size; + + /* make sure the calculated buffer is what we checked against */ + if (pos != event_size) + return EFI_COMPROMISED_DATA; + + if (pos > log_size) + return EFI_COMPROMISED_DATA; + + *offset += pos; + + return EFI_SUCCESS; +} + +/** + * tcg2_get_fw_eventlog() - Get the eventlog address and size + * + * If the previous firmware has passed some eventlog, this function get it's + * location and check for it's validity. + * + * @dev: udevice + * @log_buffer: eventlog address + * @log_sz: eventlog size + * + * Return: status code + */ +static efi_status_t tcg2_get_fw_eventlog(struct udevice *dev, void *log_buffer, + size_t *log_sz) +{ + struct tpml_digest_values digest_list; + void *buffer; + efi_status_t ret; + u32 pcr, pos; + u64 base; + u32 sz; + bool extend_pcr = false; + int i; + + ret = platform_get_eventlog(dev, &base, &sz); + if (ret != EFI_SUCCESS) + return ret; + + if (sz > TPM2_EVENT_LOG_SIZE) + return EFI_VOLUME_FULL; + + buffer = (void *)(uintptr_t)base; + pos = 0; + /* Parse the eventlog to check for its validity */ + ret = parse_event_log_header(buffer, sz, &pos); + if (ret) + return ret; + + ret = parse_specid_event(dev, buffer, sz, &pos, &digest_list); + if (ret) { + log_err("Error parsing SPEC ID Event\n"); + return ret; + } + + ret = tcg2_pcr_read(dev, 0, &digest_list); + if (ret) { + log_err("Error reading PCR 0\n"); + return ret; + } + + /* + * If PCR0 is 0, previous firmware didn't have the capability + * to extend the PCR. In this scenario, extend the PCR as + * the eventlog is parsed. + */ + for (i = 0; i < digest_list.count; i++) { + u8 hash_buf[TPM2_SHA512_DIGEST_SIZE] = { 0 }; + u16 hash_alg = digest_list.digests[i].hash_alg; + + if (!memcmp((u8 *)&digest_list.digests[i].digest, hash_buf, + alg_to_len(hash_alg))) + extend_pcr = true; + } + + while (pos < sz) { + ret = tcg2_parse_event(dev, buffer, sz, &pos, &digest_list, + &pcr); + if (ret) { + log_err("Error parsing event\n"); + return ret; + } + if (extend_pcr) { + ret = tcg2_pcr_extend(dev, pcr, &digest_list); + if (ret != EFI_SUCCESS) { + log_err("Error in extending PCR\n"); + return ret; + } + + /* Clear the digest for next event */ + for (i = 0; i < digest_list.count; i++) { + u16 hash_alg = digest_list.digests[i].hash_alg; + u8 *digest = + (u8 *)&digest_list.digests[i].digest; + + memset(digest, 0, alg_to_len(hash_alg)); + } + } + } + + memcpy(log_buffer, buffer, sz); + *log_sz = sz; + + return ret; +} + +/** * create_specid_event() - Create the first event in the eventlog * * @dev: tpm device @@ -1275,6 +1676,14 @@ void tcg2_uninit(void) event_log.buffer = NULL; efi_free_pool(event_log.final_buffer); event_log.final_buffer = NULL; + + if (!is_tcg2_protocol_installed()) + return; + + ret = efi_remove_protocol(efi_root, &efi_guid_tcg2_protocol, + (void *)&efi_tcg2_protocol); + if (ret != EFI_SUCCESS) + log_err("Failed to remove EFI TCG2 protocol\n"); } /** @@ -1313,69 +1722,6 @@ out: } /** - * efi_init_event_log() - initialize an eventlog - */ -static efi_status_t efi_init_event_log(void) -{ - /* - * vendor_info_size is currently set to 0, we need to change the length - * and allocate the flexible array member if this changes - */ - struct tcg_pcr_event *event_header = NULL; - struct udevice *dev; - size_t spec_event_size; - efi_status_t ret; - - ret = platform_get_tpm2_device(&dev); - if (ret != EFI_SUCCESS) - goto out; - - ret = efi_allocate_pool(EFI_BOOT_SERVICES_DATA, TPM2_EVENT_LOG_SIZE, - (void **)&event_log.buffer); - if (ret != EFI_SUCCESS) - goto out; - - /* - * initialize log area as 0xff so the OS can easily figure out the - * last log entry - */ - memset(event_log.buffer, 0xff, TPM2_EVENT_LOG_SIZE); - event_log.pos = 0; - event_log.last_event_size = 0; - event_log.get_event_called = false; - event_log.ebs_called = false; - event_log.truncated = false; - - /* - * The log header is defined to be in SHA1 event log entry format. - * Setup event header - */ - event_header = (struct tcg_pcr_event *)event_log.buffer; - put_unaligned_le32(0, &event_header->pcr_index); - put_unaligned_le32(EV_NO_ACTION, &event_header->event_type); - memset(&event_header->digest, 0, sizeof(event_header->digest)); - ret = create_specid_event(dev, (void *)((uintptr_t)event_log.buffer + sizeof(*event_header)), - &spec_event_size); - if (ret != EFI_SUCCESS) - goto free_pool; - put_unaligned_le32(spec_event_size, &event_header->event_size); - event_log.pos = spec_event_size + sizeof(*event_header); - event_log.last_event_size = event_log.pos; - - ret = create_final_event(); - if (ret != EFI_SUCCESS) - goto free_pool; - -out: - return ret; - -free_pool: - efi_free_pool(event_log.buffer); - event_log.buffer = NULL; - return ret; -} - -/** * tcg2_measure_event() - common function to add event log and extend PCR * * @dev: TPM device @@ -1428,6 +1774,93 @@ static efi_status_t efi_append_scrtm_version(struct udevice *dev) } /** + * efi_init_event_log() - initialize an eventlog + * + * Return: status code + */ +static efi_status_t efi_init_event_log(void) +{ + /* + * vendor_info_size is currently set to 0, we need to change the length + * and allocate the flexible array member if this changes + */ + struct tcg_pcr_event *event_header = NULL; + struct udevice *dev; + size_t spec_event_size; + efi_status_t ret; + + ret = platform_get_tpm2_device(&dev); + if (ret != EFI_SUCCESS) + return ret; + + ret = efi_allocate_pool(EFI_BOOT_SERVICES_DATA, TPM2_EVENT_LOG_SIZE, + (void **)&event_log.buffer); + if (ret != EFI_SUCCESS) + return ret; + + /* + * initialize log area as 0xff so the OS can easily figure out the + * last log entry + */ + memset(event_log.buffer, 0xff, TPM2_EVENT_LOG_SIZE); + + /* + * The log header is defined to be in SHA1 event log entry format. + * Setup event header + */ + event_header = (struct tcg_pcr_event *)event_log.buffer; + event_log.pos = 0; + event_log.last_event_size = 0; + event_log.get_event_called = false; + event_log.ebs_called = false; + event_log.truncated = false; + + /* + * Check if earlier firmware have passed any eventlog. Different + * platforms can use different ways to do so. + */ + ret = tcg2_get_fw_eventlog(dev, event_log.buffer, &event_log.pos); + /* + * If earlier firmware hasn't passed any eventlog, go ahead and + * create the eventlog header. + */ + if (ret == EFI_NOT_FOUND) { + put_unaligned_le32(0, &event_header->pcr_index); + put_unaligned_le32(EV_NO_ACTION, &event_header->event_type); + memset(&event_header->digest, 0, sizeof(event_header->digest)); + ret = create_specid_event(dev, + (void *)((uintptr_t)event_log.buffer + + sizeof(*event_header)), + &spec_event_size); + if (ret != EFI_SUCCESS) + goto free_pool; + put_unaligned_le32(spec_event_size, &event_header->event_size); + event_log.pos = spec_event_size + sizeof(*event_header); + event_log.last_event_size = event_log.pos; + + /* + * Add SCRTM version to the log if previous firmmware + * doesn't pass an eventlog. + */ + ret = efi_append_scrtm_version(dev); + } + + if (ret != EFI_SUCCESS) + goto free_pool; + + ret = create_final_event(); + if (ret != EFI_SUCCESS) + goto free_pool; + + return ret; + +free_pool: + efi_free_pool(event_log.buffer); + event_log.buffer = NULL; + return ret; +} + +/** * tcg2_measure_variable() - add variable event log and extend PCR * * @dev: TPM device @@ -1759,12 +2192,15 @@ efi_status_t efi_tcg2_measure_efi_app_invocation(struct efi_loaded_image_obj *ha u32 event = 0; struct smbios_entry *entry; + if (!is_tcg2_protocol_installed()) + return EFI_SUCCESS; + if (tcg2_efi_app_invoked) return EFI_SUCCESS; ret = platform_get_tpm2_device(&dev); if (ret != EFI_SUCCESS) - return ret; + return EFI_SECURITY_VIOLATION; ret = tcg2_measure_boot_variable(dev); if (ret != EFI_SUCCESS) @@ -1809,6 +2245,9 @@ efi_status_t efi_tcg2_measure_efi_app_exit(void) efi_status_t ret; struct udevice *dev; + if (!is_tcg2_protocol_installed()) + return EFI_SUCCESS; + ret = platform_get_tpm2_device(&dev); if (ret != EFI_SUCCESS) return ret; @@ -1834,6 +2273,12 @@ efi_tcg2_notify_exit_boot_services(struct efi_event *event, void *context) EFI_ENTRY("%p, %p", event, context); event_log.ebs_called = true; + + if (!is_tcg2_protocol_installed()) { + ret = EFI_SUCCESS; + goto out; + } + ret = platform_get_tpm2_device(&dev); if (ret != EFI_SUCCESS) goto out; @@ -1863,6 +2308,9 @@ efi_status_t efi_tcg2_notify_exit_boot_services_failed(void) struct udevice *dev; efi_status_t ret; + if (!is_tcg2_protocol_installed()) + return EFI_SUCCESS; + ret = platform_get_tpm2_device(&dev); if (ret != EFI_SUCCESS) goto out; @@ -1933,11 +2381,36 @@ error: } /** + * efi_tcg2_do_initial_measurement() - do initial measurement + * + * Return: status code + */ +efi_status_t efi_tcg2_do_initial_measurement(void) +{ + efi_status_t ret; + struct udevice *dev; + + if (!is_tcg2_protocol_installed()) + return EFI_SUCCESS; + + ret = platform_get_tpm2_device(&dev); + if (ret != EFI_SUCCESS) + return EFI_SECURITY_VIOLATION; + + ret = tcg2_measure_secure_boot_variable(dev); + if (ret != EFI_SUCCESS) + goto out; + +out: + return ret; +} + +/** * efi_tcg2_register() - register EFI_TCG2_PROTOCOL * * If a TPM2 device is available, the TPM TCG2 Protocol is registered * - * Return: An error status is only returned if adding the protocol fails. + * Return: status code */ efi_status_t efi_tcg2_register(void) { @@ -1960,10 +2433,6 @@ efi_status_t efi_tcg2_register(void) } ret = efi_init_event_log(); - if (ret != EFI_SUCCESS) - goto fail; - - ret = efi_append_scrtm_version(dev); if (ret != EFI_SUCCESS) { tcg2_uninit(); goto fail; @@ -1984,24 +2453,9 @@ efi_status_t efi_tcg2_register(void) goto fail; } - ret = tcg2_measure_secure_boot_variable(dev); - if (ret != EFI_SUCCESS) { - tcg2_uninit(); - goto fail; - } - return ret; fail: log_err("Cannot install EFI_TCG2_PROTOCOL\n"); - /* - * Return EFI_SUCCESS and don't stop the EFI subsystem. - * That's done for 2 reasons - * - If the protocol is not installed the PCRs won't be extended. So - * someone later in the boot flow will notice that and take the - * necessary actions. - * - The TPM sandbox is limited and we won't be able to run any efi - * related tests with TCG2 enabled - */ - return EFI_SUCCESS; + return ret; } diff --git a/lib/efi_loader/efi_variable_tee.c b/lib/efi_loader/efi_variable_tee.c index 281f886124a..a2c65e36947 100644 --- a/lib/efi_loader/efi_variable_tee.c +++ b/lib/efi_loader/efi_variable_tee.c @@ -15,7 +15,6 @@ #include <malloc.h> #include <mm_communication.h> -#define OPTEE_PAGE_SIZE BIT(12) extern struct efi_var_file __efi_runtime_data *efi_var_buf; static efi_uintn_t max_buffer_size; /* comm + var + func + data */ static efi_uintn_t max_payload_size; /* func + data */ @@ -114,7 +113,11 @@ static efi_status_t optee_mm_communicate(void *comm_buf, ulong dsize) rc = tee_invoke_func(conn.tee, &arg, 2, param); tee_shm_free(shm); tee_close_session(conn.tee, conn.session); - if (rc || arg.ret != TEE_SUCCESS) + if (rc) + return EFI_DEVICE_ERROR; + if (arg.ret == TEE_ERROR_EXCESS_DATA) + log_err("Variable payload too large\n"); + if (arg.ret != TEE_SUCCESS) return EFI_DEVICE_ERROR; switch (param[1].u.value.a) { @@ -256,15 +259,6 @@ efi_status_t EFIAPI get_max_payload(efi_uintn_t *size) } *size = var_payload->size; /* - * Although the max payload is configurable on StMM, we only share a - * single page from OP-TEE for the non-secure buffer used to communicate - * with StMM. Since OP-TEE will reject to map anything bigger than that, - * make sure we are in bounds. - */ - if (*size > OPTEE_PAGE_SIZE) - *size = OPTEE_PAGE_SIZE - MM_COMMUNICATE_HEADER_SIZE - - MM_VARIABLE_COMMUNICATE_SIZE; - /* * There seems to be a bug in EDK2 miscalculating the boundaries and * size checks, so deduct 2 more bytes to fulfill this requirement. Fix * it up here to ensure backwards compatibility with older versions diff --git a/lib/fdtdec.c b/lib/fdtdec.c index 7681f272d27..280cda61a72 100644 --- a/lib/fdtdec.c +++ b/lib/fdtdec.c @@ -76,6 +76,19 @@ static const char * const compat_names[COMPAT_COUNT] = { COMPAT(ALTERA_SOCFPGA_CLK_INIT, "altr,socfpga-a10-clk-init") }; +static const char *const fdt_src_name[] = { + [FDTSRC_SEPARATE] = "separate", + [FDTSRC_FIT] = "fit", + [FDTSRC_BOARD] = "board", + [FDTSRC_EMBED] = "embed", + [FDTSRC_ENV] = "env", +}; + +const char *fdtdec_get_srcname(void) +{ + return fdt_src_name[gd->fdt_src]; +} + const char *fdtdec_get_compatible(enum fdt_compat_id id) { /* We allow reading of the 'unknown' ID for testing purposes */ @@ -1146,11 +1159,10 @@ int fdtdec_setup_mem_size_base_lowest(void) return 0; } -#if CONFIG_IS_ENABLED(MULTI_DTB_FIT) -# if CONFIG_IS_ENABLED(MULTI_DTB_FIT_GZIP) ||\ - CONFIG_IS_ENABLED(MULTI_DTB_FIT_LZO) static int uncompress_blob(const void *src, ulong sz_src, void **dstp) { +#if CONFIG_IS_ENABLED(MULTI_DTB_FIT_GZIP) ||\ + CONFIG_IS_ENABLED(MULTI_DTB_FIT_LZO) size_t sz_out = CONFIG_VAL(MULTI_DTB_FIT_UNCOMPRESS_SZ); bool gzip = 0, lzo = 0; ulong sz_in = sz_src; @@ -1175,11 +1187,11 @@ static int uncompress_blob(const void *src, ulong sz_src, void **dstp) return -ENOMEM; } } else { -# if CONFIG_IS_ENABLED(MULTI_DTB_FIT_USER_DEFINED_AREA) +# if CONFIG_IS_ENABLED(MULTI_DTB_FIT_USER_DEFINED_AREA) dst = (void *)CONFIG_VAL(MULTI_DTB_FIT_USER_DEF_ADDR); -# else +# else return -ENOTSUPP; -# endif +# endif } if (CONFIG_IS_ENABLED(GZIP) && gzip) @@ -1197,27 +1209,22 @@ static int uncompress_blob(const void *src, ulong sz_src, void **dstp) return -EBADMSG; } *dstp = dst; - return 0; -} -# else -static int uncompress_blob(const void *src, ulong sz_src, void **dstp) -{ +#else + *dstp = (void *)src; *dstp = (void *)src; +#endif return 0; } -# endif -#endif -#if defined(CONFIG_OF_BOARD) || defined(CONFIG_OF_SEPARATE) -/* - * For CONFIG_OF_SEPARATE, the board may optionally implement this to - * provide and/or fixup the fdt. +/** + * fdt_find_separate() - Find a devicetree at the end of the image + * + * @return pointer to FDT blob */ -__weak void *board_fdt_blob_setup(int *err) +static void *fdt_find_separate(void) { void *fdt_blob = NULL; - *err = 0; #ifdef CONFIG_SPL_BUILD /* FDT is at end of BSS unless it is in a different memory region */ if (IS_ENABLED(CONFIG_SPL_SEPARATE_BSS)) @@ -1231,7 +1238,6 @@ __weak void *board_fdt_blob_setup(int *err) return fdt_blob; } -#endif int fdtdec_set_ethernet_mac_address(void *fdt, const u8 *mac, size_t size) { @@ -1589,60 +1595,81 @@ int fdtdec_set_carveout(void *blob, const char *node, const char *prop_name, return 0; } +/* TODO(sjg@chromium.org): This function should not be weak */ __weak int fdtdec_board_setup(const void *fdt_blob) { return 0; } -int fdtdec_setup(void) +/** + * setup_multi_dtb_fit() - locate the correct dtb from a FIT + * + * This supports the CONFIG_MULTI_DTB_FIT feature, looking for the dtb in a + * supplied FIT + * + * It accepts the current value of gd->fdt_blob, which points to the FIT, then + * updates that gd->fdt_blob, to point to the chosen dtb so that U-Boot uses the + * correct one + */ +static void setup_multi_dtb_fit(void) { - int ret; -#if CONFIG_IS_ENABLED(OF_CONTROL) -# if CONFIG_IS_ENABLED(MULTI_DTB_FIT) - void *fdt_blob; -# endif -# ifdef CONFIG_OF_EMBED - /* Get a pointer to the FDT */ -# ifdef CONFIG_SPL_BUILD - gd->fdt_blob = __dtb_dt_spl_begin; -# else - gd->fdt_blob = __dtb_dt_begin; -# endif -# elif defined(CONFIG_OF_BOARD) || defined(CONFIG_OF_SEPARATE) - /* Allow the board to override the fdt address. */ - gd->fdt_blob = board_fdt_blob_setup(&ret); - if (ret) - return ret; -# endif -# ifndef CONFIG_SPL_BUILD - /* Allow the early environment to override the fdt address */ - gd->fdt_blob = map_sysmem - (env_get_ulong("fdtcontroladdr", 16, - (unsigned long)map_to_sysmem(gd->fdt_blob)), 0); -# endif + void *blob; -# if CONFIG_IS_ENABLED(MULTI_DTB_FIT) /* * Try and uncompress the blob. * Unfortunately there is no way to know how big the input blob really * is. So let us set the maximum input size arbitrarily high. 16MB * ought to be more than enough for packed DTBs. */ - if (uncompress_blob(gd->fdt_blob, 0x1000000, &fdt_blob) == 0) - gd->fdt_blob = fdt_blob; + if (uncompress_blob(gd->fdt_blob, 0x1000000, &blob) == 0) + gd->fdt_blob = blob; /* * Check if blob is a FIT images containings DTBs. * If so, pick the most relevant */ - fdt_blob = locate_dtb_in_fit(gd->fdt_blob); - if (fdt_blob) { - gd->multi_dtb_fit = gd->fdt_blob; - gd->fdt_blob = fdt_blob; + blob = locate_dtb_in_fit(gd->fdt_blob); + if (blob) { + gd_set_multi_dtb_fit(gd->fdt_blob); + gd->fdt_blob = blob; + gd->fdt_src = FDTSRC_FIT; } +} -# endif -#endif +int fdtdec_setup(void) +{ + int ret; + + /* The devicetree is typically appended to U-Boot */ + if (IS_ENABLED(CONFIG_OF_SEPARATE)) { + gd->fdt_blob = fdt_find_separate(); + gd->fdt_src = FDTSRC_SEPARATE; + } else { /* embed dtb in ELF file for testing / development */ + gd->fdt_blob = dtb_dt_embedded(); + gd->fdt_src = FDTSRC_EMBED; + } + + /* Allow the board to override the fdt address. */ + if (IS_ENABLED(CONFIG_OF_BOARD)) { + gd->fdt_blob = board_fdt_blob_setup(&ret); + if (ret) + return ret; + gd->fdt_src = FDTSRC_BOARD; + } + + /* Allow the early environment to override the fdt address */ + if (!IS_ENABLED(CONFIG_SPL_BUILD)) { + ulong addr; + + addr = env_get_hex("fdtcontroladdr", 0); + if (addr) { + gd->fdt_blob = map_sysmem(addr, 0); + gd->fdt_src = FDTSRC_ENV; + } + } + + if (CONFIG_IS_ENABLED(MULTI_DTB_FIT)) + setup_multi_dtb_fit(); ret = fdtdec_prepare_fdt(); if (!ret) @@ -1650,7 +1677,6 @@ int fdtdec_setup(void) return ret; } -#if CONFIG_IS_ENABLED(MULTI_DTB_FIT) int fdtdec_resetup(int *rescan) { void *fdt_blob; @@ -1661,8 +1687,8 @@ int fdtdec_resetup(int *rescan) * FIT image stillpresent there. Save the time and space * required to uncompress it again. */ - if (gd->multi_dtb_fit) { - fdt_blob = locate_dtb_in_fit(gd->multi_dtb_fit); + if (gd_multi_dtb_fit()) { + fdt_blob = locate_dtb_in_fit(gd_multi_dtb_fit()); if (fdt_blob == gd->fdt_blob) { /* @@ -1686,7 +1712,6 @@ int fdtdec_resetup(int *rescan) *rescan = 0; return 0; } -#endif int fdtdec_decode_ram_size(const void *blob, const char *area, int board_id, phys_addr_t *basep, phys_size_t *sizep, diff --git a/lib/image-sparse.c b/lib/image-sparse.c index d80fdbbf58e..5ec0f94ab3e 100644 --- a/lib/image-sparse.c +++ b/lib/image-sparse.c @@ -46,9 +46,66 @@ #include <asm/cache.h> #include <linux/math64.h> +#include <linux/err.h> static void default_log(const char *ignored, char *response) {} +static lbaint_t write_sparse_chunk_raw(struct sparse_storage *info, + lbaint_t blk, lbaint_t blkcnt, + void *data, + char *response) +{ + lbaint_t n = blkcnt, write_blks, blks = 0, aligned_buf_blks = 100; + uint32_t *aligned_buf = NULL; + + if (CONFIG_IS_ENABLED(SYS_DCACHE_OFF)) { + write_blks = info->write(info, blk, n, data); + if (write_blks < n) + goto write_fail; + + return write_blks; + } + + aligned_buf = memalign(ARCH_DMA_MINALIGN, info->blksz * aligned_buf_blks); + if (!aligned_buf) { + info->mssg("Malloc failed for: CHUNK_TYPE_RAW", response); + return -ENOMEM; + } + + while (blkcnt > 0) { + n = min(aligned_buf_blks, blkcnt); + memcpy(aligned_buf, data, n * info->blksz); + + /* write_blks might be > n due to NAND bad-blocks */ + write_blks = info->write(info, blk + blks, n, aligned_buf); + if (write_blks < n) { + free(aligned_buf); + goto write_fail; + } + + blks += write_blks; + data += n * info->blksz; + blkcnt -= n; + } + + free(aligned_buf); + return blks; + +write_fail: + if (IS_ERR_VALUE(write_blks)) { + printf("%s: Write failed, block #" LBAFU " [" LBAFU "] (%lld)\n", + __func__, blk + blks, n, (long long)write_blks); + info->mssg("flash write failure", response); + return write_blks; + } + + /* write_blks < n */ + printf("%s: Write failed, block #" LBAFU " [" LBAFU "]\n", + __func__, blk + blks, n); + info->mssg("flash write failure(incomplete)", response); + return -1; +} + int write_sparse_image(struct sparse_storage *info, const char *part_name, void *data, char *response) { @@ -152,15 +209,11 @@ int write_sparse_image(struct sparse_storage *info, return -1; } - blks = info->write(info, blk, blkcnt, data); - /* blks might be > blkcnt (eg. NAND bad-blocks) */ - if (blks < blkcnt) { - printf("%s: %s" LBAFU " [" LBAFU "]\n", - __func__, "Write failed, block #", - blk, blks); - info->mssg("flash write failure", response); + blks = write_sparse_chunk_raw(info, blk, blkcnt, + data, response); + if (blks < 0) return -1; - } + blk += blks; bytes_written += ((u64)blkcnt) * info->blksz; total_blocks += chunk_header->chunk_sz; diff --git a/lib/rsa/Kconfig b/lib/rsa/Kconfig index 469596abe7a..be9775bcceb 100644 --- a/lib/rsa/Kconfig +++ b/lib/rsa/Kconfig @@ -1,7 +1,8 @@ config RSA bool "Use RSA Library" select RSA_FREESCALE_EXP if FSL_CAAM && !ARCH_MX7 && !ARCH_MX7ULP && !ARCH_MX6 && !ARCH_MX5 - select RSA_SOFTWARE_EXP if !RSA_FREESCALE_EXP + select RSA_ASPEED_EXP if ASPEED_ACRY + select RSA_SOFTWARE_EXP if !RSA_FREESCALE_EXP && !RSA_ASPEED_EXP help RSA support. This enables the RSA algorithm used for FIT image verification in U-Boot. @@ -62,4 +63,11 @@ config RSA_FREESCALE_EXP Enables driver for RSA modular exponentiation using Freescale cryptographic accelerator - CAAM. +config RSA_ASPEED_EXP + bool "Enable RSA Modular Exponentiation with ASPEED crypto accelerator" + depends on DM && ASPEED_ACRY + help + Enables driver for RSA modular exponentiation using ASPEED cryptographic + accelerator - ACRY + endif diff --git a/lib/rsa/rsa-sign.c b/lib/rsa/rsa-sign.c index 0579e5294ee..3b6e5f0f86c 100644 --- a/lib/rsa/rsa-sign.c +++ b/lib/rsa/rsa-sign.c @@ -3,6 +3,8 @@ * Copyright (c) 2013, Google Inc. */ +#define OPENSSL_API_COMPAT 0x10101000L + #include "mkimage.h" #include <stdlib.h> #include <stdio.h> @@ -626,7 +628,7 @@ int rsa_add_verify_data(struct image_sign_info *info, void *keydest) if (ret) goto err_get_pub_key; - rsa = EVP_PKEY_get0_RSA(pkey); + rsa = (RSA *)EVP_PKEY_get0_RSA(pkey); ret = rsa_get_params(rsa, &exponent, &n0_inv, &modulus, &r_squared); if (ret) goto err_get_params; diff --git a/lib/time.c b/lib/time.c index 38a9758292a..96074b84af6 100644 --- a/lib/time.c +++ b/lib/time.c @@ -5,6 +5,7 @@ */ #include <common.h> +#include <clock_legacy.h> #include <bootstage.h> #include <dm.h> #include <errno.h> diff --git a/lib/tpm-v2.c b/lib/tpm-v2.c index 2e7b27bd6bb..1bf627853af 100644 --- a/lib/tpm-v2.c +++ b/lib/tpm-v2.c @@ -254,7 +254,8 @@ u32 tpm2_nv_write_value(struct udevice *dev, u32 index, const void *data, } u32 tpm2_pcr_read(struct udevice *dev, u32 idx, unsigned int idx_min_sz, - void *data, unsigned int *updates) + u16 algorithm, void *data, u32 digest_len, + unsigned int *updates) { u8 idx_array_sz = max(idx_min_sz, DIV_ROUND_UP(idx, 8)); u8 command_v2[COMMAND_BUFFER_SIZE] = { @@ -264,7 +265,7 @@ u32 tpm2_pcr_read(struct udevice *dev, u32 idx, unsigned int idx_min_sz, /* TPML_PCR_SELECTION */ tpm_u32(1), /* Number of selections */ - tpm_u16(TPM2_ALG_SHA256), /* Algorithm of the hash */ + tpm_u16(algorithm), /* Algorithm of the hash */ idx_array_sz, /* Array size for selection */ /* bitmap(idx) Selected PCR bitmap */ }; @@ -283,10 +284,13 @@ u32 tpm2_pcr_read(struct udevice *dev, u32 idx, unsigned int idx_min_sz, if (ret) return ret; + if (digest_len > response_len) + return TPM_LIB_ERROR; + if (unpack_byte_string(response, response_len, "ds", 10, &counter, - response_len - TPM2_DIGEST_LEN, data, - TPM2_DIGEST_LEN)) + response_len - digest_len, data, + digest_len)) return TPM_LIB_ERROR; if (updates) diff --git a/lib/vsprintf.c b/lib/vsprintf.c index e634bd70b66..de9f236b908 100644 --- a/lib/vsprintf.c +++ b/lib/vsprintf.c @@ -276,9 +276,8 @@ static char *string(char *buf, char *end, char *s, int field_width, } /* U-Boot uses UTF-16 strings in the EFI context only. */ -#if CONFIG_IS_ENABLED(EFI_LOADER) && !defined(API_BUILD) -static char *string16(char *buf, char *end, u16 *s, int field_width, - int precision, int flags) +static __maybe_unused char *string16(char *buf, char *end, u16 *s, + int field_width, int precision, int flags) { const u16 *str = s ? s : L"<NULL>"; ssize_t i, len = utf16_strnlen(str, precision); @@ -317,7 +316,6 @@ static char *device_path_string(char *buf, char *end, void *dp, int field_width, return buf; } #endif -#endif static char *mac_address_string(char *buf, char *end, u8 *addr, int field_width, int precision, int flags) @@ -616,7 +614,8 @@ repeat: case 's': /* U-Boot uses UTF-16 strings in the EFI context only. */ -#if CONFIG_IS_ENABLED(EFI_LOADER) && !defined(API_BUILD) +#if (CONFIG_IS_ENABLED(EFI_LOADER) || CONFIG_IS_ENABLED(EFI_APP)) && \ + !defined(API_BUILD) if (qualifier == 'l') { str = string16(str, end, va_arg(args, u16 *), field_width, precision, flags); |