debuggers.hg

view xen/common/unlzo.c @ 21663:d8333666361d

x86: allow LZO compressed bzImage to be used as Dom0 kernel

... since recently Linux added this as another kernel compression
method, and we already have LZO compression in the tree (from tmem),
so that only glue logic is needed.

Signed-off-by: Jan Beulich <jbeulich@novell.com>
author Keir Fraser <keir.fraser@citrix.com>
date Tue Jun 15 13:19:33 2010 +0100 (2010-06-15)
parents
children
line source
1 /*
2 * LZO decompressor for the Linux kernel. Code borrowed from the lzo
3 * implementation by Markus Franz Xaver Johannes Oberhumer.
4 *
5 * Linux kernel adaptation:
6 * Copyright (C) 2009
7 * Albin Tonnerre, Free Electrons <albin.tonnerre@free-electrons.com>
8 *
9 * Original code:
10 * Copyright (C) 1996-2005 Markus Franz Xaver Johannes Oberhumer
11 * All Rights Reserved.
12 *
13 * lzop and the LZO library are free software; you can redistribute them
14 * and/or modify them under the terms of the GNU General Public License as
15 * published by the Free Software Foundation; either version 2 of
16 * the License, or (at your option) any later version.
17 *
18 * This program is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU General Public License for more details.
22 *
23 * You should have received a copy of the GNU General Public License
24 * along with this program; see the file COPYING.
25 * If not, write to the Free Software Foundation, Inc.,
26 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
27 *
28 * Markus F.X.J. Oberhumer
29 * <markus@oberhumer.com>
30 * http://www.oberhumer.com/opensource/lzop/
31 */
33 #include "decompress.h"
34 #include <xen/lzo.h>
35 #include <asm/byteorder.h>
37 #if 1 /* ndef CONFIG_??? */
38 static inline u16 INIT get_unaligned_be16(void *p)
39 {
40 return be16_to_cpup(p);
41 }
43 static inline u32 INIT get_unaligned_be32(void *p)
44 {
45 return be32_to_cpup(p);
46 }
47 #else
48 #include <asm/unaligned.h>
50 static inline u16 INIT get_unaligned_be16(void *p)
51 {
52 return be16_to_cpu(__get_unaligned(p, 2));
53 }
55 static inline u32 INIT get_unaligned_be32(void *p)
56 {
57 return be32_to_cpu(__get_unaligned(p, 4));
58 }
59 #endif
61 static const unsigned char lzop_magic[] = {
62 0x89, 0x4c, 0x5a, 0x4f, 0x00, 0x0d, 0x0a, 0x1a, 0x0a };
64 #define LZO_BLOCK_SIZE (256*1024l)
65 #define HEADER_HAS_FILTER 0x00000800L
67 static int INIT parse_header(u8 *input, u8 *skip)
68 {
69 int l;
70 u8 *parse = input;
71 u8 level = 0;
72 u16 version;
74 /* read magic: 9 first bits */
75 for (l = 0; l < 9; l++) {
76 if (*parse++ != lzop_magic[l])
77 return 0;
78 }
79 /* get version (2bytes), skip library version (2),
80 * 'need to be extracted' version (2) and
81 * method (1) */
82 version = get_unaligned_be16(parse);
83 parse += 7;
84 if (version >= 0x0940)
85 level = *parse++;
86 if (get_unaligned_be32(parse) & HEADER_HAS_FILTER)
87 parse += 8; /* flags + filter info */
88 else
89 parse += 4; /* flags */
91 /* skip mode and mtime_low */
92 parse += 8;
93 if (version >= 0x0940)
94 parse += 4; /* skip mtime_high */
96 l = *parse++;
97 /* don't care about the file name, and skip checksum */
98 parse += l + 4;
100 *skip = parse - input;
101 return 1;
102 }
104 STATIC int INIT unlzo(u8 *input, unsigned int in_len,
105 int (*fill) (void *, unsigned int),
106 int (*flush) (void *, unsigned int),
107 u8 *output, unsigned int *posp,
108 void (*error_fn) (const char *x))
109 {
110 u8 skip = 0, r = 0;
111 u32 src_len, dst_len;
112 size_t tmp;
113 u8 *in_buf, *in_buf_save, *out_buf;
114 int ret = -1;
116 set_error_fn(error_fn);
118 if (output) {
119 out_buf = output;
120 } else if (!flush) {
121 error("NULL output pointer and no flush function provided");
122 goto exit;
123 } else {
124 out_buf = malloc(LZO_BLOCK_SIZE);
125 if (!out_buf) {
126 error("Could not allocate output buffer");
127 goto exit;
128 }
129 }
131 if (input && fill) {
132 error("Both input pointer and fill function provided, don't know what to do");
133 goto exit_1;
134 } else if (input) {
135 in_buf = input;
136 } else if (!fill || !posp) {
137 error("NULL input pointer and missing position pointer or fill function");
138 goto exit_1;
139 } else {
140 in_buf = malloc(lzo1x_worst_compress(LZO_BLOCK_SIZE));
141 if (!in_buf) {
142 error("Could not allocate input buffer");
143 goto exit_1;
144 }
145 }
146 in_buf_save = in_buf;
148 if (posp)
149 *posp = 0;
151 if (fill)
152 fill(in_buf, lzo1x_worst_compress(LZO_BLOCK_SIZE));
154 if (!parse_header(input, &skip)) {
155 error("invalid header");
156 goto exit_2;
157 }
158 in_buf += skip;
160 if (posp)
161 *posp = skip;
163 for (;;) {
164 /* read uncompressed block size */
165 dst_len = get_unaligned_be32(in_buf);
166 in_buf += 4;
168 /* exit if last block */
169 if (dst_len == 0) {
170 if (posp)
171 *posp += 4;
172 break;
173 }
175 if (dst_len > LZO_BLOCK_SIZE) {
176 error("dest len longer than block size");
177 goto exit_2;
178 }
180 /* read compressed block size, and skip block checksum info */
181 src_len = get_unaligned_be32(in_buf);
182 in_buf += 8;
184 if (src_len <= 0 || src_len > dst_len) {
185 error("file corrupted");
186 goto exit_2;
187 }
189 /* decompress */
190 tmp = dst_len;
192 /* When the input data is not compressed at all,
193 * lzo1x_decompress_safe will fail, so call memcpy()
194 * instead */
195 if (unlikely(dst_len == src_len))
196 memcpy(out_buf, in_buf, src_len);
197 else {
198 r = lzo1x_decompress_safe(in_buf, src_len,
199 out_buf, &tmp);
201 if (r != LZO_E_OK || dst_len != tmp) {
202 error("Compressed data violation");
203 goto exit_2;
204 }
205 }
207 if (flush)
208 flush(out_buf, dst_len);
209 if (output)
210 out_buf += dst_len;
211 if (posp)
212 *posp += src_len + 12;
213 if (fill) {
214 in_buf = in_buf_save;
215 fill(in_buf, lzo1x_worst_compress(LZO_BLOCK_SIZE));
216 } else
217 in_buf += src_len;
218 }
220 ret = 0;
221 exit_2:
222 if (!input)
223 free(in_buf);
224 exit_1:
225 if (!output)
226 free(out_buf);
227 exit:
228 return ret;
229 }