image: allow building FIT and uImage with ramdisk
authorDaniel Golle <daniel@makrotopia.org>
Sun, 21 Feb 2021 14:19:26 +0000 (14:19 +0000)
committerDaniel Golle <daniel@makrotopia.org>
Wed, 24 Feb 2021 01:35:20 +0000 (01:35 +0000)
Instead of embedding the initrd cpio archive into the kernel, allow
for having an external ramdisk added to the FIT or uImage.
This is useful to overcome kernel size limitations present in many
stock bootloaders, as the ramdisk is then loaded seperately and doesn't
add to the kernel size. Hence we can have larger ramdisks to host ie.
installers with all binaries to flash included (or a web-based
firmware selector).
In terms of performance and total size the differences are neglectible.

Signed-off-by: Daniel Golle <daniel@makrotopia.org>
config/Config-images.in
include/image-commands.mk
include/kernel-defaults.mk
scripts/mkits.sh
scripts/target-metadata.pl
target/Config.in

index 957d3af18fa860b5edbf9bb681208bd28a2bf881..080fee2ccef620951f173cab7a90d4189f6e804d 100644 (file)
@@ -35,9 +35,11 @@ menu "Target Images"
                                bool "lzma"
 
                        config TARGET_INITRAMFS_COMPRESSION_LZO
+                               depends on !TARGET_ROOTFS_INITRAMFS_SEPERATE
                                bool "lzo"
 
                        config TARGET_INITRAMFS_COMPRESSION_LZ4
+                               depends on !TARGET_ROOTFS_INITRAMFS_SEPERATE
                                bool "lz4"
 
                        config TARGET_INITRAMFS_COMPRESSION_XZ
@@ -56,11 +58,20 @@ menu "Target Images"
                          Kernel uses specified external cpio as INITRAMFS_SOURCE.
 
                config TARGET_INITRAMFS_FORCE
-                        bool "Force"
-                        depends on TARGET_ROOTFS_INITRAMFS
-                        default n
-                        help
-                          Ignore the initramfs passed by the bootloader.
+                       bool "Force"
+                       depends on TARGET_ROOTFS_INITRAMFS
+                       default n
+                       help
+                         Ignore the initramfs passed by the bootloader.
+
+               config TARGET_ROOTFS_INITRAMFS_SEPERATE
+                       bool "seperate ramdisk"
+                       depends on TARGET_ROOTFS_INITRAMFS && !TARGET_INITRAMFS_FORCE
+                       default y if USES_SEPERATE_INITRAMFS
+                       help
+                         Generate seperate initrd.cpio instead of embedding it.
+                         This is useful for generating images with a dedicated
+                         ramdisk e.g. in U-Boot's uImage and uImage.FIT formats.
 
        comment "Root filesystem archives"
 
index 3377680a0715f4301d47599b366d49285c243e22..d4ec51ca7cd0578510cbf846c9fff3df6fc076be 100644 (file)
@@ -196,11 +196,22 @@ define Build/eva-image
        mv $@.new $@
 endef
 
+define Build/initrd_compression
+       $(if $(CONFIG_TARGET_INITRAMFS_COMPRESSION_BZIP2),.bzip2) \
+       $(if $(CONFIG_TARGET_INITRAMFS_COMPRESSION_GZIP),.gzip) \
+       $(if $(CONFIG_TARGET_INITRAMFS_COMPRESSION_LZMA),.lzma) \
+       $(if $(CONFIG_TARGET_INITRAMFS_COMPRESSION_XZ),.xz) \
+       $(if $(CONFIG_TARGET_INITRAMFS_COMPRESSION_ZSTD),.zstd)
+endef
+
 define Build/fit
        $(TOPDIR)/scripts/mkits.sh \
                -D $(DEVICE_NAME) -o $@.its -k $@ \
                $(if $(word 2,$(1)),-d $(word 2,$(1))) -C $(word 1,$(1)) \
                $(if $(findstring with-rootfs,$(word 3,$(1))),-r $(IMAGE_ROOTFS)) \
