
From: Simon Glass <sjg@chromium.org> This function is very simple at present, only supporting a fixed buffer of a fixed size. For cases where the address is not provided, we may still want to set a limit on the size. Support lmb reservation of an existing buffer as using lmb to reserved a new buffer. Use the provided size information to select a suitable size for the decompression buffer. Signed-off-by: Simon Glass <sjg@chromium.org> --- boot/bootm.c | 63 ++++++++++++++++++++++++++++++++++------------------ 1 file changed, 41 insertions(+), 22 deletions(-) diff --git a/boot/bootm.c b/boot/bootm.c index 37ddebd66c3..715b78da336 100644 --- a/boot/bootm.c +++ b/boot/bootm.c @@ -316,25 +316,48 @@ static int bootm_pre_load(const char *addr_str) /** * resolve_os_comp_buf() - Figure out where to decompress OS to * + * 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 + * * @bmi: Bootm info * Return: 0 if OK, -ENOTSUPP if the required env variables are not set, -EXDEV * if the memory region is already reserved, -EINVAL if OS size is zero - * (bmi->os_size) + * (bmi->os_size), -E2BIG if OS might decompress to >1G, -ENOSPC if lmb + * allocation failed */ static int resolve_os_comp_buf(struct bootm_info *bmi) { - if (!bmi->os_size) { - printf("Kernel size is zero\n"); - return -EINVAL; - } - images.os.load = bmi->kern_comp_addr; - images.os.image_len = bmi->kern_comp_size; - if (!images.os.load || !images.os.image_len) { - puts("kernel_comp_addr_r or kernel_comp_size is not provided!\n"); - return -ENOTSUPP; + if (bmi->kern_comp_addr) { + if (lmb_reserve(bmi->kern_comp_addr, bmi->kern_comp_size) < 0) + return -EXDEV; + } else { + phys_addr_t addr; + + if (!bmi->kern_comp_size) { + if (!bmi->os_size) { + printf("Kernel size is zero\n"); + return -EINVAL; + } + + if (bmi->os_size > SZ_1G / 4) { + printf("Kernel size might exceed 1G limit\n"); + return -E2BIG; + } + + bmi->kern_comp_size = bmi->os_size * 4; + } + + addr = lmb_alloc(bmi->kern_comp_size, SZ_2M); + if (!addr) { + printf("Cannot reserve space for kernel decompression (size %lx)\n", + bmi->kern_comp_size); + printf("- provide kernel_comp_addr_r and kernel_comp_size?\n"); + return -ENOSPC; + } + + bmi->kern_comp_addr = addr; } - if (lmb_reserve(images.os.load, images.os.image_len) < 0) - return -EXDEV; return 0; } @@ -756,20 +779,16 @@ static int bootm_load_os(struct bootm_info *bmi, int boot_progress) /* * 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); + if (os.type == IH_TYPE_KERNEL_NOLOAD && os.comp) { + int ret; + + ret = resolve_os_comp_buf(bmi); + if (ret) + return log_msg_ret("fbo", ret); - load = lmb_alloc(req_size, SZ_2M); - if (!load) - return 1; os.load = load; images->ep = load; - debug("Allocated %lx bytes at %lx for kernel (size %lx) decompression\n", - req_size, load, image_len); } log_debug("load_os load %lx image_start %lx image_len %lx\n", load, image_start, image_len); -- 2.43.0