[PATCH 00/18] Various bugfixes related to verified boot

This series collects together various misc patches that were needed when building mainline U-Boot against Chromium OS verified boot. Most of them fix minor bugs.
Simon Glass (18): buildman: Update default config to build for sandbox buildman: Fix up cfgutil binman: Correct Chromium OS entry types errno: Avoid including strings in SPL abuf: Correct a corner case with abuf_realloc() fdt: Correct condition for SEPARATE_BSS fdt: sandbox: Avoid looking for an appended device tree lzma: Tidy up the function prototype cbfs: Add some more definititions cros_ec: Complete the comment for cros_ec_read_batt_charge() spi: Avoid checking console in SPL disk: Correct the conditions for SPL Add a default for TPL_TEXT_BASE Make ASYMMETRIC_KEY_TYPE depend on FIT_SIGNATURE stdint: Add a definition of UINT8_MAX dm: core: Add a required struct declaration dm: core: Tidy up comments in uclass headers dm: blk: Expand iteration and add tests
common/spl/Kconfig | 1 + disk/Makefile | 10 +-- drivers/block/blk-uclass.c | 24 +++++++ drivers/mtd/spi/spi-nor-core.c | 2 +- include/blk.h | 45 +++++++++++++ include/cbfs.h | 43 +++++++++++++ include/cros_ec.h | 1 + include/dm/device-internal.h | 1 + include/dm/uclass-internal.h | 18 +++--- include/dm/uclass.h | 13 ++-- include/errno.h | 2 +- include/stdint.h | 7 +++ lib/abuf.c | 4 +- lib/crypto/Kconfig | 1 + lib/fdtdec.c | 5 +- lib/lzma/LzmaTools.c | 4 +- lib/lzma/LzmaTools.h | 17 ++++- test/dm/blk.c | 111 +++++++++++++++++++++++++++++++++ test/lib/abuf.c | 29 +++++++++ tools/binman/btool/futility.py | 4 +- tools/binman/etype/vblock.py | 2 +- tools/buildman/bsettings.py | 1 + tools/buildman/cfgutil.py | 4 +- 23 files changed, 315 insertions(+), 34 deletions(-)