+               $(if $(findstring with-initrd,$(word 3,$(1))), \
+                       $(if $(CONFIG_TARGET_ROOTFS_INITRAMFS_SEPERATE), \
+                               -i $(KERNEL_BUILD_DIR)/initrd.cpio$(strip $(call Build/initrd_compression)))) \
                -a $(KERNEL_LOADADDR) -e $(if $(KERNEL_ENTRY),$(KERNEL_ENTRY),$(KERNEL_LOADADDR)) \
                $(if $(DEVICE_FDT_NUM),-n $(DEVICE_FDT_NUM)) \
                -c $(if $(DEVICE_DTS_CONFIG),$(DEVICE_DTS_CONFIG),"config@1") \
@@ -450,6 +461,22 @@ define Build/uImage
        mv $@.new $@
 endef
 
+define Build/uImage-with-ramdisk
+       mkimage \
+               -A $(LINUX_KARCH) \
+               -O linux \
+               -T kernel \
+               -C $(word 1,$(1)) \
+               -a $(KERNEL_LOADADDR) \
+               -e $(if $(KERNEL_ENTRY),$(KERNEL_ENTRY),$(KERNEL_LOADADDR)) \
+               -i $(KERNEL_BUILD_DIR)/initrd.cpio.$(strip $(call Build/initrd_compression)) \
+               -n '$(if $(UIMAGE_NAME),$(UIMAGE_NAME),$(call toupper,$(LINUX_KARCH)) $(VERSION_DIST) Linux-$(LINUX_VERSION))' \
+               $(if $(UIMAGE_MAGIC),-M $(UIMAGE_MAGIC)) \
+               $(wordlist 2,$(words $(1)),$(1)) \
+               -d $@ $@.new
+       mv $@.new $@
+endef
+
 define Build/xor-image
        $(STAGING_DIR_HOST)/bin/xorimage -i $@ -o $@.xor $(1)
        mv $@.xor $@
index 8293956f6b766be9c271e57b7d684e246c3f013a..4b39296f8ca85778abd6efcb3c2579dfc8f9a09e 100644 (file)
@@ -48,6 +48,13 @@ else
 endif
 
 ifeq ($(CONFIG_TARGET_ROOTFS_INITRAMFS),y)
+  ifeq ($(CONFIG_TARGET_ROOTFS_INITRAMFS_SEPERATE),y)
+    define Kernel/SetInitramfs/PreConfigure
+       grep -v -e CONFIG_BLK_DEV_INITRD $(LINUX_DIR)/.config.old > $(LINUX_DIR)/.config
+       echo 'CONFIG_BLK_DEV_INITRD=y' >> $(LINUX_DIR)/.config
+       echo 'CONFIG_INITRAMFS_SOURCE=""' >> $(LINUX_DIR)/.config
+    endef
+  else
   ifeq ($(strip $(CONFIG_EXTERNAL_CPIO)),"")
     define Kernel/SetInitramfs/PreConfigure
        grep -v -e INITRAMFS -e CONFIG_RD_ -e CONFIG_BLK_DEV_INITRD $(LINUX_DIR)/.config.old > $(LINUX_DIR)/.config
@@ -60,14 +67,19 @@ ifeq ($(CONFIG_TARGET_ROOTFS_INITRAMFS),y)
        echo 'CONFIG_INITRAMFS_SOURCE="$(call qstrip,$(CONFIG_EXTERNAL_CPIO))"' >> $(LINUX_DIR)/.config
     endef
   endif
+endif
 
   define Kernel/SetInitramfs
        rm -f $(LINUX_DIR)/.config.prev
        mv $(LINUX_DIR)/.config $(LINUX_DIR)/.config.old
        $(call Kernel/SetInitramfs/PreConfigure)
+  ifneq ($(CONFIG_TARGET_ROOTFS_INITRAMFS_SEPERATE),y)
        echo 'CONFIG_INITRAMFS_ROOT_UID=$(shell id -u)' >> $(LINUX_DIR)/.config
        echo 'CONFIG_INITRAMFS_ROOT_GID=$(shell id -g)' >> $(LINUX_DIR)/.config
        echo "$(if $(CONFIG_TARGET_INITRAMFS_FORCE),CONFIG_INITRAMFS_FORCE=y,# CONFIG_INITRAMFS_FORCE is not set)" >> $(LINUX_DIR)/.config
