diff --git a/drivers/disk/Kconfig.ram b/drivers/disk/Kconfig.ram index b662c41fa3aff..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" @@ -22,6 +23,24 @@ 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. + +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 0cd1432c80ba7..0bc59491302d7 100644 --- a/drivers/disk/ramdisk.c +++ b/drivers/disk/ramdisk.c @@ -19,7 +19,74 @@ 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 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 + +#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) { @@ -105,7 +172,21 @@ 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(); +#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); } 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()