From 3ad4a86b6027cfcbe0ffca6d5b450ef0428c5940 Mon Sep 17 00:00:00 2001 From: "zhiwei01.li" Date: Thu, 14 May 2026 10:49:25 +0800 Subject: [PATCH] fastboot: fetch: fix [RDKS100-1919] Support fetching partition data above 4GiB offset When fastboot fetch was invoked with a starting offset >= 4GiB (e.g. chunked fetch of an 8GiB rootfs split into segments), fb_blk_read_raw_image() silently truncated the offset to its low 32 bits because its `size`/`offset` formal parameters were declared as u32. Even though the upstream callers (fastboot_blk_flash_read, fastboot_generic_flash_read) carry u64 offsets, the truncation at this leaf reads from the wrong LBA on the eMMC/UFS device. Symptom: fetch of an 8GiB ext4 rootfs produces a file of the expected size, but bytes past the 4GiB boundary are a stale duplicate of the first 4GiB of the partition. After flashing back, ext4 metadata in the higher block groups (GDT backups, inode tables) is inconsistent and the kernel mounts the filesystem only as `ro,noload`. Fixes: - fb_blk_read_raw_image(): widen size/offset to u64. - fastboot_bytes_expected/_send: u32 -> u64; printf format strings updated accordingly. - fetch(): replace dead `<= 0` check on unsigned with explicit `== 0` - fastboot_upload_remaining(): return u64; clamp at the USB callsite so transfer_size stays within EP_BUFFER_SIZE. Signed-off-by: zhiwei01.li Change-Id: I6600ff2dc973fa3aa0e574ef0df0ab5fc3a6fcd6 --- drivers/fastboot/fb_blk.c | 6 +++--- drivers/fastboot/fb_command.c | 21 +++++++++++---------- drivers/fastboot/fb_common.c | 2 +- drivers/usb/gadget/f_fastboot.c | 4 +++- include/fastboot.h | 4 ++-- 5 files changed, 20 insertions(+), 17 deletions(-) diff --git a/drivers/fastboot/fb_blk.c b/drivers/fastboot/fb_blk.c index 7556f8319fe..55a6bdde69c 100644 --- a/drivers/fastboot/fb_blk.c +++ b/drivers/fastboot/fb_blk.c @@ -463,14 +463,14 @@ static void fb_blk_write_raw_image(struct blk_desc *dev_desc, static int fb_blk_read_raw_image(struct blk_desc *dev_desc, struct disk_partition *info, const char *part_name, void *buffer, - u32 size, u32 offset, char *response) + u64 size, u64 offset, char *response) { lbaint_t blkcnt; lbaint_t blks; lbaint_t blks_offset; /* determine number of blocks to write */ - blkcnt = ((size + (info->blksz - 1)) & ~(info->blksz - 1)); + blkcnt = ((size + (info->blksz - 1)) & ~((u64)info->blksz - 1)); blkcnt = lldiv(blkcnt, info->blksz); if (blkcnt > info->size) { @@ -479,7 +479,7 @@ static int fb_blk_read_raw_image(struct blk_desc *dev_desc, struct disk_partitio return -1; } - blks_offset = ((offset + (info->blksz - 1)) & ~(info->blksz - 1)); + blks_offset = ((offset + (info->blksz - 1)) & ~((u64)info->blksz - 1)); blks_offset = lldiv(blks_offset, info->blksz); if (blkcnt + blks_offset > info->size) { diff --git a/drivers/fastboot/fb_command.c b/drivers/fastboot/fb_command.c index 292b70a15fc..83f84713501 100644 --- a/drivers/fastboot/fb_command.c +++ b/drivers/fastboot/fb_command.c @@ -33,14 +33,14 @@ static u32 image_size; static u32 fastboot_bytes_received; /** - * fastboot_bytes_expected - number of bytes expected in the current download + * fastboot_bytes_expected - number of bytes expected in the current download/upload */ -static u32 fastboot_bytes_expected; +static u64 fastboot_bytes_expected; /** - * fastboot_bytes_send - number of bytes received in the current upload + * fastboot_bytes_send - number of bytes sent in the current upload */ -static u32 fastboot_bytes_send; +static u64 fastboot_bytes_send; /** * fastboot_bytes_loaded - number of bytes for current fastboot loaded @@ -318,7 +318,7 @@ static void download(char *cmd_parameter, char *response) if (fastboot_bytes_expected > fastboot_buf_size) { fastboot_fail(cmd_parameter, response); } else { - printf("Starting download of %d bytes\n", + printf("Starting download of %llu bytes\n", fastboot_bytes_expected); fastboot_response("DATA", response, "%s", cmd_parameter); } @@ -390,7 +390,7 @@ void fastboot_download_complete(char *response) { /* Download complete. Respond with "OKAY" */ fastboot_okay(NULL, response); - printf("\ndownloading of %d bytes finished\n", fastboot_bytes_received); + printf("\ndownloading of %u bytes finished\n", fastboot_bytes_received); image_size = fastboot_bytes_received; env_set_hex("filesize", image_size); fastboot_bytes_expected = 0; @@ -408,7 +408,7 @@ void fastboot_upload_complete(char *response) { /* Upload complete. Respond with "OKAY" */ fastboot_okay(NULL, response); - printf("\nuploading 0x%x bytes completed\n", fastboot_bytes_send); + printf("\nuploading 0x%llx bytes completed\n", fastboot_bytes_send); fastboot_bytes_expected = 0; fastboot_bytes_send = 0; } @@ -551,7 +551,7 @@ static void fetch(char *cmd_parameter, char *response) offset_size = simple_strtoul(p, NULL, 16); fastboot_bytes_expected = offset_size; - if (fastboot_bytes_expected <= 0) { + if (fastboot_bytes_expected == 0) { fastboot_fail("Invalid image size", response); return; } @@ -584,7 +584,8 @@ static void fetch(char *cmd_parameter, char *response) } } - fastboot_response("DATA", response, "%08x", fastboot_bytes_expected); + fastboot_response("DATA", response, "%08llx", + fastboot_bytes_expected); fastboot_tx_write_more(response); fastboot_bytes_loaded = 0; @@ -600,7 +601,7 @@ static void fetch(char *cmd_parameter, char *response) * * Return: Number of bytes left in the current upload */ -u32 fastboot_upload_remaining(void) +u64 fastboot_upload_remaining(void) { return fastboot_bytes_expected - fastboot_bytes_send; } diff --git a/drivers/fastboot/fb_common.c b/drivers/fastboot/fb_common.c index a87db1179cb..9a63a2c73be 100644 --- a/drivers/fastboot/fb_common.c +++ b/drivers/fastboot/fb_common.c @@ -187,7 +187,7 @@ void fastboot_set_progress_callback(void (*progress)(const char *msg)) * @buf_addr: Pointer to download buffer, or NULL for default * @buf_size: Size of download buffer, or zero for default */ -void fastboot_init(void *buf_addr, u32 buf_size) +void fastboot_init(void *buf_addr, u64 buf_size) { fastboot_buf_addr = buf_addr ? buf_addr : (void *)CONFIG_FASTBOOT_BUF_ADDR; diff --git a/drivers/usb/gadget/f_fastboot.c b/drivers/usb/gadget/f_fastboot.c index c3adce41696..fb7151a0405 100644 --- a/drivers/usb/gadget/f_fastboot.c +++ b/drivers/usb/gadget/f_fastboot.c @@ -558,7 +558,9 @@ static void tx_handler_ul_image(struct usb_ep *ep, struct usb_request *req) static void *src_buf = NULL; // use static value, following loop still use it. char response[FASTBOOT_RESPONSE_LEN] = {0}; struct usb_request *in_req = fastboot_func->in_req; - unsigned int transfer_size = fastboot_upload_remaining(); + u64 remaining = fastboot_upload_remaining(); + unsigned int transfer_size = remaining > EP_BUFFER_SIZE ? + EP_BUFFER_SIZE : (unsigned int)remaining; void *buffer = in_req->buf; struct fetch_info *info = NULL; int ret; diff --git a/include/fastboot.h b/include/fastboot.h index 31015101750..093ac8363ec 100644 --- a/include/fastboot.h +++ b/include/fastboot.h @@ -170,7 +170,7 @@ void fastboot_set_progress_callback(void (*progress)(const char *msg)); * @buf_addr: Pointer to download buffer, or NULL for default * @buf_size: Size of download buffer, or zero for default */ -void fastboot_init(void *buf_addr, u32 buf_size); +void fastboot_init(void *buf_addr, u64 buf_size); /** * fastboot_boot() - Execute fastboot boot command @@ -206,7 +206,7 @@ u32 fastboot_download_remaining(void); * * Return: Number of bytes left in the current upload */ -u32 fastboot_upload_remaining(void); +u64 fastboot_upload_remaining(void); /** * fastboot_data_download() - Copy image data to fastboot_buf_addr. -- 2.25.1