Add qemu 2.4.0
[kvmfornfv.git] / qemu / roms / openhackware / src / libexec / macho.c
1 /*
2  * <macho.c>
3  *
4  * Open Hack'Ware BIOS MACH-O 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 /* MACH-O executable loader */
28 /* FAT definitions */
29 /* CPU type definitions */
30 typedef enum cpu_type_t {
31     CPU_TYPE_ANY     = -1,
32     CPU_TYPE_VAX     = 1,
33     CPU_TYPE_MC680x0 = 6,
34     CPU_TYPE_I386    = 7,
35     CPU_TYPE_MIPS    = 8,
36     CPU_TYPE_MC98000 = 10,
37     CPU_TYPE_HPPA    = 11,
38     CPU_TYPE_ARM     = 12,
39     CPU_TYPE_MC88000 = 13,
40     CPU_TYPE_SPARC   = 14,
41     CPU_TYPE_I860    = 15,
42     CPU_TYPE_ALPHA   = 16,
43     CPU_TYPE_POWERPC = 18,
44 } cpu_type_t;
45
46 /* Any CPU */
47 typedef enum cpu_subtype_any_t {
48     CPU_SUBTYPE_MULTIPLE      = -1,
49     CPU_SUBTYPE_LITTLE_ENDIAN = 0,
50     CPU_SUBTYPE_BIG_ENDIAN    = 1,
51 } cpu_subtype_any_t;
52
53 /* PowerPC */
54 typedef enum cpu_subtype_ppc_t {
55     CPU_SUBTYPE_PPC_ALL   = 0,
56     CPU_SUBTYPE_PPC_601   = 1,
57     CPU_SUBTYPE_PPC_602   = 2,
58     CPU_SUBTYPE_PPC_603   = 3,
59     CPU_SUBTYPE_PPC_603e  = 4,
60     CPU_SUBTYPE_PPC_603ev = 5,
61     CPU_SUBTYPE_PPC_604   = 6,
62     CPU_SUBTYPE_PPC_604e  = 7,
63     CPU_SUBTYPE_PPC_620   = 8,
64     CPU_SUBTYPE_PPC_750   = 9,
65     CPU_SUBTYPE_PPC_7400  = 10,
66     CPU_SUBTYPE_PPC_7450  = 11,
67 } cpu_subtype_ppc_t;
68
69 /* Fat header definition */
70 #define FAT_MAGIC 0xCAFEBABE
71
72 typedef struct fat_head_t {
73     uint32_t magic;
74     uint32_t nfat_arch;
75 } fat_head_t;
76
77 typedef struct fat_arch_t {
78     cpu_type_t    cpu_type;
79     cpu_subtype_ppc_t cpu_subtype;
80     uint32_t offset;
81     uint32_t size;
82     uint32_t align;
83 } fat_arch_t;
84
85 /* Mach-O binary definitions */
86 #define MACH_O_MAGIC 0xFEEDFACE
87
88 typedef enum filetype_t {
89     MH_OBJECT     = 0x1,
90     MH_EXECUTE    = 0x2,
91     MH_FVMLIB     = 0x3,
92     MH_CORE       = 0x4,
93     MH_PRELOAD    = 0x5,
94     MH_DYLIB      = 0x6,
95     MH_DYLINKER   = 0x7,
96     MH_BUNDLE     = 0x8,
97 } filetype_t;
98
99 enum {
100     MH_NOUNDEFS   = 0x01,
101     MH_INCRLINK   = 0x02,
102     MH_DYLDLINK   = 0x04,
103     MH_BINDATLOAD = 0x08,
104     MH_PREBOUND   = 0x10,
105 };
106
107 typedef struct mach_head_t {
108     uint32_t magic;
109     cpu_type_t cpu_type;
110     cpu_subtype_ppc_t subtype;
111     filetype_t file_type;
112     uint32_t nb_cmds;
113     uint32_t cmds_size;
114     uint32_t flags;
115 } mach_head_t;
116
117 typedef enum load_cmd_t {
118     LC_SEGMENT        = 0x01,
119     LC_SYMTAB         = 0x02,
120     LC_SYMSEG         = 0x03,
121     LC_THREAD         = 0x04,
122     LC_UNIXTHREAD     = 0x05,
123     LC_LOADFVMLIB     = 0x06,
124     LC_IDFVMLIB       = 0x07,
125     LC_IDENT          = 0x08,
126     LC_FVMFILE        = 0x09,
127     LC_PREPAGE        = 0x0A,
128     LC_DYSYMTAB       = 0x0B,
129     LC_LOAD_DYLIB     = 0x0C,
130     LC_ID_DYLIB       = 0x0D,
131     LC_LOAD_DYLINKER  = 0x0E,
132     LC_ID_DYLINKER    = 0x0F,
133     LC_PREBOUND_DYLIB = 0x10,
134     LC_0x17           = 0x17,
135 } load_cmd_t;
136
137 typedef struct mach_load_cmd_t {
138     load_cmd_t cmd;
139     uint32_t cmd_size;
140 } mach_load_cmd_t;
141
142 typedef struct mach_string_t {
143     uint32_t offset;
144 } mach_string_t;
145
146 enum {
147     SG_HIGHVM  = 0x1,
148     SG_FVMLIB  = 0x2,
149     SG_NORELOC = 0x4,
150 };
151
152 typedef struct mach_segment_t {
153     unsigned char segname[16];
154     uint32_t vmaddr;
155     uint32_t vmsize;
156     uint32_t file_offset;
157     uint32_t file_size;
158     uint32_t max_prot;
159     uint32_t init_prot;
160     uint32_t nsects;
161     uint32_t flags;
162 } mach_segment_t;
163
164 enum {
165     SECTION_TYPE               = 0xFF,
166     S_REGULAR                  = 0x0,
167     S_ZEROFILL                 = 0x1,
168     S_CSTRING_LITERALS         = 0x2,
169     S_4BYTE_LITERALS           = 0x3,
170     S_8BYTE_LITERALS           = 0x4,
171     S_LITERAL_POINTERS         = 0x5,
172     S_NON_LAZY_SYMBOL_POINTERS = 0x6,
173     S_LAZY_SYMBOL_POINTERS     = 0x7,
174     S_SYMBOL_STUBS             = 0x8,
175     S_MOD_INIT_FUNC_POINTERS   = 0x9,
176 };
177
178 enum {
179     S_ATTR_PURE_INSTRUCTIONS   = 0x80000000,
180     S_ATTR_SOME_INSTRUCTIONS   = 0x00000400,
181     S_ATTR_EXT_RELOC           = 0x00000200,
182     S_ATTR_LOC_RELOC           = 0x00000100,
183 };
184
185 typedef struct mach_section_t {
186     unsigned char sectname[16];
187     unsigned char segname[16];
188     uint32_t vmaddr;
189     uint32_t size;
190     uint32_t offset;
191     uint32_t align;
192     uint32_t reloc_offset;
193     uint32_t nreloc;
194     uint32_t flags;
195     uint32_t res1;
196     uint32_t res2;
197 } mach_section_t;
198
199 typedef struct mach_symtab_t {
200     uint32_t offset;
201     uint32_t nsyms;
202     uint32_t str_offset;
203     uint32_t str_size;
204 } mach_symtab_t;
205
206 typedef struct mach_symseg_t {
207     uint32_t offset;
208     uint32_t size;
209 } mach_symseg_t;
210
211 typedef struct mach_unixth_t {
212     uint32_t flavor;
213     uint32_t count;
214     /* This is supposed to be a stack.
215      * Let's assume it's less than 1kB (arbitrary !)
216      */
217     uint32_t data[256];
218 } mach_unixth_t;
219
220 typedef struct mach_fvmlib_t {
221     uint32_t str_offset;
222     uint32_t minor_version;
223     uint32_t header_addr;
224 } mach_fvmlib_t;
225
226 typedef struct mach_fvmfile_t {
227     uint32_t str_offset;
228     uint32_t vmaddr;
229 } mach_fvmfile_t;
230
231 typedef struct mach_dysymtab_t {
232     uint32_t ilocal_syms;
233     uint32_t nlocal_syms;
234     uint32_t iext_syms;
235     uint32_t next_syms;
236     uint32_t iundef_syms;
237     uint32_t nundef_syms;
238     uint32_t toc_offset;
239     uint32_t ntoc;
240     uint32_t modtab_offset;
241     uint32_t nmodtab;
242     uint32_t extsym_offset;
243     uint32_t nextsym;
244     uint32_t indirect_offset;
245     uint32_t nindirect;
246     uint32_t ext_reloc_offset;
247     uint32_t next_reloc;
248     uint32_t local_reloc_offset;
249     uint32_t nlocal_reloc;
250 } mach_dysymtab_t;
251
252 typedef struct mach_dylib_t {
253     uint32_t str_offset;
254     uint32_t timestamp;
255     uint32_t cur_version;
256     uint32_t compat_version;
257 } mach_dylib_t;
258
259 typedef struct mach_prebound_t {
260     uint32_t str_offset;
261     uint32_t nb_modules;
262     unsigned char linked_modules[256];
263 } mach_prebound_t;
264
265 int exec_load_macho (inode_t *file, void **dest, void **entry, void **end,
266                      uint32_t loffset)
267 {
268     mach_head_t mhdr;
269     mach_load_cmd_t lcmd;
270     fat_head_t fhdr;
271     fat_arch_t fahdr;
272     void *address, *first, *last;
273     uint32_t k, j, best, offset;
274     int entry_set;
275
276     /* Probe FAT */
277     file_seek(file, loffset);
278     if (fs_read(file, &fhdr, sizeof(fat_head_t)) < 0) {
279         ERROR("Cannot load fat header...\n");
280         return -1;
281     }
282     fhdr.magic = get_be32(&fhdr.magic);
283     if (fhdr.magic != FAT_MAGIC)
284         goto macho_probe;
285     fhdr.nfat_arch = get_be32(&fhdr.nfat_arch);
286     DPRINTF("FAT file: %d archs\n", fhdr.nfat_arch);
287     /* Find the best architecture */
288     best = -1;
289     offset = 0;
290     for (k = 0; k < fhdr.nfat_arch; k++) {
291         if (fs_read(file, &fahdr, sizeof(fat_arch_t)) < 0) {
292             ERROR("Cannot load fat arch header\n");
293             return -1;
294         }
295         fahdr.cpu_type = get_be32(&fahdr.cpu_type);
296         if (fahdr.cpu_type != CPU_TYPE_POWERPC)
297             continue;
298         fahdr.cpu_subtype = get_be32(&fahdr.cpu_subtype);
299         fahdr.offset = get_be32(&fahdr.offset);
300         fahdr.size = get_be32(&fahdr.size);
301         fahdr.align = get_be32(&fahdr.align);
302         switch (fahdr.cpu_subtype) {
303         case CPU_SUBTYPE_PPC_750:
304             best = k;
305             offset = fahdr.offset;
306             goto fat_cpu_ok;
307         case CPU_SUBTYPE_PPC_ALL:
308             if (best == (uint32_t)-1) {
309                 offset = fahdr.offset;
310                 best = k;
311             }
312             break;
313         case CPU_SUBTYPE_PPC_603:
314         case CPU_SUBTYPE_PPC_603e:
315         case CPU_SUBTYPE_PPC_603ev:
316         case CPU_SUBTYPE_PPC_604:
317         case CPU_SUBTYPE_PPC_604e:
318             best = k;
319             offset = fahdr.offset;
320             break;
321         default:
322             break;
323         }
324     }
325     if (best == (uint32_t)-1) {
326         ERROR("No matching PPC FAT arch\n");
327         return -1;
328     }
329     DPRINTF("Use FAT arch %d at %08x %08x\n", best, offset, loffset);
330  fat_cpu_ok:
331     loffset += offset;
332
333     /* Probe macho */
334  macho_probe:
335     file_seek(file, loffset);
336     if (fs_read(file, &mhdr, sizeof(mach_head_t)) < 0) {
337         ERROR("Cannot load MACH-O header...\n");
338         return -1;
339     }
340     mhdr.magic = get_be32(&mhdr.magic);
341     if (mhdr.magic != MACH_O_MAGIC) {
342         ERROR("Not a MACH-O file\n");
343         return -2;
344     }
345     mhdr.cpu_type = get_be32(&mhdr.cpu_type);
346     mhdr.subtype = get_be32(&mhdr.subtype);
347     mhdr.file_type = get_be32(&mhdr.file_type);
348     mhdr.nb_cmds = get_be32(&mhdr.nb_cmds);
349     mhdr.cmds_size = get_be32(&mhdr.cmds_size);
350     mhdr.flags = get_be32(&mhdr.flags);
351     DPRINTF("MACHO-O file cpu %d %d file type %08x %d cmds size %08x flags "
352             "%08x\n", mhdr.cpu_type, mhdr.subtype, mhdr.file_type,
353             mhdr.nb_cmds, mhdr.cmds_size, mhdr.flags);
354     offset = sizeof(mach_head_t);
355     first = (void *)-1;
356     last = NULL;
357     entry_set = 0;
358     for (k = 0; k < mhdr.nb_cmds; k++) {
359         file_seek(file, loffset + offset);
360         if (fs_read(file, &lcmd, sizeof(mach_load_cmd_t)) < 0) {
361             ERROR("Unable to load MACH-O cmd %d\n", k);
362             return -1;
363         }
364         lcmd.cmd = get_be32(&lcmd.cmd);
365         lcmd.cmd_size = get_be32(&lcmd.cmd_size);
366         DPRINTF("Cmd %d : %08x size %08x (%08x %08x)\n", k, lcmd.cmd,
367                 lcmd.cmd_size, offset, offset + loffset);
368         switch (lcmd.cmd) {
369         case LC_SEGMENT:
370             /* To be loaded for execution */
371             {
372                 mach_segment_t segment;
373                 mach_section_t section;
374                 uint32_t pos;
375                 
376                 pos = offset + sizeof(mach_load_cmd_t);
377                 if (fs_read(file, &segment, sizeof(mach_segment_t)) < 0) {
378                     ERROR("Cannot load MACH-O segment\n");
379                     return -1;
380                 }
381                 pos += sizeof(mach_segment_t);
382                 segment.vmaddr = get_be32(&segment.vmaddr);
383                 segment.vmsize = get_be32(&segment.vmsize);
384                 segment.file_offset = get_be32(&segment.file_offset);
385                 segment.file_size = get_be32(&segment.file_size);
386                 segment.max_prot = get_be32(&segment.max_prot);
387                 segment.init_prot = get_be32(&segment.init_prot);
388                 segment.nsects = get_be32(&segment.nsects);
389                 segment.flags = get_be32(&segment.flags);
390                 DPRINTF("MACH-O segment addr %08x size %08x off %08x fsize "
391                         "%08x ns %d fl %08x\n", segment.vmaddr, segment.vmsize,
392                         segment.file_offset, segment.file_size,
393                         segment.nsects, segment.flags);
394                 for (j = 0; j < segment.nsects; j++) {
395                     file_seek(file, loffset + pos);
396                     if (fs_read(file, &section, sizeof(mach_section_t)) < 0) {
397                         ERROR("Cannot load MACH-O section\n");
398                         return -1;
399                     }
400                     pos += sizeof(mach_section_t);
401                     section.vmaddr = get_be32(&section.vmaddr);
402                     section.size = get_be32(&section.size);
403                     section.offset = get_be32(&section.offset);
404                     section.align = get_be32(&section.align);
405                     section.reloc_offset = get_be32(&section.reloc_offset);
406                     section.nreloc = get_be32(&section.nreloc);
407                     section.flags = get_be32(&section.flags);
408                     section.res1 = get_be32(&section.res1);
409                     section.res2 = get_be32(&section.res2);
410                     DPRINTF("MACH-O section vmaddr %08x size %08x off %08x "
411                             "flags %08x\n", section.vmaddr, section.size,
412                             section.offset, section.flags);
413                     switch (section.flags & SECTION_TYPE) {
414                     case S_REGULAR:
415                     case S_CSTRING_LITERALS:
416                     case S_4BYTE_LITERALS:
417                     case S_8BYTE_LITERALS:
418                     case S_LITERAL_POINTERS:
419                     case S_NON_LAZY_SYMBOL_POINTERS:
420                     case S_LAZY_SYMBOL_POINTERS:
421                     case S_SYMBOL_STUBS:
422                     case S_MOD_INIT_FUNC_POINTERS:
423                         DPRINTF("Load section of type %d from %08x to %08x"
424                                 " %08x\n", section.flags, section.offset,
425                                 section.vmaddr, section.size);
426                         file_seek(file, section.offset + loffset);
427                         address = (void *)section.vmaddr;
428                         if (address < first && address != NULL)
429                             first = address;
430                         if (address + section.size > last)
431                             last = address + section.size;
432                         if (fs_read(file, address, section.size) < 0) {
433                             ERROR("Cannot load MACH-O section %d %d...\n",
434                                   k, j);
435                             return -1;
436                         }
437                         break;
438                     case S_ZEROFILL:
439                         DPRINTF("Fill zero section to %08x %08x\n",
440                                 section.vmaddr, section.size);
441                         address = (void *)section.vmaddr;
442                         if (address < first && address != NULL)
443                             first = address;
444                         if (address + section.size > last)
445                             last = address + section.size;
446                         memset(address, 0, section.size);
447                         break;
448                     default:
449                         ERROR("Unknown MACH-O section type: %d\n",
450                               section.flags);
451                         return -1;
452                     }
453                 }
454             }
455             break;
456         case LC_SYMTAB:
457             /* Don't care */
458             break;
459         case LC_SYMSEG:
460             /* Don't care */
461             break;
462         case LC_UNIXTHREAD:
463             /* To be loaded for execution */
464             {
465                 mach_unixth_t unixth;
466
467                 if (fs_read(file, &unixth, sizeof(mach_unixth_t)) < 0) {
468                     ERROR("Cannot load MACH-O UNIX thread\n");
469                     return -1;
470                 }
471                 DPRINTF("Set entry point to %08x\n", unixth.data[0]);
472                 *entry = (void *)unixth.data[0];
473                 entry_set = 1;
474             }
475             break;
476         case LC_THREAD:
477             break;
478         case LC_LOADFVMLIB:
479             break;
480         case LC_IDFVMLIB:
481             break;
482         case LC_IDENT:
483             break;
484         case LC_FVMFILE:
485             break;
486         case LC_PREPAGE:
487             printf("Prepage command\n");
488             break;
489         case LC_DYSYMTAB:
490             break;
491         case LC_LOAD_DYLIB:
492             break;
493         case LC_ID_DYLIB:
494             break;
495         case LC_LOAD_DYLINKER:
496             /* To be loaded for execution */
497             break;
498         case LC_ID_DYLINKER:
499             break;
500         case LC_PREBOUND_DYLIB:
501             break;
502         case LC_0x17:
503             /* ? */
504             break;
505         default:
506             printf("unknown MACH-O command (%d %d)\n", k, lcmd.cmd);
507             return -1;
508         }
509         offset += lcmd.cmd_size;
510     }
511     *dest = first;
512     *end = last;
513     //    if (entry_set == 0)
514         *entry = *dest;
515
516     return 0;
517 }