Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

lib: add support for LZ4-compressed kernel

Add support for extracting LZ4-compressed kernel images, as well as
LZ4-compressed ramdisk images in the kernel boot process.

Signed-off-by: Kyungsik Lee <kyungsik.lee@lge.com>
Cc: "H. Peter Anvin" <hpa@zytor.com>
Cc: Ingo Molnar <mingo@elte.hu>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Russell King <rmk@arm.linux.org.uk>
Cc: Borislav Petkov <bp@alien8.de>
Cc: Florian Fainelli <florian@openwrt.org>
Cc: Yann Collet <yann.collet.73@gmail.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

authored by

Kyungsik Lee and committed by
Linus Torvalds
e76e1fdf cffb78b0

+243 -2
+10
include/linux/decompress/unlz4.h
··· 1 + #ifndef DECOMPRESS_UNLZ4_H 2 + #define DECOMPRESS_UNLZ4_H 3 + 4 + int unlz4(unsigned char *inbuf, int len, 5 + int(*fill)(void*, unsigned int), 6 + int(*flush)(void*, unsigned int), 7 + unsigned char *output, 8 + int *pos, 9 + void(*error)(char *x)); 10 + #endif
+16 -1
init/Kconfig
··· 112 112 config HAVE_KERNEL_LZO 113 113 bool 114 114 115 + config HAVE_KERNEL_LZ4 116 + bool 117 + 115 118 choice 116 119 prompt "Kernel compression mode" 117 120 default KERNEL_GZIP 118 - depends on HAVE_KERNEL_GZIP || HAVE_KERNEL_BZIP2 || HAVE_KERNEL_LZMA || HAVE_KERNEL_XZ || HAVE_KERNEL_LZO 121 + depends on HAVE_KERNEL_GZIP || HAVE_KERNEL_BZIP2 || HAVE_KERNEL_LZMA || HAVE_KERNEL_XZ || HAVE_KERNEL_LZO || HAVE_KERNEL_LZ4 119 122 help 120 123 The linux kernel is a kind of self-extracting executable. 121 124 Several compression algorithms are available, which differ ··· 184 181 Its compression ratio is the poorest among the choices. The kernel 185 182 size is about 10% bigger than gzip; however its speed 186 183 (both compression and decompression) is the fastest. 184 + 185 + config KERNEL_LZ4 186 + bool "LZ4" 187 + depends on HAVE_KERNEL_LZ4 188 + help 189 + LZ4 is an LZ77-type compressor with a fixed, byte-oriented encoding. 190 + A preliminary version of LZ4 de/compression tool is available at 191 + <https://code.google.com/p/lz4/>. 192 + 193 + Its compression ratio is worse than LZO. The size of the kernel 194 + is about 8% bigger than LZO. But the decompression speed is 195 + faster than LZO. 187 196 188 197 endchoice 189 198
+7
lib/Kconfig
··· 194 194 config LZO_DECOMPRESS 195 195 tristate 196 196 197 + config LZ4_DECOMPRESS 198 + tristate 199 + 197 200 source "lib/xz/Kconfig" 198 201 199 202 # ··· 219 216 220 217 config DECOMPRESS_LZO 221 218 select LZO_DECOMPRESS 219 + tristate 220 + 221 + config DECOMPRESS_LZ4 222 + select LZ4_DECOMPRESS 222 223 tristate 223 224 224 225 #
+2
lib/Makefile
··· 75 75 obj-$(CONFIG_BCH) += bch.o 76 76 obj-$(CONFIG_LZO_COMPRESS) += lzo/ 77 77 obj-$(CONFIG_LZO_DECOMPRESS) += lzo/ 78 + obj-$(CONFIG_LZ4_DECOMPRESS) += lz4/ 78 79 obj-$(CONFIG_XZ_DEC) += xz/ 79 80 obj-$(CONFIG_RAID6_PQ) += raid6/ 80 81 ··· 84 83 lib-$(CONFIG_DECOMPRESS_LZMA) += decompress_unlzma.o 85 84 lib-$(CONFIG_DECOMPRESS_XZ) += decompress_unxz.o 86 85 lib-$(CONFIG_DECOMPRESS_LZO) += decompress_unlzo.o 86 + lib-$(CONFIG_DECOMPRESS_LZ4) += decompress_unlz4.o 87 87 88 88 obj-$(CONFIG_TEXTSEARCH) += textsearch.o 89 89 obj-$(CONFIG_TEXTSEARCH_KMP) += ts_kmp.o
+5
lib/decompress.c
··· 11 11 #include <linux/decompress/unxz.h> 12 12 #include <linux/decompress/inflate.h> 13 13 #include <linux/decompress/unlzo.h> 14 + #include <linux/decompress/unlz4.h> 14 15 15 16 #include <linux/types.h> 16 17 #include <linux/string.h> ··· 32 31 #ifndef CONFIG_DECOMPRESS_LZO 33 32 # define unlzo NULL 34 33 #endif 34 + #ifndef CONFIG_DECOMPRESS_LZ4 35 + # define unlz4 NULL 36 + #endif 35 37 36 38 struct compress_format { 37 39 unsigned char magic[2]; ··· 49 45 { {0x5d, 0x00}, "lzma", unlzma }, 50 46 { {0xfd, 0x37}, "xz", unxz }, 51 47 { {0x89, 0x4c}, "lzo", unlzo }, 48 + { {0x02, 0x21}, "lz4", unlz4 }, 52 49 { {0, 0}, NULL, NULL } 53 50 }; 54 51
+187
lib/decompress_unlz4.c
··· 1 + /* 2 + * Wrapper for decompressing LZ4-compressed kernel, initramfs, and initrd 3 + * 4 + * Copyright (C) 2013, LG Electronics, Kyungsik Lee <kyungsik.lee@lge.com> 5 + * 6 + * This program is free software; you can redistribute it and/or modify 7 + * it under the terms of the GNU General Public License version 2 as 8 + * published by the Free Software Foundation. 9 + */ 10 + 11 + #ifdef STATIC 12 + #define PREBOOT 13 + #include "lz4/lz4_decompress.c" 14 + #else 15 + #include <linux/decompress/unlz4.h> 16 + #endif 17 + #include <linux/types.h> 18 + #include <linux/lz4.h> 19 + #include <linux/decompress/mm.h> 20 + #include <linux/compiler.h> 21 + 22 + #include <asm/unaligned.h> 23 + 24 + /* 25 + * Note: Uncompressed chunk size is used in the compressor side 26 + * (userspace side for compression). 27 + * It is hardcoded because there is not proper way to extract it 28 + * from the binary stream which is generated by the preliminary 29 + * version of LZ4 tool so far. 30 + */ 31 + #define LZ4_DEFAULT_UNCOMPRESSED_CHUNK_SIZE (8 << 20) 32 + #define ARCHIVE_MAGICNUMBER 0x184C2102 33 + 34 + STATIC inline int INIT unlz4(u8 *input, int in_len, 35 + int (*fill) (void *, unsigned int), 36 + int (*flush) (void *, unsigned int), 37 + u8 *output, int *posp, 38 + void (*error) (char *x)) 39 + { 40 + int ret = -1; 41 + size_t chunksize = 0; 42 + size_t uncomp_chunksize = LZ4_DEFAULT_UNCOMPRESSED_CHUNK_SIZE; 43 + u8 *inp; 44 + u8 *inp_start; 45 + u8 *outp; 46 + int size = in_len; 47 + #ifdef PREBOOT 48 + size_t out_len = get_unaligned_le32(input + in_len); 49 + #endif 50 + size_t dest_len; 51 + 52 + 53 + if (output) { 54 + outp = output; 55 + } else if (!flush) { 56 + error("NULL output pointer and no flush function provided"); 57 + goto exit_0; 58 + } else { 59 + outp = large_malloc(uncomp_chunksize); 60 + if (!outp) { 61 + error("Could not allocate output buffer"); 62 + goto exit_0; 63 + } 64 + } 65 + 66 + if (input && fill) { 67 + error("Both input pointer and fill function provided,"); 68 + goto exit_1; 69 + } else if (input) { 70 + inp = input; 71 + } else if (!fill) { 72 + error("NULL input pointer and missing fill function"); 73 + goto exit_1; 74 + } else { 75 + inp = large_malloc(lz4_compressbound(uncomp_chunksize)); 76 + if (!inp) { 77 + error("Could not allocate input buffer"); 78 + goto exit_1; 79 + } 80 + } 81 + inp_start = inp; 82 + 83 + if (posp) 84 + *posp = 0; 85 + 86 + if (fill) 87 + fill(inp, 4); 88 + 89 + chunksize = get_unaligned_le32(inp); 90 + if (chunksize == ARCHIVE_MAGICNUMBER) { 91 + inp += 4; 92 + size -= 4; 93 + } else { 94 + error("invalid header"); 95 + goto exit_2; 96 + } 97 + 98 + if (posp) 99 + *posp += 4; 100 + 101 + for (;;) { 102 + 103 + if (fill) 104 + fill(inp, 4); 105 + 106 + chunksize = get_unaligned_le32(inp); 107 + if (chunksize == ARCHIVE_MAGICNUMBER) { 108 + inp += 4; 109 + size -= 4; 110 + if (posp) 111 + *posp += 4; 112 + continue; 113 + } 114 + inp += 4; 115 + size -= 4; 116 + 117 + if (posp) 118 + *posp += 4; 119 + 120 + if (fill) { 121 + if (chunksize > lz4_compressbound(uncomp_chunksize)) { 122 + error("chunk length is longer than allocated"); 123 + goto exit_2; 124 + } 125 + fill(inp, chunksize); 126 + } 127 + #ifdef PREBOOT 128 + if (out_len >= uncomp_chunksize) { 129 + dest_len = uncomp_chunksize; 130 + out_len -= dest_len; 131 + } else 132 + dest_len = out_len; 133 + ret = lz4_decompress(inp, &chunksize, outp, dest_len); 134 + #else 135 + dest_len = uncomp_chunksize; 136 + ret = lz4_decompress_unknownoutputsize(inp, chunksize, outp, 137 + &dest_len); 138 + #endif 139 + if (ret < 0) { 140 + error("Decoding failed"); 141 + goto exit_2; 142 + } 143 + 144 + if (flush && flush(outp, dest_len) != dest_len) 145 + goto exit_2; 146 + if (output) 147 + outp += dest_len; 148 + if (posp) 149 + *posp += chunksize; 150 + 151 + size -= chunksize; 152 + 153 + if (size == 0) 154 + break; 155 + else if (size < 0) { 156 + error("data corrupted"); 157 + goto exit_2; 158 + } 159 + 160 + inp += chunksize; 161 + if (fill) 162 + inp = inp_start; 163 + } 164 + 165 + ret = 0; 166 + exit_2: 167 + if (!input) 168 + large_free(inp_start); 169 + exit_1: 170 + if (!output) 171 + large_free(outp); 172 + exit_0: 173 + return ret; 174 + } 175 + 176 + #ifdef PREBOOT 177 + STATIC int INIT decompress(unsigned char *buf, int in_len, 178 + int(*fill)(void*, unsigned int), 179 + int(*flush)(void*, unsigned int), 180 + unsigned char *output, 181 + int *posp, 182 + void(*error)(char *x) 183 + ) 184 + { 185 + return unlz4(buf, in_len - 4, fill, flush, output, posp, error); 186 + } 187 + #endif
+1
lib/lz4/Makefile
··· 1 + obj-$(CONFIG_LZ4_DECOMPRESS) += lz4_decompress.o
+1 -1
lib/lz4/lz4_decompress.c
··· 1 1 /* 2 2 * LZ4 Decompressor for Linux kernel 3 3 * 4 - * Copyright (C) 2013 LG Electronics Co., Ltd. (http://www.lge.com/) 4 + * Copyright (C) 2013, LG Electronics, Kyungsik Lee <kyungsik.lee@lge.com> 5 5 * 6 6 * Based on LZ4 implementation by Yann Collet. 7 7 *
+5
scripts/Makefile.lib
··· 311 311 lzop -9 && $(call size_append, $(filter-out FORCE,$^))) > $@ || \ 312 312 (rm -f $@ ; false) 313 313 314 + quiet_cmd_lz4 = LZ4 $@ 315 + cmd_lz4 = (cat $(filter-out FORCE,$^) | \ 316 + lz4c -l -c1 stdin stdout && $(call size_append, $(filter-out FORCE,$^))) > $@ || \ 317 + (rm -f $@ ; false) 318 + 314 319 # U-Boot mkimage 315 320 # --------------------------------------------------------------------------- 316 321
+9
usr/Kconfig
··· 90 90 Support loading of a LZO encoded initial ramdisk or cpio buffer 91 91 If unsure, say N. 92 92 93 + config RD_LZ4 94 + bool "Support initial ramdisks compressed using LZ4" if EXPERT 95 + default !EXPERT 96 + depends on BLK_DEV_INITRD 97 + select DECOMPRESS_LZ4 98 + help 99 + Support loading of a LZ4 encoded initial ramdisk or cpio buffer 100 + If unsure, say N. 101 + 93 102 choice 94 103 prompt "Built-in initramfs compression mode" if INITRAMFS_SOURCE!="" 95 104 help