+  else
+       echo "# CONFIG_INITRAMFS_FORCE is not set" >> $(LINUX_DIR)/.config
+  endif
        echo "$(if $(CONFIG_TARGET_INITRAMFS_COMPRESSION_NONE),CONFIG_INITRAMFS_COMPRESSION_NONE=y,# CONFIG_INITRAMFS_COMPRESSION_NONE is not set)" >> $(LINUX_DIR)/.config
        echo -e "$(if $(CONFIG_TARGET_INITRAMFS_COMPRESSION_GZIP),CONFIG_INITRAMFS_COMPRESSION_GZIP=y\nCONFIG_RD_GZIP=y,# CONFIG_INITRAMFS_COMPRESSION_GZIP is not set\n# CONFIG_RD_GZIP is not set)" >> $(LINUX_DIR)/.config
        echo -e "$(if $(CONFIG_TARGET_INITRAMFS_COMPRESSION_BZIP2),CONFIG_INITRAMFS_COMPRESSION_BZIP2=y\nCONFIG_RD_BZIP2=y,# CONFIG_INITRAMFS_COMPRESSION_BZIP2 is not set\n# CONFIG_RD_BZIP2 is not set)" >> $(LINUX_DIR)/.config
@@ -147,6 +159,20 @@ define Kernel/CompileImage/Initramfs
        $(CP) $(GENERIC_PLATFORM_DIR)/other-files/init $(TARGET_DIR)/init
        $(if $(SOURCE_DATE_EPOCH),touch -hcd "@$(SOURCE_DATE_EPOCH)" $(TARGET_DIR)/init)
        rm -rf $(KERNEL_BUILD_DIR)/linux-$(LINUX_VERSION)/usr/initramfs_data.cpio*
+ifeq ($(CONFIG_TARGET_ROOTFS_INITRAMFS_SEPERATE),y)
+ifeq ($(CONFIG_EXTERNAL_CPIO),y)
+       $(CP) $(CONFIG_EXTERNAL_CPIO) $(KERNEL_BUILD_DIR)/initrd.cpio
+else
+       ( cd $(TARGET_DIR); find . | cpio -o -H newc -R root:root > $(KERNEL_BUILD_DIR)/initrd.cpio )
+endif
+       $(if $(CONFIG_TARGET_INITRAMFS_COMPRESSION_BZIP2),bzip2 -9 -c < $(KERNEL_BUILD_DIR)/initrd.cpio > $(KERNEL_BUILD_DIR)/initrd.cpio.bzip2)
+       $(if $(CONFIG_TARGET_INITRAMFS_COMPRESSION_GZIP),gzip -f -S .gzip -9n $(KERNEL_BUILD_DIR)/initrd.cpio)
+       $(if $(CONFIG_TARGET_INITRAMFS_COMPRESSION_LZMA),$(STAGING_DIR_HOST)/bin/lzma e -lc1 -lp2 -pb2 $(KERNEL_BUILD_DIR)/initrd.cpio $(KERNEL_BUILD_DIR)/initrd.cpio.lzma)
+# ?    $(if $(CONFIG_TARGET_INITRAMFS_COMPRESSION_LZO),)
+       $(if $(CONFIG_TARGET_INITRAMFS_COMPRESSION_XZ),$(STAGING_DIR_HOST)/bin/xz -9 -fz --check=crc32 $(KERNEL_BUILD_DIR)/initrd.cpio)
+# ?    $(if $(CONFIG_TARGET_INITRAMFS_COMPRESSION_LZ4),)
+       $(if $(CONFIG_TARGET_INITRAMFS_COMPRESSION_ZSTD),$(STAGING_DIR_HOST)/bin/zstd -T0 -f -o $(KERNEL_BUILD_DIR)/initrd.cpio.zstd $(KERNEL_BUILD_DIR)/initrd.cpio)
+endif
        +$(KERNEL_MAKE) $(KERNEL_MAKEOPTS_IMAGE) $(if $(KERNELNAME),$(KERNELNAME),all)
        $(call Kernel/CopyImage,-initramfs)
 endef
