From 6ae5357267ef6bbc68586f2e08e0495ee3dcf5a5 Mon Sep 17 00:00:00 2001 From: Mykyta Poturai Date: Thu, 15 Feb 2024 14:59:12 +0200 Subject: [PATCH 1/3] drivers: ramdisk: Add support for external initrd Add support for using initrd provided by the bootloader as the RAM Disk. Location of the initrd is specified by the DISK_RAM_START Kconfig option. Currently only uncompressed filesystem images are supported. Signed-off-by: Mykyta Poturai --- drivers/disk/Kconfig.ram | 12 ++++++++++++ drivers/disk/ramdisk.c | 23 ++++++++++++++++++++++- 2 files changed, 34 insertions(+), 1 deletion(-) diff --git a/drivers/disk/Kconfig.ram b/drivers/disk/Kconfig.ram index b662c41fa3aff..a46974afff68d 100644 --- a/drivers/disk/Kconfig.ram +++ b/drivers/disk/Kconfig.ram @@ -22,6 +22,18 @@ config DISK_RAM_VOLUME_NAME help Disk name as per file system naming guidelines. +config DISK_RAM_EXTERNAL + bool "Use initrd provided by the bootloader" + help + Use the initrd provided by the bootloader as the RAM Disk. + +config DISK_RAM_START + hex "Start address of the preloaded RAM Disk" + depends on DISK_RAM_EXTERNAL + default 0 + help + Start the RAM Disk at a specific address. + module = RAMDISK module-str = ramdisk source "subsys/logging/Kconfig.template.log_config" diff --git a/drivers/disk/ramdisk.c b/drivers/disk/ramdisk.c index 0cd1432c80ba7..6ca966f384f64 100644 --- a/drivers/disk/ramdisk.c +++ b/drivers/disk/ramdisk.c @@ -19,7 +19,26 @@ LOG_MODULE_REGISTER(ramdisk, CONFIG_RAMDISK_LOG_LEVEL); #define RAMDISK_VOLUME_SIZE (CONFIG_DISK_RAM_VOLUME_SIZE * 1024) #define RAMDISK_SECTOR_COUNT (RAMDISK_VOLUME_SIZE / RAMDISK_SECTOR_SIZE) +#if IS_ENABLED(CONFIG_DISK_RAM_EXTERNAL) +static uint8_t *ramdisk_buf; +#else static uint8_t ramdisk_buf[RAMDISK_VOLUME_SIZE]; +#endif + +#if IS_ENABLED(CONFIG_DISK_RAM_EXTERNAL) +static uint8_t *disk_ram_external_map(void) +{ +#if defined(CONFIG_MMU) + uint8_t *virt_start; + + z_phys_map(&virt_start, CONFIG_DISK_RAM_START, + RAMDISK_VOLUME_SIZE, K_MEM_CACHE_WB | K_MEM_PERM_RW); + return virt_start; +#else + return (uint8_t *)CONFIG_DISK_RAM_START; +#endif +} +#endif static void *lba_to_address(uint32_t lba) { @@ -105,7 +124,9 @@ static struct disk_info ram_disk = { static int disk_ram_init(const struct device *dev) { ARG_UNUSED(dev); - +#if IS_ENABLED(CONFIG_DISK_RAM_EXTERNAL) + ramdisk_buf = disk_ram_external_map(); +#endif return disk_access_register(&ram_disk); } From 1f1cae36a461f714e4987064c506171a6d1550ec Mon Sep 17 00:00:00 2001 From: Mykyta Poturai Date: Thu, 22 Feb 2024 15:12:48 +0200 Subject: [PATCH 2/3] modules: lz4: Add lz4frame to the build system Add lz4frame and xxhash to the build system. This is required to support the decompression of LZ4 files made with LZ4 cli tool. Base lz4 library only supports decompression of raw LZ4 blocks without taking into account the frame metadata. Signed-off-by: Mykyta Poturai --- modules/lz4/CMakeLists.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/modules/lz4/CMakeLists.txt b/modules/lz4/CMakeLists.txt index 9b9a56976ebd1..a14a40b79982f 100644 --- a/modules/lz4/CMakeLists.txt +++ b/modules/lz4/CMakeLists.txt @@ -11,6 +11,8 @@ if(CONFIG_LZ4) zephyr_library_sources( ${LZ4_DIR}/lib/lz4.c + ${LZ4_DIR}/lib/lz4frame.c + ${LZ4_DIR}/lib/xxhash.c ) endif() From 8b30bdcfe7e95c85e5efcaaffc574d0143fcd60d Mon Sep 17 00:00:00 2001 From: Mykyta Poturai Date: Thu, 22 Feb 2024 15:16:54 +0200 Subject: [PATCH 3/3] drivers: ramdisk: Add support for compressed initrd Add support for decompressing the initrd before using it as the RAM Disk. For now, only LZ4 compression is supported. It is advised to use smaller block sizes for the compressed initrd to reduce the size of heap memory required for decompression. Signed-off-by: Mykyta Poturai --- drivers/disk/Kconfig.ram | 9 +++++- drivers/disk/ramdisk.c | 60 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 68 insertions(+), 1 deletion(-) diff --git a/drivers/disk/Kconfig.ram b/drivers/disk/Kconfig.ram index a46974afff68d..e068a3d88dc00 100644 --- a/drivers/disk/Kconfig.ram +++ b/drivers/disk/Kconfig.ram @@ -14,7 +14,8 @@ config DISK_RAM_VOLUME_SIZE int "RAM Disk size in kilobytes" default 96 help - Size of the RAM Disk. + Size of the RAM Disk. If compression is supported, this + is the maximum size of the uncompressed RAM Disk. config DISK_RAM_VOLUME_NAME string "RAM Disk mount point or drive name" @@ -34,6 +35,12 @@ config DISK_RAM_START help Start the RAM Disk at a specific address. +config DISK_RAM_DECOMPRESS + bool "Decompress the initrd" + depends on DISK_RAM_EXTERNAL && LZ4 + help + Decompress the initrd before using it as the RAM Disk. + module = RAMDISK module-str = ramdisk source "subsys/logging/Kconfig.template.log_config" diff --git a/drivers/disk/ramdisk.c b/drivers/disk/ramdisk.c index 6ca966f384f64..0bc59491302d7 100644 --- a/drivers/disk/ramdisk.c +++ b/drivers/disk/ramdisk.c @@ -19,6 +19,12 @@ LOG_MODULE_REGISTER(ramdisk, CONFIG_RAMDISK_LOG_LEVEL); #define RAMDISK_VOLUME_SIZE (CONFIG_DISK_RAM_VOLUME_SIZE * 1024) #define RAMDISK_SECTOR_COUNT (RAMDISK_VOLUME_SIZE / RAMDISK_SECTOR_SIZE) +#if IS_ENABLED(CONFIG_DISK_RAM_DECOMPRESS) +#include +#define LZ4_MAGIC 0x184D2204 +static uint8_t unpacked_buf[RAMDISK_VOLUME_SIZE]; +#endif + #if IS_ENABLED(CONFIG_DISK_RAM_EXTERNAL) static uint8_t *ramdisk_buf; #else @@ -40,6 +46,48 @@ static uint8_t *disk_ram_external_map(void) } #endif +#if IS_ENABLED(CONFIG_DISK_RAM_DECOMPRESS) +static void disk_ram_external_unmap(char *virt_start) +{ +#if defined(CONFIG_MMU) + z_phys_unmap(virt_start, RAMDISK_VOLUME_SIZE); +#endif +} + +static int disk_ram_is_compressed(char *virt_start) +{ + uint32_t magic = *(uint32_t *)virt_start; + + return magic == LZ4_MAGIC; +} + +static int disk_ram_decompress(char *compressed_buf, size_t compressed_size, + char *decompressed_buf, size_t decompressed_size) +{ + size_t src_size = compressed_size; + size_t dst_size = decompressed_size; + LZ4F_decompressionContext_t lz4_ctx; + int ret; + + ret = LZ4F_createDecompressionContext(&lz4_ctx, LZ4F_VERSION); + if (ret < 0) { + LOG_ERR("Can't create decompression context, error: %s\n", + LZ4F_getErrorName(ret)); + return ret; + } + + ret = LZ4F_decompress(lz4_ctx, decompressed_buf, &dst_size, + compressed_buf, &src_size, NULL); + if (ret < 0) { + LOG_ERR("Decompression failed: %s\n", LZ4F_getErrorName(ret)); + return ret; + } + LZ4F_freeDecompressionContext(lz4_ctx); + + return ret; +} +#endif + static void *lba_to_address(uint32_t lba) { return &ramdisk_buf[lba * RAMDISK_SECTOR_SIZE]; @@ -126,6 +174,18 @@ static int disk_ram_init(const struct device *dev) ARG_UNUSED(dev); #if IS_ENABLED(CONFIG_DISK_RAM_EXTERNAL) ramdisk_buf = disk_ram_external_map(); +#if IS_ENABLED(CONFIG_DISK_RAM_DECOMPRESS) + if (disk_ram_is_compressed((char *)ramdisk_buf)) { + if (disk_ram_decompress((char *)ramdisk_buf, RAMDISK_VOLUME_SIZE, + (char *)unpacked_buf, RAMDISK_VOLUME_SIZE) < 0) { + return -EINVAL; + } + + LOG_INF("Freeing compressed initrd"); + disk_ram_external_unmap(ramdisk_buf); + ramdisk_buf = unpacked_buf; + } +#endif #endif return disk_access_register(&ram_disk); }