From 01874ac7c06b8c657e7c3fda5ac555f821ef5b36 Mon Sep 17 00:00:00 2001 From: Dmitry Rokosov Date: Thu, 17 Oct 2024 17:12:06 +0300 Subject: 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 ++++++++++++++++++++++++------------------- 1 file changed, 24 insertions(+), 19 deletions(-) (limited to 'boot') diff --git a/boot/android_ab.c b/boot/android_ab.c index 1196a189ed5..0045c8133a8 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. */ -- cgit v1.2.3 From a995084beb6682748002878ccb4b8c4de9fc0136 Mon Sep 17 00:00:00 2001 From: Dmitry Rokosov Date: Thu, 17 Oct 2024 17:12:10 +0300 Subject: 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 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 68 insertions(+) (limited to 'boot') diff --git a/boot/android_ab.c b/boot/android_ab.c index 0045c8133a8..c93e5154101 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; +} -- cgit v1.2.3 From 55c876c6f9b787488c7a9f9c678398c48d13db6f Mon Sep 17 00:00:00 2001 From: Dmitry Rokosov Date: Thu, 17 Oct 2024 17:12:11 +0300 Subject: 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(-) (limited to 'boot') diff --git a/boot/android_ab.c b/boot/android_ab.c index c93e5154101..a287eac04fe 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, -- cgit v1.2.3 From 8f8e646d790199f023f82b8100b6e160d510206d Mon Sep 17 00:00:00 2001 From: Neil Armstrong Date: Thu, 17 Oct 2024 16:44:42 +0200 Subject: 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 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'boot') diff --git a/boot/image-android.c b/boot/image-android.c index e74dd498a30..bb5f4f84487 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; -- cgit v1.2.3 From d5a85e8e95db57e350a092af62077917c7edd571 Mon Sep 17 00:00:00 2001 From: Neil Armstrong Date: Thu, 17 Oct 2024 16:44:43 +0200 Subject: 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(-) (limited to 'boot') diff --git a/boot/image-android.c b/boot/image-android.c index bb5f4f84487..3adcc69a392 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, -- cgit v1.2.3 From 21e7fa0e3ac599737cd235bb5233765e8a1b8b0f Mon Sep 17 00:00:00 2001 From: Neil Armstrong Date: Thu, 17 Oct 2024 16:44:44 +0200 Subject: 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(-) (limited to 'boot') diff --git a/boot/image-android.c b/boot/image-android.c index 3adcc69a392..cd01278f211 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; -- cgit v1.2.3