debuggers.hg

view tools/libxc/xc_dom_bzimageloader.c @ 21067:b4a1832a916f

Update Xen version to 4.0.0-rc6
author Keir Fraser <keir.fraser@citrix.com>
date Tue Mar 09 18:18:05 2010 +0000 (2010-03-09)
parents 95f01bfd2667
children 3ffdb094c2c0 779c0ef9682c
line source
1 /*
2 * Xen domain builder -- bzImage bits
3 *
4 * Parse and load bzImage kernel images.
5 *
6 * This relies on version 2.08 of the boot protocol, which contains an
7 * ELF file embedded in the bzImage. The loader extracts this ELF
8 * image and passes it off to the standard ELF loader.
9 *
10 * This code is licenced under the GPL.
11 * written 2006 by Gerd Hoffmann <kraxel@suse.de>.
12 * written 2007 by Jeremy Fitzhardinge <jeremy@xensource.com>
13 * written 2008 by Ian Campbell <ijc@hellion.org.uk>
14 * written 2009 by Chris Lalancette <clalance@redhat.com>
15 *
16 */
17 #include <stdio.h>
18 #include <stdlib.h>
19 #include <inttypes.h>
21 #include "xg_private.h"
22 #include "xc_dom.h"
24 #if defined(HAVE_BZLIB)
26 #include <bzlib.h>
28 static int xc_try_bzip2_decode(
29 struct xc_dom_image *dom, void **blob, size_t *size)
30 {
31 bz_stream stream;
32 int ret;
33 char *out_buf;
34 char *tmp_buf;
35 int retval = -1;
36 int outsize;
37 uint64_t total;
39 stream.bzalloc = NULL;
40 stream.bzfree = NULL;
41 stream.opaque = NULL;
43 ret = BZ2_bzDecompressInit(&stream, 0, 0);
44 if ( ret != BZ_OK )
45 {
46 xc_dom_printf("BZIP2: Error initting stream\n");
47 return -1;
48 }
50 /* sigh. We don't know up-front how much memory we are going to need
51 * for the output buffer. Allocate the output buffer to be equal
52 * the input buffer to start, and we'll realloc as needed.
53 */
54 outsize = dom->kernel_size;
55 out_buf = malloc(outsize);
56 if ( out_buf == NULL )
57 {
58 xc_dom_printf("BZIP2: Failed to alloc memory\n");
59 goto bzip2_cleanup;
60 }
62 stream.next_in = dom->kernel_blob;
63 stream.avail_in = dom->kernel_size;
65 stream.next_out = out_buf;
66 stream.avail_out = dom->kernel_size;
68 for ( ; ; )
69 {
70 ret = BZ2_bzDecompress(&stream);
71 if ( (stream.avail_out == 0) || (ret != BZ_OK) )
72 {
73 tmp_buf = realloc(out_buf, outsize * 2);
74 if ( tmp_buf == NULL )
75 {
76 xc_dom_printf("BZIP2: Failed to realloc memory\n");
77 free(out_buf);
78 goto bzip2_cleanup;
79 }
80 out_buf = tmp_buf;
82 stream.next_out = out_buf + outsize;
83 stream.avail_out = (outsize * 2) - outsize;
84 outsize *= 2;
85 }
87 if ( ret != BZ_OK )
88 {
89 if ( ret == BZ_STREAM_END )
90 {
91 xc_dom_printf("BZIP2: Saw data stream end\n");
92 retval = 0;
93 break;
94 }
95 xc_dom_printf("BZIP2: error\n");
96 }
97 }
99 total = (((uint64_t)stream.total_out_hi32) << 32) | stream.total_out_lo32;
101 xc_dom_printf("%s: BZIP2 decompress OK, 0x%zx -> 0x%lx\n",
102 __FUNCTION__, *size, (long unsigned int) total);
104 *blob = out_buf;
105 *size = total;
107 bzip2_cleanup:
108 BZ2_bzDecompressEnd(&stream);
110 return retval;
111 }
113 #else /* !defined(HAVE_BZLIB) */
115 static int xc_try_bzip2_decode(
116 struct xc_dom_image *dom, void **blob, size_t *size)
117 {
118 xc_dom_printf("%s: BZIP2 decompress support unavailable\n",
119 __FUNCTION__);
120 return -1;
121 }
123 #endif
125 #if defined(HAVE_LZMA)
127 #include <lzma.h>
129 static uint64_t physmem(void)
130 {
131 uint64_t ret = 0;
132 const long pagesize = sysconf(_SC_PAGESIZE);
133 const long pages = sysconf(_SC_PHYS_PAGES);
135 if ( (pagesize != -1) || (pages != -1) )
136 {
137 /*
138 * According to docs, pagesize * pages can overflow.
139 * Simple case is 32-bit box with 4 GiB or more RAM,
140 * which may report exactly 4 GiB of RAM, and "long"
141 * being 32-bit will overflow. Casting to uint64_t
142 * hopefully avoids overflows in the near future.
143 */
144 ret = (uint64_t)(pagesize) * (uint64_t)(pages);
145 }
147 return ret;
148 }
150 static int xc_try_lzma_decode(
151 struct xc_dom_image *dom, void **blob, size_t *size)
152 {
153 lzma_stream stream = LZMA_STREAM_INIT;
154 lzma_ret ret;
155 lzma_action action = LZMA_RUN;
156 unsigned char *out_buf;
157 unsigned char *tmp_buf;
158 int retval = -1;
159 int outsize;
160 const char *msg;
162 ret = lzma_alone_decoder(&stream, physmem() / 3);
163 if ( ret != LZMA_OK )
164 {
165 xc_dom_printf("LZMA: Failed to init stream decoder\n");
166 return -1;
167 }
169 /* sigh. We don't know up-front how much memory we are going to need
170 * for the output buffer. Allocate the output buffer to be equal
171 * the input buffer to start, and we'll realloc as needed.
172 */
173 outsize = dom->kernel_size;
174 out_buf = malloc(outsize);
175 if ( out_buf == NULL )
176 {
177 xc_dom_printf("LZMA: Failed to alloc memory\n");
178 goto lzma_cleanup;
179 }
181 stream.next_in = dom->kernel_blob;
182 stream.avail_in = dom->kernel_size;
184 stream.next_out = out_buf;
185 stream.avail_out = dom->kernel_size;
187 for ( ; ; )
188 {
189 ret = lzma_code(&stream, action);
190 if ( (stream.avail_out == 0) || (ret != LZMA_OK) )
191 {
192 tmp_buf = realloc(out_buf, outsize * 2);
193 if ( tmp_buf == NULL )
194 {
195 xc_dom_printf("LZMA: Failed to realloc memory\n");
196 free(out_buf);
197 goto lzma_cleanup;
198 }
199 out_buf = tmp_buf;
201 stream.next_out = out_buf + outsize;
202 stream.avail_out = (outsize * 2) - outsize;
203 outsize *= 2;
204 }
206 if ( ret != LZMA_OK )
207 {
208 if ( ret == LZMA_STREAM_END )
209 {
210 xc_dom_printf("LZMA: Saw data stream end\n");
211 retval = 0;
212 break;
213 }
215 switch ( ret )
216 {
217 case LZMA_MEM_ERROR:
218 msg = strerror(ENOMEM);
219 break;
221 case LZMA_MEMLIMIT_ERROR:
222 msg = "Memory usage limit reached";
223 break;
225 case LZMA_FORMAT_ERROR:
226 msg = "File format not recognized";
227 break;
229 case LZMA_OPTIONS_ERROR:
230 // FIXME: Better message?
231 msg = "Unsupported compression options";
232 break;
234 case LZMA_DATA_ERROR:
235 msg = "File is corrupt";
236 break;
238 case LZMA_BUF_ERROR:
239 msg = "Unexpected end of input";
240 break;
242 default:
243 msg = "Internal program error (bug)";
244 break;
245 }
246 xc_dom_printf("%s: LZMA decompression error %s\n",
247 __FUNCTION__, msg);
248 break;
249 }
250 }
252 xc_dom_printf("%s: LZMA decompress OK, 0x%zx -> 0x%zx\n",
253 __FUNCTION__, *size, (size_t)stream.total_out);
255 *blob = out_buf;
256 *size = stream.total_out;
258 lzma_cleanup:
259 lzma_end(&stream);
261 return retval;
262 }
264 #else /* !defined(HAVE_LZMA) */
266 static int xc_try_lzma_decode(
267 struct xc_dom_image *dom, void **blob, size_t *size)
268 {
269 xc_dom_printf("%s: LZMA decompress support unavailable\n",
270 __FUNCTION__);
271 return -1;
272 }
274 #endif
276 struct setup_header {
277 uint8_t _pad0[0x1f1]; /* skip uninteresting stuff */
278 uint8_t setup_sects;
279 uint16_t root_flags;
280 uint32_t syssize;
281 uint16_t ram_size;
282 uint16_t vid_mode;
283 uint16_t root_dev;
284 uint16_t boot_flag;
285 uint16_t jump;
286 uint32_t header;
287 #define HDR_MAGIC "HdrS"
288 #define HDR_MAGIC_SZ 4
289 uint16_t version;
290 #define VERSION(h,l) (((h)<<8) | (l))
291 uint32_t realmode_swtch;
292 uint16_t start_sys;
293 uint16_t kernel_version;
294 uint8_t type_of_loader;
295 uint8_t loadflags;
296 uint16_t setup_move_size;
297 uint32_t code32_start;
298 uint32_t ramdisk_image;
299 uint32_t ramdisk_size;
300 uint32_t bootsect_kludge;
301 uint16_t heap_end_ptr;
302 uint16_t _pad1;
303 uint32_t cmd_line_ptr;
304 uint32_t initrd_addr_max;
305 uint32_t kernel_alignment;
306 uint8_t relocatable_kernel;
307 uint8_t _pad2[3];
308 uint32_t cmdline_size;
309 uint32_t hardware_subarch;
310 uint64_t hardware_subarch_data;
311 uint32_t payload_offset;
312 uint32_t payload_length;
313 } __attribute__((packed));
315 extern struct xc_dom_loader elf_loader;
317 static unsigned int payload_offset(struct setup_header *hdr)
318 {
319 unsigned int off;
321 off = (hdr->setup_sects + 1) * 512;
322 off += hdr->payload_offset;
323 return off;
324 }
326 static int xc_dom_probe_bzimage_kernel(struct xc_dom_image *dom)
327 {
328 struct setup_header *hdr;
329 int ret;
331 if ( dom->kernel_blob == NULL )
332 {
333 xc_dom_panic(XC_INTERNAL_ERROR, "%s: no kernel image loaded\n",
334 __FUNCTION__);
335 return -EINVAL;
336 }
338 if ( dom->kernel_size < sizeof(struct setup_header) )
339 {
340 xc_dom_panic(XC_INTERNAL_ERROR, "%s: kernel image too small\n",
341 __FUNCTION__);
342 return -EINVAL;
343 }
345 hdr = dom->kernel_blob;
347 if ( memcmp(&hdr->header, HDR_MAGIC, HDR_MAGIC_SZ) != 0 )
348 {
349 xc_dom_panic(XC_INVALID_KERNEL, "%s: kernel is not a bzImage\n",
350 __FUNCTION__);
351 return -EINVAL;
352 }
354 if ( hdr->version < VERSION(2,8) )
355 {
356 xc_dom_panic(XC_INVALID_KERNEL, "%s: boot protocol too old (%04x)\n",
357 __FUNCTION__, hdr->version);
358 return -EINVAL;
359 }
361 dom->kernel_blob = dom->kernel_blob + payload_offset(hdr);
362 dom->kernel_size = hdr->payload_length;
364 if ( memcmp(dom->kernel_blob, "\037\213", 2) == 0 )
365 {
366 ret = xc_dom_try_gunzip(dom, &dom->kernel_blob, &dom->kernel_size);
367 if ( ret == -1 )
368 {
369 xc_dom_panic(XC_INVALID_KERNEL,
370 "%s: unable to gzip decompress kernel\n",
371 __FUNCTION__);
372 return -EINVAL;
373 }
374 }
375 else if ( memcmp(dom->kernel_blob, "\102\132\150", 3) == 0 )
376 {
377 ret = xc_try_bzip2_decode(dom, &dom->kernel_blob, &dom->kernel_size);
378 if ( ret < 0 )
379 {
380 xc_dom_panic(XC_INVALID_KERNEL,
381 "%s unable to BZIP2 decompress kernel",
382 __FUNCTION__);
383 return -EINVAL;
384 }
385 }
386 else if ( memcmp(dom->kernel_blob, "\135\000", 2) == 0 )
387 {
388 ret = xc_try_lzma_decode(dom, &dom->kernel_blob, &dom->kernel_size);
389 if ( ret < 0 )
390 {
391 xc_dom_panic(XC_INVALID_KERNEL,
392 "%s unable to LZMA decompress kernel\n",
393 __FUNCTION__);
394 return -EINVAL;
395 }
396 }
397 else
398 {
399 xc_dom_panic(XC_INVALID_KERNEL, "%s: unknown compression format\n",
400 __FUNCTION__);
401 return -EINVAL;
402 }
404 return elf_loader.probe(dom);
405 }
407 static int xc_dom_parse_bzimage_kernel(struct xc_dom_image *dom)
408 {
409 return elf_loader.parser(dom);
410 }
412 static int xc_dom_load_bzimage_kernel(struct xc_dom_image *dom)
413 {
414 return elf_loader.loader(dom);
415 }
417 static struct xc_dom_loader bzimage_loader = {
418 .name = "Linux bzImage",
419 .probe = xc_dom_probe_bzimage_kernel,
420 .parser = xc_dom_parse_bzimage_kernel,
421 .loader = xc_dom_load_bzimage_kernel,
422 };
424 static void __init register_loader(void)
425 {
426 xc_dom_register_loader(&bzimage_loader);
427 }
429 /*
430 * Local variables:
431 * mode: C
432 * c-set-style: "BSD"
433 * c-basic-offset: 4
434 * tab-width: 4
435 * indent-tabs-mode: nil
436 * End:
437 */