aboutsummaryrefslogtreecommitdiffstats
path: root/lib
diff options
context:
space:
mode:
authorKyungsik Lee <kyungsik.lee@lge.com>2013-07-08 19:01:46 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2013-07-09 13:33:30 -0400
commite76e1fdfa8f8dc1ea6699923cf5d92b5bee9c936 (patch)
treed216233bcf256a8a3d8912cebbbf82032bb7b715 /lib
parentcffb78b0e0b3a30b059b27a1d97500cf6464efa9 (diff)
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>
Diffstat (limited to 'lib')
-rw-r--r--lib/Kconfig7
-rw-r--r--lib/Makefile2
-rw-r--r--lib/decompress.c5
-rw-r--r--lib/decompress_unlz4.c187
-rw-r--r--lib/lz4/Makefile1
-rw-r--r--lib/lz4/lz4_decompress.c2
6 files changed, 203 insertions, 1 deletions
diff --git a/lib/Kconfig b/lib/Kconfig
index f1ed53c3aa44..e9cdc8ffdcee 100644
--- a/lib/Kconfig
+++ b/lib/Kconfig
@@ -194,6 +194,9 @@ config LZO_COMPRESS
194config LZO_DECOMPRESS 194config LZO_DECOMPRESS
195 tristate 195 tristate
196 196
197config LZ4_DECOMPRESS
198 tristate
199
197source "lib/xz/Kconfig" 200source "lib/xz/Kconfig"
198 201
199# 202#
@@ -218,6 +221,10 @@ config DECOMPRESS_LZO
218 select LZO_DECOMPRESS 221 select LZO_DECOMPRESS
219 tristate 222 tristate
220 223
224config DECOMPRESS_LZ4
225 select LZ4_DECOMPRESS
226 tristate
227
221# 228#
222# Generic allocator support is selected if needed 229# Generic allocator support is selected if needed
223# 230#
diff --git a/lib/Makefile b/lib/Makefile
index 9afb4f745e8f..326f6c7e6db1 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -75,6 +75,7 @@ obj-$(CONFIG_REED_SOLOMON) += reed_solomon/
75obj-$(CONFIG_BCH) += bch.o 75obj-$(CONFIG_BCH) += bch.o
76obj-$(CONFIG_LZO_COMPRESS) += lzo/ 76obj-$(CONFIG_LZO_COMPRESS) += lzo/
77obj-$(CONFIG_LZO_DECOMPRESS) += lzo/ 77obj-$(CONFIG_LZO_DECOMPRESS) += lzo/
78obj-$(CONFIG_LZ4_DECOMPRESS) += lz4/
78obj-$(CONFIG_XZ_DEC) += xz/ 79obj-$(CONFIG_XZ_DEC) += xz/
79obj-$(CONFIG_RAID6_PQ) += raid6/ 80obj-$(CONFIG_RAID6_PQ) += raid6/
80 81
@@ -83,6 +84,7 @@ lib-$(CONFIG_DECOMPRESS_BZIP2) += decompress_bunzip2.o
83lib-$(CONFIG_DECOMPRESS_LZMA) += decompress_unlzma.o 84lib-$(CONFIG_DECOMPRESS_LZMA) += decompress_unlzma.o
84lib-$(CONFIG_DECOMPRESS_XZ) += decompress_unxz.o 85lib-$(CONFIG_DECOMPRESS_XZ) += decompress_unxz.o
85lib-$(CONFIG_DECOMPRESS_LZO) += decompress_unlzo.o 86lib-$(CONFIG_DECOMPRESS_LZO) += decompress_unlzo.o
87lib-$(CONFIG_DECOMPRESS_LZ4) += decompress_unlz4.o
86 88
87obj-$(CONFIG_TEXTSEARCH) += textsearch.o 89obj-$(CONFIG_TEXTSEARCH) += textsearch.o
88obj-$(CONFIG_TEXTSEARCH_KMP) += ts_kmp.o 90obj-$(CONFIG_TEXTSEARCH_KMP) += ts_kmp.o
diff --git a/lib/decompress.c b/lib/decompress.c
index f8fdedaf7b3d..4d1cd0397aab 100644
--- a/lib/decompress.c
+++ b/lib/decompress.c
@@ -11,6 +11,7 @@
11#include <linux/decompress/unxz.h> 11#include <linux/decompress/unxz.h>
12#include <linux/decompress/inflate.h> 12#include <linux/decompress/inflate.h>
13#include <linux/decompress/unlzo.h> 13#include <linux/decompress/unlzo.h>
14#include <linux/decompress/unlz4.h>
14 15
15#include <linux/types.h> 16#include <linux/types.h>
16#include <linux/string.h> 17#include <linux/string.h>
@@ -31,6 +32,9 @@
31#ifndef CONFIG_DECOMPRESS_LZO 32#ifndef CONFIG_DECOMPRESS_LZO
32# define unlzo NULL 33# define unlzo NULL
33#endif 34#endif
35#ifndef CONFIG_DECOMPRESS_LZ4
36# define unlz4 NULL
37#endif
34 38
35struct compress_format { 39struct compress_format {
36 unsigned char magic[2]; 40 unsigned char magic[2];
@@ -45,6 +49,7 @@ static const struct compress_format compressed_formats[] __initconst = {
45 { {0x5d, 0x00}, "lzma", unlzma }, 49 { {0x5d, 0x00}, "lzma", unlzma },
46 { {0xfd, 0x37}, "xz", unxz }, 50 { {0xfd, 0x37}, "xz", unxz },
47 { {0x89, 0x4c}, "lzo", unlzo }, 51 { {0x89, 0x4c}, "lzo", unlzo },
52 { {0x02, 0x21}, "lz4", unlz4 },
48 { {0, 0}, NULL, NULL } 53 { {0, 0}, NULL, NULL }
49}; 54};
50 55
diff --git a/lib/decompress_unlz4.c b/lib/decompress_unlz4.c
new file mode 100644
index 000000000000..3e67cfad16ad
--- /dev/null
+++ b/lib/decompress_unlz4.c
@@ -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
34STATIC 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;
166exit_2:
167 if (!input)
168 large_free(inp_start);
169exit_1:
170 if (!output)
171 large_free(outp);
172exit_0:
173 return ret;
174}
175
176#ifdef PREBOOT
177STATIC 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
diff --git a/lib/lz4/Makefile b/lib/lz4/Makefile
new file mode 100644
index 000000000000..7f548c6d1c5c
--- /dev/null
+++ b/lib/lz4/Makefile
@@ -0,0 +1 @@
obj-$(CONFIG_LZ4_DECOMPRESS) += lz4_decompress.o
diff --git a/lib/lz4/lz4_decompress.c b/lib/lz4/lz4_decompress.c
index dcc89753af65..d3414eae73a1 100644
--- a/lib/lz4/lz4_decompress.c
+++ b/lib/lz4/lz4_decompress.c
@@ -1,7 +1,7 @@
1/* 1/*
2 * LZ4 Decompressor for Linux kernel 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 * Based on LZ4 implementation by Yann Collet. 6 * Based on LZ4 implementation by Yann Collet.
7 * 7 *