At present the default .buildman file written by buildman does not specify a default toolchain. Add an 'other' line so this works correctly and sandbox builds run as expected.
Signed-off-by: Simon Glass sjg@chromium.org ---
tools/buildman/bsettings.py | 1 + 1 file changed, 1 insertion(+)
diff --git a/tools/buildman/bsettings.py b/tools/buildman/bsettings.py index 0b7208da37..e634bbb279 100644 --- a/tools/buildman/bsettings.py +++ b/tools/buildman/bsettings.py @@ -74,6 +74,7 @@ def CreateBuildmanConfigFile(config_fname): print('''[toolchain] # name = path # e.g. x86 = /opt/gcc-4.6.3-nolibc/x86_64-linux +other = /
[toolchain-prefix] # name = path to prefix

On Mon, Feb 28, 2022 at 12:08:18PM -0700, Simon Glass wrote:
At present the default .buildman file written by buildman does not specify a default toolchain. Add an 'other' line so this works correctly and sandbox builds run as expected.
Signed-off-by: Simon Glass sjg@chromium.org
For the series, applied to u-boot/master, thanks!

The name of this function changed at the same time as this file was added. Fix the naming.
Signed-off-by: Simon Glass sjg@chromium.org ---
tools/buildman/cfgutil.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/tools/buildman/cfgutil.py b/tools/buildman/cfgutil.py index 4eba50868f..166b7b2419 100644 --- a/tools/buildman/cfgutil.py +++ b/tools/buildman/cfgutil.py @@ -123,7 +123,7 @@ def adjust_cfg_file(fname, adjust_cfg): C=val to set the value of C (val must have quotes if C is a string Kconfig) """ - lines = tools.ReadFile(fname, binary=False).splitlines() + lines = tools.read_file(fname, binary=False).splitlines() out_lines = adjust_cfg_lines(lines, adjust_cfg) out = '\n'.join(out_lines) + '\n' tools.WriteFile(fname, out, binary=False) @@ -219,7 +219,7 @@ def check_cfg_file(fname, adjust_cfg): Returns: str: None if OK, else an error string listing the problems """ - lines = tools.ReadFile(fname, binary=False).splitlines() + lines = tools.read_file(fname, binary=False).splitlines() bad_cfgs = check_cfg_lines(lines, adjust_cfg) if bad_cfgs: out = [f'{cfg:20} {line}' for cfg, line in bad_cfgs]

The conversion to bintools broke the invocation of the utility, since the arguments are not correct. Fix it.
Signed-off-by: Simon Glass sjg@chromium.org ---
tools/binman/btool/futility.py | 4 ++-- tools/binman/etype/vblock.py | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/tools/binman/btool/futility.py b/tools/binman/btool/futility.py index 614daaade4..8d00966a9d 100644 --- a/tools/binman/btool/futility.py +++ b/tools/binman/btool/futility.py @@ -106,7 +106,7 @@ class Bintoolfutility(bintool.Bintool): Returns: str: Tool output """ - args = ['gbb_utility' + args = ['gbb_utility', '-s', f'--hwid={hwid}', f'--rootkey={rootkey}', @@ -139,7 +139,7 @@ class Bintoolfutility(bintool.Bintool): '--keyblock', keyblock, '--signprivate', signprivate, '--version', version, - '--fw', firmware, + '--fv', firmware, '--kernelkey', kernelkey, '--flags', flags ] diff --git a/tools/binman/etype/vblock.py b/tools/binman/etype/vblock.py index a1de98290b..0074c577a2 100644 --- a/tools/binman/etype/vblock.py +++ b/tools/binman/etype/vblock.py @@ -73,7 +73,7 @@ class Entry_vblock(Entry_collection): vblock=output_fname, keyblock=prefix + self.keyblock, signprivate=prefix + self.signprivate, - version=f'{self.version,}', + version=f'{self.version:d}', firmware=input_fname, kernelkey=prefix + self.kernelkey, flags=f'{self.preamble_flags}')

At present the header file defines this function in SPL but the file may not actually be built. This causes a build error if the option is enabled.
Fix the condition in the header file.
Signed-off-by: Simon Glass sjg@chromium.org ---
include/errno.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/include/errno.h b/include/errno.h index 652ad67306..5a8816d0a1 100644 --- a/include/errno.h +++ b/include/errno.h @@ -25,7 +25,7 @@ extern int errno __errno_asm_label; * Return: string describing the error. If CONFIG_ERRNO_STR is not * defined an empty string is returned. */ -#ifdef CONFIG_ERRNO_STR +#if CONFIG_IS_ENABLED(ERRNO_STR) const char *errno_str(int errno); #else static const char error_message[] = "";

If the buffer is empty and not allocated, then abuf_realloc() tries to copy invalid data. This happens because an incorrect change to use memdup() was added after the original code was written.
Signed-off-by: Simon Glass sjg@chromium.org ---
lib/abuf.c | 4 +++- test/lib/abuf.c | 29 +++++++++++++++++++++++++++++ 2 files changed, 32 insertions(+), 1 deletion(-)
diff --git a/lib/abuf.c b/lib/abuf.c index 4b17e0b8c0..1635d58682 100644 --- a/lib/abuf.c +++ b/lib/abuf.c @@ -51,9 +51,11 @@ bool abuf_realloc(struct abuf *abuf, size_t new_size) /* not currently allocated and new size is larger. Alloc and * copy in data. The new space is not inited. */ - ptr = memdup(abuf->data, new_size); + ptr = malloc(new_size); if (!ptr) return false; + if (abuf->size) + memcpy(ptr, abuf->data, abuf->size); abuf->data = ptr; abuf->size = new_size; abuf->alloced = true; diff --git a/test/lib/abuf.c b/test/lib/abuf.c index 086c9b2282..42ee4c1755 100644 --- a/test/lib/abuf.c +++ b/test/lib/abuf.c @@ -126,6 +126,35 @@ static int lib_test_abuf_realloc(struct unit_test_state *uts) } LIB_TEST(lib_test_abuf_realloc, 0);
+/* Test abuf_realloc() on an non-allocated buffer of zero size */ +static int lib_test_abuf_realloc_size(struct unit_test_state *uts) +{ + struct abuf buf; + ulong start; + + start = ut_check_free(); + + abuf_init(&buf); + + /* Allocate some space */ + ut_asserteq(true, abuf_realloc(&buf, TEST_DATA_LEN)); + ut_assertnonnull(buf.data); + ut_asserteq(TEST_DATA_LEN, buf.size); + ut_asserteq(true, buf.alloced); + + /* Free it */ + ut_asserteq(true, abuf_realloc(&buf, 0)); + ut_assertnull(buf.data); + ut_asserteq(0, buf.size); + ut_asserteq(false, buf.alloced); + + /* Check for memory leaks */ + ut_assertok(ut_check_delta(start)); + + return 0; +} +LIB_TEST(lib_test_abuf_realloc_size, 0); + /* Test handling of buffers that are too large */ static int lib_test_abuf_large(struct unit_test_state *uts) {

This may have different settings for SPL and TPL. Correct the condition.
Signed-off-by: Simon Glass sjg@chromium.org ---
lib/fdtdec.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/lib/fdtdec.c b/lib/fdtdec.c index 87aa677a4a..086f0c732a 100644 --- a/lib/fdtdec.c +++ b/lib/fdtdec.c @@ -1227,7 +1227,7 @@ static void *fdt_find_separate(void)
#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)) + if (CONFIG_IS_ENABLED(SEPARATE_BSS)) fdt_blob = (ulong *)&_image_binary_end; else fdt_blob = (ulong *)&__bss_end;

We don't use an appended tree for sandbox and the required symbols are not present. Add a condition to avoid a build error.
Signed-off-by: Simon Glass sjg@chromium.org ---
lib/fdtdec.c | 3 +++ 1 file changed, 3 insertions(+)
diff --git a/lib/fdtdec.c b/lib/fdtdec.c index 086f0c732a..0c0ec034ec 100644 --- a/lib/fdtdec.c +++ b/lib/fdtdec.c @@ -1225,6 +1225,9 @@ static void *fdt_find_separate(void) { void *fdt_blob = NULL;
+ if (IS_ENABLED(CONFIG_SANDBOX)) + return NULL; + #ifdef CONFIG_SPL_BUILD /* FDT is at end of BSS unless it is in a different memory region */ if (CONFIG_IS_ENABLED(SEPARATE_BSS))

This should use a const pointer for the input stream. Fix this and also add a proper comment.
Signed-off-by: Simon Glass sjg@chromium.org ---
lib/lzma/LzmaTools.c | 4 ++-- lib/lzma/LzmaTools.h | 17 +++++++++++++++-- 2 files changed, 17 insertions(+), 4 deletions(-)
diff --git a/lib/lzma/LzmaTools.c b/lib/lzma/LzmaTools.c index 521258e623..af88900d31 100644 --- a/lib/lzma/LzmaTools.c +++ b/lib/lzma/LzmaTools.c @@ -37,8 +37,8 @@ static void *SzAlloc(void *p, size_t size) { return malloc(size); } static void SzFree(void *p, void *address) { free(address); }
-int lzmaBuffToBuffDecompress (unsigned char *outStream, SizeT *uncompressedSize, - unsigned char *inStream, SizeT length) +int lzmaBuffToBuffDecompress(unsigned char *outStream, SizeT *uncompressedSize, + const unsigned char *inStream, SizeT length) { int res = SZ_ERROR_DATA; int i; diff --git a/lib/lzma/LzmaTools.h b/lib/lzma/LzmaTools.h index e52dfb8fac..2c46859a62 100644 --- a/lib/lzma/LzmaTools.h +++ b/lib/lzma/LzmaTools.h @@ -13,6 +13,19 @@
#include <lzma/LzmaTypes.h>
-extern int lzmaBuffToBuffDecompress (unsigned char *outStream, SizeT *uncompressedSize, - unsigned char *inStream, SizeT length); +/** + * lzmaBuffToBuffDecompress() - Decompress LZMA data + * + * @outStream: output buffer + * @uncompressedSize: On entry, the mnaximum uncompressed size of the data; + * on exit, the actual uncompressed size after processing + * @inStream: Compressed bytes to decompress + * @length: Sizeof @inStream + * @return 0 if OK, SZ_ERROR_DATA if the data is in a format that cannot be + * decompressed; SZ_ERROR_OUTPUT_EOF if *uncompressedSize is too small; + * see also other SZ_ERROR... values + */ +int lzmaBuffToBuffDecompress(unsigned char *outStream, SizeT *uncompressedSize, + const unsigned char *inStream, SizeT length); + #endif

Add definitions for a payload or 'self', which is like an unpacked ELF file.
Signed-off-by: Simon Glass sjg@chromium.org ---
include/cbfs.h | 43 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+)
diff --git a/include/cbfs.h b/include/cbfs.h index 7449873b49..38efb1d2b0 100644 --- a/include/cbfs.h +++ b/include/cbfs.h @@ -24,6 +24,8 @@ enum cbfs_filetype { CBFS_TYPE_CBFSHEADER = 0x02, CBFS_TYPE_STAGE = 0x10, CBFS_TYPE_PAYLOAD = 0x20, + CBFS_TYPE_SELF = CBFS_TYPE_PAYLOAD, + CBFS_TYPE_FIT = 0x21, CBFS_TYPE_OPTIONROM = 0x30, CBFS_TYPE_BOOTSPLASH = 0x40, @@ -120,6 +122,47 @@ struct cbfs_file_attr_hash { u8 hash_data[]; } __packed;
+/*** Component sub-headers ***/ + +/* Following are component sub-headers for the "standard" component types */ + +/** + * struct cbfs_stage - sub-header for stage components + * + * Stages are loaded by coreboot during the normal boot process + */ +struct cbfs_stage { + u32 compression; /** Compression type */ + u64 entry; /** entry point */ + u64 load; /** Where to load in memory */ + u32 len; /** length of data to load */ + u32 memlen; /** total length of object in memory */ +} __packed; + +/** + * struct cbfs_payload_segment - sub-header for payload components + * + * Payloads are loaded by coreboot at the end of the boot process + */ +struct cbfs_payload_segment { + u32 type; + u32 compression; + u32 offset; + u64 load_addr; + u32 len; + u32 mem_len; +} __packed; + +struct cbfs_payload { + struct cbfs_payload_segment segments; +}; + +#define PAYLOAD_SEGMENT_CODE 0x45444F43 +#define PAYLOAD_SEGMENT_DATA 0x41544144 +#define PAYLOAD_SEGMENT_BSS 0x20535342 +#define PAYLOAD_SEGMENT_PARAMS 0x41524150 +#define PAYLOAD_SEGMENT_ENTRY 0x52544E45 + struct cbfs_cachenode { struct cbfs_cachenode *next; void *data;

Add the missing 'Return' information.
Signed-off-by: Simon Glass sjg@chromium.org ---
include/cros_ec.h | 1 + 1 file changed, 1 insertion(+)
diff --git a/include/cros_ec.h b/include/cros_ec.h index 2a7728622c..94c988a7d6 100644 --- a/include/cros_ec.h +++ b/include/cros_ec.h @@ -648,6 +648,7 @@ int cros_ec_vstore_write(struct udevice *dev, int slot, const uint8_t *data, * * @dev: CROS-EC device * @chargep: Return battery-charge state as a percentage + * Return: 0 if OK, -ve on error */ int cros_ec_read_batt_charge(struct udevice *dev, uint *chargep);

When SPI flash is used in SPL there is no console, so ctrlc() cannot be called. Add a condition to fix this.
Signed-off-by: Simon Glass sjg@chromium.org ---
drivers/mtd/spi/spi-nor-core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/mtd/spi/spi-nor-core.c b/drivers/mtd/spi/spi-nor-core.c index a70fbda4bb..3b7c817c02 100644 --- a/drivers/mtd/spi/spi-nor-core.c +++ b/drivers/mtd/spi/spi-nor-core.c @@ -929,7 +929,7 @@ static int spi_nor_erase(struct mtd_info *mtd, struct erase_info *instr)
while (len) { WATCHDOG_RESET(); - if (ctrlc()) { + if (!IS_ENABLED(CONFIG_SPL_BUILD) && ctrlc()) { addr_known = false; ret = -EINTR; goto erase_err;

These filesystems may have different settings for SPL and TPL. Use the correct Makefile variable to handle this.
Signed-off-by: Simon Glass sjg@chromium.org ---
disk/Makefile | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-)
diff --git a/disk/Makefile b/disk/Makefile index 6ce5a687b3..83f5af6069 100644 --- a/disk/Makefile +++ b/disk/Makefile @@ -6,8 +6,8 @@ #ccflags-y += -DET_DEBUG -DDEBUG
obj-$(CONFIG_PARTITIONS) += part.o -obj-$(CONFIG_$(SPL_)MAC_PARTITION) += part_mac.o -obj-$(CONFIG_$(SPL_)DOS_PARTITION) += part_dos.o -obj-$(CONFIG_$(SPL_)ISO_PARTITION) += part_iso.o -obj-$(CONFIG_$(SPL_)AMIGA_PARTITION) += part_amiga.o -obj-$(CONFIG_$(SPL_)EFI_PARTITION) += part_efi.o +obj-$(CONFIG_$(SPL_TPL_)MAC_PARTITION) += part_mac.o +obj-$(CONFIG_$(SPL_TPL_)DOS_PARTITION) += part_dos.o +obj-$(CONFIG_$(SPL_TPL_)ISO_PARTITION) += part_iso.o +obj-$(CONFIG_$(SPL_TPL_)AMIGA_PARTITION) += part_amiga.o +obj-$(CONFIG_$(SPL_TPL_)EFI_PARTITION) += part_efi.o

If this value is not provided it causes a hang in the build. Add a default value to avoid this.
Signed-off-by: Simon Glass sjg@chromium.org ---
common/spl/Kconfig | 1 + 1 file changed, 1 insertion(+)
diff --git a/common/spl/Kconfig b/common/spl/Kconfig index 9418d37b2e..b59215fe4f 100644 --- a/common/spl/Kconfig +++ b/common/spl/Kconfig @@ -1412,6 +1412,7 @@ config TPL_POWER
config TPL_TEXT_BASE hex "Base address for the .text section of the TPL stage" + default 0 help The base address for the .text section of the TPL stage.

Add this dependency to avoid a build error if FIT_SIGNATURE is not enabled.
Signed-off-by: Simon Glass sjg@chromium.org ---
lib/crypto/Kconfig | 1 + 1 file changed, 1 insertion(+)
diff --git a/lib/crypto/Kconfig b/lib/crypto/Kconfig index 6369bafac0..5c6e964862 100644 --- a/lib/crypto/Kconfig +++ b/lib/crypto/Kconfig @@ -1,5 +1,6 @@ menuconfig ASYMMETRIC_KEY_TYPE bool "Asymmetric (public-key cryptographic) key Support" + depends on FIT_SIGNATURE help This option provides support for a key type that holds the data for the asymmetric keys used for public key cryptographic operations such

Simon,
On Mon, Feb 28, 2022 at 12:08:31PM -0700, Simon Glass wrote:
Add this dependency to avoid a build error if FIT_SIGNATURE is not enabled.
I doubt it. With qemu_arm64_defconfig & ASYMMETRIC_KEY_TYPE & !FIT_SIGNATURE, I don't see any build error on 2022.04-rc2.
-Takahiro Akashi
Signed-off-by: Simon Glass sjg@chromium.org
lib/crypto/Kconfig | 1 + 1 file changed, 1 insertion(+)
diff --git a/lib/crypto/Kconfig b/lib/crypto/Kconfig index 6369bafac0..5c6e964862 100644 --- a/lib/crypto/Kconfig +++ b/lib/crypto/Kconfig @@ -1,5 +1,6 @@ menuconfig ASYMMETRIC_KEY_TYPE bool "Asymmetric (public-key cryptographic) key Support"
- depends on FIT_SIGNATURE help This option provides support for a key type that holds the data for the asymmetric keys used for public key cryptographic operations such
-- 2.35.1.574.g5d30c73bfb-goog

Hi Takahiro,
On Mon, 28 Feb 2022 at 21:22, AKASHI Takahiro takahiro.akashi@linaro.org wrote:
Simon,
On Mon, Feb 28, 2022 at 12:08:31PM -0700, Simon Glass wrote:
Add this dependency to avoid a build error if FIT_SIGNATURE is not enabled.
I doubt it. With qemu_arm64_defconfig & ASYMMETRIC_KEY_TYPE & !FIT_SIGNATURE, I don't see any build error on 2022.04-rc2.
This is what I see when building sandbox with Chromium OS verified boot (where FIT_SIGNATURE is not enabled).
/usr/bin/ld: lib/crypto/public_key.o: in function `public_key_verify_signature': lib/crypto/public_key.c:113: undefined reference to `image_get_padding_algo' /usr/bin/ld: lib/crypto/public_key.c:124: undefined reference to `image_get_checksum_algo' /usr/bin/ld: lib/crypto/public_key.c:126: undefined reference to `image_get_crypto_algo' /usr/bin/ld: lib/crypto/public_key.c:136: undefined reference to `rsa_verify_with_pkey' collect2: error: ld returned 1 exit status make[1]: *** [Makefile:1901: u-boot] Error 1
Regards, Simon [..]

Hi Simon,
On Fri, Mar 11, 2022 at 07:25:16PM -0700, Simon Glass wrote:
Hi Takahiro,
On Mon, 28 Feb 2022 at 21:22, AKASHI Takahiro takahiro.akashi@linaro.org wrote:
Simon,
On Mon, Feb 28, 2022 at 12:08:31PM -0700, Simon Glass wrote:
Add this dependency to avoid a build error if FIT_SIGNATURE is not enabled.
I doubt it. With qemu_arm64_defconfig & ASYMMETRIC_KEY_TYPE & !FIT_SIGNATURE, I don't see any build error on 2022.04-rc2.
This is what I see when building sandbox with Chromium OS verified boot (where FIT_SIGNATURE is not enabled).
/usr/bin/ld: lib/crypto/public_key.o: in function `public_key_verify_signature': lib/crypto/public_key.c:113: undefined reference to `image_get_padding_algo' /usr/bin/ld: lib/crypto/public_key.c:124: undefined reference to `image_get_checksum_algo' /usr/bin/ld: lib/crypto/public_key.c:126: undefined reference to `image_get_crypto_algo'
After my commit b983cc2da0ba ("lib: rsa: decouple rsa from FIT image verification"), those symbols are independently compiled in with CONFIG_IMAGE_SIGN_INFO.
/usr/bin/ld: lib/crypto/public_key.c:136: undefined reference to `rsa_verify_with_pkey'
Likewise, please select CONFIG_RSA_VERIFY_WITH_PKEY specifically instead of CONFIG_FIT_SIGNATURE.
-Takahiro Akashi
collect2: error: ld returned 1 exit status make[1]: *** [Makefile:1901: u-boot] Error 1
Regards, Simon [..]

This is normally defined in stdint.h but is not used in U-Boot. When libraries (such as Chromium OS vboot) are built against U-Boot they may expect this value to be available. Add it to avoid build errors in this case.
Signed-off-by: Simon Glass sjg@chromium.org ---
include/stdint.h | 7 +++++++ 1 file changed, 7 insertions(+)
diff --git a/include/stdint.h b/include/stdint.h index 2e126d14bd..dea83c8226 100644 --- a/include/stdint.h +++ b/include/stdint.h @@ -5,3 +5,10 @@ * * U-Boot uses linux types (linux/types.h) so does not make use of stdint.h */ + +#ifndef __UB_STDINT_H +#define __UB_STDINT_H + +#define UINT8_MAX 0xff + +#endif

This file uses struct driver, so declare it at the top in case the header-inclusion order is not as expected.
Signed-off-by: Simon Glass sjg@chromium.org ---
include/dm/device-internal.h | 1 + 1 file changed, 1 insertion(+)
diff --git a/include/dm/device-internal.h b/include/dm/device-internal.h index 02002acb78..46ae0e1f1f 100644 --- a/include/dm/device-internal.h +++ b/include/dm/device-internal.h @@ -14,6 +14,7 @@ #include <dm/ofnode.h>
struct device_node; +struct driver_info; struct udevice;
/*

Improve some of the comments in these files, which don't follow the correct style.
Signed-off-by: Simon Glass sjg@chromium.org ---
include/dm/uclass-internal.h | 18 +++++++++--------- include/dm/uclass.h | 13 ++++++------- 2 files changed, 15 insertions(+), 16 deletions(-)
diff --git a/include/dm/uclass-internal.h b/include/dm/uclass-internal.h index e71b86a973..daf856c03c 100644 --- a/include/dm/uclass-internal.h +++ b/include/dm/uclass-internal.h @@ -55,7 +55,7 @@ * * @_name: Name of the uclass. This must be a valid C identifier, used by the * linker_list - * @returns struct uclass * for the device + * Return: struct uclass * for the device */ #define DM_UCLASS_REF(_name) \ ll_entry_ref(struct uclass, _name, uclass) @@ -120,7 +120,7 @@ int dev_get_uclass_index(struct udevice *dev, struct uclass **ucp); * uclass_find_device() - Return n-th child of uclass * @id: Id number of the uclass * @index: Position of the child in uclass's list - * #devp: Returns pointer to device, or NULL on error + * @devp: Returns pointer to device, or NULL on error * * The device is not prepared for use - this is an internal function. * The function uclass_get_device_tail() can be used to probe the device. @@ -133,7 +133,7 @@ int uclass_find_device(enum uclass_id id, int index, struct udevice **devp); /** * uclass_find_first_device() - Return the first device in a uclass * @id: Id number of the uclass - * #devp: Returns pointer to device, or NULL on error + * @devp: Returns pointer to device, or NULL on error * * The device is not prepared for use - this is an internal function. * The function uclass_get_device_tail() can be used to probe the device. @@ -239,7 +239,7 @@ int uclass_find_device_by_phandle(enum uclass_id id, struct udevice *parent, * Connect the device into uclass's list of devices. * * @dev: Pointer to the device - * #return 0 on success, -ve on error + * Return: 0 on success, -ve on error */ int uclass_bind_device(struct udevice *dev);
@@ -250,7 +250,7 @@ int uclass_bind_device(struct udevice *dev); * Call any handled needed before uclass_unbind_device() is called * * @dev: Pointer to the device - * #return 0 on success, -ve on error + * Return: 0 on success, -ve on error */ int uclass_pre_unbind_device(struct udevice *dev);
@@ -260,7 +260,7 @@ int uclass_pre_unbind_device(struct udevice *dev); * Disconnect the device from uclass's list of devices. * * @dev: Pointer to the device - * #return 0 on success, -ve on error + * Return: 0 on success, -ve on error */ int uclass_unbind_device(struct udevice *dev);
@@ -277,7 +277,7 @@ static inline int uclass_unbind_device(struct udevice *dev) { return 0; } * uclass' child_pre_probe() method. * * @dev: Pointer to the device - * #return 0 on success, -ve on error + * Return: 0 on success, -ve on error */ int uclass_pre_probe_device(struct udevice *dev);
@@ -288,7 +288,7 @@ int uclass_pre_probe_device(struct udevice *dev); * uclass. * * @dev: Pointer to the device - * #return 0 on success, -ve on error + * Return: 0 on success, -ve on error */ int uclass_post_probe_device(struct udevice *dev);
@@ -298,7 +298,7 @@ int uclass_post_probe_device(struct udevice *dev); * Perform any pre-processing of a device that is about to be removed. * * @dev: Pointer to the device - * #return 0 on success, -ve on error + * Return: 0 on success, -ve on error */ #if CONFIG_IS_ENABLED(DM_DEVICE_REMOVE) int uclass_pre_remove_device(struct udevice *dev); diff --git a/include/dm/uclass.h b/include/dm/uclass.h index 7f33c34214..aafe652288 100644 --- a/include/dm/uclass.h +++ b/include/dm/uclass.h @@ -435,7 +435,7 @@ int uclass_probe_all(enum uclass_id id); int uclass_id_count(enum uclass_id id);
/** - * uclass_id_foreach_dev() - Helper function to iteration through devices + * uclass_id_foreach_dev() - iterate through devices of a given uclass ID * * This creates a for() loop which works through the available devices in * a uclass ID in order from start to end. @@ -452,20 +452,20 @@ int uclass_id_count(enum uclass_id id); list_for_each_entry(pos, &uc->dev_head, uclass_node)
/** - * uclass_foreach_dev() - Helper function to iteration through devices + * uclass_foreach_dev() - iterate through devices of a given uclass * * This creates a for() loop which works through the available devices in * a uclass in order from start to end. * * @pos: struct udevice * to hold the current device. Set to NULL when there * are no more devices. - * @uc: uclass to scan + * @uc: uclass to scan (`struct uclass *`) */ #define uclass_foreach_dev(pos, uc) \ list_for_each_entry(pos, &uc->dev_head, uclass_node)
/** - * uclass_foreach_dev_safe() - Helper function to safely iteration through devs + * uclass_foreach_dev_safe() - safely iterate through devices of a given uclass * * This creates a for() loop which works through the available devices in * a uclass in order from start to end. Inside the loop, it is safe to remove @@ -474,14 +474,13 @@ int uclass_id_count(enum uclass_id id); * @pos: struct udevice * to hold the current device. Set to NULL when there * are no more devices. * @next: struct udevice * to hold the next next - * @uc: uclass to scan + * @uc: uclass to scan (`struct uclass *`) */ #define uclass_foreach_dev_safe(pos, next, uc) \ list_for_each_entry_safe(pos, next, &uc->dev_head, uclass_node)
/** - * uclass_foreach_dev_probe() - Helper function to iteration through devices - * of given uclass + * uclass_foreach_dev_probe() - iterate through devices of a given uclass ID * * This creates a for() loop which works through the available devices in * a uclass in order from start to end. Devices are probed if necessary,

Add some functions which support iteration before probing. Also add tests for the functions.
Signed-off-by: Simon Glass sjg@chromium.org ---
drivers/block/blk-uclass.c | 24 ++++++++ include/blk.h | 45 +++++++++++++++ test/dm/blk.c | 111 +++++++++++++++++++++++++++++++++++++ 3 files changed, 180 insertions(+)
diff --git a/drivers/block/blk-uclass.c b/drivers/block/blk-uclass.c index bee1cd6f0d..84502bb47c 100644 --- a/drivers/block/blk-uclass.c +++ b/drivers/block/blk-uclass.c @@ -552,6 +552,30 @@ static int blk_flags_check(struct udevice *dev, enum blk_flag_t req_flags) return flags & req_flags ? 0 : 1; }
+int blk_find_first(enum blk_flag_t flags, struct udevice **devp) +{ + int ret; + + for (ret = uclass_find_first_device(UCLASS_BLK, devp); + *devp && !blk_flags_check(*devp, flags); + ret = uclass_find_next_device(devp)) + return 0; + + return -ENODEV; +} + +int blk_find_next(enum blk_flag_t flags, struct udevice **devp) +{ + int ret; + + for (ret = uclass_find_next_device(devp); + *devp && !blk_flags_check(*devp, flags); + ret = uclass_find_next_device(devp)) + return 0; + + return -ENODEV; +} + int blk_first_device_err(enum blk_flag_t flags, struct udevice **devp) { int ret; diff --git a/include/blk.h b/include/blk.h index d06098bc13..dbe9ae219d 100644 --- a/include/blk.h +++ b/include/blk.h @@ -731,6 +731,51 @@ int blk_first_device_err(enum blk_flag_t flags, struct udevice **devp); */ int blk_next_device_err(enum blk_flag_t flags, struct udevice **devp);
+/** + * blk_find_first() - Return the first matching block device + * @flags: Indicates type of device to return + * @devp: Returns pointer to device, or NULL on error + * + * The device is not prepared for use - this is an internal function. + * The function uclass_get_device_tail() can be used to probe the device. + * + * Note that some devices are considered removable until they have been probed + * + * @return 0 if found, -ENODEV if not found + */ +int blk_find_first(enum blk_flag_t flags, struct udevice **devp); + +/** + * blk_find_next() - Return the next matching block device + * @flags: Indicates type of device to return + * @devp: On entry, pointer to device to lookup. On exit, returns pointer + * to the next device in the same uclass, or NULL if none + * + * The device is not prepared for use - this is an internal function. + * The function uclass_get_device_tail() can be used to probe the device. + * + * Note that some devices are considered removable until they have been probed + * + * @return 0 if found, -ENODEV if not found + */ +int blk_find_next(enum blk_flag_t flags, struct udevice **devp); + +/** + * blk_foreach() - iterate through block devices + * + * This creates a for() loop which works through the available block devices in + * order from start to end. + * + * If for some reason the uclass cannot be found, this does nothing. + * + * @_flags: Indicates type of device to return + * @_pos: struct udevice * to hold the current device. Set to NULL when there + * are no more devices. + */ +#define blk_foreach(_flags, _pos) \ + for (int _ret = blk_find_first(_flags, &_pos); !_ret && _pos; \ + _ret = blk_find_next(_flags, &_pos)) + /** * blk_foreach_probe() - Helper function to iteration through block devices * diff --git a/test/dm/blk.c b/test/dm/blk.c index deccf05289..8556cc7159 100644 --- a/test/dm/blk.c +++ b/test/dm/blk.c @@ -217,3 +217,114 @@ static int dm_test_blk_iter(struct unit_test_state *uts) return 0; } DM_TEST(dm_test_blk_iter, UT_TESTF_SCAN_PDATA | UT_TESTF_SCAN_FDT); + +/* Test finding fixed/removable block devices */ +static int dm_test_blk_flags(struct unit_test_state *uts) +{ + struct udevice *dev; + + /* Iterate through devices without probing them */ + ut_assertok(blk_find_first(BLKF_BOTH, &dev)); + ut_assertnonnull(dev); + ut_asserteq_str("mmc2.blk", dev->name); + + ut_assertok(blk_find_next(BLKF_BOTH, &dev)); + ut_assertnonnull(dev); + ut_asserteq_str("mmc1.blk", dev->name); + + ut_assertok(blk_find_next(BLKF_BOTH, &dev)); + ut_assertnonnull(dev); + ut_asserteq_str("mmc0.blk", dev->name); + + ut_asserteq(-ENODEV, blk_find_next(BLKF_BOTH, &dev)); + ut_assertnull(dev); + + /* All devices are removable until probed */ + ut_asserteq(-ENODEV, blk_find_first(BLKF_FIXED, &dev)); + + ut_assertok(blk_find_first(BLKF_REMOVABLE, &dev)); + ut_assertnonnull(dev); + ut_asserteq_str("mmc2.blk", dev->name); + + /* Now probe them and iterate again */ + ut_assertok(blk_first_device_err(BLKF_BOTH, &dev)); + ut_assertnonnull(dev); + ut_asserteq_str("mmc2.blk", dev->name); + + ut_assertok(blk_next_device_err(BLKF_BOTH, &dev)); + ut_assertnonnull(dev); + ut_asserteq_str("mmc1.blk", dev->name); + + ut_assertok(blk_next_device_err(BLKF_BOTH, &dev)); + ut_assertnonnull(dev); + ut_asserteq_str("mmc0.blk", dev->name); + + ut_asserteq(-ENODEV, blk_next_device_err(BLKF_BOTH, &dev)); + + /* Look only for fixed devices */ + ut_assertok(blk_first_device_err(BLKF_FIXED, &dev)); + ut_assertnonnull(dev); + ut_asserteq_str("mmc2.blk", dev->name); + + ut_asserteq(-ENODEV, blk_next_device_err(BLKF_FIXED, &dev)); + + /* Look only for removable devices */ + ut_assertok(blk_first_device_err(BLKF_REMOVABLE, &dev)); + ut_assertnonnull(dev); + ut_asserteq_str("mmc1.blk", dev->name); + + ut_assertok(blk_next_device_err(BLKF_REMOVABLE, &dev)); + ut_assertnonnull(dev); + ut_asserteq_str("mmc0.blk", dev->name); + + ut_asserteq(-ENODEV, blk_next_device_err(BLKF_REMOVABLE, &dev)); + + return 0; +} +DM_TEST(dm_test_blk_flags, UT_TESTF_SCAN_PDATA | UT_TESTF_SCAN_FDT); + +/* Test blk_foreach() and friend */ +static int dm_test_blk_foreach(struct unit_test_state *uts) +{ + struct udevice *dev; + int found; + + /* Test blk_foreach() - use the 3rd bytes of the name (0/1/2) */ + found = 0; + blk_foreach(BLKF_BOTH, dev) + found |= 1 << dectoul(&dev->name[3], NULL); + ut_asserteq(7, found); + + /* All devices are removable until probed */ + found = 0; + blk_foreach(BLKF_FIXED, dev) + found |= 1 << dectoul(&dev->name[3], NULL); + ut_asserteq(0, found); + + found = 0; + blk_foreach(BLKF_REMOVABLE, dev) + found |= 1 << dectoul(&dev->name[3], NULL); + ut_asserteq(7, found); + + /* Now try again with the probing functions */ + found = 0; + blk_foreach_probe(BLKF_BOTH, dev) + found |= 1 << dectoul(&dev->name[3], NULL); + ut_asserteq(7, found); + ut_asserteq(3, blk_count_devices(BLKF_BOTH)); + + found = 0; + blk_foreach_probe(BLKF_FIXED, dev) + found |= 1 << dectoul(&dev->name[3], NULL); + ut_asserteq(4, found); + ut_asserteq(1, blk_count_devices(BLKF_FIXED)); + + found = 0; + blk_foreach_probe(BLKF_REMOVABLE, dev) + found |= 1 << dectoul(&dev->name[3], NULL); + ut_asserteq(3, found); + ut_asserteq(2, blk_count_devices(BLKF_REMOVABLE)); + + return 0; +} +DM_TEST(dm_test_blk_foreach, UT_TESTF_SCAN_PDATA | UT_TESTF_SCAN_FDT);
participants (3)
-
AKASHI Takahiro
-
Simon Glass
-
Tom Rini