aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTom Rini <trini@konsulko.com>2023-12-15 09:41:44 -0500
committerTom Rini <trini@konsulko.com>2023-12-15 09:41:44 -0500
commitd7a2c7ff7528653612dfeed175a127b1e691e855 (patch)
tree84dd025a4aaf85140c77d87cfb57cb8915c858f2
parentfa3f19aa56c519d6345cc774187b7a8fdc053d71 (diff)
parent69544c4fd8b1e77e00403e9a6cba7e2d7bb3ff68 (diff)
downloadu-boot-d7a2c7ff7528653612dfeed175a127b1e691e855.zip
u-boot-d7a2c7ff7528653612dfeed175a127b1e691e855.tar.gz
u-boot-d7a2c7ff7528653612dfeed175a127b1e691e855.tar.bz2
Merge patch series "bootm: Handle compressed arm64 images with bootm"
To quote the author: This little series corrects a problem I noticed with arm64 images, where the kernel is not recognised if compression is used: U-Boot> tftp image.fit Using ethernet@7d580000 device TFTP from server 192.168.4.7; our IP address is 192.168.4.147 Filename 'image.fit'. Load address: 0x1000000 Loading: ################################################## 23 MiB 20.5 MiB/s done Bytes transferred = 24118272 (1700400 hex) U-Boot> bootm ## Loading kernel from FIT Image at 01000000 ... Using 'conf-768' configuration Trying 'kernel' kernel subimage Description: Linux Type: Kernel Image (no loading done) Compression: gzip compressed Data Start: 0x01000120 Data Size: 13662338 Bytes = 13 MiB Verifying Hash Integrity ... OK Bad Linux ARM64 Image magic! With this series: U-Boot> tftp 20000000 image.fit Using ethernet@7d580000 device TFTP from server 192.168.4.7; our IP address is 192.168.4.147 Filename 'image.fit'. Load address: 0x20000000 Loading: ################################################## 23.5 MiB 20.8 MiB/s done Bytes transferred = 24642560 (1780400 hex) U-Boot> bootm 0x20000000 ## Loading kernel from FIT Image at 20000000 ... Using 'conf-768' configuration Trying 'kernel' kernel subimage Description: Linux Type: Kernel Image (no loading done) Compression: zstd compressed Data Start: 0x20000120 Data Size: 14333475 Bytes = 13.7 MiB Verifying Hash Integrity ... OK Using kernel load address 80000 ## Loading fdt from FIT Image at 20000000 ... Using 'conf-768' configuration Trying 'fdt-768' fdt subimage Description: Raspberry Pi 4 Model B Type: Flat Device Tree Compression: zstd compressed Data Start: 0x215f820c Data Size: 9137 Bytes = 8.9 KiB Architecture: AArch64 Verifying Hash Integrity ... OK Uncompressing Flat Device Tree to 3aff3010 Booting using the fdt blob at 0x3aff3010 Working FDT set to 3aff3010 Uncompressing Kernel Image (no loading done) to 80000 Moving Image from 0x80000 to 0x200000, end=2b00000 Using Device Tree in place at 000000003aff3010, end 000000003afff4c4 Working FDT set to 3aff3010 Starting kernel ... [ 0.000000] Booting Linux on physical CPU 0x0000000000 [0x410fd083] The problem is that the arm64 magic is checked before the image is decompressed. However this is only part of it. The kernel_noload image type doesn't work with compression, since the kernel is not loaded. So this series deals with that by using an lmb-allocated buffer for the uncompressed kernel. Another issue is that the arm64 handling is done too early, before the image is loaded. This series moves it to after loading, so that compression can be handled. A patch is included to show the kernel load-address, so it is easy to see what is going on. One annoying feature of arm64 is that the image is often copied to another address. It might be possible for U-Boot to figure that out earlier and decompress it to the right place, but perhaps not. With all of this it should be possible to boot a compressed kernel on any of the 990 arm64 boards supported by Linux, although I have only tested two.
-rw-r--r--boot/bootm.c63
-rw-r--r--boot/image.c13
-rw-r--r--include/image.h2
3 files changed, 55 insertions, 23 deletions
diff --git a/boot/bootm.c b/boot/bootm.c
index a0d17be..301cfde 100644
--- a/boot/bootm.c
+++ b/boot/bootm.c
@@ -443,24 +443,8 @@ static int bootm_find_os(const char *cmd_name, const char *addr_fit)
}
if (images.os.type == IH_TYPE_KERNEL_NOLOAD) {
- if (IS_ENABLED(CONFIG_CMD_BOOTI) &&
- images.os.arch == IH_ARCH_ARM64 &&
- images.os.os == IH_OS_LINUX) {
- ulong image_addr;
- ulong image_size;
-
- ret = booti_setup(images.os.image_start, &image_addr,
- &image_size, true);
- if (ret != 0)
- return 1;
-
- images.os.type = IH_TYPE_KERNEL;
- images.os.load = image_addr;
- images.ep = image_addr;
- } else {
- images.os.load = images.os.image_start;
- images.ep += images.os.image_start;
- }
+ images.os.load = images.os.image_start;
+ images.ep += images.os.image_start;
}
images.os.start = map_to_sysmem(os_hdr);
@@ -645,6 +629,24 @@ static int bootm_load_os(struct bootm_headers *images, int boot_progress)
void *load_buf, *image_buf;
int err;
+ /*
+ * For a "noload" compressed kernel we need to allocate a buffer large
+ * enough to decompress in to and use that as the load address now.
+ * Assume that the kernel compression is at most a factor of 4 since
+ * zstd almost achieves that.
+ * Use an alignment of 2MB since this might help arm64
+ */
+ if (os.type == IH_TYPE_KERNEL_NOLOAD && os.comp != IH_COMP_NONE) {
+ ulong req_size = ALIGN(image_len * 4, SZ_1M);
+
+ load = lmb_alloc(&images->lmb, req_size, SZ_2M);
+ if (!load)
+ return 1;
+ os.load = load;
+ debug("Allocated %lx bytes at %lx for kernel (size %lx) decompression\n",
+ req_size, load, image_len);
+ }
+
load_buf = map_sysmem(load, 0);
image_buf = map_sysmem(os.image_start, image_len);
err = image_decomp(os.comp, load, os.image_start, os.type,
@@ -685,6 +687,31 @@ static int bootm_load_os(struct bootm_headers *images, int boot_progress)
}
}
+ if (IS_ENABLED(CONFIG_CMD_BOOTI) && images->os.arch == IH_ARCH_ARM64 &&
+ images->os.os == IH_OS_LINUX) {
+ ulong relocated_addr;
+ ulong image_size;
+ int ret;
+
+ ret = booti_setup(load, &relocated_addr, &image_size, false);
+ if (ret) {
+ printf("Failed to prep arm64 kernel (err=%d)\n", ret);
+ return BOOTM_ERR_RESET;
+ }
+
+ /* Handle BOOTM_STATE_LOADOS */
+ if (relocated_addr != load) {
+ printf("Moving Image from 0x%lx to 0x%lx, end=%lx\n",
+ load, relocated_addr,
+ relocated_addr + image_size);
+ memmove((void *)relocated_addr, load_buf, image_size);
+ }
+
+ images->ep = relocated_addr;
+ images->os.start = relocated_addr;
+ images->os.end = relocated_addr + image_size;
+ }
+
lmb_reserve(&images->lmb, images->os.load, (load_end -
images->os.load));
return 0;
diff --git a/boot/image.c b/boot/image.c
index 88b67bc..675b5dd 100644
--- a/boot/image.c
+++ b/boot/image.c
@@ -415,15 +415,20 @@ void image_print_contents(const void *ptr)
* @type: OS type (IH_OS_...)
* @comp_type: Compression type being used (IH_COMP_...)
* @is_xip: true if the load address matches the image start
+ * @load: Load address for printing
*/
-static void print_decomp_msg(int comp_type, int type, bool is_xip)
+static void print_decomp_msg(int comp_type, int type, bool is_xip,
+ ulong load)
{
const char *name = genimg_get_type_name(type);
+ /* Shows "Loading Kernel Image" for example */
if (comp_type == IH_COMP_NONE)
- printf(" %s %s\n", is_xip ? "XIP" : "Loading", name);
+ printf(" %s %s", is_xip ? "XIP" : "Loading", name);
else
- printf(" Uncompressing %s\n", name);
+ printf(" Uncompressing %s", name);
+
+ printf(" to %lx\n", load);
}
int image_decomp_type(const unsigned char *buf, ulong len)
@@ -448,7 +453,7 @@ int image_decomp(int comp, ulong load, ulong image_start, int type,
int ret = -ENOSYS;
*load_end = load;
- print_decomp_msg(comp, type, load == image_start);
+ print_decomp_msg(comp, type, load == image_start, load);
/*
* Load the image to the right place, decompressing if needed. After
diff --git a/include/image.h b/include/image.h
index 9f43518..432ec92 100644
--- a/include/image.h
+++ b/include/image.h
@@ -1011,7 +1011,7 @@ int image_decomp_type(const unsigned char *buf, ulong len);
* @load: Destination load address in U-Boot memory
* @image_start Image start address (where we are decompressing from)
* @type: OS type (IH_OS_...)
- * @load_bug: Place to decompress to
+ * @load_buf: Place to decompress to
* @image_buf: Address to decompress from
* @image_len: Number of bytes in @image_buf to decompress
* @unc_len: Available space for decompression