Skip to content

Commit 1dccf71

Browse files
Kyungsik Leeinvisiblek
Kyungsik Lee
authored andcommitted
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>
1 parent ceb498e commit 1dccf71

File tree

10 files changed

+243
-2
lines changed

10 files changed

+243
-2
lines changed

include/linux/decompress/unlz4.h

+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
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

init/Kconfig

+16-1
Original file line numberDiff line numberDiff line change
@@ -130,10 +130,13 @@ config HAVE_KERNEL_XZ
130130
config HAVE_KERNEL_LZO
131131
bool
132132

133+
config HAVE_KERNEL_LZ4
134+
bool
135+
133136
choice
134137
prompt "Kernel compression mode"
135138
default KERNEL_GZIP
136-
depends on HAVE_KERNEL_GZIP || HAVE_KERNEL_BZIP2 || HAVE_KERNEL_LZMA || HAVE_KERNEL_XZ || HAVE_KERNEL_LZO
139+
depends on HAVE_KERNEL_GZIP || HAVE_KERNEL_BZIP2 || HAVE_KERNEL_LZMA || HAVE_KERNEL_XZ || HAVE_KERNEL_LZO || HAVE_KERNEL_LZ4
137140
help
138141
The linux kernel is a kind of self-extracting executable.
139142
Several compression algorithms are available, which differ
@@ -201,6 +204,18 @@ config KERNEL_LZO
201204
size is about 10% bigger than gzip; however its speed
202205
(both compression and decompression) is the fastest.
203206

207+
config KERNEL_LZ4
208+
bool "LZ4"
209+
depends on HAVE_KERNEL_LZ4
210+
help
211+
LZ4 is an LZ77-type compressor with a fixed, byte-oriented encoding.
212+
A preliminary version of LZ4 de/compression tool is available at
213+
<https://code.google.com/p/lz4/>.
214+
215+
Its compression ratio is worse than LZO. The size of the kernel
216+
is about 8% bigger than LZO. But the decompression speed is
217+
faster than LZO.
218+
204219
endchoice
205220

206221
config DEFAULT_HOSTNAME

lib/Kconfig

+7
Original file line numberDiff line numberDiff line change
@@ -177,6 +177,9 @@ config LZO_COMPRESS
177177
config LZO_DECOMPRESS
178178
tristate
179179

180+
config LZ4_DECOMPRESS
181+
tristate
182+
180183
source "lib/xz/Kconfig"
181184

182185
#
@@ -201,6 +204,10 @@ config DECOMPRESS_LZO
201204
select LZO_DECOMPRESS
202205
tristate
203206

207+
config DECOMPRESS_LZ4
208+
select LZ4_DECOMPRESS
209+
tristate
210+
204211
#
205212
# Generic allocator support is selected if needed
206213
#

lib/Makefile

+2
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@ obj-$(CONFIG_REED_SOLOMON) += reed_solomon/
7171
obj-$(CONFIG_BCH) += bch.o
7272
obj-$(CONFIG_LZO_COMPRESS) += lzo/
7373
obj-$(CONFIG_LZO_DECOMPRESS) += lzo/
74+
obj-$(CONFIG_LZ4_DECOMPRESS) += lz4/
7475
obj-$(CONFIG_XZ_DEC) += xz/
7576
obj-$(CONFIG_RAID6_PQ) += raid6/
7677

@@ -79,6 +80,7 @@ lib-$(CONFIG_DECOMPRESS_BZIP2) += decompress_bunzip2.o
7980
lib-$(CONFIG_DECOMPRESS_LZMA) += decompress_unlzma.o
8081
lib-$(CONFIG_DECOMPRESS_XZ) += decompress_unxz.o
8182
lib-$(CONFIG_DECOMPRESS_LZO) += decompress_unlzo.o
83+
lib-$(CONFIG_DECOMPRESS_LZ4) += decompress_unlz4.o
8284

8385
obj-$(CONFIG_TEXTSEARCH) += textsearch.o
8486
obj-$(CONFIG_TEXTSEARCH_KMP) += ts_kmp.o

lib/decompress.c

+5
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
#include <linux/decompress/unxz.h>
77
#include <linux/decompress/inflate.h>
88
#include <linux/decompress/unlzo.h>
9+
#include <linux/decompress/unlz4.h>
910

1011
#include <linux/types.h>
1112
#include <linux/string.h>
@@ -25,6 +26,9 @@
2526
#ifndef CONFIG_DECOMPRESS_LZO
2627
# define unlzo NULL
2728
#endif
29+
#ifndef CONFIG_DECOMPRESS_LZ4
30+
# define unlz4 NULL
31+
#endif
2832

2933
static const struct compress_format {
3034
unsigned char magic[2];
@@ -37,6 +41,7 @@ static const struct compress_format {
3741
{ {0x5d, 0x00}, "lzma", unlzma },
3842
{ {0xfd, 0x37}, "xz", unxz },
3943
{ {0x89, 0x4c}, "lzo", unlzo },
44+
{ {0x02, 0x21}, "lz4", unlz4 },
4045
{ {0, 0}, NULL, NULL }
4146
};
4247

lib/decompress_unlz4.c

+187
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,187 @@
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

lib/lz4/Makefile

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
obj-$(CONFIG_LZ4_DECOMPRESS) += lz4_decompress.o

lib/lz4/lz4_decompress.c

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
/*
22
* LZ4 Decompressor for Linux kernel
33
*
4-
* Copyright (C) 2013 LG Electronics Co., Ltd. (http://www.lge.com/)
4+
* Copyright (C) 2013, LG Electronics, Kyungsik Lee <kyungsik.lee@lge.com>
55
*
66
* Based on LZ4 implementation by Yann Collet.
77
*

scripts/Makefile.lib

+5
Original file line numberDiff line numberDiff line change
@@ -310,6 +310,11 @@ cmd_lzo = (cat $(filter-out FORCE,$^) | \
310310
lzop -9 && $(call size_append, $(filter-out FORCE,$^))) > $@ || \
311311
(rm -f $@ ; false)
312312

313+
quiet_cmd_lz4 = LZ4 $@
314+
cmd_lz4 = (cat $(filter-out FORCE,$^) | \
315+
lz4c -l -c1 stdin stdout && $(call size_append, $(filter-out FORCE,$^))) > $@ || \
316+
(rm -f $@ ; false)
317+
313318
# U-Boot mkimage
314319
# ---------------------------------------------------------------------------
315320

usr/Kconfig

+9
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,15 @@ config RD_LZO
9090
Support loading of a LZO encoded initial ramdisk or cpio buffer
9191
If unsure, say N.
9292

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+
93102
choice
94103
prompt "Built-in initramfs compression mode" if INITRAMFS_SOURCE!=""
95104
help

0 commit comments

Comments
 (0)