symbian-qemu-0.9.1-12/qemu-symbian-svp/loader.c
changeset 1 2fb8b9db1c86
equal deleted inserted replaced
0:ffa851df0825 1:2fb8b9db1c86
       
     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 }