index 59ff3a2d15195a6eff3c3b20093b373745bfa562..ecaba8e9655ed1e49b03ddbf54d72a9a4befda9f 100755 (executable)
@@ -24,6 +24,7 @@ usage() {
        printf "\n\t-a ==> set load address to 'addr' (hex)"
        printf "\n\t-e ==> set entry point to 'entry' (hex)"
        printf "\n\t-f ==> set device tree compatible string"
+       printf "\n\t-i ==> include initrd Blob 'initrd'"
        printf "\n\t-v ==> set kernel version to 'version'"
        printf "\n\t-k ==> include kernel image 'kernel'"
        printf "\n\t-D ==> human friendly Device Tree Blob 'name'"
@@ -37,10 +38,11 @@ usage() {
 
 FDTNUM=1
 ROOTFSNUM=1
+INITRDNUM=1
 HASH=sha1
 LOADABLES=
 
-while getopts ":A:a:c:C:D:d:e:f:k:n:o:v:r:S" OPTION
+while getopts ":A:a:c:C:D:d:e:f:i:k:n:o:v:r:S" OPTION
 do
        case $OPTION in
                A ) ARCH=$OPTARG;;
@@ -51,6 +53,7 @@ do
                d ) DTB=$OPTARG;;
                e ) ENTRY_ADDR=$OPTARG;;
                f ) COMPATIBLE=$OPTARG;;
+               i ) INITRD=$OPTARG;;
                k ) KERNEL=$OPTARG;;
                n ) FDTNUM=$OPTARG;;
                o ) OUTPUT=$OPTARG;;
@@ -96,6 +99,27 @@ if [ -n "${DTB}" ]; then
        FDT_PROP="fdt = \"fdt@$FDTNUM\";"
 fi
 
+if [ -n "${INITRD}" ]; then
+       INITRD_NODE="
+               initrd@$INITRDNUM {
+                       description = \"${ARCH_UPPER} OpenWrt ${DEVICE} initrd\";
+                       ${COMPATIBLE_PROP}
+                       data = /incbin/(\"${INITRD}\");
+                       type = \"ramdisk\";
+                       arch = \"${ARCH}\";
+                       os = \"linux\";
+                       hash@1 {
+                               algo = \"crc32\";
+                       };
+                       hash@2 {
+                               algo = \"${HASH}\";
+                       };
+               };
+"
+       INITRD_PROP="ramdisk=\"initrd@${INITRDNUM}\";"
+fi
+
+
 if [ -n "${ROOTFS}" ]; then
        dd if="${ROOTFS}" of="${ROOTFS}.pagesync" bs=4096 conv=sync
        ROOTFS_NODE="
@@ -141,6 +165,7 @@ DATA="/dts-v1/;
                                algo = \"$HASH\";
                        };
                };
+${INITRD_NODE}
 ${FDT_NODE}
 ${ROOTFS_NODE}
        };
@@ -153,6 +178,7 @@ ${ROOTFS_NODE}
                        ${FDT_PROP}
                        ${LOADABLES:+loadables = ${LOADABLES};}
                        ${COMPATIBLE_PROP}
+                       ${INITRD_PROP}
                };
        };
 };"
index 78f77b16d5f8d7076de75e177cb705cccb592cf7..4128d544612014834f9fec065bba802148b47537 100755 (executable)
@@ -33,6 +33,7 @@ sub target_config_features(@) {
                /^fpu$/ and $ret .= "\tselect HAS_FPU\n";
                /^spe_fpu$/ and $ret .= "\tselect HAS_SPE_FPU\n";
                /^ramdisk$/ and $ret .= "\tselect USES_INITRAMFS\n";
+               /^seperate_ramdisk$/ and $ret .= "\tselect USES_INITRAMFS\n\tselect USES_SEPERATE_INITRAMFS\n";
                /^powerpc64$/ and $ret .= "\tselect powerpc64\n";
                /^nommu$/ and $ret .= "\tselect NOMMU\n";
                /^mips16$/ and $ret .= "\tselect HAS_MIPS16\n";
index 43de4710dfd3e6d19a7cc031db73f57891837e2f..9dbc5ffe465096b2748af55f74081093eee96926 100644 (file)
@@ -51,6 +51,9 @@ config USES_DEVICETREE
 config USES_INITRAMFS
        bool
 
+config USES_SEPERATE_INITRAMFS
+       bool
+
 config USES_SQUASHFS
        bool