From 0872ac098a400632f02ae442dde65d77cc7eb1cb Mon Sep 17 00:00:00 2001 From: Neil Armstrong Date: Tue, 1 Oct 2024 18:06:11 +0200 Subject: [PATCH 01/11] spi: add DM_SPI_FLASH compatibility inline functions To smoothly handle the transition from the legacy SPI FLASH API to the driver model API, add the DM functions as dummy inline functions. Today, client code uses #if/#else conditionals, but it's better to use if(IS_ENABLED()) to make sure all code builds fine and avoid configuration hell, leaving the compiler remove the dead code. An example is cmd/sf, which could make use of those dummy functions to drop the conditional compilation. Signed-off-by: Neil Armstrong Reviewed-by: Mattijs Korpershoek Link: https://lore.kernel.org/r/20241001-uboot-topic-dfu-sf-dt-v2-1-67f7acfa3ff5@linaro.org [mkorpershoek: removed duplicate "the" from commit msg] Signed-off-by: Mattijs Korpershoek --- include/spi_flash.h | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/include/spi_flash.h b/include/spi_flash.h index 10d19fd4b1..2e703e8525 100644 --- a/include/spi_flash.h +++ b/include/spi_flash.h @@ -139,6 +139,40 @@ int sandbox_sf_bind_emul(struct sandbox_state *state, int busnum, int cs, void sandbox_sf_unbind_emul(struct sandbox_state *state, int busnum, int cs); #else +/* Compatibility functions for when DM_SPI_FLASH is disabled */ +static inline int spi_flash_probe_bus_cs(unsigned int busnum, unsigned int cs, + struct udevice **devp) +{ + return -ENODEV; +} + +static inline int spi_flash_read_dm(struct udevice *dev, u32 offset, size_t len, + void *buf) +{ + return -ENODEV; +} + +static inline int spi_flash_write_dm(struct udevice *dev, u32 offset, size_t len, + const void *buf) +{ + return -ENODEV; +} + +static inline int spi_flash_erase_dm(struct udevice *dev, u32 offset, size_t len) +{ + return -ENODEV; +} + +static inline int spl_flash_get_sw_write_prot(struct udevice *dev) +{ + return -ENODEV; +} + +static inline int spi_flash_std_probe(struct udevice *dev) +{ + return -ENODEV; +} + struct spi_flash *spi_flash_probe(unsigned int bus, unsigned int cs, unsigned int max_hz, unsigned int spi_mode); From 97c29f868dd4e6d8f38d1cfdd964fb6b2b40267c Mon Sep 17 00:00:00 2001 From: Neil Armstrong Date: Tue, 1 Oct 2024 18:06:12 +0200 Subject: [PATCH 02/11] dfu: sf: rely on DT for spi speed and mode Align with cmd_sf, and try to rely on DT for spi speed and mode, and still fallback on spi_flash_probe() if it fails. With the current scheme, spi_flash_probe() will be called with CONFIG_SF_DEFAULT_SPEED and CONFIG_SF_DEFAULT_MODE with are set to 0 by default on DT platforms using DM_SPI_FLASH. Like cmd_sf, keep the option to specify the speed and mode from the dfu_alt_mode string, but rely on DT properties if not specified. Using CONFIG_SF_DEFAULT_SPEED and CONFIG_SF_DEFAULT_MODE makes the SPIFC controller on Amlogic Meson G12B & SM1 hardware fail and is unable to recover until a system reboot. Signed-off-by: Neil Armstrong Reviewed-by: Mattijs Korpershoek Link: https://lore.kernel.org/r/20241001-uboot-topic-dfu-sf-dt-v2-2-67f7acfa3ff5@linaro.org Signed-off-by: Mattijs Korpershoek --- drivers/dfu/dfu_sf.c | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/drivers/dfu/dfu_sf.c b/drivers/dfu/dfu_sf.c index 7c1c0f9e2d..8f7296adec 100644 --- a/drivers/dfu/dfu_sf.c +++ b/drivers/dfu/dfu_sf.c @@ -123,6 +123,7 @@ static struct spi_flash *parse_dev(char *devstr) unsigned int mode = CONFIG_SF_DEFAULT_MODE; char *s, *endp; struct spi_flash *dev; + bool use_dt = true; s = strsep(&devstr, ":"); if (!s || !*s || (bus = simple_strtoul(s, &endp, 0), *endp)) { @@ -143,6 +144,8 @@ static struct spi_flash *parse_dev(char *devstr) printf("Invalid SPI speed %s\n", s); return NULL; } + if (IS_ENABLED(CONFIG_DM_SPI_FLASH)) + use_dt = false; } s = strsep(&devstr, ":"); @@ -152,9 +155,20 @@ static struct spi_flash *parse_dev(char *devstr) printf("Invalid SPI mode %s\n", s); return NULL; } + if (IS_ENABLED(CONFIG_DM_SPI_FLASH)) + use_dt = false; } - dev = spi_flash_probe(bus, cs, speed, mode); + if (IS_ENABLED(CONFIG_DM_SPI_FLASH) && use_dt) { + struct udevice *new; + + if (!spi_flash_probe_bus_cs(bus, cs, &new)) + dev = dev_get_uclass_priv(new); + else + dev = NULL; + } else { + dev = spi_flash_probe(bus, cs, speed, mode); + } if (!dev) { printf("Failed to create SPI flash at %u:%u:%u:%u\n", bus, cs, speed, mode); From 01874ac7c06b8c657e7c3fda5ac555f821ef5b36 Mon Sep 17 00:00:00 2001 From: Dmitry Rokosov Date: Thu, 17 Oct 2024 17:12:06 +0300 Subject: [PATCH 03/11] include/android_ab: move ab_select_slot() documentation to @ notation There are new function documentation requirements in U-Boot, so apply these changes for android_ab. Reviewed-by: Mattijs Korpershoek Reviewed-by: Simon Glass Tested-by: Guillaume La Roque Signed-off-by: Dmitry Rokosov Tested-by: Mattijs Korpershoek # vim3_android Link: https://lore.kernel.org/r/20241017-android_ab_master-v5-1-43bfcc096d95@salutedevices.com Signed-off-by: Mattijs Korpershoek --- boot/android_ab.c | 43 ++++++++++++++++++++++++------------------- include/android_ab.h | 7 ++++--- 2 files changed, 28 insertions(+), 22 deletions(-) diff --git a/boot/android_ab.c b/boot/android_ab.c index 1196a189ed..0045c8133a 100644 --- a/boot/android_ab.c +++ b/boot/android_ab.c @@ -13,13 +13,13 @@ #include /** - * Compute the CRC-32 of the bootloader control struct. + * ab_control_compute_crc() - Compute the CRC32 of the bootloader control. + * + * @abc: Bootloader control block * * Only the bytes up to the crc32_le field are considered for the CRC-32 * calculation. * - * @param[in] abc bootloader control block - * * Return: crc32 sum */ static uint32_t ab_control_compute_crc(struct bootloader_control *abc) @@ -28,14 +28,14 @@ static uint32_t ab_control_compute_crc(struct bootloader_control *abc) } /** - * Initialize bootloader_control to the default value. + * ab_control_default() - Initialize bootloader_control to the default value. + * + * @abc: Bootloader control block * * It allows us to boot all slots in order from the first one. This value * should be used when the bootloader message is corrupted, but not when * a valid message indicates that all slots are unbootable. * - * @param[in] abc bootloader control block - * * Return: 0 on success and a negative on error */ static int ab_control_default(struct bootloader_control *abc) @@ -67,7 +67,13 @@ static int ab_control_default(struct bootloader_control *abc) } /** - * Load the boot_control struct from disk into newly allocated memory. + * ab_control_create_from_disk() - Load the boot_control from disk into memory. + * + * @dev_desc: Device where to read the boot_control struct from + * @part_info: Partition in 'dev_desc' where to read from, normally + * the "misc" partition should be used + * @abc: pointer to pointer to bootloader_control data + * @offset: boot_control struct offset * * This function allocates and returns an integer number of disk blocks, * based on the block size of the passed device to help performing a @@ -75,10 +81,6 @@ static int ab_control_default(struct bootloader_control *abc) * The boot_control struct offset (2 KiB) must be a multiple of the device * block size, for simplicity. * - * @param[in] dev_desc Device where to read the boot_control struct from - * @param[in] part_info Partition in 'dev_desc' where to read from, normally - * the "misc" partition should be used - * @param[out] pointer to pointer to bootloader_control data * Return: 0 on success and a negative on error */ static int ab_control_create_from_disk(struct blk_desc *dev_desc, @@ -122,15 +124,17 @@ static int ab_control_create_from_disk(struct blk_desc *dev_desc, } /** - * Store the loaded boot_control block. + * ab_control_store() - Store the loaded boot_control block. + * + * @dev_desc: Device where we should write the boot_control struct + * @part_info: Partition on the 'dev_desc' where to write + * @abc Pointer to the boot control struct and the extra bytes after + * it up to the nearest block boundary + * @offset: boot_control struct offset * * Store back to the same location it was read from with * ab_control_create_from_misc(). * - * @param[in] dev_desc Device where we should write the boot_control struct - * @param[in] part_info Partition on the 'dev_desc' where to write - * @param[in] abc Pointer to the boot control struct and the extra bytes after - * it up to the nearest block boundary * Return: 0 on success and a negative on error */ static int ab_control_store(struct blk_desc *dev_desc, @@ -160,12 +164,13 @@ static int ab_control_store(struct blk_desc *dev_desc, } /** - * Compare two slots. + * ab_compare_slots() - Compare two slots. + * + * @a: The first bootable slot metadata + * @b: The second bootable slot metadata * * The function determines slot which is should we boot from among the two. * - * @param[in] a The first bootable slot metadata - * @param[in] b The second bootable slot metadata * Return: Negative if the slot "a" is better, positive of the slot "b" is * better or 0 if they are equally good. */ diff --git a/include/android_ab.h b/include/android_ab.h index dbf20343da..1e53879a25 100644 --- a/include/android_ab.h +++ b/include/android_ab.h @@ -18,7 +18,10 @@ struct disk_partition; #define NUM_SLOTS 2 /** - * Select the slot where to boot from. + * ab_select_slot() - Select the slot where to boot from. + * + * @dev_desc: Place to store the device description pointer + * @part_info: Place to store the partition information * * On Android devices with more than one boot slot (multiple copies of the * kernel and system images) selects which slot should be used to boot from and @@ -28,8 +31,6 @@ struct disk_partition; * registered before returning from this function so it isn't selected * indefinitely. * - * @param[in] dev_desc Place to store the device description pointer - * @param[in] part_info Place to store the partition information * Return: The slot number (>= 0) on success, or a negative on error */ int ab_select_slot(struct blk_desc *dev_desc, struct disk_partition *part_info, From a8ca7d46ea744381185c0bf70cbdf4db7dc734b7 Mon Sep 17 00:00:00 2001 From: Dmitry Rokosov Date: Thu, 17 Oct 2024 17:12:07 +0300 Subject: [PATCH 04/11] cmd: bcb: rework the command to U_BOOT_LONGHELP approach U_BOOT_LONGHELP and U_BOOT_CMD_WITH_SUBCMDS offer numerous advantages, including: - common argument restrictions checking - automatic subcommand matching - improved usage and help handling By utilizing the U_BOOT_LONGHELP approach, we can reduce the amount of command management code and describe commands more succinctly. Signed-off-by: Dmitry Rokosov Reviewed-by: Mattijs Korpershoek Tested-by: Mattijs Korpershoek # vim3_android Link: https://lore.kernel.org/r/20241017-android_ab_master-v5-2-43bfcc096d95@salutedevices.com Signed-off-by: Mattijs Korpershoek --- cmd/bcb.c | 151 ++++++++++++++++-------------------------------------- 1 file changed, 43 insertions(+), 108 deletions(-) diff --git a/cmd/bcb.c b/cmd/bcb.c index 97a96c0096..98b2a71087 100644 --- a/cmd/bcb.c +++ b/cmd/bcb.c @@ -16,15 +16,6 @@ #include #include -enum bcb_cmd { - BCB_CMD_LOAD, - BCB_CMD_FIELD_SET, - BCB_CMD_FIELD_CLEAR, - BCB_CMD_FIELD_TEST, - BCB_CMD_FIELD_DUMP, - BCB_CMD_STORE, -}; - static const char * const fields[] = { "command", "status", @@ -38,67 +29,9 @@ static struct disk_partition partition_data; static struct blk_desc *block; static struct disk_partition *partition = &partition_data; -static int bcb_cmd_get(char *cmd) +static int bcb_not_loaded(void) { - if (!strcmp(cmd, "load")) - return BCB_CMD_LOAD; - if (!strcmp(cmd, "set")) - return BCB_CMD_FIELD_SET; - if (!strcmp(cmd, "clear")) - return BCB_CMD_FIELD_CLEAR; - if (!strcmp(cmd, "test")) - return BCB_CMD_FIELD_TEST; - if (!strcmp(cmd, "store")) - return BCB_CMD_STORE; - if (!strcmp(cmd, "dump")) - return BCB_CMD_FIELD_DUMP; - else - return -1; -} - -static int bcb_is_misused(int argc, char *const argv[]) -{ - int cmd = bcb_cmd_get(argv[0]); - - switch (cmd) { - case BCB_CMD_LOAD: - if (argc != 3 && argc != 4) - goto err; - break; - case BCB_CMD_FIELD_SET: - if (argc != 3) - goto err; - break; - case BCB_CMD_FIELD_TEST: - if (argc != 4) - goto err; - break; - case BCB_CMD_FIELD_CLEAR: - if (argc != 1 && argc != 2) - goto err; - break; - case BCB_CMD_STORE: - if (argc != 1) - goto err; - break; - case BCB_CMD_FIELD_DUMP: - if (argc != 2) - goto err; - break; - default: - printf("Error: 'bcb %s' not supported\n", argv[0]); - return -1; - } - - if (cmd != BCB_CMD_LOAD && !block) { - printf("Error: Please, load BCB first!\n"); - return -1; - } - - return 0; -err: - printf("Error: Bad usage of 'bcb %s'\n", argv[0]); - + printf("Error: Please, load BCB first!\n"); return -1; } @@ -216,6 +149,9 @@ static int do_bcb_load(struct cmd_tbl *cmdtp, int flag, int argc, char *endp; char *iface = "mmc"; + if (argc < 3) + return CMD_RET_USAGE; + if (argc == 4) { iface = argv[1]; argc--; @@ -270,6 +206,12 @@ static int __bcb_set(const char *fieldp, const char *valp) static int do_bcb_set(struct cmd_tbl *cmdtp, int flag, int argc, char * const argv[]) { + if (argc < 3) + return CMD_RET_USAGE; + + if (!block) + return bcb_not_loaded(); + return __bcb_set(argv[1], argv[2]); } @@ -279,6 +221,9 @@ static int do_bcb_clear(struct cmd_tbl *cmdtp, int flag, int argc, int size; char *field; + if (!block) + return bcb_not_loaded(); + if (argc == 1) { memset(&bcb, 0, sizeof(bcb)); return CMD_RET_SUCCESS; @@ -297,7 +242,15 @@ static int do_bcb_test(struct cmd_tbl *cmdtp, int flag, int argc, { int size; char *field; - char *op = argv[2]; + char *op; + + if (argc < 4) + return CMD_RET_USAGE; + + if (!block) + return bcb_not_loaded(); + + op = argv[2]; if (bcb_field_get(argv[1], &field, &size)) return CMD_RET_FAILURE; @@ -325,6 +278,12 @@ static int do_bcb_dump(struct cmd_tbl *cmdtp, int flag, int argc, int size; char *field; + if (argc < 2) + return CMD_RET_USAGE; + + if (!block) + return bcb_not_loaded(); + if (bcb_field_get(argv[1], &field, &size)) return CMD_RET_FAILURE; @@ -356,6 +315,9 @@ err: static int do_bcb_store(struct cmd_tbl *cmdtp, int flag, int argc, char * const argv[]) { + if (!block) + return bcb_not_loaded(); + return __bcb_store(); } @@ -414,44 +376,7 @@ void bcb_reset(void) __bcb_reset(); } -static struct cmd_tbl cmd_bcb_sub[] = { - U_BOOT_CMD_MKENT(load, CONFIG_SYS_MAXARGS, 1, do_bcb_load, "", ""), - U_BOOT_CMD_MKENT(set, CONFIG_SYS_MAXARGS, 1, do_bcb_set, "", ""), - U_BOOT_CMD_MKENT(clear, CONFIG_SYS_MAXARGS, 1, do_bcb_clear, "", ""), - U_BOOT_CMD_MKENT(test, CONFIG_SYS_MAXARGS, 1, do_bcb_test, "", ""), - U_BOOT_CMD_MKENT(dump, CONFIG_SYS_MAXARGS, 1, do_bcb_dump, "", ""), - U_BOOT_CMD_MKENT(store, CONFIG_SYS_MAXARGS, 1, do_bcb_store, "", ""), -}; - -static int do_bcb(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]) -{ - struct cmd_tbl *c; - - if (argc < 2) - return CMD_RET_USAGE; - - argc--; - argv++; - - c = find_cmd_tbl(argv[0], cmd_bcb_sub, ARRAY_SIZE(cmd_bcb_sub)); - if (!c) - return CMD_RET_USAGE; - - if (bcb_is_misused(argc, argv)) { - /* - * We try to improve the user experience by reporting the - * root-cause of misusage, so don't return CMD_RET_USAGE, - * since the latter prints out the full-blown help text - */ - return CMD_RET_FAILURE; - } - - return c->cmd(cmdtp, flag, argc, argv); -} - -U_BOOT_CMD( - bcb, CONFIG_SYS_MAXARGS, 1, do_bcb, - "Load/set/clear/test/dump/store Android BCB fields", +U_BOOT_LONGHELP(bcb, "load - load BCB from :\n" "load - load BCB from mmc :\n" "bcb set - set BCB to \n" @@ -472,3 +397,13 @@ U_BOOT_CMD( " NOTE: any ':' character in will be replaced by line feed\n" " during 'bcb set' and used as separator by upper layers\n" ); + +U_BOOT_CMD_WITH_SUBCMDS(bcb, + "Load/set/clear/test/dump/store Android BCB fields", bcb_help_text, + U_BOOT_SUBCMD_MKENT(load, 4, 1, do_bcb_load), + U_BOOT_SUBCMD_MKENT(set, 3, 1, do_bcb_set), + U_BOOT_SUBCMD_MKENT(clear, 2, 1, do_bcb_clear), + U_BOOT_SUBCMD_MKENT(test, 4, 1, do_bcb_test), + U_BOOT_SUBCMD_MKENT(dump, 2, 1, do_bcb_dump), + U_BOOT_SUBCMD_MKENT(store, 1, 1, do_bcb_store), +); From b523b4d2c32f07ca0793bb0f926b02ecb0556cc6 Mon Sep 17 00:00:00 2001 From: Dmitry Rokosov Date: Thu, 17 Oct 2024 17:12:08 +0300 Subject: [PATCH 05/11] treewide: bcb: move ab_select command to bcb subcommands To enhance code organization, it is beneficial to consolidate all A/B BCB management routines into a single super-command. The 'bcb' command is an excellent candidate for this purpose. This patch integrates the separate 'ab_select' command into the 'bcb' group as the 'ab_select' subcommand, maintaining the same parameter list for consistency. Signed-off-by: Dmitry Rokosov Reviewed-by: Mattijs Korpershoek Tested-by: Mattijs Korpershoek # vim3_android Link: https://lore.kernel.org/r/20241017-android_ab_master-v5-3-43bfcc096d95@salutedevices.com Signed-off-by: Mattijs Korpershoek --- MAINTAINERS | 1 - cmd/Kconfig | 14 ----- cmd/Makefile | 1 - cmd/ab_select.c | 66 ----------------------- cmd/bcb.c | 63 ++++++++++++++++++++++ configs/am57xx_evm_defconfig | 1 - configs/am57xx_hs_evm_defconfig | 1 - configs/am57xx_hs_evm_usb_defconfig | 1 - configs/khadas-vim3_android_ab_defconfig | 1 - configs/khadas-vim3l_android_ab_defconfig | 1 - configs/sandbox64_defconfig | 2 + configs/sandbox_defconfig | 1 - doc/android/ab.rst | 12 ++--- include/configs/khadas-vim3_android.h | 2 +- include/configs/khadas-vim3l_android.h | 2 +- include/configs/meson64_android.h | 4 +- include/configs/ti_omap5_common.h | 4 +- test/py/tests/test_android/test_ab.py | 8 +-- 18 files changed, 81 insertions(+), 104 deletions(-) delete mode 100644 cmd/ab_select.c diff --git a/MAINTAINERS b/MAINTAINERS index 240cf8633f..8e375e75e5 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -65,7 +65,6 @@ R: Sam Protsenko S: Maintained T: git https://source.denx.de/u-boot/custodians/u-boot-dfu.git F: boot/android_ab.c -F: cmd/ab_select.c F: doc/android/ab.rst F: include/android_ab.h F: test/py/tests/test_android/test_ab.py diff --git a/cmd/Kconfig b/cmd/Kconfig index 3ee70f31b1..40485be192 100644 --- a/cmd/Kconfig +++ b/cmd/Kconfig @@ -1782,20 +1782,6 @@ config CMD_XXD endmenu -menu "Android support commands" - -config CMD_AB_SELECT - bool "ab_select" - depends on ANDROID_AB - help - On Android devices with more than one boot slot (multiple copies of - the kernel and system images) this provides a command to select which - slot should be used to boot from and register the boot attempt. This - is used by the new A/B update model where one slot is updated in the - background while running from the other slot. - -endmenu - if NET || NET_LWIP menuconfig CMD_NET diff --git a/cmd/Makefile b/cmd/Makefile index 3c5bd56e91..7fe2044aab 100644 --- a/cmd/Makefile +++ b/cmd/Makefile @@ -17,7 +17,6 @@ obj-$(CONFIG_CMD_2048) += 2048.o obj-$(CONFIG_CMD_ACPI) += acpi.o obj-$(CONFIG_CMD_ADDRMAP) += addrmap.o obj-$(CONFIG_CMD_AES) += aes.o -obj-$(CONFIG_CMD_AB_SELECT) += ab_select.o obj-$(CONFIG_CMD_ADC) += adc.o obj-$(CONFIG_CMD_ARMFLASH) += armflash.o obj-$(CONFIG_BLK) += blk_common.o diff --git a/cmd/ab_select.c b/cmd/ab_select.c deleted file mode 100644 index 7c178c728c..0000000000 --- a/cmd/ab_select.c +++ /dev/null @@ -1,66 +0,0 @@ -// SPDX-License-Identifier: BSD-2-Clause -/* - * Copyright (C) 2017 The Android Open Source Project - */ - -#include -#include -#include -#include - -static int do_ab_select(struct cmd_tbl *cmdtp, int flag, int argc, - char *const argv[]) -{ - int ret; - struct blk_desc *dev_desc; - struct disk_partition part_info; - char slot[2]; - bool dec_tries = true; - - if (argc < 4) - return CMD_RET_USAGE; - - for (int i = 4; i < argc; i++) { - if (strcmp(argv[i], "--no-dec") == 0) { - dec_tries = false; - } else { - return CMD_RET_USAGE; - } - } - - /* Lookup the "misc" partition from argv[2] and argv[3] */ - if (part_get_info_by_dev_and_name_or_num(argv[2], argv[3], - &dev_desc, &part_info, - false) < 0) { - return CMD_RET_FAILURE; - } - - ret = ab_select_slot(dev_desc, &part_info, dec_tries); - if (ret < 0) { - printf("Android boot failed, error %d.\n", ret); - return CMD_RET_FAILURE; - } - - /* Android standard slot names are 'a', 'b', ... */ - slot[0] = BOOT_SLOT_NAME(ret); - slot[1] = '\0'; - env_set(argv[1], slot); - printf("ANDROID: Booting slot: %s\n", slot); - return CMD_RET_SUCCESS; -} - -U_BOOT_CMD(ab_select, 5, 0, do_ab_select, - "Select the slot used to boot from and register the boot attempt.", - " [--no-dec]\n" - " - Load the slot metadata from the partition 'part' on\n" - " device type 'interface' instance 'dev' and store the active\n" - " slot in the 'slot_var_name' variable. This also updates the\n" - " Android slot metadata with a boot attempt, which can cause\n" - " successive calls to this function to return a different result\n" - " if the returned slot runs out of boot attempts.\n" - " - If 'part_name' is passed, preceded with a # instead of :, the\n" - " partition name whose label is 'part_name' will be looked up in\n" - " the partition table. This is commonly the \"misc\" partition.\n" - " - If '--no-dec' is set, the number of tries remaining will not\n" - " decremented for the selected boot slot\n" -); diff --git a/cmd/bcb.c b/cmd/bcb.c index 98b2a71087..2854408e56 100644 --- a/cmd/bcb.c +++ b/cmd/bcb.c @@ -8,6 +8,7 @@ #include #include #include +#include #include #include #include @@ -376,6 +377,48 @@ void bcb_reset(void) __bcb_reset(); } +__maybe_unused static int do_bcb_ab_select(struct cmd_tbl *cmdtp, + int flag, int argc, + char * const argv[]) +{ + int ret; + struct blk_desc *dev_desc; + struct disk_partition part_info; + char slot[2]; + bool dec_tries = true; + + if (argc < 4) + return CMD_RET_USAGE; + + for (int i = 4; i < argc; i++) { + if (strcmp(argv[i], "--no-dec") == 0) + dec_tries = false; + else + return CMD_RET_USAGE; + } + + /* Lookup the "misc" partition from argv[2] and argv[3] */ + if (part_get_info_by_dev_and_name_or_num(argv[2], argv[3], + &dev_desc, &part_info, + false) < 0) { + return CMD_RET_FAILURE; + } + + ret = ab_select_slot(dev_desc, &part_info, dec_tries); + if (ret < 0) { + printf("Android boot failed, error %d.\n", ret); + return CMD_RET_FAILURE; + } + + /* Android standard slot names are 'a', 'b', ... */ + slot[0] = BOOT_SLOT_NAME(ret); + slot[1] = '\0'; + env_set(argv[1], slot); + printf("ANDROID: Booting slot: %s\n", slot); + + return CMD_RET_SUCCESS; +} + U_BOOT_LONGHELP(bcb, "load - load BCB from :\n" "load - load BCB from mmc :\n" @@ -385,6 +428,23 @@ U_BOOT_LONGHELP(bcb, "bcb dump - dump BCB \n" "bcb store - store BCB back to \n" "\n" +#if IS_ENABLED(CONFIG_ANDROID_AB) + "bcb ab_select -\n" + " Select the slot used to boot from and register the boot attempt.\n" + " [--no-dec]\n" + " - Load the slot metadata from the partition 'part' on\n" + " device type 'interface' instance 'dev' and store the active\n" + " slot in the 'slot_var_name' variable. This also updates the\n" + " Android slot metadata with a boot attempt, which can cause\n" + " successive calls to this function to return a different result\n" + " if the returned slot runs out of boot attempts.\n" + " - If 'part_name' is passed, preceded with a # instead of :, the\n" + " partition name whose label is 'part_name' will be looked up in\n" + " the partition table. This is commonly the \"misc\" partition.\n" + " - If '--no-dec' is set, the number of tries remaining will not\n" + " decremented for the selected boot slot\n" + "\n" +#endif "Legend:\n" " - storage device interface (virtio, mmc, etc)\n" " - storage device index containing the BCB partition\n" @@ -406,4 +466,7 @@ U_BOOT_CMD_WITH_SUBCMDS(bcb, U_BOOT_SUBCMD_MKENT(test, 4, 1, do_bcb_test), U_BOOT_SUBCMD_MKENT(dump, 2, 1, do_bcb_dump), U_BOOT_SUBCMD_MKENT(store, 1, 1, do_bcb_store), +#if IS_ENABLED(CONFIG_ANDROID_AB) + U_BOOT_SUBCMD_MKENT(ab_select, 5, 1, do_bcb_ab_select), +#endif ); diff --git a/configs/am57xx_evm_defconfig b/configs/am57xx_evm_defconfig index efc154eda0..b793f00bab 100644 --- a/configs/am57xx_evm_defconfig +++ b/configs/am57xx_evm_defconfig @@ -48,7 +48,6 @@ CONFIG_CMD_SPL=y CONFIG_SYS_I2C_EEPROM_ADDR_LEN=2 CONFIG_CMD_BCB=y # CONFIG_CMD_SETEXPR is not set -CONFIG_CMD_AB_SELECT=y CONFIG_BOOTP_DNS2=y # CONFIG_CMD_PMIC is not set CONFIG_CMD_AVB=y diff --git a/configs/am57xx_hs_evm_defconfig b/configs/am57xx_hs_evm_defconfig index 0f8533e15d..5cacd7f9cc 100644 --- a/configs/am57xx_hs_evm_defconfig +++ b/configs/am57xx_hs_evm_defconfig @@ -44,7 +44,6 @@ CONFIG_CMD_ADTIMG=y CONFIG_CMD_ABOOTIMG=y CONFIG_SYS_I2C_EEPROM_ADDR_LEN=2 CONFIG_CMD_BCB=y -CONFIG_CMD_AB_SELECT=y CONFIG_BOOTP_DNS2=y # CONFIG_CMD_PMIC is not set CONFIG_CMD_AVB=y diff --git a/configs/am57xx_hs_evm_usb_defconfig b/configs/am57xx_hs_evm_usb_defconfig index 81a938339d..2d8068ecdc 100644 --- a/configs/am57xx_hs_evm_usb_defconfig +++ b/configs/am57xx_hs_evm_usb_defconfig @@ -46,7 +46,6 @@ CONFIG_CMD_ADTIMG=y CONFIG_CMD_ABOOTIMG=y CONFIG_SYS_I2C_EEPROM_ADDR_LEN=2 CONFIG_CMD_BCB=y -CONFIG_CMD_AB_SELECT=y CONFIG_BOOTP_DNS2=y # CONFIG_CMD_PMIC is not set CONFIG_CMD_AVB=y diff --git a/configs/khadas-vim3_android_ab_defconfig b/configs/khadas-vim3_android_ab_defconfig index 510fe4f892..de5357c45c 100644 --- a/configs/khadas-vim3_android_ab_defconfig +++ b/configs/khadas-vim3_android_ab_defconfig @@ -47,7 +47,6 @@ CONFIG_CMD_SPI=y CONFIG_CMD_USB=y CONFIG_CMD_USB_MASS_STORAGE=y # CONFIG_CMD_SETEXPR is not set -CONFIG_CMD_AB_SELECT=y CONFIG_CMD_REGULATOR=y CONFIG_CMD_AVB=y CONFIG_OF_CONTROL=y diff --git a/configs/khadas-vim3l_android_ab_defconfig b/configs/khadas-vim3l_android_ab_defconfig index d2da8ff2a6..4d7b90f230 100644 --- a/configs/khadas-vim3l_android_ab_defconfig +++ b/configs/khadas-vim3l_android_ab_defconfig @@ -47,7 +47,6 @@ CONFIG_CMD_SPI=y CONFIG_CMD_USB=y CONFIG_CMD_USB_MASS_STORAGE=y # CONFIG_CMD_SETEXPR is not set -CONFIG_CMD_AB_SELECT=y CONFIG_CMD_REGULATOR=y CONFIG_CMD_AVB=y CONFIG_OF_CONTROL=y diff --git a/configs/sandbox64_defconfig b/configs/sandbox64_defconfig index 1b3b8c6e78..b5f80b8572 100644 --- a/configs/sandbox64_defconfig +++ b/configs/sandbox64_defconfig @@ -27,6 +27,7 @@ CONFIG_CONSOLE_RECORD=y CONFIG_CONSOLE_RECORD_OUT_SIZE=0x6000 CONFIG_PRE_CONSOLE_BUFFER=y CONFIG_DISPLAY_BOARDINFO_LATE=y +CONFIG_ANDROID_AB=y CONFIG_CMD_CPU=y CONFIG_CMD_LICENSE=y CONFIG_CMD_BOOTZ=y @@ -46,6 +47,7 @@ CONFIG_CMD_MD5SUM=y CONFIG_CMD_MEMINFO=y CONFIG_CMD_MX_CYCLIC=y CONFIG_CMD_MEMTEST=y +CONFIG_CMD_BCB=y CONFIG_CMD_CLK=y CONFIG_CMD_DEMO=y CONFIG_CMD_GPIO=y diff --git a/configs/sandbox_defconfig b/configs/sandbox_defconfig index f596f1cc55..d111858082 100644 --- a/configs/sandbox_defconfig +++ b/configs/sandbox_defconfig @@ -103,7 +103,6 @@ CONFIG_CMD_AXI=y CONFIG_CMD_CAT=y CONFIG_CMD_SETEXPR_FMT=y CONFIG_CMD_XXD=y -CONFIG_CMD_AB_SELECT=y CONFIG_CMD_DHCP6=y CONFIG_BOOTP_DNS2=y CONFIG_CMD_PCAP=y diff --git a/doc/android/ab.rst b/doc/android/ab.rst index 2adf88781d..7fd4aeb6a7 100644 --- a/doc/android/ab.rst +++ b/doc/android/ab.rst @@ -18,7 +18,7 @@ The A/B updates support can be activated by specifying next options in your board configuration file:: CONFIG_ANDROID_AB=y - CONFIG_CMD_AB_SELECT=y + CONFIG_CMD_BCB=y The disk space on target device must be partitioned in a way so that each partition which needs to be updated has two or more instances. The name of @@ -26,8 +26,8 @@ each instance must be formed by adding suffixes: ``_a``, ``_b``, ``_c``, etc. For example: ``boot_a``, ``boot_b``, ``system_a``, ``system_b``, ``vendor_a``, ``vendor_b``. -As a result you can use ``ab_select`` command to ensure A/B boot process in your -boot script. This command analyzes and processes A/B metadata stored on a +As a result you can use ``bcb ab_select`` command to ensure A/B boot process in +your boot script. This command analyzes and processes A/B metadata stored on a special partition (e.g. ``misc``) and determines which slot should be used for booting up. @@ -42,15 +42,15 @@ Command usage .. code-block:: none - ab_select + bcb ab_select for example:: - => ab_select slot_name mmc 1:4 + => bcb ab_select slot_name mmc 1:4 or:: - => ab_select slot_name mmc 1#misc + => bcb ab_select slot_name mmc 1#misc Result:: diff --git a/include/configs/khadas-vim3_android.h b/include/configs/khadas-vim3_android.h index b76e049f09..fc89efb4c3 100644 --- a/include/configs/khadas-vim3_android.h +++ b/include/configs/khadas-vim3_android.h @@ -12,7 +12,7 @@ #define LOGO_UUID "43a3305d-150f-4cc9-bd3b-38fca8693846;" #define ROOT_UUID "ddb8c3f6-d94d-4394-b633-3134139cc2e0;" -#if defined(CONFIG_CMD_AB_SELECT) +#if defined(CONFIG_CMD_BCB) && defined(CONFIG_ANDROID_AB) #define PARTS_DEFAULT \ "uuid_disk=${uuid_gpt_disk};" \ "name=logo,start=512K,size=2M,uuid=" LOGO_UUID \ diff --git a/include/configs/khadas-vim3l_android.h b/include/configs/khadas-vim3l_android.h index 0ab8ffd372..5b2aed1cf6 100644 --- a/include/configs/khadas-vim3l_android.h +++ b/include/configs/khadas-vim3l_android.h @@ -12,7 +12,7 @@ #define LOGO_UUID "43a3305d-150f-4cc9-bd3b-38fca8693846;" #define ROOT_UUID "ddb8c3f6-d94d-4394-b633-3134139cc2e0;" -#if defined(CONFIG_CMD_AB_SELECT) +#if defined(CONFIG_CMD_BCB) && defined(CONFIG_ANDROID_AB) #define PARTS_DEFAULT \ "uuid_disk=${uuid_gpt_disk};" \ "name=logo,start=512K,size=2M,uuid=" LOGO_UUID \ diff --git a/include/configs/meson64_android.h b/include/configs/meson64_android.h index fa52026580..77364bbf9c 100644 --- a/include/configs/meson64_android.h +++ b/include/configs/meson64_android.h @@ -47,13 +47,13 @@ #define AVB_VERIFY_CMD "" #endif -#if defined(CONFIG_CMD_AB_SELECT) +#if defined(CONFIG_CMD_BCB) && defined(CONFIG_ANDROID_AB) #define ANDROIDBOOT_GET_CURRENT_SLOT_CMD "get_current_slot=" \ "if part number mmc ${mmcdev} " CONTROL_PARTITION " control_part_number; " \ "then " \ "echo " CONTROL_PARTITION \ " partition number:${control_part_number};" \ - "ab_select current_slot mmc ${mmcdev}:${control_part_number};" \ + "bcb ab_select current_slot mmc ${mmcdev}:${control_part_number};" \ "else " \ "echo " CONTROL_PARTITION " partition not found;" \ "fi;\0" diff --git a/include/configs/ti_omap5_common.h b/include/configs/ti_omap5_common.h index 26494ae980..26b6c1cd18 100644 --- a/include/configs/ti_omap5_common.h +++ b/include/configs/ti_omap5_common.h @@ -93,13 +93,13 @@ #define CONTROL_PARTITION "misc" -#if defined(CONFIG_CMD_AB_SELECT) +#if defined(CONFIG_CMD_BCB) && defined(CONFIG_ANDROID_AB) #define AB_SELECT_SLOT \ "if part number mmc 1 " CONTROL_PARTITION " control_part_number; " \ "then " \ "echo " CONTROL_PARTITION \ " partition number:${control_part_number};" \ - "ab_select slot_name mmc ${mmcdev}:${control_part_number};" \ + "bcb ab_select slot_name mmc ${mmcdev}:${control_part_number};" \ "else " \ "echo " CONTROL_PARTITION " partition not found;" \ "exit;" \ diff --git a/test/py/tests/test_android/test_ab.py b/test/py/tests/test_android/test_ab.py index c79cb07fda..0d7b7995a9 100644 --- a/test/py/tests/test_android/test_ab.py +++ b/test/py/tests/test_android/test_ab.py @@ -56,20 +56,20 @@ def ab_disk_image(u_boot_console): @pytest.mark.boardspec('sandbox') @pytest.mark.buildconfigspec('android_ab') -@pytest.mark.buildconfigspec('cmd_ab_select') +@pytest.mark.buildconfigspec('cmd_bcb') @pytest.mark.requiredtool('sgdisk') def test_ab(ab_disk_image, u_boot_console): - """Test the 'ab_select' command.""" + """Test the 'bcb ab_select' command.""" u_boot_console.run_command('host bind 0 ' + ab_disk_image.path) - output = u_boot_console.run_command('ab_select slot_name host 0#misc') + output = u_boot_console.run_command('bcb ab_select slot_name host 0#misc') assert 're-initializing A/B metadata' in output assert 'Attempting slot a, tries remaining 7' in output output = u_boot_console.run_command('printenv slot_name') assert 'slot_name=a' in output - output = u_boot_console.run_command('ab_select slot_name host 0:1') + output = u_boot_console.run_command('bcb ab_select slot_name host 0:1') assert 'Attempting slot b, tries remaining 7' in output output = u_boot_console.run_command('printenv slot_name') assert 'slot_name=b' in output From b1bc9a2fc93da8ed25dfc4078e76220ac26eb6b0 Mon Sep 17 00:00:00 2001 From: Dmitry Rokosov Date: Thu, 17 Oct 2024 17:12:09 +0300 Subject: [PATCH 06/11] cmd: bcb: change strcmp() usage style in the do_bcb_ab_select() In the entire cmd/bcb.c file, the return value of strcmp() is not directly compared to 0. Therefore, it would be better to maintain this style in the new do_bcb_ab_select() function as well. Reviewed-by: Mattijs Korpershoek Reviewed-by: Simon Glass Tested-by: Guillaume La Roque Signed-off-by: Dmitry Rokosov Tested-by: Mattijs Korpershoek # vim3_android Link: https://lore.kernel.org/r/20241017-android_ab_master-v5-4-43bfcc096d95@salutedevices.com Signed-off-by: Mattijs Korpershoek --- cmd/bcb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd/bcb.c b/cmd/bcb.c index 2854408e56..b33c046af0 100644 --- a/cmd/bcb.c +++ b/cmd/bcb.c @@ -391,7 +391,7 @@ __maybe_unused static int do_bcb_ab_select(struct cmd_tbl *cmdtp, return CMD_RET_USAGE; for (int i = 4; i < argc; i++) { - if (strcmp(argv[i], "--no-dec") == 0) + if (!strcmp(argv[i], "--no-dec")) dec_tries = false; else return CMD_RET_USAGE; From a995084beb6682748002878ccb4b8c4de9fc0136 Mon Sep 17 00:00:00 2001 From: Dmitry Rokosov Date: Thu, 17 Oct 2024 17:12:10 +0300 Subject: [PATCH 07/11] cmd: bcb: introduce 'ab_dump' command to print BCB block content It's really helpful to have the ability to dump BCB block for debugging A/B logic on the board supported this partition schema. Command 'bcb ab_dump' prints all fields of bootloader_control struct including slot_metadata for all presented slots. Output example: ===== > board# bcb ab_dump ubi 0#misc > Read 512 bytes from volume misc to 000000000bf07580 > Read 512 bytes from volume misc to 000000000bf42f40 > Bootloader Control: [misc] > Active Slot: _a > Magic Number: 0x42414342 > Version: 1 > Number of Slots: 2 > Recovery Tries Remaining: 0 > CRC: 0x2c8b50bc (Valid) > > Slot[0] Metadata: > - Priority: 15 > - Tries Remaining: 0 > - Successful Boot: 1 > - Verity Corrupted: 0 > > Slot[1] Metadata: > - Priority: 14 > - Tries Remaining: 7 > - Successful Boot: 0 > - Verity Corrupted: 0 ==== The ab_dump command allows you to display ABC data directly on the U-Boot console. During an A/B test execution, this test verifies the accuracy of each field within the ABC data. Signed-off-by: Dmitry Rokosov Reviewed-by: Mattijs Korpershoek Tested-by: Mattijs Korpershoek # vim3_android Link: https://lore.kernel.org/r/20241017-android_ab_master-v5-5-43bfcc096d95@salutedevices.com Signed-off-by: Mattijs Korpershoek --- boot/android_ab.c | 68 +++++++++++++++++++++++++++ cmd/bcb.c | 31 ++++++++++++ include/android_ab.h | 10 ++++ test/py/tests/test_android/test_ab.py | 23 +++++++++ 4 files changed, 132 insertions(+) diff --git a/boot/android_ab.c b/boot/android_ab.c index 0045c8133a..c93e515410 100644 --- a/boot/android_ab.c +++ b/boot/android_ab.c @@ -372,3 +372,71 @@ int ab_select_slot(struct blk_desc *dev_desc, struct disk_partition *part_info, return slot; } + +int ab_dump_abc(struct blk_desc *dev_desc, struct disk_partition *part_info) +{ + struct bootloader_control *abc; + u32 crc32_le; + int i, ret; + struct slot_metadata *slot; + + if (!dev_desc || !part_info) { + log_err("ANDROID: Empty device descriptor or partition info\n"); + return -EINVAL; + } + + ret = ab_control_create_from_disk(dev_desc, part_info, &abc, 0); + if (ret < 0) { + log_err("ANDROID: Cannot create bcb from disk %d\n", ret); + return ret; + } + + if (abc->magic != BOOT_CTRL_MAGIC) { + log_err("ANDROID: Unknown A/B metadata: %.8x\n", abc->magic); + ret = -ENODATA; + goto error; + } + + if (abc->version > BOOT_CTRL_VERSION) { + log_err("ANDROID: Unsupported A/B metadata version: %.8x\n", + abc->version); + ret = -ENODATA; + goto error; + } + + if (abc->nb_slot > ARRAY_SIZE(abc->slot_info)) { + log_err("ANDROID: Wrong number of slots %u, expected %zu\n", + abc->nb_slot, ARRAY_SIZE(abc->slot_info)); + ret = -ENODATA; + goto error; + } + + printf("Bootloader Control: [%s]\n", part_info->name); + printf("Active Slot: %s\n", abc->slot_suffix); + printf("Magic Number: 0x%x\n", abc->magic); + printf("Version: %u\n", abc->version); + printf("Number of Slots: %u\n", abc->nb_slot); + printf("Recovery Tries Remaining: %u\n", abc->recovery_tries_remaining); + + printf("CRC: 0x%.8x", abc->crc32_le); + + crc32_le = ab_control_compute_crc(abc); + if (abc->crc32_le != crc32_le) + printf(" (Invalid, Expected: 0x%.8x)\n", crc32_le); + else + printf(" (Valid)\n"); + + for (i = 0; i < abc->nb_slot; ++i) { + slot = &abc->slot_info[i]; + printf("\nSlot[%d] Metadata:\n", i); + printf("\t- Priority: %u\n", slot->priority); + printf("\t- Tries Remaining: %u\n", slot->tries_remaining); + printf("\t- Successful Boot: %u\n", slot->successful_boot); + printf("\t- Verity Corrupted: %u\n", slot->verity_corrupted); + } + +error: + free(abc); + + return ret; +} diff --git a/cmd/bcb.c b/cmd/bcb.c index b33c046af0..16eabfe00f 100644 --- a/cmd/bcb.c +++ b/cmd/bcb.c @@ -419,6 +419,32 @@ __maybe_unused static int do_bcb_ab_select(struct cmd_tbl *cmdtp, return CMD_RET_SUCCESS; } +__maybe_unused static int do_bcb_ab_dump(struct cmd_tbl *cmdtp, + int flag, int argc, + char *const argv[]) +{ + int ret; + struct blk_desc *dev_desc; + struct disk_partition part_info; + + if (argc < 3) + return CMD_RET_USAGE; + + if (part_get_info_by_dev_and_name_or_num(argv[1], argv[2], + &dev_desc, &part_info, + false) < 0) { + return CMD_RET_FAILURE; + } + + ret = ab_dump_abc(dev_desc, &part_info); + if (ret < 0) { + printf("Cannot dump ABC data, error %d.\n", ret); + return CMD_RET_FAILURE; + } + + return CMD_RET_SUCCESS; +} + U_BOOT_LONGHELP(bcb, "load - load BCB from :\n" "load - load BCB from mmc :\n" @@ -444,6 +470,10 @@ U_BOOT_LONGHELP(bcb, " - If '--no-dec' is set, the number of tries remaining will not\n" " decremented for the selected boot slot\n" "\n" + "bcb ab_dump -\n" + " Dump boot_control information from specific partition.\n" + " \n" + "\n" #endif "Legend:\n" " - storage device interface (virtio, mmc, etc)\n" @@ -468,5 +498,6 @@ U_BOOT_CMD_WITH_SUBCMDS(bcb, U_BOOT_SUBCMD_MKENT(store, 1, 1, do_bcb_store), #if IS_ENABLED(CONFIG_ANDROID_AB) U_BOOT_SUBCMD_MKENT(ab_select, 5, 1, do_bcb_ab_select), + U_BOOT_SUBCMD_MKENT(ab_dump, 3, 1, do_bcb_ab_dump), #endif ); diff --git a/include/android_ab.h b/include/android_ab.h index 1e53879a25..838230e06f 100644 --- a/include/android_ab.h +++ b/include/android_ab.h @@ -36,4 +36,14 @@ struct disk_partition; int ab_select_slot(struct blk_desc *dev_desc, struct disk_partition *part_info, bool dec_tries); +/** + * ab_dump_abc() - Dump ABC information for specific partition. + * + * @dev_desc: Device description pointer + * @part_info: Partition information + * + * Return: 0 on success, or a negative on error + */ +int ab_dump_abc(struct blk_desc *dev_desc, struct disk_partition *part_info); + #endif /* __ANDROID_AB_H */ diff --git a/test/py/tests/test_android/test_ab.py b/test/py/tests/test_android/test_ab.py index 0d7b7995a9..9bf1a0eb00 100644 --- a/test/py/tests/test_android/test_ab.py +++ b/test/py/tests/test_android/test_ab.py @@ -54,6 +54,27 @@ def ab_disk_image(u_boot_console): di = ABTestDiskImage(u_boot_console) return di +def ab_dump(u_boot_console, slot_num, crc): + output = u_boot_console.run_command('bcb ab_dump host 0#misc') + header, slot0, slot1 = output.split('\r\r\n\r\r\n') + slots = [slot0, slot1] + slot_suffixes = ['_a', '_b'] + + header = dict(map(lambda x: map(str.strip, x.split(':')), header.split('\r\r\n'))) + assert header['Bootloader Control'] == '[misc]' + assert header['Active Slot'] == slot_suffixes[slot_num] + assert header['Magic Number'] == '0x42414342' + assert header['Version'] == '1' + assert header['Number of Slots'] == '2' + assert header['Recovery Tries Remaining'] == '0' + assert header['CRC'] == '{} (Valid)'.format(crc) + + slot = dict(map(lambda x: map(str.strip, x.split(':')), slots[slot_num].split('\r\r\n\t- ')[1:])) + assert slot['Priority'] == '15' + assert slot['Tries Remaining'] == '6' + assert slot['Successful Boot'] == '0' + assert slot['Verity Corrupted'] == '0' + @pytest.mark.boardspec('sandbox') @pytest.mark.buildconfigspec('android_ab') @pytest.mark.buildconfigspec('cmd_bcb') @@ -68,8 +89,10 @@ def test_ab(ab_disk_image, u_boot_console): assert 'Attempting slot a, tries remaining 7' in output output = u_boot_console.run_command('printenv slot_name') assert 'slot_name=a' in output + ab_dump(u_boot_console, 0, '0xd438d1b9') output = u_boot_console.run_command('bcb ab_select slot_name host 0:1') assert 'Attempting slot b, tries remaining 7' in output output = u_boot_console.run_command('printenv slot_name') assert 'slot_name=b' in output + ab_dump(u_boot_console, 1, '0x011ec016') From 55c876c6f9b787488c7a9f9c678398c48d13db6f Mon Sep 17 00:00:00 2001 From: Dmitry Rokosov Date: Thu, 17 Oct 2024 17:12:11 +0300 Subject: [PATCH 08/11] common: android_ab: fix slot suffix for abc block To align with the official Android BCB (Bootloader Control Block) specifications, it's important to note that the slot_suffix should start with an underscore symbol. For a comprehensive understanding of the expected slot_suffix format in userspace, please refer to the provided reference [1]. Links: [1] - https://source.android.com/docs/core/architecture/bootloader/updating#slots Based-on: https://android-review.googlesource.com/c/platform/external/u-boot/+/1446439 Reviewed-by: Mattijs Korpershoek Reviewed-by: Simon Glass Tested-by: Guillaume La Roque Signed-off-by: Dmitry Rokosov Tested-by: Mattijs Korpershoek # vim3_android Link: https://lore.kernel.org/r/20241017-android_ab_master-v5-6-43bfcc096d95@salutedevices.com Signed-off-by: Mattijs Korpershoek --- boot/android_ab.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/boot/android_ab.c b/boot/android_ab.c index c93e515410..a287eac04f 100644 --- a/boot/android_ab.c +++ b/boot/android_ab.c @@ -52,7 +52,7 @@ static int ab_control_default(struct bootloader_control *abc) if (!abc) return -EFAULT; - memcpy(abc->slot_suffix, "a\0\0\0", 4); + memcpy(abc->slot_suffix, "_a\0\0", 4); abc->magic = BOOT_CTRL_MAGIC; abc->version = BOOT_CTRL_VERSION; abc->nb_slot = NUM_SLOTS; @@ -328,7 +328,8 @@ int ab_select_slot(struct blk_desc *dev_desc, struct disk_partition *part_info, * or the device tree. */ memset(slot_suffix, 0, sizeof(slot_suffix)); - slot_suffix[0] = BOOT_SLOT_NAME(slot); + slot_suffix[0] = '_'; + slot_suffix[1] = BOOT_SLOT_NAME(slot); if (memcmp(abc->slot_suffix, slot_suffix, sizeof(slot_suffix))) { memcpy(abc->slot_suffix, slot_suffix, From 8f8e646d790199f023f82b8100b6e160d510206d Mon Sep 17 00:00:00 2001 From: Neil Armstrong Date: Thu, 17 Oct 2024 16:44:42 +0200 Subject: [PATCH 09/11] image: android: use ulong for kernel address When booting with platforms having > 4GiB of memory, the kernel physical address can be more than 32bits. Use ulong like all the other addresses, and fix the print to show the > 32bits address numbers. Signed-off-by: Neil Armstrong Reviewed-by: Mattijs Korpershoek Tested-by: Guillaume La Roque Link: https://lore.kernel.org/r/20241017-topic-fastboot-fixes-mkbootimg-v2-1-c3927102d931@linaro.org Signed-off-by: Mattijs Korpershoek --- boot/image-android.c | 4 ++-- include/android_image.h | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/boot/image-android.c b/boot/image-android.c index e74dd498a3..bb5f4f8448 100644 --- a/boot/image-android.c +++ b/boot/image-android.c @@ -256,7 +256,7 @@ int android_image_get_kernel(const void *hdr, ulong *os_data, ulong *os_len) { struct andr_image_data img_data = {0}; - u32 kernel_addr; + ulong kernel_addr; const struct legacy_img_hdr *ihdr; if (!android_image_get_data(hdr, vendor_boot_img, &img_data)) @@ -275,7 +275,7 @@ int android_image_get_kernel(const void *hdr, if (strlen(andr_tmp_str)) printf("Android's image name: %s\n", andr_tmp_str); - printf("Kernel load addr 0x%08x size %u KiB\n", + printf("Kernel load addr 0x%08lx size %u KiB\n", kernel_addr, DIV_ROUND_UP(img_data.kernel_size, 1024)); int len = 0; diff --git a/include/android_image.h b/include/android_image.h index d503c980b2..96820709b4 100644 --- a/include/android_image.h +++ b/include/android_image.h @@ -348,7 +348,7 @@ struct andr_image_data { ulong bootconfig_addr; /* bootconfig image address */ ulong bootconfig_size; /* bootconfig image size */ - u32 kernel_addr; /* physical load addr */ + ulong kernel_addr; /* physical load addr */ ulong ramdisk_addr; /* physical load addr */ ulong ramdisk_ptr; /* ramdisk address */ ulong dtb_load_addr; /* physical load address for DTB image */ From d5a85e8e95db57e350a092af62077917c7edd571 Mon Sep 17 00:00:00 2001 From: Neil Armstrong Date: Thu, 17 Oct 2024 16:44:43 +0200 Subject: [PATCH 10/11] image: android: do not boot XIP when kernel is compressed When trying to boot an android boot image with a compressed kernel, if the kernel is used in-place because it was created with mkbootimg, the space will be too small to properly uncompress. Take in account the compressed state, and if compressed use the kernel_addr_r which should be big enough. Signed-off-by: Neil Armstrong Reviewed-by: Mattijs Korpershoek Tested-by: Guillaume La Roque Link: https://lore.kernel.org/r/20241017-topic-fastboot-fixes-mkbootimg-v2-2-c3927102d931@linaro.org Signed-off-by: Mattijs Korpershoek --- boot/image-android.c | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/boot/image-android.c b/boot/image-android.c index bb5f4f8448..3adcc69a39 100644 --- a/boot/image-android.c +++ b/boot/image-android.c @@ -208,7 +208,8 @@ bool android_image_get_data(const void *boot_hdr, const void *vendor_boot_hdr, return true; } -static ulong android_image_get_kernel_addr(struct andr_image_data *img_data) +static ulong android_image_get_kernel_addr(struct andr_image_data *img_data, + ulong comp) { /* * All the Android tools that generate a boot.img use this @@ -221,8 +222,11 @@ static ulong android_image_get_kernel_addr(struct andr_image_data *img_data) * * Otherwise, we will return the actual value set by the user. */ - if (img_data->kernel_addr == ANDROID_IMAGE_DEFAULT_KERNEL_ADDR) - return img_data->kernel_ptr; + if (img_data->kernel_addr == ANDROID_IMAGE_DEFAULT_KERNEL_ADDR) { + if (comp == IH_COMP_NONE) + return img_data->kernel_ptr; + return env_get_ulong("kernel_addr_r", 16, 0); + } /* * abootimg creates images where all load addresses are 0 @@ -258,11 +262,14 @@ int android_image_get_kernel(const void *hdr, struct andr_image_data img_data = {0}; ulong kernel_addr; const struct legacy_img_hdr *ihdr; + ulong comp; if (!android_image_get_data(hdr, vendor_boot_img, &img_data)) return -EINVAL; - kernel_addr = android_image_get_kernel_addr(&img_data); + comp = android_image_get_kcomp(hdr, vendor_boot_img); + + kernel_addr = android_image_get_kernel_addr(&img_data, comp); ihdr = (const struct legacy_img_hdr *)img_data.kernel_ptr; /* @@ -359,11 +366,14 @@ ulong android_image_get_kload(const void *hdr, const void *vendor_boot_img) { struct andr_image_data img_data; + ulong comp; if (!android_image_get_data(hdr, vendor_boot_img, &img_data)) return -EINVAL; - return android_image_get_kernel_addr(&img_data); + comp = android_image_get_kcomp(hdr, vendor_boot_img); + + return android_image_get_kernel_addr(&img_data, comp); } ulong android_image_get_kcomp(const void *hdr, From 21e7fa0e3ac599737cd235bb5233765e8a1b8b0f Mon Sep 17 00:00:00 2001 From: Neil Armstrong Date: Thu, 17 Oct 2024 16:44:44 +0200 Subject: [PATCH 11/11] image: android: handle ramdisk default address The two tools that create android boot images, mkbootimg and the fastboot client, set the kernel address by default to 0x11008000. U-boot always honors this field, and will try to copy the ramdisk to whatever value is set in the header, which won't be mapped to the actual RAM on most platforms, resulting in the kernel obviously not booting. All the targets in U-Boot right now will download the android boot image to CONFIG_SYS_LOAD_ADDR, which means that it will already have been downloaded to some location that is suitable to use the ramdisk in-place for header version 0 to 2. For header version 3 and later, the ramdisk can't be used in-place to use ramdisk_addr_r in this case. Signed-off-by: Neil Armstrong Reviewed-by: Mattijs Korpershoek Tested-by: Guillaume La Roque Link: https://lore.kernel.org/r/20241017-topic-fastboot-fixes-mkbootimg-v2-3-c3927102d931@linaro.org Signed-off-by: Mattijs Korpershoek --- boot/image-android.c | 38 ++++++++++++++++++++++++++++++-------- 1 file changed, 30 insertions(+), 8 deletions(-) diff --git a/boot/image-android.c b/boot/image-android.c index 3adcc69a39..cd01278f21 100644 --- a/boot/image-android.c +++ b/boot/image-android.c @@ -14,6 +14,7 @@ #include #define ANDROID_IMAGE_DEFAULT_KERNEL_ADDR 0x10008000 +#define ANDROID_IMAGE_DEFAULT_RAMDISK_ADDR 0x11000000 static char andr_tmp_str[ANDR_BOOT_ARGS_SIZE + 1]; @@ -405,9 +406,25 @@ int android_image_get_ramdisk(const void *hdr, const void *vendor_boot_img, if (!img_data.ramdisk_size) return -ENOENT; - + /* + * Android tools can generate a boot.img with default load address + * or 0, even though it doesn't really make a lot of sense, and it + * might be valid on some platforms, we treat that address as + * the default value for this field, and try to pass ramdisk + * in place if possible. + */ if (img_data.header_version > 2) { - ramdisk_ptr = img_data.ramdisk_addr; + /* Ramdisk can't be used in-place, copy it to ramdisk_addr_r */ + if (img_data.ramdisk_addr == ANDROID_IMAGE_DEFAULT_RAMDISK_ADDR) { + ramdisk_ptr = env_get_ulong("ramdisk_addr_r", 16, 0); + if (!ramdisk_ptr) { + printf("Invalid ramdisk_addr_r to copy ramdisk into\n"); + return -EINVAL; + } + } else { + ramdisk_ptr = img_data.ramdisk_addr; + } + *rd_data = ramdisk_ptr; memcpy((void *)(ramdisk_ptr), (void *)img_data.vendor_ramdisk_ptr, img_data.vendor_ramdisk_size); ramdisk_ptr += img_data.vendor_ramdisk_size; @@ -420,15 +437,20 @@ int android_image_get_ramdisk(const void *hdr, const void *vendor_boot_img, img_data.bootconfig_size); } } else { - ramdisk_ptr = img_data.ramdisk_addr; - memcpy((void *)(ramdisk_ptr), (void *)img_data.ramdisk_ptr, - img_data.ramdisk_size); + /* Ramdisk can be used in-place, use current ptr */ + if (img_data.ramdisk_addr == 0 || + img_data.ramdisk_addr == ANDROID_IMAGE_DEFAULT_RAMDISK_ADDR) { + *rd_data = img_data.ramdisk_ptr; + } else { + ramdisk_ptr = img_data.ramdisk_addr; + *rd_data = ramdisk_ptr; + memcpy((void *)(ramdisk_ptr), (void *)img_data.ramdisk_ptr, + img_data.ramdisk_size); + } } printf("RAM disk load addr 0x%08lx size %u KiB\n", - img_data.ramdisk_addr, DIV_ROUND_UP(img_data.ramdisk_size, 1024)); - - *rd_data = img_data.ramdisk_addr; + *rd_data, DIV_ROUND_UP(img_data.ramdisk_size, 1024)); *rd_len = img_data.ramdisk_size; return 0;