4 * Open Hack'Ware BIOS XCOFF executable file loader
6 * Copyright (c) 2004-2005 Jocelyn Mayer
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
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.
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
27 uint32_t fs_inode_get_size (inode_t *inode);
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 */
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 */
48 * F_RELFLG relocation info stripped from file
49 * F_EXEC file is executable (i.e. no unresolved external
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
62 * F_PATCH file contains "patch" list in optional header
63 * F_NODF (minimal file only) no decision functions for
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
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 */
105 #define AOUT_MAGIC 0x010b
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 */
120 int exec_load_xcoff (inode_t *file, void **dest, void **entry, void **end,
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");
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);
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);
145 if (fhdr.f_opthdr != sizeof(COFF_aouthdr_t)) {
146 ERROR("AOUT optional error size missmactch in XCOFF file\n");
149 if (fs_read(file, &ahdr, sizeof(COFF_aouthdr_t)) < 0) {
150 ERROR("Cannot load XCOFF AOUT header...\n");
153 if (ahdr.magic != AOUT_MAGIC) {
154 ERROR("Invalid AOUT optional header\n");
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)),
166 *entry = (void *)ahdr.entry + 0xC;
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);
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);
188 if (shdr.s_scnptr + shdr.s_size > fs_inode_get_size(file)) {
189 ERROR("Section %d data offset > file size\n", i);
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);
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);
208 DPRINTF("Skip '%s' section\n", shdr.s_name);
210 offset += sizeof(COFF_scnhdr_t);