1 |
dpavlin |
1 |
/* |
2 |
|
|
* PearPC |
3 |
|
|
* promboot.cc |
4 |
|
|
* |
5 |
|
|
* Copyright (C) 2004 Stefan Weyergraf |
6 |
|
|
* Copyright (C) 2004 Sebastian Biallas (sb@biallas.net) |
7 |
|
|
* |
8 |
|
|
* This program is free software; you can redistribute it and/or modify |
9 |
|
|
* it under the terms of the GNU General Public License version 2 as |
10 |
|
|
* 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., 675 Mass Ave, Cambridge, MA 02139, USA. |
20 |
|
|
*/ |
21 |
|
|
#include <cstring> |
22 |
|
|
#include <sys/time.h> |
23 |
|
|
#include <sys/types.h> |
24 |
|
|
#include <unistd.h> |
25 |
|
|
|
26 |
|
|
#include "debug/tracers.h" |
27 |
|
|
#include "tools/debug.h" |
28 |
|
|
#include "tools/endianess.h" |
29 |
|
|
#include "cpu/cpu.h" |
30 |
|
|
#include "cpu/mem.h" |
31 |
|
|
#include "io/prom/fs/part.h" |
32 |
|
|
#include "io/ide/ide.h" |
33 |
|
|
#include "io/cuda/cuda.h" |
34 |
|
|
#include "system/keyboard.h" |
35 |
|
|
#include "system/display.h" |
36 |
|
|
#include "system/sys.h" |
37 |
|
|
#include "tools/debug.h" |
38 |
|
|
#include "tools/except.h" |
39 |
|
|
#include "tools/strtools.h" |
40 |
|
|
#include "configparser.h" |
41 |
|
|
#include "prom.h" |
42 |
|
|
#include "promboot.h" |
43 |
|
|
#include "promdt.h" |
44 |
|
|
#include "prommem.h" |
45 |
|
|
|
46 |
|
|
#define MSR_SF (1<<31) |
47 |
|
|
#define MSR_UNKNOWN (1<<30) |
48 |
|
|
#define MSR_UNKNOWN2 (1<<27) |
49 |
|
|
#define MSR_VEC (1<<25) |
50 |
|
|
#define MSR_KEY (1<<19) // 603e |
51 |
|
|
#define MSR_POW (1<<18) |
52 |
|
|
#define MSR_TGPR (1<<15) // 603(e) |
53 |
|
|
#define MSR_ILE (1<<16) |
54 |
|
|
#define MSR_EE (1<<15) |
55 |
|
|
#define MSR_PR (1<<14) |
56 |
|
|
#define MSR_FP (1<<13) |
57 |
|
|
#define MSR_ME (1<<12) |
58 |
|
|
#define MSR_FE0 (1<<11) |
59 |
|
|
#define MSR_SE (1<<10) |
60 |
|
|
#define MSR_BE (1<<9) |
61 |
|
|
#define MSR_FE1 (1<<8) |
62 |
|
|
#define MSR_IP (1<<6) |
63 |
|
|
#define MSR_IR (1<<5) |
64 |
|
|
#define MSR_DR (1<<4) |
65 |
|
|
#define MSR_PM (1<<2) |
66 |
|
|
#define MSR_RI (1<<1) |
67 |
|
|
#define MSR_LE (1) |
68 |
|
|
|
69 |
|
|
|
70 |
|
|
byte ELF_PROGRAM_HEADER32_struct[]= { |
71 |
|
|
STRUCT_ENDIAN_32 | STRUCT_ENDIAN_HOST, |
72 |
|
|
STRUCT_ENDIAN_32 | STRUCT_ENDIAN_HOST, |
73 |
|
|
STRUCT_ENDIAN_32 | STRUCT_ENDIAN_HOST, |
74 |
|
|
STRUCT_ENDIAN_32 | STRUCT_ENDIAN_HOST, |
75 |
|
|
STRUCT_ENDIAN_32 | STRUCT_ENDIAN_HOST, |
76 |
|
|
STRUCT_ENDIAN_32 | STRUCT_ENDIAN_HOST, |
77 |
|
|
STRUCT_ENDIAN_32 | STRUCT_ENDIAN_HOST, |
78 |
|
|
STRUCT_ENDIAN_32 | STRUCT_ENDIAN_HOST, |
79 |
|
|
0, |
80 |
|
|
}; |
81 |
|
|
|
82 |
|
|
byte MACHO_HEADER_struct[]= { |
83 |
|
|
STRUCT_ENDIAN_32 | STRUCT_ENDIAN_HOST, |
84 |
|
|
STRUCT_ENDIAN_32 | STRUCT_ENDIAN_HOST, |
85 |
|
|
STRUCT_ENDIAN_32 | STRUCT_ENDIAN_HOST, |
86 |
|
|
STRUCT_ENDIAN_32 | STRUCT_ENDIAN_HOST, |
87 |
|
|
STRUCT_ENDIAN_32 | STRUCT_ENDIAN_HOST, |
88 |
|
|
STRUCT_ENDIAN_32 | STRUCT_ENDIAN_HOST, |
89 |
|
|
STRUCT_ENDIAN_32 | STRUCT_ENDIAN_HOST, |
90 |
|
|
0, |
91 |
|
|
}; |
92 |
|
|
|
93 |
|
|
byte MACHO_COMMAND_struct[]= { |
94 |
|
|
STRUCT_ENDIAN_32 | STRUCT_ENDIAN_HOST, |
95 |
|
|
STRUCT_ENDIAN_32 | STRUCT_ENDIAN_HOST, |
96 |
|
|
0, |
97 |
|
|
}; |
98 |
|
|
|
99 |
|
|
byte MACHO_SEGMENT_COMMAND_struct[]= { |
100 |
|
|
STRUCT_ENDIAN_8 | STRUCT_ENDIAN_HOST, |
101 |
|
|
STRUCT_ENDIAN_8 | STRUCT_ENDIAN_HOST, |
102 |
|
|
STRUCT_ENDIAN_8 | STRUCT_ENDIAN_HOST, |
103 |
|
|
STRUCT_ENDIAN_8 | STRUCT_ENDIAN_HOST, |
104 |
|
|
STRUCT_ENDIAN_8 | STRUCT_ENDIAN_HOST, |
105 |
|
|
STRUCT_ENDIAN_8 | STRUCT_ENDIAN_HOST, |
106 |
|
|
STRUCT_ENDIAN_8 | STRUCT_ENDIAN_HOST, |
107 |
|
|
STRUCT_ENDIAN_8 | STRUCT_ENDIAN_HOST, |
108 |
|
|
STRUCT_ENDIAN_8 | STRUCT_ENDIAN_HOST, |
109 |
|
|
STRUCT_ENDIAN_8 | STRUCT_ENDIAN_HOST, |
110 |
|
|
STRUCT_ENDIAN_8 | STRUCT_ENDIAN_HOST, |
111 |
|
|
STRUCT_ENDIAN_8 | STRUCT_ENDIAN_HOST, |
112 |
|
|
STRUCT_ENDIAN_8 | STRUCT_ENDIAN_HOST, |
113 |
|
|
STRUCT_ENDIAN_8 | STRUCT_ENDIAN_HOST, |
114 |
|
|
STRUCT_ENDIAN_8 | STRUCT_ENDIAN_HOST, |
115 |
|
|
STRUCT_ENDIAN_8 | STRUCT_ENDIAN_HOST, |
116 |
|
|
STRUCT_ENDIAN_32 | STRUCT_ENDIAN_HOST, |
117 |
|
|
STRUCT_ENDIAN_32 | STRUCT_ENDIAN_HOST, |
118 |
|
|
STRUCT_ENDIAN_32 | STRUCT_ENDIAN_HOST, |
119 |
|
|
STRUCT_ENDIAN_32 | STRUCT_ENDIAN_HOST, |
120 |
|
|
STRUCT_ENDIAN_32 | STRUCT_ENDIAN_HOST, |
121 |
|
|
STRUCT_ENDIAN_32 | STRUCT_ENDIAN_HOST, |
122 |
|
|
STRUCT_ENDIAN_32 | STRUCT_ENDIAN_HOST, |
123 |
|
|
STRUCT_ENDIAN_32 | STRUCT_ENDIAN_HOST, |
124 |
|
|
0, |
125 |
|
|
}; |
126 |
|
|
|
127 |
|
|
byte MACHO_THREAD_COMMAND_struct[] = { |
128 |
|
|
STRUCT_ENDIAN_32 | STRUCT_ENDIAN_HOST, |
129 |
|
|
STRUCT_ENDIAN_32 | STRUCT_ENDIAN_HOST, |
130 |
|
|
|
131 |
|
|
STRUCT_ENDIAN_32 | STRUCT_ENDIAN_HOST, |
132 |
|
|
STRUCT_ENDIAN_32 | STRUCT_ENDIAN_HOST, |
133 |
|
|
STRUCT_ENDIAN_32 | STRUCT_ENDIAN_HOST, |
134 |
|
|
STRUCT_ENDIAN_32 | STRUCT_ENDIAN_HOST, |
135 |
|
|
STRUCT_ENDIAN_32 | STRUCT_ENDIAN_HOST, |
136 |
|
|
STRUCT_ENDIAN_32 | STRUCT_ENDIAN_HOST, |
137 |
|
|
STRUCT_ENDIAN_32 | STRUCT_ENDIAN_HOST, |
138 |
|
|
STRUCT_ENDIAN_32 | STRUCT_ENDIAN_HOST, |
139 |
|
|
STRUCT_ENDIAN_32 | STRUCT_ENDIAN_HOST, |
140 |
|
|
STRUCT_ENDIAN_32 | STRUCT_ENDIAN_HOST, |
141 |
|
|
STRUCT_ENDIAN_32 | STRUCT_ENDIAN_HOST, |
142 |
|
|
STRUCT_ENDIAN_32 | STRUCT_ENDIAN_HOST, |
143 |
|
|
STRUCT_ENDIAN_32 | STRUCT_ENDIAN_HOST, |
144 |
|
|
STRUCT_ENDIAN_32 | STRUCT_ENDIAN_HOST, |
145 |
|
|
STRUCT_ENDIAN_32 | STRUCT_ENDIAN_HOST, |
146 |
|
|
STRUCT_ENDIAN_32 | STRUCT_ENDIAN_HOST, |
147 |
|
|
STRUCT_ENDIAN_32 | STRUCT_ENDIAN_HOST, |
148 |
|
|
STRUCT_ENDIAN_32 | STRUCT_ENDIAN_HOST, |
149 |
|
|
STRUCT_ENDIAN_32 | STRUCT_ENDIAN_HOST, |
150 |
|
|
STRUCT_ENDIAN_32 | STRUCT_ENDIAN_HOST, |
151 |
|
|
STRUCT_ENDIAN_32 | STRUCT_ENDIAN_HOST, |
152 |
|
|
STRUCT_ENDIAN_32 | STRUCT_ENDIAN_HOST, |
153 |
|
|
STRUCT_ENDIAN_32 | STRUCT_ENDIAN_HOST, |
154 |
|
|
STRUCT_ENDIAN_32 | STRUCT_ENDIAN_HOST, |
155 |
|
|
STRUCT_ENDIAN_32 | STRUCT_ENDIAN_HOST, |
156 |
|
|
STRUCT_ENDIAN_32 | STRUCT_ENDIAN_HOST, |
157 |
|
|
STRUCT_ENDIAN_32 | STRUCT_ENDIAN_HOST, |
158 |
|
|
STRUCT_ENDIAN_32 | STRUCT_ENDIAN_HOST, |
159 |
|
|
STRUCT_ENDIAN_32 | STRUCT_ENDIAN_HOST, |
160 |
|
|
STRUCT_ENDIAN_32 | STRUCT_ENDIAN_HOST, |
161 |
|
|
STRUCT_ENDIAN_32 | STRUCT_ENDIAN_HOST, |
162 |
|
|
STRUCT_ENDIAN_32 | STRUCT_ENDIAN_HOST, |
163 |
|
|
STRUCT_ENDIAN_32 | STRUCT_ENDIAN_HOST, |
164 |
|
|
STRUCT_ENDIAN_32 | STRUCT_ENDIAN_HOST, |
165 |
|
|
STRUCT_ENDIAN_32 | STRUCT_ENDIAN_HOST, |
166 |
|
|
STRUCT_ENDIAN_32 | STRUCT_ENDIAN_HOST, |
167 |
|
|
STRUCT_ENDIAN_32 | STRUCT_ENDIAN_HOST, |
168 |
|
|
STRUCT_ENDIAN_32 | STRUCT_ENDIAN_HOST, |
169 |
|
|
STRUCT_ENDIAN_32 | STRUCT_ENDIAN_HOST, |
170 |
|
|
STRUCT_ENDIAN_32 | STRUCT_ENDIAN_HOST, |
171 |
|
|
0, |
172 |
|
|
}; |
173 |
|
|
|
174 |
|
|
|
175 |
|
|
struct MachOHeader { |
176 |
|
|
byte magic[4]; |
177 |
|
|
uint32 cputype; |
178 |
|
|
uint32 cpusubtype; |
179 |
|
|
uint32 filetype; |
180 |
|
|
uint32 ncmds; |
181 |
|
|
uint32 sizeofcmds; |
182 |
|
|
uint32 flags; |
183 |
|
|
}; |
184 |
|
|
|
185 |
|
|
struct MachOCommand { |
186 |
|
|
uint32 cmd; /* type of load command */ |
187 |
|
|
uint32 cmdsize; /* total size of command in bytes */ |
188 |
|
|
}; |
189 |
|
|
|
190 |
|
|
|
191 |
|
|
struct MachOSegmentCommand { |
192 |
|
|
byte segname[16]; /* segment name */ |
193 |
|
|
uint32 vmaddr; /* memory address of this segment */ |
194 |
|
|
uint32 vmsize; /* memory size of this segment */ |
195 |
|
|
uint32 fileoff; /* file offset of this segment */ |
196 |
|
|
uint32 filesize; /* amount to map from the file */ |
197 |
|
|
uint32 maxprot; /* maximum VM protection */ |
198 |
|
|
uint32 initprot; /* initial VM protection */ |
199 |
|
|
uint32 nsects; /* number of sections in segment */ |
200 |
|
|
uint32 flags; /* flags */ |
201 |
|
|
}; |
202 |
|
|
|
203 |
|
|
struct MachOPPCThreadState { |
204 |
|
|
uint32 flavor; /* flavor of thread state */ |
205 |
|
|
uint32 count; /* count of longs in thread state */ |
206 |
|
|
|
207 |
|
|
uint32 srr0; /* Instruction address register (PC) */ |
208 |
|
|
uint32 srr1; /* Machine state register (supervisor) */ |
209 |
|
|
uint32 r[32]; |
210 |
|
|
uint32 cr; /* Condition register */ |
211 |
|
|
uint32 xer; /* User's integer exception register */ |
212 |
|
|
uint32 lr; /* Link register */ |
213 |
|
|
uint32 ctr; /* Count register */ |
214 |
|
|
uint32 mq; /* MQ register (601 only) */ |
215 |
|
|
|
216 |
|
|
uint32 vrsave; /* Vector Save Register */ |
217 |
|
|
}; |
218 |
|
|
|
219 |
|
|
typedef struct COFF_HEADER { |
220 |
|
|
uint16 machine PACKED; |
221 |
|
|
uint16 section_count PACKED; |
222 |
|
|
uint32 timestamp PACKED; |
223 |
|
|
uint32 symbol_table_offset PACKED; |
224 |
|
|
uint32 symbol_count PACKED; |
225 |
|
|
uint16 optional_header_size PACKED; |
226 |
|
|
uint16 characteristics PACKED; |
227 |
|
|
}; |
228 |
|
|
|
229 |
|
|
byte COFF_HEADER_struct[] = { |
230 |
|
|
STRUCT_ENDIAN_16 | STRUCT_ENDIAN_HOST, |
231 |
|
|
STRUCT_ENDIAN_16 | STRUCT_ENDIAN_HOST, |
232 |
|
|
STRUCT_ENDIAN_32 | STRUCT_ENDIAN_HOST, |
233 |
|
|
STRUCT_ENDIAN_32 | STRUCT_ENDIAN_HOST, |
234 |
|
|
STRUCT_ENDIAN_32 | STRUCT_ENDIAN_HOST, |
235 |
|
|
STRUCT_ENDIAN_16 | STRUCT_ENDIAN_HOST, |
236 |
|
|
STRUCT_ENDIAN_16 | STRUCT_ENDIAN_HOST, |
237 |
|
|
0 |
238 |
|
|
}; |
239 |
|
|
|
240 |
|
|
#define COFF_SIZEOF_SHORT_NAME 8 |
241 |
|
|
|
242 |
|
|
struct COFF_SECTION_HEADER { |
243 |
|
|
byte name[COFF_SIZEOF_SHORT_NAME]; |
244 |
|
|
uint32 data_vsize; // or data_phys_address ! |
245 |
|
|
uint32 data_address; |
246 |
|
|
uint32 data_size; |
247 |
|
|
uint32 data_offset; |
248 |
|
|
uint32 relocation_offset; |
249 |
|
|
uint32 linenumber_offset; |
250 |
|
|
uint16 relocation_count; |
251 |
|
|
uint16 linenumber_count; |
252 |
|
|
uint32 characteristics; |
253 |
|
|
} PACKED; |
254 |
|
|
|
255 |
|
|
byte COFF_SECTION_HEADER_struct[] = { |
256 |
|
|
COFF_SIZEOF_SHORT_NAME, |
257 |
|
|
STRUCT_ENDIAN_32 | STRUCT_ENDIAN_HOST, |
258 |
|
|
STRUCT_ENDIAN_32 | STRUCT_ENDIAN_HOST, |
259 |
|
|
STRUCT_ENDIAN_32 | STRUCT_ENDIAN_HOST, |
260 |
|
|
STRUCT_ENDIAN_32 | STRUCT_ENDIAN_HOST, |
261 |
|
|
STRUCT_ENDIAN_32 | STRUCT_ENDIAN_HOST, |
262 |
|
|
STRUCT_ENDIAN_32 | STRUCT_ENDIAN_HOST, |
263 |
|
|
STRUCT_ENDIAN_16 | STRUCT_ENDIAN_HOST, |
264 |
|
|
STRUCT_ENDIAN_16 | STRUCT_ENDIAN_HOST, |
265 |
|
|
STRUCT_ENDIAN_32 | STRUCT_ENDIAN_HOST, |
266 |
|
|
0 |
267 |
|
|
}; |
268 |
|
|
|
269 |
|
|
#define ELF_SIZEOF_IDENT 16 |
270 |
|
|
|
271 |
|
|
static byte ELF_HEADER_struct[] = { |
272 |
|
|
ELF_SIZEOF_IDENT, |
273 |
|
|
STRUCT_ENDIAN_16 | STRUCT_ENDIAN_HOST, // e_type |
274 |
|
|
STRUCT_ENDIAN_16 | STRUCT_ENDIAN_HOST, // e_machine |
275 |
|
|
STRUCT_ENDIAN_32 | STRUCT_ENDIAN_HOST, // e_version |
276 |
|
|
STRUCT_ENDIAN_32 | STRUCT_ENDIAN_HOST, // e_entry |
277 |
|
|
STRUCT_ENDIAN_32 | STRUCT_ENDIAN_HOST, // e_phoff |
278 |
|
|
STRUCT_ENDIAN_32 | STRUCT_ENDIAN_HOST, // e_shoff |
279 |
|
|
STRUCT_ENDIAN_32 | STRUCT_ENDIAN_HOST, // e_flags |
280 |
|
|
STRUCT_ENDIAN_16 | STRUCT_ENDIAN_HOST, // e_ehsize |
281 |
|
|
STRUCT_ENDIAN_16 | STRUCT_ENDIAN_HOST, // e_phentsize |
282 |
|
|
STRUCT_ENDIAN_16 | STRUCT_ENDIAN_HOST, // e_phnum |
283 |
|
|
STRUCT_ENDIAN_16 | STRUCT_ENDIAN_HOST, // e_shentsize |
284 |
|
|
STRUCT_ENDIAN_16 | STRUCT_ENDIAN_HOST, // e_shnum |
285 |
|
|
STRUCT_ENDIAN_16 | STRUCT_ENDIAN_HOST, // e_shstrndx |
286 |
|
|
0 |
287 |
|
|
}; |
288 |
|
|
|
289 |
|
|
static byte ELF_PHEADER_struct[] = { |
290 |
|
|
STRUCT_ENDIAN_32 | STRUCT_ENDIAN_HOST, // p_type |
291 |
|
|
STRUCT_ENDIAN_32 | STRUCT_ENDIAN_HOST, // p_offset |
292 |
|
|
STRUCT_ENDIAN_32 | STRUCT_ENDIAN_HOST, // p_vaddr |
293 |
|
|
STRUCT_ENDIAN_32 | STRUCT_ENDIAN_HOST, // p_paddr |
294 |
|
|
STRUCT_ENDIAN_32 | STRUCT_ENDIAN_HOST, // p_filesz |
295 |
|
|
STRUCT_ENDIAN_32 | STRUCT_ENDIAN_HOST, // p_memsz |
296 |
|
|
STRUCT_ENDIAN_32 | STRUCT_ENDIAN_HOST, // p_flags |
297 |
|
|
STRUCT_ENDIAN_32 | STRUCT_ENDIAN_HOST, // p_align |
298 |
|
|
0 |
299 |
|
|
}; |
300 |
|
|
|
301 |
|
|
static byte ELF_NHEADER_struct[] = { |
302 |
|
|
STRUCT_ENDIAN_32 | STRUCT_ENDIAN_HOST, // n_namesz |
303 |
|
|
STRUCT_ENDIAN_32 | STRUCT_ENDIAN_HOST, // n_descsz |
304 |
|
|
STRUCT_ENDIAN_32 | STRUCT_ENDIAN_HOST, // n_type |
305 |
|
|
0 |
306 |
|
|
}; |
307 |
|
|
|
308 |
|
|
struct ELF_HEADER32 { |
309 |
|
|
uint8 e_ident[ELF_SIZEOF_IDENT]; |
310 |
|
|
uint16 e_type; |
311 |
|
|
uint16 e_machine; |
312 |
|
|
uint32 e_version; |
313 |
|
|
uint32 e_entry; |
314 |
|
|
uint32 e_phoff; |
315 |
|
|
uint32 e_shoff; |
316 |
|
|
uint32 e_flags; |
317 |
|
|
uint16 e_ehsize; |
318 |
|
|
uint16 e_phentsize; |
319 |
|
|
uint16 e_phnum; |
320 |
|
|
uint16 e_shentsize; |
321 |
|
|
uint16 e_shnum; |
322 |
|
|
uint16 e_shstrndx; |
323 |
|
|
}; |
324 |
|
|
|
325 |
|
|
struct ELF_PROGRAM_HEADER32 { |
326 |
|
|
uint32 p_type; |
327 |
|
|
uint32 p_offset; |
328 |
|
|
uint32 p_vaddr; |
329 |
|
|
uint32 p_paddr; |
330 |
|
|
uint32 p_filesz; |
331 |
|
|
uint32 p_memsz; |
332 |
|
|
uint32 p_flags; |
333 |
|
|
uint32 p_align; |
334 |
|
|
}; |
335 |
|
|
|
336 |
|
|
struct ELF_NHEADER32 { |
337 |
|
|
uint32 n_descsz; |
338 |
|
|
uint32 n_namesz; |
339 |
|
|
uint32 n_type; |
340 |
|
|
}; |
341 |
|
|
|
342 |
|
|
struct CHRP_desc { |
343 |
|
|
uint32 real_mode; |
344 |
|
|
uint32 real_base; |
345 |
|
|
uint32 real_size; |
346 |
|
|
uint32 virt_base; |
347 |
|
|
uint32 virt_size; |
348 |
|
|
uint32 load_base; |
349 |
|
|
}; |
350 |
|
|
|
351 |
|
|
static byte ELF_DESC_struct[] = { |
352 |
|
|
STRUCT_ENDIAN_32 | STRUCT_ENDIAN_HOST, // real_mode |
353 |
|
|
STRUCT_ENDIAN_32 | STRUCT_ENDIAN_HOST, // real_base |
354 |
|
|
STRUCT_ENDIAN_32 | STRUCT_ENDIAN_HOST, // real_size |
355 |
|
|
STRUCT_ENDIAN_32 | STRUCT_ENDIAN_HOST, // virt_base |
356 |
|
|
STRUCT_ENDIAN_32 | STRUCT_ENDIAN_HOST, // virt_size |
357 |
|
|
STRUCT_ENDIAN_32 | STRUCT_ENDIAN_HOST, // load_base |
358 |
|
|
0 |
359 |
|
|
}; |
360 |
|
|
|
361 |
|
|
static bool real_mode = false; |
362 |
|
|
|
363 |
|
|
/* |
364 |
|
|
* helpers |
365 |
|
|
*/ |
366 |
|
|
static bool init_page_create(uint32 ea, uint32 pa) |
367 |
|
|
{ |
368 |
|
|
return prom_claim_page(pa) && ppc_prom_page_create(ea, pa); |
369 |
|
|
} |
370 |
|
|
|
371 |
|
|
static bool chrp_init_page_create(uint32 ea, uint32 pa, int no_claim) |
372 |
|
|
{ |
373 |
|
|
bool ret = true; |
374 |
|
|
|
375 |
|
|
if (!no_claim) |
376 |
|
|
ret = prom_claim_page(pa); |
377 |
|
|
|
378 |
|
|
if (real_mode) |
379 |
|
|
return ret; |
380 |
|
|
else |
381 |
|
|
return ret && ppc_prom_page_create(ea, pa); |
382 |
|
|
} |
383 |
|
|
|
384 |
|
|
/* |
385 |
|
|
* ELF |
386 |
|
|
*/ |
387 |
|
|
//#define ELF_LOAD_ADDRESS 0x20000 |
388 |
|
|
#define ELF_LOAD_ADDRESS 0x800000 |
389 |
|
|
#define ROM_BASE 0x40800000 |
390 |
|
|
#define MAX_ELF_HEADERS 32 |
391 |
|
|
#define PPC_PAGE_SIZE 4096 |
392 |
|
|
#define PPC_PAGE_MASK 0x00000fff |
393 |
|
|
|
394 |
|
|
#define PROMBOOT_OUTPUT(...) do { \ |
395 |
|
|
gDisplay->printf(__VA_ARGS__); \ |
396 |
|
|
ht_printf(__VA_ARGS__); \ |
397 |
|
|
} while(0) |
398 |
|
|
|
399 |
|
|
#define PLOAD_NOCOPY (1 << 0) |
400 |
|
|
#define PLOAD_PADDR_MAP (1 << 1) |
401 |
|
|
|
402 |
|
|
bool promboot_copy_file_to_memory(File &f, uint32 &paddr, uint32 &vaddr, sint32 loader_size, sint32 zero_size, int flags) |
403 |
|
|
{ |
404 |
|
|
byte page[PPC_PAGE_SIZE]; |
405 |
|
|
|
406 |
|
|
bool no_copy = flags & PLOAD_NOCOPY; |
407 |
|
|
bool paddr_map = flags & PLOAD_PADDR_MAP; |
408 |
|
|
|
409 |
|
|
bool copy = !no_copy; |
410 |
|
|
if (paddr_map) { |
411 |
|
|
copy = true; |
412 |
|
|
} |
413 |
|
|
printf("promboot_copy_file_to_memory(%08x, %08x, %08x, %08x)\n", paddr, vaddr, loader_size, zero_size); |
414 |
|
|
while (loader_size > 0) { |
415 |
|
|
sint32 size = loader_size; |
416 |
|
|
if (size > PPC_PAGE_SIZE) |
417 |
|
|
size = PPC_PAGE_SIZE; |
418 |
|
|
|
419 |
|
|
/* if (paddr_map && !chrp_init_page_create(vaddr, paddr, false)) { |
420 |
|
|
PROMBOOT_OUTPUT("PROM ERROR: Unable to create load page!\n"); |
421 |
|
|
return false; |
422 |
|
|
}*/ |
423 |
|
|
|
424 |
|
|
if (!chrp_init_page_create(vaddr, paddr, no_copy)) { |
425 |
|
|
PROMBOOT_OUTPUT("LOADER WARNING: data overwrite!\n"); |
426 |
|
|
return false; |
427 |
|
|
} |
428 |
|
|
|
429 |
|
|
if (copy) { |
430 |
|
|
f.readx(page, size); |
431 |
|
|
|
432 |
|
|
if (size < PPC_PAGE_SIZE && zero_size) { |
433 |
|
|
sint32 offset = size; |
434 |
|
|
|
435 |
|
|
size += zero_size; |
436 |
|
|
if (size > PPC_PAGE_SIZE) { |
437 |
|
|
size = PPC_PAGE_SIZE; |
438 |
|
|
} |
439 |
|
|
|
440 |
|
|
memset(page+offset, 0, size-offset); |
441 |
|
|
} |
442 |
|
|
|
443 |
|
|
if (!ppc_dma_write(paddr, page, size)) { |
444 |
|
|
PROMBOOT_OUTPUT("LOADER ERROR: Unable to write page!\n"); |
445 |
|
|
return false; |
446 |
|
|
} |
447 |
|
|
} |
448 |
|
|
|
449 |
|
|
paddr += PPC_PAGE_SIZE; |
450 |
|
|
vaddr += PPC_PAGE_SIZE; |
451 |
|
|
loader_size -= size; |
452 |
|
|
} |
453 |
|
|
|
454 |
|
|
if (zero_size > 0) { |
455 |
|
|
loader_size += zero_size; |
456 |
|
|
|
457 |
|
|
if (copy) memset(page, 0, PPC_PAGE_SIZE); |
458 |
|
|
|
459 |
|
|
while(loader_size > 0) { |
460 |
|
|
sint32 size = loader_size; |
461 |
|
|
if (size > PPC_PAGE_SIZE) |
462 |
|
|
size = PPC_PAGE_SIZE; |
463 |
|
|
|
464 |
|
|
if (!chrp_init_page_create(vaddr, paddr, no_copy)) { |
465 |
|
|
PROMBOOT_OUTPUT("LOADER WARNING: zero-page overwrite!\n"); |
466 |
|
|
return false; |
467 |
|
|
} |
468 |
|
|
if (copy) { |
469 |
|
|
if (!ppc_dma_write(paddr, page, size)) { |
470 |
|
|
PROMBOOT_OUTPUT("LOADER ERROR: Unable to write page!\n"); |
471 |
|
|
return false; |
472 |
|
|
} |
473 |
|
|
} |
474 |
|
|
paddr += PPC_PAGE_SIZE; |
475 |
|
|
vaddr += PPC_PAGE_SIZE; |
476 |
|
|
loader_size -= size; |
477 |
|
|
} |
478 |
|
|
} |
479 |
|
|
} |
480 |
|
|
|
481 |
|
|
extern uint32 gMemorySize; |
482 |
|
|
|
483 |
|
|
/* Based on those standards from: |
484 |
|
|
* PowerPC Microprocessor Common Hardware Reference Platform (CHRP) |
485 |
|
|
* System binding to: IEEE Std 1275-1994 |
486 |
|
|
* Standard for Boot (Initialization, Configuration) |
487 |
|
|
* Firmware |
488 |
|
|
* Revision: 1.8 [Approved Version] |
489 |
|
|
* Date: Feburary 2, 1998 |
490 |
|
|
*/ |
491 |
|
|
bool mapped_load_elf_from_chrp(File &f, uint disp_off) |
492 |
|
|
{ |
493 |
|
|
String fn; |
494 |
|
|
PROMBOOT_OUTPUT("ELF: trying to load '%y'\n", &f.getDesc(fn)); |
495 |
|
|
try { |
496 |
|
|
ELF_HEADER32 hdr; |
497 |
|
|
ELF_PROGRAM_HEADER32 *phdr; |
498 |
|
|
ELF_NHEADER32 nhdr; |
499 |
|
|
uint32 stack = 0; |
500 |
|
|
uint32 stackp = 0; |
501 |
|
|
|
502 |
|
|
// for (int i=0; i < gMemorySize - PROM_MEM_SIZE; i+=4096) |
503 |
|
|
// ppc_prom_page_create(i, i); |
504 |
|
|
|
505 |
|
|
f.seek(disp_off); |
506 |
|
|
f.readx(&hdr, sizeof hdr); |
507 |
|
|
createHostStructx(&hdr, sizeof hdr, ELF_HEADER_struct, big_endian); |
508 |
|
|
|
509 |
|
|
if (hdr.e_ident[0] != 0x7f |
510 |
|
|
|| hdr.e_ident[1] != 'E' |
511 |
|
|
|| hdr.e_ident[2] != 'L' |
512 |
|
|
|| hdr.e_ident[3] != 'F') { |
513 |
|
|
PROMBOOT_OUTPUT("ELF ERROR: bad magic number.\n"); |
514 |
|
|
return false; |
515 |
|
|
} |
516 |
|
|
|
517 |
|
|
if (hdr.e_ident[4] != 1) { |
518 |
|
|
PROMBOOT_OUTPUT("ELF ERROR: non-32-bit ELF.\n"); |
519 |
|
|
return false; |
520 |
|
|
} |
521 |
|
|
|
522 |
|
|
if (hdr.e_ident[5] != 2) { |
523 |
|
|
PROMBOOT_OUTPUT("ELF ERROR: non-big-endian ELF.\n"); |
524 |
|
|
return false; |
525 |
|
|
} |
526 |
|
|
|
527 |
|
|
if (hdr.e_type != 2) { |
528 |
|
|
PROMBOOT_OUTPUT("ELF ERROR: non-executable ELF.\n"); |
529 |
|
|
return false; |
530 |
|
|
} |
531 |
|
|
if (hdr.e_machine != 20) { |
532 |
|
|
PROMBOOT_OUTPUT("ELF ERROR: non-PowerPC ELF.\n"); |
533 |
|
|
return false; |
534 |
|
|
} |
535 |
|
|
if (hdr.e_version != 1) { |
536 |
|
|
PROMBOOT_OUTPUT("ELF ERROR: bad ELF version.\n"); |
537 |
|
|
return false; |
538 |
|
|
} |
539 |
|
|
if (hdr.e_flags != 0) { |
540 |
|
|
PROMBOOT_OUTPUT("ELF ERROR: non-empty flag field.\n"); |
541 |
|
|
return false; |
542 |
|
|
} |
543 |
|
|
|
544 |
|
|
/* Non-specification limit */ |
545 |
|
|
if (hdr.e_phnum > MAX_ELF_HEADERS) { |
546 |
|
|
PROMBOOT_OUTPUT("ELF ERROR: too many program headers.\n"); |
547 |
|
|
return false; |
548 |
|
|
} |
549 |
|
|
|
550 |
|
|
phdr = new ELF_PROGRAM_HEADER32[hdr.e_phnum]; |
551 |
|
|
f.seek(disp_off + hdr.e_phoff); |
552 |
|
|
f.readx(phdr, sizeof(ELF_PROGRAM_HEADER32) * hdr.e_phnum); |
553 |
|
|
for (int i=0; i < hdr.e_phnum; i++) { |
554 |
|
|
createHostStructx(&(phdr[i]), sizeof(phdr[i]), ELF_PHEADER_struct, big_endian); |
555 |
|
|
} |
556 |
|
|
|
557 |
|
|
uint32 load_base = ELF_LOAD_ADDRESS; |
558 |
|
|
uint32 real_base = 0x00000000; |
559 |
|
|
uint32 real_size = 0xffffffff; |
560 |
|
|
uint32 virt_base = 0x00000000; |
561 |
|
|
uint32 virt_size = 0xffffffff; |
562 |
|
|
|
563 |
|
|
for (int i=0; i < hdr.e_phnum; i++) { |
564 |
|
|
if (phdr[i].p_type == 4) { // PT_NOTE |
565 |
|
|
f.seek(disp_off + phdr[i].p_offset); |
566 |
|
|
f.readx(&nhdr, sizeof nhdr); |
567 |
|
|
|
568 |
|
|
createHostStructx(&nhdr, sizeof nhdr, ELF_NHEADER_struct, big_endian); |
569 |
|
|
|
570 |
|
|
if (nhdr.n_type != 0x1275) { |
571 |
|
|
PROMBOOT_OUTPUT("ELF WARNING: unusual PT_NOTE section: %04x\n", nhdr.n_type); |
572 |
|
|
continue; |
573 |
|
|
} |
574 |
|
|
|
575 |
|
|
char *name; |
576 |
|
|
name = (char *)malloc(nhdr.n_namesz); |
577 |
|
|
f.readx(name, nhdr.n_namesz); |
578 |
|
|
PROMBOOT_OUTPUT("ELF PT_NOTE: Name '%s'\n", name); |
579 |
|
|
free(name); |
580 |
|
|
|
581 |
|
|
CHRP_desc *desc; |
582 |
|
|
desc = (CHRP_desc *)malloc(nhdr.n_descsz); |
583 |
|
|
f.readx(desc, nhdr.n_descsz); |
584 |
|
|
createHostStructx(desc, sizeof(CHRP_desc), ELF_DESC_struct, big_endian); |
585 |
|
|
|
586 |
|
|
real_mode = desc->real_mode; |
587 |
|
|
|
588 |
|
|
if (desc->real_base != -1) |
589 |
|
|
real_base = desc->real_base; |
590 |
|
|
|
591 |
|
|
if (desc->real_size != -1) |
592 |
|
|
real_size = desc->real_size; |
593 |
|
|
|
594 |
|
|
if (desc->virt_base != -1) |
595 |
|
|
virt_base = desc->virt_base; |
596 |
|
|
|
597 |
|
|
if (desc->virt_size != -1) |
598 |
|
|
virt_size = desc->virt_size; |
599 |
|
|
|
600 |
|
|
if (desc->load_base != -1) |
601 |
|
|
load_base = desc->load_base; |
602 |
|
|
|
603 |
|
|
free(desc); |
604 |
|
|
break; |
605 |
|
|
} |
606 |
|
|
} |
607 |
|
|
|
608 |
|
|
PROMBOOT_OUTPUT("ELF: real-mode: %s\n", real_mode ? "true" : "false"); |
609 |
|
|
PROMBOOT_OUTPUT("ELF: real-base: %08x\n", real_base); |
610 |
|
|
PROMBOOT_OUTPUT("ELF: real-size: %08x\n", real_size); |
611 |
|
|
PROMBOOT_OUTPUT("ELF: virt-base: %08x\n", virt_base); |
612 |
|
|
PROMBOOT_OUTPUT("ELF: virt-size: %08x\n", virt_size); |
613 |
|
|
PROMBOOT_OUTPUT("ELF: load-base: %08x\n", load_base); |
614 |
|
|
|
615 |
|
|
if (real_mode) { |
616 |
|
|
PROMBOOT_OUTPUT("ELF ERROR: real-mode bootup not supported.\n"); |
617 |
|
|
return false; |
618 |
|
|
} |
619 |
|
|
|
620 |
|
|
sint32 client_size = f.getSize() - disp_off; |
621 |
|
|
|
622 |
|
|
uint32 paddr = load_base; |
623 |
|
|
byte page[PPC_PAGE_SIZE]; |
624 |
|
|
|
625 |
|
|
f.seek(disp_off); |
626 |
|
|
// promboot_copy_file_to_memory(f, paddr, vaddr, client_size, 0, PLOAD_PADDR_MAP); |
627 |
|
|
|
628 |
|
|
for (int i=0; i < hdr.e_phnum; i++) { |
629 |
|
|
if (phdr[i].p_type != 1) // PT_LOAD |
630 |
|
|
continue; |
631 |
|
|
|
632 |
|
|
uint32 vaddr = phdr[i].p_vaddr; |
633 |
|
|
|
634 |
|
|
sint32 loader_size = phdr[i].p_filesz; |
635 |
|
|
if (loader_size > phdr[i].p_memsz) { |
636 |
|
|
loader_size = phdr[i].p_memsz; |
637 |
|
|
} |
638 |
|
|
|
639 |
|
|
sint32 zero_size = 0; |
640 |
|
|
if (phdr[i].p_memsz > phdr[i].p_filesz) |
641 |
|
|
zero_size = phdr[i].p_memsz - phdr[i].p_filesz; |
642 |
|
|
|
643 |
|
|
f.seek(disp_off+phdr[i].p_offset); |
644 |
|
|
|
645 |
|
|
promboot_copy_file_to_memory(f, paddr, vaddr, loader_size, zero_size, 0); |
646 |
|
|
} |
647 |
|
|
|
648 |
|
|
stack = gMemorySize - 21*4096 - PROM_MEM_SIZE; |
649 |
|
|
stackp = gMemorySize - 21*4096 - PROM_MEM_SIZE; |
650 |
|
|
//stack = (stack + PPC_PAGE_MASK) & ~PPC_PAGE_MASK; |
651 |
|
|
//stackp = (stackp + PPC_PAGE_MASK) & ~PPC_PAGE_MASK; |
652 |
|
|
|
653 |
|
|
for (int i=0; i<20; i++) { |
654 |
|
|
if (!init_page_create(stack, stackp)) { |
655 |
|
|
PROMBOOT_OUTPUT("ELF ERROR: Unable to create stack page %i!\n", i); |
656 |
|
|
return false; |
657 |
|
|
} |
658 |
|
|
|
659 |
|
|
stack += PPC_PAGE_SIZE; |
660 |
|
|
stackp += PPC_PAGE_SIZE; |
661 |
|
|
} |
662 |
|
|
|
663 |
|
|
delete[] phdr; |
664 |
|
|
|
665 |
|
|
ppc_cpu_set_pc(0, hdr.e_entry); |
666 |
|
|
|
667 |
|
|
if (real_mode) { |
668 |
|
|
ppc_cpu_set_msr(0, MSR_FP); |
669 |
|
|
ppc_cpu_set_gpr(0, 1, stackp-(4096+32)); |
670 |
|
|
} else { // turn on address translation |
671 |
|
|
ppc_cpu_set_msr(0, MSR_IR | MSR_DR | MSR_FP); |
672 |
|
|
ppc_cpu_set_gpr(0, 1, stack-(4096+32)); |
673 |
|
|
} |
674 |
|
|
|
675 |
|
|
ppc_cpu_set_gpr(0, 2, 0); |
676 |
|
|
ppc_cpu_set_gpr(0, 3, 0); |
677 |
|
|
ppc_cpu_set_gpr(0, 4, 0); |
678 |
|
|
ppc_cpu_set_gpr(0, 5, gPromOSIEntry); |
679 |
|
|
|
680 |
|
|
PROMBOOT_OUTPUT("Booting ELF...\n"); |
681 |
|
|
|
682 |
|
|
ppc_prom_page_create(0, 0); |
683 |
|
|
return true; |
684 |
|
|
} catch (...) { |
685 |
|
|
PROMBOOT_OUTPUT("ELF ERROR: caught exception.\n"); |
686 |
|
|
return false; |
687 |
|
|
} |
688 |
|
|
} |
689 |
|
|
|
690 |
|
|
bool mapped_load_elf(File &f) |
691 |
|
|
{ |
692 |
|
|
String fn; |
693 |
|
|
gDisplay->printf("ELF: trying to load '%y'\n", &f.getDesc(fn)); |
694 |
|
|
IO_PROM_TRACE("ELF: trying to load '%y'\n", &fn); |
695 |
|
|
try { |
696 |
|
|
// FIXME: better code |
697 |
|
|
byte magic[4]; |
698 |
|
|
f.seek(0); |
699 |
|
|
f.readx(magic, 4); |
700 |
|
|
if ((magic[0] != 0x7f) || (magic[1] != 'E') |
701 |
|
|
|| (magic[2] != 'L') ||(magic[3] != 'F')) { |
702 |
|
|
IO_PROM_TRACE("no ELF\n"); |
703 |
|
|
return false; |
704 |
|
|
} |
705 |
|
|
|
706 |
|
|
uint32 la = ELF_LOAD_ADDRESS; |
707 |
|
|
f.seek(0x2c); |
708 |
|
|
uint16 program_hdrs; |
709 |
|
|
f.readx(&program_hdrs, 2); |
710 |
|
|
program_hdrs = createHostInt(&program_hdrs, 2, big_endian); |
711 |
|
|
uint32 stack=0; |
712 |
|
|
uint32 stackp=0; |
713 |
|
|
for (int i=0; i<program_hdrs; i++) { |
714 |
|
|
// IO_PROM_TRACE("program header %d:\n", i); |
715 |
|
|
ELF_PROGRAM_HEADER32 program_hdr; |
716 |
|
|
f.seek(0x34+i*sizeof program_hdr); |
717 |
|
|
f.readx(&program_hdr, sizeof program_hdr); |
718 |
|
|
createHostStructx(&program_hdr, sizeof program_hdr, ELF_PROGRAM_HEADER32_struct, big_endian); |
719 |
|
|
uint32 pages_from_file = program_hdr.p_filesz / 4096; |
720 |
|
|
uint32 ea = program_hdr.p_vaddr; |
721 |
|
|
sint32 vs = program_hdr.p_memsz; |
722 |
|
|
f.seek(program_hdr.p_offset); |
723 |
|
|
uint32 fo = program_hdr.p_offset; |
724 |
|
|
byte page[4096]; |
725 |
|
|
while (pages_from_file) { |
726 |
|
|
// IO_PROM_TRACE("loading from %08x to ea:%08x (pa:%08x)\n", fo, ea, la); |
727 |
|
|
f.readx(page, sizeof page); |
728 |
|
|
if (!init_page_create(ea, la)) return false; |
729 |
|
|
if (!ppc_dma_write(la, page, 4096)) { |
730 |
|
|
return false; |
731 |
|
|
} |
732 |
|
|
pages_from_file--; |
733 |
|
|
la += 4096; |
734 |
|
|
ea += 4096; |
735 |
|
|
fo += 4096; |
736 |
|
|
vs -= 4096; |
737 |
|
|
} |
738 |
|
|
if (program_hdr.p_filesz % 4096) { |
739 |
|
|
// ht_printf("loading remaining from %08x to ea:%08x (pa:%08x)\n", fo, ea, la); |
740 |
|
|
f.read(page, program_hdr.p_filesz % 4096); |
741 |
|
|
if (!init_page_create(ea, la)) return false; |
742 |
|
|
if (!ppc_dma_write(la+(ea&0xfff), page, program_hdr.p_filesz % 4096)) { |
743 |
|
|
return false; |
744 |
|
|
} |
745 |
|
|
la += 4096; |
746 |
|
|
ea += 4096; |
747 |
|
|
fo += 4096; |
748 |
|
|
vs -= 4096; |
749 |
|
|
} |
750 |
|
|
while (vs > 0) { |
751 |
|
|
// ht_printf("creating for ea:%08x (pa:%08x)\n", ea, la); |
752 |
|
|
if (!init_page_create(ea, la)) return false; |
753 |
|
|
la += 4096; |
754 |
|
|
ea += 4096; |
755 |
|
|
vs -= 4096; |
756 |
|
|
} |
757 |
|
|
stack = ea; |
758 |
|
|
stackp = la; |
759 |
|
|
} |
760 |
|
|
|
761 |
|
|
stack = gMemorySize - 65536 - (4096*20) - PROM_MEM_SIZE; |
762 |
|
|
stackp = gMemorySize - 65536 - (4096*20) - PROM_MEM_SIZE; |
763 |
|
|
// allocate stack |
764 |
|
|
for (int i=0; i<20; i++) { |
765 |
|
|
if (!init_page_create(stack, stackp)) return false; |
766 |
|
|
stack += 4096; |
767 |
|
|
stackp += 4096; |
768 |
|
|
} |
769 |
|
|
|
770 |
|
|
|
771 |
|
|
f.seek(0x18); |
772 |
|
|
uint32 entry; |
773 |
|
|
f.readx(&entry, 4); |
774 |
|
|
entry = createHostInt(&entry, 4, big_endian); |
775 |
|
|
|
776 |
|
|
// turn on address translation |
777 |
|
|
ppc_cpu_set_msr(0, MSR_IR | MSR_DR | MSR_FP); |
778 |
|
|
ppc_cpu_set_pc(0, entry); |
779 |
|
|
|
780 |
|
|
ppc_cpu_set_gpr(0, 1, gMemorySize - 65536 - 32 - PROM_MEM_SIZE); |
781 |
|
|
ppc_cpu_set_gpr(0, 2, 0); |
782 |
|
|
ppc_cpu_set_gpr(0, 3, 0); |
783 |
|
|
ppc_cpu_set_gpr(0, 4, 0); |
784 |
|
|
ppc_cpu_set_gpr(0, 5, gPromOSIEntry); |
785 |
|
|
|
786 |
|
|
// wtf?! |
787 |
|
|
ppc_prom_page_create(0, 0); |
788 |
|
|
return true; |
789 |
|
|
} catch (...) { |
790 |
|
|
return false; |
791 |
|
|
} |
792 |
|
|
} |
793 |
|
|
|
794 |
|
|
/* |
795 |
|
|
* XCOFF |
796 |
|
|
*/ |
797 |
|
|
bool mapped_load_xcoff(File &f, uint disp_ofs) |
798 |
|
|
{ |
799 |
|
|
String fn; |
800 |
|
|
gDisplay->printf("XCOFF trying to load '%y'\n", &f.getDesc(fn)); |
801 |
|
|
IO_PROM_TRACE("XCOFF trying to load '%y'\n", &fn); |
802 |
|
|
|
803 |
|
|
f.seek(disp_ofs); |
804 |
|
|
try { |
805 |
|
|
COFF_HEADER hdr; |
806 |
|
|
f.readx(&hdr, sizeof hdr); |
807 |
|
|
createHostStructx(&hdr, sizeof hdr, COFF_HEADER_struct, big_endian); |
808 |
|
|
if (hdr.machine != 0x1df) { |
809 |
|
|
IO_PROM_TRACE("invalid machine %04x (expecting 01df)\n", hdr.machine); |
810 |
|
|
return false; |
811 |
|
|
} |
812 |
|
|
if (hdr.optional_header_size != 0x48) { |
813 |
|
|
IO_PROM_TRACE("invalid optional header size %04x (expecting 0048)\n", hdr.optional_header_size); |
814 |
|
|
return false; |
815 |
|
|
} |
816 |
|
|
uint32 stack=0; |
817 |
|
|
uint32 stackp=0; |
818 |
|
|
uint32 entrypoint; |
819 |
|
|
uint32 entrypoint_ofs = 0; |
820 |
|
|
f.seek(disp_ofs+0x24); |
821 |
|
|
f.readx(&entrypoint, 4); |
822 |
|
|
entrypoint = createHostInt(&entrypoint, 4, big_endian); |
823 |
|
|
|
824 |
|
|
for (int i=0; i<hdr.section_count; i++) { |
825 |
|
|
// ht_printf("program header %d:\n", i); |
826 |
|
|
COFF_SECTION_HEADER shdr; |
827 |
|
|
f.seek(disp_ofs+0x5c+i*sizeof shdr); |
828 |
|
|
f.readx(&shdr, sizeof shdr); |
829 |
|
|
createHostStructx(&shdr, sizeof shdr, COFF_SECTION_HEADER_struct, big_endian); |
830 |
|
|
if ((entrypoint >= shdr.data_address) && (entrypoint < shdr.data_address+shdr.data_size)) { |
831 |
|
|
IO_PROM_TRACE("found entrypoint-structure in section %d\n", i); |
832 |
|
|
entrypoint_ofs = entrypoint - shdr.data_address + shdr.data_offset; |
833 |
|
|
} |
834 |
|
|
uint32 in_file_size = (shdr.data_offset) ? shdr.data_size : 0; |
835 |
|
|
uint32 pages_from_file = in_file_size / 4096; |
836 |
|
|
uint32 pa = shdr.data_vsize; /* really: physical addr */ |
837 |
|
|
uint32 ea = shdr.data_address; |
838 |
|
|
sint32 vs = shdr.data_size; |
839 |
|
|
f.seek(disp_ofs+shdr.data_offset); |
840 |
|
|
uint32 fo = shdr.data_offset; |
841 |
|
|
byte page[4096]; |
842 |
|
|
while (pages_from_file) { |
843 |
|
|
// ht_printf("loading from %08x to ea:%08x (pa:%08x)\n", fo, ea, pa); |
844 |
|
|
f.readx(page, sizeof page); |
845 |
|
|
if (!init_page_create(ea, pa)) return false; |
846 |
|
|
if (!ppc_dma_write(pa, page, 4096)) { |
847 |
|
|
return false; |
848 |
|
|
} |
849 |
|
|
pages_from_file--; |
850 |
|
|
pa += 4096; |
851 |
|
|
ea += 4096; |
852 |
|
|
fo += 4096; |
853 |
|
|
vs -= 4096; |
854 |
|
|
} |
855 |
|
|
if (in_file_size % 4096) { |
856 |
|
|
// ht_printf("loading remaining from %08x to ea:%08x (pa:%08x)\n", fo, ea, pa); |
857 |
|
|
f.readx(page, in_file_size % 4096); |
858 |
|
|
if (!init_page_create(ea, pa)) return false; |
859 |
|
|
if (!ppc_dma_write(pa+(ea&0xfff), page, in_file_size % 4096)) { |
860 |
|
|
return false; |
861 |
|
|
} |
862 |
|
|
pa += 4096; |
863 |
|
|
ea += 4096; |
864 |
|
|
fo += 4096; |
865 |
|
|
vs -= 4096; |
866 |
|
|
} |
867 |
|
|
while (vs > 0) { |
868 |
|
|
// ht_printf("creating for ea:%08x (pa:%08x)\n", ea, pa); |
869 |
|
|
if (!init_page_create(ea, pa)) return false; |
870 |
|
|
pa += 4096; |
871 |
|
|
ea += 4096; |
872 |
|
|
vs -= 4096; |
873 |
|
|
} |
874 |
|
|
stack = ea; |
875 |
|
|
stackp = pa; |
876 |
|
|
} |
877 |
|
|
if (!entrypoint_ofs) { |
878 |
|
|
IO_PROM_TRACE("couldn't find entrypoint offset\n"); |
879 |
|
|
return false; |
880 |
|
|
} |
881 |
|
|
// allocate stack |
882 |
|
|
for (int i=0; i<20; i++) { |
883 |
|
|
if (!init_page_create(stack, stackp)) return false; |
884 |
|
|
stack += 4096; |
885 |
|
|
stackp += 4096; |
886 |
|
|
} |
887 |
|
|
|
888 |
|
|
uint32 real_entrypoint = 0; |
889 |
|
|
f.seek(disp_ofs+entrypoint_ofs); |
890 |
|
|
f.read(&real_entrypoint, 4); |
891 |
|
|
real_entrypoint = createHostInt(&real_entrypoint, 4, big_endian); |
892 |
|
|
IO_PROM_TRACE("real_entrypoint = %08x\n", real_entrypoint); |
893 |
|
|
// turn on address translation |
894 |
|
|
ppc_cpu_set_msr(0, MSR_IR | MSR_DR | MSR_FP); |
895 |
|
|
ppc_cpu_set_pc(0, real_entrypoint); |
896 |
|
|
|
897 |
|
|
ppc_cpu_set_gpr(0, 1, stack-(4096+32)); |
898 |
|
|
ppc_cpu_set_gpr(0, 2, 0); |
899 |
|
|
ppc_cpu_set_gpr(0, 3, 0); |
900 |
|
|
ppc_cpu_set_gpr(0, 4, 0); |
901 |
|
|
ppc_cpu_set_gpr(0, 5, gPromOSIEntry); |
902 |
|
|
|
903 |
|
|
return true; |
904 |
|
|
} catch (...) { |
905 |
|
|
return false; |
906 |
|
|
} |
907 |
|
|
} |
908 |
|
|
|
909 |
|
|
static void chrpReadWaitForChar(File &f, char *buf, uint buflen, char waitFor) |
910 |
|
|
{ |
911 |
|
|
while (buflen) { |
912 |
|
|
f.readx(buf, 1); |
913 |
|
|
|
914 |
|
|
if (*buf == 0x0d) *buf = '\n'; |
915 |
|
|
|
916 |
|
|
if (!*buf) throw new MsgException("Binary files not allowed here"); |
917 |
|
|
if (*buf == waitFor) { |
918 |
|
|
*buf = 0; |
919 |
|
|
return; |
920 |
|
|
} |
921 |
|
|
buf++; |
922 |
|
|
buflen--; |
923 |
|
|
} |
924 |
|
|
throw new MsgException("wait for char failed"); |
925 |
|
|
} |
926 |
|
|
|
927 |
|
|
static void chrpReadWaitForString(File &f, char *buf, uint buflen, char *waitFor) |
928 |
|
|
{ |
929 |
|
|
uint zlen = strlen(waitFor); |
930 |
|
|
char *z = strdup(waitFor); |
931 |
|
|
*z = 0; |
932 |
|
|
*buf = 0; |
933 |
|
|
if (!zlen) return; |
934 |
|
|
FileOfs o = f.tell(); |
935 |
|
|
while (buflen) { |
936 |
|
|
f.seek(o); |
937 |
|
|
f.readx(z, zlen); |
938 |
|
|
if (strcmp(z, waitFor) == 0) { |
939 |
|
|
*buf = 0; |
940 |
|
|
free(z); |
941 |
|
|
return; |
942 |
|
|
} |
943 |
|
|
if (buf != NULL) { |
944 |
|
|
*buf = (*z == 0xd) ? '\n' : *z; |
945 |
|
|
buf++; |
946 |
|
|
buflen--; |
947 |
|
|
} |
948 |
|
|
o++; |
949 |
|
|
} |
950 |
|
|
free(z); |
951 |
|
|
throw new MsgException("wait for string failed"); |
952 |
|
|
} |
953 |
|
|
|
954 |
|
|
#if 0 |
955 |
|
|
static void readCHRPIcon(byte *icon, char *&t, uint width, uint height) |
956 |
|
|
{ |
957 |
|
|
memset(icon, 0, width*height); |
958 |
|
|
uint y = 0; |
959 |
|
|
uint x = 0; |
960 |
|
|
while (t[0] && t[1]) { |
961 |
|
|
if (t[0] == '\n') { |
962 |
|
|
while (*t == '\n') t++; |
963 |
|
|
// fprintf(stderr, "parse icon: line %d length %d\n", y, x); |
964 |
|
|
x = 0; |
965 |
|
|
y++; |
966 |
|
|
if (y >= height) break; |
967 |
|
|
continue; |
968 |
|
|
} |
969 |
|
|
if (x>=width) break; |
970 |
|
|
hexb_ex(icon[x+y*width], t); |
971 |
|
|
t += 2; |
972 |
|
|
x++; |
973 |
|
|
} |
974 |
|
|
} |
975 |
|
|
#endif |
976 |
|
|
|
977 |
|
|
static bool chrpBoot(const char *bootpath, const char *bootargs) |
978 |
|
|
{ |
979 |
|
|
IO_PROM_TRACE("CHRP boot file (bootpath = %s, bootargs = %s).\n", bootpath, bootargs); |
980 |
|
|
// set bootpath in device tree |
981 |
|
|
PromNode *chosen = findDevice("/chosen", FIND_DEVICE_FIND, NULL); |
982 |
|
|
if (chosen) { |
983 |
|
|
PromProp *bp = chosen->findProp("bootpath"); |
984 |
|
|
if (bp) { |
985 |
|
|
PromPropString *s = dynamic_cast<PromPropString*>(bp); |
986 |
|
|
if (s) { |
987 |
|
|
free(s->value); |
988 |
|
|
s->value = strdup(bootpath); |
989 |
|
|
} |
990 |
|
|
} else { |
991 |
|
|
chosen->addProp(new PromPropString("bootpath", bootpath)); |
992 |
|
|
} |
993 |
|
|
PromProp *ba = chosen->findProp("bootargs"); |
994 |
|
|
if (ba) { |
995 |
|
|
PromPropString *s = dynamic_cast<PromPropString*>(ba); |
996 |
|
|
if (s) { |
997 |
|
|
free(s->value); |
998 |
|
|
s->value = strdup(bootargs); |
999 |
|
|
} |
1000 |
|
|
} else { |
1001 |
|
|
chosen->addProp(new PromPropString("bootargs", bootargs)); |
1002 |
|
|
} |
1003 |
|
|
} |
1004 |
|
|
|
1005 |
|
|
PromInstanceHandle ih; |
1006 |
|
|
if (!findDevice(bootpath, FIND_DEVICE_OPEN, &ih)) return false; |
1007 |
|
|
|
1008 |
|
|
PromInstanceDiskFile *ix = dynamic_cast<PromInstanceDiskFile*>(handleToInstance(ih)); |
1009 |
|
|
if (!ix || !ix->mFile) { |
1010 |
|
|
IO_PROM_TRACE("couldn't load CHRP boot file (1) (bootpath = %s).\n", bootpath); |
1011 |
|
|
return false; |
1012 |
|
|
} |
1013 |
|
|
|
1014 |
|
|
PromNode *pn = ix->getType(); |
1015 |
|
|
File *f = ix->mFile; |
1016 |
|
|
|
1017 |
|
|
if (!mapped_load_elf(*f) |
1018 |
|
|
&& !mapped_load_xcoff(*f, 0) |
1019 |
|
|
&& !mapped_load_chrp(*f)) { |
1020 |
|
|
IO_PROM_TRACE("couldn't load CHRP boot file (2) (bootpath = %s).\n", bootpath); |
1021 |
|
|
pn->close(ih); |
1022 |
|
|
return false; |
1023 |
|
|
} |
1024 |
|
|
pn->close(ih); |
1025 |
|
|
return true; |
1026 |
|
|
} |
1027 |
|
|
|
1028 |
|
|
bool mapped_load_chrp(File &f) |
1029 |
|
|
{ |
1030 |
|
|
String fn; |
1031 |
|
|
gDisplay->printf("CHRP: trying to load '%y'\n", &f.getDesc(fn)); |
1032 |
|
|
IO_PROM_TRACE("CHRP: trying to load '%y'\n", &fn); |
1033 |
|
|
try { |
1034 |
|
|
char hdr[13]; |
1035 |
|
|
f.seek(0); |
1036 |
|
|
if (f.read(hdr, 12) != 12) return false; |
1037 |
|
|
hdr[12] = 0; |
1038 |
|
|
IO_PROM_TRACE("header: %s\n", hdr); |
1039 |
|
|
if (strncmp(hdr, "<CHRP-BOOT>", 11)) return false; |
1040 |
|
|
IO_PROM_TRACE("CHRP-BOOT OK\n"); |
1041 |
|
|
char buf[32*1024]; |
1042 |
|
|
uint buflen; |
1043 |
|
|
char tag[32*1024]; |
1044 |
|
|
char expect[4*1024+1]; // sizeof buf+1 |
1045 |
|
|
while (1) { |
1046 |
|
|
chrpReadWaitForChar(f, buf, sizeof buf, '\n'); |
1047 |
|
|
buflen = strlen(buf); |
1048 |
|
|
IO_PROM_TRACE("read %d bytes: %s\n", buflen, buf); |
1049 |
|
|
if (buflen < 1) |
1050 |
|
|
continue; |
1051 |
|
|
if ((buf[0] != '<') || (buflen<3) || (buf[buflen-1] != '>')) return false; |
1052 |
|
|
if (buf[1] == '/') { |
1053 |
|
|
if (memcmp(buf, "</CHRP-BOOT>", buflen-1) != 0) |
1054 |
|
|
return false; |
1055 |
|
|
byte b; |
1056 |
|
|
FileOfs from = f.tell(); |
1057 |
|
|
while (1) { |
1058 |
|
|
if (!f.read(&b, 1)) return false; |
1059 |
|
|
if (b == 0x01) break; |
1060 |
|
|
} |
1061 |
|
|
if (b != 0x01) return false; |
1062 |
|
|
if (!f.read(&b, 1)) return false; |
1063 |
|
|
if (b == 0xdf) { |
1064 |
|
|
PROMBOOT_OUTPUT("Loading XCOFF...\n"); |
1065 |
|
|
return mapped_load_xcoff(f, f.tell()-2); |
1066 |
|
|
} else if (b == 0x02) { |
1067 |
|
|
f.seek(from); |
1068 |
|
|
while (1) { |
1069 |
|
|
if (!f.read(&b, 1)) |
1070 |
|
|
return false; |
1071 |
|
|
if (b == 0x7f) break; |
1072 |
|
|
} |
1073 |
|
|
|
1074 |
|
|
PROMBOOT_OUTPUT("Loading ELF...\n"); |
1075 |
|
|
return mapped_load_elf_from_chrp(f, f.tell()-1); |
1076 |
|
|
} else |
1077 |
|
|
return false; |
1078 |
|
|
} |
1079 |
|
|
expect[0] = '<'; |
1080 |
|
|
expect[1] = '/'; |
1081 |
|
|
int index; |
1082 |
|
|
for (index=0; index<buflen-1; index++) { |
1083 |
|
|
if (buf[index+1] == ' ') break; |
1084 |
|
|
if (buf[index+1] == '>') break; |
1085 |
|
|
expect[index+2] = buf[index+1]; |
1086 |
|
|
} |
1087 |
|
|
//memcpy(expect+2, buf+1, buflen-1); |
1088 |
|
|
//expect[buflen+1] = '\n'; |
1089 |
|
|
expect[index+2] = '>'; |
1090 |
|
|
expect[index+3] = 0; |
1091 |
|
|
strcpy(tag, buf); |
1092 |
|
|
IO_PROM_TRACE("waitforstring: %s\n", expect); |
1093 |
|
|
chrpReadWaitForString(f, buf, sizeof buf, expect); |
1094 |
|
|
IO_PROM_TRACE("found: %s\n", buf); |
1095 |
|
|
if (strcmp(tag, "<BOOT-SCRIPT>") == 0) { |
1096 |
|
|
char *bootpath = strstr(buf, "boot "); |
1097 |
|
|
if (bootpath) { |
1098 |
|
|
bootpath += 5; |
1099 |
|
|
char *bootpathend = strchr(bootpath, '\n'); |
1100 |
|
|
if (!bootpathend) bootpathend = bootpath + strlen(bootpath); |
1101 |
|
|
char mybootpath[1024]; |
1102 |
|
|
char *mybootargs = NULL; |
1103 |
|
|
strncpy(mybootpath, bootpath, sizeof mybootpath-1); |
1104 |
|
|
mybootpath[bootpathend-bootpath] = 0; |
1105 |
|
|
mybootpath[sizeof mybootpath-1] = 0; |
1106 |
|
|
mybootargs = mybootpath+ sizeof mybootpath-1; |
1107 |
|
|
int l = strlen(mybootpath); |
1108 |
|
|
for (int i=0; i<l; i++) { |
1109 |
|
|
if (mybootpath[i] == '\n') { |
1110 |
|
|
mybootpath[i] = 0; |
1111 |
|
|
break; |
1112 |
|
|
} else if (mybootpath[i] == ' ') { |
1113 |
|
|
mybootpath[i] = 0; |
1114 |
|
|
mybootargs = mybootpath+i+1; |
1115 |
|
|
break; |
1116 |
|
|
} |
1117 |
|
|
} |
1118 |
|
|
return chrpBoot(mybootpath, mybootargs); |
1119 |
|
|
} |
1120 |
|
|
} |
1121 |
|
|
#if 0 |
1122 |
|
|
if (strcmp(tag, "<OS-BADGE-ICONS>") == 0) { |
1123 |
|
|
char *t = buf; |
1124 |
|
|
uint width = 1000, height = 1000; |
1125 |
|
|
char fmt[64]; |
1126 |
|
|
while (*t && *t != '\n') t++; |
1127 |
|
|
if (*t == '\n') t++; |
1128 |
|
|
if (t-buf < (int)sizeof buf) { |
1129 |
|
|
strncpy(fmt, buf, t-buf); |
1130 |
|
|
fmt[t-buf] = 0; |
1131 |
|
|
} else { |
1132 |
|
|
fmt[0] = 0; |
1133 |
|
|
} |
1134 |
|
|
// fprintf(stderr, "format string: %s\n", fmt); |
1135 |
|
|
if (strlen(fmt) == 4) { |
1136 |
|
|
uint8 x; |
1137 |
|
|
if (hexb_ex(x, fmt)) width = x; |
1138 |
|
|
if (hexb_ex(x, fmt+2)) height = x; |
1139 |
|
|
} else if (strlen(fmt) == 8) { |
1140 |
|
|
uint16 x; |
1141 |
|
|
if (hexw_ex(x, fmt)) width = x; |
1142 |
|
|
if (hexw_ex(x, fmt+4)) height = x; |
1143 |
|
|
} |
1144 |
|
|
if ((width > 128) || (height > 128)) { |
1145 |
|
|
// safety |
1146 |
|
|
width = 16; |
1147 |
|
|
height = 16; |
1148 |
|
|
} |
1149 |
|
|
byte icon0[width*height]; |
1150 |
|
|
byte icon1[width*height]; |
1151 |
|
|
byte icon2[width*height]; |
1152 |
|
|
readCHRPIcon(icon0, t, width, height); |
1153 |
|
|
readCHRPIcon(icon1, t, width, height); |
1154 |
|
|
readCHRPIcon(icon2, t, width, height); |
1155 |
|
|
uint8 colors2_r[] = {0xff, 0xaa, 0x55, 0x00}; |
1156 |
|
|
uint8 colors3_r[] = {0xff, 0xdb, 0xb7, 0x92, 0x6e, 0x49, 0x25, 0x00}; |
1157 |
|
|
uint8 colors2[] = {0x00, 0x55, 0xaa, 0xff}; |
1158 |
|
|
uint8 colors3[] = {0x00, 0x25, 0x49, 0x6e, 0x92, 0xb7, 0xdb, 0xff}; |
1159 |
|
|
for (uint y=0; y < height; y++) { |
1160 |
|
|
for (uint x=0; x < height; x++) { |
1161 |
|
|
uint8 r = colors3_r[(icon0[x+y*width]>>5) & 0x7]; |
1162 |
|
|
uint8 g = colors3_r[(icon0[x+y*width]>>2) & 0x7]; |
1163 |
|
|
uint8 b = colors2_r[(icon0[x+y*width]>>0) & 0x3]; |
1164 |
|
|
uint src = icon0[x+y*width]; |
1165 |
|
|
r = (src>>5) & 0x7; |
1166 |
|
|
g = (src>>2) & 0x7; |
1167 |
|
|
b = (src>>0) & 0x3; |
1168 |
|
|
r = colors3_r[r]; |
1169 |
|
|
g = colors3_r[g]; |
1170 |
|
|
b = colors2_r[b]; |
1171 |
|
|
RGBA rgba = MK_RGBA(r, g, b, icon2[x+y*width]); |
1172 |
|
|
gDisplay->putPixelRGBA(20+2*x+0, 20+2*y+0, rgba); |
1173 |
|
|
gDisplay->putPixelRGBA(20+2*x+0, 20+2*y+1, rgba); |
1174 |
|
|
gDisplay->putPixelRGBA(20+2*x+1, 20+2*y+0, rgba); |
1175 |
|
|
gDisplay->putPixelRGBA(20+2*x+1, 20+2*y+1, rgba); |
1176 |
|
|
r = ~icon1[x+y*width]; |
1177 |
|
|
g = ~icon1[x+y*width]; |
1178 |
|
|
b = ~icon1[x+y*width]; |
1179 |
|
|
rgba = MK_RGBA(r, g, b, icon2[x+y*width]); |
1180 |
|
|
gDisplay->putPixelRGBA(60+x, 20+y, rgba); |
1181 |
|
|
} |
1182 |
|
|
} |
1183 |
|
|
// while (1) ; |
1184 |
|
|
} |
1185 |
|
|
#endif |
1186 |
|
|
} |
1187 |
|
|
return false; |
1188 |
|
|
} catch (Exception *x) { |
1189 |
|
|
String s; |
1190 |
|
|
IO_PROM_TRACE("mapped_load_chrp: exception: %y\n", &x->reason(s)); |
1191 |
|
|
return false; |
1192 |
|
|
} catch (...) { |
1193 |
|
|
return false; |
1194 |
|
|
} |
1195 |
|
|
} |
1196 |
|
|
|
1197 |
|
|
/* |
1198 |
|
|
* brute force loading |
1199 |
|
|
*/ |
1200 |
|
|
bool mapped_load_flat(const char *filename, uint fileofs, uint filesize, uint vaddr, uint pc) |
1201 |
|
|
{ |
1202 |
|
|
gDisplay->printf("FLAT loading: %s\n", filename); |
1203 |
|
|
|
1204 |
|
|
uint32 pa; |
1205 |
|
|
uint32 ea; |
1206 |
|
|
// allocate image |
1207 |
|
|
pa = vaddr; |
1208 |
|
|
ea = vaddr; |
1209 |
|
|
|
1210 |
|
|
uint32 loadaddr = pa; |
1211 |
|
|
|
1212 |
|
|
for (uint p = 0; p<(filesize+4095) / 4096; p++) { |
1213 |
|
|
if (!init_page_create(ea, pa)) return false; |
1214 |
|
|
ea += 4096; |
1215 |
|
|
pa += 4096; |
1216 |
|
|
} |
1217 |
|
|
|
1218 |
|
|
// allocate stack |
1219 |
|
|
int stackea = 44*1024*1024; |
1220 |
|
|
int stacksize = 40*4096; |
1221 |
|
|
ea = stackea; |
1222 |
|
|
pa = stackea; |
1223 |
|
|
for (int i=0; i<(stacksize+4095) / 4096; i++) { |
1224 |
|
|
if (!init_page_create(ea, pa)) return false; |
1225 |
|
|
ea += 4096; |
1226 |
|
|
pa += 4096; |
1227 |
|
|
} |
1228 |
|
|
|
1229 |
|
|
// allocate bss |
1230 |
|
|
int bssea = 0x1c25000; |
1231 |
|
|
int bsssize = 0x9c000; |
1232 |
|
|
pa = bssea; |
1233 |
|
|
ea = bssea; |
1234 |
|
|
for (int i=0; i<(bsssize+4095) / 4096; i++) { |
1235 |
|
|
if (!init_page_create(ea, pa)) return false; |
1236 |
|
|
ea += 4096; |
1237 |
|
|
pa += 4096; |
1238 |
|
|
} |
1239 |
|
|
|
1240 |
|
|
FILE *f; |
1241 |
|
|
if (!(f = fopen(filename, "rb"))) { |
1242 |
|
|
return false; |
1243 |
|
|
} |
1244 |
|
|
|
1245 |
|
|
fseek(f, fileofs, SEEK_SET); |
1246 |
|
|
|
1247 |
|
|
byte *p = (byte *)malloc(filesize); |
1248 |
|
|
if (!p) return false; |
1249 |
|
|
|
1250 |
|
|
if (fread(p, filesize, 1, f) != 1) { |
1251 |
|
|
free(p); |
1252 |
|
|
return false; |
1253 |
|
|
} |
1254 |
|
|
|
1255 |
|
|
ppc_dma_write(loadaddr, p, filesize); |
1256 |
|
|
|
1257 |
|
|
free(p); |
1258 |
|
|
|
1259 |
|
|
ppc_cpu_set_msr(0, MSR_IR | MSR_DR | MSR_FP); |
1260 |
|
|
ppc_cpu_set_pc(0, pc); |
1261 |
|
|
|
1262 |
|
|
ppc_cpu_set_gpr(0, 1, stackea+stacksize/2); |
1263 |
|
|
ppc_cpu_set_gpr(0, 2, 0); |
1264 |
|
|
ppc_cpu_set_gpr(0, 3, 0x47110815); |
1265 |
|
|
ppc_cpu_set_gpr(0, 4, 0); |
1266 |
|
|
ppc_cpu_set_gpr(0, 5, gPromOSIEntry); |
1267 |
|
|
return true; |
1268 |
|
|
} |
1269 |
|
|
|
1270 |
|
|
bool mapped_load_direct(File &f, uint vaddr, uint pc) |
1271 |
|
|
{ |
1272 |
|
|
String fn; |
1273 |
|
|
gDisplay->printf("direct: trying to load '%y'\n", &f.getDesc(fn)); |
1274 |
|
|
IO_PROM_TRACE("direct: trying to load '%y'\n", &fn); |
1275 |
|
|
|
1276 |
|
|
uint32 pa; |
1277 |
|
|
uint32 ea; |
1278 |
|
|
// allocate image |
1279 |
|
|
pa = vaddr; |
1280 |
|
|
ea = vaddr; |
1281 |
|
|
|
1282 |
|
|
uint32 loadaddr = pa; |
1283 |
|
|
|
1284 |
|
|
uint size = f.getSize(); |
1285 |
|
|
for (uint p = 0; p<(size+4095) / 4096; p++) { |
1286 |
|
|
if (!init_page_create(ea, pa)) return false; |
1287 |
|
|
ea += 4096; |
1288 |
|
|
pa += 4096; |
1289 |
|
|
} |
1290 |
|
|
|
1291 |
|
|
// allocate stack |
1292 |
|
|
int stackea = (vaddr+size + 4096) & 0xfffff000; |
1293 |
|
|
int stacksize = 40*4096; |
1294 |
|
|
ea = stackea; |
1295 |
|
|
pa = stackea; |
1296 |
|
|
for (int i=0; i<(stacksize+4095) / 4096; i++) { |
1297 |
|
|
if (!init_page_create(ea, pa)) return false; |
1298 |
|
|
ea += 4096; |
1299 |
|
|
pa += 4096; |
1300 |
|
|
} |
1301 |
|
|
|
1302 |
|
|
// allocate bss |
1303 |
|
|
/* int bssea = 0x1c25000; |
1304 |
|
|
int bsssize = 0x9c000; |
1305 |
|
|
pa = bssea; |
1306 |
|
|
ea = bssea; |
1307 |
|
|
for (int i=0; i<(bsssize+4095) / 4096; i++) { |
1308 |
|
|
if (!init_page_create(ea, pa)) return false; |
1309 |
|
|
ea += 4096; |
1310 |
|
|
pa += 4096; |
1311 |
|
|
}*/ |
1312 |
|
|
|
1313 |
|
|
// memcpy(pt, mem, size); |
1314 |
|
|
f.seek(0); |
1315 |
|
|
|
1316 |
|
|
byte *p = (byte *)malloc(f.getSize()); |
1317 |
|
|
if (!p) return false; |
1318 |
|
|
|
1319 |
|
|
if (f.read(p, f.getSize()) != f.getSize()) { |
1320 |
|
|
free(p); |
1321 |
|
|
return false; |
1322 |
|
|
} |
1323 |
|
|
|
1324 |
|
|
ppc_dma_write(loadaddr, p, f.getSize()); |
1325 |
|
|
|
1326 |
|
|
free(p); |
1327 |
|
|
|
1328 |
|
|
ppc_cpu_set_msr(0, MSR_IR | MSR_DR | MSR_FP); |
1329 |
|
|
ppc_cpu_set_pc(0, pc); |
1330 |
|
|
|
1331 |
|
|
ppc_cpu_set_gpr(0, 1, stackea+stacksize/2); |
1332 |
|
|
ppc_cpu_set_gpr(0, 2, 0); |
1333 |
|
|
ppc_cpu_set_gpr(0, 3, 0x47110815); |
1334 |
|
|
ppc_cpu_set_gpr(0, 4, 0); |
1335 |
|
|
ppc_cpu_set_gpr(0, 5, gPromOSIEntry); |
1336 |
|
|
return true; |
1337 |
|
|
} |
1338 |
|
|
|
1339 |
|
|
/* |
1340 |
|
|
* Mach-O |
1341 |
|
|
*/ |
1342 |
|
|
#if 0 |
1343 |
|
|
bool mapped_load_mach_o(const char *filename) |
1344 |
|
|
{ |
1345 |
|
|
gDisplay->printf("MACH-O loading: %s\n", filename); |
1346 |
|
|
byte *pt; |
1347 |
|
|
if (ppc_direct_physical_memory_handle(0x0, pt)) { |
1348 |
|
|
return false; |
1349 |
|
|
} |
1350 |
|
|
|
1351 |
|
|
FILE *f; |
1352 |
|
|
f = fopen(filename, "rb"); |
1353 |
|
|
MachOHeader hdr; |
1354 |
|
|
if (fread(&hdr, sizeof hdr, 1, f) != 1) return false; |
1355 |
|
|
createHostStructx(&hdr, sizeof hdr, MACHO_HEADER_struct, big_endian); |
1356 |
|
|
for (uint i=0; i < hdr.ncmds; i++) { |
1357 |
|
|
// ht_printf("cmd %d/%d\n", i+1, hdr.ncmds); |
1358 |
|
|
long fpos = ftell(f); |
1359 |
|
|
MachOCommand cmd; |
1360 |
|
|
if (fread(&cmd, sizeof cmd, 1, f) != 1) return false; |
1361 |
|
|
createHostStructx(&cmd, sizeof cmd, MACHO_COMMAND_struct, big_endian); |
1362 |
|
|
if (cmd.cmd == 1) { |
1363 |
|
|
MachOSegmentCommand seg; |
1364 |
|
|
if (fread(&seg, sizeof seg, 1, f) != 1) return false; |
1365 |
|
|
createHostStructx(&seg, sizeof seg, MACHO_SEGMENT_COMMAND_struct, big_endian); |
1366 |
|
|
// ht_printf("mapping %08x->%08x (%d bytes)\n", seg.fileoff, seg.vmaddr, seg.filesize); |
1367 |
|
|
fseek(f, seg.fileoff, SEEK_SET); |
1368 |
|
|
memset(pt+seg.vmaddr, 0, seg.vmsize); |
1369 |
|
|
if (fread(pt+seg.vmaddr, seg.filesize, 1, f) != 1) return false; |
1370 |
|
|
} else if (cmd.cmd == 5) { |
1371 |
|
|
MachOPPCThreadState ts; |
1372 |
|
|
if (fread(&ts, sizeof ts, 1, f) != 1) return false; |
1373 |
|
|
createHostStructx(&ts, sizeof ts, MACHO_THREAD_COMMAND_struct, big_endian); |
1374 |
|
|
|
1375 |
|
|
gCPU.pc = ts.srr0; |
1376 |
|
|
gCPU.srr[0] = ts.srr0; |
1377 |
|
|
gCPU.srr[1] = ts.srr1; |
1378 |
|
|
|
1379 |
|
|
gCPU.gpr[1] = 8*1024*1024; |
1380 |
|
|
gCPU.gpr[3] = 0x47110815; |
1381 |
|
|
gCPU.gpr[4] = 0x4d4f5358; // MOSX |
1382 |
|
|
gCPU.gpr[5] = gPromOSIEntry; // prom entry |
1383 |
|
|
// gSinglestep = true; |
1384 |
|
|
} |
1385 |
|
|
fseek(f, fpos, SEEK_SET); |
1386 |
|
|
fseek(f, cmd.cmdsize, SEEK_CUR); |
1387 |
|
|
} |
1388 |
|
|
fclose(f); |
1389 |
|
|
return true; |
1390 |
|
|
} |
1391 |
|
|
#endif |
1392 |
|
|
|
1393 |
|
|
/* |
1394 |
|
|
* |
1395 |
|
|
*/ |
1396 |
|
|
class BootRec: public Object { |
1397 |
|
|
public: |
1398 |
|
|
PromNodeDisk *d; |
1399 |
|
|
PartitionEntry *pe; |
1400 |
|
|
int partnum; |
1401 |
|
|
String *devname; |
1402 |
|
|
|
1403 |
|
|
BootRec(PromNodeDisk *aD, PartitionEntry *aPe, int aPartnum, const String &aDevname) |
1404 |
|
|
{ |
1405 |
|
|
d = aD; |
1406 |
|
|
pe = aPe; |
1407 |
|
|
partnum = aPartnum; |
1408 |
|
|
devname = new String(aDevname); |
1409 |
|
|
} |
1410 |
|
|
virtual ~BootRec() |
1411 |
|
|
{ |
1412 |
|
|
delete devname; |
1413 |
|
|
} |
1414 |
|
|
}; |
1415 |
|
|
|
1416 |
|
|
static void read_partitions(Container &brs, bool only_bootable) |
1417 |
|
|
{ |
1418 |
|
|
brs.delAll(); |
1419 |
|
|
char *boot_devices[] = {"cdrom0", "cdrom1", "disk0", "disk1", NULL}; |
1420 |
|
|
char **boot_device = boot_devices; |
1421 |
|
|
while (*boot_device) { |
1422 |
|
|
PromNode *node = findDevice(*boot_device, FIND_DEVICE_FIND, NULL); |
1423 |
|
|
PromNodeDisk *d = dynamic_cast<PromNodeDisk*>(node); |
1424 |
|
|
if (d) { |
1425 |
|
|
Enumerator *e = d->pm->getPartitions(); |
1426 |
|
|
int partnum=0; |
1427 |
|
|
foreach(PartitionEntry, pe, *e, |
1428 |
|
|
if (!only_bootable || (pe->mBootMethod != BM_none)) { |
1429 |
|
|
brs.insert(new BootRec(d, pe, partnum, *boot_device)); |
1430 |
|
|
} |
1431 |
|
|
partnum++; |
1432 |
|
|
); |
1433 |
|
|
} |
1434 |
|
|
boot_device++; |
1435 |
|
|
} |
1436 |
|
|
} |
1437 |
|
|
|
1438 |
|
|
bool prom_user_boot_partition(File *&ret_file, uint32 &size, bool &direct, uint32 &loadAddr, uint32 &entryAddr) |
1439 |
|
|
{ |
1440 |
|
|
gDisplay->setAnsiColor(VCP(VC_LIGHT(VC_YELLOW), VC_TRANSPARENT)); |
1441 |
|
|
gDisplay->printf("\n PROM boot-loader\n"); |
1442 |
|
|
gDisplay->printf(" ==================\n\n"); |
1443 |
|
|
Array brs(true); |
1444 |
|
|
read_partitions(brs, true); |
1445 |
|
|
char key2digit[256]; |
1446 |
|
|
for (int i=0; i<256; i++) key2digit[i] = -1; |
1447 |
|
|
key2digit[KEY_0] = 0; |
1448 |
|
|
key2digit[KEY_1] = 1; |
1449 |
|
|
key2digit[KEY_2] = 2; |
1450 |
|
|
key2digit[KEY_3] = 3; |
1451 |
|
|
key2digit[KEY_4] = 4; |
1452 |
|
|
key2digit[KEY_5] = 5; |
1453 |
|
|
key2digit[KEY_6] = 6; |
1454 |
|
|
key2digit[KEY_7] = 7; |
1455 |
|
|
key2digit[KEY_8] = 8; |
1456 |
|
|
key2digit[KEY_9] = 9; |
1457 |
|
|
|
1458 |
|
|
bool only_bootable = true; |
1459 |
|
|
|
1460 |
|
|
while (1) { |
1461 |
|
|
if (gPromBootMethod == prombmSelect) gDisplay->printf("Which partition do you want to boot?\n"); |
1462 |
|
|
if (only_bootable) { |
1463 |
|
|
gDisplay->printf("\n%d bootable partition(s) found:\n", brs.count()); |
1464 |
|
|
if (gPromBootMethod == prombmSelect) { |
1465 |
|
|
gDisplay->printf(" 0. Show all (even unbootable)\n"); |
1466 |
|
|
} |
1467 |
|
|
} else { |
1468 |
|
|
gDisplay->printf("\n%d partition(s) found:\n", brs.count()); |
1469 |
|
|
gDisplay->printf(" 0. Show only bootable\n"); |
1470 |
|
|
} |
1471 |
|
|
for (uint i=0; i < brs.count(); i++) { |
1472 |
|
|
BootRec *bootrec = dynamic_cast<BootRec *>(brs[i]); |
1473 |
|
|
gDisplay->printf(" %2d. partition %d of '%y' (%s/%s)\n", i+1, bootrec->partnum, bootrec->devname, bootrec->pe->mName, bootrec->pe->mType); |
1474 |
|
|
} |
1475 |
|
|
uint choice = 0; |
1476 |
|
|
if (gPromBootMethod == prombmSelect) { |
1477 |
|
|
gDisplay->printf("\nYour choice (ESC abort):"); |
1478 |
|
|
while (1) { |
1479 |
|
|
gDisplay->printf("\r\e[0K\rYour choice (ESC abort): %d", choice); |
1480 |
|
|
uint32 keycode; |
1481 |
|
|
do { |
1482 |
|
|
while (!cuda_prom_get_key(keycode)) sys_suspend(); |
1483 |
|
|
} while (keycode & 0x80); |
1484 |
|
|
|
1485 |
|
|
if (keycode == KEY_DELETE) choice = 0; else |
1486 |
|
|
if (keycode == KEY_RETURN) break; else |
1487 |
|
|
if (keycode == KEY_ESCAPE) return false; |
1488 |
|
|
|
1489 |
|
|
if ((keycode<256) && (key2digit[keycode]>=0)) { |
1490 |
|
|
choice *= 10; |
1491 |
|
|
choice += key2digit[keycode]; |
1492 |
|
|
} |
1493 |
|
|
} |
1494 |
|
|
} else { |
1495 |
|
|
choice = 1; |
1496 |
|
|
} |
1497 |
|
|
if (choice == 0) { |
1498 |
|
|
gDisplay->printf("\n\n"); |
1499 |
|
|
only_bootable = !only_bootable; |
1500 |
|
|
read_partitions(brs, only_bootable); |
1501 |
|
|
continue; |
1502 |
|
|
} |
1503 |
|
|
gPromBootMethod = prombmSelect; |
1504 |
|
|
if ((choice > 0) && (choice <= brs.count())) { |
1505 |
|
|
choice--; |
1506 |
|
|
BootRec *bootrec = dynamic_cast<BootRec *>(brs[choice]); |
1507 |
|
|
if (bootrec->pe->mBootMethod == BM_none) { |
1508 |
|
|
gDisplay->printf("\nThis partition is not bootable!\n"); |
1509 |
|
|
continue; |
1510 |
|
|
} |
1511 |
|
|
gDisplay->printf("\nBooting %d: '%y:%d'...\n", choice+1, bootrec->devname, bootrec->partnum); |
1512 |
|
|
// FIXME: ic hack |
1513 |
|
|
IDEConfig *ic = ide_get_config(bootrec->d->mNumber); |
1514 |
|
|
File *rawFile = ic->device->promGetRawFile(); |
1515 |
|
|
File *bootFile = bootrec->pe->mInstantiateBootFile(rawFile, |
1516 |
|
|
bootrec->pe->mInstantiateBootFilePrivData); |
1517 |
|
|
if (!bootFile) { |
1518 |
|
|
IO_PROM_ERR("can't open boot file\n"); |
1519 |
|
|
return false; |
1520 |
|
|
} |
1521 |
|
|
uint bootFileSize = bootFile->getSize(); |
1522 |
|
|
if (bootFileSize > 64*1024*1024) { |
1523 |
|
|
gDisplay->printf("Boot file too large. size=%d (>64MB)\n", bootFileSize); |
1524 |
|
|
continue; |
1525 |
|
|
} |
1526 |
|
|
// set bootpath |
1527 |
|
|
char bootpath[1024]; |
1528 |
|
|
char devicebootpath[1024]; |
1529 |
|
|
bootrec->d->toPath(devicebootpath, sizeof devicebootpath); |
1530 |
|
|
ht_snprintf(bootpath, sizeof bootpath, "%s:%d,BootX", devicebootpath, bootrec->partnum); |
1531 |
|
|
// ht_snprintf(bootpath, sizeof bootpath, "/pci/pci-bridge/pci-ata/ata-4/disk1@1:9,BootX"); |
1532 |
|
|
PromNode *chosen = findDevice("/chosen", FIND_DEVICE_FIND, NULL); |
1533 |
|
|
if (chosen) { |
1534 |
|
|
chosen->addProp(new PromPropString("bootpath", bootpath)); |
1535 |
|
|
} |
1536 |
|
|
|
1537 |
|
|
ret_file = bootFile; |
1538 |
|
|
// FIXME: HACK!!! |
1539 |
|
|
gBootPartNum = bootrec->partnum; |
1540 |
|
|
gBootNodeID = bootrec->d->getPHandle(); |
1541 |
|
|
|
1542 |
|
|
gDisplay->setAnsiColor(VCP(VC_LIGHT(VC_BLUE), VC_TRANSPARENT)); |
1543 |
|
|
size = bootFileSize; |
1544 |
|
|
switch (bootrec->pe->mBootMethod) { |
1545 |
|
|
case BM_chrp: { |
1546 |
|
|
direct = false; |
1547 |
|
|
return true; |
1548 |
|
|
} |
1549 |
|
|
case BM_direct: { |
1550 |
|
|
direct = true; |
1551 |
|
|
loadAddr = bootrec->pe->mBootImageLoadAddr; |
1552 |
|
|
entryAddr = bootrec->pe->mBootImageEntrypoint; |
1553 |
|
|
return true; |
1554 |
|
|
} |
1555 |
|
|
default: |
1556 |
|
|
ASSERT(0); |
1557 |
|
|
} |
1558 |
|
|
return false; |
1559 |
|
|
} else { |
1560 |
|
|
gDisplay->printf("\nInvalid choice, try again.\n"); |
1561 |
|
|
} |
1562 |
|
|
} |
1563 |
|
|
return false; |
1564 |
|
|
} |
1565 |
|
|
|
1566 |
|
|
bool prom_load_boot_file() |
1567 |
|
|
{ |
1568 |
|
|
if (gPromBootMethod == prombmForce) { |
1569 |
|
|
if (gConfig->haveKey("prom_loadfile")) { |
1570 |
|
|
String loadfile; |
1571 |
|
|
gConfig->getConfigString("prom_loadfile", loadfile); |
1572 |
|
|
PromNode *pn = findDevice(gPromBootPath.contentChar(), FIND_DEVICE_FIND, NULL); |
1573 |
|
|
if (pn) { |
1574 |
|
|
gBootNodeID = pn->getPHandle(); |
1575 |
|
|
String dev, rest; |
1576 |
|
|
gPromBootPath.leftSplit(':', dev, rest); |
1577 |
|
|
String partNum, rest2; |
1578 |
|
|
rest.leftSplit(',', partNum, rest2); |
1579 |
|
|
uint32 p; |
1580 |
|
|
if (partNum.toInt32(p)) gBootPartNum = p; |
1581 |
|
|
} |
1582 |
|
|
|
1583 |
|
|
LocalFile f(loadfile); |
1584 |
|
|
// if (!mapped_load_elf_from_chrp(f, 0) |
1585 |
|
|
if (!mapped_load_elf(f) |
1586 |
|
|
&& !mapped_load_xcoff(f, 0) |
1587 |
|
|
&& !mapped_load_chrp(f)) { |
1588 |
|
|
IO_PROM_WARN("couldn't load '%y'.\n", &loadfile); |
1589 |
|
|
return false; |
1590 |
|
|
} |
1591 |
|
|
} else { |
1592 |
|
|
IO_PROM_ERR("bootmethod is 'force', but no prom_loadfile defined\n"); |
1593 |
|
|
return false; |
1594 |
|
|
} |
1595 |
|
|
} else { |
1596 |
|
|
uint32 loadAddr; |
1597 |
|
|
uint32 entryAddr; |
1598 |
|
|
File *f; |
1599 |
|
|
uint32 msize; |
1600 |
|
|
bool direct; |
1601 |
|
|
if (!prom_user_boot_partition(f, msize, direct, loadAddr, entryAddr)) { |
1602 |
|
|
IO_PROM_WARN("Can't boot a partition.\nTry bootmethod 'force' and specify a 'prom_loadfile' in your config-file...\n"); |
1603 |
|
|
return false; |
1604 |
|
|
} |
1605 |
|
|
try { |
1606 |
|
|
LocalFile lf("bootfile.dump", IOAM_WRITE, FOM_CREATE); |
1607 |
|
|
f->seek(0); |
1608 |
|
|
f->copyAllTo(&lf); |
1609 |
|
|
} catch (...) { |
1610 |
|
|
printf("error dumping bootfile"); |
1611 |
|
|
} |
1612 |
|
|
if (direct) { |
1613 |
|
|
if (!mapped_load_direct(*f, loadAddr, entryAddr)) { |
1614 |
|
|
IO_PROM_TRACE("couldn't load.\n"); |
1615 |
|
|
return false; |
1616 |
|
|
} |
1617 |
|
|
} else { |
1618 |
|
|
if (!mapped_load_chrp(*f)) { |
1619 |
|
|
IO_PROM_TRACE("couldn't load.\n"); |
1620 |
|
|
return false; |
1621 |
|
|
} |
1622 |
|
|
} |
1623 |
|
|
delete f; |
1624 |
|
|
} |
1625 |
|
|
return true; |
1626 |
|
|
} |