From 78cc3fcf089b8fcaa4d9f21fcd1728bb32d9f5b7 Mon Sep 17 00:00:00 2001 From: Bruno Thomsen Date: Fri, 12 Jun 2020 17:17:33 +0200 Subject: [PATCH 01/24] tpm2: tis_spi: add linux compatible fallback string This solves a compatibility issue with Linux device trees that contain TPMv2.x hardware. So it's easier to import DTS from upstream kernel when migrating board init from C code to DTS. The issue is that fallback binding is different between Linux and u-Boot. Linux: "tcg,tpm_tis-spi" U-Boot: "tis,tpm2-spi" As there are currently no in-tree users of the U-Boot binding, it makes sense to use Linux fallback binding. Signed-off-by: Bruno Thomsen Reviewed-by: Tom Rini --- doc/device-tree-bindings/tpm2/tis-tpm2-spi.txt | 4 ++-- drivers/tpm/tpm2_tis_spi.c | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/doc/device-tree-bindings/tpm2/tis-tpm2-spi.txt b/doc/device-tree-bindings/tpm2/tis-tpm2-spi.txt index b48a15112d..3a2ee4bd17 100644 --- a/doc/device-tree-bindings/tpm2/tis-tpm2-spi.txt +++ b/doc/device-tree-bindings/tpm2/tis-tpm2-spi.txt @@ -2,7 +2,7 @@ ST33TPHF20 SPI TPMv2.0 bindings ------------------------------- Required properties: -- compatible : Should be "tis,tpm2-spi" +- compatible : Should be "tcg,tpm_tis-spi" - reg : SPI Chip select Optional properties: @@ -12,7 +12,7 @@ Optional properties: Example: tpm@1 { - compatible = "tis,tpm2-spi"; + compatible = "tcg,tpm_tis-spi"; reg = <1>; spi-max-frequency = <10000000>; }; diff --git a/drivers/tpm/tpm2_tis_spi.c b/drivers/tpm/tpm2_tis_spi.c index 36016de4a6..9a8145e6ba 100644 --- a/drivers/tpm/tpm2_tis_spi.c +++ b/drivers/tpm/tpm2_tis_spi.c @@ -676,7 +676,7 @@ static const struct tpm_tis_chip_data tpm_tis_std_chip_data = { static const struct udevice_id tpm_tis_spi_ids[] = { { - .compatible = "tis,tpm2-spi", + .compatible = "tcg,tpm_tis-spi", .data = (ulong)&tpm_tis_std_chip_data, }, { } From 06bea4980980c05106944b0192f24700fe479f0b Mon Sep 17 00:00:00 2001 From: Dhananjay Phadke Date: Thu, 4 Jun 2020 16:43:59 -0700 Subject: [PATCH 02/24] tpm: add TPM2_GetRandom command support Add support for TPM2 GetRandom command Signed-off-by: Dhananjay Phadke Reviewed-by: Simon Glass --- include/tpm-v2.h | 13 +++++++++++++ lib/tpm-v2.c | 44 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 57 insertions(+) diff --git a/include/tpm-v2.h b/include/tpm-v2.h index d53d2e4023..f6c045d354 100644 --- a/include/tpm-v2.h +++ b/include/tpm-v2.h @@ -70,6 +70,7 @@ enum tpm2_handles { * @TPM2_CC_DAM_RESET: TPM2_DictionaryAttackLockReset(). * @TPM2_CC_DAM_PARAMETERS: TPM2_DictionaryAttackParameters(). * @TPM2_CC_GET_CAPABILITY: TPM2_GetCapibility(). + * @TPM2_CC_GET_RANDOM: TPM2_GetRandom(). * @TPM2_CC_PCR_READ: TPM2_PCR_Read(). * @TPM2_CC_PCR_EXTEND: TPM2_PCR_Extend(). * @TPM2_CC_PCR_SETAUTHVAL: TPM2_PCR_SetAuthValue(). @@ -85,6 +86,7 @@ enum tpm2_command_codes { TPM2_CC_DAM_PARAMETERS = 0x013A, TPM2_CC_NV_READ = 0x014E, TPM2_CC_GET_CAPABILITY = 0x017A, + TPM2_CC_GET_RANDOM = 0x017B, TPM2_CC_PCR_READ = 0x017E, TPM2_CC_PCR_EXTEND = 0x0182, TPM2_CC_PCR_SETAUTHVAL = 0x0183, @@ -339,4 +341,15 @@ u32 tpm2_pcr_setauthvalue(struct udevice *dev, const char *pw, const ssize_t pw_sz, u32 index, const char *key, const ssize_t key_sz); +/** + * Issue a TPM2_GetRandom command. + * + * @dev TPM device + * @param data output buffer for the random bytes + * @param count size of output buffer + * + * @return return code of the operation + */ +u32 tpm2_get_random(struct udevice *dev, void *data, u32 count); + #endif /* __TPM_V2_H */ diff --git a/lib/tpm-v2.c b/lib/tpm-v2.c index 5a039f65d1..a4c352e3ef 100644 --- a/lib/tpm-v2.c +++ b/lib/tpm-v2.c @@ -422,3 +422,47 @@ u32 tpm2_pcr_setauthvalue(struct udevice *dev, const char *pw, return tpm_sendrecv_command(dev, command_v2, NULL, NULL); } + +u32 tpm2_get_random(struct udevice *dev, void *data, u32 count) +{ + const u8 command_v2[10] = { + tpm_u16(TPM2_ST_NO_SESSIONS), + tpm_u32(12), + tpm_u32(TPM2_CC_GET_RANDOM), + }; + u8 buf[COMMAND_BUFFER_SIZE], response[COMMAND_BUFFER_SIZE]; + + const size_t data_size_offset = 10; + const size_t data_offset = 12; + size_t response_length = sizeof(response); + u32 data_size; + u8 *out = data; + + while (count > 0) { + u32 this_bytes = min((size_t)count, + sizeof(response) - data_offset); + u32 err; + + if (pack_byte_string(buf, sizeof(buf), "sw", + 0, command_v2, sizeof(command_v2), + sizeof(command_v2), this_bytes)) + return TPM_LIB_ERROR; + err = tpm_sendrecv_command(dev, buf, response, + &response_length); + if (err) + return err; + if (unpack_byte_string(response, response_length, "w", + data_size_offset, &data_size)) + return TPM_LIB_ERROR; + if (data_size > this_bytes) + return TPM_LIB_ERROR; + if (unpack_byte_string(response, response_length, "s", + data_offset, out, data_size)) + return TPM_LIB_ERROR; + + count -= data_size; + out += data_size; + } + + return 0; +} From bedbb383e1bf5777386c885950f7fb0a21b0daa2 Mon Sep 17 00:00:00 2001 From: Johannes Holland Date: Mon, 11 May 2020 15:22:25 +0200 Subject: [PATCH 03/24] tpm: add #ifndef to fix redeclaration build errors tpm_tis_spi.c directly includes tpm_tis.h and tpm-v2.h which both define the same enums (see e.g. TPM_ACCESS_VALID). Add an #ifndef to prevent redeclaration errors. Signed-off-by: Johannes Holland --- drivers/tpm/tpm_tis.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/tpm/tpm_tis.h b/drivers/tpm/tpm_tis.h index 947585f8e3..2a160fe05c 100644 --- a/drivers/tpm/tpm_tis.h +++ b/drivers/tpm/tpm_tis.h @@ -104,6 +104,7 @@ struct tpm_cmd_t { /* Max number of iterations after i2c NAK */ #define MAX_COUNT 3 +#ifndef __TPM_V2_H /* * Max number of iterations after i2c NAK for 'long' commands * @@ -127,5 +128,6 @@ enum tis_status { TPM_STS_DATA_AVAIL = 0x10, TPM_STS_DATA_EXPECT = 0x08, }; +#endif #endif From ce6515ecee1fa060a7a4e79eafc8db5f86d259a0 Mon Sep 17 00:00:00 2001 From: Stefan Roese Date: Fri, 15 May 2020 07:09:03 +0200 Subject: [PATCH 04/24] debug_uart: Add CR before and after announce string Add linefeeds before and after the announce string. This makes the output easier to read, especially if some text follows the announce message without a specific additional CR. Signed-off-by: Stefan Roese Reviewed-by: Bin Meng --- include/debug_uart.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/debug_uart.h b/include/debug_uart.h index 4d1c58075c..714b369e6f 100644 --- a/include/debug_uart.h +++ b/include/debug_uart.h @@ -112,7 +112,7 @@ void printhex8(unsigned int value); void printdec(unsigned int value); #ifdef CONFIG_DEBUG_UART_ANNOUNCE -#define _DEBUG_UART_ANNOUNCE printascii(" "); +#define _DEBUG_UART_ANNOUNCE printascii("\n\n"); #else #define _DEBUG_UART_ANNOUNCE #endif From 85ecfd1a128fa0235c34e14eccafb5aa9bf65554 Mon Sep 17 00:00:00 2001 From: Heiko Stuebner Date: Tue, 30 Jun 2020 01:05:45 +0200 Subject: [PATCH 05/24] cmd: add a panic command Even in boot scripts it may be needed to "panic" when all options are exhausted and the device specification specifies hanging instead of resetting the board. So add a new panic command that just wraps around the core panic call in U-Boot and can take an optional message. Signed-off-by: Heiko Stuebner Reviewed-by: Simon Glass Reviewed-by: Tom Rini --- cmd/Makefile | 1 + cmd/panic.c | 23 +++++++++++++++++++++++ 2 files changed, 24 insertions(+) create mode 100644 cmd/panic.c diff --git a/cmd/Makefile b/cmd/Makefile index 006075a048..7008dd42dc 100644 --- a/cmd/Makefile +++ b/cmd/Makefile @@ -8,6 +8,7 @@ ifndef CONFIG_SPL_BUILD obj-y += boot.o obj-$(CONFIG_CMD_BOOTM) += bootm.o obj-y += help.o +obj-y += panic.o obj-y += version.o # command diff --git a/cmd/panic.c b/cmd/panic.c new file mode 100644 index 0000000000..f13b3f094f --- /dev/null +++ b/cmd/panic.c @@ -0,0 +1,23 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (c) 2020 Theobroma Systems Design und Consulting GmbH + */ + +#include +#include + +static int do_panic(struct cmd_tbl *cmdtp, int flag, int argc, + char * const argv[]) +{ + char *text = (argc < 2) ? "" : argv[1]; + + panic(text); + + return CMD_RET_SUCCESS; +} + +U_BOOT_CMD( + panic, 2, 1, do_panic, + "Panic with optional message", + "[message]" +); From 3075eb70c912f7f1569117da719023fb1caf6275 Mon Sep 17 00:00:00 2001 From: Heiko Stuebner Date: Thu, 18 Jun 2020 16:23:21 +0200 Subject: [PATCH 06/24] lib: rsa: distinguish between tpl and spl for CONFIG_RSA_VERIFY MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit While the SPL may want to do signature checking this won't be the case for TPL in all cases, as TPL is mostly used when the amount of initial memory is not enough for a full SPL. So on a system where SPL uses DM but TPL does not we currently end up with a TPL compile error of: lib/rsa/rsa-verify.c:48:25: error: dereferencing pointer to incomplete type ‘struct checksum_algo’ To prevent that change the $(SPL_) to $(SPL_TPL_) to distinguish between both. If someone really needs FIT signature checking in TPL as well, a new TPL_RSA_VERIFY config symbol needs to be added. Signed-off-by: Heiko Stuebner Reviewed-by: Philipp Tomsich Reviewed-by: Simon Glass --- lib/rsa/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/rsa/Makefile b/lib/rsa/Makefile index 14ed3cb401..c61ebfd79e 100644 --- a/lib/rsa/Makefile +++ b/lib/rsa/Makefile @@ -5,6 +5,6 @@ # (C) Copyright 2000-2007 # Wolfgang Denk, DENX Software Engineering, wd@denx.de. -obj-$(CONFIG_$(SPL_)RSA_VERIFY) += rsa-verify.o rsa-checksum.o +obj-$(CONFIG_$(SPL_TPL_)RSA_VERIFY) += rsa-verify.o rsa-checksum.o obj-$(CONFIG_RSA_VERIFY_WITH_PKEY) += rsa-keyprop.o obj-$(CONFIG_RSA_SOFTWARE_EXP) += rsa-mod-exp.o From 447b1d7580868273c426feb0985e966572755bc7 Mon Sep 17 00:00:00 2001 From: Heiko Stuebner Date: Thu, 18 Jun 2020 16:23:22 +0200 Subject: [PATCH 07/24] lib: rsa: take spl/non-spl into account when building rsa_verify_with_pkey() Right now in multiple places there are only checks for the full CONFIG_RSA_VERIFY_WITH_PKEY option, not split into main,spl,tpl variants. This breaks when the rsa functions get enabled for SPL, for example to verify u-boot proper from spl. So fix this by using the existing helpers to distinguis between build-steps. Signed-off-by: Heiko Stuebner Reviewed-by: Simon Glass --- lib/rsa/Makefile | 2 +- lib/rsa/rsa-verify.c | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/rsa/Makefile b/lib/rsa/Makefile index c61ebfd79e..8b75d41f04 100644 --- a/lib/rsa/Makefile +++ b/lib/rsa/Makefile @@ -6,5 +6,5 @@ # Wolfgang Denk, DENX Software Engineering, wd@denx.de. obj-$(CONFIG_$(SPL_TPL_)RSA_VERIFY) += rsa-verify.o rsa-checksum.o -obj-$(CONFIG_RSA_VERIFY_WITH_PKEY) += rsa-keyprop.o +obj-$(CONFIG_$(SPL_TPL_)RSA_VERIFY_WITH_PKEY) += rsa-keyprop.o obj-$(CONFIG_RSA_SOFTWARE_EXP) += rsa-mod-exp.o diff --git a/lib/rsa/rsa-verify.c b/lib/rsa/rsa-verify.c index 1d55b997e3..048f1ab789 100644 --- a/lib/rsa/rsa-verify.c +++ b/lib/rsa/rsa-verify.c @@ -285,7 +285,7 @@ out: } #endif -#if CONFIG_IS_ENABLED(FIT_SIGNATURE) || IS_ENABLED(CONFIG_RSA_VERIFY_WITH_PKEY) +#if CONFIG_IS_ENABLED(FIT_SIGNATURE) || CONFIG_IS_ENABLED(RSA_VERIFY_WITH_PKEY) /** * rsa_verify_key() - Verify a signature against some data using RSA Key * @@ -359,7 +359,7 @@ static int rsa_verify_key(struct image_sign_info *info, } #endif -#ifdef CONFIG_RSA_VERIFY_WITH_PKEY +#if CONFIG_IS_ENABLED(RSA_VERIFY_WITH_PKEY) /** * rsa_verify_with_pkey() - Verify a signature against some data using * only modulus and exponent as RSA key properties. @@ -492,7 +492,7 @@ int rsa_verify(struct image_sign_info *info, return -EINVAL; } - if (IS_ENABLED(CONFIG_RSA_VERIFY_WITH_PKEY) && !info->fdt_blob) { + if (CONFIG_IS_ENABLED(RSA_VERIFY_WITH_PKEY) && !info->fdt_blob) { /* don't rely on fdt properties */ ret = rsa_verify_with_pkey(info, hash, sig, sig_len); From 8434b4373058018ee5b79f06f2cafd6b7c0c15e1 Mon Sep 17 00:00:00 2001 From: Heiko Stuebner Date: Thu, 18 Jun 2020 16:23:23 +0200 Subject: [PATCH 08/24] lib: rsa: bring exp_len in line when generating a key_prop The exponent field of struct key_prop gets allocated an uint64_t, and the contents are positioned from the back, so an exponent of "0x01 0x00 0x01" becomes 0x0 0x0 0x0 0x0 0x0 0x1 0x0 0x1" Right now rsa_gen_key_prop() allocates a uint64_t but sets exp_len to the size returned from the parser, while on the other hand the when getting the key from the devicetree exp_len always gets set to sizeof(uint64_t). So bring that in line with the established code. Signed-off-by: Heiko Stuebner Reviewed-by: Simon Glass --- lib/rsa/rsa-keyprop.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/rsa/rsa-keyprop.c b/lib/rsa/rsa-keyprop.c index 9464df0093..4b54db44c4 100644 --- a/lib/rsa/rsa-keyprop.c +++ b/lib/rsa/rsa-keyprop.c @@ -691,7 +691,7 @@ int rsa_gen_key_prop(const void *key, uint32_t keylen, struct key_prop **prop) memcpy((void *)(*prop)->public_exponent + sizeof(uint64_t) - rsa_key.e_sz, rsa_key.e, rsa_key.e_sz); - (*prop)->exp_len = rsa_key.e_sz; + (*prop)->exp_len = sizeof(uint64_t); /* n0 inverse */ br_i32_decode(n, &rsa_key.n[i], rsa_key.n_sz - i); From 49d0ea3746cae267b4f3c60c0e2e73dcac3d3213 Mon Sep 17 00:00:00 2001 From: Heiko Stuebner Date: Tue, 7 Jul 2020 22:57:26 +0200 Subject: [PATCH 09/24] lib: rsa: fix allocated size for rr and rrtmp in rsa_gen_key_prop() When calculating rrtmp/rr rsa_gen_key_prop() tries to make (((rlen + 31) >> 5) + 1) steps in the rr uint32_t array and (((rlen + 7) >> 3) + 1) / 4 steps in uint32_t rrtmp[] with rlen being num_bits * 2 On a 4096bit key this comes down to to 257 uint32_t elements in rr and 256 elements in rrtmp but with the current allocation rr and rrtmp only have 129 uint32_t elements. On 2048bit keys this works by chance as the defined max_rsa_size=4096 allocates a suitable number of elements, but with an actual 4096bit key this results in other memory parts getting overwritten. So as suggested by Heinrich Schuchardt just use the actual bit-size of the key as base for the size calculation, in turn making the code compatible to any future keysizes. Suggested-by: Heinrich Schuchardt Signed-off-by: Heiko Stuebner Reviewed-by: Simon Glass rrtmp needs 2 + (((*prop)->num_bits * 2) >> 5) array elements. Reviewed-by: Heinrich Schuchardt --- lib/rsa/rsa-keyprop.c | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/lib/rsa/rsa-keyprop.c b/lib/rsa/rsa-keyprop.c index 4b54db44c4..cc0d2f9066 100644 --- a/lib/rsa/rsa-keyprop.c +++ b/lib/rsa/rsa-keyprop.c @@ -654,14 +654,10 @@ int rsa_gen_key_prop(const void *key, uint32_t keylen, struct key_prop **prop) { struct rsa_key rsa_key; uint32_t *n = NULL, *rr = NULL, *rrtmp = NULL; - const int max_rsa_size = 4096; int rlen, i, ret; *prop = calloc(sizeof(**prop), 1); - n = calloc(sizeof(uint32_t), 1 + (max_rsa_size >> 5)); - rr = calloc(sizeof(uint32_t), 1 + (max_rsa_size >> 5)); - rrtmp = calloc(sizeof(uint32_t), 1 + (max_rsa_size >> 5)); - if (!(*prop) || !n || !rr || !rrtmp) { + if (!(*prop)) { ret = -ENOMEM; goto err; } @@ -682,6 +678,14 @@ int rsa_gen_key_prop(const void *key, uint32_t keylen, struct key_prop **prop) } memcpy((void *)(*prop)->modulus, &rsa_key.n[i], rsa_key.n_sz - i); + n = calloc(sizeof(uint32_t), 1 + ((*prop)->num_bits >> 5)); + rr = calloc(sizeof(uint32_t), 1 + (((*prop)->num_bits * 2) >> 5)); + rrtmp = calloc(sizeof(uint32_t), 2 + (((*prop)->num_bits * 2) >> 5)); + if (!n || !rr || !rrtmp) { + ret = -ENOMEM; + goto err; + } + /* exponent */ (*prop)->public_exponent = calloc(1, sizeof(uint64_t)); if (!(*prop)->public_exponent) { From eda753be8a33d9cadf2c41ea614069a31e314ba3 Mon Sep 17 00:00:00 2001 From: Heiko Stuebner Date: Thu, 18 Jun 2020 16:23:25 +0200 Subject: [PATCH 10/24] lib: rsa: free local arrays after use in rsa_gen_key_prop() n, rr and rrtmp are used for internal calculations, but in the end the results are copied into separately allocated elements of the actual key_prop, so the n, rr and rrtmp elements are not used anymore when returning from the function and should of course be freed. Signed-off-by: Heiko Stuebner Reviewed-by: Simon Glass --- lib/rsa/rsa-keyprop.c | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/lib/rsa/rsa-keyprop.c b/lib/rsa/rsa-keyprop.c index cc0d2f9066..1e83eedc82 100644 --- a/lib/rsa/rsa-keyprop.c +++ b/lib/rsa/rsa-keyprop.c @@ -654,17 +654,17 @@ int rsa_gen_key_prop(const void *key, uint32_t keylen, struct key_prop **prop) { struct rsa_key rsa_key; uint32_t *n = NULL, *rr = NULL, *rrtmp = NULL; - int rlen, i, ret; + int rlen, i, ret = 0; *prop = calloc(sizeof(**prop), 1); if (!(*prop)) { ret = -ENOMEM; - goto err; + goto out; } ret = rsa_parse_pub_key(&rsa_key, key, keylen); if (ret) - goto err; + goto out; /* modulus */ /* removing leading 0's */ @@ -674,7 +674,7 @@ int rsa_gen_key_prop(const void *key, uint32_t keylen, struct key_prop **prop) (*prop)->modulus = malloc(rsa_key.n_sz - i); if (!(*prop)->modulus) { ret = -ENOMEM; - goto err; + goto out; } memcpy((void *)(*prop)->modulus, &rsa_key.n[i], rsa_key.n_sz - i); @@ -683,14 +683,14 @@ int rsa_gen_key_prop(const void *key, uint32_t keylen, struct key_prop **prop) rrtmp = calloc(sizeof(uint32_t), 2 + (((*prop)->num_bits * 2) >> 5)); if (!n || !rr || !rrtmp) { ret = -ENOMEM; - goto err; + goto out; } /* exponent */ (*prop)->public_exponent = calloc(1, sizeof(uint64_t)); if (!(*prop)->public_exponent) { ret = -ENOMEM; - goto err; + goto out; } memcpy((void *)(*prop)->public_exponent + sizeof(uint64_t) - rsa_key.e_sz, @@ -714,16 +714,15 @@ int rsa_gen_key_prop(const void *key, uint32_t keylen, struct key_prop **prop) (*prop)->rr = malloc(rlen); if (!(*prop)->rr) { ret = -ENOMEM; - goto err; + goto out; } br_i32_encode((void *)(*prop)->rr, rlen, rr); - return 0; - -err: +out: free(n); free(rr); free(rrtmp); - rsa_free_key_prop(*prop); + if (ret < 0) + rsa_free_key_prop(*prop); return ret; } From 1a62c23ecf1f38d999f7d94d8d27fbc97483b35d Mon Sep 17 00:00:00 2001 From: Heiko Stuebner Date: Thu, 18 Jun 2020 16:23:26 +0200 Subject: [PATCH 11/24] lib: rsa: add documentation to padding_pss_verify to document limitations padding_pss_verify only works with the default pss salt setting of -2 (length to be automatically determined based on the PSS block structure) not -1 (salt length set to the maximum permissible value), which makes verifications of signatures with that saltlen fail. Until this gets implemented at least document this behaviour. Signed-off-by: Heiko Stuebner Reviewed-by: Simon Glass --- lib/rsa/rsa-verify.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/lib/rsa/rsa-verify.c b/lib/rsa/rsa-verify.c index 048f1ab789..61d98e6e2d 100644 --- a/lib/rsa/rsa-verify.c +++ b/lib/rsa/rsa-verify.c @@ -194,6 +194,19 @@ out: return ret; } +/* + * padding_pss_verify() - verify the pss padding of a signature + * + * Only works with a rsa_pss_saltlen:-2 (default value) right now + * saltlen:-1 "set the salt length to the digest length" is currently + * not supported. + * + * @info: Specifies key and FIT information + * @msg: byte array of message, len equal to msg_len + * @msg_len: Message length + * @hash: Pointer to the expected hash + * @hash_len: Length of the hash + */ int padding_pss_verify(struct image_sign_info *info, uint8_t *msg, int msg_len, const uint8_t *hash, int hash_len) From 051cc09ea1fe37eba2204d62de6d35bbe5f5d919 Mon Sep 17 00:00:00 2001 From: Heiko Stuebner Date: Thu, 18 Jun 2020 16:23:27 +0200 Subject: [PATCH 12/24] spl: fit: select SPL_HASH_SUPPORT for SPL_FIT_SIGNATURE rsa-checsum needs support for hash functions or else will run into compile errors like: u-boot/lib/rsa/rsa-checksum.c:28: undefined reference to `hash_progressive_lookup_algo' So similar to the main FIT_SIGNATURE entry selects HASH, select SPL_HASH_SUPPORT for SPL_FIT_SIGNATURE. Cc: Heinrich Schuchardt Signed-off-by: Heiko Stuebner Reviewed-by: Philipp Tomsich Reviewed-by: Simon Glass --- Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/Kconfig b/Kconfig index 99bc5fab02..8151be6404 100644 --- a/Kconfig +++ b/Kconfig @@ -509,6 +509,7 @@ config SPL_FIT_SIGNATURE bool "Enable signature verification of FIT firmware within SPL" depends on SPL_DM select SPL_FIT + select SPL_HASH_SUPPORT select SPL_RSA select SPL_RSA_VERIFY select SPL_IMAGE_SIGN_INFO From c076faba141eb5ec45c447ccb8cd10014c719ee6 Mon Sep 17 00:00:00 2001 From: Heiko Stuebner Date: Thu, 18 Jun 2020 16:23:28 +0200 Subject: [PATCH 13/24] spl: fit: select SPL_CRYPTO_SUPPORT for SPL_FIT_SIGNATURE Verifying FIT images obviously needs the rsa parts of crypto support and while main uboot always compiles crypto support, it's optional for SPL and we should thus select the necessary option to not end up in compile errors like: u-boot/lib/rsa/rsa-verify.c:328: undefined reference to `rsa_mod_exp' So select SPL_CRYPTO_SUPPORT in SPL_FIT_SIGNATURE. Signed-off-by: Heiko Stuebner Reviewed-by: Philipp Tomsich Reviewed-by: Simon Glass --- Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/Kconfig b/Kconfig index 8151be6404..566ca72c92 100644 --- a/Kconfig +++ b/Kconfig @@ -509,6 +509,7 @@ config SPL_FIT_SIGNATURE bool "Enable signature verification of FIT firmware within SPL" depends on SPL_DM select SPL_FIT + select SPL_CRYPTO_SUPPORT select SPL_HASH_SUPPORT select SPL_RSA select SPL_RSA_VERIFY From 146a17ad64e2132222d7134b6961b26817faa3bd Mon Sep 17 00:00:00 2001 From: Dario Binacchi Date: Wed, 27 May 2020 13:56:18 +0200 Subject: [PATCH 14/24] spl: fix format of function documentation U-Boot adopted the kernel-doc annotation style. cc: Michael Trimarchi Signed-off-by: Dario Binacchi Reviewed-by: Simon Glass --- include/spl.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/spl.h b/include/spl.h index b31c9bb4ab..580e4e024f 100644 --- a/include/spl.h +++ b/include/spl.h @@ -155,7 +155,7 @@ struct spl_image_info { #endif }; -/* +/** * Information required to load data from a device * * @dev: Pointer to the device, e.g. struct mmc * From 585b468a8c73df0445e994443a39869697fc53a8 Mon Sep 17 00:00:00 2001 From: Dario Binacchi Date: Wed, 27 May 2020 13:56:19 +0200 Subject: [PATCH 15/24] spl: fit: fail fit loading in case of FDT appending error If uboot does not embed its device tree and the FIT loading function returns error in case of failure in the FDT append, the redundant itb image could be loaded. cc: Michael Trimarchi Signed-off-by: Dario Binacchi Reviewed-by: Michael Trimarchi Reviewed-by: Simon Glass --- common/spl/spl_fit.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/common/spl/spl_fit.c b/common/spl/spl_fit.c index f581a22421..365104fe02 100644 --- a/common/spl/spl_fit.c +++ b/common/spl/spl_fit.c @@ -619,9 +619,12 @@ int spl_load_simple_fit(struct spl_image_info *spl_image, * Booting a next-stage U-Boot may require us to append the FDT. * We allow this to fail, as the U-Boot image might embed its FDT. */ - if (spl_image->os == IH_OS_U_BOOT) - spl_fit_append_fdt(spl_image, info, sector, fit, - images, base_offset); + if (spl_image->os == IH_OS_U_BOOT) { + ret = spl_fit_append_fdt(spl_image, info, sector, fit, + images, base_offset); + if (!IS_ENABLED(CONFIG_OF_EMBED) && ret < 0) + return ret; + } firmware_node = node; /* Now check if there are more images for us to load */ From 9f6a14c47ff95354185248ea6e7b1c695e64939e Mon Sep 17 00:00:00 2001 From: Dario Binacchi Date: Wed, 27 May 2020 13:56:20 +0200 Subject: [PATCH 16/24] spl: fit: nand: fix fit loading in case of bad blocks The offset at which the image to be loaded from NAND is located is retrieved from the itb header. The presence of bad blocks in the area of the NAND where the itb image is located could invalidate the offset which must therefore be adjusted taking into account the state of the sectors concerned. cc: Michael Trimarchi Signed-off-by: Dario Binacchi Reviewed-by: Michael Trimarchi --- common/spl/spl_nand.c | 5 ++++- drivers/mtd/nand/raw/nand_spl_loaders.c | 28 +++++++++++++++++++++++++ include/nand.h | 1 + 3 files changed, 33 insertions(+), 1 deletion(-) diff --git a/common/spl/spl_nand.c b/common/spl/spl_nand.c index 48c97549eb..1e6f2dce56 100644 --- a/common/spl/spl_nand.c +++ b/common/spl/spl_nand.c @@ -42,8 +42,11 @@ static int spl_nand_load_image(struct spl_image_info *spl_image, static ulong spl_nand_fit_read(struct spl_load_info *load, ulong offs, ulong size, void *dst) { + ulong sector; int ret; + sector = *(int *)load->priv; + offs = sector + nand_spl_adjust_offset(sector, offs - sector); ret = nand_spl_load_image(offs, size, dst); if (!ret) return size; @@ -66,7 +69,7 @@ static int spl_nand_load_element(struct spl_image_info *spl_image, debug("Found FIT\n"); load.dev = NULL; - load.priv = NULL; + load.priv = &offset; load.filename = NULL; load.bl_len = 1; load.read = spl_nand_fit_read; diff --git a/drivers/mtd/nand/raw/nand_spl_loaders.c b/drivers/mtd/nand/raw/nand_spl_loaders.c index 177c12b581..4befc75c04 100644 --- a/drivers/mtd/nand/raw/nand_spl_loaders.c +++ b/drivers/mtd/nand/raw/nand_spl_loaders.c @@ -41,6 +41,34 @@ int nand_spl_load_image(uint32_t offs, unsigned int size, void *dst) return 0; } +/** + * nand_spl_adjust_offset - Adjust offset from a starting sector + * @sector: Address of the sector + * @offs: Offset starting from @sector + * + * If one or more bad blocks are in the address space between @sector + * and @sector + @offs, @offs is increased by the NAND block size for + * each bad block found. + */ +u32 nand_spl_adjust_offset(u32 sector, u32 offs) +{ + unsigned int block, lastblock; + + block = sector / CONFIG_SYS_NAND_BLOCK_SIZE; + lastblock = (sector + offs) / CONFIG_SYS_NAND_BLOCK_SIZE; + + while (block <= lastblock) { + if (nand_is_bad_block(block)) { + offs += CONFIG_SYS_NAND_BLOCK_SIZE; + lastblock++; + } + + block++; + } + + return offs; +} + #ifdef CONFIG_SPL_UBI /* * Temporary storage for non NAND page aligned and non NAND page sized diff --git a/include/nand.h b/include/nand.h index 93cbe1e25d..80dd6469bc 100644 --- a/include/nand.h +++ b/include/nand.h @@ -120,6 +120,7 @@ int nand_unlock(struct mtd_info *mtd, loff_t start, size_t length, int allexcept); int nand_get_lock_status(struct mtd_info *mtd, loff_t offset); +u32 nand_spl_adjust_offset(u32 sector, u32 offs); int nand_spl_load_image(uint32_t offs, unsigned int size, void *dst); int nand_spl_read_block(int block, int offset, int len, void *dst); void nand_deselect(void); From 84dd1902443cf500b2536eeb14d6662c6b502698 Mon Sep 17 00:00:00 2001 From: Dario Binacchi Date: Wed, 27 May 2020 13:56:21 +0200 Subject: [PATCH 17/24] spl: fit: improve spl_nand_fit_read(...) readability Replacing the ret variable with err and handling first the error condition about the value returned by the spl_nand_fit_read routine, improves the code readability. Furthermore, the 'else' int the 'else return ret' instruction was useless. cc: Michael Trimarchi Signed-off-by: Dario Binacchi --- common/spl/spl_nand.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/common/spl/spl_nand.c b/common/spl/spl_nand.c index 1e6f2dce56..d13a524597 100644 --- a/common/spl/spl_nand.c +++ b/common/spl/spl_nand.c @@ -43,15 +43,15 @@ static ulong spl_nand_fit_read(struct spl_load_info *load, ulong offs, ulong size, void *dst) { ulong sector; - int ret; + int err; sector = *(int *)load->priv; offs = sector + nand_spl_adjust_offset(sector, offs - sector); - ret = nand_spl_load_image(offs, size, dst); - if (!ret) - return size; - else + err = nand_spl_load_image(offs, size, dst); + if (err) return 0; + + return size; } static int spl_nand_load_element(struct spl_image_info *spl_image, From 3428faf23af5079e80c53d0d8473af30d3c19fca Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Tue, 2 Jun 2020 19:26:44 -0600 Subject: [PATCH 18/24] Update MEM_SUPPORT_64BIT_DATA to be always defined Define this macro always so we don't need the preprocessor to check it. Convert the users to #if instead of #ifdef. Note that '#if MEM_SUPPORT_64BIT_DATA' does not give an error if the macro is not define. It just assumes zero. Signed-off-by: Simon Glass Reviewed-by: Stefan Roese --- cmd/mem.c | 54 +++++++++++++++++++++---------------------- common/command.c | 2 +- include/compiler.h | 4 +++- lib/display_options.c | 6 ++--- 4 files changed, 34 insertions(+), 32 deletions(-) diff --git a/cmd/mem.c b/cmd/mem.c index 9b97f7bf69..fe43427d3c 100644 --- a/cmd/mem.c +++ b/cmd/mem.c @@ -116,7 +116,7 @@ static int do_mem_nm(struct cmd_tbl *cmdtp, int flag, int argc, static int do_mem_mw(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]) { -#ifdef MEM_SUPPORT_64BIT_DATA +#if MEM_SUPPORT_64BIT_DATA u64 writeval; #else ulong writeval; @@ -141,7 +141,7 @@ static int do_mem_mw(struct cmd_tbl *cmdtp, int flag, int argc, /* Get the value to write. */ -#ifdef MEM_SUPPORT_64BIT_DATA +#if MEM_SUPPORT_64BIT_DATA writeval = simple_strtoull(argv[2], NULL, 16); #else writeval = simple_strtoul(argv[2], NULL, 16); @@ -160,7 +160,7 @@ static int do_mem_mw(struct cmd_tbl *cmdtp, int flag, int argc, while (count-- > 0) { if (size == 4) *((u32 *)buf) = (u32)writeval; -#ifdef MEM_SUPPORT_64BIT_DATA +#if MEM_SUPPORT_64BIT_DATA else if (size == 8) *((u64 *)buf) = (u64)writeval; #endif @@ -240,7 +240,7 @@ static int do_mem_cmp(struct cmd_tbl *cmdtp, int flag, int argc, int rcode = 0; const char *type; const void *buf1, *buf2, *base; -#ifdef MEM_SUPPORT_64BIT_DATA +#if MEM_SUPPORT_64BIT_DATA u64 word1, word2; #else ulong word1, word2; @@ -272,7 +272,7 @@ static int do_mem_cmp(struct cmd_tbl *cmdtp, int flag, int argc, if (size == 4) { word1 = *(u32 *)buf1; word2 = *(u32 *)buf2; -#ifdef MEM_SUPPORT_64BIT_DATA +#if MEM_SUPPORT_64BIT_DATA } else if (size == 8) { word1 = *(u64 *)buf1; word2 = *(u64 *)buf2; @@ -286,7 +286,7 @@ static int do_mem_cmp(struct cmd_tbl *cmdtp, int flag, int argc, } if (word1 != word2) { ulong offset = buf1 - base; -#ifdef MEM_SUPPORT_64BIT_DATA +#if MEM_SUPPORT_64BIT_DATA printf("%s at 0x%p (%#0*llx) != %s at 0x%p (%#0*llx)\n", type, (void *)(addr1 + offset), size, word1, type, (void *)(addr2 + offset), size, word2); @@ -391,7 +391,7 @@ static int do_mem_loop(struct cmd_tbl *cmdtp, int flag, int argc, { ulong addr, length, i, bytes; int size; -#ifdef MEM_SUPPORT_64BIT_DATA +#if MEM_SUPPORT_64BIT_DATA volatile u64 *llp; #endif volatile u32 *longp; @@ -424,7 +424,7 @@ static int do_mem_loop(struct cmd_tbl *cmdtp, int flag, int argc, * If we have only one object, just run infinite loops. */ if (length == 1) { -#ifdef MEM_SUPPORT_64BIT_DATA +#if MEM_SUPPORT_64BIT_DATA if (size == 8) { llp = (u64 *)buf; for (;;) @@ -446,7 +446,7 @@ static int do_mem_loop(struct cmd_tbl *cmdtp, int flag, int argc, i = *cp; } -#ifdef MEM_SUPPORT_64BIT_DATA +#if MEM_SUPPORT_64BIT_DATA if (size == 8) { for (;;) { llp = (u64 *)buf; @@ -489,7 +489,7 @@ static int do_mem_loopw(struct cmd_tbl *cmdtp, int flag, int argc, { ulong addr, length, i, bytes; int size; -#ifdef MEM_SUPPORT_64BIT_DATA +#if MEM_SUPPORT_64BIT_DATA volatile u64 *llp; u64 data; #else @@ -519,7 +519,7 @@ static int do_mem_loopw(struct cmd_tbl *cmdtp, int flag, int argc, length = simple_strtoul(argv[2], NULL, 16); /* data to write */ -#ifdef MEM_SUPPORT_64BIT_DATA +#if MEM_SUPPORT_64BIT_DATA data = simple_strtoull(argv[3], NULL, 16); #else data = simple_strtoul(argv[3], NULL, 16); @@ -532,7 +532,7 @@ static int do_mem_loopw(struct cmd_tbl *cmdtp, int flag, int argc, * If we have only one object, just run infinite loops. */ if (length == 1) { -#ifdef MEM_SUPPORT_64BIT_DATA +#if MEM_SUPPORT_64BIT_DATA if (size == 8) { llp = (u64 *)buf; for (;;) @@ -554,7 +554,7 @@ static int do_mem_loopw(struct cmd_tbl *cmdtp, int flag, int argc, *cp = data; } -#ifdef MEM_SUPPORT_64BIT_DATA +#if MEM_SUPPORT_64BIT_DATA if (size == 8) { for (;;) { llp = (u64 *)buf; @@ -1023,7 +1023,7 @@ mod_mem(struct cmd_tbl *cmdtp, int incrflag, int flag, int argc, char *const argv[]) { ulong addr; -#ifdef MEM_SUPPORT_64BIT_DATA +#if MEM_SUPPORT_64BIT_DATA u64 i; #else ulong i; @@ -1062,7 +1062,7 @@ mod_mem(struct cmd_tbl *cmdtp, int incrflag, int flag, int argc, printf("%08lx:", addr); if (size == 4) printf(" %08x", *((u32 *)ptr)); -#ifdef MEM_SUPPORT_64BIT_DATA +#if MEM_SUPPORT_64BIT_DATA else if (size == 8) printf(" %016llx", *((u64 *)ptr)); #endif @@ -1089,7 +1089,7 @@ mod_mem(struct cmd_tbl *cmdtp, int incrflag, int flag, int argc, #endif else { char *endp; -#ifdef MEM_SUPPORT_64BIT_DATA +#if MEM_SUPPORT_64BIT_DATA i = simple_strtoull(console_buffer, &endp, 16); #else i = simple_strtoul(console_buffer, &endp, 16); @@ -1101,7 +1101,7 @@ mod_mem(struct cmd_tbl *cmdtp, int incrflag, int flag, int argc, bootretry_reset_cmd_timeout(); if (size == 4) *((u32 *)ptr) = i; -#ifdef MEM_SUPPORT_64BIT_DATA +#if MEM_SUPPORT_64BIT_DATA else if (size == 8) *((u64 *)ptr) = i; #endif @@ -1196,7 +1196,7 @@ static int do_random(struct cmd_tbl *cmdtp, int flag, int argc, U_BOOT_CMD( md, 3, 1, do_mem_md, "memory display", -#ifdef MEM_SUPPORT_64BIT_DATA +#if MEM_SUPPORT_64BIT_DATA "[.b, .w, .l, .q] address [# of objects]" #else "[.b, .w, .l] address [# of objects]" @@ -1207,7 +1207,7 @@ U_BOOT_CMD( U_BOOT_CMD( mm, 2, 1, do_mem_mm, "memory modify (auto-incrementing address)", -#ifdef MEM_SUPPORT_64BIT_DATA +#if MEM_SUPPORT_64BIT_DATA "[.b, .w, .l, .q] address" #else "[.b, .w, .l] address" @@ -1218,7 +1218,7 @@ U_BOOT_CMD( U_BOOT_CMD( nm, 2, 1, do_mem_nm, "memory modify (constant address)", -#ifdef MEM_SUPPORT_64BIT_DATA +#if MEM_SUPPORT_64BIT_DATA "[.b, .w, .l, .q] address" #else "[.b, .w, .l] address" @@ -1228,7 +1228,7 @@ U_BOOT_CMD( U_BOOT_CMD( mw, 4, 1, do_mem_mw, "memory write (fill)", -#ifdef MEM_SUPPORT_64BIT_DATA +#if MEM_SUPPORT_64BIT_DATA "[.b, .w, .l, .q] address value [count]" #else "[.b, .w, .l] address value [count]" @@ -1238,7 +1238,7 @@ U_BOOT_CMD( U_BOOT_CMD( cp, 4, 1, do_mem_cp, "memory copy", -#ifdef MEM_SUPPORT_64BIT_DATA +#if MEM_SUPPORT_64BIT_DATA "[.b, .w, .l, .q] source target count" #else "[.b, .w, .l] source target count" @@ -1248,7 +1248,7 @@ U_BOOT_CMD( U_BOOT_CMD( cmp, 4, 1, do_mem_cmp, "memory compare", -#ifdef MEM_SUPPORT_64BIT_DATA +#if MEM_SUPPORT_64BIT_DATA "[.b, .w, .l, .q] addr1 addr2 count" #else "[.b, .w, .l] addr1 addr2 count" @@ -1299,7 +1299,7 @@ U_BOOT_CMD( U_BOOT_CMD( loop, 3, 1, do_mem_loop, "infinite loop on address range", -#ifdef MEM_SUPPORT_64BIT_DATA +#if MEM_SUPPORT_64BIT_DATA "[.b, .w, .l, .q] address number_of_objects" #else "[.b, .w, .l] address number_of_objects" @@ -1310,7 +1310,7 @@ U_BOOT_CMD( U_BOOT_CMD( loopw, 4, 1, do_mem_loopw, "infinite write loop on address range", -#ifdef MEM_SUPPORT_64BIT_DATA +#if MEM_SUPPORT_64BIT_DATA "[.b, .w, .l, .q] address number_of_objects data_to_write" #else "[.b, .w, .l] address number_of_objects data_to_write" @@ -1330,7 +1330,7 @@ U_BOOT_CMD( U_BOOT_CMD( mdc, 4, 1, do_mem_mdc, "memory display cyclic", -#ifdef MEM_SUPPORT_64BIT_DATA +#if MEM_SUPPORT_64BIT_DATA "[.b, .w, .l, .q] address count delay(ms)" #else "[.b, .w, .l] address count delay(ms)" @@ -1340,7 +1340,7 @@ U_BOOT_CMD( U_BOOT_CMD( mwc, 4, 1, do_mem_mwc, "memory write cyclic", -#ifdef MEM_SUPPORT_64BIT_DATA +#if MEM_SUPPORT_64BIT_DATA "[.b, .w, .l, .q] address value delay(ms)" #else "[.b, .w, .l] address value delay(ms)" diff --git a/common/command.c b/common/command.c index 4f49f15bfd..fc37ed4d7c 100644 --- a/common/command.c +++ b/common/command.c @@ -473,7 +473,7 @@ int cmd_get_data_size(char* arg, int default_size) return 2; case 'l': return 4; -#ifdef MEM_SUPPORT_64BIT_DATA +#if MEM_SUPPORT_64BIT_DATA case 'q': return 8; #endif diff --git a/include/compiler.h b/include/compiler.h index ed74c272b8..90b7afae53 100644 --- a/include/compiler.h +++ b/include/compiler.h @@ -145,7 +145,9 @@ typedef unsigned long int uintptr_t; #define unlikely(x) __builtin_expect(!!(x), 0) #ifdef __LP64__ -#define MEM_SUPPORT_64BIT_DATA +#define MEM_SUPPORT_64BIT_DATA 1 +#else +#define MEM_SUPPORT_64BIT_DATA 0 #endif #endif diff --git a/lib/display_options.c b/lib/display_options.c index 1dd5b6affd..f4b1059c24 100644 --- a/lib/display_options.c +++ b/lib/display_options.c @@ -138,7 +138,7 @@ int print_buffer(ulong addr, const void *data, uint width, uint count, { /* linebuf as a union causes proper alignment */ union linebuf { -#ifdef MEM_SUPPORT_64BIT_DATA +#if MEM_SUPPORT_64BIT_DATA uint64_t uq[MAX_LINE_LENGTH_BYTES/sizeof(uint64_t) + 1]; #endif uint32_t ui[MAX_LINE_LENGTH_BYTES/sizeof(uint32_t) + 1]; @@ -146,7 +146,7 @@ int print_buffer(ulong addr, const void *data, uint width, uint count, uint8_t uc[MAX_LINE_LENGTH_BYTES/sizeof(uint8_t) + 1]; } lb; int i; -#ifdef MEM_SUPPORT_64BIT_DATA +#if MEM_SUPPORT_64BIT_DATA uint64_t __maybe_unused x; #else uint32_t __maybe_unused x; @@ -169,7 +169,7 @@ int print_buffer(ulong addr, const void *data, uint width, uint count, for (i = 0; i < thislinelen; i++) { if (width == 4) x = lb.ui[i] = *(volatile uint32_t *)data; -#ifdef MEM_SUPPORT_64BIT_DATA +#if MEM_SUPPORT_64BIT_DATA else if (width == 8) x = lb.uq[i] = *(volatile uint64_t *)data; #endif From 76be8f75c5f9cd4d968f720f80b891e101fff1fd Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Tue, 2 Jun 2020 19:26:45 -0600 Subject: [PATCH 19/24] cmd: mem: Use a macro to avoid #ifdef in help It is a bit painful to have #ifdefs in the middle of the help for each command. Add a macro to avoid this. Signed-off-by: Simon Glass Reviewed-by: Stefan Roese --- cmd/mem.c | 68 ++++++++++++++----------------------------------------- 1 file changed, 17 insertions(+), 51 deletions(-) diff --git a/cmd/mem.c b/cmd/mem.c index fe43427d3c..da02bbce95 100644 --- a/cmd/mem.c +++ b/cmd/mem.c @@ -33,6 +33,13 @@ DECLARE_GLOBAL_DATA_PTR; #define CONFIG_SYS_MEMTEST_SCRATCH 0 #endif +/* Create a compile-time value */ +#if MEM_SUPPORT_64BIT_DATA +#define HELP_Q ", .q" +#else +#define HELP_Q "" +#endif + static int mod_mem(struct cmd_tbl *, int, int, int, char * const []); /* Display values from last command. @@ -1016,7 +1023,6 @@ static int do_mem_mtest(struct cmd_tbl *cmdtp, int flag, int argc, * * Syntax: * mm{.b, .w, .l, .q} {addr} - * nm{.b, .w, .l, .q} {addr} */ static int mod_mem(struct cmd_tbl *cmdtp, int incrflag, int flag, int argc, @@ -1196,63 +1202,39 @@ static int do_random(struct cmd_tbl *cmdtp, int flag, int argc, U_BOOT_CMD( md, 3, 1, do_mem_md, "memory display", -#if MEM_SUPPORT_64BIT_DATA - "[.b, .w, .l, .q] address [# of objects]" -#else - "[.b, .w, .l] address [# of objects]" -#endif + "[.b, .w, .l" HELP_Q "] address [# of objects]" ); U_BOOT_CMD( mm, 2, 1, do_mem_mm, "memory modify (auto-incrementing address)", -#if MEM_SUPPORT_64BIT_DATA - "[.b, .w, .l, .q] address" -#else - "[.b, .w, .l] address" -#endif + "[.b, .w, .l" HELP_Q "] address" ); U_BOOT_CMD( nm, 2, 1, do_mem_nm, "memory modify (constant address)", -#if MEM_SUPPORT_64BIT_DATA - "[.b, .w, .l, .q] address" -#else - "[.b, .w, .l] address" -#endif + "[.b, .w, .l" HELP_Q "] address" ); U_BOOT_CMD( mw, 4, 1, do_mem_mw, "memory write (fill)", -#if MEM_SUPPORT_64BIT_DATA - "[.b, .w, .l, .q] address value [count]" -#else - "[.b, .w, .l] address value [count]" -#endif + "[.b, .w, .l" HELP_Q "] address value [count]" ); U_BOOT_CMD( cp, 4, 1, do_mem_cp, "memory copy", -#if MEM_SUPPORT_64BIT_DATA - "[.b, .w, .l, .q] source target count" -#else - "[.b, .w, .l] source target count" -#endif + "[.b, .w, .l" HELP_Q "] source target count" ); U_BOOT_CMD( cmp, 4, 1, do_mem_cmp, "memory compare", -#if MEM_SUPPORT_64BIT_DATA - "[.b, .w, .l, .q] addr1 addr2 count" -#else - "[.b, .w, .l] addr1 addr2 count" -#endif + "[.b, .w, .l" HELP_Q "] addr1 addr2 count" ); #ifdef CONFIG_CMD_CRC32 @@ -1299,22 +1281,14 @@ U_BOOT_CMD( U_BOOT_CMD( loop, 3, 1, do_mem_loop, "infinite loop on address range", -#if MEM_SUPPORT_64BIT_DATA - "[.b, .w, .l, .q] address number_of_objects" -#else - "[.b, .w, .l] address number_of_objects" -#endif + "[.b, .w, .l" HELP_Q "] address number_of_objects" ); #ifdef CONFIG_LOOPW U_BOOT_CMD( loopw, 4, 1, do_mem_loopw, "infinite write loop on address range", -#if MEM_SUPPORT_64BIT_DATA - "[.b, .w, .l, .q] address number_of_objects data_to_write" -#else - "[.b, .w, .l] address number_of_objects data_to_write" -#endif + "[.b, .w, .l" HELP_Q "] address number_of_objects data_to_write" ); #endif /* CONFIG_LOOPW */ @@ -1330,21 +1304,13 @@ U_BOOT_CMD( U_BOOT_CMD( mdc, 4, 1, do_mem_mdc, "memory display cyclic", -#if MEM_SUPPORT_64BIT_DATA - "[.b, .w, .l, .q] address count delay(ms)" -#else - "[.b, .w, .l] address count delay(ms)" -#endif + "[.b, .w, .l" HELP_Q "] address count delay(ms)" ); U_BOOT_CMD( mwc, 4, 1, do_mem_mwc, "memory write cyclic", -#if MEM_SUPPORT_64BIT_DATA - "[.b, .w, .l, .q] address value delay(ms)" -#else - "[.b, .w, .l] address value delay(ms)" -#endif + "[.b, .w, .l" HELP_Q "] address value delay(ms)" ); #endif /* CONFIG_CMD_MX_CYCLIC */ From 4680976fb6e6dd478c0cb0233889122755f4d2db Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Tue, 2 Jun 2020 19:26:46 -0600 Subject: [PATCH 20/24] cmd: mem: Drop #ifdef for MEM_SUPPORT_64BIT_DATA This is defined only when __lp64__ is defined. That means that ulong is 64 bits long. Therefore we don't need to use a separate u64 type on those architectures. Fix up the code to take advantage of that, removing the preprocessor conditions. Signed-off-by: Simon Glass Reviewed-by: Stefan Roese --- cmd/mem.c | 117 ++++++++++++++++++------------------------------------ 1 file changed, 38 insertions(+), 79 deletions(-) diff --git a/cmd/mem.c b/cmd/mem.c index da02bbce95..9ab6b1dd08 100644 --- a/cmd/mem.c +++ b/cmd/mem.c @@ -34,9 +34,11 @@ DECLARE_GLOBAL_DATA_PTR; #endif /* Create a compile-time value */ -#if MEM_SUPPORT_64BIT_DATA +#ifdef MEM_SUPPORT_64BIT_DATA +#define SUPPORT_64BIT_DATA 1 #define HELP_Q ", .q" #else +#define SUPPORT_64BIT_DATA 0 #define HELP_Q "" #endif @@ -123,11 +125,7 @@ static int do_mem_nm(struct cmd_tbl *cmdtp, int flag, int argc, static int do_mem_mw(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]) { -#if MEM_SUPPORT_64BIT_DATA - u64 writeval; -#else - ulong writeval; -#endif + ulong writeval; /* 64-bit if SUPPORT_64BIT_DATA */ ulong addr, count; int size; void *buf, *start; @@ -148,11 +146,10 @@ static int do_mem_mw(struct cmd_tbl *cmdtp, int flag, int argc, /* Get the value to write. */ -#if MEM_SUPPORT_64BIT_DATA - writeval = simple_strtoull(argv[2], NULL, 16); -#else - writeval = simple_strtoul(argv[2], NULL, 16); -#endif + if (SUPPORT_64BIT_DATA) + writeval = simple_strtoull(argv[2], NULL, 16); + else + writeval = simple_strtoul(argv[2], NULL, 16); /* Count ? */ if (argc == 4) { @@ -167,10 +164,8 @@ static int do_mem_mw(struct cmd_tbl *cmdtp, int flag, int argc, while (count-- > 0) { if (size == 4) *((u32 *)buf) = (u32)writeval; -#if MEM_SUPPORT_64BIT_DATA - else if (size == 8) - *((u64 *)buf) = (u64)writeval; -#endif + else if (SUPPORT_64BIT_DATA && size == 8) + *((ulong *)buf) = writeval; else if (size == 2) *((u16 *)buf) = (u16)writeval; else @@ -247,11 +242,7 @@ static int do_mem_cmp(struct cmd_tbl *cmdtp, int flag, int argc, int rcode = 0; const char *type; const void *buf1, *buf2, *base; -#if MEM_SUPPORT_64BIT_DATA - u64 word1, word2; -#else - ulong word1, word2; -#endif + ulong word1, word2; /* 64-bit if SUPPORT_64BIT_DATA */ if (argc != 4) return CMD_RET_USAGE; @@ -279,11 +270,9 @@ static int do_mem_cmp(struct cmd_tbl *cmdtp, int flag, int argc, if (size == 4) { word1 = *(u32 *)buf1; word2 = *(u32 *)buf2; -#if MEM_SUPPORT_64BIT_DATA - } else if (size == 8) { - word1 = *(u64 *)buf1; - word2 = *(u64 *)buf2; -#endif + } else if (SUPPORT_64BIT_DATA && size == 8) { + word1 = *(ulong *)buf1; + word2 = *(ulong *)buf2; } else if (size == 2) { word1 = *(u16 *)buf1; word2 = *(u16 *)buf2; @@ -293,15 +282,9 @@ static int do_mem_cmp(struct cmd_tbl *cmdtp, int flag, int argc, } if (word1 != word2) { ulong offset = buf1 - base; -#if MEM_SUPPORT_64BIT_DATA - printf("%s at 0x%p (%#0*llx) != %s at 0x%p (%#0*llx)\n", - type, (void *)(addr1 + offset), size, word1, - type, (void *)(addr2 + offset), size, word2); -#else printf("%s at 0x%08lx (%#0*lx) != %s at 0x%08lx (%#0*lx)\n", type, (ulong)(addr1 + offset), size, word1, type, (ulong)(addr2 + offset), size, word2); -#endif rcode = 1; break; } @@ -398,9 +381,7 @@ static int do_mem_loop(struct cmd_tbl *cmdtp, int flag, int argc, { ulong addr, length, i, bytes; int size; -#if MEM_SUPPORT_64BIT_DATA - volatile u64 *llp; -#endif + volatile ulong *llp; /* 64-bit if SUPPORT_64BIT_DATA */ volatile u32 *longp; volatile u16 *shortp; volatile u8 *cp; @@ -431,13 +412,11 @@ static int do_mem_loop(struct cmd_tbl *cmdtp, int flag, int argc, * If we have only one object, just run infinite loops. */ if (length == 1) { -#if MEM_SUPPORT_64BIT_DATA - if (size == 8) { - llp = (u64 *)buf; + if (SUPPORT_64BIT_DATA && size == 8) { + llp = (ulong *)buf; for (;;) i = *llp; } -#endif if (size == 4) { longp = (u32 *)buf; for (;;) @@ -453,16 +432,14 @@ static int do_mem_loop(struct cmd_tbl *cmdtp, int flag, int argc, i = *cp; } -#if MEM_SUPPORT_64BIT_DATA - if (size == 8) { + if (SUPPORT_64BIT_DATA && size == 8) { for (;;) { - llp = (u64 *)buf; + llp = (ulong *)buf; i = length; while (i-- > 0) *llp++; } } -#endif if (size == 4) { for (;;) { longp = (u32 *)buf; @@ -496,12 +473,8 @@ static int do_mem_loopw(struct cmd_tbl *cmdtp, int flag, int argc, { ulong addr, length, i, bytes; int size; -#if MEM_SUPPORT_64BIT_DATA - volatile u64 *llp; - u64 data; -#else - ulong data; -#endif + volatile ulong *llp; /* 64-bit if SUPPORT_64BIT_DATA */ + ulong data; /* 64-bit if SUPPORT_64BIT_DATA */ volatile u32 *longp; volatile u16 *shortp; volatile u8 *cp; @@ -526,11 +499,10 @@ static int do_mem_loopw(struct cmd_tbl *cmdtp, int flag, int argc, length = simple_strtoul(argv[2], NULL, 16); /* data to write */ -#if MEM_SUPPORT_64BIT_DATA - data = simple_strtoull(argv[3], NULL, 16); -#else - data = simple_strtoul(argv[3], NULL, 16); -#endif + if (SUPPORT_64BIT_DATA) + data = simple_strtoull(argv[3], NULL, 16); + else + data = simple_strtoul(argv[3], NULL, 16); bytes = size * length; buf = map_sysmem(addr, bytes); @@ -539,13 +511,11 @@ static int do_mem_loopw(struct cmd_tbl *cmdtp, int flag, int argc, * If we have only one object, just run infinite loops. */ if (length == 1) { -#if MEM_SUPPORT_64BIT_DATA - if (size == 8) { - llp = (u64 *)buf; + if (SUPPORT_64BIT_DATA && size == 8) { + llp = (ulong *)buf; for (;;) *llp = data; } -#endif if (size == 4) { longp = (u32 *)buf; for (;;) @@ -561,16 +531,14 @@ static int do_mem_loopw(struct cmd_tbl *cmdtp, int flag, int argc, *cp = data; } -#if MEM_SUPPORT_64BIT_DATA - if (size == 8) { + if (SUPPORT_64BIT_DATA && size == 8) { for (;;) { - llp = (u64 *)buf; + llp = (ulong *)buf; i = length; while (i-- > 0) *llp++ = data; } } -#endif if (size == 4) { for (;;) { longp = (u32 *)buf; @@ -1029,11 +997,7 @@ mod_mem(struct cmd_tbl *cmdtp, int incrflag, int flag, int argc, char *const argv[]) { ulong addr; -#if MEM_SUPPORT_64BIT_DATA - u64 i; -#else - ulong i; -#endif + ulong i; /* 64-bit if SUPPORT_64BIT_DATA */ int nbytes, size; void *ptr = NULL; @@ -1068,10 +1032,8 @@ mod_mem(struct cmd_tbl *cmdtp, int incrflag, int flag, int argc, printf("%08lx:", addr); if (size == 4) printf(" %08x", *((u32 *)ptr)); -#if MEM_SUPPORT_64BIT_DATA - else if (size == 8) - printf(" %016llx", *((u64 *)ptr)); -#endif + else if (SUPPORT_64BIT_DATA && size == 8) + printf(" %0lx", *((ulong *)ptr)); else if (size == 2) printf(" %04x", *((u16 *)ptr)); else @@ -1095,11 +1057,10 @@ mod_mem(struct cmd_tbl *cmdtp, int incrflag, int flag, int argc, #endif else { char *endp; -#if MEM_SUPPORT_64BIT_DATA - i = simple_strtoull(console_buffer, &endp, 16); -#else - i = simple_strtoul(console_buffer, &endp, 16); -#endif + if (SUPPORT_64BIT_DATA) + i = simple_strtoull(console_buffer, &endp, 16); + else + i = simple_strtoul(console_buffer, &endp, 16); nbytes = endp - console_buffer; if (nbytes) { /* good enough to not time out @@ -1107,10 +1068,8 @@ mod_mem(struct cmd_tbl *cmdtp, int incrflag, int flag, int argc, bootretry_reset_cmd_timeout(); if (size == 4) *((u32 *)ptr) = i; -#if MEM_SUPPORT_64BIT_DATA - else if (size == 8) - *((u64 *)ptr) = i; -#endif + else if (SUPPORT_64BIT_DATA && size == 8) + *((ulong *)ptr) = i; else if (size == 2) *((u16 *)ptr) = i; else From 677dbf5daebe5bd49193c2971593ac8b1fe734f1 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Tue, 2 Jun 2020 19:26:47 -0600 Subject: [PATCH 21/24] display_options: Drop #ifdef for MEM_SUPPORT_64BIT_DATA This is defined only when __lp64__ is defined. That means that ulong is 64 bits long. Therefore we don't need to use a separate u64 type on those architectures. Fix up the code to take advantage of that, removing the preprocessor conditions. Also include the missing header file that defines MEM_SUPPORT_64BIT_DATA Fixes: 09140113108 ("command: Remove the cmd_tbl_t typedef") Signed-off-by: Simon Glass --- lib/display_options.c | 18 ++++-------------- 1 file changed, 4 insertions(+), 14 deletions(-) diff --git a/lib/display_options.c b/lib/display_options.c index f4b1059c24..ea9977cc18 100644 --- a/lib/display_options.c +++ b/lib/display_options.c @@ -138,19 +138,13 @@ int print_buffer(ulong addr, const void *data, uint width, uint count, { /* linebuf as a union causes proper alignment */ union linebuf { -#if MEM_SUPPORT_64BIT_DATA uint64_t uq[MAX_LINE_LENGTH_BYTES/sizeof(uint64_t) + 1]; -#endif uint32_t ui[MAX_LINE_LENGTH_BYTES/sizeof(uint32_t) + 1]; uint16_t us[MAX_LINE_LENGTH_BYTES/sizeof(uint16_t) + 1]; uint8_t uc[MAX_LINE_LENGTH_BYTES/sizeof(uint8_t) + 1]; } lb; int i; -#if MEM_SUPPORT_64BIT_DATA - uint64_t __maybe_unused x; -#else - uint32_t __maybe_unused x; -#endif + ulong x; if (linelen*width > MAX_LINE_LENGTH_BYTES) linelen = MAX_LINE_LENGTH_BYTES / width; @@ -169,20 +163,16 @@ int print_buffer(ulong addr, const void *data, uint width, uint count, for (i = 0; i < thislinelen; i++) { if (width == 4) x = lb.ui[i] = *(volatile uint32_t *)data; -#if MEM_SUPPORT_64BIT_DATA - else if (width == 8) - x = lb.uq[i] = *(volatile uint64_t *)data; -#endif + else if (MEM_SUPPORT_64BIT_DATA && width == 8) + x = lb.uq[i] = *(volatile ulong *)data; else if (width == 2) x = lb.us[i] = *(volatile uint16_t *)data; else x = lb.uc[i] = *(volatile uint8_t *)data; #if defined(CONFIG_SPL_BUILD) printf(" %x", (uint)x); -#elif defined(MEM_SUPPORT_64BIT_DATA) - printf(" %0*llx", width * 2, (long long)x); #else - printf(" %0*x", width * 2, x); + printf(" %0*lx", width * 2, x); #endif data += width; } From a33a824227e130d81260dfd3a275af3b0daa81c1 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Tue, 2 Jun 2020 19:26:48 -0600 Subject: [PATCH 22/24] command: Drop #ifdef for MEM_SUPPORT_64BIT_DATA This is defined only when __lp64__ is defined. That means that ulong is 64 bits long. Therefore we don't need to use a separate u64 type on those architectures. Fix up the code to take advantage of that, removing the preprocessor conditions. Also include the header file that defines MEM_SUPPORT_64BIT_DATA. It is included by env.h in this file, but that might not last forever. Signed-off-by: Simon Glass --- common/command.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/common/command.c b/common/command.c index fc37ed4d7c..2c491e20a7 100644 --- a/common/command.c +++ b/common/command.c @@ -9,6 +9,7 @@ */ #include +#include #include #include #include @@ -473,12 +474,12 @@ int cmd_get_data_size(char* arg, int default_size) return 2; case 'l': return 4; -#if MEM_SUPPORT_64BIT_DATA - case 'q': - return 8; -#endif case 's': return -2; + case 'q': + if (MEM_SUPPORT_64BIT_DATA) + return 8; + /* no break */ default: return -1; } From bdded2015c1e54038a86557e339b606b4a31968b Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Tue, 2 Jun 2020 19:26:49 -0600 Subject: [PATCH 23/24] cmd: Add a memory-search command It is useful to be able to find hex values and strings in a memory range. Add a command to support this. cmd: Fix 'md' and add a memory-search command At present 'md.q' is broken. This series provides a fix for this. It also implements a new memory-search command called 'ms'. It allows searching memory for hex and string data. END Signed-off-by: Simon Glass --- README | 10 ++ cmd/Kconfig | 14 +++ cmd/mem.c | 151 +++++++++++++++++++++++ test/Makefile | 1 + test/cmd/Makefile | 5 + test/cmd/mem_search.c | 275 ++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 456 insertions(+) create mode 100644 test/cmd/Makefile create mode 100644 test/cmd/mem_search.c diff --git a/README b/README index 020918a543..2384966a39 100644 --- a/README +++ b/README @@ -3237,6 +3237,7 @@ md - memory display mm - memory modify (auto-incrementing) nm - memory modify (constant address) mw - memory write (fill) +ms - memory search cp - memory copy cmp - memory compare crc32 - checksum calculation @@ -3482,6 +3483,15 @@ List of environment variables (most likely not complete): CONFIG_NET_RETRY_COUNT, if defined. This value has precedence over the valu based on CONFIG_NET_RETRY_COUNT. + memmatches - Number of matches found by the last 'ms' command, in hex + + memaddr - Address of the last match found by the 'ms' command, in hex, + or 0 if none + + mempos - Index position of the last match found by the 'ms' command, + in units of the size (.b, .w, .l) of the search + + The following image location variables contain the location of images used in booting. The "Image" column gives the role of the image and is not an environment variable name. The other columns are environment diff --git a/cmd/Kconfig b/cmd/Kconfig index 0ead88eff1..2b823dd260 100644 --- a/cmd/Kconfig +++ b/cmd/Kconfig @@ -718,6 +718,20 @@ config CMD_MEMORY base - print or set address offset loop - initialize loop on address range +config MEM_SEARCH + bool "ms - Memory search" + help + Memory-search command + + This allows searching through a region of memory looking for hex + data (byte, 16-bit word, 32-bit long, also 64-bit on machines that + support it). It is also possible to search for a string. The + command accepts a memory range and a list of values to search for. + The values need to appear in memory in the same order they are given + in the command. At most 10 matches can be returned at a time, but + pressing return will show the next 10 matches. Environment variables + are set for use with scripting (memmatches, memaddr, mempos). + config CMD_MX_CYCLIC bool "Enable cyclic md/mw commands" depends on CMD_MEMORY diff --git a/cmd/mem.c b/cmd/mem.c index 9ab6b1dd08..575893c18d 100644 --- a/cmd/mem.c +++ b/cmd/mem.c @@ -25,6 +25,7 @@ #include #include #include +#include #include DECLARE_GLOBAL_DATA_PTR; @@ -52,6 +53,10 @@ static ulong dp_last_length = 0x40; static ulong mm_last_addr, mm_last_size; static ulong base_address = 0; +#ifdef CONFIG_MEM_SEARCH +static u8 search_buf[64]; +static uint search_len; +#endif /* Memory Display * @@ -362,6 +367,142 @@ static int do_mem_cp(struct cmd_tbl *cmdtp, int flag, int argc, return 0; } +#ifdef CONFIG_MEM_SEARCH +static int do_mem_search(struct cmd_tbl *cmdtp, int flag, int argc, + char *const argv[]) +{ + ulong addr, length, bytes, offset; + u8 *ptr, *end, *buf; + bool quiet = false; + ulong last_pos; /* Offset of last match in 'size' units*/ + ulong last_addr; /* Address of last displayed line */ + int limit = 10; + int count; + int size; + int i; + + /* We use the last specified parameters, unless new ones are entered */ + addr = dp_last_addr; + size = dp_last_size; + length = dp_last_length; + + if (argc < 3) + return CMD_RET_USAGE; + + if ((!flag & CMD_FLAG_REPEAT)) { + /* + * Check for a size specification. + * Defaults to long if no or incorrect specification. + */ + size = cmd_get_data_size(argv[0], 4); + if (size < 0 && size != -2 /* string */) + return 1; + + argc--; argv++; + while (argc && *argv[0] == '-') { + int ch = argv[0][1]; + + if (ch == 'q') + quiet = true; + else if (ch == 'l' && isxdigit(argv[0][2])) + limit = simple_strtoul(argv[0] + 2, NULL, 16); + else + return CMD_RET_USAGE; + argc--; argv++; + } + + /* Address is specified since argc > 1 */ + addr = simple_strtoul(argv[0], NULL, 16); + addr += base_address; + + /* Length is the number of objects, not number of bytes */ + length = simple_strtoul(argv[1], NULL, 16); + + /* Read the bytes to search for */ + end = search_buf + sizeof(search_buf); + for (i = 2, ptr = search_buf; i < argc && ptr < end; i++) { + if (SUPPORT_64BIT_DATA && size == 8) { + u64 val = simple_strtoull(argv[i], NULL, 16); + + *(u64 *)ptr = val; + } else if (size == -2) { /* string */ + int len = min(strlen(argv[i]), + (size_t)(end - ptr)); + + memcpy(ptr, argv[i], len); + ptr += len; + continue; + } else { + u32 val = simple_strtoul(argv[i], NULL, 16); + + switch (size) { + case 1: + *ptr = val; + break; + case 2: + *(u16 *)ptr = val; + break; + case 4: + *(u32 *)ptr = val; + break; + } + } + ptr += size; + } + search_len = ptr - search_buf; + } + + /* Do the search */ + if (size == -2) + size = 1; + bytes = size * length; + buf = map_sysmem(addr, bytes); + last_pos = 0; + last_addr = 0; + count = 0; + for (offset = 0; offset <= bytes - search_len && count < limit; + offset += size) { + void *ptr = buf + offset; + + if (!memcmp(ptr, search_buf, search_len)) { + uint align = (addr + offset) & 0xf; + ulong match = addr + offset; + + if (!count || (last_addr & ~0xf) != (match & ~0xf)) { + if (!quiet) { + if (count) + printf("--\n"); + print_buffer(match - align, ptr - align, + size, + ALIGN(search_len + align, + 16) / size, 0); + } + last_addr = match; + last_pos = offset / size; + } + count++; + } + } + if (!quiet) { + printf("%d match%s", count, count == 1 ? "" : "es"); + if (count == limit) + printf(" (repeat command to check for more)"); + printf("\n"); + } + env_set_hex("memmatches", count); + env_set_hex("memaddr", last_addr); + env_set_hex("mempos", last_pos); + + unmap_sysmem(buf); + + dp_last_addr = addr + offset / size; + dp_last_size = size; + dp_last_length = length - offset / size; + + return count ? 0 : CMD_RET_FAILURE; +} +#endif + static int do_mem_base(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]) { @@ -1196,6 +1337,16 @@ U_BOOT_CMD( "[.b, .w, .l" HELP_Q "] addr1 addr2 count" ); +#ifdef CONFIG_MEM_SEARCH +/**************************************************/ +U_BOOT_CMD( + ms, 255, 1, do_mem_search, + "memory search", + "[.b, .w, .l" HELP_Q ", .s] [-q | -] address #-of-objects ..." + " -q = quiet, -l = match limit" : +); +#endif + #ifdef CONFIG_CMD_CRC32 #ifndef CONFIG_CRC32_VERIFY diff --git a/test/Makefile b/test/Makefile index bab8f1a5c2..7c4039964e 100644 --- a/test/Makefile +++ b/test/Makefile @@ -3,6 +3,7 @@ # (C) Copyright 2012 The Chromium Authors obj-$(CONFIG_SANDBOX) += bloblist.o +obj-$(CONFIG_CMDLINE) += cmd/ obj-$(CONFIG_UNIT_TEST) += cmd_ut.o obj-$(CONFIG_UNIT_TEST) += ut.o obj-$(CONFIG_SANDBOX) += command_ut.o diff --git a/test/cmd/Makefile b/test/cmd/Makefile new file mode 100644 index 0000000000..85d38f09e8 --- /dev/null +++ b/test/cmd/Makefile @@ -0,0 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0+ +# +# Copyright (c) 2013 Google, Inc + +obj-$(CONFIG_MEM_SEARCH) += mem_search.o diff --git a/test/cmd/mem_search.c b/test/cmd/mem_search.c new file mode 100644 index 0000000000..d57bfad398 --- /dev/null +++ b/test/cmd/mem_search.c @@ -0,0 +1,275 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Tests for memory commands + * + * Copyright 2020 Google LLC + * Written by Simon Glass + */ + +#include +#include +#include +#include +#include + +#define BUF_SIZE 0x100 + +/* Test 'ms' command with bytes */ +static int dm_test_ms_b(struct unit_test_state *uts) +{ + u8 *buf; + + buf = map_sysmem(0, BUF_SIZE + 1); + memset(buf, '\0', BUF_SIZE); + buf[0x0] = 0x12; + buf[0x31] = 0x12; + buf[0xff] = 0x12; + buf[0x100] = 0x12; + console_record_reset(); + run_command("ms.b 1 ff 12", 0); + ut_assert_nextline("00000030: 00 12 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................"); + ut_assert_nextline("--"); + ut_assert_nextline("000000f0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 12 ................"); + ut_assert_nextline("2 matches"); + ut_assert_console_end(); + + ut_asserteq(2, env_get_hex("memmatches", 0)); + ut_asserteq(0xff, env_get_hex("memaddr", 0)); + ut_asserteq(0xfe, env_get_hex("mempos", 0)); + + unmap_sysmem(buf); + + return 0; +} +DM_TEST(dm_test_ms_b, 0); + +/* Test 'ms' command with 16-bit values */ +static int dm_test_ms_w(struct unit_test_state *uts) +{ + u16 *buf; + + buf = map_sysmem(0, BUF_SIZE + 2); + memset(buf, '\0', BUF_SIZE); + buf[0x34 / 2] = 0x1234; + buf[BUF_SIZE / 2] = 0x1234; + console_record_reset(); + run_command("ms.w 0 80 1234", 0); + ut_assert_nextline("00000030: 0000 0000 1234 0000 0000 0000 0000 0000 ....4..........."); + ut_assert_nextline("1 match"); + ut_assert_console_end(); + + ut_asserteq(1, env_get_hex("memmatches", 0)); + ut_asserteq(0x34, env_get_hex("memaddr", 0)); + ut_asserteq(0x34 / 2, env_get_hex("mempos", 0)); + + unmap_sysmem(buf); + + return 0; +} +DM_TEST(dm_test_ms_w, 0); + +/* Test 'ms' command with 32-bit values */ +static int dm_test_ms_l(struct unit_test_state *uts) +{ + u32 *buf; + + buf = map_sysmem(0, BUF_SIZE + 4); + memset(buf, '\0', BUF_SIZE); + buf[0x38 / 4] = 0x12345678; + buf[BUF_SIZE / 4] = 0x12345678; + console_record_reset(); + run_command("ms 0 40 12345678", 0); + ut_assert_nextline("00000030: 00000000 00000000 12345678 00000000 ........xV4....."); + ut_assert_nextline("1 match"); + ut_assert_console_end(); + + ut_asserteq(1, env_get_hex("memmatches", 0)); + ut_asserteq(0x38, env_get_hex("memaddr", 0)); + ut_asserteq(0x38 / 4, env_get_hex("mempos", 0)); + + console_record_reset(); + run_command("ms 0 80 12345679", 0); + ut_assert_nextline("0 matches"); + ut_assert_console_end(); + + ut_asserteq(0, env_get_hex("memmatches", 0)); + ut_asserteq(0, env_get_hex("memaddr", 0)); + ut_asserteq(0 / 4, env_get_hex("mempos", 0)); + + unmap_sysmem(buf); + + return 0; +} +DM_TEST(dm_test_ms_l, 0); + +/* Test 'ms' command with continuation */ +static int dm_test_ms_cont(struct unit_test_state *uts) +{ + char *const args[] = {"ms.b", "0", "100", "34"}; + int repeatable; + u8 *buf; + int i; + + buf = map_sysmem(0, BUF_SIZE); + memset(buf, '\0', BUF_SIZE); + for (i = 5; i < 0x33; i += 3) + buf[i] = 0x34; + console_record_reset(); + run_command("ms.b 0 100 34", 0); + ut_assert_nextlinen("00000000: 00 00 00 00 00 34 00 00 34 00 00 34 00 00 34 00"); + ut_assert_nextline("--"); + ut_assert_nextlinen("00000010: 00 34 00 00 34 00 00 34 00 00 34 00 00 34 00 00"); + ut_assert_nextline("--"); + ut_assert_nextlinen("00000020: 34 00 00 34 00 00 34 00 00 34 00 00 34 00 00 34"); + ut_assert_nextlinen("10 matches (repeat command to check for more)"); + ut_assert_console_end(); + + ut_asserteq(10, env_get_hex("memmatches", 0)); + ut_asserteq(0x20, env_get_hex("memaddr", 0)); + ut_asserteq(0x20, env_get_hex("mempos", 0)); + + /* + * run_command() ignoes the repeatable flag when using hush, so call + * cmd_process() directly + */ + console_record_reset(); + cmd_process(CMD_FLAG_REPEAT, 4, args, &repeatable, NULL); + ut_assert_nextlinen("00000020: 34 00 00 34 00 00 34 00 00 34 00 00 34 00 00 34"); + ut_assert_nextline("--"); + ut_assert_nextlinen("00000030: 00 00 34 00 00 00 00 00"); + ut_assert_nextlinen("6 matches"); + ut_assert_console_end(); + + ut_asserteq(6, env_get_hex("memmatches", 0)); + ut_asserteq(0x32, env_get_hex("memaddr", 0)); + + /* 0x32 less 0x21, where the second search started */ + ut_asserteq(0x11, env_get_hex("mempos", 0)); + + unmap_sysmem(buf); + + return 0; +} +DM_TEST(dm_test_ms_cont, 0); + +/* Test 'ms' command with multiple values */ +static int dm_test_ms_mult(struct unit_test_state *uts) +{ + static const char str[] = "hello"; + char *buf; + + buf = map_sysmem(0, BUF_SIZE + 5); + memset(buf, '\0', BUF_SIZE); + strcpy(buf + 0x1e, str); + strcpy(buf + 0x63, str); + strcpy(buf + BUF_SIZE - strlen(str) + 1, str); + console_record_reset(); + run_command("ms.b 0 100 68 65 6c 6c 6f", 0); + ut_assert_nextline("00000010: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 68 65 ..............he"); + ut_assert_nextline("00000020: 6c 6c 6f 00 00 00 00 00 00 00 00 00 00 00 00 00 llo............."); + ut_assert_nextline("--"); + ut_assert_nextline("00000060: 00 00 00 68 65 6c 6c 6f 00 00 00 00 00 00 00 00 ...hello........"); + ut_assert_nextline("2 matches"); + ut_assert_console_end(); + unmap_sysmem(buf); + + ut_asserteq(2, env_get_hex("memmatches", 0)); + ut_asserteq(0x63, env_get_hex("memaddr", 0)); + ut_asserteq(0x63, env_get_hex("mempos", 0)); + + return 0; +} +DM_TEST(dm_test_ms_mult, 0); + +/* Test 'ms' command with string */ +static int dm_test_ms_s(struct unit_test_state *uts) +{ + static const char str[] = "hello"; + static const char str2[] = "hellothere"; + char *buf; + + buf = map_sysmem(0, BUF_SIZE); + memset(buf, '\0', BUF_SIZE); + strcpy(buf + 0x1e, str); + strcpy(buf + 0x63, str); + strcpy(buf + 0xa1, str2); + console_record_reset(); + run_command("ms.s 0 100 hello", 0); + ut_assert_nextline("00000010: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 68 65 ..............he"); + ut_assert_nextline("00000020: 6c 6c 6f 00 00 00 00 00 00 00 00 00 00 00 00 00 llo............."); + ut_assert_nextline("--"); + ut_assert_nextline("00000060: 00 00 00 68 65 6c 6c 6f 00 00 00 00 00 00 00 00 ...hello........"); + ut_assert_nextline("--"); + ut_assert_nextline("000000a0: 00 68 65 6c 6c 6f 74 68 65 72 65 00 00 00 00 00 .hellothere....."); + ut_assert_nextline("3 matches"); + ut_assert_console_end(); + + ut_asserteq(3, env_get_hex("memmatches", 0)); + ut_asserteq(0xa1, env_get_hex("memaddr", 0)); + ut_asserteq(0xa1, env_get_hex("mempos", 0)); + + console_record_reset(); + run_command("ms.s 0 100 hello there", 0); + ut_assert_nextline("000000a0: 00 68 65 6c 6c 6f 74 68 65 72 65 00 00 00 00 00 .hellothere....."); + ut_assert_nextline("1 match"); + ut_assert_console_end(); + + ut_asserteq(1, env_get_hex("memmatches", 0)); + ut_asserteq(0xa1, env_get_hex("memaddr", 0)); + ut_asserteq(0xa1, env_get_hex("mempos", 0)); + + unmap_sysmem(buf); + + return 0; +} +DM_TEST(dm_test_ms_s, 0); + +/* Test 'ms' command with limit */ +static int dm_test_ms_limit(struct unit_test_state *uts) +{ + u8 *buf; + + buf = map_sysmem(0, BUF_SIZE + 1); + memset(buf, '\0', BUF_SIZE); + buf[0x0] = 0x12; + buf[0x31] = 0x12; + buf[0x62] = 0x12; + buf[0x76] = 0x12; + console_record_reset(); + run_command("ms.b -l2 1 ff 12", 0); + ut_assert_nextline("00000030: 00 12 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................"); + ut_assert_nextline("--"); + ut_assert_nextlinen("00000060: 00 00 12 00 00 00 00 00 00 00 00 00 00 00 00 00"); + ut_assert_nextline("2 matches (repeat command to check for more)"); + ut_assert_console_end(); + + ut_asserteq(2, env_get_hex("memmatches", 0)); + ut_asserteq(0x62, env_get_hex("memaddr", 0)); + ut_asserteq(0x61, env_get_hex("mempos", 0)); + + unmap_sysmem(buf); + + return 0; +} +DM_TEST(dm_test_ms_limit, 0); + +/* Test 'ms' command in quiet mode */ +static int dm_test_ms_quiet(struct unit_test_state *uts) +{ + u8 *buf; + + buf = map_sysmem(0, BUF_SIZE + 1); + memset(buf, '\0', BUF_SIZE); + buf[0x0] = 0x12; + buf[0x31] = 0x12; + buf[0x62] = 0x12; + buf[0x76] = 0x12; + console_record_reset(); + run_command("ms.b -l2 1 ff 12", 0); + ut_assert_console_end(); + unmap_sysmem(buf); + + return 0; +} +DM_TEST(dm_test_ms_quiet, 0); + From c89b41b4db4a746647c4f0e6d33c6f4edfe96e38 Mon Sep 17 00:00:00 2001 From: Heiko Stuebner Date: Fri, 22 May 2020 16:20:33 +0200 Subject: [PATCH 24/24] lib: rsa: function to verify a signature against a hash rsa_verify() expects a memory region and wants to do the hashing itself, but there may be cases where the hashing is done via other means, like hashing a squashfs rootfs. So add rsa_verify_hash() to allow verifiying a signature against an existing hash. As this entails the same verification routines we can just move the relevant code over from rsa_verify() and also call rsa_verify_hash() from there. Signed-off-by: Heiko Stuebner --- include/u-boot/rsa.h | 21 +++++++++++++++++ lib/rsa/rsa-verify.c | 56 +++++++++++++++++++++++++------------------- 2 files changed, 53 insertions(+), 24 deletions(-) diff --git a/include/u-boot/rsa.h b/include/u-boot/rsa.h index 2d3024d8b7..a0bae495f0 100644 --- a/include/u-boot/rsa.h +++ b/include/u-boot/rsa.h @@ -82,6 +82,20 @@ static inline int rsa_add_verify_data(struct image_sign_info *info, #endif #if IMAGE_ENABLE_VERIFY +/** + * rsa_verify_hash() - Verify a signature against a hash + * + * Verify a RSA PKCS1.5 signature against an expected hash. + * + * @info: Specifies key and FIT information + * @hash: Hash according to algorithm specified in @info + * @sig: Signature + * @sig_len: Number of bytes in signature + * @return 0 if verified, -ve on error + */ +int rsa_verify_hash(struct image_sign_info *info, + const uint8_t *hash, uint8_t *sig, uint sig_len); + /** * rsa_verify() - Verify a signature against some data * @@ -108,6 +122,13 @@ int padding_pss_verify(struct image_sign_info *info, const uint8_t *hash, int hash_len); #endif /* CONFIG_FIT_ENABLE_RSASSA_PSS_SUPPORT */ #else +static inline int rsa_verify_hash(struct image_sign_info *info, + const uint8_t *hash, + uint8_t *sig, uint sig_len) +{ + return -ENXIO; +} + static inline int rsa_verify(struct image_sign_info *info, const struct image_region region[], int region_count, uint8_t *sig, uint sig_len) diff --git a/lib/rsa/rsa-verify.c b/lib/rsa/rsa-verify.c index 61d98e6e2d..6c4bbc4625 100644 --- a/lib/rsa/rsa-verify.c +++ b/lib/rsa/rsa-verify.c @@ -478,33 +478,11 @@ static int rsa_verify_with_keynode(struct image_sign_info *info, } #endif -int rsa_verify(struct image_sign_info *info, - const struct image_region region[], int region_count, - uint8_t *sig, uint sig_len) +int rsa_verify_hash(struct image_sign_info *info, + const uint8_t *hash, uint8_t *sig, uint sig_len) { - /* Reserve memory for maximum checksum-length */ - uint8_t hash[info->crypto->key_len]; int ret = -EACCES; - /* - * Verify that the checksum-length does not exceed the - * rsa-signature-length - */ - if (info->checksum->checksum_len > - info->crypto->key_len) { - debug("%s: invlaid checksum-algorithm %s for %s\n", - __func__, info->checksum->name, info->crypto->name); - return -EINVAL; - } - - /* Calculate checksum with checksum-algorithm */ - ret = info->checksum->calculate(info->checksum->name, - region, region_count, hash); - if (ret < 0) { - debug("%s: Error in checksum calculation\n", __func__); - return -EINVAL; - } - if (CONFIG_IS_ENABLED(RSA_VERIFY_WITH_PKEY) && !info->fdt_blob) { /* don't rely on fdt properties */ ret = rsa_verify_with_pkey(info, hash, sig, sig_len); @@ -555,3 +533,33 @@ int rsa_verify(struct image_sign_info *info, return ret; } + +int rsa_verify(struct image_sign_info *info, + const struct image_region region[], int region_count, + uint8_t *sig, uint sig_len) +{ + /* Reserve memory for maximum checksum-length */ + uint8_t hash[info->crypto->key_len]; + int ret = -EACCES; + + /* + * Verify that the checksum-length does not exceed the + * rsa-signature-length + */ + if (info->checksum->checksum_len > + info->crypto->key_len) { + debug("%s: invlaid checksum-algorithm %s for %s\n", + __func__, info->checksum->name, info->crypto->name); + return -EINVAL; + } + + /* Calculate checksum with checksum-algorithm */ + ret = info->checksum->calculate(info->checksum->name, + region, region_count, hash); + if (ret < 0) { + debug("%s: Error in checksum calculation\n", __func__); + return -EINVAL; + } + + return rsa_verify_hash(info, hash, sig, sig_len); +}