mirror of https://github.com/wolfSSL/wolfBoot.git
fit: gzip-compressed kernel + ramdisk (initramfs) support
Wires the new wolfBoot_gunzip inflater into the FIT image-loading path
and adds initramfs (ramdisk) extraction with DTB /chosen fixup so a
single signed FIT can carry kernel, DTB, and rootfs.
GZIP path
---------
* fit_load_image_ex(out_max) added; fit_load_image kept as a wrapper.
* When a subimage carries compression="gzip", inflate straight to the
FIT-declared load address, then verify the FIT hash-1 subnode
(sha256 / sha384 if available) for defense in depth on top of the
outer wolfBoot signature. The compression property is now read
unconditionally so a build without WOLFBOOT_GZIP can warn and fail
closed instead of silently memcpy-ing compressed bytes as if they
were raw.
* fit_verify_hash propagates wc_InitSha256 / wc_Sha256Update /
wc_Sha256Final return codes (and the SHA-384 equivalents) - any
non-zero return is treated as a verification failure so a misbehaving
backend cannot silently degrade to a no-op.
* GZIP=1 is the new default in the FIT-using example configs (zynqmp,
zynqmp_sdcard, polarfire_mpfs250, polarfire_mpfs250_qspi,
versal_vmk180, versal_vmk180_sdcard); set GZIP=0 to opt out.
Ramdisk path
------------
* fit_find_images() gains a ramdisk out-arg and fdt_fixup_initrd()
writes /chosen/linux,initrd-{start,end} as 64-bit big-endian cells.
* update_disk.c and update_ram.c load the FIT ramdisk node (under
WOLFBOOT_FIT_RAMDISK) and patch the loaded DTB. Compressed (gzip)
ramdisks reuse the same fit_load_image_ex() decompress path.
* RAMDISK=1 build switch defines WOLFBOOT_FIT_RAMDISK;
WOLFBOOT_LOAD_RAMDISK_ADDRESS is plumbed through tools/config.mk ->
Makefile sed -> include/target.h.in. Defaults to 0; when 0 the
ramdisk stays at whatever fit_load_image returned.
* hal/zynq.c and hal/versal.c bump fdt_totalsize headroom from 512 to
768 bytes to fit the new linux,initrd-{start,end} entries.
* config/examples/zynqmp_sdcard.config gains a commented-out opt-in
block (RAMDISK=1, WOLFBOOT_LOAD_RAMDISK_ADDRESS=0x40000000, alt
LINUX_BOOTARGS) so a single config file covers both rootfs-on-disk
and FIT-bundled-initramfs flows.
Builds against the existing master configs are byte-identical when
GZIP=0 and RAMDISK is unset.
pull/772/head
parent
090f0ef411
commit
c643215c5e
1
Makefile
1
Makefile
|
|
@ -638,6 +638,7 @@ include/target.h: $(TARGET_H_TEMPLATE) FORCE
|
|||
sed -e "s/@WOLFBOOT_DTS_UPDATE_ADDRESS@/$(WOLFBOOT_DTS_UPDATE_ADDRESS)/g" | \
|
||||
sed -e "s/@WOLFBOOT_LOAD_ADDRESS@/$(WOLFBOOT_LOAD_ADDRESS)/g" | \
|
||||
sed -e "s/@WOLFBOOT_LOAD_DTS_ADDRESS@/$(WOLFBOOT_LOAD_DTS_ADDRESS)/g" | \
|
||||
sed -e "s/@WOLFBOOT_LOAD_RAMDISK_ADDRESS@/$(WOLFBOOT_LOAD_RAMDISK_ADDRESS)/g" | \
|
||||
sed -e "s|@WOLFBOOT_RAMBOOT_MAX_SIZE_DEFINE@|$(if $(strip $(WOLFBOOT_RAMBOOT_MAX_SIZE)),#define WOLFBOOT_RAMBOOT_MAX_SIZE $(WOLFBOOT_RAMBOOT_MAX_SIZE),/* WOLFBOOT_RAMBOOT_MAX_SIZE undefined */)|g" | \
|
||||
sed -e "s/@WOLFBOOT_PARTITION_SELF_HEADER_ADDRESS@/$(WOLFBOOT_PARTITION_SELF_HEADER_ADDRESS)/g" \
|
||||
> $@
|
||||
|
|
|
|||
|
|
@ -46,6 +46,9 @@ WOLFTPM?=0
|
|||
ELF?=1
|
||||
#DEBUG_ELF?=1
|
||||
|
||||
# Native gzip decompression for FIT subimages (set GZIP=0 to disable)
|
||||
GZIP?=1
|
||||
|
||||
# Use RISC-V assembly version of ECDSA and SHA
|
||||
NO_ASM?=0
|
||||
|
||||
|
|
|
|||
|
|
@ -35,6 +35,9 @@ WOLFTPM?=0
|
|||
ELF?=1
|
||||
#DEBUG_ELF?=1
|
||||
|
||||
# Native gzip decompression for FIT subimages (set GZIP=0 to disable)
|
||||
GZIP?=1
|
||||
|
||||
# Use RISC-V assembly version of ECDSA and SHA
|
||||
NO_ASM?=0
|
||||
|
||||
|
|
|
|||
|
|
@ -59,6 +59,9 @@ NO_XIP=1
|
|||
# ELF loading support
|
||||
ELF?=1
|
||||
|
||||
# Native gzip decompression for FIT subimages (set GZIP=0 to disable)
|
||||
GZIP?=1
|
||||
|
||||
# Toolchain
|
||||
USE_GCC=1
|
||||
CROSS_COMPILE=aarch64-none-elf-
|
||||
|
|
|
|||
|
|
@ -33,6 +33,9 @@ NO_XIP=1
|
|||
# ELF loading support
|
||||
ELF?=1
|
||||
|
||||
# Native gzip decompression for FIT subimages (set GZIP=0 to disable)
|
||||
GZIP?=1
|
||||
|
||||
# Boot Benchmarking (optional)
|
||||
BOOT_BENCHMARK?=1
|
||||
|
||||
|
|
|
|||
|
|
@ -58,6 +58,9 @@ USE_GCC=1
|
|||
ELF?=1
|
||||
#DEBUG_ELF?=1
|
||||
|
||||
# Native gzip decompression for FIT subimages (set GZIP=0 to disable)
|
||||
GZIP?=1
|
||||
|
||||
# Flash Sector Size
|
||||
WOLFBOOT_SECTOR_SIZE=0x20000
|
||||
# Application Partition Size
|
||||
|
|
|
|||
|
|
@ -43,6 +43,9 @@ NO_XIP=1
|
|||
ELF?=1
|
||||
#DEBUG_ELF?=1
|
||||
|
||||
# Native gzip decompression for FIT subimages (set GZIP=0 to disable)
|
||||
GZIP?=1
|
||||
|
||||
# Boot Exception Level: leave wolfBoot at EL2 for handoff to Linux (matches
|
||||
# the standard PetaLinux U-Boot flow and preserves KVM/hypervisor use of
|
||||
# EL2). The EL2 Linux-cleanup path in do_boot() will clean dcache/disable
|
||||
|
|
@ -100,6 +103,21 @@ CFLAGS_EXTRA+=-DDISK_BLOCK_SIZE=0x80000
|
|||
# Check `ls /sys/class/mmc_host/` on your running target to confirm.
|
||||
CFLAGS_EXTRA+=-DLINUX_BOOTARGS_ROOT=\"/dev/mmcblk0p4\"
|
||||
|
||||
# ============================================================================
|
||||
# Optional: FIT-bundled initramfs (ramdisk) instead of an on-disk rootfs
|
||||
# ============================================================================
|
||||
# Expects the PetaLinux INITRAMFS_IMAGE_BUNDLE=0 layout (FIT contains kernel
|
||||
# + DTB + ramdisk). wolfBoot extracts the ramdisk to
|
||||
# WOLFBOOT_LOAD_RAMDISK_ADDRESS and patches the loaded DTB with
|
||||
# /chosen/linux,initrd-{start,end} so the kernel can find it. Compressed
|
||||
# (gzip) ramdisks decompress automatically when GZIP=1.
|
||||
#
|
||||
# To enable: uncomment the three lines below and comment out the
|
||||
# LINUX_BOOTARGS_ROOT line above (root= is supplied by the cpio's /init).
|
||||
#RAMDISK?=1
|
||||
#WOLFBOOT_LOAD_RAMDISK_ADDRESS?=0x40000000
|
||||
#CFLAGS_EXTRA+=-DLINUX_BOOTARGS='"earlycon console=ttyPS0,115200 init_fatal_sh=1"'
|
||||
|
||||
# ============================================================================
|
||||
# Boot Memory Layout
|
||||
# ============================================================================
|
||||
|
|
|
|||
|
|
@ -1276,8 +1276,9 @@ int hal_dts_fixup(void* dts_addr)
|
|||
wolfBoot_printf("FDT: Version %d, Size %d\n",
|
||||
fdt_version(fdt), fdt_totalsize(fdt));
|
||||
|
||||
/* Expand total size to allow adding/modifying properties */
|
||||
fdt_set_totalsize(fdt, fdt_totalsize(fdt) + 512);
|
||||
/* Expand total size to allow adding/modifying properties (bootargs and,
|
||||
* when WOLFBOOT_FIT_RAMDISK is in play, linux,initrd-{start,end}). */
|
||||
fdt_set_totalsize(fdt, fdt_totalsize(fdt) + 768);
|
||||
|
||||
/* Find /chosen node; create it only if genuinely missing. Any other
|
||||
* negative return (malformed FDT, etc.) is surfaced directly rather
|
||||
|
|
|
|||
11
hal/zynq.c
11
hal/zynq.c
|
|
@ -1927,11 +1927,12 @@ int hal_dts_fixup(void* dts_addr)
|
|||
fdt_version(fdt), fdt_totalsize(fdt));
|
||||
|
||||
/* Expand totalsize so fdt_setprop() has in-blob free space to place
|
||||
* a new/larger bootargs property. Physical headroom is already
|
||||
* guaranteed by the load-address layout (DTB at WOLFBOOT_LOAD_DTS_ADDRESS,
|
||||
* kernel loaded much higher), so growing the header is safe. Matches
|
||||
* the pattern used in hal/versal.c:hal_dts_fixup. */
|
||||
fdt_set_totalsize(fdt, fdt_totalsize(fdt) + 512);
|
||||
* a new/larger bootargs property and (when WOLFBOOT_FIT_RAMDISK is in
|
||||
* play) the linux,initrd-{start,end} properties. Physical headroom is
|
||||
* already guaranteed by the load-address layout (DTB at
|
||||
* WOLFBOOT_LOAD_DTS_ADDRESS, kernel loaded much higher), so growing
|
||||
* the header is safe. Matches the pattern in hal/versal.c. */
|
||||
fdt_set_totalsize(fdt, fdt_totalsize(fdt) + 768);
|
||||
|
||||
/* Find /chosen node; create it only if genuinely missing. Any other
|
||||
* negative return (malformed FDT, etc.) is surfaced directly rather
|
||||
|
|
|
|||
|
|
@ -158,8 +158,15 @@ int fdt_fixup_val64(void* fdt, int off, const char* node, const char* name, uint
|
|||
int fdt_shrink(void* fdt);
|
||||
|
||||
/* FIT */
|
||||
const char* fit_find_images(void* fdt, const char** pkernel, const char** pflat_dt);
|
||||
const char* fit_find_images(void* fdt, const char** pkernel, const char** pflat_dt,
|
||||
const char** pramdisk);
|
||||
void* fit_load_image(void* fdt, const char* image, int* lenp);
|
||||
void* fit_load_image_ex(void* fdt, const char* image, int* lenp, uint32_t out_max);
|
||||
|
||||
/* FDT initrd fixup: writes /chosen/linux,initrd-{start,end} as 64-bit
|
||||
* big-endian properties. Creates /chosen if missing. Returns 0 on success
|
||||
* or a negative FDT_ERR_*. */
|
||||
int fdt_fixup_initrd(void* fdt, uint64_t start, uint64_t size);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
|
|
|||
|
|
@ -157,5 +157,10 @@
|
|||
@WOLFBOOT_RAMBOOT_MAX_SIZE_DEFINE@
|
||||
#define WOLFBOOT_LOAD_DTS_ADDRESS @WOLFBOOT_LOAD_DTS_ADDRESS@
|
||||
|
||||
/* Load address for FIT ramdisk extraction (used when WOLFBOOT_FIT_RAMDISK
|
||||
* is set; otherwise unused). 0 means "use the FIT image's `load` property
|
||||
* verbatim — do not relocate". */
|
||||
#define WOLFBOOT_LOAD_RAMDISK_ADDRESS @WOLFBOOT_LOAD_RAMDISK_ADDRESS@
|
||||
|
||||
|
||||
#endif /* !H_TARGETS_TARGET_ */
|
||||
|
|
|
|||
16
options.mk
16
options.mk
|
|
@ -900,6 +900,22 @@ ifeq ($(DELTA_UPDATES),1)
|
|||
endif
|
||||
endif
|
||||
|
||||
# GZIP=1 enables native gzip decompression of FIT subimages
|
||||
# (RFC 1951 + RFC 1952). Enabled by default in FIT-using example configs.
|
||||
GZIP ?= 0
|
||||
ifeq ($(GZIP),1)
|
||||
OBJS += src/gzip.o
|
||||
CFLAGS+=-DWOLFBOOT_GZIP
|
||||
endif
|
||||
|
||||
# RAMDISK=1 enables FIT ramdisk (initramfs) extraction and DTB
|
||||
# /chosen/linux,initrd-{start,end} fixup. Compressed (gzip) ramdisks
|
||||
# decompress through the same path when GZIP=1.
|
||||
RAMDISK ?= 0
|
||||
ifeq ($(RAMDISK),1)
|
||||
CFLAGS+=-DWOLFBOOT_FIT_RAMDISK
|
||||
endif
|
||||
|
||||
ifeq ($(ARMORED),1)
|
||||
CFLAGS+=-DWOLFBOOT_ARMORED
|
||||
endif
|
||||
|
|
|
|||
240
src/fdt.c
240
src/fdt.c
|
|
@ -30,6 +30,16 @@
|
|||
#include "string.h"
|
||||
#include <stdint.h>
|
||||
|
||||
#ifdef WOLFBOOT_GZIP
|
||||
#include "gzip.h"
|
||||
#ifdef WOLFBOOT_HASH_SHA256
|
||||
#include <wolfssl/wolfcrypt/sha256.h>
|
||||
#endif
|
||||
#ifdef WOLFBOOT_HASH_SHA384
|
||||
#include <wolfssl/wolfcrypt/sha512.h>
|
||||
#endif
|
||||
#endif /* WOLFBOOT_GZIP */
|
||||
|
||||
uint32_t cpu_to_fdt32(uint32_t x)
|
||||
{
|
||||
#ifdef BIG_ENDIAN_ORDER
|
||||
|
|
@ -787,10 +797,11 @@ int fdt_fixup_val64(void* fdt, int off, const char* node, const char* name,
|
|||
|
||||
|
||||
/* FIT Specific */
|
||||
const char* fit_find_images(void* fdt, const char** pkernel, const char** pflat_dt)
|
||||
const char* fit_find_images(void* fdt, const char** pkernel, const char** pflat_dt,
|
||||
const char** pramdisk)
|
||||
{
|
||||
const void* val;
|
||||
const char *conf = NULL, *kernel = NULL, *flat_dt = NULL;
|
||||
const char *conf = NULL, *kernel = NULL, *flat_dt = NULL, *ramdisk = NULL;
|
||||
int off, len = 0;
|
||||
|
||||
/* Find the default configuration (optional) */
|
||||
|
|
@ -806,6 +817,7 @@ const char* fit_find_images(void* fdt, const char** pkernel, const char** pflat_
|
|||
if (off > 0) {
|
||||
kernel = fdt_getprop(fdt, off, "kernel", &len);
|
||||
flat_dt = fdt_getprop(fdt, off, "fdt", &len);
|
||||
ramdisk = fdt_getprop(fdt, off, "ramdisk", &len);
|
||||
}
|
||||
}
|
||||
if (kernel == NULL) {
|
||||
|
|
@ -828,19 +840,190 @@ const char* fit_find_images(void* fdt, const char** pkernel, const char** pflat_
|
|||
}
|
||||
}
|
||||
}
|
||||
if (ramdisk == NULL) {
|
||||
/* find node with "type" == ramdisk */
|
||||
off = fdt_find_prop_offset(fdt, -1, "type", "ramdisk");
|
||||
if (off > 0) {
|
||||
val = fdt_get_name(fdt, off, &len);
|
||||
if (val != NULL && len > 0) {
|
||||
ramdisk = (const char*)val;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (pkernel)
|
||||
*pkernel = kernel;
|
||||
if (pflat_dt)
|
||||
*pflat_dt = flat_dt;
|
||||
if (pramdisk)
|
||||
*pramdisk = ramdisk;
|
||||
|
||||
return conf;
|
||||
}
|
||||
|
||||
void* fit_load_image(void* fdt, const char* image, int* lenp)
|
||||
int fdt_fixup_initrd(void* fdt, uint64_t start, uint64_t size)
|
||||
{
|
||||
int off, ret;
|
||||
uint64_t end;
|
||||
|
||||
if (fdt == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
end = start + size;
|
||||
|
||||
off = fdt_find_node_offset(fdt, -1, "chosen");
|
||||
if (off == -FDT_ERR_NOTFOUND) {
|
||||
off = fdt_add_subnode(fdt, 0, "chosen");
|
||||
}
|
||||
if (off < 0) {
|
||||
return off;
|
||||
}
|
||||
|
||||
ret = fdt_fixup_val64(fdt, off, "chosen", "linux,initrd-start", start);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
ret = fdt_fixup_val64(fdt, off, "chosen", "linux,initrd-end", end);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef WOLFBOOT_GZIP
|
||||
/* Verify FIT per-subimage hash-1 subnode against the loaded/decompressed
|
||||
* image bytes. This is defense-in-depth: the outer wolfBoot signature
|
||||
* already authenticates the entire FIT blob, but recomputing the per-image
|
||||
* hash catches inflater bugs and corrupt streams that still parse.
|
||||
*
|
||||
* Returns 0 on success or when no usable hash node is present.
|
||||
* Returns negative on hash mismatch.
|
||||
*
|
||||
* If hash-1.algo names an algorithm that is not compiled into this build,
|
||||
* a warning is printed and 0 is returned (best-effort verification). */
|
||||
static int fit_verify_hash(const void *fdt, int img_off,
|
||||
const uint8_t *data, uint32_t data_len)
|
||||
{
|
||||
int ret = 0;
|
||||
int done = 0;
|
||||
int hash_off, len = 0;
|
||||
const char *algo = NULL;
|
||||
const uint8_t *value = NULL;
|
||||
#ifdef WOLFBOOT_HASH_SHA256
|
||||
wc_Sha256 sha256_ctx;
|
||||
uint8_t sha256_digest[WC_SHA256_DIGEST_SIZE];
|
||||
#endif
|
||||
#ifdef WOLFBOOT_HASH_SHA384
|
||||
wc_Sha384 sha384_ctx;
|
||||
uint8_t sha384_digest[WC_SHA384_DIGEST_SIZE];
|
||||
#endif
|
||||
|
||||
hash_off = fdt_subnode_offset_namelen(fdt, img_off, "hash-1", 6);
|
||||
if (hash_off < 0) {
|
||||
done = 1; /* no hash-1 subnode; nothing to verify */
|
||||
}
|
||||
|
||||
if (!done) {
|
||||
algo = (const char*)fdt_getprop(fdt, hash_off, "algo", &len);
|
||||
if (algo == NULL || len <= 0) {
|
||||
wolfBoot_printf("FIT hash-1: missing algo\n");
|
||||
done = 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (!done) {
|
||||
value = (const uint8_t*)fdt_getprop(fdt, hash_off, "value", &len);
|
||||
if (value == NULL) {
|
||||
/* mkimage emits the hash node but populates 'value' only after
|
||||
* signing; an empty 'value' on an unsigned tree is benign. */
|
||||
done = 1;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef WOLFBOOT_HASH_SHA256
|
||||
if (!done && strcmp(algo, "sha256") == 0) {
|
||||
if (len != WC_SHA256_DIGEST_SIZE) {
|
||||
wolfBoot_printf("FIT hash-1: bad sha256 value len %d\n", len);
|
||||
ret = -1;
|
||||
}
|
||||
if (ret == 0) {
|
||||
ret = wc_InitSha256(&sha256_ctx);
|
||||
}
|
||||
if (ret == 0) {
|
||||
ret = wc_Sha256Update(&sha256_ctx, data, (word32)data_len);
|
||||
}
|
||||
if (ret == 0) {
|
||||
ret = wc_Sha256Final(&sha256_ctx, sha256_digest);
|
||||
}
|
||||
wc_Sha256Free(&sha256_ctx);
|
||||
if (ret != 0) {
|
||||
wolfBoot_printf("FIT hash-1 (sha256): wc_Sha256 failed rc=%d\n",
|
||||
ret);
|
||||
ret = -1;
|
||||
}
|
||||
else if (memcmp(sha256_digest, value, WC_SHA256_DIGEST_SIZE) != 0) {
|
||||
wolfBoot_printf("FIT hash-1 (sha256): MISMATCH\n");
|
||||
ret = -1;
|
||||
}
|
||||
else {
|
||||
wolfBoot_printf("FIT hash-1 (sha256): OK\n");
|
||||
}
|
||||
done = 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef WOLFBOOT_HASH_SHA384
|
||||
if (!done && strcmp(algo, "sha384") == 0) {
|
||||
if (len != WC_SHA384_DIGEST_SIZE) {
|
||||
wolfBoot_printf("FIT hash-1: bad sha384 value len %d\n", len);
|
||||
ret = -1;
|
||||
}
|
||||
if (ret == 0) {
|
||||
ret = wc_InitSha384(&sha384_ctx);
|
||||
}
|
||||
if (ret == 0) {
|
||||
ret = wc_Sha384Update(&sha384_ctx, data, (word32)data_len);
|
||||
}
|
||||
if (ret == 0) {
|
||||
ret = wc_Sha384Final(&sha384_ctx, sha384_digest);
|
||||
}
|
||||
wc_Sha384Free(&sha384_ctx);
|
||||
if (ret != 0) {
|
||||
wolfBoot_printf("FIT hash-1 (sha384): wc_Sha384 failed rc=%d\n",
|
||||
ret);
|
||||
ret = -1;
|
||||
}
|
||||
else if (memcmp(sha384_digest, value, WC_SHA384_DIGEST_SIZE) != 0) {
|
||||
wolfBoot_printf("FIT hash-1 (sha384): MISMATCH\n");
|
||||
ret = -1;
|
||||
}
|
||||
else {
|
||||
wolfBoot_printf("FIT hash-1 (sha384): OK\n");
|
||||
}
|
||||
done = 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
if ((ret == 0) && !done) {
|
||||
wolfBoot_printf("FIT hash-1: algo '%s' not built in, skipping\n",
|
||||
algo);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
#endif /* WOLFBOOT_GZIP */
|
||||
|
||||
void* fit_load_image_ex(void* fdt, const char* image, int* lenp,
|
||||
uint32_t out_max)
|
||||
{
|
||||
void *load, *entry, *data = NULL;
|
||||
int off, len = 0;
|
||||
const char *comp;
|
||||
int complen = 0;
|
||||
#ifndef WOLFBOOT_GZIP
|
||||
(void)out_max;
|
||||
#endif
|
||||
|
||||
off = fdt_find_node_offset(fdt, -1, image);
|
||||
if (off > 0) {
|
||||
|
|
@ -849,9 +1032,49 @@ void* fit_load_image(void* fdt, const char* image, int* lenp)
|
|||
load = fdt_getprop_address(fdt, off, "load");
|
||||
entry = fdt_getprop_address(fdt, off, "entry");
|
||||
if (data != NULL && load != NULL && data != load) {
|
||||
wolfBoot_printf("Loading Image %s: %p -> %p (%d bytes)\n",
|
||||
image, data, load, len);
|
||||
memcpy(load, data, len);
|
||||
/* Detect compression unconditionally so we can warn (and fail
|
||||
* closed) when the build lacks support for it instead of
|
||||
* silently copying compressed bytes as if they were raw. */
|
||||
comp = (const char*)fdt_getprop(fdt, off, "compression",
|
||||
&complen);
|
||||
if (comp != NULL && complen > 0 && strcmp(comp, "gzip") == 0) {
|
||||
#ifdef WOLFBOOT_GZIP
|
||||
uint32_t out_len = 0;
|
||||
int rc;
|
||||
wolfBoot_printf("Decompressing Image %s (gzip): "
|
||||
"%p -> %p (%d bytes)\n", image, data, load, len);
|
||||
rc = wolfBoot_gunzip((const uint8_t*)data, (uint32_t)len,
|
||||
(uint8_t*)load, out_max, &out_len);
|
||||
if (rc != 0) {
|
||||
wolfBoot_printf("FIT gunzip failed for %s: rc=%d "
|
||||
"(wrote %u bytes)\n", image, rc, out_len);
|
||||
return NULL;
|
||||
}
|
||||
len = (int)out_len;
|
||||
wolfBoot_printf("Decompressed %s: %u bytes\n", image,
|
||||
out_len);
|
||||
#else
|
||||
wolfBoot_printf("FIT: subimage '%s' has compression="
|
||||
"\"gzip\" but WOLFBOOT_GZIP is not enabled in this "
|
||||
"build (rebuild with GZIP=1)\n", image);
|
||||
return NULL;
|
||||
#endif
|
||||
}
|
||||
else {
|
||||
wolfBoot_printf("Loading Image %s: %p -> %p (%d bytes)\n",
|
||||
image, data, load, len);
|
||||
memcpy(load, data, len);
|
||||
}
|
||||
|
||||
#ifdef WOLFBOOT_GZIP
|
||||
/* Defense-in-depth: verify FIT hash-1 against loaded bytes */
|
||||
if (fit_verify_hash(fdt, off, (const uint8_t*)load,
|
||||
(uint32_t)len) != 0) {
|
||||
wolfBoot_printf("FIT hash verification failed for %s\n",
|
||||
image);
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* load should always have entry, but if not use load address */
|
||||
data = (entry != NULL) ? entry : load;
|
||||
|
|
@ -868,4 +1091,9 @@ void* fit_load_image(void* fdt, const char* image, int* lenp)
|
|||
|
||||
}
|
||||
|
||||
void* fit_load_image(void* fdt, const char* image, int* lenp)
|
||||
{
|
||||
return fit_load_image_ex(fdt, image, lenp, 0xFFFFFFFFU);
|
||||
}
|
||||
|
||||
#endif /* (MMU || WOLFBOOT_FDT) && !BUILD_LOADER_STAGE1 */
|
||||
|
|
|
|||
|
|
@ -541,12 +541,12 @@ void RAMFUNCTION wolfBoot_start(void)
|
|||
/* Is this a Flattened uImage Tree (FIT) image (FDT format) */
|
||||
if (wolfBoot_get_dts_size(load_address) > 0) {
|
||||
void* fit = (void*)load_address;
|
||||
const char *kernel = NULL, *flat_dt = NULL;
|
||||
const char *kernel = NULL, *flat_dt = NULL, *ramdisk = NULL;
|
||||
|
||||
wolfBoot_printf("Flattened uImage Tree: Version %d, Size %d\n",
|
||||
fdt_version(fit), fdt_totalsize(fit));
|
||||
|
||||
(void)fit_find_images(fit, &kernel, &flat_dt);
|
||||
(void)fit_find_images(fit, &kernel, &flat_dt, &ramdisk);
|
||||
if (kernel != NULL) {
|
||||
load_address = fit_load_image(fit, kernel, NULL);
|
||||
}
|
||||
|
|
@ -560,6 +560,45 @@ void RAMFUNCTION wolfBoot_start(void)
|
|||
memcpy(dts_addr, dts_ptr, dts_size);
|
||||
}
|
||||
}
|
||||
#ifdef WOLFBOOT_FIT_RAMDISK
|
||||
if (ramdisk != NULL) {
|
||||
int rd_size = 0;
|
||||
uint8_t *rd_ptr = (uint8_t*)fit_load_image(fit, ramdisk, &rd_size);
|
||||
if (rd_ptr != NULL && rd_size > 0) {
|
||||
uint8_t *rd_dst;
|
||||
/* If WOLFBOOT_LOAD_RAMDISK_ADDRESS is set (nonzero), use it
|
||||
* as the canonical destination (overrides the FIT's `load`
|
||||
* property). Otherwise honor whatever fit_load_image
|
||||
* returned (FIT-specified load addr or in-FIT pointer). */
|
||||
if (WOLFBOOT_LOAD_RAMDISK_ADDRESS != 0) {
|
||||
rd_dst = (uint8_t*)WOLFBOOT_LOAD_RAMDISK_ADDRESS;
|
||||
if (rd_ptr != rd_dst) {
|
||||
wolfBoot_printf("Loading ramdisk: %p -> %p (%d bytes)\n",
|
||||
rd_ptr, rd_dst, rd_size);
|
||||
memcpy(rd_dst, rd_ptr, rd_size);
|
||||
}
|
||||
else {
|
||||
wolfBoot_printf("Loaded ramdisk: %p (%d bytes)\n",
|
||||
rd_dst, rd_size);
|
||||
}
|
||||
}
|
||||
else {
|
||||
rd_dst = rd_ptr;
|
||||
wolfBoot_printf("Loaded ramdisk: %p (%d bytes)\n",
|
||||
rd_dst, rd_size);
|
||||
}
|
||||
if (dts_addr != NULL) {
|
||||
(void)fdt_fixup_initrd((void*)dts_addr,
|
||||
(uint64_t)(uintptr_t)rd_dst, (uint64_t)rd_size);
|
||||
}
|
||||
}
|
||||
else {
|
||||
wolfBoot_printf("FIT: ramdisk node present but load failed\n");
|
||||
}
|
||||
}
|
||||
#else
|
||||
(void)ramdisk;
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
|
|
|
|||
|
|
@ -368,12 +368,12 @@ backup_on_failure:
|
|||
/* Is this a Flattened uImage Tree (FIT) image (FDT format) */
|
||||
if (wolfBoot_get_dts_size(load_address) > 0) {
|
||||
void* fit = (void*)load_address;
|
||||
const char *kernel = NULL, *flat_dt = NULL;
|
||||
const char *kernel = NULL, *flat_dt = NULL, *ramdisk = NULL;
|
||||
|
||||
wolfBoot_printf("Flattened uImage Tree: Version %d, Size %d\n",
|
||||
fdt_version(fit), fdt_totalsize(fit));
|
||||
|
||||
(void)fit_find_images(fit, &kernel, &flat_dt);
|
||||
(void)fit_find_images(fit, &kernel, &flat_dt, &ramdisk);
|
||||
if (kernel != NULL) {
|
||||
load_address = fit_load_image(fit, kernel, NULL);
|
||||
}
|
||||
|
|
@ -387,6 +387,45 @@ backup_on_failure:
|
|||
memcpy(dts_addr, dts_ptr, dts_size);
|
||||
}
|
||||
}
|
||||
#ifdef WOLFBOOT_FIT_RAMDISK
|
||||
if (ramdisk != NULL) {
|
||||
int rd_size = 0;
|
||||
uint8_t *rd_ptr = (uint8_t*)fit_load_image(fit, ramdisk, &rd_size);
|
||||
if (rd_ptr != NULL && rd_size > 0) {
|
||||
uint8_t *rd_dst;
|
||||
/* If WOLFBOOT_LOAD_RAMDISK_ADDRESS is set (nonzero), use it
|
||||
* as the canonical destination (overrides the FIT's `load`
|
||||
* property). Otherwise honor whatever fit_load_image
|
||||
* returned (FIT-specified load addr or in-FIT pointer). */
|
||||
if (WOLFBOOT_LOAD_RAMDISK_ADDRESS != 0) {
|
||||
rd_dst = (uint8_t*)WOLFBOOT_LOAD_RAMDISK_ADDRESS;
|
||||
if (rd_ptr != rd_dst) {
|
||||
wolfBoot_printf("Loading ramdisk: %p -> %p (%d bytes)\n",
|
||||
rd_ptr, rd_dst, rd_size);
|
||||
memcpy(rd_dst, rd_ptr, rd_size);
|
||||
}
|
||||
else {
|
||||
wolfBoot_printf("Loaded ramdisk: %p (%d bytes)\n",
|
||||
rd_dst, rd_size);
|
||||
}
|
||||
}
|
||||
else {
|
||||
rd_dst = rd_ptr;
|
||||
wolfBoot_printf("Loaded ramdisk: %p (%d bytes)\n",
|
||||
rd_dst, rd_size);
|
||||
}
|
||||
if (dts_addr != NULL) {
|
||||
(void)fdt_fixup_initrd((void*)dts_addr,
|
||||
(uint64_t)(uintptr_t)rd_dst, (uint64_t)rd_size);
|
||||
}
|
||||
}
|
||||
else {
|
||||
wolfBoot_printf("FIT: ramdisk node present but load failed\n");
|
||||
}
|
||||
}
|
||||
#else
|
||||
(void)ramdisk;
|
||||
#endif
|
||||
}
|
||||
else {
|
||||
/* Load DTS to RAM */
|
||||
|
|
|
|||
|
|
@ -76,6 +76,7 @@ ifeq ($(ARCH),)
|
|||
WOLFBOOT_DTS_UPDATE_ADDRESS=0x50000
|
||||
WOLFBOOT_LOAD_ADDRESS?=0x200000
|
||||
WOLFBOOT_LOAD_DTS_ADDRESS?=0x400000
|
||||
WOLFBOOT_LOAD_RAMDISK_ADDRESS?=0
|
||||
WOLFBOOT_SMALL_STACK?=0
|
||||
DELTA_UPDATES?=0
|
||||
DELTA_BLOCK_SIZE?=256
|
||||
|
|
@ -109,7 +110,8 @@ CONFIG_VARS:= ARCH TARGET SIGN HASH MCUXSDK MCUXPRESSO MCUXPRESSO_CPU MCUXPRESSO
|
|||
WOLFBOOT_PARTITION_SIZE WOLFBOOT_SECTOR_SIZE \
|
||||
WOLFBOOT_PARTITION_BOOT_ADDRESS WOLFBOOT_PARTITION_UPDATE_ADDRESS \
|
||||
WOLFBOOT_PARTITION_SWAP_ADDRESS WOLFBOOT_LOAD_ADDRESS \
|
||||
WOLFBOOT_LOAD_DTS_ADDRESS WOLFBOOT_DTS_BOOT_ADDRESS WOLFBOOT_DTS_UPDATE_ADDRESS \
|
||||
WOLFBOOT_LOAD_DTS_ADDRESS WOLFBOOT_LOAD_RAMDISK_ADDRESS \
|
||||
WOLFBOOT_DTS_BOOT_ADDRESS WOLFBOOT_DTS_UPDATE_ADDRESS \
|
||||
WOLFBOOT_SMALL_STACK DELTA_UPDATES DELTA_BLOCK_SIZE WOLFBOOT_IMG_HASH_ONESHOT \
|
||||
WOLFBOOT_HUGE_STACK FORCE_32BIT\
|
||||
ENCRYPT_WITH_CHACHA ENCRYPT_WITH_AES128 ENCRYPT_WITH_AES256 ARMORED \
|
||||
|
|
@ -117,6 +119,7 @@ CONFIG_VARS:= ARCH TARGET SIGN HASH MCUXSDK MCUXPRESSO MCUXPRESSO_CPU MCUXPRESSO
|
|||
WOLFBOOT_UNIVERSAL_KEYSTORE \
|
||||
XMSS_PARAMS \
|
||||
ELF BIG_ENDIAN \
|
||||
GZIP RAMDISK \
|
||||
NXP_CUSTOM_DCD NXP_CUSTOM_DCD_OBJS \
|
||||
FLASH_OTP_KEYSTORE \
|
||||
KEYVAULT_OBJ_SIZE \
|
||||
|
|
|
|||
|
|
@ -372,9 +372,9 @@ void dts_parse_fit_image(void* fit, const char* image, const char* desc)
|
|||
|
||||
int dts_parse_fit(void* image)
|
||||
{
|
||||
const char *conf = NULL, *kernel = NULL, *flat_dt = NULL;
|
||||
const char *conf = NULL, *kernel = NULL, *flat_dt = NULL, *ramdisk = NULL;
|
||||
|
||||
conf = fit_find_images(image, &kernel, &flat_dt);
|
||||
conf = fit_find_images(image, &kernel, &flat_dt, &ramdisk);
|
||||
if (conf != NULL) {
|
||||
printf("FIT: Found '%s' configuration\n", conf);
|
||||
dts_fit_image_item(image, fdt_find_node_offset(image, -1, conf),
|
||||
|
|
@ -384,6 +384,9 @@ int dts_parse_fit(void* image)
|
|||
/* dump image information */
|
||||
dts_parse_fit_image(image, kernel, "Kernel");
|
||||
dts_parse_fit_image(image, flat_dt, "FDT");
|
||||
if (ramdisk != NULL) {
|
||||
dts_parse_fit_image(image, ramdisk, "Ramdisk");
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue