From 9df731a176aab8e03b984b681b1bea01ccff6644 Mon Sep 17 00:00:00 2001 From: hc <hc@nodka.com> Date: Mon, 06 Nov 2023 07:23:06 +0000 Subject: [PATCH] rk3568 rt uboot init --- u-boot/common/android_bootloader.c | 415 ++++++++++++++++++++++++++++++++++++++++++++++++++-------- 1 files changed, 355 insertions(+), 60 deletions(-) diff --git a/u-boot/common/android_bootloader.c b/u-boot/common/android_bootloader.c index 772e6bf..ab080b8 100644 --- a/u-boot/common/android_bootloader.c +++ b/u-boot/common/android_bootloader.c @@ -18,6 +18,7 @@ #include <dt_table.h> #include <image-android-dt.h> #include <malloc.h> +#include <mp_boot.h> #include <fdt_support.h> #include <fs.h> #include <boot_rkimg.h> @@ -462,15 +463,305 @@ slot->successful_boot = 0; } +static char *join_str(const char *a, const char *b) +{ + size_t len = strlen(a) + strlen(b) + 1 /* null term */; + char *ret = (char *)malloc(len); + + if (!ret) { + debug("failed to alloc %zu\n", len); + return NULL; + } + strcpy(ret, a); + strcat(ret, b); + + return ret; +} + +static size_t get_partition_size(AvbOps *ops, char *name, + const char *slot_suffix) +{ + char *partition_name = join_str(name, slot_suffix); + uint64_t size = 0; + AvbIOResult res; + + if (partition_name == NULL) + goto bail; + + res = ops->get_size_of_partition(ops, partition_name, &size); + if (res != AVB_IO_RESULT_OK && res != AVB_IO_RESULT_ERROR_NO_SUCH_PARTITION) + size = 0; +bail: + if (partition_name) + free(partition_name); + + return size; +} + +static struct AvbOpsData preload_user_data; + +static int avb_image_distribute_prepare(AvbSlotVerifyData *slot_data, + AvbOps *ops, char *slot_suffix) +{ + struct AvbOpsData *data = (struct AvbOpsData *)(ops->user_data); + size_t vendor_boot_size; + size_t init_boot_size; + size_t resource_size; + size_t boot_size; + void *image_buf; + + boot_size = max(get_partition_size(ops, ANDROID_PARTITION_BOOT, slot_suffix), + get_partition_size(ops, ANDROID_PARTITION_RECOVERY, slot_suffix)); + init_boot_size = get_partition_size(ops, + ANDROID_PARTITION_INIT_BOOT, slot_suffix); + vendor_boot_size = get_partition_size(ops, + ANDROID_PARTITION_VENDOR_BOOT, slot_suffix); + resource_size = get_partition_size(ops, + ANDROID_PARTITION_RESOURCE, slot_suffix); + image_buf = sysmem_alloc(MEM_AVB_ANDROID, + boot_size + init_boot_size + + vendor_boot_size + resource_size); + if (!image_buf) { + printf("avb: sysmem alloc failed\n"); + return -ENOMEM; + } + + /* layout: | boot/recovery | vendor_boot | init_boot | resource | */ + data->slot_suffix = slot_suffix; + data->boot.addr = image_buf; + data->boot.size = 0; + data->vendor_boot.addr = data->boot.addr + boot_size; + data->vendor_boot.size = 0; + data->init_boot.addr = data->vendor_boot.addr + vendor_boot_size; + data->init_boot.size = 0; + data->resource.addr = data->init_boot.addr + init_boot_size; + data->resource.size = 0; + + return 0; +} + +static int avb_image_distribute_finish(AvbSlotVerifyData *slot_data, + AvbSlotVerifyFlags flags, + ulong *load_address) +{ + struct andr_img_hdr *hdr; + ulong load_addr = *load_address; + void *vendor_boot_hdr = NULL; + void *init_boot_hdr = NULL; + void *boot_hdr = NULL; + char *part_name; + int i, ret; + + for (i = 0; i < slot_data->num_loaded_partitions; i++) { + part_name = slot_data->loaded_partitions[i].partition_name; + if (!strncmp(ANDROID_PARTITION_BOOT, part_name, 4) || + !strncmp(ANDROID_PARTITION_RECOVERY, part_name, 8)) { + boot_hdr = slot_data->loaded_partitions[i].data; + } else if (!strncmp(ANDROID_PARTITION_INIT_BOOT, part_name, 9)) { + init_boot_hdr = slot_data->loaded_partitions[i].data; + } else if (!strncmp(ANDROID_PARTITION_VENDOR_BOOT, part_name, 11)) { + vendor_boot_hdr = slot_data->loaded_partitions[i].data; + } + } + + /* + * populate boot_img_hdr_v34 + * + * If allow verification error: the images are loaded by + * ops->get_preloaded_partition() which auto populates + * boot_img_hdr_v34. + * + * If not allow verification error: the images are full loaded + * by ops->read_from_partition() which doesn't populate + * boot_img_hdr_v34, we need to fix it here for bootm and + */ + + hdr = boot_hdr; + if (hdr->header_version >= 3 && + !(flags & AVB_SLOT_VERIFY_FLAGS_ALLOW_VERIFICATION_ERROR)) { + hdr = malloc(sizeof(struct andr_img_hdr)); + if (!hdr) + return -ENOMEM; + + ret = populate_boot_info(boot_hdr, vendor_boot_hdr, + init_boot_hdr, hdr, true); + if (ret < 0) { + printf("avb: populate boot info failed, ret=%d\n", ret); + return ret; + } + memcpy(boot_hdr, hdr, sizeof(*hdr)); + } + + /* distribute ! */ + load_addr -= hdr->page_size; + if (android_image_memcpy_separate(boot_hdr, &load_addr)) { + printf("Failed to separate copy android image\n"); + return AVB_SLOT_VERIFY_RESULT_ERROR_IO; + } + + *load_address = load_addr; + + return 0; +} + +int android_image_verify_resource(const char *boot_part, ulong *resc_buf) +{ + const char *requested_partitions[] = { + NULL, + NULL, + }; + struct AvbOpsData *data; + uint8_t unlocked = true; + AvbOps *ops; + AvbSlotVerifyFlags flags; + AvbSlotVerifyData *slot_data = {NULL}; + AvbSlotVerifyResult verify_result; + char slot_suffix[3] = {0}; + char *part_name; + void *image_buf = NULL; + int retry_no_vbmeta_partition = 1; + int i, ret; + + ops = avb_ops_user_new(); + if (ops == NULL) { + printf("avb_ops_user_new() failed!\n"); + return -AVB_SLOT_VERIFY_RESULT_ERROR_OOM; + } + + if (ops->read_is_device_unlocked(ops, (bool *)&unlocked) != AVB_IO_RESULT_OK) + printf("Error determining whether device is unlocked.\n"); + + printf("Device is: %s\n", (unlocked & LOCK_MASK)? "UNLOCKED" : "LOCKED"); + + if (unlocked & LOCK_MASK) { + *resc_buf = 0; + return 0; + } + + flags = AVB_SLOT_VERIFY_FLAGS_NONE; + if (strcmp(boot_part, ANDROID_PARTITION_RECOVERY) == 0) + flags |= AVB_SLOT_VERIFY_FLAGS_NO_VBMETA_PARTITION; + +#ifdef CONFIG_ANDROID_AB + part_name = strdup(boot_part); + *(part_name + strlen(boot_part) - 2) = '\0'; + requested_partitions[0] = part_name; + + ret = rk_avb_get_current_slot(slot_suffix); + if (ret) { + printf("Failed to get slot suffix, ret=%d\n", ret); + return ret; + } +#else + requested_partitions[0] = boot_part; +#endif + data = (struct AvbOpsData *)(ops->user_data); + ret = avb_image_distribute_prepare(slot_data, ops, slot_suffix); + if (ret) { + printf("avb image distribute prepare failed %d\n", ret); + return ret; + } + +retry_verify: + verify_result = + avb_slot_verify(ops, + requested_partitions, + slot_suffix, + flags, + AVB_HASHTREE_ERROR_MODE_RESTART, + &slot_data); + if (verify_result != AVB_SLOT_VERIFY_RESULT_OK && + verify_result != AVB_SLOT_VERIFY_RESULT_ERROR_PUBLIC_KEY_REJECTED) { + if (retry_no_vbmeta_partition && strcmp(boot_part, ANDROID_PARTITION_RECOVERY) == 0) { + printf("Verify recovery with vbmeta.\n"); + flags &= ~AVB_SLOT_VERIFY_FLAGS_NO_VBMETA_PARTITION; + retry_no_vbmeta_partition = 0; + goto retry_verify; + } + } + + if (verify_result != AVB_SLOT_VERIFY_RESULT_OK || !slot_data) { + sysmem_free((ulong)data->boot.addr); + return verify_result; + } + + for (i = 0; i < slot_data->num_loaded_partitions; i++) { + part_name = slot_data->loaded_partitions[i].partition_name; + if (!strncmp(ANDROID_PARTITION_RESOURCE, part_name, 8)) { + image_buf = slot_data->loaded_partitions[i].data; + break; + } else if (!strncmp(ANDROID_PARTITION_BOOT, part_name, 4) || + !strncmp(ANDROID_PARTITION_RECOVERY, part_name, 8)) { + struct andr_img_hdr *hdr; + + hdr = (void *)slot_data->loaded_partitions[i].data; + if (android_image_check_header(hdr)) + continue; + + if (hdr->header_version <= 2) { + image_buf = (void *)hdr + hdr->page_size + + ALIGN(hdr->kernel_size, hdr->page_size) + + ALIGN(hdr->ramdisk_size, hdr->page_size); + break; + } + } + } + + if (image_buf) { + memcpy((char *)&preload_user_data, (char *)data, sizeof(*data)); + *resc_buf = (ulong)image_buf; + } + + return 0; +} + +/* + * AVB Policy. + * + * == avb with unlock: + * Don't process hash verify. + * Go pre-loaded path: Loading vendor_boot and init_boot + * directly to where they should be, while loading the + * boot/recovery. The boot message tells like: + * ··· + * preloaded: distribute image from 'boot_a' + * preloaded: distribute image from 'init_boot_a' + * preloaded: distribute image from 'vendor_boot_a' + * ··· + * + * == avb with lock: + * Process hash verify. + * Go pre-loaded path: Loading full vendor_boot, init_boot and + * boot/recovery one by one to verify, and distributing them to + * where they should be by memcpy at last. + * + * The three images share a large memory buffer that allocated + * by sysmem_alloc(), it locate at high memory address that + * just lower than SP bottom. The boot message tells like: + * ··· + * preloaded: full image from 'boot_a' at 0xe47f90c0 - 0xe7a4b0c0 + * preloaded: full image from 'init_boot_a' at 0xeaff90c0 - 0xeb2950c0 + * preloaded: full image from 'vendor_boot_a' at 0xe87f90c0 - 0xe9f6e0c0 + * ··· + */ static AvbSlotVerifyResult android_slot_verify(char *boot_partname, unsigned long *android_load_address, char *slot_suffix) { - const char *requested_partitions[1] = {NULL}; + const char *requested_partitions[] = { + boot_partname, + NULL, + NULL, + NULL, + }; + struct AvbOpsData *data; + struct blk_desc *dev_desc; + struct andr_img_hdr *hdr; + disk_partition_t part_info; uint8_t unlocked = true; AvbOps *ops; AvbSlotVerifyFlags flags; - AvbSlotVerifyData *slot_data[1] = {NULL}; + AvbSlotVerifyData *slot_data = {NULL}; AvbSlotVerifyResult verify_result; AvbABData ab_data, ab_data_orig; size_t slot_index_to_boot = 0; @@ -478,9 +769,29 @@ char can_boot = 1; char retry_no_vbmeta_partition = 1; unsigned long load_address = *android_load_address; - struct andr_img_hdr *hdr; + int ret; - requested_partitions[0] = boot_partname; + dev_desc = rockchip_get_bootdev(); + if (!dev_desc) + return AVB_IO_RESULT_ERROR_IO; + + if (part_get_info_by_name(dev_desc, boot_partname, &part_info) < 0) { + printf("Could not find \"%s\" partition\n", boot_partname); + return AVB_IO_RESULT_ERROR_NO_SUCH_PARTITION; + } + + hdr = populate_andr_img_hdr(dev_desc, &part_info); + if (!hdr) { + printf("No valid android hdr\n"); + return AVB_IO_RESULT_ERROR_NO_SUCH_VALUE; + } + + if (hdr->header_version >= 4) { + requested_partitions[1] = ANDROID_PARTITION_VENDOR_BOOT; + if (((hdr->os_version >> 25) & 0x7f) >= 13) + requested_partitions[2] = ANDROID_PARTITION_INIT_BOOT; + } + ops = avb_ops_user_new(); if (ops == NULL) { printf("avb_ops_user_new() failed!\n"); @@ -497,7 +808,7 @@ if (unlocked & LOCK_MASK) flags |= AVB_SLOT_VERIFY_FLAGS_ALLOW_VERIFICATION_ERROR; - if(load_metadata(ops->ab_ops, &ab_data, &ab_data_orig)) { + if (load_metadata(ops->ab_ops, &ab_data, &ab_data_orig)) { printf("Can not load metadata\n"); return AVB_SLOT_VERIFY_RESULT_ERROR_IO; } @@ -509,8 +820,30 @@ else slot_index_to_boot = 0; - if (strcmp(boot_partname, "recovery") == 0) + if (strcmp(boot_partname, ANDROID_PARTITION_RECOVERY) == 0) flags |= AVB_SLOT_VERIFY_FLAGS_NO_VBMETA_PARTITION; + +#ifdef CONFIG_MP_BOOT + preload_user_data.boot.addr = (void *)mpb_post(1); + preload_user_data.boot.size = (size_t)mpb_post(2); +#endif + + /* use preload one if available */ + if (preload_user_data.boot.addr) { + data = (struct AvbOpsData *)(ops->user_data); + + data->slot_suffix = slot_suffix; + data->boot = preload_user_data.boot; + data->vendor_boot = preload_user_data.vendor_boot; + data->init_boot = preload_user_data.init_boot; + data->resource = preload_user_data.resource; + } else { + ret = avb_image_distribute_prepare(slot_data, ops, slot_suffix); + if (ret < 0) { + printf("avb image distribute prepare failed %d\n", ret); + return AVB_SLOT_VERIFY_RESULT_ERROR_OOM; + } + } retry_verify: verify_result = @@ -519,10 +852,10 @@ slot_suffix, flags, AVB_HASHTREE_ERROR_MODE_RESTART, - &slot_data[0]); + &slot_data); if (verify_result != AVB_SLOT_VERIFY_RESULT_OK && verify_result != AVB_SLOT_VERIFY_RESULT_ERROR_PUBLIC_KEY_REJECTED) { - if (retry_no_vbmeta_partition && strcmp(boot_partname, "recovery") == 0) { + if (retry_no_vbmeta_partition && strcmp(boot_partname, ANDROID_PARTITION_RECOVERY) == 0) { printf("Verify recovery with vbmeta.\n"); flags &= ~AVB_SLOT_VERIFY_FLAGS_NO_VBMETA_PARTITION; retry_no_vbmeta_partition = 0; @@ -558,7 +891,7 @@ break; } - if (!slot_data[0]) { + if (!slot_data) { can_boot = 0; goto out; } @@ -569,12 +902,12 @@ int len = 0; char *bootargs, *newbootargs; #ifdef CONFIG_ANDROID_AVB_ROLLBACK_INDEX - if (rk_avb_update_stored_rollback_indexes_for_slot(ops, slot_data[0])) + if (rk_avb_update_stored_rollback_indexes_for_slot(ops, slot_data)) printf("Fail to update the rollback indexes.\n"); #endif - if (*slot_data[0]->cmdline) { - debug("Kernel command line: %s\n", slot_data[0]->cmdline); - len += strlen(slot_data[0]->cmdline); + if (slot_data->cmdline) { + debug("Kernel command line: %s\n", slot_data->cmdline); + len += strlen(slot_data->cmdline); } bootargs = env_get("bootargs"); @@ -593,49 +926,15 @@ strcpy(newbootargs, bootargs); strcat(newbootargs, " "); } - if (*slot_data[0]->cmdline) - strcat(newbootargs, slot_data[0]->cmdline); + if (slot_data->cmdline) + strcat(newbootargs, slot_data->cmdline); env_set("bootargs", newbootargs); - hdr = (void *)slot_data[0]->loaded_partitions->data; - - /* - * populate boot_img_hdr_v34 - * - * If allow verification error: the image is loaded by - * ops->get_preloaded_partition() which auto populates - * boot_img_hdr_v34. - * - * If not allow verification error: the image is full loaded - * by ops->read_from_partition() which doesn't populate - * boot_img_hdr_v34, we need to fix it here. - */ - if (hdr->header_version >= 3 && - !(flags & AVB_SLOT_VERIFY_FLAGS_ALLOW_VERIFICATION_ERROR)) { - struct andr_img_hdr *v3hdr; - struct blk_desc *dev_desc; - disk_partition_t part; - - dev_desc = rockchip_get_bootdev(); - if (!dev_desc) - return -1; - - if (part_get_info_by_name(dev_desc, - boot_partname, &part) < 0) - return -1; - - v3hdr = populate_andr_img_hdr(dev_desc, &part); - if (v3hdr) { - memcpy(hdr, v3hdr, sizeof(*v3hdr)); - free(v3hdr); - } - } - - /* Reserve page_size */ - load_address -= hdr->page_size; - if (android_image_memcpy_separate(hdr, &load_address)) { - printf("Failed to separate copy android image\n"); - return AVB_SLOT_VERIFY_RESULT_ERROR_IO; + /* if need, distribute full image to where they should be */ + ret = avb_image_distribute_finish(slot_data, flags, &load_address); + if (ret) { + printf("avb image distribute finish failed %d\n", ret); + return ret; } *android_load_address = load_address; } else { @@ -649,8 +948,8 @@ verify_result = AVB_SLOT_VERIFY_RESULT_ERROR_IO; } - if (slot_data[0] != NULL) - avb_slot_verify_data_free(slot_data[0]); + if (slot_data != NULL) + avb_slot_verify_data_free(slot_data); if ((unlocked & LOCK_MASK) && can_boot) return 0; @@ -1047,10 +1346,6 @@ printf("Android image load failed\n"); return -1; } -#endif - -#ifdef CONFIG_ANDROID_AB - ab_update_root_uuid(); #endif /* Set Android root variables. */ -- Gitblit v1.6.2