From be683756f620349966e0ebb4a5e02e5ff03c8a8e Mon Sep 17 00:00:00 2001 From: Ruslan Trofymenko Date: Fri, 14 Jun 2019 17:01:26 +0300 Subject: [PATCH 01/24] cmd: part: Add 'number' sub-command This sub-command serves for getting the partition index from partition name. Also it can be used to test the existence of specified partition. Use case: For example, in most CI environments this U-Boot command for automatic testing of Linux rootfs is used: => setenv bootpart 1:f where 0xf is "userdata" partition. But the number of "userdata" partition can be changed any time, when partition table is changed. So it would be nice to get rid of that 0xf magic number and use partition name instead, like this: => part number mmc 1 userdata part_num => setenv bootpart 1:${part_num} Signed-off-by: Ruslan Trofymenko Signed-off-by: Igor Opaniuk Reviewed-by: Alistair Strachan Reviewed-by: Sam Protsenko Reviewed-by: Simon Glass Reviewed-by: Sam Protsenko --- cmd/part.c | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/cmd/part.c b/cmd/part.c index bfb6488b0f2..653e13ced17 100644 --- a/cmd/part.c +++ b/cmd/part.c @@ -24,6 +24,7 @@ enum cmd_part_info { CMD_PART_INFO_START = 0, CMD_PART_INFO_SIZE, + CMD_PART_INFO_NUMBER }; static int do_part_uuid(int argc, char * const argv[]) @@ -149,6 +150,9 @@ static int do_part_info(int argc, char * const argv[], enum cmd_part_info param) case CMD_PART_INFO_SIZE: snprintf(buf, sizeof(buf), LBAF, info.size); break; + case CMD_PART_INFO_NUMBER: + snprintf(buf, sizeof(buf), "%d", part); + break; default: printf("** Unknown cmd_part_info value: %d\n", param); return 1; @@ -172,6 +176,11 @@ static int do_part_size(int argc, char * const argv[]) return do_part_info(argc, argv, CMD_PART_INFO_SIZE); } +static int do_part_number(int argc, char * const argv[]) +{ + return do_part_info(argc, argv, CMD_PART_INFO_NUMBER); +} + static int do_part(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) { if (argc < 2) @@ -185,6 +194,8 @@ static int do_part(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) return do_part_start(argc - 2, argv + 2); else if (!strcmp(argv[1], "size")) return do_part_size(argc - 2, argv + 2); + else if (!strcmp(argv[1], "number")) + return do_part_number(argc - 2, argv + 2); return CMD_RET_USAGE; } @@ -206,5 +217,8 @@ U_BOOT_CMD( " part can be either partition number or partition name\n" "part size \n" " - set environment variable to the size of the partition (in blocks)\n" - " part can be either partition number or partition name" + " part can be either partition number or partition name\n" + "part number \n" + " - set environment variable to the partition number using the partition name\n" + " part must be specified as partition name" ); From dfaad8208f069f95d35f52c4cc69b1a05cd60f75 Mon Sep 17 00:00:00 2001 From: Leon Yu Date: Fri, 21 Jun 2019 12:12:39 +0800 Subject: [PATCH 02/24] menu: don't bother going interactive with just one menu item If there is only one menu item available, prompting user to enter choice makes little sense and just causes unnecessary boot delay. This change makes menu_get_choice return the only one item when there is no other choices. Signed-off-by: Leon Yu Cc: Tom Warren Cc: Stephen Warren Cc: Thierry Reding --- common/menu.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/common/menu.c b/common/menu.c index 0f0a29ac2ee..7b66d199a9b 100644 --- a/common/menu.c +++ b/common/menu.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-2.0+ /* * Copyright 2010-2011 Calxeda, Inc. + * Copyright (c) 2019, NVIDIA CORPORATION. All rights reserved. */ #include @@ -39,6 +40,7 @@ struct menu { char *(*item_choice)(void *); void *item_choice_data; struct list_head items; + int item_cnt; }; /* @@ -271,7 +273,7 @@ int menu_get_choice(struct menu *m, void **choice) if (!m || !choice) return -EINVAL; - if (!m->prompt) + if (!m->prompt || m->item_cnt == 1) return menu_default_choice(m, choice); return menu_interactive_choice(m, choice); @@ -323,6 +325,7 @@ int menu_item_add(struct menu *m, char *item_key, void *item_data) item->data = item_data; list_add_tail(&item->list, &m->items); + m->item_cnt++; return 1; } @@ -374,6 +377,7 @@ struct menu *menu_create(char *title, int timeout, int prompt, m->item_data_print = item_data_print; m->item_choice = item_choice; m->item_choice_data = item_choice_data; + m->item_cnt = 0; if (title) { m->title = strdup(title); From 39f790b03ace5b1b7861b154b195eabbe344cfa1 Mon Sep 17 00:00:00 2001 From: Roman Stratiienko Date: Mon, 3 Jun 2019 15:38:13 +0300 Subject: [PATCH 03/24] image: android: allow to wrap uImage into the Android boot image This allows to use any available compression format with Android boot image Since not all available compression formats have a magic number we should explicitly specify type of compression. For this purpose using uImage format becomes very useful, as this format is well-known by the community and mkimage tool is already available. Usage example: mkimage -A ARM64 -T kernel -C lzma -d Image.lzma out/kernel At this moment only -C option is handled, but specifying -A and -T options are recommended for compatibility reasons in the future. Kernel that compressed with LZ4 can be already used without wrapping into the uImage, but I recommend wrapping it into the uImage in order to avoid situations when by some mistake legacy LZ4 is used, that is interpreted as raw Image and causes CPU to enter Exception Handler without providing any meaningful explanation to the user. Signed-off-by: Roman Stratiienko --- common/image-android.c | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/common/image-android.c b/common/image-android.c index 8b0f6b3b8ba..6c9568a655d 100644 --- a/common/image-android.c +++ b/common/image-android.c @@ -52,6 +52,8 @@ int android_image_get_kernel(const struct andr_img_hdr *hdr, int verify, ulong *os_data, ulong *os_len) { u32 kernel_addr = android_image_get_kernel_addr(hdr); + const struct image_header *ihdr = (const struct image_header *) + ((uintptr_t)hdr + hdr->page_size); /* * Not all Android tools use the id field for signing the image with @@ -93,11 +95,19 @@ int android_image_get_kernel(const struct andr_img_hdr *hdr, int verify, env_set("bootargs", newbootargs); if (os_data) { - *os_data = (ulong)hdr; - *os_data += hdr->page_size; + if (image_get_magic(ihdr) == IH_MAGIC) { + *os_data = image_get_data(ihdr); + } else { + *os_data = (ulong)hdr; + *os_data += hdr->page_size; + } + } + if (os_len) { + if (image_get_magic(ihdr) == IH_MAGIC) + *os_len = image_get_data_size(ihdr); + else + *os_len = hdr->kernel_size; } - if (os_len) - *os_len = hdr->kernel_size; return 0; } @@ -131,7 +141,9 @@ ulong android_image_get_kcomp(const struct andr_img_hdr *hdr) { const void *p = (void *)((uintptr_t)hdr + hdr->page_size); - if (get_unaligned_le32(p) == LZ4F_MAGIC) + if (image_get_magic((image_header_t *)p) == IH_MAGIC) + return image_get_comp((image_header_t *)p); + else if (get_unaligned_le32(p) == LZ4F_MAGIC) return IH_COMP_LZ4; else return IH_COMP_NONE; From cef4de88359ddc37954046a758c0152dda53069b Mon Sep 17 00:00:00 2001 From: Eugeniu Rosca Date: Fri, 19 Jul 2019 23:26:11 +0200 Subject: [PATCH 04/24] treewide: Fix stale references of Android docs Commit 9bdf0e8fef86 ("doc: relocate/rename Android README and add BCB overview") left some obsolete references of Android documents/paths. This has been pointed out by Sam (thanks!) in: https://patchwork.ozlabs.org/patch/1104245/#2208134 Fixes: 9bdf0e8fef86 ("doc: relocate/rename Android README and add BCB overview") Reported-by: Sam Protsenko Suggested-by: Sam Protsenko Signed-off-by: Eugeniu Rosca Reviewed-by: Igor Opaniuk Reviewed-by: Sam Protsenko --- cmd/Kconfig | 2 +- test/py/tests/test_avb.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/cmd/Kconfig b/cmd/Kconfig index 175c6ad9e33..e1e050f4ad5 100644 --- a/cmd/Kconfig +++ b/cmd/Kconfig @@ -735,7 +735,7 @@ config CMD_FASTBOOT Android devices. Fastboot requires either the network stack enabled or support for acting as a USB device. - See doc/README.android-fastboot for more information. + See doc/android/fastboot.txt for more information. config CMD_FDC bool "fdcboot - Boot from floppy device" diff --git a/test/py/tests/test_avb.py b/test/py/tests/test_avb.py index 2bb75ed6e2a..81324234355 100644 --- a/test/py/tests/test_avb.py +++ b/test/py/tests/test_avb.py @@ -8,7 +8,7 @@ This tests Android Verified Boot 2.0 support in U-boot: For additional details about how to build proper vbmeta partition -check doc/README.avb2 +check doc/android/avb2.txt For configuration verification: - Corrupt boot partition and check for failure From e47b73b821f7f6078c0d11b453545507e25727cc Mon Sep 17 00:00:00 2001 From: Eugeniu Rosca Date: Fri, 19 Jul 2019 23:26:12 +0200 Subject: [PATCH 05/24] cmd: bcb: Fix duplicated handling in two case-branches Fix warning V1037 reported by PVS-Studio Static Analyzer: Two or more case-branches perform the same actions. Check lines: 49, 53 Fixes: db7b7a05b267 ("cmd: Add 'bcb' command to read/modify/write BCB fields") Signed-off-by: Eugeniu Rosca Reviewed-by: Igor Opaniuk Reviewed-by: Sam Protsenko --- cmd/bcb.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/cmd/bcb.c b/cmd/bcb.c index 2bd5a744deb..3b1c7434e28 100644 --- a/cmd/bcb.c +++ b/cmd/bcb.c @@ -46,9 +46,6 @@ static int bcb_is_misused(int argc, char *const argv[]) switch (cmd) { case BCB_CMD_LOAD: - if (argc != 3) - goto err; - break; case BCB_CMD_FIELD_SET: if (argc != 3) goto err; From 739168cfdc18690273e24a34f0360a61e6658424 Mon Sep 17 00:00:00 2001 From: Eugeniu Rosca Date: Fri, 19 Jul 2019 23:26:13 +0200 Subject: [PATCH 06/24] cmd: bcb: Use strcmp() instead of strncmp() for string literals Quote from https://patchwork.ozlabs.org/patch/1104244/#2210814: ----------8<----------- strncmp() is chosen for the sake of paranoid/defensive programming. Indeed, strncmp() is not really needed when comparing a variable with a string literal. We expect strcmp() to behave safely even if the string variable is not NUL-terminated. In the same scenario, Linux v5.2-rc7 uses both strcmp() and strncmp(), but the frequency of strcmp() is higher: $ git --version git version 2.22.0 $ (Linux 5.2-rc7) git grep -En 'strncmp\([^"]*"[[:alnum:]]+"' | wc -l 1066 $ (Linux 5.2-rc7) git grep -En 'strcmp\([^"]*"[[:alnum:]]+"' | wc -l 1968 A quick "strcmp vs strncmp" object size test shows that strcmp() generates smaller memory footprint (gcc-8, x86_64): $ (U-Boot) size cmd/bcb-strncmp.o cmd/bcb-strcmp.o text data bss dec hex filename 3373 400 2048 5821 16bd cmd/bcb-strncmp.o 3314 400 2048 5762 1682 cmd/bcb-strcmp.o So, overall, I agree to use strcmp() whenever variables are compared with string literals. ----------8<----------- Fixes: db7b7a05b267 ("cmd: Add 'bcb' command to read/modify/write BCB fields") Reported-by: Simon Glass Signed-off-by: Eugeniu Rosca Reviewed-by: Sam Protsenko Reviewed-by: Igor Opaniuk --- cmd/bcb.c | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/cmd/bcb.c b/cmd/bcb.c index 3b1c7434e28..fa9fdeeb0df 100644 --- a/cmd/bcb.c +++ b/cmd/bcb.c @@ -24,17 +24,17 @@ static struct bootloader_message bcb = { { 0 } }; static int bcb_cmd_get(char *cmd) { - if (!strncmp(cmd, "load", sizeof("load"))) + if (!strcmp(cmd, "load")) return BCB_CMD_LOAD; - if (!strncmp(cmd, "set", sizeof("set"))) + if (!strcmp(cmd, "set")) return BCB_CMD_FIELD_SET; - if (!strncmp(cmd, "clear", sizeof("clear"))) + if (!strcmp(cmd, "clear")) return BCB_CMD_FIELD_CLEAR; - if (!strncmp(cmd, "test", sizeof("test"))) + if (!strcmp(cmd, "test")) return BCB_CMD_FIELD_TEST; - if (!strncmp(cmd, "store", sizeof("store"))) + if (!strcmp(cmd, "store")) return BCB_CMD_STORE; - if (!strncmp(cmd, "dump", sizeof("dump"))) + if (!strcmp(cmd, "dump")) return BCB_CMD_FIELD_DUMP; else return -1; @@ -85,19 +85,19 @@ err: static int bcb_field_get(char *name, char **field, int *size) { - if (!strncmp(name, "command", sizeof("command"))) { + if (!strcmp(name, "command")) { *field = bcb.command; *size = sizeof(bcb.command); - } else if (!strncmp(name, "status", sizeof("status"))) { + } else if (!strcmp(name, "status")) { *field = bcb.status; *size = sizeof(bcb.status); - } else if (!strncmp(name, "recovery", sizeof("recovery"))) { + } else if (!strcmp(name, "recovery")) { *field = bcb.recovery; *size = sizeof(bcb.recovery); - } else if (!strncmp(name, "stage", sizeof("stage"))) { + } else if (!strcmp(name, "stage")) { *field = bcb.stage; *size = sizeof(bcb.stage); - } else if (!strncmp(name, "reserved", sizeof("reserved"))) { + } else if (!strcmp(name, "reserved")) { *field = bcb.reserved; *size = sizeof(bcb.reserved); } else { From 37f1811a0b31005284e8514955e7bf7e174cc506 Mon Sep 17 00:00:00 2001 From: Eugeniu Rosca Date: Fri, 19 Jul 2019 23:26:14 +0200 Subject: [PATCH 07/24] cmd: bcb: Apply non-functional refinements These have been reported by Simon in [1] and fixed in [2]. However, since [1] has already been pushed to u-boot/master, the improvements incorporated in [2] are now extracted and resubmitted. The changes are in the area of coding style and best practices: * s/field/fieldp/, s/size/sizep/, to convey that the variables return an output to the caller * s/err_1/err_read_fail/, s/err_2/err_too_small/, to be more descriptive * Made sure 'static int do_bcb_load' appears on the same line * Placed a `/*` on top of multi-line comment [1] https://patchwork.ozlabs.org/patch/1104244/#2200259 [2] https://patchwork.ozlabs.org/cover/1128661/ ("[v4,0/4] Add 'bcb' command to read/modify/write Android BCB") Fixes: db7b7a05b267 ("cmd: Add 'bcb' command to read/modify/write BCB fields") Reported-by: Simon Glass Signed-off-by: Eugeniu Rosca Reviewed-by: Sam Protsenko --- cmd/bcb.c | 43 ++++++++++++++++++++++--------------------- 1 file changed, 22 insertions(+), 21 deletions(-) diff --git a/cmd/bcb.c b/cmd/bcb.c index fa9fdeeb0df..9626f2c69e3 100644 --- a/cmd/bcb.c +++ b/cmd/bcb.c @@ -83,23 +83,23 @@ err: return -1; } -static int bcb_field_get(char *name, char **field, int *size) +static int bcb_field_get(char *name, char **fieldp, int *sizep) { if (!strcmp(name, "command")) { - *field = bcb.command; - *size = sizeof(bcb.command); + *fieldp = bcb.command; + *sizep = sizeof(bcb.command); } else if (!strcmp(name, "status")) { - *field = bcb.status; - *size = sizeof(bcb.status); + *fieldp = bcb.status; + *sizep = sizeof(bcb.status); } else if (!strcmp(name, "recovery")) { - *field = bcb.recovery; - *size = sizeof(bcb.recovery); + *fieldp = bcb.recovery; + *sizep = sizeof(bcb.recovery); } else if (!strcmp(name, "stage")) { - *field = bcb.stage; - *size = sizeof(bcb.stage); + *fieldp = bcb.stage; + *sizep = sizeof(bcb.stage); } else if (!strcmp(name, "reserved")) { - *field = bcb.reserved; - *size = sizeof(bcb.reserved); + *fieldp = bcb.reserved; + *sizep = sizeof(bcb.reserved); } else { printf("Error: Unknown bcb field '%s'\n", name); return -1; @@ -108,8 +108,8 @@ static int bcb_field_get(char *name, char **field, int *size) return 0; } -static int -do_bcb_load(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) +static int do_bcb_load(cmd_tbl_t *cmdtp, int flag, int argc, + char * const argv[]) { struct blk_desc *desc; disk_partition_t info; @@ -119,28 +119,28 @@ do_bcb_load(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) ret = blk_get_device_by_str("mmc", argv[1], &desc); if (ret < 0) - goto err_1; + goto err_read_fail; part = simple_strtoul(argv[2], &endp, 0); if (*endp == '\0') { ret = part_get_info(desc, part, &info); if (ret) - goto err_1; + goto err_read_fail; } else { part = part_get_info_by_name(desc, argv[2], &info); if (part < 0) { ret = part; - goto err_1; + goto err_read_fail; } } cnt = DIV_ROUND_UP(sizeof(struct bootloader_message), info.blksz); if (cnt > info.size) - goto err_2; + goto err_too_small; if (blk_dread(desc, info.start, cnt, &bcb) != cnt) { ret = -EIO; - goto err_1; + goto err_read_fail; } bcb_dev = desc->devnum; @@ -148,10 +148,10 @@ do_bcb_load(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) debug("%s: Loaded from mmc %d:%d\n", __func__, bcb_dev, bcb_part); return CMD_RET_SUCCESS; -err_1: +err_read_fail: printf("Error: mmc %s:%s read failed (%d)\n", argv[1], argv[2], ret); goto err; -err_2: +err_too_small: printf("Error: mmc %s:%s too small!", argv[1], argv[2]); goto err; err: @@ -304,7 +304,8 @@ static int do_bcb(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) return CMD_RET_USAGE; if (bcb_is_misused(argc, argv)) { - /* We try to improve the user experience by reporting the + /* + * 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 */ From 6eccd1f740601f39796bace54c40cd785408e74e Mon Sep 17 00:00:00 2001 From: Ruslan Trofymenko Date: Fri, 5 Jul 2019 15:37:31 +0300 Subject: [PATCH 08/24] disk: part: Extend API to get partition info This patch adds part_get_info_by_dev_and_name_or_num() function which allows us to get partition info from its number or name. Partition of interest is specified by string like "device_num:partition_number" or "device_num#partition_name". The patch was extracted from [1]. [1] https://android-review.googlesource.com/c/platform/external/u-boot/+/729880/2 Signed-off-by: Ruslan Trofymenko Signed-off-by: Igor Opaniuk Reviewed-by: Alistair Strachan Reviewed-by: Sam Protsenko Reviewed-by: Simon Glass --- disk/part.c | 68 ++++++++++++++++++++++++++++++++++++++++++++++++++ include/part.h | 21 ++++++++++++++++ 2 files changed, 89 insertions(+) diff --git a/disk/part.c b/disk/part.c index f14bc22b6db..7e842147317 100644 --- a/disk/part.c +++ b/disk/part.c @@ -674,6 +674,74 @@ int part_get_info_by_name(struct blk_desc *dev_desc, const char *name, return part_get_info_by_name_type(dev_desc, name, info, PART_TYPE_ALL); } +/** + * Get partition info from device number and partition name. + * + * Parse a device number and partition name string in the form of + * "device_num#partition_name", for example "0#misc". If the partition + * is found, sets dev_desc and part_info accordingly with the information + * of the partition with the given partition_name. + * + * @param[in] dev_iface Device interface + * @param[in] dev_part_str Input string argument, like "0#misc" + * @param[out] dev_desc Place to store the device description pointer + * @param[out] part_info Place to store the partition information + * @return 0 on success, or a negative on error + */ +static int part_get_info_by_dev_and_name(const char *dev_iface, + const char *dev_part_str, + struct blk_desc **dev_desc, + disk_partition_t *part_info) +{ + char *ep; + const char *part_str; + int dev_num; + + part_str = strchr(dev_part_str, '#'); + if (!part_str || part_str == dev_part_str) + return -EINVAL; + + dev_num = simple_strtoul(dev_part_str, &ep, 16); + if (ep != part_str) { + /* Not all the first part before the # was parsed. */ + return -EINVAL; + } + part_str++; + + *dev_desc = blk_get_dev(dev_iface, dev_num); + if (!*dev_desc) { + printf("Could not find %s %d\n", dev_iface, dev_num); + return -EINVAL; + } + if (part_get_info_by_name(*dev_desc, part_str, part_info) < 0) { + printf("Could not find \"%s\" partition\n", part_str); + return -EINVAL; + } + return 0; +} + +int part_get_info_by_dev_and_name_or_num(const char *dev_iface, + const char *dev_part_str, + struct blk_desc **dev_desc, + disk_partition_t *part_info) +{ + /* Split the part_name if passed as "$dev_num#part_name". */ + if (!part_get_info_by_dev_and_name(dev_iface, dev_part_str, + dev_desc, part_info)) + return 0; + /* + * Couldn't lookup by name, try looking up the partition description + * directly. + */ + if (blk_get_device_part_str(dev_iface, dev_part_str, + dev_desc, part_info, 1) < 0) { + printf("Couldn't find partition %s %s\n", + dev_iface, dev_part_str); + return -EINVAL; + } + return 0; +} + void part_set_generic_name(const struct blk_desc *dev_desc, int part_num, char *name) { diff --git a/include/part.h b/include/part.h index ebca546db5d..0b5cf3d5e81 100644 --- a/include/part.h +++ b/include/part.h @@ -201,6 +201,27 @@ int part_get_info_by_name_type(struct blk_desc *dev_desc, const char *name, int part_get_info_by_name(struct blk_desc *dev_desc, const char *name, disk_partition_t *info); +/** + * Get partition info from dev number + part name, or dev number + part number. + * + * Parse a device number and partition description (either name or number) + * in the form of device number plus partition name separated by a "#" + * (like "device_num#partition_name") or a device number plus a partition number + * separated by a ":". For example both "0#misc" and "0:1" can be valid + * partition descriptions for a given interface. If the partition is found, sets + * dev_desc and part_info accordingly with the information of the partition. + * + * @param[in] dev_iface Device interface + * @param[in] dev_part_str Input partition description, like "0#misc" or "0:1" + * @param[out] dev_desc Place to store the device description pointer + * @param[out] part_info Place to store the partition information + * @return 0 on success, or a negative on error + */ +int part_get_info_by_dev_and_name_or_num(const char *dev_iface, + const char *dev_part_str, + struct blk_desc **dev_desc, + disk_partition_t *part_info); + /** * part_set_generic_name() - create generic partition like hda1 or sdb2 * From d65e8da92ee7d594226aeee04eb0bef5d60f8bda Mon Sep 17 00:00:00 2001 From: Ruslan Trofymenko Date: Fri, 5 Jul 2019 15:37:32 +0300 Subject: [PATCH 09/24] common: Implement A/B metadata This patch determines the A/B-specific bootloader message structure that is the basis for implementation of recovery and A/B update functions. A/B metadata is stored in this structure and used to decide which slot should we use to boot the device. Also some basic functions for A/B metadata manipulation are implemented (like slot selection). The patch was extracted from commits [1], [2] with some coding style fixes. [1] https://android-review.googlesource.com/c/platform/external/u-boot/+/729878/2 [2] https://android-review.googlesource.com/c/platform/external/u-boot/+/729880/2 Signed-off-by: Ruslan Trofymenko Signed-off-by: Igor Opaniuk Reviewed-by: Sam Protsenko Reviewed-by: Simon Glass --- common/Kconfig | 10 ++ common/Makefile | 1 + common/android_ab.c | 300 +++++++++++++++++++++++++++++++++++++++++++ include/android_ab.h | 34 +++++ 4 files changed, 345 insertions(+) create mode 100644 common/android_ab.c create mode 100644 include/android_ab.h diff --git a/common/Kconfig b/common/Kconfig index 4865a4dfc86..b556b59e9f0 100644 --- a/common/Kconfig +++ b/common/Kconfig @@ -821,6 +821,16 @@ config UPDATE_TFTP_MSEC_MAX default 100 depends on UPDATE_TFTP +config ANDROID_AB + bool "Android A/B updates" + default n + help + If enabled, adds support for the new Android A/B update model. This + allows the bootloader to select which slot to boot from based on the + information provided by userspace via the Android boot_ctrl HAL. This + allows a bootloader to try a new version of the system but roll back + to previous version if the new one didn't boot all the way. + endmenu menu "Blob list" diff --git a/common/Makefile b/common/Makefile index c7e41ef3073..302d8beaf35 100644 --- a/common/Makefile +++ b/common/Makefile @@ -107,6 +107,7 @@ endif endif obj-y += image.o +obj-$(CONFIG_ANDROID_AB) += android_ab.o obj-$(CONFIG_ANDROID_BOOT_IMAGE) += image-android.o obj-$(CONFIG_$(SPL_TPL_)OF_LIBFDT) += image-fdt.o obj-$(CONFIG_$(SPL_TPL_)FIT) += image-fit.o diff --git a/common/android_ab.c b/common/android_ab.c new file mode 100644 index 00000000000..05ffc6f4e50 --- /dev/null +++ b/common/android_ab.c @@ -0,0 +1,300 @@ +// SPDX-License-Identifier: BSD-2-Clause +/* + * Copyright (C) 2017 The Android Open Source Project + */ +#include +#include +#include +#include +#include +#include + +/** + * Compute the CRC-32 of the bootloader control struct. + * + * 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) +{ + return crc32(0, (void *)abc, offsetof(typeof(*abc), crc32_le)); +} + +/** + * Initialize bootloader_control to the default value. + * + * 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) +{ + int i; + const struct slot_metadata metadata = { + .priority = 15, + .tries_remaining = 7, + .successful_boot = 0, + .verity_corrupted = 0, + .reserved = 0 + }; + + if (!abc) + return -EFAULT; + + memcpy(abc->slot_suffix, "a\0\0\0", 4); + abc->magic = BOOT_CTRL_MAGIC; + abc->version = BOOT_CTRL_VERSION; + abc->nb_slot = NUM_SLOTS; + memset(abc->reserved0, 0, sizeof(abc->reserved0)); + for (i = 0; i < abc->nb_slot; ++i) + abc->slot_info[i] = metadata; + + memset(abc->reserved1, 0, sizeof(abc->reserved1)); + abc->crc32_le = ab_control_compute_crc(abc); + + return 0; +} + +/** + * Load the boot_control struct from disk into newly allocated memory. + * + * This function allocates and returns an integer number of disk blocks, + * based on the block size of the passed device to help performing a + * read-modify-write operation on the boot_control struct. + * 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, + const disk_partition_t *part_info, + struct bootloader_control **abc) +{ + ulong abc_offset, abc_blocks, ret; + + abc_offset = offsetof(struct bootloader_message_ab, slot_suffix); + if (abc_offset % part_info->blksz) { + log_err("ANDROID: Boot control block not block aligned.\n"); + return -EINVAL; + } + abc_offset /= part_info->blksz; + + abc_blocks = DIV_ROUND_UP(sizeof(struct bootloader_control), + part_info->blksz); + if (abc_offset + abc_blocks > part_info->size) { + log_err("ANDROID: boot control partition too small. Need at"); + log_err(" least %lu blocks but have %lu blocks.\n", + abc_offset + abc_blocks, part_info->size); + return -EINVAL; + } + *abc = malloc_cache_aligned(abc_blocks * part_info->blksz); + if (!*abc) + return -ENOMEM; + + ret = blk_dread(dev_desc, part_info->start + abc_offset, abc_blocks, + *abc); + if (IS_ERR_VALUE(ret)) { + log_err("ANDROID: Could not read from boot ctrl partition\n"); + free(*abc); + return -EIO; + } + + log_debug("ANDROID: Loaded ABC, %lu blocks\n", abc_blocks); + + return 0; +} + +/** + * Store the loaded boot_control block. + * + * 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, + const disk_partition_t *part_info, + struct bootloader_control *abc) +{ + ulong abc_offset, abc_blocks, ret; + + abc_offset = offsetof(struct bootloader_message_ab, slot_suffix) / + part_info->blksz; + abc_blocks = DIV_ROUND_UP(sizeof(struct bootloader_control), + part_info->blksz); + ret = blk_dwrite(dev_desc, part_info->start + abc_offset, abc_blocks, + abc); + if (IS_ERR_VALUE(ret)) { + log_err("ANDROID: Could not write back the misc partition\n"); + return -EIO; + } + + return 0; +} + +/** + * Compare two slots. + * + * 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. + */ +static int ab_compare_slots(const struct slot_metadata *a, + const struct slot_metadata *b) +{ + /* Higher priority is better */ + if (a->priority != b->priority) + return b->priority - a->priority; + + /* Higher successful_boot value is better, in case of same priority */ + if (a->successful_boot != b->successful_boot) + return b->successful_boot - a->successful_boot; + + /* Higher tries_remaining is better to ensure round-robin */ + if (a->tries_remaining != b->tries_remaining) + return b->tries_remaining - a->tries_remaining; + + return 0; +} + +int ab_select_slot(struct blk_desc *dev_desc, disk_partition_t *part_info) +{ + struct bootloader_control *abc = NULL; + u32 crc32_le; + int slot, i, ret; + bool store_needed = false; + char slot_suffix[4]; + + ret = ab_control_create_from_disk(dev_desc, part_info, &abc); + if (ret < 0) { + /* + * This condition represents an actual problem with the code or + * the board setup, like an invalid partition information. + * Signal a repair mode and do not try to boot from either slot. + */ + return ret; + } + + crc32_le = ab_control_compute_crc(abc); + if (abc->crc32_le != crc32_le) { + log_err("ANDROID: Invalid CRC-32 (expected %.8x, found %.8x),", + crc32_le, abc->crc32_le); + log_err("re-initializing A/B metadata.\n"); + + ret = ab_control_default(abc); + if (ret < 0) { + free(abc); + return -ENODATA; + } + store_needed = true; + } + + if (abc->magic != BOOT_CTRL_MAGIC) { + log_err("ANDROID: Unknown A/B metadata: %.8x\n", abc->magic); + free(abc); + return -ENODATA; + } + + if (abc->version > BOOT_CTRL_VERSION) { + log_err("ANDROID: Unsupported A/B metadata version: %.8x\n", + abc->version); + free(abc); + return -ENODATA; + } + + /* + * At this point a valid boot control metadata is stored in abc, + * followed by other reserved data in the same block. We select a with + * the higher priority slot that + * - is not marked as corrupted and + * - either has tries_remaining > 0 or successful_boot is true. + * If the selected slot has a false successful_boot, we also decrement + * the tries_remaining until it eventually becomes unbootable because + * tries_remaining reaches 0. This mechanism produces a bootloader + * induced rollback, typically right after a failed update. + */ + + /* Safety check: limit the number of slots. */ + if (abc->nb_slot > ARRAY_SIZE(abc->slot_info)) { + abc->nb_slot = ARRAY_SIZE(abc->slot_info); + store_needed = true; + } + + slot = -1; + for (i = 0; i < abc->nb_slot; ++i) { + if (abc->slot_info[i].verity_corrupted || + !abc->slot_info[i].tries_remaining) { + log_debug("ANDROID: unbootable slot %d tries: %d, ", + i, abc->slot_info[i].tries_remaining); + log_debug("corrupt: %d\n", + abc->slot_info[i].verity_corrupted); + continue; + } + log_debug("ANDROID: bootable slot %d pri: %d, tries: %d, ", + i, abc->slot_info[i].priority, + abc->slot_info[i].tries_remaining); + log_debug("corrupt: %d, successful: %d\n", + abc->slot_info[i].verity_corrupted, + abc->slot_info[i].successful_boot); + + if (slot < 0 || + ab_compare_slots(&abc->slot_info[i], + &abc->slot_info[slot]) < 0) { + slot = i; + } + } + + if (slot >= 0 && !abc->slot_info[slot].successful_boot) { + log_err("ANDROID: Attempting slot %c, tries remaining %d\n", + BOOT_SLOT_NAME(slot), + abc->slot_info[slot].tries_remaining); + abc->slot_info[slot].tries_remaining--; + store_needed = true; + } + + if (slot >= 0) { + /* + * Legacy user-space requires this field to be set in the BCB. + * Newer releases load this slot suffix from the command line + * or the device tree. + */ + memset(slot_suffix, 0, sizeof(slot_suffix)); + slot_suffix[0] = BOOT_SLOT_NAME(slot); + if (memcmp(abc->slot_suffix, slot_suffix, + sizeof(slot_suffix))) { + memcpy(abc->slot_suffix, slot_suffix, + sizeof(slot_suffix)); + store_needed = true; + } + } + + if (store_needed) { + abc->crc32_le = ab_control_compute_crc(abc); + ab_control_store(dev_desc, part_info, abc); + } + free(abc); + + if (slot < 0) + return -EINVAL; + + return slot; +} diff --git a/include/android_ab.h b/include/android_ab.h new file mode 100644 index 00000000000..810906d22b3 --- /dev/null +++ b/include/android_ab.h @@ -0,0 +1,34 @@ +/* SPDX-License-Identifier: BSD-2-Clause */ +/* + * Copyright (C) 2017 The Android Open Source Project + */ + +#ifndef __ANDROID_AB_H +#define __ANDROID_AB_H + +#include + +/* Android standard boot slot names are 'a', 'b', 'c', ... */ +#define BOOT_SLOT_NAME(slot_num) ('a' + (slot_num)) + +/* Number of slots */ +#define NUM_SLOTS 2 + +/** + * Select the slot where to boot from. + * + * 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 + * registers the boot attempt. This is used in by the new A/B update model where + * one slot is updated in the background while running from the other slot. If + * the selected slot did not successfully boot in the past, a boot attempt is + * 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, disk_partition_t *part_info); + +#endif /* __ANDROID_AB_H */ From 17030c7c4c99c09f439641628734dfc5840da3ff Mon Sep 17 00:00:00 2001 From: Ruslan Trofymenko Date: Fri, 5 Jul 2019 15:37:33 +0300 Subject: [PATCH 10/24] cmd: Add 'ab_select' command For A/B system update support the Android boot process requires to send 'androidboot.slot_suffix' parameter as a command line argument. This patch implementes 'ab_select' command which allows us to obtain current slot by processing the A/B metadata. The patch was extracted from commit [1] with one modification: the separator for specifying the name of metadata partition was changed from ';' to '#', because ';' is used for commands separation. [1] https://android-review.googlesource.com/c/platform/external/u-boot/+/729880/2 Signed-off-by: Ruslan Trofymenko Signed-off-by: Igor Opaniuk Reviewed-by: Alistair Strachan Reviewed-by: Sam Protsenko Reviewed-by: Simon Glass --- cmd/Kconfig | 15 ++++++++++++++ cmd/Makefile | 1 + cmd/ab_select.c | 52 +++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 68 insertions(+) create mode 100644 cmd/ab_select.c diff --git a/cmd/Kconfig b/cmd/Kconfig index e1e050f4ad5..9e66cc110de 100644 --- a/cmd/Kconfig +++ b/cmd/Kconfig @@ -1198,6 +1198,21 @@ config CMD_SETEXPR endmenu +menu "Android support commands" + +config CMD_AB_SELECT + bool "ab_select" + default n + 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 menuconfig CMD_NET diff --git a/cmd/Makefile b/cmd/Makefile index 0aa37414533..43a6b0ee216 100644 --- a/cmd/Makefile +++ b/cmd/Makefile @@ -12,6 +12,7 @@ obj-y += version.o # command 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-y += blk_common.o diff --git a/cmd/ab_select.c b/cmd/ab_select.c new file mode 100644 index 00000000000..7c8f2ee8eb3 --- /dev/null +++ b/cmd/ab_select.c @@ -0,0 +1,52 @@ +// SPDX-License-Identifier: BSD-2-Clause +/* + * Copyright (C) 2017 The Android Open Source Project + */ + +#include +#include + +static int do_ab_select(cmd_tbl_t *cmdtp, int flag, int argc, + char * const argv[]) +{ + int ret; + struct blk_desc *dev_desc; + disk_partition_t part_info; + char slot[2]; + + if (argc != 4) + 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) < 0) { + return CMD_RET_FAILURE; + } + + ret = ab_select_slot(dev_desc, &part_info); + 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, 4, 0, do_ab_select, + "Select the slot used to boot from and register the boot attempt.", + " \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" +); From 31a38799d5e9e604783f8c454e8b7cd30e446ebd Mon Sep 17 00:00:00 2001 From: Ruslan Trofymenko Date: Fri, 5 Jul 2019 15:37:34 +0300 Subject: [PATCH 11/24] test/py: Add base test case for A/B updates Add sandbox test for 'ab_select' command. Test: ./test/py/test.py --bd sandbox --build -k test_ab Signed-off-by: Ruslan Trofymenko Signed-off-by: Igor Opaniuk Signed-off-by: Sam Protsenko Reviewed-by: Alistair Strachan Reviewed-by: Sam Protsenko Reviewed-by: Simon Glass --- configs/sandbox_defconfig | 2 + test/py/tests/test_android/test_ab.py | 75 +++++++++++++++++++++++++++ 2 files changed, 77 insertions(+) create mode 100644 test/py/tests/test_android/test_ab.py diff --git a/configs/sandbox_defconfig b/configs/sandbox_defconfig index 61391a7acd4..11cc097cd55 100644 --- a/configs/sandbox_defconfig +++ b/configs/sandbox_defconfig @@ -20,6 +20,7 @@ CONFIG_PRE_CON_BUF_ADDR=0xf0000 CONFIG_LOG_MAX_LEVEL=6 CONFIG_LOG_ERROR_RETURN=y CONFIG_DISPLAY_BOARDINFO_LATE=y +CONFIG_ANDROID_AB=y CONFIG_CMD_CPU=y CONFIG_CMD_LICENSE=y CONFIG_CMD_BOOTZ=y @@ -47,6 +48,7 @@ CONFIG_CMD_REMOTEPROC=y CONFIG_CMD_SPI=y CONFIG_CMD_USB=y CONFIG_CMD_AXI=y +CONFIG_CMD_AB_SELECT=y CONFIG_CMD_TFTPPUT=y CONFIG_CMD_TFTPSRV=y CONFIG_CMD_RARP=y diff --git a/test/py/tests/test_android/test_ab.py b/test/py/tests/test_android/test_ab.py new file mode 100644 index 00000000000..c79cb07fda3 --- /dev/null +++ b/test/py/tests/test_android/test_ab.py @@ -0,0 +1,75 @@ +# SPDX-License-Identifier: GPL-2.0 +# (C) Copyright 2018 Texas Instruments, + +# Test A/B update commands. + +import os +import pytest +import u_boot_utils + +class ABTestDiskImage(object): + """Disk Image used by the A/B tests.""" + + def __init__(self, u_boot_console): + """Initialize a new ABTestDiskImage object. + + Args: + u_boot_console: A U-Boot console. + + Returns: + Nothing. + """ + + filename = 'test_ab_disk_image.bin' + + persistent = u_boot_console.config.persistent_data_dir + '/' + filename + self.path = u_boot_console.config.result_dir + '/' + filename + + with u_boot_utils.persistent_file_helper(u_boot_console.log, persistent): + if os.path.exists(persistent): + u_boot_console.log.action('Disk image file ' + persistent + + ' already exists') + else: + u_boot_console.log.action('Generating ' + persistent) + fd = os.open(persistent, os.O_RDWR | os.O_CREAT) + os.ftruncate(fd, 524288) + os.close(fd) + cmd = ('sgdisk', persistent) + u_boot_utils.run_and_log(u_boot_console, cmd) + + cmd = ('sgdisk', '--new=1:64:512', '--change-name=1:misc', + persistent) + u_boot_utils.run_and_log(u_boot_console, cmd) + cmd = ('sgdisk', '--load-backup=' + persistent) + u_boot_utils.run_and_log(u_boot_console, cmd) + + cmd = ('cp', persistent, self.path) + u_boot_utils.run_and_log(u_boot_console, cmd) + +di = None +@pytest.fixture(scope='function') +def ab_disk_image(u_boot_console): + global di + if not di: + di = ABTestDiskImage(u_boot_console) + return di + +@pytest.mark.boardspec('sandbox') +@pytest.mark.buildconfigspec('android_ab') +@pytest.mark.buildconfigspec('cmd_ab_select') +@pytest.mark.requiredtool('sgdisk') +def test_ab(ab_disk_image, u_boot_console): + """Test the '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') + 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') + 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 ae954baf3bf73ff4ae436e080444e91f54b8aebf Mon Sep 17 00:00:00 2001 From: Ruslan Trofymenko Date: Fri, 5 Jul 2019 15:37:35 +0300 Subject: [PATCH 12/24] doc: android: Add simple guide for A/B updates Add a short documentation for A/B enablement and 'ab_select' command usage. Signed-off-by: Ruslan Trofymenko Signed-off-by: Igor Opaniuk Signed-off-by: Sam Protsenko Reviewed-by: Alistair Strachan Reviewed-by: Sam Protsenko Reviewed-by: Simon Glass --- doc/android/ab.txt | 67 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 67 insertions(+) create mode 100644 doc/android/ab.txt diff --git a/doc/android/ab.txt b/doc/android/ab.txt new file mode 100644 index 00000000000..9f37ed5c586 --- /dev/null +++ b/doc/android/ab.txt @@ -0,0 +1,67 @@ +Android A/B updates +=================== + +Overview +-------- + +A/B system updates ensures modern approach for system update. This feature +allows one to use two sets (or more) of partitions referred to as slots +(normally slot A and slot B). The system runs from the current slot while the +partitions in the unused slot can be updated [1]. + +A/B enablement +-------------- + +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 + +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 +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 +special partition (e.g. "misc") and determines which slot should be used for +booting up. + +Command usage +------------- + + ab_select + +for example: + + => ab_select slot_name mmc 1:4 + +or + + => ab_select slot_name mmc 1#misc + +Result: + + => printenv slot_name + slot_name=a + +Based on this slot information, the current boot partition should be defined, +and next kernel command line parameters should be generated: + + - androidboot.slot_suffix= + - root= + +For example: + + androidboot.slot_suffix=_a root=/dev/mmcblk1p12 + +A/B metadata is organized according to AOSP reference [2]. On the first system +start with A/B enabled, when 'misc' partition doesn't contain required data, +the default A/B metadata will be created and written to 'misc' partition. + +References +---------- + +[1] https://source.android.com/devices/tech/ota/ab +[2] bootable/recovery/bootloader_message/include/bootloader_message/bootloader_message.h From edd31084f2560008b7aed6c9654b014a90ebd33e Mon Sep 17 00:00:00 2001 From: Ruslan Trofymenko Date: Fri, 5 Jul 2019 15:37:36 +0300 Subject: [PATCH 13/24] env: am57xx: Implement A/B boot process Add support for A/B boot process on AM57xx based boards: 1. Define 'slot_suffix' variable (using 'ab_select' command) 2. Extend 'emmc_android_boot' boot command (add commands for A/B boot process) 'ab_select' command is used to decide which slot should be used for booting up. A/B metadata resides in 'misc' partition. To activate the A/B boot process, the following config options must be set: CONFIG_ANDROID_AB=y CONFIG_CMD_AB_SELECT=y For successful A/B boot, the corresponding A/B infrastructure must be involved on Android side [1] (including mounting system as root), and disk must be partitioned accordingly. When A/B boot is enabled, there are some known limitations currently exist (not related to A/B patches, need to be implemented later): 1. The 'Verified Boot' sequence is not supported 2. dev path to system partition (system_a or system_b) is passed via 'bootargs' as 'root=' argument like 'root=/dev/mmcblk1p12', but further we'll need to rework it with respect to dm-verity requirements [2] In case when A/B partitions are not present in system (and A/B boot is enabled), boot up process will be terminated and next message will be shown: "boot_a(b) partition not found" [1] https://source.android.com/devices/tech/ota/ab [2] https://source.android.com/devices/tech/ota/ab/ab_implement#kernel Signed-off-by: Ruslan Trofymenko Signed-off-by: Igor Opaniuk Signed-off-by: Sam Protsenko Reviewed-by: Alistair Strachan Reviewed-by: Sam Protsenko Reviewed-by: Simon Glass --- include/environment/ti/boot.h | 58 +++++++++++++++++++++++++++++++---- 1 file changed, 52 insertions(+), 6 deletions(-) diff --git a/include/environment/ti/boot.h b/include/environment/ti/boot.h index 05bdbbc23e4..54e9b2de4d1 100644 --- a/include/environment/ti/boot.h +++ b/include/environment/ti/boot.h @@ -23,6 +23,18 @@ #define VBMETA_PART "" #endif +#if defined(CONFIG_CMD_AB_SELECT) +#define COMMON_PARTS \ + "name=boot_a,size=20M,uuid=${uuid_gpt_boot_a};" \ + "name=boot_b,size=20M,uuid=${uuid_gpt_boot_b};" \ + "name=system_a,size=1024M,uuid=${uuid_gpt_system_a};" \ + "name=system_b,size=1024M,uuid=${uuid_gpt_system_b};" +#else +#define COMMON_PARTS \ + "name=boot,size=20M,uuid=${uuid_gpt_boot};" \ + "name=system,size=1024M,uuid=${uuid_gpt_system};" +#endif + #ifndef PARTS_DEFAULT /* Define the default GPT table for eMMC */ #define PARTS_DEFAULT \ @@ -38,8 +50,7 @@ "name=uboot-env,start=2432K,size=256K,uuid=${uuid_gpt_reserved};" \ "name=misc,size=128K,uuid=${uuid_gpt_misc};" \ "name=recovery,size=40M,uuid=${uuid_gpt_recovery};" \ - "name=boot,size=10M,uuid=${uuid_gpt_boot};" \ - "name=system,size=1024M,uuid=${uuid_gpt_system};" \ + COMMON_PARTS \ "name=vendor,size=256M,uuid=${uuid_gpt_vendor};" \ VBMETA_PART \ "name=userdata,size=-,uuid=${uuid_gpt_userdata}" @@ -58,6 +69,35 @@ #define AVB_VERIFY_CMD "" #endif +#define CONTROL_PARTITION "misc" + +#if defined(CONFIG_CMD_AB_SELECT) +#define AB_SELECT \ + "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};" \ + "else " \ + "echo " CONTROL_PARTITION " partition not found;" \ + "exit;" \ + "fi;" \ + "setenv slot_suffix _${slot_name};" \ + "if part number mmc ${mmcdev} system${slot_suffix} " \ + "system_part_number; then " \ + "setenv bootargs_ab " \ + "ro root=/dev/mmcblk${mmcdev}p${system_part_number} " \ + "rootwait init=/init skip_initramfs " \ + "androidboot.slot_suffix=${slot_suffix};" \ + "echo A/B cmdline addition: ${bootargs_ab};" \ + "setenv bootargs ${bootargs} ${bootargs_ab};" \ + "else " \ + "echo system${slot_suffix} partition not found;" \ + "fi;" +#else +#define AB_SELECT "" +#endif + #define DEFAULT_COMMON_BOOT_TI_ARGS \ "console=" CONSOLEDEV ",115200n8\0" \ "fdtfile=undefined\0" \ @@ -86,10 +126,16 @@ "mmc dev $mmcdev; " \ "mmc rescan; " \ AVB_VERIFY_CHECK \ - "part start mmc ${mmcdev} boot boot_start; " \ - "part size mmc ${mmcdev} boot boot_size; " \ - "mmc read ${loadaddr} ${boot_start} ${boot_size}; " \ - "bootm ${loadaddr}#${fdtfile};\0 " + AB_SELECT \ + "if part start mmc ${mmcdev} boot${slot_suffix} boot_start; " \ + "then " \ + "part size mmc ${mmcdev} boot${slot_suffix} " \ + "boot_size; " \ + "mmc read ${loadaddr} ${boot_start} ${boot_size}; " \ + "bootm ${loadaddr}#${fdtfile}; " \ + "else " \ + "echo boot${slot_suffix} partition not found; " \ + "fi;\0" #ifdef CONFIG_OMAP54XX From 61779ce0a1f0ad020e28d2154d8fe3ddbec05ce6 Mon Sep 17 00:00:00 2001 From: Jonathan Corbet Date: Sun, 14 Jul 2019 10:35:45 +0200 Subject: [PATCH 14/24] doc: Cope with Sphinx logging deprecations Recent versions of sphinx will emit messages like: doc/sphinx/kerneldoc.py:103: RemovedInSphinx20Warning: app.warning() is now deprecated. Use sphinx.util.logging instead. Switch to sphinx.util.logging to make this unsightly message go away. Alas, that interface was only added in version 1.6, so we have to add a version check to keep things working with older sphinxes. Signed-off-by: Jonathan Corbet Rebased for U-Boot Signed-off-by: Heinrich Schuchardt --- doc/sphinx/kerneldoc.py | 12 ++++++++---- doc/sphinx/kernellog.py | 28 ++++++++++++++++++++++++++++ doc/sphinx/kfigure.py | 40 +++++++++++++++++++++++----------------- 3 files changed, 59 insertions(+), 21 deletions(-) create mode 100644 doc/sphinx/kernellog.py diff --git a/doc/sphinx/kerneldoc.py b/doc/sphinx/kerneldoc.py index fbedcc39460..e536360de16 100644 --- a/doc/sphinx/kerneldoc.py +++ b/doc/sphinx/kerneldoc.py @@ -39,6 +39,8 @@ from docutils.statemachine import ViewList from docutils.parsers.rst import directives, Directive from sphinx.ext.autodoc import AutodocReporter +import kernellog + __version__ = '1.0' class KernelDocDirective(Directive): @@ -86,7 +88,8 @@ class KernelDocDirective(Directive): cmd += [filename] try: - env.app.verbose('calling kernel-doc \'%s\'' % (" ".join(cmd))) + kernellog.verbose(env.app, + 'calling kernel-doc \'%s\'' % (" ".join(cmd))) p = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE) out, err = p.communicate() @@ -96,7 +99,8 @@ class KernelDocDirective(Directive): if p.returncode != 0: sys.stderr.write(err) - env.app.warn('kernel-doc \'%s\' failed with return code %d' % (" ".join(cmd), p.returncode)) + kernellog.warn(env.app, + 'kernel-doc \'%s\' failed with return code %d' % (" ".join(cmd), p.returncode)) return [nodes.error(None, nodes.paragraph(text = "kernel-doc missing"))] elif env.config.kerneldoc_verbosity > 0: sys.stderr.write(err) @@ -128,8 +132,8 @@ class KernelDocDirective(Directive): return node.children except Exception as e: # pylint: disable=W0703 - env.app.warn('kernel-doc \'%s\' processing failed with: %s' % - (" ".join(cmd), str(e))) + kernellog.warn(env.app, 'kernel-doc \'%s\' processing failed with: %s' % + (" ".join(cmd), str(e))) return [nodes.error(None, nodes.paragraph(text = "kernel-doc missing"))] def setup(app): diff --git a/doc/sphinx/kernellog.py b/doc/sphinx/kernellog.py new file mode 100644 index 00000000000..af924f51a7d --- /dev/null +++ b/doc/sphinx/kernellog.py @@ -0,0 +1,28 @@ +# SPDX-License-Identifier: GPL-2.0 +# +# Sphinx has deprecated its older logging interface, but the replacement +# only goes back to 1.6. So here's a wrapper layer to keep around for +# as long as we support 1.4. +# +import sphinx + +if sphinx.__version__[:3] >= '1.6': + UseLogging = True + from sphinx.util import logging + logger = logging.getLogger('kerneldoc') +else: + UseLogging = False + +def warn(app, message): + if UseLogging: + logger.warning(message) + else: + app.warn(message) + +def verbose(app, message): + if UseLogging: + logger.verbose(message) + else: + app.verbose(message) + + diff --git a/doc/sphinx/kfigure.py b/doc/sphinx/kfigure.py index b97228d2cc0..fbfe6693bb6 100644 --- a/doc/sphinx/kfigure.py +++ b/doc/sphinx/kfigure.py @@ -60,6 +60,8 @@ import sphinx from sphinx.util.nodes import clean_astext from six import iteritems +import kernellog + PY3 = sys.version_info[0] == 3 if PY3: @@ -171,20 +173,20 @@ def setupTools(app): This function is called once, when the builder is initiated. """ global dot_cmd, convert_cmd # pylint: disable=W0603 - app.verbose("kfigure: check installed tools ...") + kernellog.verbose(app, "kfigure: check installed tools ...") dot_cmd = which('dot') convert_cmd = which('convert') if dot_cmd: - app.verbose("use dot(1) from: " + dot_cmd) + kernellog.verbose(app, "use dot(1) from: " + dot_cmd) else: - app.warn("dot(1) not found, for better output quality install " - "graphviz from http://www.graphviz.org") + kernellog.warn(app, "dot(1) not found, for better output quality install " + "graphviz from http://www.graphviz.org") if convert_cmd: - app.verbose("use convert(1) from: " + convert_cmd) + kernellog.verbose(app, "use convert(1) from: " + convert_cmd) else: - app.warn( + kernellog.warn(app, "convert(1) not found, for SVG to PDF conversion install " "ImageMagick (https://www.imagemagick.org)") @@ -220,12 +222,13 @@ def convert_image(img_node, translator, src_fname=None): # in kernel builds, use 'make SPHINXOPTS=-v' to see verbose messages - app.verbose('assert best format for: ' + img_node['uri']) + kernellog.verbose(app, 'assert best format for: ' + img_node['uri']) if in_ext == '.dot': if not dot_cmd: - app.verbose("dot from graphviz not available / include DOT raw.") + kernellog.verbose(app, + "dot from graphviz not available / include DOT raw.") img_node.replace_self(file2literal(src_fname)) elif translator.builder.format == 'latex': @@ -252,7 +255,8 @@ def convert_image(img_node, translator, src_fname=None): if translator.builder.format == 'latex': if convert_cmd is None: - app.verbose("no SVG to PDF conversion available / include SVG raw.") + kernellog.verbose(app, + "no SVG to PDF conversion available / include SVG raw.") img_node.replace_self(file2literal(src_fname)) else: dst_fname = path.join(translator.builder.outdir, fname + '.pdf') @@ -265,18 +269,19 @@ def convert_image(img_node, translator, src_fname=None): _name = dst_fname[len(translator.builder.outdir) + 1:] if isNewer(dst_fname, src_fname): - app.verbose("convert: {out}/%s already exists and is newer" % _name) + kernellog.verbose(app, + "convert: {out}/%s already exists and is newer" % _name) else: ok = False mkdir(path.dirname(dst_fname)) if in_ext == '.dot': - app.verbose('convert DOT to: {out}/' + _name) + kernellog.verbose(app, 'convert DOT to: {out}/' + _name) ok = dot2format(app, src_fname, dst_fname) elif in_ext == '.svg': - app.verbose('convert SVG to: {out}/' + _name) + kernellog.verbose(app, 'convert SVG to: {out}/' + _name) ok = svg2pdf(app, src_fname, dst_fname) if not ok: @@ -305,7 +310,8 @@ def dot2format(app, dot_fname, out_fname): with open(out_fname, "w") as out: exit_code = subprocess.call(cmd, stdout = out) if exit_code != 0: - app.warn("Error #%d when calling: %s" % (exit_code, " ".join(cmd))) + kernellog.warn(app, + "Error #%d when calling: %s" % (exit_code, " ".join(cmd))) return bool(exit_code == 0) def svg2pdf(app, svg_fname, pdf_fname): @@ -322,7 +328,7 @@ def svg2pdf(app, svg_fname, pdf_fname): # use stdout and stderr from parent exit_code = subprocess.call(cmd) if exit_code != 0: - app.warn("Error #%d when calling: %s" % (exit_code, " ".join(cmd))) + kernellog.warn(app, "Error #%d when calling: %s" % (exit_code, " ".join(cmd))) return bool(exit_code == 0) @@ -415,15 +421,15 @@ def visit_kernel_render(self, node): app = self.builder.app srclang = node.get('srclang') - app.verbose('visit kernel-render node lang: "%s"' % (srclang)) + kernellog.verbose(app, 'visit kernel-render node lang: "%s"' % (srclang)) tmp_ext = RENDER_MARKUP_EXT.get(srclang, None) if tmp_ext is None: - app.warn('kernel-render: "%s" unknown / include raw.' % (srclang)) + kernellog.warn(app, 'kernel-render: "%s" unknown / include raw.' % (srclang)) return if not dot_cmd and tmp_ext == '.dot': - app.verbose("dot from graphviz not available / include raw.") + kernellog.verbose(app, "dot from graphviz not available / include raw.") return literal_block = node[0] From b7ab0982074de39c5fa43188a3b8c1233984472d Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Sun, 14 Jul 2019 11:30:22 +0200 Subject: [PATCH 15/24] scripts/kernel-doc: update script from Linux 5.2 Update the script from Linux 5.2 to avoid some warnings. Signed-off-by: Heinrich Schuchardt --- scripts/kernel-doc | 37 +++++++++++++++++++------------------ 1 file changed, 19 insertions(+), 18 deletions(-) diff --git a/scripts/kernel-doc b/scripts/kernel-doc index 3cb6259182f..3350e498b4c 100755 --- a/scripts/kernel-doc +++ b/scripts/kernel-doc @@ -212,7 +212,7 @@ my $anon_struct_union = 0; my $type_constant = '\b``([^\`]+)``\b'; my $type_constant2 = '\%([-_\w]+)'; my $type_func = '(\w+)\(\)'; -my $type_param = '\@(\w*(\.\w+)*(\.\.\.)?)'; +my $type_param = '\@(\w*((\.\w+)|(->\w+))*(\.\.\.)?)'; my $type_fp_param = '\@(\w+)\(\)'; # Special RST handling for func ptr params my $type_env = '(\$\w+)'; my $type_enum = '\&(enum\s*([_\w]+))'; @@ -1062,7 +1062,7 @@ sub dump_struct($$) { my $x = shift; my $file = shift; - if ($x =~ /(struct|union)\s+(\w+)\s*{(.*)}/) { + if ($x =~ /(struct|union)\s+(\w+)\s*\{(.*)\}(\s*(__packed|__aligned|__attribute__\s*\(\([a-z0-9,_\s\(\)]*\)\)))*/) { my $decl_type = $1; $declaration_name = $2; my $members = $3; @@ -1073,8 +1073,9 @@ sub dump_struct($$) { # strip comments: $members =~ s/\/\*.*?\*\///gos; # strip attributes - $members =~ s/__attribute__\s*\(\([a-z,_\*\s\(\)]*\)\)//i; - $members =~ s/__aligned\s*\([^;]*\)//gos; + $members =~ s/\s*__attribute__\s*\(\([a-z0-9,_\*\s\(\)]*\)\)//gi; + $members =~ s/\s*__aligned\s*\([^;]*\)//gos; + $members =~ s/\s*__packed\s*//gos; $members =~ s/\s*CRYPTO_MINALIGN_ATTR//gos; # replace DECLARE_BITMAP $members =~ s/DECLARE_BITMAP\s*\(([^,)]+),\s*([^,)]+)\)/unsigned long $1\[BITS_TO_LONGS($2)\]/gos; @@ -1148,20 +1149,20 @@ sub dump_struct($$) { } } } - $members =~ s/(struct|union)([^\{\};]+)\{([^\{\}]*)}([^\{\}\;]*)\;/$newmember/; + $members =~ s/(struct|union)([^\{\};]+)\{([^\{\}]*)\}([^\{\}\;]*)\;/$newmember/; } # Ignore other nested elements, like enums - $members =~ s/({[^\{\}]*})//g; + $members =~ s/(\{[^\{\}]*\})//g; create_parameterlist($members, ';', $file, $declaration_name); check_sections($file, $declaration_name, $decl_type, $sectcheck, $struct_actual); # Adjust declaration for better display - $declaration =~ s/([{;])/$1\n/g; - $declaration =~ s/}\s+;/};/g; + $declaration =~ s/([\{;])/$1\n/g; + $declaration =~ s/\}\s+;/};/g; # Better handle inlined enums - do {} while ($declaration =~ s/(enum\s+{[^}]+),([^\n])/$1,\n$2/); + do {} while ($declaration =~ s/(enum\s+\{[^\}]+),([^\n])/$1,\n$2/); my @def_args = split /\n/, $declaration; my $level = 1; @@ -1171,12 +1172,12 @@ sub dump_struct($$) { $clause =~ s/\s+$//; $clause =~ s/\s+/ /; next if (!$clause); - $level-- if ($clause =~ m/(})/ && $level > 1); + $level-- if ($clause =~ m/(\})/ && $level > 1); if (!($clause =~ m/^\s*#/)) { $declaration .= "\t" x $level; } $declaration .= "\t" . $clause . "\n"; - $level++ if ($clause =~ m/({)/ && !($clause =~m/}/)); + $level++ if ($clause =~ m/(\{)/ && !($clause =~m/\}/)); } output_declaration($declaration_name, 'struct', @@ -1244,7 +1245,7 @@ sub dump_enum($$) { # strip #define macros inside enums $x =~ s@#\s*((define|ifdef)\s+|endif)[^;]*;@@gos; - if ($x =~ /enum\s+(\w+)\s*{(.*)}/) { + if ($x =~ /enum\s+(\w+)\s*\{(.*)\}/) { $declaration_name = $1; my $members = $2; my %_members; @@ -1473,7 +1474,7 @@ sub push_parameter($$$$) { if (!defined $parameterdescs{$param} && $param !~ /^#/) { $parameterdescs{$param} = $undescribed; - if (show_warnings($type, $declaration_name)) { + if (show_warnings($type, $declaration_name) && $param !~ /\./) { print STDERR "${file}:$.: warning: Function parameter or member '$param' not described in '$declaration_name'\n"; ++$warnings; @@ -1785,7 +1786,7 @@ sub process_proto_type($$) { } while (1) { - if ( $x =~ /([^{};]*)([{};])(.*)/ ) { + if ( $x =~ /([^\{\};]*)([\{\};])(.*)/ ) { if( length $prototype ) { $prototype .= " " } @@ -1904,13 +1905,13 @@ sub process_name($$) { ++$warnings; } - if ($identifier =~ m/^struct/) { + if ($identifier =~ m/^struct\b/) { $decl_type = 'struct'; - } elsif ($identifier =~ m/^union/) { + } elsif ($identifier =~ m/^union\b/) { $decl_type = 'union'; - } elsif ($identifier =~ m/^enum/) { + } elsif ($identifier =~ m/^enum\b/) { $decl_type = 'enum'; - } elsif ($identifier =~ m/^typedef/) { + } elsif ($identifier =~ m/^typedef\b/) { $decl_type = 'typedef'; } else { $decl_type = 'function'; From 146ce6474d0355a45fbd289981ecc8d2d15ff993 Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Sun, 14 Jul 2019 11:30:23 +0200 Subject: [PATCH 16/24] scripts/kernel-doc: fix parsing of function pointers kernel-doc fails to parse function definitions like the one below efi_status_t efi_create_event(uint32_t type, efi_uintn_t notify_tpl, void (EFIAPI *notify_function) ( struct efi_event *event, void *context), void *notify_context, efi_guid_t *group, struct efi_event **event) { due to the "EFIAPI" attribute preceding the function name. cf. https://lkml.org/lkml/2018/9/3/1185 Signed-off-by: Heinrich Schuchardt --- scripts/kernel-doc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/kernel-doc b/scripts/kernel-doc index 3350e498b4c..516cf1db32c 100755 --- a/scripts/kernel-doc +++ b/scripts/kernel-doc @@ -1382,7 +1382,7 @@ sub create_parameterlist($$$$) { } elsif ($arg =~ m/\(.+\)\s*\(/) { # pointer-to-function $arg =~ tr/#/,/; - $arg =~ m/[^\(]+\(\*?\s*([\w\.]*)\s*\)/; + $arg =~ m/[^\(]+\([\w\s]*\*?\s*([\w\.]*)\s*\)/; $param = $1; $type = $arg; $type =~ s/([^\(]+\(\*?)\s*$param/$1/; From 60ca969a7a1cbab6e43c5f97ffe99a9630257d08 Mon Sep 17 00:00:00 2001 From: Baruch Siach Date: Sun, 14 Jul 2019 17:54:21 +0300 Subject: [PATCH 17/24] spl: sata: support U-Boot load from raw sata disk Support load of the U-Boot image from raw SATA disk sector. This is equivalent to load from MMC raw sector. Signed-off-by: Baruch Siach --- common/spl/Kconfig | 14 ++++++++++++++ common/spl/spl_sata.c | 34 ++++++++++++++++++++++++++++++++++ 2 files changed, 48 insertions(+) diff --git a/common/spl/Kconfig b/common/spl/Kconfig index 5978fb29343..5d6da5db89b 100644 --- a/common/spl/Kconfig +++ b/common/spl/Kconfig @@ -918,6 +918,20 @@ config SPL_SATA_SUPPORT expense and power consumption. This enables loading from SATA using a configured device. +config SPL_SATA_RAW_U_BOOT_USE_SECTOR + bool "SATA raw mode: by sector" + depends on SPL_SATA_SUPPORT + help + Use sector number for specifying U-Boot location on SATA disk in + raw mode. + +config SPL_SATA_RAW_U_BOOT_SECTOR + hex "Sector on the SATA disk to load U-Boot from" + depends on SPL_SATA_RAW_U_BOOT_USE_SECTOR + help + Sector on the SATA disk to load U-Boot from, when the SATA disk is being + used in raw mode. Units: SATA disk sectors (1 sector = 512 bytes). + config SPL_SERIAL_SUPPORT bool "Support serial" select SPL_PRINTF diff --git a/common/spl/spl_sata.c b/common/spl/spl_sata.c index f0af9f38d19..e108af0576a 100644 --- a/common/spl/spl_sata.c +++ b/common/spl/spl_sata.c @@ -25,6 +25,37 @@ #define CONFIG_SPL_FS_LOAD_PAYLOAD_NAME "u-boot.img" #endif +#ifndef CONFIG_SPL_SATA_RAW_U_BOOT_SECTOR +/* Dummy value to make the compiler happy */ +#define CONFIG_SPL_SATA_RAW_U_BOOT_SECTOR 0x100 +#endif + +static int spl_sata_load_image_raw(struct spl_image_info *spl_image, + struct blk_desc *stor_dev, unsigned long sector) +{ + struct image_header *header; + unsigned long count; + u32 image_size_sectors; + int ret; + + header = spl_get_load_buffer(-sizeof(*header), stor_dev->blksz); + count = blk_dread(stor_dev, sector, 1, header); + if (count == 0) + return -EIO; + + ret = spl_parse_image_header(spl_image, header); + if (ret) + return ret; + + image_size_sectors = DIV_ROUND_UP(spl_image->size, stor_dev->blksz); + count = blk_dread(stor_dev, sector, image_size_sectors, + (void *)spl_image->load_addr); + if (count != image_size_sectors) + return -EIO; + + return 0; +} + static int spl_sata_load_image(struct spl_image_info *spl_image, struct spl_boot_device *bootdev) { @@ -59,6 +90,9 @@ static int spl_sata_load_image(struct spl_image_info *spl_image, err = spl_load_image_fat(spl_image, stor_dev, CONFIG_SYS_SATA_FAT_BOOT_PARTITION, CONFIG_SPL_FS_LOAD_PAYLOAD_NAME); + } else if (IS_ENABLED(CONFIG_SPL_SATA_RAW_U_BOOT_USE_SECTOR)) { + err = spl_sata_load_image_raw(spl_image, stor_dev, + CONFIG_SPL_SATA_RAW_U_BOOT_SECTOR); } } if (err) { From 98c0d49c3d52a44fd27648cdb7107632bb5f2600 Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Tue, 16 Jul 2019 09:39:19 -0700 Subject: [PATCH 18/24] doc: Add .gitignore for the Sphinx build output directory With Sphinx documentation moving from Documentation directory to doc directory, we missed updating .gitignore for the Sphinx build output directory. Signed-off-by: Bin Meng --- Documentation/.gitignore | 1 - doc/.gitignore | 1 + 2 files changed, 1 insertion(+), 1 deletion(-) create mode 100644 doc/.gitignore diff --git a/Documentation/.gitignore b/Documentation/.gitignore index e74fec8693b..0d20b6487c6 100644 --- a/Documentation/.gitignore +++ b/Documentation/.gitignore @@ -1,2 +1 @@ -output *.pyc diff --git a/doc/.gitignore b/doc/.gitignore new file mode 100644 index 00000000000..53752db253e --- /dev/null +++ b/doc/.gitignore @@ -0,0 +1 @@ +output From e766b2ea0aa887366f510074349b766eb5be98d6 Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Tue, 16 Jul 2019 09:39:20 -0700 Subject: [PATCH 19/24] doc: Add the U-Boot logo to the html doc Now we have a logo for U-Boot, we can include it in the Sphinx html doc. Signed-off-by: Bin Meng --- doc/conf.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/conf.py b/doc/conf.py index 168c31346b6..0772fb6f0c8 100644 --- a/doc/conf.py +++ b/doc/conf.py @@ -170,7 +170,7 @@ except ImportError: # The name of an image file (relative to this directory) to place at the top # of the sidebar. -#html_logo = None +html_logo = '../tools/logos/u-boot_logo.svg' # The name of an image file (within the static path) to use as favicon of the # docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 From 15958c74a91eae88f470776788a114f82ef3e922 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micka=C3=ABl=20Tansorier?= Date: Wed, 17 Jul 2019 17:57:16 +0200 Subject: [PATCH 20/24] doc: fitImage: Fix conf number incrementation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Increment conf id to avoid to have two same conf name into one configuration description. Signed-off-by: Mickaël Tansorier --- doc/uImage.FIT/signature.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/uImage.FIT/signature.txt b/doc/uImage.FIT/signature.txt index c9b1802686f..1695bf4cd84 100644 --- a/doc/uImage.FIT/signature.txt +++ b/doc/uImage.FIT/signature.txt @@ -216,7 +216,7 @@ As an example, consider this FIT: kernel = "kernel-1"; fdt = "fdt-1"; }; - conf-1 { + conf-2 { kernel = "kernel-2"; fdt = "fdt-2"; }; @@ -232,7 +232,7 @@ configuration 3 with kernel 1 and fdt 2: kernel = "kernel-1"; fdt = "fdt-1"; }; - conf-1 { + conf-2 { kernel = "kernel-2"; fdt = "fdt-2"; }; From 57a51123f18df0a89aa8ec7521e8e7b1330719dc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micka=C3=ABl=20Tansorier?= Date: Wed, 17 Jul 2019 17:57:29 +0200 Subject: [PATCH 21/24] doc: fitImage: Cosmetics break lines MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add missing newline before title and subtitle. Signed-off-by: Mickaël Tansorier --- doc/uImage.FIT/signature.txt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/doc/uImage.FIT/signature.txt b/doc/uImage.FIT/signature.txt index 1695bf4cd84..eee06517fa5 100644 --- a/doc/uImage.FIT/signature.txt +++ b/doc/uImage.FIT/signature.txt @@ -337,6 +337,7 @@ WARNING: When relying on signed FIT images with required signature check the legacy image format is default disabled by not defining CONFIG_LEGACY_IMAGE_FORMAT + Testing ------- An easy way to test signing and verification is to use the test script @@ -349,6 +350,8 @@ A sample run is show below: $ make O=sandbox sandbox_config $ make O=sandbox $ O=sandbox ./test/vboot/vboot_test.sh + + Simple Verified Boot Test ========================= From 26557d1025eff712a5fd5ff98cfd831727bdd009 Mon Sep 17 00:00:00 2001 From: Suman Anna Date: Fri, 19 Jul 2019 10:27:56 -0500 Subject: [PATCH 22/24] remoteproc: Fix potential build issues with SPL remoteproc The rproc uclass driver can either be built with SPL_REMOTEPROC or REMOTEPROC, but the function prototypes in remoteproc.h are defined only when CONFIG_REMOTEPROC is defined. This can cause build issues in SPL if CONFIG_REMOTEPROC is not selected. Fix this by replacing the existing precompiler macro usage with CONFIG_IS_ENABLED. Fixes: ddf56bc7e3ef ("drivers: Introduce a simplified remoteproc framework") Signed-off-by: Suman Anna Reviewed-by: Nishanth Menon Reviewed-by: Lokesh Vutla --- include/remoteproc.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/remoteproc.h b/include/remoteproc.h index c29c0867bcf..49871949055 100644 --- a/include/remoteproc.h +++ b/include/remoteproc.h @@ -130,7 +130,7 @@ struct dm_rproc_ops { /* Accessor */ #define rproc_get_ops(dev) ((struct dm_rproc_ops *)(dev)->driver->ops) -#ifdef CONFIG_REMOTEPROC +#if CONFIG_IS_ENABLED(REMOTEPROC) /** * rproc_init() - Initialize all bound remote proc devices * @return 0 if all ok, else appropriate error value. From f0ebcf8c17c086cfc96914ee2e6c5210ab4551d5 Mon Sep 17 00:00:00 2001 From: David Abdurachmanov Date: Mon, 22 Jul 2019 11:38:11 +0300 Subject: [PATCH 23/24] distro_bootcmd: refactor virtio to support PCI block devices Starting libvirt v5.3.0 with QEMU 4.0.0 use of PCI is automatic and thus storage is connected via PCI, which is not visible to U-Boot out-of-the-box. Refactor to do "pci enum" followed by "virtio scan" to see PCI connected storage, and allow bootloader to load kernel and initramfs images. Tested with Fedora/RISCV using releases: libvirt 5.4.0 & 5.5.0, QEMU 4.0.0 and U-Boot 2019.07 RC4. Signed-off-by: David Abdurachmanov --- include/config_distro_bootcmd.h | 27 +++++++++++++++++++++------ 1 file changed, 21 insertions(+), 6 deletions(-) diff --git a/include/config_distro_bootcmd.h b/include/config_distro_bootcmd.h index 26e61ef1969..3570a32dff8 100644 --- a/include/config_distro_bootcmd.h +++ b/include/config_distro_bootcmd.h @@ -254,11 +254,11 @@ #endif #if defined(CONFIG_DM_PCI) -#define BOOTENV_RUN_NET_PCI_ENUM "run boot_net_pci_enum; " +#define BOOTENV_RUN_PCI_ENUM "run boot_pci_enum; " #define BOOTENV_SHARED_PCI \ - "boot_net_pci_enum=pci enum\0" + "boot_pci_enum=pci enum\0" #else -#define BOOTENV_RUN_NET_PCI_ENUM +#define BOOTENV_RUN_PCI_ENUM #define BOOTENV_SHARED_PCI #endif @@ -281,10 +281,24 @@ #endif #ifdef CONFIG_CMD_VIRTIO -#define BOOTENV_SHARED_VIRTIO BOOTENV_SHARED_BLKDEV(virtio) +#define BOOTENV_RUN_VIRTIO_INIT "run virtio_init; " +#define BOOTENV_SET_VIRTIO_NEED_INIT "virtio_need_init=; " +#define BOOTENV_SHARED_VIRTIO \ + "virtio_init=" \ + "if ${virtio_need_init}; then " \ + "virtio_need_init=false; " \ + "virtio scan; " \ + "fi\0" \ + \ + "virtio_boot=" \ + BOOTENV_RUN_PCI_ENUM \ + BOOTENV_RUN_VIRTIO_INIT \ + BOOTENV_SHARED_BLKDEV_BODY(virtio) #define BOOTENV_DEV_VIRTIO BOOTENV_DEV_BLKDEV #define BOOTENV_DEV_NAME_VIRTIO BOOTENV_DEV_NAME_BLKDEV #else +#define BOOTENV_RUN_VIRTIO_INIT +#define BOOTENV_SET_VIRTIO_NEED_INIT #define BOOTENV_SHARED_VIRTIO #define BOOTENV_DEV_VIRTIO \ BOOT_TARGET_DEVICES_references_VIRTIO_without_CONFIG_CMD_VIRTIO @@ -350,7 +364,7 @@ #define BOOTENV_DEV_DHCP(devtypeu, devtypel, instance) \ "bootcmd_dhcp=" \ BOOTENV_RUN_NET_USB_START \ - BOOTENV_RUN_NET_PCI_ENUM \ + BOOTENV_RUN_PCI_ENUM \ "if dhcp ${scriptaddr} ${boot_script_dhcp}; then " \ "source ${scriptaddr}; " \ "fi;" \ @@ -369,7 +383,7 @@ #define BOOTENV_DEV_PXE(devtypeu, devtypel, instance) \ "bootcmd_pxe=" \ BOOTENV_RUN_NET_USB_START \ - BOOTENV_RUN_NET_PCI_ENUM \ + BOOTENV_RUN_PCI_ENUM \ "dhcp; " \ "if pxe get; then " \ "pxe boot; " \ @@ -465,6 +479,7 @@ "distro_bootcmd=" BOOTENV_SET_SCSI_NEED_INIT \ BOOTENV_SET_NVME_NEED_INIT \ BOOTENV_SET_IDE_NEED_INIT \ + BOOTENV_SET_VIRTIO_NEED_INIT \ "for target in ${boot_targets}; do " \ "run bootcmd_${target}; " \ "done\0" From e21e3ffdd18b88a12d98f6ae985fd5d334b9cec9 Mon Sep 17 00:00:00 2001 From: Patrick Delaunay Date: Mon, 22 Jul 2019 14:19:20 +0200 Subject: [PATCH 24/24] psci: Fix warnings when compiling with W=1 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This patch solves the following warnings: arch/arm/mach-stm32mp/psci.c: warning: no previous prototype for ‘psci_set_state’ [-Wmissing-prototypes] warning: no previous prototype for ‘psci_arch_cpu_entry’ [-Wmissing-prototypes] warning: no previous prototype for ‘psci_features’ [-Wmissing-prototypes] warning: no previous prototype for ‘psci_version’ [-Wmissing-prototypes] warning: no previous prototype for ‘psci_affinity_info’ [-Wmissing-prototypes] warning: no previous prototype for ‘psci_migrate_info_type’ [-Wmissing-prototypes] warning: no previous prototype for ‘psci_cpu_on’ [-Wmissing-prototypes] warning: no previous prototype for ‘psci_cpu_off’ [-Wmissing-prototypes] warning: no previous prototype for ‘psci_system_reset’ [-Wmissing-prototypes] warning: no previous prototype for ‘psci_system_off’ [-Wmissing-prototypes] Signed-off-by: Patrick Delaunay --- arch/arm/cpu/armv7/sunxi/psci.c | 2 +- arch/arm/include/asm/system.h | 15 +++++++++++++++ arch/arm/mach-imx/mx7/psci-mx7.c | 2 +- arch/arm/mach-stm32mp/psci.c | 18 +++++++++--------- arch/arm/mach-uniphier/arm32/psci.c | 4 ++-- 5 files changed, 28 insertions(+), 13 deletions(-) diff --git a/arch/arm/cpu/armv7/sunxi/psci.c b/arch/arm/cpu/armv7/sunxi/psci.c index f3e8f99a719..2c5d99e9acd 100644 --- a/arch/arm/cpu/armv7/sunxi/psci.c +++ b/arch/arm/cpu/armv7/sunxi/psci.c @@ -276,7 +276,7 @@ int __secure psci_cpu_on(u32 __always_unused unused, u32 mpidr, u32 pc, return ARM_PSCI_RET_SUCCESS; } -void __secure psci_cpu_off(void) +s32 __secure psci_cpu_off(void) { psci_cpu_off_common(); diff --git a/arch/arm/include/asm/system.h b/arch/arm/include/asm/system.h index aed2e3c51ef..a1a5e35ef6f 100644 --- a/arch/arm/include/asm/system.h +++ b/arch/arm/include/asm/system.h @@ -516,6 +516,21 @@ enum { */ void mmu_page_table_flush(unsigned long start, unsigned long stop); +#ifdef CONFIG_ARMV7_PSCI +void psci_arch_cpu_entry(void); +u32 psci_version(void); +s32 psci_features(u32 function_id, u32 psci_fid); +s32 psci_cpu_off(void); +s32 psci_cpu_on(u32 function_id, u32 target_cpu, u32 pc, + u32 context_id); +s32 psci_affinity_info(u32 function_id, u32 target_affinity, + u32 lowest_affinity_level); +u32 psci_migrate_info_type(void); +void psci_system_off(void); +void psci_system_reset(void); +s32 psci_features(u32 function_id, u32 psci_fid); +#endif + #endif /* __ASSEMBLY__ */ #define arch_align_stack(x) (x) diff --git a/arch/arm/mach-imx/mx7/psci-mx7.c b/arch/arm/mach-imx/mx7/psci-mx7.c index 34ba0a9307d..c98d2e96af5 100644 --- a/arch/arm/mach-imx/mx7/psci-mx7.c +++ b/arch/arm/mach-imx/mx7/psci-mx7.c @@ -298,7 +298,7 @@ __secure s32 psci_affinity_info(u32 __always_unused function_id, return psci_state[cpu]; } -__secure s32 psci_migrate_info_type(u32 function_id) +__secure u32 psci_migrate_info_type(void) { /* Trusted OS is either not present or does not require migration */ return 2; diff --git a/arch/arm/mach-stm32mp/psci.c b/arch/arm/mach-stm32mp/psci.c index 139bb092922..1d91b2d324a 100644 --- a/arch/arm/mach-stm32mp/psci.c +++ b/arch/arm/mach-stm32mp/psci.c @@ -30,7 +30,7 @@ u8 psci_state[STM32MP1_PSCI_NR_CPUS] __secure_data = { PSCI_AFFINITY_LEVEL_ON, PSCI_AFFINITY_LEVEL_OFF}; -void __secure psci_set_state(int cpu, u8 state) +static inline void psci_set_state(int cpu, u8 state) { psci_state[cpu] = state; dsb(); @@ -67,7 +67,7 @@ void __secure psci_arch_cpu_entry(void) writel(0xFFFFFFFF, TAMP_BACKUP_MAGIC_NUMBER); } -int __secure psci_features(u32 function_id, u32 psci_fid) +s32 __secure psci_features(u32 function_id, u32 psci_fid) { switch (psci_fid) { case ARM_PSCI_0_2_FN_PSCI_VERSION: @@ -82,12 +82,12 @@ int __secure psci_features(u32 function_id, u32 psci_fid) return ARM_PSCI_RET_NI; } -unsigned int __secure psci_version(u32 function_id) +u32 __secure psci_version(void) { return ARM_PSCI_VER_1_0; } -int __secure psci_affinity_info(u32 function_id, u32 target_affinity, +s32 __secure psci_affinity_info(u32 function_id, u32 target_affinity, u32 lowest_affinity_level) { u32 cpu = target_affinity & MPIDR_AFF0; @@ -104,7 +104,7 @@ int __secure psci_affinity_info(u32 function_id, u32 target_affinity, return psci_state[cpu]; } -int __secure psci_migrate_info_type(u32 function_id) +u32 __secure psci_migrate_info_type(void) { /* * in Power_State_Coordination_Interface_PDD_v1_1_DEN0022D.pdf @@ -116,7 +116,7 @@ int __secure psci_migrate_info_type(u32 function_id) return 2; } -int __secure psci_cpu_on(u32 function_id, u32 target_cpu, u32 pc, +s32 __secure psci_cpu_on(u32 function_id, u32 target_cpu, u32 pc, u32 context_id) { u32 cpu = target_cpu & MPIDR_AFF0; @@ -161,7 +161,7 @@ int __secure psci_cpu_on(u32 function_id, u32 target_cpu, u32 pc, return ARM_PSCI_RET_SUCCESS; } -int __secure psci_cpu_off(u32 function_id) +s32 __secure psci_cpu_off(void) { u32 cpu; @@ -181,7 +181,7 @@ int __secure psci_cpu_off(u32 function_id) wfi(); } -void __secure psci_system_reset(u32 function_id) +void __secure psci_system_reset(void) { /* System reset */ writel(RCC_MP_GRSTCSETR_MPSYSRST, RCC_MP_GRSTCSETR); @@ -190,7 +190,7 @@ void __secure psci_system_reset(u32 function_id) wfi(); } -void __secure psci_system_off(u32 function_id) +void __secure psci_system_off(void) { /* System Off is not managed, waiting user power off * TODO: handle I2C write in PMIC Main Control register bit 0 = SWOFF diff --git a/arch/arm/mach-uniphier/arm32/psci.c b/arch/arm/mach-uniphier/arm32/psci.c index 3f67edf26eb..ef35923f6ac 100644 --- a/arch/arm/mach-uniphier/arm32/psci.c +++ b/arch/arm/mach-uniphier/arm32/psci.c @@ -130,7 +130,7 @@ void psci_arch_init(void) u32 uniphier_psci_holding_pen_release __secure_data = 0xffffffff; -int __secure psci_cpu_on(u32 function_id, u32 cpuid, u32 entry_point, +s32 __secure psci_cpu_on(u32 function_id, u32 cpuid, u32 entry_point, u32 context_id) { u32 cpu = cpuid & 0xff; @@ -155,7 +155,7 @@ int __secure psci_cpu_on(u32 function_id, u32 cpuid, u32 entry_point, return PSCI_RET_SUCCESS; } -void __secure psci_system_reset(u32 function_id) +void __secure psci_system_reset(void) { reset_cpu(0); }