|
1 /* |
|
2 * QEMU Executable loader |
|
3 * |
|
4 * Copyright (c) 2006 Fabrice Bellard |
|
5 * |
|
6 * Permission is hereby granted, free of charge, to any person obtaining a copy |
|
7 * of this software and associated documentation files (the "Software"), to deal |
|
8 * in the Software without restriction, including without limitation the rights |
|
9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
|
10 * copies of the Software, and to permit persons to whom the Software is |
|
11 * furnished to do so, subject to the following conditions: |
|
12 * |
|
13 * The above copyright notice and this permission notice shall be included in |
|
14 * all copies or substantial portions of the Software. |
|
15 * |
|
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
|
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
|
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
|
19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
|
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
|
21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN |
|
22 * THE SOFTWARE. |
|
23 * |
|
24 * Gunzip functionality in this file is derived from u-boot: |
|
25 * |
|
26 * (C) Copyright 2008 Semihalf |
|
27 * |
|
28 * (C) Copyright 2000-2005 |
|
29 * Wolfgang Denk, DENX Software Engineering, wd@denx.de. |
|
30 * |
|
31 * This program is free software; you can redistribute it and/or |
|
32 * modify it under the terms of the GNU General Public License as |
|
33 * published by the Free Software Foundation; either version 2 of |
|
34 * the License, or (at your option) any later version. |
|
35 * |
|
36 * This program is distributed in the hope that it will be useful, |
|
37 * but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
38 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
39 * GNU General Public License for more details. |
|
40 * |
|
41 * You should have received a copy of the GNU General Public License |
|
42 * along with this program; if not, write to the Free Software |
|
43 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, |
|
44 * MA 02111-1307 USA |
|
45 */ |
|
46 |
|
47 #include "qemu-common.h" |
|
48 #include "disas.h" |
|
49 #include "sysemu.h" |
|
50 #include "uboot_image.h" |
|
51 |
|
52 #include <zlib.h> |
|
53 |
|
54 /* return the size or -1 if error */ |
|
55 int get_image_size(const char *filename) |
|
56 { |
|
57 int fd, size; |
|
58 fd = open(filename, O_RDONLY | O_BINARY); |
|
59 if (fd < 0) |
|
60 return -1; |
|
61 size = lseek(fd, 0, SEEK_END); |
|
62 close(fd); |
|
63 return size; |
|
64 } |
|
65 |
|
66 /* return the size or -1 if error */ |
|
67 /* deprecated, because caller does not specify buffer size! */ |
|
68 int load_image(const char *filename, uint8_t *addr) |
|
69 { |
|
70 int fd, size; |
|
71 fd = open(filename, O_RDONLY | O_BINARY); |
|
72 if (fd < 0) |
|
73 return -1; |
|
74 size = lseek(fd, 0, SEEK_END); |
|
75 lseek(fd, 0, SEEK_SET); |
|
76 if (read(fd, addr, size) != size) { |
|
77 close(fd); |
|
78 return -1; |
|
79 } |
|
80 close(fd); |
|
81 return size; |
|
82 } |
|
83 |
|
84 /* return the amount read, just like fread. 0 may mean error or eof */ |
|
85 int fread_targphys(target_phys_addr_t dst_addr, size_t nbytes, FILE *f) |
|
86 { |
|
87 uint8_t buf[4096]; |
|
88 target_phys_addr_t dst_begin = dst_addr; |
|
89 size_t want, did; |
|
90 |
|
91 while (nbytes) { |
|
92 want = nbytes > sizeof(buf) ? sizeof(buf) : nbytes; |
|
93 did = fread(buf, 1, want, f); |
|
94 if (did != want) break; |
|
95 |
|
96 cpu_physical_memory_write_rom(dst_addr, buf, did); |
|
97 dst_addr += did; |
|
98 nbytes -= did; |
|
99 } |
|
100 return dst_addr - dst_begin; |
|
101 } |
|
102 |
|
103 /* returns 0 on error, 1 if ok */ |
|
104 int fread_targphys_ok(target_phys_addr_t dst_addr, size_t nbytes, FILE *f) |
|
105 { |
|
106 return fread_targphys(dst_addr, nbytes, f) == nbytes; |
|
107 } |
|
108 |
|
109 /* read()-like version */ |
|
110 int read_targphys(int fd, target_phys_addr_t dst_addr, size_t nbytes) |
|
111 { |
|
112 uint8_t buf[4096]; |
|
113 target_phys_addr_t dst_begin = dst_addr; |
|
114 size_t want, did; |
|
115 |
|
116 while (nbytes) { |
|
117 want = nbytes > sizeof(buf) ? sizeof(buf) : nbytes; |
|
118 did = read(fd, buf, want); |
|
119 if (did != want) break; |
|
120 |
|
121 cpu_physical_memory_write_rom(dst_addr, buf, did); |
|
122 dst_addr += did; |
|
123 nbytes -= did; |
|
124 } |
|
125 return dst_addr - dst_begin; |
|
126 } |
|
127 |
|
128 /* return the size or -1 if error */ |
|
129 int load_image_targphys(const char *filename, |
|
130 target_phys_addr_t addr, int max_sz) |
|
131 { |
|
132 FILE *f; |
|
133 size_t got; |
|
134 |
|
135 f = fopen(filename, "rb"); |
|
136 if (!f) return -1; |
|
137 |
|
138 got = fread_targphys(addr, max_sz, f); |
|
139 if (ferror(f)) { fclose(f); return -1; } |
|
140 fclose(f); |
|
141 |
|
142 return got; |
|
143 } |
|
144 |
|
145 void pstrcpy_targphys(target_phys_addr_t dest, int buf_size, |
|
146 const char *source) |
|
147 { |
|
148 static const uint8_t nul_byte = 0; |
|
149 const char *nulp; |
|
150 |
|
151 if (buf_size <= 0) return; |
|
152 nulp = memchr(source, 0, buf_size); |
|
153 if (nulp) { |
|
154 cpu_physical_memory_write_rom(dest, (uint8_t *)source, |
|
155 (nulp - source) + 1); |
|
156 } else { |
|
157 cpu_physical_memory_write_rom(dest, (uint8_t *)source, buf_size - 1); |
|
158 cpu_physical_memory_write_rom(dest, &nul_byte, 1); |
|
159 } |
|
160 } |
|
161 |
|
162 /* A.OUT loader */ |
|
163 |
|
164 struct exec |
|
165 { |
|
166 uint32_t a_info; /* Use macros N_MAGIC, etc for access */ |
|
167 uint32_t a_text; /* length of text, in bytes */ |
|
168 uint32_t a_data; /* length of data, in bytes */ |
|
169 uint32_t a_bss; /* length of uninitialized data area, in bytes */ |
|
170 uint32_t a_syms; /* length of symbol table data in file, in bytes */ |
|
171 uint32_t a_entry; /* start address */ |
|
172 uint32_t a_trsize; /* length of relocation info for text, in bytes */ |
|
173 uint32_t a_drsize; /* length of relocation info for data, in bytes */ |
|
174 }; |
|
175 |
|
176 #ifdef BSWAP_NEEDED |
|
177 static void bswap_ahdr(struct exec *e) |
|
178 { |
|
179 bswap32s(&e->a_info); |
|
180 bswap32s(&e->a_text); |
|
181 bswap32s(&e->a_data); |
|
182 bswap32s(&e->a_bss); |
|
183 bswap32s(&e->a_syms); |
|
184 bswap32s(&e->a_entry); |
|
185 bswap32s(&e->a_trsize); |
|
186 bswap32s(&e->a_drsize); |
|
187 } |
|
188 #else |
|
189 #define bswap_ahdr(x) do { } while (0) |
|
190 #endif |
|
191 |
|
192 #define N_MAGIC(exec) ((exec).a_info & 0xffff) |
|
193 #define OMAGIC 0407 |
|
194 #define NMAGIC 0410 |
|
195 #define ZMAGIC 0413 |
|
196 #define QMAGIC 0314 |
|
197 #define _N_HDROFF(x) (1024 - sizeof (struct exec)) |
|
198 #define N_TXTOFF(x) \ |
|
199 (N_MAGIC(x) == ZMAGIC ? _N_HDROFF((x)) + sizeof (struct exec) : \ |
|
200 (N_MAGIC(x) == QMAGIC ? 0 : sizeof (struct exec))) |
|
201 #define N_TXTADDR(x) (N_MAGIC(x) == QMAGIC ? TARGET_PAGE_SIZE : 0) |
|
202 #define N_DATOFF(x) (N_TXTOFF(x) + (x).a_text) |
|
203 #define _N_SEGMENT_ROUND(x) (((x) + TARGET_PAGE_SIZE - 1) & ~(TARGET_PAGE_SIZE - 1)) |
|
204 |
|
205 #define _N_TXTENDADDR(x) (N_TXTADDR(x)+(x).a_text) |
|
206 |
|
207 #define N_DATADDR(x) \ |
|
208 (N_MAGIC(x)==OMAGIC? (_N_TXTENDADDR(x)) \ |
|
209 : (_N_SEGMENT_ROUND (_N_TXTENDADDR(x)))) |
|
210 |
|
211 |
|
212 int load_aout(const char *filename, target_phys_addr_t addr, int max_sz) |
|
213 { |
|
214 int fd, size, ret; |
|
215 struct exec e; |
|
216 uint32_t magic; |
|
217 |
|
218 fd = open(filename, O_RDONLY | O_BINARY); |
|
219 if (fd < 0) |
|
220 return -1; |
|
221 |
|
222 size = read(fd, &e, sizeof(e)); |
|
223 if (size < 0) |
|
224 goto fail; |
|
225 |
|
226 bswap_ahdr(&e); |
|
227 |
|
228 magic = N_MAGIC(e); |
|
229 switch (magic) { |
|
230 case ZMAGIC: |
|
231 case QMAGIC: |
|
232 case OMAGIC: |
|
233 if (e.a_text + e.a_data > max_sz) |
|
234 goto fail; |
|
235 lseek(fd, N_TXTOFF(e), SEEK_SET); |
|
236 size = read_targphys(fd, addr, e.a_text + e.a_data); |
|
237 if (size < 0) |
|
238 goto fail; |
|
239 break; |
|
240 case NMAGIC: |
|
241 if (N_DATADDR(e) + e.a_data > max_sz) |
|
242 goto fail; |
|
243 lseek(fd, N_TXTOFF(e), SEEK_SET); |
|
244 size = read_targphys(fd, addr, e.a_text); |
|
245 if (size < 0) |
|
246 goto fail; |
|
247 ret = read_targphys(fd, addr + N_DATADDR(e), e.a_data); |
|
248 if (ret < 0) |
|
249 goto fail; |
|
250 size += ret; |
|
251 break; |
|
252 default: |
|
253 goto fail; |
|
254 } |
|
255 close(fd); |
|
256 return size; |
|
257 fail: |
|
258 close(fd); |
|
259 return -1; |
|
260 } |
|
261 |
|
262 /* ELF loader */ |
|
263 |
|
264 static void *load_at(int fd, int offset, int size) |
|
265 { |
|
266 void *ptr; |
|
267 if (lseek(fd, offset, SEEK_SET) < 0) |
|
268 return NULL; |
|
269 ptr = qemu_malloc(size); |
|
270 if (!ptr) |
|
271 return NULL; |
|
272 if (read(fd, ptr, size) != size) { |
|
273 qemu_free(ptr); |
|
274 return NULL; |
|
275 } |
|
276 return ptr; |
|
277 } |
|
278 |
|
279 |
|
280 #define ELF_CLASS ELFCLASS32 |
|
281 #include "elf.h" |
|
282 |
|
283 #define SZ 32 |
|
284 #define elf_word uint32_t |
|
285 #define elf_sword int32_t |
|
286 #define bswapSZs bswap32s |
|
287 #include "elf_ops.h" |
|
288 |
|
289 #undef elfhdr |
|
290 #undef elf_phdr |
|
291 #undef elf_shdr |
|
292 #undef elf_sym |
|
293 #undef elf_note |
|
294 #undef elf_word |
|
295 #undef elf_sword |
|
296 #undef bswapSZs |
|
297 #undef SZ |
|
298 #define elfhdr elf64_hdr |
|
299 #define elf_phdr elf64_phdr |
|
300 #define elf_note elf64_note |
|
301 #define elf_shdr elf64_shdr |
|
302 #define elf_sym elf64_sym |
|
303 #define elf_word uint64_t |
|
304 #define elf_sword int64_t |
|
305 #define bswapSZs bswap64s |
|
306 #define SZ 64 |
|
307 #include "elf_ops.h" |
|
308 |
|
309 /* return < 0 if error, otherwise the number of bytes loaded in memory */ |
|
310 int load_elf(const char *filename, int64_t address_offset, |
|
311 uint64_t *pentry, uint64_t *lowaddr, uint64_t *highaddr) |
|
312 { |
|
313 int fd, data_order, host_data_order, must_swab, ret; |
|
314 uint8_t e_ident[EI_NIDENT]; |
|
315 |
|
316 fd = open(filename, O_RDONLY | O_BINARY); |
|
317 if (fd < 0) { |
|
318 perror(filename); |
|
319 return -1; |
|
320 } |
|
321 if (read(fd, e_ident, sizeof(e_ident)) != sizeof(e_ident)) |
|
322 goto fail; |
|
323 if (e_ident[0] != ELFMAG0 || |
|
324 e_ident[1] != ELFMAG1 || |
|
325 e_ident[2] != ELFMAG2 || |
|
326 e_ident[3] != ELFMAG3) |
|
327 goto fail; |
|
328 #ifdef WORDS_BIGENDIAN |
|
329 data_order = ELFDATA2MSB; |
|
330 #else |
|
331 data_order = ELFDATA2LSB; |
|
332 #endif |
|
333 must_swab = data_order != e_ident[EI_DATA]; |
|
334 |
|
335 #ifdef TARGET_WORDS_BIGENDIAN |
|
336 host_data_order = ELFDATA2MSB; |
|
337 #else |
|
338 host_data_order = ELFDATA2LSB; |
|
339 #endif |
|
340 if (host_data_order != e_ident[EI_DATA]) |
|
341 return -1; |
|
342 |
|
343 lseek(fd, 0, SEEK_SET); |
|
344 if (e_ident[EI_CLASS] == ELFCLASS64) { |
|
345 ret = load_elf64(fd, address_offset, must_swab, pentry, |
|
346 lowaddr, highaddr); |
|
347 } else { |
|
348 ret = load_elf32(fd, address_offset, must_swab, pentry, |
|
349 lowaddr, highaddr); |
|
350 } |
|
351 |
|
352 close(fd); |
|
353 return ret; |
|
354 |
|
355 fail: |
|
356 close(fd); |
|
357 return -1; |
|
358 } |
|
359 |
|
360 static void bswap_uboot_header(uboot_image_header_t *hdr) |
|
361 { |
|
362 #ifndef WORDS_BIGENDIAN |
|
363 bswap32s(&hdr->ih_magic); |
|
364 bswap32s(&hdr->ih_hcrc); |
|
365 bswap32s(&hdr->ih_time); |
|
366 bswap32s(&hdr->ih_size); |
|
367 bswap32s(&hdr->ih_load); |
|
368 bswap32s(&hdr->ih_ep); |
|
369 bswap32s(&hdr->ih_dcrc); |
|
370 #endif |
|
371 } |
|
372 |
|
373 |
|
374 #define ZALLOC_ALIGNMENT 16 |
|
375 |
|
376 static void *zalloc(void *x, unsigned items, unsigned size) |
|
377 { |
|
378 void *p; |
|
379 |
|
380 size *= items; |
|
381 size = (size + ZALLOC_ALIGNMENT - 1) & ~(ZALLOC_ALIGNMENT - 1); |
|
382 |
|
383 p = qemu_malloc(size); |
|
384 |
|
385 return (p); |
|
386 } |
|
387 |
|
388 static void zfree(void *x, void *addr, unsigned nb) |
|
389 { |
|
390 qemu_free(addr); |
|
391 } |
|
392 |
|
393 |
|
394 #define HEAD_CRC 2 |
|
395 #define EXTRA_FIELD 4 |
|
396 #define ORIG_NAME 8 |
|
397 #define COMMENT 0x10 |
|
398 #define RESERVED 0xe0 |
|
399 |
|
400 #define DEFLATED 8 |
|
401 |
|
402 /* This is the maximum in uboot, so if a uImage overflows this, it would |
|
403 * overflow on real hardware too. */ |
|
404 #define UBOOT_MAX_GUNZIP_BYTES 0x800000 |
|
405 |
|
406 static ssize_t gunzip(void *dst, size_t dstlen, uint8_t *src, |
|
407 size_t srclen) |
|
408 { |
|
409 z_stream s; |
|
410 ssize_t dstbytes; |
|
411 int r, i, flags; |
|
412 |
|
413 /* skip header */ |
|
414 i = 10; |
|
415 flags = src[3]; |
|
416 if (src[2] != DEFLATED || (flags & RESERVED) != 0) { |
|
417 puts ("Error: Bad gzipped data\n"); |
|
418 return -1; |
|
419 } |
|
420 if ((flags & EXTRA_FIELD) != 0) |
|
421 i = 12 + src[10] + (src[11] << 8); |
|
422 if ((flags & ORIG_NAME) != 0) |
|
423 while (src[i++] != 0) |
|
424 ; |
|
425 if ((flags & COMMENT) != 0) |
|
426 while (src[i++] != 0) |
|
427 ; |
|
428 if ((flags & HEAD_CRC) != 0) |
|
429 i += 2; |
|
430 if (i >= srclen) { |
|
431 puts ("Error: gunzip out of data in header\n"); |
|
432 return -1; |
|
433 } |
|
434 |
|
435 s.zalloc = zalloc; |
|
436 s.zfree = (free_func)zfree; |
|
437 |
|
438 r = inflateInit2(&s, -MAX_WBITS); |
|
439 if (r != Z_OK) { |
|
440 printf ("Error: inflateInit2() returned %d\n", r); |
|
441 return (-1); |
|
442 } |
|
443 s.next_in = src + i; |
|
444 s.avail_in = srclen - i; |
|
445 s.next_out = dst; |
|
446 s.avail_out = dstlen; |
|
447 r = inflate(&s, Z_FINISH); |
|
448 if (r != Z_OK && r != Z_STREAM_END) { |
|
449 printf ("Error: inflate() returned %d\n", r); |
|
450 return -1; |
|
451 } |
|
452 dstbytes = s.next_out - (unsigned char *) dst; |
|
453 inflateEnd(&s); |
|
454 |
|
455 return dstbytes; |
|
456 } |
|
457 |
|
458 /* Load a U-Boot image. */ |
|
459 int load_uimage(const char *filename, target_ulong *ep, target_ulong *loadaddr, |
|
460 int *is_linux) |
|
461 { |
|
462 int fd; |
|
463 int size; |
|
464 uboot_image_header_t h; |
|
465 uboot_image_header_t *hdr = &h; |
|
466 uint8_t *data = NULL; |
|
467 int ret = -1; |
|
468 |
|
469 fd = open(filename, O_RDONLY | O_BINARY); |
|
470 if (fd < 0) |
|
471 return -1; |
|
472 |
|
473 size = read(fd, hdr, sizeof(uboot_image_header_t)); |
|
474 if (size < 0) |
|
475 goto out; |
|
476 |
|
477 bswap_uboot_header(hdr); |
|
478 |
|
479 if (hdr->ih_magic != IH_MAGIC) |
|
480 goto out; |
|
481 |
|
482 /* TODO: Implement other image types. */ |
|
483 if (hdr->ih_type != IH_TYPE_KERNEL) { |
|
484 fprintf(stderr, "Can only load u-boot image type \"kernel\"\n"); |
|
485 goto out; |
|
486 } |
|
487 |
|
488 switch (hdr->ih_comp) { |
|
489 case IH_COMP_NONE: |
|
490 case IH_COMP_GZIP: |
|
491 break; |
|
492 default: |
|
493 fprintf(stderr, |
|
494 "Unable to load u-boot images with compression type %d\n", |
|
495 hdr->ih_comp); |
|
496 goto out; |
|
497 } |
|
498 |
|
499 /* TODO: Check CPU type. */ |
|
500 if (is_linux) { |
|
501 if (hdr->ih_os == IH_OS_LINUX) |
|
502 *is_linux = 1; |
|
503 else |
|
504 *is_linux = 0; |
|
505 } |
|
506 |
|
507 *ep = hdr->ih_ep; |
|
508 data = qemu_malloc(hdr->ih_size); |
|
509 if (!data) |
|
510 goto out; |
|
511 |
|
512 if (read(fd, data, hdr->ih_size) != hdr->ih_size) { |
|
513 fprintf(stderr, "Error reading file\n"); |
|
514 goto out; |
|
515 } |
|
516 |
|
517 if (hdr->ih_comp == IH_COMP_GZIP) { |
|
518 uint8_t *compressed_data; |
|
519 size_t max_bytes; |
|
520 ssize_t bytes; |
|
521 |
|
522 compressed_data = data; |
|
523 max_bytes = UBOOT_MAX_GUNZIP_BYTES; |
|
524 data = qemu_malloc(max_bytes); |
|
525 |
|
526 bytes = gunzip(data, max_bytes, compressed_data, hdr->ih_size); |
|
527 qemu_free(compressed_data); |
|
528 if (bytes < 0) { |
|
529 fprintf(stderr, "Unable to decompress gzipped image!\n"); |
|
530 goto out; |
|
531 } |
|
532 hdr->ih_size = bytes; |
|
533 } |
|
534 |
|
535 cpu_physical_memory_write_rom(hdr->ih_load, data, hdr->ih_size); |
|
536 |
|
537 if (loadaddr) |
|
538 *loadaddr = hdr->ih_load; |
|
539 |
|
540 ret = hdr->ih_size; |
|
541 |
|
542 out: |
|
543 if (data) |
|
544 qemu_free(data); |
|
545 close(fd); |
|
546 return ret; |
|
547 } |