* [PATCH 1/2] libfile: copy_fd: add size argument
2026-01-20 14:55 [PATCH 0/2] Android image support Sascha Hauer
@ 2026-01-20 14:55 ` Sascha Hauer
2026-01-20 14:55 ` [PATCH 2/2] bootm: add generic android image handler Sascha Hauer
1 sibling, 0 replies; 6+ messages in thread
From: Sascha Hauer @ 2026-01-20 14:55 UTC (permalink / raw)
To: BAREBOX
Add a size argument to copy_fd() to allow copying a specified number of
bytes. While at it add some function documentation.
Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
common/firmware.c | 2 +-
include/libfile.h | 2 +-
lib/libfile.c | 37 +++++++++++++++++++++++++++++++++----
3 files changed, 35 insertions(+), 6 deletions(-)
diff --git a/common/firmware.c b/common/firmware.c
index 264fc9d66d..cdc55467cd 100644
--- a/common/firmware.c
+++ b/common/firmware.c
@@ -292,7 +292,7 @@ int firmwaremgr_load_file(struct firmware_mgr *mgr, const char *firmware)
ret = uncompress_fd_to_fd(firmwarefd, devicefd,
uncompress_err_stdout);
else
- ret = copy_fd(firmwarefd, devicefd);
+ ret = copy_fd(firmwarefd, devicefd, 0);
out:
free(dst);
diff --git a/include/libfile.h b/include/libfile.h
index dc292e422e..370f8b9725 100644
--- a/include/libfile.h
+++ b/include/libfile.h
@@ -11,7 +11,7 @@ int pread_full(int fd, void *buf, size_t size, loff_t offset);
int pwrite_full(int fd, const void *buf, size_t size, loff_t offset);
int write_full(int fd, const void *buf, size_t size);
int read_full(int fd, void *buf, size_t size);
-int copy_fd(int in, int out);
+int copy_fd(int in, int out, size_t size);
ssize_t read_file_into_buf(const char *filename, void *buf, size_t size);
diff --git a/lib/libfile.c b/lib/libfile.c
index 01189773b7..32b0c27eba 100644
--- a/lib/libfile.c
+++ b/lib/libfile.c
@@ -124,25 +124,54 @@ int read_full(int fd, void *buf, size_t size)
}
EXPORT_SYMBOL(read_full);
-int copy_fd(int in, int out)
+/*
+ * copy_fd - copy one file descriptor to another
+ * @in: input file descriptor
+ * @out: output file descriptor
+ * @size: size to copy
+ *
+ * This copies at @size bytes from @in file descriptor to @out
+ * file descriptor. If @size is zero then all data is copied until
+ * EOF is reached.
+ *
+ * @return: 0 for success and negatibe error code otherwise. If @size
+ * is non zero and not all data could be read from @in then -ENODATA
+ * is returned.
+ */
+int copy_fd(int in, int out, size_t size)
{
- int bs = 4096, ret;
+ size_t copied = 0, bs = 4096;
void *buf = malloc(bs);
+ int ret;
if (!buf)
return -ENOMEM;
while (1) {
- ret = read(in, buf, bs);
+ size_t now = min(bs, size - copied);
+
+ if (!now) {
+ ret = 0;
+ break;
+ }
+
+ ret = read(in, buf, now);
if (ret <= 0)
break;
+ now = ret;
+
ret = write_full(out, buf, ret);
if (ret < 0)
break;
+
+ copied += now;
}
- free(buf);
+ free(buf);
+
+ if (size && copied < size)
+ ret = -ENODATA;
return ret;
}
--
2.47.3
^ permalink raw reply [flat|nested] 6+ messages in thread* [PATCH 2/2] bootm: add generic android image handler
2026-01-20 14:55 [PATCH 0/2] Android image support Sascha Hauer
2026-01-20 14:55 ` [PATCH 1/2] libfile: copy_fd: add size argument Sascha Hauer
@ 2026-01-20 14:55 ` Sascha Hauer
2026-01-20 15:04 ` Ahmad Fatoum
1 sibling, 1 reply; 6+ messages in thread
From: Sascha Hauer @ 2026-01-20 14:55 UTC (permalink / raw)
To: BAREBOX
An Android image handler is particularly useful for use with fastboot.
The fastboot protocol supports a "boot" command which can be used to
boot a kernel via fastboot. The fastboot host tool encapsulates the
Kernel binary in a Android image format which is then transferred.
This patch brings us an image handler which extracts the Kernel binary
and optionally an initrd and passes this on to bootm.
We previously already had an Android image handler, but this is very
limited and replaced with this patch. The existing handler was only
supported on ARM32 and only zImages. It hasn't seen any active changes
for more than 10 years.
Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
arch/arm/lib32/bootm.c | 174 -------------------------------------------
common/Makefile | 1 +
common/bootm-android-image.c | 154 ++++++++++++++++++++++++++++++++++++++
3 files changed, 155 insertions(+), 174 deletions(-)
diff --git a/arch/arm/lib32/bootm.c b/arch/arm/lib32/bootm.c
index dca4fec020..2ae132d435 100644
--- a/arch/arm/lib32/bootm.c
+++ b/arch/arm/lib32/bootm.c
@@ -567,180 +567,6 @@ static struct image_handler socfpga_xload_handler = {
.filetype = filetype_socfpga_xload,
};
-#include <aimage.h>
-
-static int aimage_load_resource(int fd, struct resource *r, void* buf, int ps)
-{
- int ret;
- void *image = (void *)r->start;
- unsigned to_read = ps - resource_size(r) % ps;
-
- ret = read_full(fd, image, resource_size(r));
- if (ret < 0)
- return ret;
-
- ret = read_full(fd, buf, to_read);
- if (ret < 0)
- printf("could not read dummy %u\n", to_read);
-
- return ret;
-}
-
-static int do_bootm_aimage(struct image_data *data)
-{
- struct resource *snd_stage_res;
- int fd, ret;
- struct android_header __header, *header;
- void *buf;
- int to_read;
- struct android_header_comp *cmp;
- unsigned long mem_free;
- unsigned long mem_start, mem_size;
-
- ret = sdram_start_and_size(&mem_start, &mem_size);
- if (ret)
- return ret;
-
- fd = open(data->os_file, O_RDONLY);
- if (fd < 0) {
- perror("open");
- return 1;
- }
-
- header = &__header;
- ret = read(fd, header, sizeof(*header));
- if (ret < sizeof(*header)) {
- printf("could not read %s\n", data->os_file);
- goto err_out;
- }
-
- printf("Android Image for '%s'\n", header->name);
-
- /*
- * As on tftp we do not support lseek and we will just have to seek
- * for the size of a page - 1 max just buffer instead to read to dummy
- * data
- */
- buf = xmalloc(header->page_size);
-
- to_read = header->page_size - sizeof(*header);
- ret = read_full(fd, buf, to_read);
- if (ret < 0) {
- printf("could not read dummy %d from %s\n", to_read, data->os_file);
- goto err_out;
- }
-
- cmp = &header->kernel;
- data->os_res = request_sdram_region("akernel", cmp->load_addr, cmp->size,
- MEMTYPE_LOADER_CODE, MEMATTRS_RWX);
- if (!data->os_res) {
- pr_err("Cannot request region 0x%08x - 0x%08x, using default load address\n",
- cmp->load_addr, cmp->size);
-
- data->os_address = mem_start + PAGE_ALIGN(cmp->size * 4);
- data->os_res = request_sdram_region("akernel", data->os_address, cmp->size,
- MEMTYPE_LOADER_CODE, MEMATTRS_RWX);
- if (!data->os_res) {
- pr_err("Cannot request region 0x%08x - 0x%08x\n",
- cmp->load_addr, cmp->size);
- ret = -ENOMEM;
- goto err_out;
- }
- }
-
- ret = aimage_load_resource(fd, data->os_res, buf, header->page_size);
- if (ret < 0) {
- perror("could not read kernel");
- goto err_out;
- }
-
- /*
- * fastboot always expect a ramdisk
- * in barebox we can be less restrictive
- */
- cmp = &header->ramdisk;
- if (cmp->size) {
- data->initrd_res = request_sdram_region("ainitrd", cmp->load_addr, cmp->size,
- MEMTYPE_LOADER_DATA, MEMATTRS_RW);
- if (!data->initrd_res) {
- ret = -ENOMEM;
- goto err_out;
- }
-
- ret = aimage_load_resource(fd, data->initrd_res, buf, header->page_size);
- if (ret < 0) {
- perror("could not read initrd");
- goto err_out;
- }
- }
-
- if (!getenv("aimage_noverwrite_bootargs"))
- linux_bootargs_overwrite(header->cmdline);
-
- if (!getenv("aimage_noverwrite_tags"))
- armlinux_set_bootparams((void *)(unsigned long)header->tags_addr);
-
- cmp = &header->second_stage;
- if (cmp->size) {
- void (*second)(void);
-
- snd_stage_res = request_sdram_region("asecond", cmp->load_addr, cmp->size,
- MEMTYPE_LOADER_CODE, MEMATTRS_RWX);
- if (!snd_stage_res) {
- ret = -ENOMEM;
- goto err_out;
- }
-
- ret = aimage_load_resource(fd, snd_stage_res, buf, header->page_size);
- if (ret < 0) {
- perror("could not read initrd");
- goto err_out;
- }
-
- second = (void*)snd_stage_res->start;
- shutdown_barebox();
-
- second();
-
- restart_machine(0);
- }
-
- close(fd);
-
- /*
- * Put devicetree right after initrd if present or after the kernel
- * if not.
- */
- if (data->initrd_res)
- mem_free = PAGE_ALIGN(data->initrd_res->end);
- else
- mem_free = PAGE_ALIGN(data->os_res->end + SZ_1M);
-
- return __do_bootm_linux(data, mem_free, 0, NULL);
-
-err_out:
- linux_bootargs_overwrite(NULL);
- close(fd);
-
- return ret;
-}
-
-static struct image_handler aimage_handler = {
- .name = "ARM Android Image",
- .bootm = do_bootm_aimage,
- .filetype = filetype_aimage,
-};
-
-#ifdef CONFIG_BOOTM_AIMAGE
-BAREBOX_MAGICVAR(aimage_noverwrite_bootargs, "Disable overwrite of the bootargs with the one present in aimage");
-BAREBOX_MAGICVAR(aimage_noverwrite_tags, "Disable overwrite of the tags addr with the one present in aimage");
-#endif
-
-static struct binfmt_hook binfmt_aimage_hook = {
- .type = filetype_aimage,
- .exec = "bootm",
-};
-
static struct binfmt_hook binfmt_arm_zimage_hook = {
.type = filetype_arm_zimage,
.exec = "bootm",
diff --git a/common/Makefile b/common/Makefile
index 36dee5f7a9..54120d3d8a 100644
--- a/common/Makefile
+++ b/common/Makefile
@@ -28,6 +28,7 @@ obj-$(CONFIG_BINFMT) += binfmt.o
obj-$(CONFIG_BLOCK) += block.o
obj-$(CONFIG_BLSPEC) += blspec.o
obj-$(CONFIG_BOOTM) += bootm.o booti.o
+obj-$(CONFIG_BOOTM_AIMAGE) += bootm-android-image.o
obj-$(CONFIG_CMD_LOADS) += s_record.o
obj-$(CONFIG_MEMTEST) += memtest.o
obj-$(CONFIG_COMMAND_SUPPORT) += command.o
diff --git a/common/bootm-android-image.c b/common/bootm-android-image.c
new file mode 100644
index 0000000000..cb86123659
--- /dev/null
+++ b/common/bootm-android-image.c
@@ -0,0 +1,154 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#define pr_fmt(fmt) "android-image: " fmt
+
+#include <bootm.h>
+#include <aimage.h>
+#include <init.h>
+#include <fcntl.h>
+#include <libfile.h>
+#include <linux/fs.h>
+#include <linux/sizes.h>
+#include <linux/align.h>
+#include <unistd.h>
+#include <filetype.h>
+
+static char *aimage_copy_component(int from, size_t ofs, size_t size)
+{
+ char *path;
+ int to, ret;
+ loff_t pos;
+
+ path = make_temp("aimage");
+ if (!path) {
+ ret = -ENOMEM;
+ goto err;
+ }
+
+ pos = lseek(from, ofs, SEEK_SET);
+ if (pos < 0) {
+ ret = -errno;
+ goto err;
+ }
+
+ to = open(path, O_CREAT | O_WRONLY);
+ if (to < 0) {
+ ret = to;
+ goto err;
+ }
+
+ ret = copy_fd(from, to, size);
+
+ close(to);
+
+ if (!ret)
+ return path;
+err:
+ free(path);
+
+ return ERR_PTR(ret);
+}
+
+static int do_bootm_aimage(struct image_data *img_data)
+{
+ struct bootm_data bootm_data = {
+ .oftree_file = img_data->oftree_file,
+ .initrd_file = img_data->initrd_file,
+ .tee_file = img_data->tee_file,
+ .verbose = img_data->verbose,
+ .verify = img_data->verify,
+ .force = img_data->force,
+ .dryrun = img_data->dryrun,
+ .initrd_address = img_data->initrd_address,
+ .os_address = img_data->os_address,
+ .os_entry = img_data->os_entry,
+ };
+ struct android_header *hdr;
+ int fd, ret;
+ char *kernel = NULL, *initrd = NULL;
+ size_t ofs;
+
+ hdr = xmalloc(sizeof(*hdr));
+
+ fd = open(img_data->os_file, O_RDONLY);
+ if (fd < 0) {
+ ret = fd;
+ goto err;
+ }
+
+ ret = read_full(fd, hdr, sizeof(*hdr));
+ if (ret < 0)
+ goto err_close;
+
+ if (ret < sizeof(*hdr)) {
+ ret = -EINVAL;
+ goto err_close;
+ }
+
+ if (file_detect_type(hdr, sizeof(*hdr)) != filetype_aimage) {
+ pr_err("Image is not an Android image\n");
+ ret = -EINVAL;
+ goto err;
+ }
+
+ if (hdr->page_size < sizeof(*hdr) || hdr->page_size > SZ_64K) {
+ pr_err("Invalid page_size 0x%08x\n", hdr->page_size);
+ ret = -EINVAL;
+ goto err_close;
+ }
+
+ ofs = hdr->page_size;
+ if (hdr->kernel.size) {
+ kernel = aimage_copy_component(fd, ofs, hdr->kernel.size);
+ if (IS_ERR(kernel)) {
+ kernel = NULL;
+ ret = PTR_ERR(kernel);
+ goto err_close;
+ }
+ }
+
+ ofs += ALIGN(hdr->kernel.size, hdr->page_size);
+
+ if (hdr->ramdisk.size) {
+ initrd = aimage_copy_component(fd, ofs, hdr->ramdisk.size);
+ if (IS_ERR(initrd)) {
+ initrd = NULL;
+ ret = PTR_ERR(initrd);
+ goto err_close;
+ }
+ }
+
+ if (kernel)
+ bootm_data.os_file = kernel;
+
+ if (initrd)
+ bootm_data.initrd_file = initrd;
+
+ close(fd);
+
+ ret = bootm_boot(&bootm_data);
+
+err_close:
+ close(fd);
+
+ if (kernel)
+ unlink(kernel);
+ if (initrd)
+ unlink(initrd);
+err:
+ free(hdr);
+
+ return ret;
+}
+
+static struct image_handler aimage_bootm_handler = {
+ .name = "Android boot image",
+ .bootm = do_bootm_aimage,
+ .filetype = filetype_aimage,
+};
+
+static int bootm_aimage_register(void)
+{
+ return register_image_handler(&aimage_bootm_handler);
+}
+late_initcall(bootm_aimage_register);
--
2.47.3
^ permalink raw reply [flat|nested] 6+ messages in thread