Add qemu 2.4.0
[kvmfornfv.git] / qemu / roms / openhackware / src / libexec / pef.c
1 /*
2  * <pef.c>
3  *
4  * Open Hack'Ware BIOS Classic MacOS 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 /* PEF (old MacOS executable format) */
28 typedef struct PEF_container_t PEF_container_t;
29 struct PEF_container_t {
30     uint32_t tag1;
31     uint32_t tag2;
32     uint32_t arch;
33     uint32_t version;
34     uint32_t timestamp;
35     uint32_t oldDefVersion;
36     uint32_t oldImpVersion;
37     uint32_t currentVersion;
38     uint16_t nb_sections;
39     uint16_t nb_inst_sections;
40     uint32_t pad;
41 } __attribute__ (( packed ));
42
43 typedef struct PEF_section_t PEF_section_t;
44 struct PEF_section_t {
45     int32_t name_offset;
46     uint32_t address;
47     uint32_t total_size;
48     uint32_t unpacked_size;
49     uint32_t packed_size;
50     uint32_t container_offset;
51     uint8_t  section_kind;
52     uint8_t  share_kind;
53     uint8_t  align;
54     uint8_t  pad;
55 } __attribute__ (( packed ));
56
57 typedef struct PEF_loader_t PEF_loader_t;
58 struct PEF_loader_t {
59     int32_t  main_section;
60     uint32_t main_offset;
61     int32_t  init_section;
62     uint32_t init_offset;
63     int32_t  term_section;
64     uint32_t term_offset;
65     uint32_t nb_import_libs;
66     uint32_t nb_import_symbols;
67     uint32_t nb_reloc_sections;
68     uint32_t reloc_instr_offset;
69     uint32_t loader_strings_offset;
70     uint32_t export_hash_offset;
71     uint32_t export_hashtable_power;
72     uint32_t nb_export_symbols;
73 } __attribute__ (( packed ));
74
75 enum {
76     PEF_SECTION_CODE     = 0,
77     PEF_SECTION_UNPDATA  = 1,
78     PEF_SECTION_INIDATA  = 2,
79     PEF_SECTION_CONSTANT = 3,
80     PEF_SECTION_LOADER   = 4,
81     PEF_SECTION_DEBUG    = 5,
82     PEF_SECTION_EXEC     = 6,
83     PEF_SECTION_EXCP     = 7,
84     PEF_SECTION_TRACE    = 8,
85 };
86
87 enum {
88     PEF_SHARE_PROCESS    = 1,
89     PEF_SHARE_GLOBAL     = 4,
90     PEF_SHARE_PROTECTED  = 5,
91 };
92
93 int exec_load_pef (inode_t *file, void **dest, void **entry, void **end,
94                    uint32_t loffset)
95 {
96     PEF_container_t container;
97     PEF_section_t section;
98     PEF_loader_t loader;
99     void *first, *last, *addr, **sections;
100     uint32_t pos, padsize, size, lpos, main_offset;
101     uint8_t opcode;
102     int nb_sections, nb_inst_sections, main_section, i, n;
103
104     file_seek(file, loffset);
105     if (fs_read(file, &container, sizeof(PEF_container_t)) < 0) {
106         ERROR("Cannot load container header\n");
107         return -1;
108     }
109     pos = sizeof(PEF_container_t);
110     /* Check tags and architecture */
111     if (memcmp(&container.tag1, "Joy!", 4) != 0) {
112         DPRINTF("No joy, no PEF\n");
113         return -2;
114     }
115     if (memcmp(&container.tag2, "peff", 4) != 0) {
116         DPRINTF("No PEFF file\n");
117         return -2;
118     }
119     if (memcmp(&container.arch, "pwpc", 4) != 0) {
120         DPRINTF("PEFF file not for PPC\n");
121         return -2;
122     }
123     if (get_be32(&container.version) != 1) {
124         DPRINTF("Unknown PEFF container version\n");
125         return -2;
126     }
127     nb_sections = get_be32(&container.nb_sections);
128     sections = malloc(nb_sections * sizeof(void *));
129     if (sections == NULL) {
130         ERROR("Cannot allocate sections\n");
131         return -1;
132     }
133     nb_inst_sections = get_be32(&container.nb_inst_sections);
134     first = (void *)0xFFFFFFFF;
135     last = NULL;
136     main_section = -1;
137     main_offset = 0;
138     for (i = 0, n = 0; i < nb_sections; i++) {
139         file_seek(file, loffset + pos);
140         if (fs_read(file, &section, sizeof(PEF_section_t)) < 0) {
141             ERROR("Cannot read section %d\n", i);
142             return -1;
143         }
144         pos += sizeof(PEF_section_t);
145         addr = (void *)get_be32(&section.address);
146         sections[i] = addr;
147         if (addr < first)
148             first = addr;
149         size = get_be32(&section.total_size);
150         lpos = get_be32(&section.container_offset);
151         file_seek(file, loffset + lpos);
152         switch (section.section_kind) {
153         case PEF_SECTION_CODE:
154         case PEF_SECTION_UNPDATA:
155             /* Load as raw data */
156             padsize = get_be32(&section.unpacked_size) - size;
157             file_seek(file, loffset + lpos);
158             if (fs_read(file, addr, size) < 0) {
159                 ERROR("Cannot load section %d\n", i);
160                 return -1;
161             }
162             addr = (char *)addr + size;
163             memset(addr, 0, padsize);
164             addr = (char *)addr + padsize;
165             break;
166         case PEF_SECTION_INIDATA:
167         case PEF_SECTION_CONSTANT:
168         case PEF_SECTION_EXEC:
169             /* Load as compressed data */
170             for (;;) {
171                 void *ref;
172                 uint32_t total;
173                 uint8_t bsize, csize, count, j;
174
175                 if (fs_read(file, &opcode, 1) < 0) {
176                     ERROR("Cannot get opcode\n");
177                     return -1;
178                 }
179                 bsize = opcode & 0x1F;
180                 switch (opcode >> 5) {
181                 case 0x0:
182                     /* Initialize size bytes to zero */
183                     memset(addr, 0, bsize);
184                     addr = (char *)addr + bsize;
185                     total = bsize;
186                     break;
187                 case 0x1:
188                     /* Copy bloc */
189                     if (fs_read(file, addr, bsize) < 0) {
190                         ERROR("Cannot copy bloc\n");
191                         return -1;
192                     }
193                     addr = (char *)addr + bsize;
194                     total = bsize;
195                     break;
196                 case 0x2:
197                     /* Repeat bloc */
198                     if (fs_read(file, &count, 1) < 0) {
199                         ERROR("Cannot read bloc size\n");
200                         return -1;
201                     }
202                     total = 0;
203                     if (count == 0) {
204                         break;
205                     }
206                     if (fs_read(file, addr, bsize) < 0) {
207                         ERROR("Cannot read repeat bloc\n");
208                         return -1;
209                     }
210                     ref = addr;
211                     addr = (char *)addr + bsize;
212                     for (j = 1; j < count; j++) {
213                         memcpy(addr, ref, bsize);
214                         total += bsize;
215                         addr = (char *)addr + bsize;
216                     }
217                     break;
218                 case 0x3:
219                     /* Interleave repeat bloc with bloc copy */
220                     if (fs_read(file, &csize, 1) < 0 ||
221                         fs_read(file, &count, 1) < 0) {
222                         ERROR("Cannot read repeat params\n");
223                         return -1;
224                     }
225                     ref = addr;
226                     if (fs_read(file, addr, bsize) < 0) {
227                         ERROR("Cannot read common data\n");
228                         return -1;
229                     }
230                     addr = (char *)addr + bsize;
231                     total = bsize;
232                     for (j = 0; j < count; j++) {
233                         if (fs_read(file, addr, csize) < 0) {
234                             ERROR("Cannot read custom data\n");
235                             return -1;
236                         }
237                         addr = (char *)addr + csize;
238                         memcpy(addr, ref, bsize);
239                         addr = (char *)addr + bsize;
240                         total += csize + bsize;
241                     }
242                     break;
243                 case 0x4:
244                     /* Interleave repeat bloc with zero */
245                     if (fs_read(file, &csize, 1) < 0 ||
246                         fs_read(file, &count, 1) < 0) {
247                         ERROR("Cannot read repeat params\n");
248                         return -1;
249                     }
250                     total = 0;
251                     for (j = 0; j < count; j++) {
252                         memset(addr, 0, bsize);
253                         addr = (char *)addr + bsize;
254                         if (fs_read(file, addr, csize) < 0) {
255                             ERROR("Cannot read repeat data\n");
256                             return -1;
257                         }
258                         addr = (char *)addr + csize;
259                         total += csize + bsize;
260                     }
261                     memset(addr, 0, bsize);
262                     addr = (char *)addr + bsize;
263                     total += bsize;
264                     break;
265                 default:
266                     ERROR("Unknown opcode\n");
267                     return -1;
268                 }
269                 if (addr > last)
270                     last = addr;
271                 if (total >= size)
272                     break;
273                 size -= total;
274             }
275             break;
276         case PEF_SECTION_LOADER:
277             /* find entry point */
278             if (fs_read(file, &loader, sizeof(PEF_loader_t)) < 0) {
279                 ERROR("Cannot read loader header\n");
280                 return -1;
281             }
282             main_section = get_be32(&loader.main_section);
283             main_offset = get_be32(&loader.main_offset);
284             if (main_section >= nb_sections) {
285                 ERROR("Invalid main section\n");
286                 return -1;
287             }
288             break;
289         case PEF_SECTION_DEBUG:
290         case PEF_SECTION_EXCP:
291         case PEF_SECTION_TRACE:
292             break;
293         default:
294             return -2;
295         }
296     }
297     *dest = first;
298     *end = last;
299     if (main_section == -1) {
300         *entry = first;
301     } else {
302         *entry = (char *)sections[main_section] + main_offset;
303     }
304     free(sections);
305
306     return 0;
307 }