From 1cd0a441066d3003c63fc90d936f6c4e1b47c896 Mon Sep 17 00:00:00 2001 From: Quentin Schulz Date: Thu, 18 Dec 2025 13:19:07 +0100 Subject: [PATCH 01/10] boot: fix missing dependency for BOOTMETH_ANDROID The code depends on set_avendor_bootimg_addr and set_abootimg_addr functions which are only defined in cmd/abootimg.c, only built when CMD_ABOOTIMG=y so let's add a dependency. It should be "depends on" to be properly implemented, but we get a circular dependency otherwise: boot/Kconfig:566:error: recursive dependency detected! boot/Kconfig:566: symbol BOOTMETH_ANDROID depends on CMD_ABOOTIMG cmd/Kconfig:504: symbol CMD_ABOOTIMG depends on ANDROID_BOOT_IMAGE boot/Kconfig:7: symbol ANDROID_BOOT_IMAGE is selected by BOOTMETH_ANDROID so instead we do a select. It is safe because CMD_ABOOTIMG depends on ANDROID_BOOT_IMAGE which we select here as well. Fixes: 125d9f3306ea ("bootstd: Add a bootmeth for Android") Signed-off-by: Quentin Schulz Reviewed-by: Kory Maincent Reviewed-by: Mattijs Korpershoek Link: https://lore.kernel.org/r/20251218-bootmeth_android-deps-v1-1-0113c804f951@cherry.de Signed-off-by: Mattijs Korpershoek --- boot/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/boot/Kconfig b/boot/Kconfig index 676a42a6ed4..b090f3c4c11 100644 --- a/boot/Kconfig +++ b/boot/Kconfig @@ -550,6 +550,7 @@ config BOOTMETH_ANDROID depends on X86 || ARM || SANDBOX depends on CMDLINE select ANDROID_BOOT_IMAGE + select CMD_ABOOTIMG select CMD_BCB imply CMD_FASTBOOT imply FASTBOOT if !NET_LWIP From 6a92e9827650797b6b5290621c1831fe32d6ea4b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Petr=20Bene=C5=A1?= Date: Thu, 18 Dec 2025 15:27:35 +0100 Subject: [PATCH 02/10] usb: ci_udc: Check ci_ep->desc before use MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit There are two places where ci_ep->desc could be accessed despite it is not valid at that moment. Either the endpoint has not been enabled yet or it has been disabled meanwhile (The ethernet gadged behaves this way at least.). That results in dereferencing a null pointer. Moreover, the patch gets rid of possible outstanding requests if the endpoint's state changes to disabled. Signed-off-by: Petr Beneš Reviewed-by: Mattijs Korpershoek Link: https://lore.kernel.org/r/20251218142737.3169753-1-petr.benes@ysoft.com Signed-off-by: Mattijs Korpershoek --- drivers/usb/gadget/ci_udc.c | 47 ++++++++++++++++++++++++++++++++++++- 1 file changed, 46 insertions(+), 1 deletion(-) diff --git a/drivers/usb/gadget/ci_udc.c b/drivers/usb/gadget/ci_udc.c index 4bff75da759..c8953d48723 100644 --- a/drivers/usb/gadget/ci_udc.c +++ b/drivers/usb/gadget/ci_udc.c @@ -308,6 +308,27 @@ static void ci_ep_free_request(struct usb_ep *ep, struct usb_request *req) free(ci_req); } +static void request_complete(struct usb_ep *ep, struct ci_req *req, int status) +{ + if (req->req.status == -EINPROGRESS) + req->req.status = status; + + DBG("%s: req %p complete: status %d, actual %u\n", + ep->name, req, req->req.status, req->req.actual); + + req->req.complete(ep, &req->req); +} + +static void request_complete_list(struct usb_ep *ep, struct list_head *list, int status) +{ + struct ci_req *req, *tmp_req; + + list_for_each_entry_safe(req, tmp_req, list, queue) { + list_del_init(&req->queue); + request_complete(ep, req, status); + } +} + static void ep_enable(int num, int in, int maxpacket) { struct ci_udc *udc = (struct ci_udc *)controller.ctrl->hcor; @@ -335,6 +356,12 @@ static int ci_ep_enable(struct usb_ep *ep, int num, in; num = desc->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK; in = (desc->bEndpointAddress & USB_DIR_IN) != 0; + + if (ci_ep->desc) { + DBG("%s: endpoint num %d in %d already enabled\n", __func__, num, in); + return -EBUSY; + } + ci_ep->desc = desc; ep->desc = desc; @@ -385,19 +412,32 @@ static int ep_disable(int num, int in) static int ci_ep_disable(struct usb_ep *ep) { struct ci_ep *ci_ep = container_of(ep, struct ci_ep, ep); + LIST_HEAD(req_list); int num, in, err; + if (!ci_ep->desc) { + DBG("%s: attempt to disable a not enabled yet endpoint\n", __func__); + err = -EBUSY; + goto nodesc; + } + num = ci_ep->desc->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK; in = (ci_ep->desc->bEndpointAddress & USB_DIR_IN) != 0; + list_splice_init(&ci_ep->queue, &req_list); + request_complete_list(ep, &req_list, -ESHUTDOWN); + err = ep_disable(num, in); if (err) return err; ci_ep->desc = NULL; + err = 0; + +nodesc: ep->desc = NULL; ci_ep->req_primed = false; - return 0; + return err; } static int ci_bounce(struct ci_req *ci_req, int in) @@ -606,6 +646,11 @@ static int ci_ep_queue(struct usb_ep *ep, int in, ret; int __maybe_unused num; + if (!ci_ep->desc) { + DBG("%s: ci_ep->desc == NULL, nothing to do!\n", __func__); + return -EINVAL; + } + num = ci_ep->desc->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK; in = (ci_ep->desc->bEndpointAddress & USB_DIR_IN) != 0; From 8ea70d8132df30c37c9592952c6267c2e9b4e562 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Petr=20Bene=C5=A1?= Date: Thu, 18 Dec 2025 15:27:36 +0100 Subject: [PATCH 03/10] usb: ci_udc: cosmetics: EP and requests debug info MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Make a note in an unexpected situation, e.g. queuing a request on a disabled endpoint, enabling an enabled endpoint... Reviewed-by: Mattijs Korpershoek Signed-off-by: Petr Beneš Link: https://lore.kernel.org/r/20251218142737.3169753-2-petr.benes@ysoft.com Signed-off-by: Mattijs Korpershoek --- drivers/usb/gadget/ci_udc.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/drivers/usb/gadget/ci_udc.c b/drivers/usb/gadget/ci_udc.c index c8953d48723..046bb335ecb 100644 --- a/drivers/usb/gadget/ci_udc.c +++ b/drivers/usb/gadget/ci_udc.c @@ -273,8 +273,10 @@ ci_ep_alloc_request(struct usb_ep *ep, unsigned int gfp_flags) if (ci_ep->desc) num = ci_ep->desc->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK; - if (num == 0 && controller.ep0_req) + if (num == 0 && controller.ep0_req) { + DBG("%s: already got controller.ep0_req = %p\n", __func__, controller.ep0_req); return &controller.ep0_req->req; + } ci_req = calloc(1, sizeof(*ci_req)); if (!ci_req) @@ -296,6 +298,8 @@ static void ci_ep_free_request(struct usb_ep *ep, struct usb_request *req) if (ci_ep->desc) num = ci_ep->desc->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK; + else + DBG("%s: no endpoint %p descriptor\n", __func__, ci_ep); if (num == 0) { if (!controller.ep0_req) @@ -624,8 +628,10 @@ static int ci_ep_dequeue(struct usb_ep *_ep, struct usb_request *_req) break; } - if (&ci_req->req != _req) + if (&ci_req->req != _req) { + DBG("%s: ci_req not found in the queue\n", __func__); return -EINVAL; + } list_del_init(&ci_req->queue); From 3f9765672ce424300b6d9fb95d8b01313df9dff7 Mon Sep 17 00:00:00 2001 From: Sean Anderson Date: Tue, 6 Jan 2026 17:22:11 -0500 Subject: [PATCH 04/10] dfu: Report error codes A lot of things can go wrong while parsing dfu_alt_info. Make sure to pass the real error codes all the way up instead of replacing them with an unhelpful -1. Signed-off-by: Sean Anderson Reviewed-by: Mattijs Korpershoek Link: https://lore.kernel.org/r/20260106222212.744823-1-sean.anderson@linux.dev Signed-off-by: Mattijs Korpershoek --- drivers/dfu/dfu.c | 52 ++++++++++++++++++++++++++--------------------- 1 file changed, 29 insertions(+), 23 deletions(-) diff --git a/drivers/dfu/dfu.c b/drivers/dfu/dfu.c index eefdf44ec87..90d8b45ce8a 100644 --- a/drivers/dfu/dfu.c +++ b/drivers/dfu/dfu.c @@ -185,7 +185,7 @@ int dfu_init_env_entities(char *interface, char *devstr) ret = dfu_config_entities(env_bkp, interface, devstr); if (ret) { - pr_err("DFU entities configuration failed!\n"); + pr_err("DFU entities configuration failed: %d\n", ret); pr_err("(partition table does not match dfu_alt_info?)\n"); goto done; } @@ -518,7 +518,7 @@ static int dfu_fill_entity(struct dfu_entity *dfu, char *s, int alt, char *interface, char *devstr) { char *argv[DFU_MAX_ENTITY_ARGS]; - int argc; + int argc, ret; char *st; debug("%s: %s interface: %s dev: %s\n", __func__, s, interface, devstr); @@ -547,30 +547,37 @@ static int dfu_fill_entity(struct dfu_entity *dfu, char *s, int alt, /* Specific for mmc device */ if (strcmp(interface, "mmc") == 0) { - if (dfu_fill_entity_mmc(dfu, devstr, argv, argc)) - return -1; + ret = dfu_fill_entity_mmc(dfu, devstr, argv, argc); + if (ret) + return ret; } else if (strcmp(interface, "mtd") == 0) { - if (dfu_fill_entity_mtd(dfu, devstr, argv, argc)) - return -1; + ret = dfu_fill_entity_mtd(dfu, devstr, argv, argc); + if (ret) + return ret; } else if (strcmp(interface, "nand") == 0) { - if (dfu_fill_entity_nand(dfu, devstr, argv, argc)) - return -1; + ret = dfu_fill_entity_nand(dfu, devstr, argv, argc); + if (ret) + return ret; } else if (strcmp(interface, "ram") == 0) { - if (dfu_fill_entity_ram(dfu, devstr, argv, argc)) - return -1; + ret = dfu_fill_entity_ram(dfu, devstr, argv, argc); + if (ret) + return ret; } else if (strcmp(interface, "sf") == 0) { - if (dfu_fill_entity_sf(dfu, devstr, argv, argc)) - return -1; + ret = dfu_fill_entity_sf(dfu, devstr, argv, argc); + if (ret) + return ret; } else if (strcmp(interface, "virt") == 0) { - if (dfu_fill_entity_virt(dfu, devstr, argv, argc)) - return -1; + ret = dfu_fill_entity_virt(dfu, devstr, argv, argc); + if (ret) + return ret; } else if (strcmp(interface, "scsi") == 0) { - if (dfu_fill_entity_scsi(dfu, devstr, argv, argc)) - return -1; + ret = dfu_fill_entity_scsi(dfu, devstr, argv, argc); + if (ret) + return ret; } else { printf("%s: Device %s not (yet) supported!\n", __func__, interface); - return -1; + return -EOPNOTSUPP; } dfu_get_buf(dfu); @@ -624,12 +631,12 @@ int dfu_alt_add(struct dfu_entity *dfu, char *interface, char *devstr, char *s) int ret; if (alt_num_cnt >= dfu_alt_num) - return -1; + return -EINVAL; p_dfu = &dfu[alt_num_cnt]; ret = dfu_fill_entity(p_dfu, s, alt_num_cnt, interface, devstr); if (ret) - return -1; + return ret; list_add_tail(&p_dfu->list, &dfu_list); alt_num_cnt++; @@ -645,16 +652,15 @@ int dfu_config_entities(char *env, char *interface, char *devstr) ret = dfu_alt_init(dfu_find_alt_num(env), &dfu); if (ret) - return -1; + return ret; for (i = 0; i < dfu_alt_num; i++) { s = strsep(&env, ";"); s = skip_spaces(s); ret = dfu_alt_add(dfu, interface, devstr, s); - if (ret) { + if (ret) /* We will free "dfu" in dfu_free_entities() */ - return -1; - } + return ret; } return 0; From 8fa0cf5f3d7ca15e2d102d0d46a132d246793486 Mon Sep 17 00:00:00 2001 From: Francois Berder Date: Wed, 14 Jan 2026 10:14:55 +0100 Subject: [PATCH 05/10] bootstd: android: Add missing free in android_read_bootflow If strdup call fails, one needs to free priv variable. Signed-off-by: Francois Berder Reviewed-by: Mattijs Korpershoek Reviewed-by: Tom Rini Link: https://lore.kernel.org/r/BESP194MB28052734FD0361EA602F6360DA8FA@BESP194MB2805.EURP194.PROD.OUTLOOK.COM Signed-off-by: Mattijs Korpershoek --- boot/bootmeth_android.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/boot/bootmeth_android.c b/boot/bootmeth_android.c index 1374551dbeb..1d70e8d5c05 100644 --- a/boot/bootmeth_android.c +++ b/boot/bootmeth_android.c @@ -252,8 +252,10 @@ static int android_read_bootflow(struct udevice *dev, struct bootflow *bflow) priv->boot_mode = ANDROID_BOOT_MODE_NORMAL; bflow->os_name = strdup("Android"); } - if (!bflow->os_name) + if (!bflow->os_name) { + free(priv); return log_msg_ret("os", -ENOMEM); + } if (priv->boot_mode == ANDROID_BOOT_MODE_BOOTLOADER) { /* Clear BCB */ From 6b0f079ba260b37a5b3577e6429ba721070ee2bf Mon Sep 17 00:00:00 2001 From: "Mattijs Korpershoek (TI.com)" Date: Mon, 12 Jan 2026 11:55:37 +0100 Subject: [PATCH 06/10] boot: android: import addBootConfigParameters() from AOSP To properly implement Android boot image v4, U-Boot must be able to add additional entries to the bootconfig. Add `add_bootconfig_parameters()` to do so. This has been imported from Google's U-Boot source[1] The variables/function names have been reworked to be compliant with U-Boot's coding style. [1] https://android.googlesource.com/platform/external/u-boot/+/7af0a0506d4de6f5ea147d10fb0664a8af07d326 Signed-off-by: Mattijs Korpershoek (TI.com) Reviewed-by: Mattijs Korpershoek Signed-off-by: Guillaume La Roque (TI.com) Link: https://lore.kernel.org/r/20260112-bootconfig-v5-1-79b242159ac7@baylibre.com Signed-off-by: Mattijs Korpershoek --- boot/image-android.c | 40 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/boot/image-android.c b/boot/image-android.c index ea47869a64c..5407390ef36 100644 --- a/boot/image-android.c +++ b/boot/image-android.c @@ -57,6 +57,46 @@ static ulong add_trailer(ulong bootconfig_start_addr, ulong bootconfig_size) return BOOTCONFIG_TRAILER_SIZE; } +/* + * Add a string of boot config parameters to memory appended by the trailer. + * NOTE: This function expects bootconfig_start_addr to be already mapped. + * It works directly with the mapped pointer, not a physical address. + */ +static long add_bootconfig_parameters(char *params, long params_len, + ulong bootconfig_start_addr, u32 bootconfig_size) +{ + long applied_bytes = 0; + long new_size = 0; + ulong end; + + if (!params || !bootconfig_start_addr) + return -EINVAL; + + if (params_len == 0) + return 0; + + end = bootconfig_start_addr + bootconfig_size; + + if (is_trailer_present(end)) { + end -= BOOTCONFIG_TRAILER_SIZE; + applied_bytes -= BOOTCONFIG_TRAILER_SIZE; + memcpy(&new_size, (void *)end, BOOTCONFIG_SIZE_SIZE); + } else { + /* + * When no trailer is present, the bootconfig_size includes the actual content. + * We should write new parameters right after the existing content. + */ + end = bootconfig_start_addr + bootconfig_size; + new_size = bootconfig_size; + } + + memcpy((void *)end, params, params_len); + applied_bytes += params_len; + applied_bytes += add_trailer(bootconfig_start_addr, + bootconfig_size + applied_bytes); + return applied_bytes; +} + __weak ulong get_avendor_bootimg_addr(void) { return -1; From 8f6d43557056c73469c1e70d2949ebef6ce5ce44 Mon Sep 17 00:00:00 2001 From: "Guillaume La Roque (TI.com)" Date: Mon, 12 Jan 2026 11:55:38 +0100 Subject: [PATCH 07/10] boot: android: Add sandbox memory mapping support Use map_to_sysmem() to convert header pointers to physical addresses in parse_hdr functions, and add proper map_sysmem()/unmap_sysmem() calls in android_image_get_data() for sandbox compatibility. Reviewed-by: Mattijs Korpershoek Reviewed-by: Simon Glass Signed-off-by: Guillaume La Roque (TI.com) Link: https://lore.kernel.org/r/20260112-bootconfig-v5-2-79b242159ac7@baylibre.com Signed-off-by: Mattijs Korpershoek --- boot/image-android.c | 58 +++++++++++++++++++++++++------------------- cmd/abootimg.c | 20 +++++---------- 2 files changed, 39 insertions(+), 39 deletions(-) diff --git a/boot/image-android.c b/boot/image-android.c index 5407390ef36..b9e0b3f68b0 100644 --- a/boot/image-android.c +++ b/boot/image-android.c @@ -114,7 +114,7 @@ static void android_boot_image_v3_v4_parse_hdr(const struct andr_boot_img_hdr_v3 * The header takes a full page, the remaining components are aligned * on page boundary. */ - end = (ulong)hdr; + end = map_to_sysmem(hdr); end += ANDR_GKI_PAGE_SIZE; data->kernel_ptr = end; data->kernel_size = hdr->kernel_size; @@ -127,7 +127,7 @@ static void android_boot_image_v3_v4_parse_hdr(const struct andr_boot_img_hdr_v3 if (hdr->header_version > 3) end += ALIGN(hdr->signature_size, ANDR_GKI_PAGE_SIZE); - data->boot_img_total_size = end - (ulong)hdr; + data->boot_img_total_size = end - map_to_sysmem(hdr); } static void android_vendor_boot_image_v3_v4_parse_hdr(const struct andr_vnd_boot_img_hdr @@ -146,7 +146,7 @@ static void android_vendor_boot_image_v3_v4_parse_hdr(const struct andr_vnd_boot data->ramdisk_addr = hdr->ramdisk_addr; data->dtb_load_addr = hdr->dtb_addr; data->bootconfig_size = hdr->bootconfig_size; - end = (ulong)hdr; + end = map_to_sysmem(hdr); if (hdr->header_version > 3) end += ALIGN(ANDR_VENDOR_BOOT_V4_SIZE, hdr->page_size); @@ -167,12 +167,16 @@ static void android_vendor_boot_image_v3_v4_parse_hdr(const struct andr_vnd_boot end += ALIGN(hdr->vendor_ramdisk_table_size, hdr->page_size); data->bootconfig_addr = end; if (hdr->bootconfig_size) { - data->bootconfig_size += add_trailer(data->bootconfig_addr, + void *bootconfig_ptr = map_sysmem(data->bootconfig_addr, + data->bootconfig_size + + BOOTCONFIG_TRAILER_SIZE); + data->bootconfig_size += add_trailer((ulong)bootconfig_ptr, data->bootconfig_size); + unmap_sysmem(bootconfig_ptr); data->ramdisk_size += data->bootconfig_size; } end += ALIGN(data->bootconfig_size, hdr->page_size); - data->vendor_boot_img_total_size = end - (ulong)hdr; + data->vendor_boot_img_total_size = end - map_to_sysmem(hdr); } static void android_boot_image_v0_v1_v2_parse_hdr(const struct andr_boot_img_hdr_v0 *hdr, @@ -187,7 +191,7 @@ static void android_boot_image_v0_v1_v2_parse_hdr(const struct andr_boot_img_hdr data->header_version = hdr->header_version; data->dtb_load_addr = hdr->dtb_addr; - end = (ulong)hdr; + end = map_to_sysmem(hdr); /* * The header takes a full page, the remaining components are aligned @@ -220,7 +224,7 @@ static void android_boot_image_v0_v1_v2_parse_hdr(const struct andr_boot_img_hdr end += ALIGN(hdr->dtb_size, hdr->page_size); } - data->boot_img_total_size = end - (ulong)hdr; + data->boot_img_total_size = end - map_to_sysmem(hdr); } bool android_image_get_bootimg_size(const void *hdr, u32 *boot_img_size) @@ -271,31 +275,42 @@ bool android_image_get_vendor_bootimg_size(const void *hdr, u32 *vendor_boot_img bool android_image_get_data(const void *boot_hdr, const void *vendor_boot_hdr, struct andr_image_data *data) { + const struct andr_boot_img_hdr_v0 *bhdr; + const struct andr_vnd_boot_img_hdr *vhdr; + if (!boot_hdr || !data) { printf("boot_hdr or data params can't be NULL\n"); return false; } - if (!is_android_boot_image_header(boot_hdr)) { + bhdr = map_sysmem((ulong)boot_hdr, sizeof(*bhdr)); + if (!is_android_boot_image_header(bhdr)) { printf("Incorrect boot image header\n"); + unmap_sysmem(bhdr); return false; } - if (((struct andr_boot_img_hdr_v0 *)boot_hdr)->header_version > 2) { + if (bhdr->header_version > 2) { if (!vendor_boot_hdr) { printf("For boot header v3+ vendor boot image has to be provided\n"); + unmap_sysmem(bhdr); return false; } - if (!is_android_vendor_boot_image_header(vendor_boot_hdr)) { + vhdr = map_sysmem((ulong)vendor_boot_hdr, sizeof(*vhdr)); + if (!is_android_vendor_boot_image_header(vhdr)) { printf("Incorrect vendor boot image header\n"); + unmap_sysmem(vhdr); + unmap_sysmem(bhdr); return false; } - android_boot_image_v3_v4_parse_hdr(boot_hdr, data); - android_vendor_boot_image_v3_v4_parse_hdr(vendor_boot_hdr, data); + android_boot_image_v3_v4_parse_hdr((const struct andr_boot_img_hdr_v3 *)bhdr, data); + android_vendor_boot_image_v3_v4_parse_hdr(vhdr, data); + unmap_sysmem(vhdr); } else { - android_boot_image_v0_v1_v2_parse_hdr(boot_hdr, data); + android_boot_image_v0_v1_v2_parse_hdr(bhdr, data); } + unmap_sysmem(bhdr); return true; } @@ -724,21 +739,14 @@ bool android_image_get_dtb_by_index(ulong hdr_addr, ulong vendor_boot_img, u32 index, ulong *addr, u32 *size) { struct andr_image_data img_data; - const struct andr_boot_img_hdr_v0 *hdr; - const struct andr_vnd_boot_img_hdr *vhdr = NULL; + const void *vendor_boot_hdr = NULL; - hdr = map_sysmem(hdr_addr, sizeof(*hdr)); if (vendor_boot_img != -1) - vhdr = map_sysmem(vendor_boot_img, sizeof(*vhdr)); - if (!android_image_get_data(hdr, vhdr, &img_data)) { - if (vendor_boot_img != -1) - unmap_sysmem(vhdr); - unmap_sysmem(hdr); + vendor_boot_hdr = (const void *)vendor_boot_img; + + if (!android_image_get_data((const void *)hdr_addr, vendor_boot_hdr, + &img_data)) return false; - } - if (vendor_boot_img != -1) - unmap_sysmem(vhdr); - unmap_sysmem(hdr); ulong dtb_img_addr; /* address of DTB part in boot image */ u32 dtb_img_size; /* size of DTB payload in boot image */ diff --git a/cmd/abootimg.c b/cmd/abootimg.c index 6fb52153786..c488609a8f4 100644 --- a/cmd/abootimg.c +++ b/cmd/abootimg.c @@ -92,26 +92,18 @@ static int abootimg_get_recovery_dtbo(int argc, char *const argv[]) static int abootimg_get_dtb_load_addr(int argc, char *const argv[]) { + struct andr_image_data img_data = {0}; + const void *vendor_boot_hdr = NULL; + if (argc > 1) return CMD_RET_USAGE; - struct andr_image_data img_data = {0}; - const struct andr_boot_img_hdr_v0 *hdr; - const struct andr_vnd_boot_img_hdr *vhdr = NULL; - hdr = map_sysmem(abootimg_addr(), sizeof(*hdr)); if (get_avendor_bootimg_addr() != -1) - vhdr = map_sysmem(get_avendor_bootimg_addr(), sizeof(*vhdr)); + vendor_boot_hdr = (const void *)get_avendor_bootimg_addr(); - if (!android_image_get_data(hdr, vhdr, &img_data)) { - if (get_avendor_bootimg_addr() != -1) - unmap_sysmem(vhdr); - unmap_sysmem(hdr); + if (!android_image_get_data((const void *)abootimg_addr(), + vendor_boot_hdr, &img_data)) return CMD_RET_FAILURE; - } - - if (get_avendor_bootimg_addr() != -1) - unmap_sysmem(vhdr); - unmap_sysmem(hdr); if (img_data.header_version < 2) { printf("Error: header_version must be >= 2 for this\n"); From 733f5a601989f5404947c4b268d40724bac414f6 Mon Sep 17 00:00:00 2001 From: "Guillaume La Roque (TI.com)" Date: Mon, 12 Jan 2026 11:55:39 +0100 Subject: [PATCH 08/10] boot: android: Add bootconfig support For android vendor boot image version 4 bootconfig is mandatory.[1] In the android_image_get_ramdisk function, after copying both vendor and boot ramdisks, we extract all androidboot.* entries from the kernel command line. These entries are added to the bootconfig section. We then update the sizes of the ramdisk and bootconfig. Finally, all androidboot.* entries are removed from the kernel command line. [1] https://source.android.com/docs/core/architecture/partitions/vendor-boot-partitions#bootloader-support Reviewed-by: Simon Glass Signed-off-by: Guillaume La Roque (TI.com) Link: https://lore.kernel.org/r/20260112-bootconfig-v5-3-79b242159ac7@baylibre.com [mkorpershoek: dropped irrelevant code comments] Signed-off-by: Mattijs Korpershoek --- boot/image-android.c | 174 ++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 163 insertions(+), 11 deletions(-) diff --git a/boot/image-android.c b/boot/image-android.c index b9e0b3f68b0..fb26290d40c 100644 --- a/boot/image-android.c +++ b/boot/image-android.c @@ -505,6 +505,166 @@ ulong android_image_get_kcomp(const void *hdr, return image_decomp_type(p, sizeof(u32)); } +/** + * android_boot_append_bootconfig() - Append bootconfig parameters to ramdisk + * @img_data: Pointer to Android image data + * @params: Pointer to boot config parameters to append + * @params_len: Length of boot config parameters + * @ramdisk_dest: Destination address for the merged ramdisk + * + * This function copies the vendor ramdisk, boot ramdisk, and bootconfig to + * the destination. It then appends the provided bootconfig parameters. + * + * Return: Bytes added to the bootconfig on success, negative on error. + */ +static long android_boot_append_bootconfig(const struct andr_image_data *img_data, + char *params, long params_len, + void *ramdisk_dest) +{ + void *vendor_ramdisk_src; + void *boot_ramdisk_src; + void *bootconfig_src; + long bytes_added = 0; + + /* Map sources */ + vendor_ramdisk_src = map_sysmem(img_data->vendor_ramdisk_ptr, + img_data->vendor_ramdisk_size); + boot_ramdisk_src = map_sysmem(img_data->ramdisk_ptr, + img_data->boot_ramdisk_size); + + /* Copy Vendor Ramdisk */ + memcpy(ramdisk_dest, vendor_ramdisk_src, img_data->vendor_ramdisk_size); + + /* Copy Boot Ramdisk */ + memcpy((char *)ramdisk_dest + img_data->vendor_ramdisk_size, + boot_ramdisk_src, img_data->boot_ramdisk_size); + + /* Copy Bootconfig and Append Params */ + if (img_data->bootconfig_size) { + bootconfig_src = map_sysmem(img_data->bootconfig_addr, + img_data->bootconfig_size); + memcpy((char *)ramdisk_dest + img_data->vendor_ramdisk_size + + img_data->boot_ramdisk_size, + bootconfig_src, img_data->bootconfig_size); + unmap_sysmem(bootconfig_src); + + if (params && params_len > 1) { + void *bootconfig_ptr = (char *)ramdisk_dest + + img_data->vendor_ramdisk_size + + img_data->boot_ramdisk_size; + bytes_added = add_bootconfig_parameters(params, params_len, + (ulong)bootconfig_ptr, + img_data->bootconfig_size); + } + } + + unmap_sysmem(boot_ramdisk_src); + unmap_sysmem(vendor_ramdisk_src); + + if (bytes_added < 0) + return bytes_added; + + return bytes_added; +} + +/** + * android_image_set_bootconfig() - Extract androidboot.* args and append to bootconfig + * @hdr: Pointer to boot image header + * @vendor_boot_img: Pointer to vendor boot image header + * @ramdisk_addr: Destination address for the merged ramdisk + * + * Return: Size of the bootconfig section (including new params) on success, negative on error. + */ +static long android_image_set_bootconfig(const void *hdr, + const void *vendor_boot_img, + ulong ramdisk_addr) +{ + const char *bootargs = env_get("bootargs"); + char *params = NULL; + char *new_bootargs = NULL; + long params_len = 0; + struct andr_image_data img_data; + long ret; + size_t len; + const char *src; + char *bc_dst; + char *args_dst; + ulong total_size; + void *ramdisk_dest; + + if (!android_image_get_data(hdr, vendor_boot_img, &img_data)) + return -EINVAL; + + /* Extract androidboot.* parameters from bootargs */ + if (bootargs && img_data.bootconfig_size) { + len = strlen(bootargs); + src = bootargs; + + params = malloc(len + 1); + new_bootargs = malloc(len + 1); + if (!params || !new_bootargs) { + free(params); + free(new_bootargs); + printf("Error: malloc failed\n"); + return -ENOMEM; + } + + bc_dst = params; + args_dst = new_bootargs; + + /* Extract androidboot.* and build new bootargs in one pass */ + while (*src) { + /* Skip leading spaces */ + while (*src == ' ') + src++; + if (!*src) + break; + + /* Check if this param starts with androidboot. */ + if (strncmp(src, "androidboot.", 12) == 0) { + /* Copy to bootconfig (add newline if not first) */ + if (bc_dst != params) + *bc_dst++ = '\n'; + while (*src && *src != ' ') + *bc_dst++ = *src++; + } else { + /* Copy to new bootargs (add space if not first) */ + if (args_dst != new_bootargs) + *args_dst++ = ' '; + while (*src && *src != ' ') + *args_dst++ = *src++; + } + } + + *bc_dst++ = '\n'; /* Final newline for bootconfig */ + *bc_dst = '\0'; + *args_dst = '\0'; + params_len = bc_dst - params; + + /* Update bootargs if we extracted any androidboot params */ + if (params_len > 1) + env_set("bootargs", new_bootargs); + } + + /* Calculate total size for mapping */ + total_size = img_data.ramdisk_size + img_data.bootconfig_size; + if (params_len > 1) + total_size += params_len + BOOTCONFIG_TRAILER_SIZE; + + /* Map Dest */ + ramdisk_dest = map_sysmem(ramdisk_addr, total_size); + + /* Copy data */ + ret = android_boot_append_bootconfig(&img_data, params, params_len, + ramdisk_dest); + + unmap_sysmem(ramdisk_dest); + free(params); + free(new_bootargs); + + return ret; +} + int android_image_get_ramdisk(const void *hdr, const void *vendor_boot_img, ulong *rd_data, ulong *rd_len) { @@ -536,17 +696,9 @@ int android_image_get_ramdisk(const void *hdr, const void *vendor_boot_img, ramdisk_ptr = img_data.ramdisk_addr; } *rd_data = ramdisk_ptr; - memcpy((void *)(ramdisk_ptr), (void *)img_data.vendor_ramdisk_ptr, - img_data.vendor_ramdisk_size); - ramdisk_ptr += img_data.vendor_ramdisk_size; - memcpy((void *)(ramdisk_ptr), (void *)img_data.ramdisk_ptr, - img_data.boot_ramdisk_size); - ramdisk_ptr += img_data.boot_ramdisk_size; - if (img_data.bootconfig_size) { - memcpy((void *) - (ramdisk_ptr), (void *)img_data.bootconfig_addr, - img_data.bootconfig_size); - } + if (img_data.header_version > 3) + img_data.ramdisk_size += + android_image_set_bootconfig(hdr, vendor_boot_img, ramdisk_ptr); } else { /* Ramdisk can be used in-place, use current ptr */ if (img_data.ramdisk_addr == 0 || From 892409d4fc04d585fc974e33ef63b735d401e11a Mon Sep 17 00:00:00 2001 From: "Guillaume La Roque (TI.com)" Date: Mon, 12 Jan 2026 11:55:40 +0100 Subject: [PATCH 09/10] cmd: abootimg: Add 'get ramdisk' command Add support for retrieving ramdisk address and size from Android boot images. This command allows users to extract the ramdisk information for boot image v3+ which combines vendor ramdisk, boot ramdisk and bootconfig sections. Reviewed-by: Mattijs Korpershoek Reviewed-by: Simon Glass Signed-off-by: Guillaume La Roque (TI.com) Link: https://lore.kernel.org/r/20260112-bootconfig-v5-4-79b242159ac7@baylibre.com Signed-off-by: Mattijs Korpershoek --- cmd/abootimg.c | 35 ++++++++++++++++++++++++++++++++++- 1 file changed, 34 insertions(+), 1 deletion(-) diff --git a/cmd/abootimg.c b/cmd/abootimg.c index c488609a8f4..eae3e643b60 100644 --- a/cmd/abootimg.c +++ b/cmd/abootimg.c @@ -222,6 +222,33 @@ static int do_abootimg_addr(struct cmd_tbl *cmdtp, int flag, int argc, return CMD_RET_SUCCESS; } +static int abootimg_get_ramdisk(int argc, char *const argv[]) +{ + ulong rd_data, rd_len; + + if (argc > 2) + return CMD_RET_USAGE; + + /* + * Call android_image_get_ramdisk with UNMAPPED addresses + * The function will do its own mapping internally as needed + */ + if (android_image_get_ramdisk((void *)abootimg_addr(), + (void *)get_avendor_bootimg_addr(), + &rd_data, &rd_len)) + return CMD_RET_FAILURE; + + if (argc == 0) { + printf("%lx\n", rd_data); + } else { + env_set_hex(argv[0], rd_data); + if (argc == 2) + env_set_hex(argv[1], rd_len); + } + + return CMD_RET_SUCCESS; +} + static int do_abootimg_get(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]) { @@ -241,6 +268,8 @@ static int do_abootimg_get(struct cmd_tbl *cmdtp, int flag, int argc, return abootimg_get_dtb_load_addr(argc, argv); else if (!strcmp(param, "dtb")) return abootimg_get_dtb(argc, argv); + else if (!strcmp(param, "ramdisk")) + return abootimg_get_ramdisk(argc, argv); return CMD_RET_USAGE; } @@ -307,5 +336,9 @@ U_BOOT_CMD( " - get address and size (hex) of DT blob in the image by index\n" " : index number of desired DT blob in DTB area\n" " [addr_var]: variable name to contain DT blob address\n" - " [size_var]: variable name to contain DT blob size" + " [size_var]: variable name to contain DT blob size\n" + "abootimg get ramdisk [addr_var [size_var]]\n" + " - get address and size (hex) of ramdisk in the image\n" + " [addr_var]: variable name to contain ramdisk address\n" + " [size_var]: variable name to contain ramdisk size" ); From 0efe1d9502a022d5d5c39c73340dd0b7b3f9cbe5 Mon Sep 17 00:00:00 2001 From: "Guillaume La Roque (TI.com)" Date: Mon, 12 Jan 2026 11:55:41 +0100 Subject: [PATCH 10/10] test: abootimg: Add test for bootconfig handling Add test to verify that androidboot.* parameters are correctly extracted from bootargs and appended to the bootconfig section when using 'abootimg get ramdisk' with boot image v4 and vendor_boot image. The test verifies: - androidboot.* parameters are removed from bootargs - They are appended to the bootconfig section in the ramdisk - Non-androidboot parameters remain in bootargs - The bootconfig trailer is properly updated Reviewed-by: Simon Glass Signed-off-by: Guillaume La Roque (TI.com) Reviewed-by: Mattijs Korpershoek Link: https://lore.kernel.org/r/20260112-bootconfig-v5-5-79b242159ac7@baylibre.com [mkorpershoek: dropped whitespace changes from original patch] Signed-off-by: Mattijs Korpershoek --- test/py/tests/test_android/test_abootimg.py | 87 +++++++++++++++++---- 1 file changed, 72 insertions(+), 15 deletions(-) diff --git a/test/py/tests/test_android/test_abootimg.py b/test/py/tests/test_android/test_abootimg.py index daa87643e93..ff54a8318a1 100644 --- a/test/py/tests/test_android/test_abootimg.py +++ b/test/py/tests/test_android/test_abootimg.py @@ -62,22 +62,24 @@ b7762ffff07d345446c1281805e8a0868d81e117a45e111c0d8dc101b253 d4a9820881a70f3873f35352731892f3730b124b32937252a96bb9119ae5 463a5546f82c1f05a360148c8251300a462e000085bf67f200200000""" -# boot img v4 hex dump -boot_img_hex = """1f8b080827b0cd630203626f6f742e696d6700edd8bd0d82601885d1d7c4 -58d8c808b88195bd098d8d246e40e42b083f1aa0717be99d003d277916b8 -e5bddc8a7b792d8e8788c896ce9b88d32ebe6c971e7ddd3543cae734cd01 -c0ffc84c0000b0766d1a87d4e5afeadd3dab7a6f10000000f84163d5d7cd -d43a000000000000000060c53e7544995700400000""" +# bootable boot image v4 hex dump (with DTBs) +boot_img_hex = """1f8b0808e2dd60690203626f6f745f6e65772e696d6700edd8ab0d836018 +40d14f900a0c8c5036e80a24180c24dde04f4034d04740b13d02d90920e7 +8c70e5adbbe6d9b74d5544441987c72dfe64010000009cd5342e9f71beff +d2367fd3900b0200000017b4a4f7f05a2703000000002e6c0765d9bd6000 +300000""" -# vendor boot image v4 hex dump -vboot_img_hex = """1f8b0808baaecd63020376626f6f742e696d6700edd8310b824018c6f1b3 -222a08f41b3436b4280dcdd19c11d16ee9109d18d59042d047ec8b04cd0d -d19d5a4345534bf6ffc173ef29272f38e93b1d0ec67dd79d548462aa1cd2 -d5d20b0000f8438678f90c18d584b8a4bbb3a557991ecb2a0000f80d6b2f -f4179b656be5c532f2fc066f040000000080e23936af2755f62a3d918df1 -db2a7ab67f9ffdeb7df7cda3465ecb79c4ce7e5c577562bb9364b74449a5 -1e467e20c53c0a57de763193c1779b3b4fcd9d4ee27c6a0e00000000c0ff -309ffea7010000000040f1dc004129855400400000""" +# bootable vendor boot image v4 hex dump (with DTBs + bootconfig) +vboot_img_hex = """1f8b0808e2dd6069020376656e646f725f626f6f745f6e65772e696d6700 +eddb316bc24014c0f14b2dd20a425c3b393a48c1d0c1a54be9aca588fbc5 +0b3434e9c979d04628f811fd22426787d2bbc43a68e9d4a5f1ff83f7de25 +5c787053f220d3d1fde3dd783c39174ee86255e68e4f0000e00405e2e835 +e0e142886db9fae8f89c95dbaa7ac5890100f02f1899ab74f1dc9dcb22d3 +52b538110000000000ea67ddfedcb8f2ee6228aa317ecf859fed7fcffefd +fae68747835d6dec42bc0df6d74d1fc5a0bfac6e89331797b9564926663a +9f4b9bc659f2b7cda383e6517f19fdd61c0000000080d3111e7c4f030000 +000080fa912fcae854c55adbeb2769d4ab34c9ad4d16963f010000000000 +a88d2fb468951800500000""" # Expected response for "abootimg dtb_dump" command dtb_dump_resp="""## DTB area contents (concat format): @@ -282,3 +284,58 @@ def test_abootimgv4(abootimgv4_disk_image_vboot, abootimgv4_disk_image_boot, ubm ubman.run_command('fdt get value v / model') response = ubman.run_command('env print v') assert response == 'v=x2' + +@pytest.mark.boardspec('sandbox') +@pytest.mark.buildconfigspec('android_boot_image') +@pytest.mark.buildconfigspec('cmd_abootimg') +@pytest.mark.requiredtool('xxd') +@pytest.mark.requiredtool('gunzip') +def test_abootimg_bootconfig(abootimgv4_disk_image_vboot, + abootimgv4_disk_image_boot, + ubman): + """Test bootconfig handling with boot image v4. + + Verifies that androidboot.* parameters from bootargs are appended to the + bootconfig section in vendor_boot image in memory, and that non-androidboot + parameters remain in bootargs. + """ + + # Setup addresses + ram_base = utils.find_ram_base(ubman) + ramdisk_addr_r = ram_base + 0x4000000 + ubman.run_command('setenv ramdisk_addr_r 0x%x' % ramdisk_addr_r) + ubman.run_command('setenv loadaddr 0x%x' % loadaddr) + ubman.run_command('setenv vloadaddr 0x%x' % vloadaddr) + + # Set bootargs with androidboot.* parameters + ubman.run_command('setenv bootargs "androidboot.serialno=ABC123 androidboot.mode=recovery console=ttyS0"') + + # Load images + ubman.run_command('host load hostfs - 0x%x %s' % (vloadaddr, + abootimgv4_disk_image_vboot.path)) + ubman.run_command('host load hostfs - 0x%x %s' % (loadaddr, + abootimgv4_disk_image_boot.path)) + ubman.run_command('abootimg addr 0x%x 0x%x' % (loadaddr, vloadaddr)) + + # Extract ramdisk (triggers bootconfig append) + ubman.run_command('abootimg get ramdisk ramdisk_addr ramdisk_size') + + # Get ramdisk address + response = ubman.run_command('env print ramdisk_addr') + ramdisk_start = int(response.split('=')[1], 16) + + # Verify androidboot.* parameters were removed from bootargs + response = ubman.run_command('env print bootargs') + assert 'androidboot.' not in response + assert 'console=ttyS0' in response + + # Get ramdisk size and verify BOOTCONFIG magic at the end + response = ubman.run_command('env print ramdisk_size') + ramdisk_size = int(response.split('=')[1], 16) + + # Dump the end of the ramdisk where BOOTCONFIG trailer should be + # The trailer is at the end, so dump the last 48 bytes + response = ubman.run_command('md.b 0x%x 48' % (ramdisk_start + ramdisk_size - 48)) + + # Verify BOOTCONFIG magic is present + assert 'BOOTCONFIG' in response