2 * QEMU Executable loader
4 * Copyright (c) 2006 Fabrice Bellard
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:
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
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
24 #include "qemu-common.h"
27 #include "uboot_image.h"
31 /* return the size or -1 if error */
32 int get_image_size(const char *filename
)
35 fd
= open(filename
, O_RDONLY
| O_BINARY
);
38 size
= lseek(fd
, 0, SEEK_END
);
43 /* return the size or -1 if error */
44 int load_image(const char *filename
, uint8_t *addr
)
47 fd
= open(filename
, O_RDONLY
| O_BINARY
);
50 size
= lseek(fd
, 0, SEEK_END
);
51 lseek(fd
, 0, SEEK_SET
);
52 if (read(fd
, addr
, size
) != size
) {
64 uint32_t a_info
; /* Use macros N_MAGIC, etc for access */
65 uint32_t a_text
; /* length of text, in bytes */
66 uint32_t a_data
; /* length of data, in bytes */
67 uint32_t a_bss
; /* length of uninitialized data area, in bytes */
68 uint32_t a_syms
; /* length of symbol table data in file, in bytes */
69 uint32_t a_entry
; /* start address */
70 uint32_t a_trsize
; /* length of relocation info for text, in bytes */
71 uint32_t a_drsize
; /* length of relocation info for data, in bytes */
75 static void bswap_ahdr(struct exec
*e
)
82 bswap32s(&e
->a_entry
);
83 bswap32s(&e
->a_trsize
);
84 bswap32s(&e
->a_drsize
);
87 #define bswap_ahdr(x) do { } while (0)
90 #define N_MAGIC(exec) ((exec).a_info & 0xffff)
95 #define _N_HDROFF(x) (1024 - sizeof (struct exec))
97 (N_MAGIC(x) == ZMAGIC ? _N_HDROFF((x)) + sizeof (struct exec) : \
98 (N_MAGIC(x) == QMAGIC ? 0 : sizeof (struct exec)))
99 #define N_TXTADDR(x) (N_MAGIC(x) == QMAGIC ? TARGET_PAGE_SIZE : 0)
100 #define N_DATOFF(x) (N_TXTOFF(x) + (x).a_text)
101 #define _N_SEGMENT_ROUND(x) (((x) + TARGET_PAGE_SIZE - 1) & ~(TARGET_PAGE_SIZE - 1))
103 #define _N_TXTENDADDR(x) (N_TXTADDR(x)+(x).a_text)
105 #define N_DATADDR(x) \
106 (N_MAGIC(x)==OMAGIC? (_N_TXTENDADDR(x)) \
107 : (_N_SEGMENT_ROUND (_N_TXTENDADDR(x))))
110 int load_aout(const char *filename
, uint8_t *addr
)
116 fd
= open(filename
, O_RDONLY
| O_BINARY
);
120 size
= read(fd
, &e
, sizeof(e
));
131 lseek(fd
, N_TXTOFF(e
), SEEK_SET
);
132 size
= read(fd
, addr
, e
.a_text
+ e
.a_data
);
137 lseek(fd
, N_TXTOFF(e
), SEEK_SET
);
138 size
= read(fd
, addr
, e
.a_text
);
141 ret
= read(fd
, addr
+ N_DATADDR(e
), e
.a_data
);
158 static void *load_at(int fd
, int offset
, int size
)
161 if (lseek(fd
, offset
, SEEK_SET
) < 0)
163 ptr
= qemu_malloc(size
);
166 if (read(fd
, ptr
, size
) != size
) {
174 #define ELF_CLASS ELFCLASS32
178 #define elf_word uint32_t
179 #define elf_sword int32_t
180 #define bswapSZs bswap32s
192 #define elfhdr elf64_hdr
193 #define elf_phdr elf64_phdr
194 #define elf_note elf64_note
195 #define elf_shdr elf64_shdr
196 #define elf_sym elf64_sym
197 #define elf_word uint64_t
198 #define elf_sword int64_t
199 #define bswapSZs bswap64s
203 /* return < 0 if error, otherwise the number of bytes loaded in memory */
204 int load_elf(const char *filename
, int64_t virt_to_phys_addend
,
205 uint64_t *pentry
, uint64_t *lowaddr
, uint64_t *highaddr
)
207 int fd
, data_order
, host_data_order
, must_swab
, ret
;
208 uint8_t e_ident
[EI_NIDENT
];
210 fd
= open(filename
, O_RDONLY
| O_BINARY
);
215 if (read(fd
, e_ident
, sizeof(e_ident
)) != sizeof(e_ident
))
217 if (e_ident
[0] != ELFMAG0
||
218 e_ident
[1] != ELFMAG1
||
219 e_ident
[2] != ELFMAG2
||
220 e_ident
[3] != ELFMAG3
)
222 #ifdef WORDS_BIGENDIAN
223 data_order
= ELFDATA2MSB
;
225 data_order
= ELFDATA2LSB
;
227 must_swab
= data_order
!= e_ident
[EI_DATA
];
229 #ifdef TARGET_WORDS_BIGENDIAN
230 host_data_order
= ELFDATA2MSB
;
232 host_data_order
= ELFDATA2LSB
;
234 if (host_data_order
!= e_ident
[EI_DATA
])
237 lseek(fd
, 0, SEEK_SET
);
238 if (e_ident
[EI_CLASS
] == ELFCLASS64
) {
239 ret
= load_elf64(fd
, virt_to_phys_addend
, must_swab
, pentry
,
242 ret
= load_elf32(fd
, virt_to_phys_addend
, must_swab
, pentry
,
254 static void bswap_uboot_header(uboot_image_header_t
*hdr
)
256 #ifndef WORDS_BIGENDIAN
257 bswap32s(&hdr
->ih_magic
);
258 bswap32s(&hdr
->ih_hcrc
);
259 bswap32s(&hdr
->ih_time
);
260 bswap32s(&hdr
->ih_size
);
261 bswap32s(&hdr
->ih_load
);
262 bswap32s(&hdr
->ih_ep
);
263 bswap32s(&hdr
->ih_dcrc
);
267 /* Load a U-Boot image. */
269 /* gunzip functionality is derived from gunzip function
270 * in uboot source code
273 #define ZALLOC_ALIGNMENT 16
275 static void *zalloc(void *x
, unsigned items
, unsigned size
)
280 size
= (size
+ ZALLOC_ALIGNMENT
- 1) & ~(ZALLOC_ALIGNMENT
- 1);
287 static void zfree(void *x
, void *addr
, unsigned nb
)
294 #define EXTRA_FIELD 4
297 #define RESERVED 0xe0
301 static int gunzip(void *dst
, int dstlen
, unsigned char *src
,
310 if (src
[2] != DEFLATED
|| (flags
& RESERVED
) != 0) {
311 puts ("Error: Bad gzipped data\n");
314 if ((flags
& EXTRA_FIELD
) != 0)
315 i
= 12 + src
[10] + (src
[11] << 8);
316 if ((flags
& ORIG_NAME
) != 0)
317 while (src
[i
++] != 0)
319 if ((flags
& COMMENT
) != 0)
320 while (src
[i
++] != 0)
322 if ((flags
& HEAD_CRC
) != 0)
325 puts ("Error: gunzip out of data in header\n");
330 s
.zfree
= (free_func
)zfree
;
332 r
= inflateInit2(&s
, -MAX_WBITS
);
334 printf ("Error: inflateInit2() returned %d\n", r
);
338 s
.avail_in
= *lenp
- i
;
340 s
.avail_out
= dstlen
;
341 r
= inflate(&s
, Z_FINISH
);
342 if (r
!= Z_OK
&& r
!= Z_STREAM_END
) {
343 printf ("Error: inflate() returned %d\n", r
);
346 *lenp
= s
.next_out
- (unsigned char *) dst
;
353 #define MAX_KERNEL_SIZE 8<<20 //8MB
354 /* This functions can load uImage & cuImage files */
355 int load_uimage(const char *filename
, target_ulong
*ep
,
356 target_ulong
*load_address
,
357 target_ulong
*loaded_image_size
,
363 uboot_image_header_t h
;
364 uboot_image_header_t
*hdr
= &h
;
365 uint8_t *data
= NULL
;
366 uint8_t *uncompressed_data
= NULL
;
367 unsigned long tmp_loaded_image_size
;
369 fd
= open(filename
, O_RDONLY
| O_BINARY
);
373 size
= read(fd
, hdr
, sizeof(uboot_image_header_t
));
377 bswap_uboot_header(hdr
);
379 if (hdr
->ih_magic
!= IH_MAGIC
)
382 /* TODO: Implement Multi-File images. */
383 if (hdr
->ih_type
== IH_TYPE_MULTI
) {
384 fprintf(stderr
, "Unable to load multi-file u-boot images\n");
388 /* TODO bzip2 support */
389 if (hdr
->ih_comp
== IH_COMP_BZIP2
) {
390 fprintf(stderr
, "Unable to load bzip2 compressed u-boot images\n");
394 /* TODO: Check CPU type. */
397 if (hdr
->ih_type
== IH_TYPE_KERNEL
&& hdr
->ih_os
== IH_OS_LINUX
)
405 data
= qemu_malloc(hdr
->ih_size
);
409 if (read(fd
, data
, hdr
->ih_size
) != hdr
->ih_size
) {
410 fprintf(stderr
, "Error reading file\n");
414 tmp_loaded_image_size
= hdr
->ih_size
;
416 if (hdr
->ih_comp
== IH_COMP_GZIP
) {
417 uncompressed_data
= qemu_malloc(MAX_KERNEL_SIZE
);
418 ret
= gunzip(uncompressed_data
, MAX_KERNEL_SIZE
,
419 (unsigned char *) data
,
420 &tmp_loaded_image_size
);
423 fprintf(stderr
, "Unable to decompress gziped image!\n");
428 cpu_physical_memory_write_rom(hdr
->ih_load
, uncompressed_data
,
429 tmp_loaded_image_size
);
431 cpu_physical_memory_write_rom(hdr
->ih_load
, data
,
432 tmp_loaded_image_size
);
435 if (loaded_image_size
!= NULL
)
436 *loaded_image_size
= tmp_loaded_image_size
;
438 if (load_address
!= NULL
)
439 *load_address
= hdr
->ih_load
;
450 /* XXX this function is to keep compatibility with other
451 * qemu callers. Once those callers are modified. This function
452 * should be removed from here & sysemu.h
454 int load_uboot(const char *filename
, target_ulong
*ep
, int *is_linux
)
459 ret
= load_uimage(filename
, ep
, NULL
, &size
, is_linux
);