hw/core/loader.c | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-)
U-Boot is able to decompress Zstandard images since almost
6 years (u-boot commit 8509f22a).
Signed-off-by: Philippe Mathieu-Daudé <philmd@linaro.org>
---
Based-on: <20251011081553.4065883-1-daan.j.demeyer@gmail.com>
---
hw/core/loader.c | 22 ++++++++++++++++++----
1 file changed, 18 insertions(+), 4 deletions(-)
diff --git a/hw/core/loader.c b/hw/core/loader.c
index e5904cdafa1..97fa8248ce7 100644
--- a/hw/core/loader.c
+++ b/hw/core/loader.c
@@ -635,7 +635,7 @@ static ssize_t load_uboot_image(const char *filename, hwaddr *ep,
uboot_image_header_t *hdr = &h;
uint8_t *data = NULL;
int ret = -1;
- int do_uncompress = 0;
+ bool do_uncompress = false;
fd = open(filename, O_RDONLY | O_BINARY);
if (fd < 0)
@@ -685,7 +685,8 @@ static ssize_t load_uboot_image(const char *filename, hwaddr *ep,
case IH_COMP_NONE:
break;
case IH_COMP_GZIP:
- do_uncompress = 1;
+ case IH_COMP_ZSTD:
+ do_uncompress = true;
break;
default:
fprintf(stderr,
@@ -747,10 +748,23 @@ static ssize_t load_uboot_image(const char *filename, hwaddr *ep,
max_bytes = UBOOT_MAX_GUNZIP_BYTES;
data = g_malloc(max_bytes);
- bytes = gunzip(data, max_bytes, compressed_data, hdr->ih_size);
+ switch (hdr->ih_comp) {
+ case IH_COMP_GZIP:
+ bytes = gunzip(data, max_bytes, compressed_data, hdr->ih_size);
+ break;
+#ifdef CONFIG_ZSTD
+ case IH_COMP_ZSTD: {
+ size_t ret = ZSTD_decompress(data, max_bytes,
+ compressed_data, hdr->ih_size);
+ bytes = ZSTD_isError(ret) ? -1 : (ssize_t) ret;
+ } break;
+#endif
+ default:
+ g_assert_not_reached();
+ }
g_free(compressed_data);
if (bytes < 0) {
- fprintf(stderr, "Unable to decompress gzipped image!\n");
+ fprintf(stderr, "Unable to decompress image!\n");
goto out;
}
hdr->ih_size = bytes;
--
2.51.0
On Mon, 24 Nov 2025 at 12:22, Philippe Mathieu-Daudé <philmd@linaro.org> wrote:
>
> U-Boot is able to decompress Zstandard images since almost
> 6 years (u-boot commit 8509f22a).
>
> Signed-off-by: Philippe Mathieu-Daudé <philmd@linaro.org>
> ---
> Based-on: <20251011081553.4065883-1-daan.j.demeyer@gmail.com>
> ---
> hw/core/loader.c | 22 ++++++++++++++++++----
> 1 file changed, 18 insertions(+), 4 deletions(-)
>
> diff --git a/hw/core/loader.c b/hw/core/loader.c
> index e5904cdafa1..97fa8248ce7 100644
> --- a/hw/core/loader.c
> +++ b/hw/core/loader.c
> @@ -635,7 +635,7 @@ static ssize_t load_uboot_image(const char *filename, hwaddr *ep,
> uboot_image_header_t *hdr = &h;
> uint8_t *data = NULL;
> int ret = -1;
> - int do_uncompress = 0;
> + bool do_uncompress = false;
>
> fd = open(filename, O_RDONLY | O_BINARY);
> if (fd < 0)
> @@ -685,7 +685,8 @@ static ssize_t load_uboot_image(const char *filename, hwaddr *ep,
> case IH_COMP_NONE:
> break;
> case IH_COMP_GZIP:
> - do_uncompress = 1;
> + case IH_COMP_ZSTD:
> + do_uncompress = true;
> break;
Here we set do_uncompress whether QEMU was built with
CONFIG_ZSTD or not...
> default:
> fprintf(stderr,
> @@ -747,10 +748,23 @@ static ssize_t load_uboot_image(const char *filename, hwaddr *ep,
> max_bytes = UBOOT_MAX_GUNZIP_BYTES;
> data = g_malloc(max_bytes);
>
> - bytes = gunzip(data, max_bytes, compressed_data, hdr->ih_size);
> + switch (hdr->ih_comp) {
> + case IH_COMP_GZIP:
> + bytes = gunzip(data, max_bytes, compressed_data, hdr->ih_size);
> + break;
> +#ifdef CONFIG_ZSTD
> + case IH_COMP_ZSTD: {
> + size_t ret = ZSTD_decompress(data, max_bytes,
> + compressed_data, hdr->ih_size);
> + bytes = ZSTD_isError(ret) ? -1 : (ssize_t) ret;
> + } break;
> +#endif
...so here if the user passes a ZSTD image to a QEMU
built without CONFIG_ZSTD I think we fall into the default
case and assert.
I think the neatest fix for this would be to have the
switch (hdr->ih_comp) that sets do_uncompress to have
an ifdef for CONFIG_ZSTD so that we can tell the user
"couldn't load this image because QEMU was compiled without
zstd support".
PS: do we need to cast ret to a ssize_t ? bytes is
already a ssize_t variable.
thanks
-- PMM
On 24/11/25 13:22, Philippe Mathieu-Daudé wrote:
> U-Boot is able to decompress Zstandard images since almost
> 6 years (u-boot commit 8509f22a).
>
> Signed-off-by: Philippe Mathieu-Daudé <philmd@linaro.org>
> ---
> Based-on: <20251011081553.4065883-1-daan.j.demeyer@gmail.com>
Same patch applies on Daan's v4:
Based-on: <20251124123521.1058183-1-daan.j.demeyer@gmail.com>
> ---
> hw/core/loader.c | 22 ++++++++++++++++++----
> 1 file changed, 18 insertions(+), 4 deletions(-)
>
> diff --git a/hw/core/loader.c b/hw/core/loader.c
> index e5904cdafa1..97fa8248ce7 100644
> --- a/hw/core/loader.c
> +++ b/hw/core/loader.c
> @@ -635,7 +635,7 @@ static ssize_t load_uboot_image(const char *filename, hwaddr *ep,
> uboot_image_header_t *hdr = &h;
> uint8_t *data = NULL;
> int ret = -1;
> - int do_uncompress = 0;
> + bool do_uncompress = false;
>
> fd = open(filename, O_RDONLY | O_BINARY);
> if (fd < 0)
> @@ -685,7 +685,8 @@ static ssize_t load_uboot_image(const char *filename, hwaddr *ep,
> case IH_COMP_NONE:
> break;
> case IH_COMP_GZIP:
> - do_uncompress = 1;
> + case IH_COMP_ZSTD:
> + do_uncompress = true;
> break;
> default:
> fprintf(stderr,
> @@ -747,10 +748,23 @@ static ssize_t load_uboot_image(const char *filename, hwaddr *ep,
> max_bytes = UBOOT_MAX_GUNZIP_BYTES;
> data = g_malloc(max_bytes);
>
> - bytes = gunzip(data, max_bytes, compressed_data, hdr->ih_size);
> + switch (hdr->ih_comp) {
> + case IH_COMP_GZIP:
> + bytes = gunzip(data, max_bytes, compressed_data, hdr->ih_size);
> + break;
> +#ifdef CONFIG_ZSTD
> + case IH_COMP_ZSTD: {
> + size_t ret = ZSTD_decompress(data, max_bytes,
> + compressed_data, hdr->ih_size);
> + bytes = ZSTD_isError(ret) ? -1 : (ssize_t) ret;
> + } break;
> +#endif
> + default:
> + g_assert_not_reached();
> + }
> g_free(compressed_data);
> if (bytes < 0) {
> - fprintf(stderr, "Unable to decompress gzipped image!\n");
> + fprintf(stderr, "Unable to decompress image!\n");
> goto out;
> }
> hdr->ih_size = bytes;
© 2016 - 2026 Red Hat, Inc.