Add qemu 2.4.0
[kvmfornfv.git] / qemu / roms / openhackware / src / libexec / xcoff.c
1 /*
2  * <xcoff.c>
3  *
4  * Open Hack'Ware BIOS XCOFF executable file loader
5  * 
6  * Copyright (c) 2004-2005 Jocelyn Mayer
7  * 
8  *   This program is free software; you can redistribute it and/or
9  *   modify it under the terms of the GNU General Public License V2
10  *   as published by the Free Software Foundation
11  *
12  *   This program is distributed in the hope that it will be useful,
13  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
14  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  *   GNU General Public License for more details.
16  *
17  *   You should have received a copy of the GNU General Public License
18  *   along with this program; if not, write to the Free Software
19  *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
20  */
21
22 #include <stdlib.h>
23 #include <stdio.h>
24 #include "bios.h"
25 #include "exec.h"
26
27 uint32_t fs_inode_get_size (inode_t *inode);
28
29 /* XCOFF executable loader */
30 typedef struct COFF_filehdr_t {
31     uint16_t f_magic;   /* magic number                 */
32     uint16_t f_nscns;   /* number of sections           */
33     uint32_t f_timdat;  /* time & date stamp            */
34     uint32_t f_symptr;  /* file pointer to symtab       */
35     uint32_t f_nsyms;   /* number of symtab entries     */
36     uint16_t f_opthdr;  /* sizeof(optional hdr)         */
37     uint16_t f_flags;   /* flags                        */
38 } COFF_filehdr_t;
39
40 /* IBM RS/6000 */
41 #define U802WRMAGIC     0730    /* writeable text segments **chh**      */
42 #define U802ROMAGIC     0735    /* readonly sharable text segments      */
43 #define U802TOCMAGIC    0737    /* readonly text segments and TOC       */
44
45 /*
46  *   Bits for f_flags:
47  *
48  *      F_RELFLG        relocation info stripped from file
49  *      F_EXEC          file is executable  (i.e. no unresolved external
50  *                      references)
51  *      F_LNNO          line numbers stripped from file
52  *      F_LSYMS         local symbols stripped from file
53  *      F_MINMAL        this is a minimal object file (".m") output of fextract
54  *      F_UPDATE        this is a fully bound update file, output of ogen
55  *      F_SWABD         this file has had its bytes swabbed (in names)
56  *      F_AR16WR        this file has the byte ordering of an AR16WR
57  *                      (e.g. 11/70) machine
58  *      F_AR32WR        this file has the byte ordering of an AR32WR machine
59  *                      (e.g. vax and iNTEL 386)
60  *      F_AR32W         this file has the byte ordering of an AR32W machine
61  *                      (e.g. 3b,maxi)
62  *      F_PATCH         file contains "patch" list in optional header
63  *      F_NODF          (minimal file only) no decision functions for
64  *                      replaced functions
65  */
66
67 #define  COFF_F_RELFLG          0000001
68 #define  COFF_F_EXEC            0000002
69 #define  COFF_F_LNNO            0000004
70 #define  COFF_F_LSYMS           0000010
71 #define  COFF_F_MINMAL          0000020
72 #define  COFF_F_UPDATE          0000040
73 #define  COFF_F_SWABD           0000100
74 #define  COFF_F_AR16WR          0000200
75 #define  COFF_F_AR32WR          0000400
76 #define  COFF_F_AR32W           0001000
77 #define  COFF_F_PATCH           0002000
78 #define  COFF_F_NODF            0002000
79
80 typedef struct COFF_aouthdr_t {
81     uint16_t magic;      /* type of file                          */
82     uint16_t vstamp;     /* version stamp                         */
83     uint32_t tsize;      /* text size in bytes, padded to FW bdry */
84     uint32_t dsize;      /* initialized data "  "                 */
85     uint32_t bsize;      /* uninitialized data "   "              */
86     uint32_t entry;      /* entry pt.                             */
87     uint32_t text_start; /* base of text used for this file       */
88     uint32_t data_start; /* base of data used for this file       */
89     uint32_t o_toc;      /* address of TOC                        */
90     uint16_t o_snentry;  /* section number of entry point         */
91     uint16_t o_sntext;   /* section number of .text section       */
92     uint16_t o_sndata;   /* section number of .data section       */
93     uint16_t o_sntoc;    /* section number of TOC                 */
94     uint16_t o_snloader; /* section number of .loader section     */
95     uint16_t o_snbss;    /* section number of .bss section        */
96     uint16_t o_algntext; /* .text alignment                       */
97     uint16_t o_algndata; /* .data alignment                       */
98     uint16_t o_modtype;  /* module type (??)                      */
99     uint16_t o_cputype;  /* cpu type                              */
100     uint32_t o_maxstack; /* max stack size (??)                   */
101     uint32_t o_maxdata;  /* max data size (??)                    */
102     char o_resv2[12];    /* reserved                              */
103 } COFF_aouthdr_t;
104
105 #define AOUT_MAGIC      0x010b
106
107 typedef struct COFF_scnhdr_t {
108     char s_name[8];     /* section name                     */
109     uint32_t s_paddr;   /* physical address, aliased s_nlib */
110     uint32_t s_vaddr;   /* virtual address                  */
111     uint32_t s_size;    /* section size                     */
112     uint32_t s_scnptr;  /* file ptr to raw data for section */
113     uint32_t s_relptr;  /* file ptr to relocation           */
114     uint32_t s_lnnoptr; /* file ptr to line numbers         */
115     uint16_t s_nreloc;  /* number of relocation entries     */
116     uint16_t s_nlnno;   /* number of line number entries    */
117     uint32_t s_flags;   /* flags                            */
118 } COFF_scnhdr_t;
119
120 int exec_load_xcoff (inode_t *file, void **dest, void **entry, void **end,
121                      uint32_t loffset)
122 {
123     COFF_filehdr_t fhdr;
124     COFF_aouthdr_t ahdr;
125     COFF_scnhdr_t shdr;
126     void *first, *last;
127     uint32_t offset;
128     int i;
129
130     file_seek(file, loffset);
131     if (fs_read(file, &fhdr, sizeof(COFF_filehdr_t)) < 0) {
132         ERROR("Cannot load first bloc of file...\n");
133         return -1;
134     }
135     if (fhdr.f_magic != U802WRMAGIC && fhdr.f_magic != U802ROMAGIC &&
136         fhdr.f_magic != U802TOCMAGIC && fhdr.f_magic != 0x01DF) {
137         DPRINTF("Not a XCOFF file %02x %08x\n", fhdr.f_magic,
138                 *(uint32_t *)&fhdr.f_magic);
139         return -2;
140     }
141     if (fhdr.f_magic != 0x01DF && (fhdr.f_flags & COFF_F_EXEC) == 0) {
142         ERROR("Not an executable XCOFF file %02x\n", fhdr.f_flags);
143         return -2;
144     }
145     if (fhdr.f_opthdr != sizeof(COFF_aouthdr_t)) {
146         ERROR("AOUT optional error size missmactch in XCOFF file\n");
147         return -2;
148     }
149     if (fs_read(file, &ahdr, sizeof(COFF_aouthdr_t)) < 0) {
150         ERROR("Cannot load XCOFF AOUT header...\n");
151         return -1;
152     }
153     if (ahdr.magic != AOUT_MAGIC) {
154         ERROR("Invalid AOUT optional header\n");
155         return -2;
156     }
157 #if 0 // XXX: buggy: this makes NetBSD fail to boot
158     if (fhdr.f_magic == 0x01DF) {
159         /* Load embedded file */
160         return _bootfile_load(file, dest, entry, end, loffset +
161                               sizeof(COFF_filehdr_t) + sizeof(COFF_aouthdr_t) +
162                               (fhdr.f_nscns * sizeof(COFF_scnhdr_t)),
163                               -1);
164     }
165 #endif
166     *entry = (void *)ahdr.entry + 0xC;
167     last = NULL;
168     first = last - 4;
169     offset = sizeof(COFF_filehdr_t) + sizeof(COFF_aouthdr_t);
170     DPRINTF("XCOFF file with %d sections entry:%p\n", fhdr.f_nscns, *entry);
171     for (i = 0; i < fhdr.f_nscns; i++) {
172         DPRINTF("Read next header (%0x)\n", offset);
173         file_seek(file, offset + loffset);
174         if (fs_read(file, &shdr, sizeof(COFF_scnhdr_t)) < 0) {
175             ERROR("Cannot load section header %d...\n", i);
176             return -1;
177         }
178         if (strcmp(shdr.s_name, ".text") == 0 ||
179             strcmp(shdr.s_name, ".data") == 0) {
180             if ((void *)shdr.s_vaddr < first)
181                 first = (void *)shdr.s_vaddr;
182             if ((void *)shdr.s_vaddr > last)
183                 last = (void *)shdr.s_vaddr;
184             DPRINTF("Load '%s' section from %0x %0x to %0x (%0x)\n",
185                     shdr.s_name, offset, shdr.s_scnptr,
186                     shdr.s_vaddr, shdr.s_size);
187 #if 0
188             if (shdr.s_scnptr + shdr.s_size > fs_inode_get_size(file)) {
189                 ERROR("Section %d data offset > file size\n", i);
190                 return -1;
191             }
192 #endif
193             file_seek(file, shdr.s_scnptr + loffset);
194             set_loadinfo((void *)first, last - first);
195             if (fs_read(file, (void *)shdr.s_vaddr, shdr.s_size) < 0) {
196                 ERROR("Cannot load section %d...\n", i);
197                 return -1;
198             }
199         } else if (strcmp(shdr.s_name, ".bss") == 0) {
200             if ((void *)shdr.s_vaddr < first)
201                 first = (void *)shdr.s_vaddr;
202             if ((void *)shdr.s_vaddr > last)
203                 last = (void *)shdr.s_vaddr;
204             DPRINTF("Erase '%s' section at %0x size: %0x\n",
205                     shdr.s_name, shdr.s_vaddr, shdr.s_size);
206             memset((void *)shdr.s_vaddr, 0, shdr.s_size);
207         } else {
208             DPRINTF("Skip '%s' section\n", shdr.s_name);
209         }
210         offset += sizeof(COFF_scnhdr_t);
211     }
212     *dest = first;
213     *end = last;
214
215     return 0;
216 }