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' (CHRP)\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 entry; |
707 |
uint32 la = ELF_LOAD_ADDRESS; |
708 |
f.seek(0x2c); |
709 |
uint16 program_hdrs; |
710 |
f.readx(&program_hdrs, 2); |
711 |
program_hdrs = createHostInt(&program_hdrs, 2, big_endian); |
712 |
uint32 stack=0; |
713 |
uint32 stackp=0; |
714 |
for (int i=0; i<program_hdrs; i++) { |
715 |
IO_PROM_TRACE("program header %d:\n", i); |
716 |
ELF_PROGRAM_HEADER32 program_hdr; |
717 |
f.seek(0x34+i*sizeof program_hdr); |
718 |
f.readx(&program_hdr, sizeof program_hdr); |
719 |
createHostStructx(&program_hdr, sizeof program_hdr, ELF_PROGRAM_HEADER32_struct, big_endian); |
720 |
uint32 pages_from_file = program_hdr.p_filesz / 4096; |
721 |
uint32 ea = program_hdr.p_vaddr; |
722 |
ea = 0x00000000; // XXX force load to beginning of RAM |
723 |
entry = ea; |
724 |
sint32 vs = program_hdr.p_memsz; |
725 |
f.seek(program_hdr.p_offset); |
726 |
uint32 fo = program_hdr.p_offset; |
727 |
byte page[4096]; |
728 |
while (pages_from_file) { |
729 |
IO_PROM_TRACE("loading from %08x to ea:%08x (pa:%08x)\n", fo, ea, la); |
730 |
f.readx(page, sizeof page); |
731 |
if (!init_page_create(ea, la)) return false; |
732 |
if (!ppc_dma_write(la, page, 4096)) { |
733 |
return false; |
734 |
} |
735 |
pages_from_file--; |
736 |
la += 4096; |
737 |
ea += 4096; |
738 |
fo += 4096; |
739 |
vs -= 4096; |
740 |
} |
741 |
if (program_hdr.p_filesz % 4096) { |
742 |
ht_printf("loading remaining from %08x to ea:%08x (pa:%08x)\n", fo, ea, la); |
743 |
f.read(page, program_hdr.p_filesz % 4096); |
744 |
if (!init_page_create(ea, la)) return false; |
745 |
if (!ppc_dma_write(la+(ea&0xfff), page, program_hdr.p_filesz % 4096)) { |
746 |
return false; |
747 |
} |
748 |
la += 4096; |
749 |
ea += 4096; |
750 |
fo += 4096; |
751 |
vs -= 4096; |
752 |
} |
753 |
while (vs > 0) { |
754 |
ht_printf("creating for ea:%08x (pa:%08x)\n", ea, la); |
755 |
if (!init_page_create(ea, la)) return false; |
756 |
la += 4096; |
757 |
ea += 4096; |
758 |
vs -= 4096; |
759 |
} |
760 |
stack = ea; |
761 |
stackp = la; |
762 |
} |
763 |
|
764 |
stack = gMemorySize - 65536 - (4096*20) - PROM_MEM_SIZE; |
765 |
stackp = gMemorySize - 65536 - (4096*20) - PROM_MEM_SIZE; |
766 |
// allocate stack |
767 |
for (int i=0; i<20; i++) { |
768 |
if (!init_page_create(stack, stackp)) return false; |
769 |
stack += 4096; |
770 |
stackp += 4096; |
771 |
} |
772 |
|
773 |
gDisplay->printf("starting from PC %08x\n", entry); |
774 |
|
775 |
// turn on address translation |
776 |
ppc_cpu_set_msr(0, MSR_IR | MSR_DR | MSR_FP); |
777 |
ppc_cpu_set_pc(0, entry); |
778 |
|
779 |
ppc_cpu_set_gpr(0, 1, gMemorySize - 65536 - 32 - PROM_MEM_SIZE); |
780 |
ppc_cpu_set_gpr(0, 2, 0); |
781 |
ppc_cpu_set_gpr(0, 3, 0); |
782 |
ppc_cpu_set_gpr(0, 4, 0); |
783 |
ppc_cpu_set_gpr(0, 5, gPromOSIEntry); |
784 |
|
785 |
// wtf?! |
786 |
ppc_prom_page_create(0, 0); |
787 |
return true; |
788 |
} catch (...) { |
789 |
return false; |
790 |
} |
791 |
} |
792 |
|
793 |
/* |
794 |
* XCOFF |
795 |
*/ |
796 |
bool mapped_load_xcoff(File &f, uint disp_ofs) |
797 |
{ |
798 |
String fn; |
799 |
gDisplay->printf("XCOFF trying to load '%y'\n", &f.getDesc(fn)); |
800 |
IO_PROM_TRACE("XCOFF trying to load '%y'\n", &fn); |
801 |
|
802 |
f.seek(disp_ofs); |
803 |
try { |
804 |
COFF_HEADER hdr; |
805 |
f.readx(&hdr, sizeof hdr); |
806 |
createHostStructx(&hdr, sizeof hdr, COFF_HEADER_struct, big_endian); |
807 |
if (hdr.machine != 0x1df) { |
808 |
IO_PROM_TRACE("invalid machine %04x (expecting 01df)\n", hdr.machine); |
809 |
return false; |
810 |
} |
811 |
if (hdr.optional_header_size != 0x48) { |
812 |
IO_PROM_TRACE("invalid optional header size %04x (expecting 0048)\n", hdr.optional_header_size); |
813 |
return false; |
814 |
} |
815 |
uint32 stack=0; |
816 |
uint32 stackp=0; |
817 |
uint32 entrypoint; |
818 |
uint32 entrypoint_ofs = 0; |
819 |
f.seek(disp_ofs+0x24); |
820 |
f.readx(&entrypoint, 4); |
821 |
entrypoint = createHostInt(&entrypoint, 4, big_endian); |
822 |
|
823 |
for (int i=0; i<hdr.section_count; i++) { |
824 |
// ht_printf("program header %d:\n", i); |
825 |
COFF_SECTION_HEADER shdr; |
826 |
f.seek(disp_ofs+0x5c+i*sizeof shdr); |
827 |
f.readx(&shdr, sizeof shdr); |
828 |
createHostStructx(&shdr, sizeof shdr, COFF_SECTION_HEADER_struct, big_endian); |
829 |
if ((entrypoint >= shdr.data_address) && (entrypoint < shdr.data_address+shdr.data_size)) { |
830 |
IO_PROM_TRACE("found entrypoint-structure in section %d\n", i); |
831 |
entrypoint_ofs = entrypoint - shdr.data_address + shdr.data_offset; |
832 |
} |
833 |
uint32 in_file_size = (shdr.data_offset) ? shdr.data_size : 0; |
834 |
uint32 pages_from_file = in_file_size / 4096; |
835 |
uint32 pa = shdr.data_vsize; /* really: physical addr */ |
836 |
uint32 ea = shdr.data_address; |
837 |
sint32 vs = shdr.data_size; |
838 |
f.seek(disp_ofs+shdr.data_offset); |
839 |
uint32 fo = shdr.data_offset; |
840 |
byte page[4096]; |
841 |
while (pages_from_file) { |
842 |
// ht_printf("loading from %08x to ea:%08x (pa:%08x)\n", fo, ea, pa); |
843 |
f.readx(page, sizeof page); |
844 |
if (!init_page_create(ea, pa)) return false; |
845 |
if (!ppc_dma_write(pa, page, 4096)) { |
846 |
return false; |
847 |
} |
848 |
pages_from_file--; |
849 |
pa += 4096; |
850 |
ea += 4096; |
851 |
fo += 4096; |
852 |
vs -= 4096; |
853 |
} |
854 |
if (in_file_size % 4096) { |
855 |
// ht_printf("loading remaining from %08x to ea:%08x (pa:%08x)\n", fo, ea, pa); |
856 |
f.readx(page, in_file_size % 4096); |
857 |
if (!init_page_create(ea, pa)) return false; |
858 |
if (!ppc_dma_write(pa+(ea&0xfff), page, in_file_size % 4096)) { |
859 |
return false; |
860 |
} |
861 |
pa += 4096; |
862 |
ea += 4096; |
863 |
fo += 4096; |
864 |
vs -= 4096; |
865 |
} |
866 |
while (vs > 0) { |
867 |
// ht_printf("creating for ea:%08x (pa:%08x)\n", ea, pa); |
868 |
if (!init_page_create(ea, pa)) return false; |
869 |
pa += 4096; |
870 |
ea += 4096; |
871 |
vs -= 4096; |
872 |
} |
873 |
stack = ea; |
874 |
stackp = pa; |
875 |
} |
876 |
if (!entrypoint_ofs) { |
877 |
IO_PROM_TRACE("couldn't find entrypoint offset\n"); |
878 |
return false; |
879 |
} |
880 |
// allocate stack |
881 |
for (int i=0; i<20; i++) { |
882 |
if (!init_page_create(stack, stackp)) return false; |
883 |
stack += 4096; |
884 |
stackp += 4096; |
885 |
} |
886 |
|
887 |
uint32 real_entrypoint = 0; |
888 |
f.seek(disp_ofs+entrypoint_ofs); |
889 |
f.read(&real_entrypoint, 4); |
890 |
real_entrypoint = createHostInt(&real_entrypoint, 4, big_endian); |
891 |
IO_PROM_TRACE("real_entrypoint = %08x\n", real_entrypoint); |
892 |
// turn on address translation |
893 |
ppc_cpu_set_msr(0, MSR_IR | MSR_DR | MSR_FP); |
894 |
ppc_cpu_set_pc(0, real_entrypoint); |
895 |
|
896 |
ppc_cpu_set_gpr(0, 1, stack-(4096+32)); |
897 |
ppc_cpu_set_gpr(0, 2, 0); |
898 |
ppc_cpu_set_gpr(0, 3, 0); |
899 |
ppc_cpu_set_gpr(0, 4, 0); |
900 |
ppc_cpu_set_gpr(0, 5, gPromOSIEntry); |
901 |
|
902 |
return true; |
903 |
} catch (...) { |
904 |
return false; |
905 |
} |
906 |
} |
907 |
|
908 |
static void chrpReadWaitForChar(File &f, char *buf, uint buflen, char waitFor) |
909 |
{ |
910 |
while (buflen) { |
911 |
f.readx(buf, 1); |
912 |
|
913 |
if (*buf == 0x0d) *buf = '\n'; |
914 |
|
915 |
if (!*buf) throw new MsgException("Binary files not allowed here"); |
916 |
if (*buf == waitFor) { |
917 |
*buf = 0; |
918 |
return; |
919 |
} |
920 |
buf++; |
921 |
buflen--; |
922 |
} |
923 |
throw new MsgException("wait for char failed"); |
924 |
} |
925 |
|
926 |
static void chrpReadWaitForString(File &f, char *buf, uint buflen, char *waitFor) |
927 |
{ |
928 |
uint zlen = strlen(waitFor); |
929 |
char *z = strdup(waitFor); |
930 |
*z = 0; |
931 |
*buf = 0; |
932 |
if (!zlen) return; |
933 |
FileOfs o = f.tell(); |
934 |
while (buflen) { |
935 |
f.seek(o); |
936 |
f.readx(z, zlen); |
937 |
if (strcmp(z, waitFor) == 0) { |
938 |
*buf = 0; |
939 |
free(z); |
940 |
return; |
941 |
} |
942 |
if (buf != NULL) { |
943 |
*buf = (*z == 0xd) ? '\n' : *z; |
944 |
buf++; |
945 |
buflen--; |
946 |
} |
947 |
o++; |
948 |
} |
949 |
free(z); |
950 |
throw new MsgException("wait for string failed"); |
951 |
} |
952 |
|
953 |
#if 0 |
954 |
static void readCHRPIcon(byte *icon, char *&t, uint width, uint height) |
955 |
{ |
956 |
memset(icon, 0, width*height); |
957 |
uint y = 0; |
958 |
uint x = 0; |
959 |
while (t[0] && t[1]) { |
960 |
if (t[0] == '\n') { |
961 |
while (*t == '\n') t++; |
962 |
// fprintf(stderr, "parse icon: line %d length %d\n", y, x); |
963 |
x = 0; |
964 |
y++; |
965 |
if (y >= height) break; |
966 |
continue; |
967 |
} |
968 |
if (x>=width) break; |
969 |
hexb_ex(icon[x+y*width], t); |
970 |
t += 2; |
971 |
x++; |
972 |
} |
973 |
} |
974 |
#endif |
975 |
|
976 |
static bool chrpBoot(const char *bootpath, const char *bootargs) |
977 |
{ |
978 |
IO_PROM_TRACE("CHRP boot file (bootpath = %s, bootargs = %s).\n", bootpath, bootargs); |
979 |
// set bootpath in device tree |
980 |
PromNode *chosen = findDevice("/chosen", FIND_DEVICE_FIND, NULL); |
981 |
if (chosen) { |
982 |
PromProp *bp = chosen->findProp("bootpath"); |
983 |
if (bp) { |
984 |
PromPropString *s = dynamic_cast<PromPropString*>(bp); |
985 |
if (s) { |
986 |
free(s->value); |
987 |
s->value = strdup(bootpath); |
988 |
} |
989 |
} else { |
990 |
chosen->addProp(new PromPropString("bootpath", bootpath)); |
991 |
} |
992 |
PromProp *ba = chosen->findProp("bootargs"); |
993 |
if (ba) { |
994 |
PromPropString *s = dynamic_cast<PromPropString*>(ba); |
995 |
if (s) { |
996 |
free(s->value); |
997 |
s->value = strdup(bootargs); |
998 |
} |
999 |
} else { |
1000 |
chosen->addProp(new PromPropString("bootargs", bootargs)); |
1001 |
} |
1002 |
} |
1003 |
|
1004 |
PromInstanceHandle ih; |
1005 |
if (!findDevice(bootpath, FIND_DEVICE_OPEN, &ih)) return false; |
1006 |
|
1007 |
PromInstanceDiskFile *ix = dynamic_cast<PromInstanceDiskFile*>(handleToInstance(ih)); |
1008 |
if (!ix || !ix->mFile) { |
1009 |
IO_PROM_TRACE("couldn't load CHRP boot file (1) (bootpath = %s).\n", bootpath); |
1010 |
return false; |
1011 |
} |
1012 |
|
1013 |
PromNode *pn = ix->getType(); |
1014 |
File *f = ix->mFile; |
1015 |
|
1016 |
if (!mapped_load_elf(*f) |
1017 |
&& !mapped_load_xcoff(*f, 0) |
1018 |
&& !mapped_load_chrp(*f)) { |
1019 |
IO_PROM_TRACE("couldn't load CHRP boot file (2) (bootpath = %s).\n", bootpath); |
1020 |
pn->close(ih); |
1021 |
return false; |
1022 |
} |
1023 |
pn->close(ih); |
1024 |
return true; |
1025 |
} |
1026 |
|
1027 |
bool mapped_load_chrp(File &f) |
1028 |
{ |
1029 |
String fn; |
1030 |
gDisplay->printf("CHRP: trying to load '%y'\n", &f.getDesc(fn)); |
1031 |
IO_PROM_TRACE("CHRP: trying to load '%y'\n", &fn); |
1032 |
try { |
1033 |
char hdr[13]; |
1034 |
f.seek(0); |
1035 |
if (f.read(hdr, 12) != 12) return false; |
1036 |
hdr[12] = 0; |
1037 |
IO_PROM_TRACE("header: %s\n", hdr); |
1038 |
if (strncmp(hdr, "<CHRP-BOOT>", 11)) return false; |
1039 |
IO_PROM_TRACE("CHRP-BOOT OK\n"); |
1040 |
char buf[32*1024]; |
1041 |
uint buflen; |
1042 |
char tag[32*1024]; |
1043 |
char expect[4*1024+1]; // sizeof buf+1 |
1044 |
while (1) { |
1045 |
chrpReadWaitForChar(f, buf, sizeof buf, '\n'); |
1046 |
buflen = strlen(buf); |
1047 |
IO_PROM_TRACE("read %d bytes: %s\n", buflen, buf); |
1048 |
if (buflen < 1) |
1049 |
continue; |
1050 |
if ((buf[0] != '<') || (buflen<3) || (buf[buflen-1] != '>')) return false; |
1051 |
if (buf[1] == '/') { |
1052 |
if (memcmp(buf, "</CHRP-BOOT>", buflen-1) != 0) |
1053 |
return false; |
1054 |
byte b; |
1055 |
FileOfs from = f.tell(); |
1056 |
while (1) { |
1057 |
if (!f.read(&b, 1)) return false; |
1058 |
if (b == 0x01) break; |
1059 |
} |
1060 |
if (b != 0x01) return false; |
1061 |
if (!f.read(&b, 1)) return false; |
1062 |
if (b == 0xdf) { |
1063 |
PROMBOOT_OUTPUT("Loading XCOFF...\n"); |
1064 |
return mapped_load_xcoff(f, f.tell()-2); |
1065 |
} else if (b == 0x02) { |
1066 |
f.seek(from); |
1067 |
while (1) { |
1068 |
if (!f.read(&b, 1)) |
1069 |
return false; |
1070 |
if (b == 0x7f) break; |
1071 |
} |
1072 |
|
1073 |
PROMBOOT_OUTPUT("Loading ELF...\n"); |
1074 |
return mapped_load_elf_from_chrp(f, f.tell()-1); |
1075 |
} else |
1076 |
return false; |
1077 |
} |
1078 |
expect[0] = '<'; |
1079 |
expect[1] = '/'; |
1080 |
int index; |
1081 |
for (index=0; index<buflen-1; index++) { |
1082 |
if (buf[index+1] == ' ') break; |
1083 |
if (buf[index+1] == '>') break; |
1084 |
expect[index+2] = buf[index+1]; |
1085 |
} |
1086 |
//memcpy(expect+2, buf+1, buflen-1); |
1087 |
//expect[buflen+1] = '\n'; |
1088 |
expect[index+2] = '>'; |
1089 |
expect[index+3] = 0; |
1090 |
strcpy(tag, buf); |
1091 |
IO_PROM_TRACE("waitforstring: %s\n", expect); |
1092 |
chrpReadWaitForString(f, buf, sizeof buf, expect); |
1093 |
IO_PROM_TRACE("found: %s\n", buf); |
1094 |
if (strcmp(tag, "<BOOT-SCRIPT>") == 0) { |
1095 |
char *bootpath = strstr(buf, "boot "); |
1096 |
if (bootpath) { |
1097 |
bootpath += 5; |
1098 |
char *bootpathend = strchr(bootpath, '\n'); |
1099 |
if (!bootpathend) bootpathend = bootpath + strlen(bootpath); |
1100 |
char mybootpath[1024]; |
1101 |
char *mybootargs = NULL; |
1102 |
strncpy(mybootpath, bootpath, sizeof mybootpath-1); |
1103 |
mybootpath[bootpathend-bootpath] = 0; |
1104 |
mybootpath[sizeof mybootpath-1] = 0; |
1105 |
mybootargs = mybootpath+ sizeof mybootpath-1; |
1106 |
int l = strlen(mybootpath); |
1107 |
for (int i=0; i<l; i++) { |
1108 |
if (mybootpath[i] == '\n') { |
1109 |
mybootpath[i] = 0; |
1110 |
break; |
1111 |
} else if (mybootpath[i] == ' ') { |
1112 |
mybootpath[i] = 0; |
1113 |
mybootargs = mybootpath+i+1; |
1114 |
break; |
1115 |
} |
1116 |
} |
1117 |
return chrpBoot(mybootpath, mybootargs); |
1118 |
} |
1119 |
} |
1120 |
#if 0 |
1121 |
if (strcmp(tag, "<OS-BADGE-ICONS>") == 0) { |
1122 |
char *t = buf; |
1123 |
uint width = 1000, height = 1000; |
1124 |
char fmt[64]; |
1125 |
while (*t && *t != '\n') t++; |
1126 |
if (*t == '\n') t++; |
1127 |
if (t-buf < (int)sizeof buf) { |
1128 |
strncpy(fmt, buf, t-buf); |
1129 |
fmt[t-buf] = 0; |
1130 |
} else { |
1131 |
fmt[0] = 0; |
1132 |
} |
1133 |
// fprintf(stderr, "format string: %s\n", fmt); |
1134 |
if (strlen(fmt) == 4) { |
1135 |
uint8 x; |
1136 |
if (hexb_ex(x, fmt)) width = x; |
1137 |
if (hexb_ex(x, fmt+2)) height = x; |
1138 |
} else if (strlen(fmt) == 8) { |
1139 |
uint16 x; |
1140 |
if (hexw_ex(x, fmt)) width = x; |
1141 |
if (hexw_ex(x, fmt+4)) height = x; |
1142 |
} |
1143 |
if ((width > 128) || (height > 128)) { |
1144 |
// safety |
1145 |
width = 16; |
1146 |
height = 16; |
1147 |
} |
1148 |
byte icon0[width*height]; |
1149 |
byte icon1[width*height]; |
1150 |
byte icon2[width*height]; |
1151 |
readCHRPIcon(icon0, t, width, height); |
1152 |
readCHRPIcon(icon1, t, width, height); |
1153 |
readCHRPIcon(icon2, t, width, height); |
1154 |
uint8 colors2_r[] = {0xff, 0xaa, 0x55, 0x00}; |
1155 |
uint8 colors3_r[] = {0xff, 0xdb, 0xb7, 0x92, 0x6e, 0x49, 0x25, 0x00}; |
1156 |
uint8 colors2[] = {0x00, 0x55, 0xaa, 0xff}; |
1157 |
uint8 colors3[] = {0x00, 0x25, 0x49, 0x6e, 0x92, 0xb7, 0xdb, 0xff}; |
1158 |
for (uint y=0; y < height; y++) { |
1159 |
for (uint x=0; x < height; x++) { |
1160 |
uint8 r = colors3_r[(icon0[x+y*width]>>5) & 0x7]; |
1161 |
uint8 g = colors3_r[(icon0[x+y*width]>>2) & 0x7]; |
1162 |
uint8 b = colors2_r[(icon0[x+y*width]>>0) & 0x3]; |
1163 |
uint src = icon0[x+y*width]; |
1164 |
r = (src>>5) & 0x7; |
1165 |
g = (src>>2) & 0x7; |
1166 |
b = (src>>0) & 0x3; |
1167 |
r = colors3_r[r]; |
1168 |
g = colors3_r[g]; |
1169 |
b = colors2_r[b]; |
1170 |
RGBA rgba = MK_RGBA(r, g, b, icon2[x+y*width]); |
1171 |
gDisplay->putPixelRGBA(20+2*x+0, 20+2*y+0, rgba); |
1172 |
gDisplay->putPixelRGBA(20+2*x+0, 20+2*y+1, rgba); |
1173 |
gDisplay->putPixelRGBA(20+2*x+1, 20+2*y+0, rgba); |
1174 |
gDisplay->putPixelRGBA(20+2*x+1, 20+2*y+1, rgba); |
1175 |
r = ~icon1[x+y*width]; |
1176 |
g = ~icon1[x+y*width]; |
1177 |
b = ~icon1[x+y*width]; |
1178 |
rgba = MK_RGBA(r, g, b, icon2[x+y*width]); |
1179 |
gDisplay->putPixelRGBA(60+x, 20+y, rgba); |
1180 |
} |
1181 |
} |
1182 |
// while (1) ; |
1183 |
} |
1184 |
#endif |
1185 |
} |
1186 |
return false; |
1187 |
} catch (Exception *x) { |
1188 |
String s; |
1189 |
IO_PROM_TRACE("mapped_load_chrp: exception: %y\n", &x->reason(s)); |
1190 |
return false; |
1191 |
} catch (...) { |
1192 |
return false; |
1193 |
} |
1194 |
} |
1195 |
|
1196 |
/* |
1197 |
* brute force loading |
1198 |
*/ |
1199 |
bool mapped_load_flat(const char *filename, uint fileofs, uint filesize, uint vaddr, uint pc) |
1200 |
{ |
1201 |
gDisplay->printf("FLAT loading: %s\n", filename); |
1202 |
|
1203 |
uint32 pa; |
1204 |
uint32 ea; |
1205 |
// allocate image |
1206 |
pa = vaddr; |
1207 |
ea = vaddr; |
1208 |
|
1209 |
uint32 loadaddr = pa; |
1210 |
|
1211 |
for (uint p = 0; p<(filesize+4095) / 4096; p++) { |
1212 |
if (!init_page_create(ea, pa)) return false; |
1213 |
ea += 4096; |
1214 |
pa += 4096; |
1215 |
} |
1216 |
|
1217 |
// allocate stack |
1218 |
int stackea = 44*1024*1024; |
1219 |
int stacksize = 40*4096; |
1220 |
ea = stackea; |
1221 |
pa = stackea; |
1222 |
for (int i=0; i<(stacksize+4095) / 4096; i++) { |
1223 |
if (!init_page_create(ea, pa)) return false; |
1224 |
ea += 4096; |
1225 |
pa += 4096; |
1226 |
} |
1227 |
|
1228 |
// allocate bss |
1229 |
int bssea = 0x1c25000; |
1230 |
int bsssize = 0x9c000; |
1231 |
pa = bssea; |
1232 |
ea = bssea; |
1233 |
for (int i=0; i<(bsssize+4095) / 4096; i++) { |
1234 |
if (!init_page_create(ea, pa)) return false; |
1235 |
ea += 4096; |
1236 |
pa += 4096; |
1237 |
} |
1238 |
|
1239 |
FILE *f; |
1240 |
if (!(f = fopen(filename, "rb"))) { |
1241 |
return false; |
1242 |
} |
1243 |
|
1244 |
fseek(f, fileofs, SEEK_SET); |
1245 |
|
1246 |
byte *p = (byte *)malloc(filesize); |
1247 |
if (!p) return false; |
1248 |
|
1249 |
if (fread(p, filesize, 1, f) != 1) { |
1250 |
free(p); |
1251 |
return false; |
1252 |
} |
1253 |
|
1254 |
ppc_dma_write(loadaddr, p, filesize); |
1255 |
|
1256 |
free(p); |
1257 |
|
1258 |
ppc_cpu_set_msr(0, MSR_IR | MSR_DR | MSR_FP); |
1259 |
ppc_cpu_set_pc(0, pc); |
1260 |
|
1261 |
ppc_cpu_set_gpr(0, 1, stackea+stacksize/2); |
1262 |
ppc_cpu_set_gpr(0, 2, 0); |
1263 |
ppc_cpu_set_gpr(0, 3, 0x47110815); |
1264 |
ppc_cpu_set_gpr(0, 4, 0); |
1265 |
ppc_cpu_set_gpr(0, 5, gPromOSIEntry); |
1266 |
return true; |
1267 |
} |
1268 |
|
1269 |
bool mapped_load_direct(File &f, uint vaddr, uint pc) |
1270 |
{ |
1271 |
String fn; |
1272 |
gDisplay->printf("direct: trying to load '%y'\n", &f.getDesc(fn)); |
1273 |
IO_PROM_TRACE("direct: trying to load '%y'\n", &fn); |
1274 |
|
1275 |
uint32 pa; |
1276 |
uint32 ea; |
1277 |
// allocate image |
1278 |
pa = vaddr; |
1279 |
ea = vaddr; |
1280 |
|
1281 |
uint32 loadaddr = pa; |
1282 |
|
1283 |
uint size = f.getSize(); |
1284 |
for (uint p = 0; p<(size+4095) / 4096; p++) { |
1285 |
if (!init_page_create(ea, pa)) return false; |
1286 |
ea += 4096; |
1287 |
pa += 4096; |
1288 |
} |
1289 |
|
1290 |
// allocate stack |
1291 |
int stackea = (vaddr+size + 4096) & 0xfffff000; |
1292 |
int stacksize = 40*4096; |
1293 |
ea = stackea; |
1294 |
pa = stackea; |
1295 |
for (int i=0; i<(stacksize+4095) / 4096; i++) { |
1296 |
if (!init_page_create(ea, pa)) return false; |
1297 |
ea += 4096; |
1298 |
pa += 4096; |
1299 |
} |
1300 |
|
1301 |
// allocate bss |
1302 |
/* int bssea = 0x1c25000; |
1303 |
int bsssize = 0x9c000; |
1304 |
pa = bssea; |
1305 |
ea = bssea; |
1306 |
for (int i=0; i<(bsssize+4095) / 4096; i++) { |
1307 |
if (!init_page_create(ea, pa)) return false; |
1308 |
ea += 4096; |
1309 |
pa += 4096; |
1310 |
}*/ |
1311 |
|
1312 |
// memcpy(pt, mem, size); |
1313 |
f.seek(0); |
1314 |
|
1315 |
byte *p = (byte *)malloc(f.getSize()); |
1316 |
if (!p) return false; |
1317 |
|
1318 |
if (f.read(p, f.getSize()) != f.getSize()) { |
1319 |
free(p); |
1320 |
return false; |
1321 |
} |
1322 |
|
1323 |
ppc_dma_write(loadaddr, p, f.getSize()); |
1324 |
|
1325 |
free(p); |
1326 |
|
1327 |
ppc_cpu_set_msr(0, MSR_IR | MSR_DR | MSR_FP); |
1328 |
ppc_cpu_set_pc(0, pc); |
1329 |
|
1330 |
ppc_cpu_set_gpr(0, 1, stackea+stacksize/2); |
1331 |
ppc_cpu_set_gpr(0, 2, 0); |
1332 |
ppc_cpu_set_gpr(0, 3, 0x47110815); |
1333 |
ppc_cpu_set_gpr(0, 4, 0); |
1334 |
ppc_cpu_set_gpr(0, 5, gPromOSIEntry); |
1335 |
return true; |
1336 |
} |
1337 |
|
1338 |
/* |
1339 |
* Mach-O |
1340 |
*/ |
1341 |
#if 0 |
1342 |
bool mapped_load_mach_o(const char *filename) |
1343 |
{ |
1344 |
gDisplay->printf("MACH-O loading: %s\n", filename); |
1345 |
byte *pt; |
1346 |
if (ppc_direct_physical_memory_handle(0x0, pt)) { |
1347 |
return false; |
1348 |
} |
1349 |
|
1350 |
FILE *f; |
1351 |
f = fopen(filename, "rb"); |
1352 |
MachOHeader hdr; |
1353 |
if (fread(&hdr, sizeof hdr, 1, f) != 1) return false; |
1354 |
createHostStructx(&hdr, sizeof hdr, MACHO_HEADER_struct, big_endian); |
1355 |
for (uint i=0; i < hdr.ncmds; i++) { |
1356 |
// ht_printf("cmd %d/%d\n", i+1, hdr.ncmds); |
1357 |
long fpos = ftell(f); |
1358 |
MachOCommand cmd; |
1359 |
if (fread(&cmd, sizeof cmd, 1, f) != 1) return false; |
1360 |
createHostStructx(&cmd, sizeof cmd, MACHO_COMMAND_struct, big_endian); |
1361 |
if (cmd.cmd == 1) { |
1362 |
MachOSegmentCommand seg; |
1363 |
if (fread(&seg, sizeof seg, 1, f) != 1) return false; |
1364 |
createHostStructx(&seg, sizeof seg, MACHO_SEGMENT_COMMAND_struct, big_endian); |
1365 |
// ht_printf("mapping %08x->%08x (%d bytes)\n", seg.fileoff, seg.vmaddr, seg.filesize); |
1366 |
fseek(f, seg.fileoff, SEEK_SET); |
1367 |
memset(pt+seg.vmaddr, 0, seg.vmsize); |
1368 |
if (fread(pt+seg.vmaddr, seg.filesize, 1, f) != 1) return false; |
1369 |
} else if (cmd.cmd == 5) { |
1370 |
MachOPPCThreadState ts; |
1371 |
if (fread(&ts, sizeof ts, 1, f) != 1) return false; |
1372 |
createHostStructx(&ts, sizeof ts, MACHO_THREAD_COMMAND_struct, big_endian); |
1373 |
|
1374 |
gCPU.pc = ts.srr0; |
1375 |
gCPU.srr[0] = ts.srr0; |
1376 |
gCPU.srr[1] = ts.srr1; |
1377 |
|
1378 |
gCPU.gpr[1] = 8*1024*1024; |
1379 |
gCPU.gpr[3] = 0x47110815; |
1380 |
gCPU.gpr[4] = 0x4d4f5358; // MOSX |
1381 |
gCPU.gpr[5] = gPromOSIEntry; // prom entry |
1382 |
// gSinglestep = true; |
1383 |
} |
1384 |
fseek(f, fpos, SEEK_SET); |
1385 |
fseek(f, cmd.cmdsize, SEEK_CUR); |
1386 |
} |
1387 |
fclose(f); |
1388 |
return true; |
1389 |
} |
1390 |
#endif |
1391 |
|
1392 |
/* |
1393 |
* |
1394 |
*/ |
1395 |
class BootRec: public Object { |
1396 |
public: |
1397 |
PromNodeDisk *d; |
1398 |
PartitionEntry *pe; |
1399 |
int partnum; |
1400 |
String *devname; |
1401 |
|
1402 |
BootRec(PromNodeDisk *aD, PartitionEntry *aPe, int aPartnum, const String &aDevname) |
1403 |
{ |
1404 |
d = aD; |
1405 |
pe = aPe; |
1406 |
partnum = aPartnum; |
1407 |
devname = new String(aDevname); |
1408 |
} |
1409 |
virtual ~BootRec() |
1410 |
{ |
1411 |
delete devname; |
1412 |
} |
1413 |
}; |
1414 |
|
1415 |
static void read_partitions(Container &brs, bool only_bootable) |
1416 |
{ |
1417 |
brs.delAll(); |
1418 |
char *boot_devices[] = {"cdrom0", "cdrom1", "disk0", "disk1", NULL}; |
1419 |
char **boot_device = boot_devices; |
1420 |
while (*boot_device) { |
1421 |
PromNode *node = findDevice(*boot_device, FIND_DEVICE_FIND, NULL); |
1422 |
PromNodeDisk *d = dynamic_cast<PromNodeDisk*>(node); |
1423 |
if (d) { |
1424 |
Enumerator *e = d->pm->getPartitions(); |
1425 |
int partnum=0; |
1426 |
foreach(PartitionEntry, pe, *e, |
1427 |
if (!only_bootable || (pe->mBootMethod != BM_none)) { |
1428 |
brs.insert(new BootRec(d, pe, partnum, *boot_device)); |
1429 |
} |
1430 |
partnum++; |
1431 |
); |
1432 |
} |
1433 |
boot_device++; |
1434 |
} |
1435 |
} |
1436 |
|
1437 |
bool prom_user_boot_partition(File *&ret_file, uint32 &size, bool &direct, uint32 &loadAddr, uint32 &entryAddr) |
1438 |
{ |
1439 |
gDisplay->setAnsiColor(VCP(VC_LIGHT(VC_YELLOW), VC_TRANSPARENT)); |
1440 |
gDisplay->printf("\n PROM boot-loader\n"); |
1441 |
gDisplay->printf(" ==================\n\n"); |
1442 |
Array brs(true); |
1443 |
read_partitions(brs, true); |
1444 |
char key2digit[256]; |
1445 |
for (int i=0; i<256; i++) key2digit[i] = -1; |
1446 |
key2digit[KEY_0] = 0; |
1447 |
key2digit[KEY_1] = 1; |
1448 |
key2digit[KEY_2] = 2; |
1449 |
key2digit[KEY_3] = 3; |
1450 |
key2digit[KEY_4] = 4; |
1451 |
key2digit[KEY_5] = 5; |
1452 |
key2digit[KEY_6] = 6; |
1453 |
key2digit[KEY_7] = 7; |
1454 |
key2digit[KEY_8] = 8; |
1455 |
key2digit[KEY_9] = 9; |
1456 |
|
1457 |
bool only_bootable = true; |
1458 |
|
1459 |
while (1) { |
1460 |
if (gPromBootMethod == prombmSelect) gDisplay->printf("Which partition do you want to boot?\n"); |
1461 |
if (only_bootable) { |
1462 |
gDisplay->printf("\n%d bootable partition(s) found:\n", brs.count()); |
1463 |
if (gPromBootMethod == prombmSelect) { |
1464 |
gDisplay->printf(" 0. Show all (even unbootable)\n"); |
1465 |
} |
1466 |
} else { |
1467 |
gDisplay->printf("\n%d partition(s) found:\n", brs.count()); |
1468 |
gDisplay->printf(" 0. Show only bootable\n"); |
1469 |
} |
1470 |
for (uint i=0; i < brs.count(); i++) { |
1471 |
BootRec *bootrec = dynamic_cast<BootRec *>(brs[i]); |
1472 |
gDisplay->printf(" %2d. partition %d of '%y' (%s/%s)\n", i+1, bootrec->partnum, bootrec->devname, bootrec->pe->mName, bootrec->pe->mType); |
1473 |
} |
1474 |
uint choice = 0; |
1475 |
if (gPromBootMethod == prombmSelect) { |
1476 |
gDisplay->printf("\nYour choice (ESC abort):"); |
1477 |
while (1) { |
1478 |
gDisplay->printf("\r\e[0K\rYour choice (ESC abort): %d", choice); |
1479 |
uint32 keycode; |
1480 |
do { |
1481 |
while (!cuda_prom_get_key(keycode)) sys_suspend(); |
1482 |
} while (keycode & 0x80); |
1483 |
|
1484 |
if (keycode == KEY_DELETE) choice = 0; else |
1485 |
if (keycode == KEY_RETURN) break; else |
1486 |
if (keycode == KEY_ESCAPE) return false; |
1487 |
|
1488 |
if ((keycode<256) && (key2digit[keycode]>=0)) { |
1489 |
choice *= 10; |
1490 |
choice += key2digit[keycode]; |
1491 |
} |
1492 |
} |
1493 |
} else { |
1494 |
choice = 1; |
1495 |
} |
1496 |
if (choice == 0) { |
1497 |
gDisplay->printf("\n\n"); |
1498 |
only_bootable = !only_bootable; |
1499 |
read_partitions(brs, only_bootable); |
1500 |
continue; |
1501 |
} |
1502 |
gPromBootMethod = prombmSelect; |
1503 |
if ((choice > 0) && (choice <= brs.count())) { |
1504 |
choice--; |
1505 |
BootRec *bootrec = dynamic_cast<BootRec *>(brs[choice]); |
1506 |
if (bootrec->pe->mBootMethod == BM_none) { |
1507 |
gDisplay->printf("\nThis partition is not bootable!\n"); |
1508 |
continue; |
1509 |
} |
1510 |
gDisplay->printf("\nBooting %d: '%y:%d'...\n", choice+1, bootrec->devname, bootrec->partnum); |
1511 |
// FIXME: ic hack |
1512 |
IDEConfig *ic = ide_get_config(bootrec->d->mNumber); |
1513 |
File *rawFile = ic->device->promGetRawFile(); |
1514 |
File *bootFile = bootrec->pe->mInstantiateBootFile(rawFile, |
1515 |
bootrec->pe->mInstantiateBootFilePrivData); |
1516 |
if (!bootFile) { |
1517 |
IO_PROM_ERR("can't open boot file\n"); |
1518 |
return false; |
1519 |
} |
1520 |
uint bootFileSize = bootFile->getSize(); |
1521 |
if (bootFileSize > 64*1024*1024) { |
1522 |
gDisplay->printf("Boot file too large. size=%d (>64MB)\n", bootFileSize); |
1523 |
continue; |
1524 |
} |
1525 |
// set bootpath |
1526 |
char bootpath[1024]; |
1527 |
char devicebootpath[1024]; |
1528 |
bootrec->d->toPath(devicebootpath, sizeof devicebootpath); |
1529 |
ht_snprintf(bootpath, sizeof bootpath, "%s:%d,BootX", devicebootpath, bootrec->partnum); |
1530 |
// ht_snprintf(bootpath, sizeof bootpath, "/pci/pci-bridge/pci-ata/ata-4/disk1@1:9,BootX"); |
1531 |
PromNode *chosen = findDevice("/chosen", FIND_DEVICE_FIND, NULL); |
1532 |
if (chosen) { |
1533 |
chosen->addProp(new PromPropString("bootpath", bootpath)); |
1534 |
} |
1535 |
|
1536 |
ret_file = bootFile; |
1537 |
// FIXME: HACK!!! |
1538 |
gBootPartNum = bootrec->partnum; |
1539 |
gBootNodeID = bootrec->d->getPHandle(); |
1540 |
|
1541 |
gDisplay->setAnsiColor(VCP(VC_LIGHT(VC_BLUE), VC_TRANSPARENT)); |
1542 |
size = bootFileSize; |
1543 |
switch (bootrec->pe->mBootMethod) { |
1544 |
case BM_chrp: { |
1545 |
direct = false; |
1546 |
return true; |
1547 |
} |
1548 |
case BM_direct: { |
1549 |
direct = true; |
1550 |
loadAddr = bootrec->pe->mBootImageLoadAddr; |
1551 |
entryAddr = bootrec->pe->mBootImageEntrypoint; |
1552 |
return true; |
1553 |
} |
1554 |
default: |
1555 |
ASSERT(0); |
1556 |
} |
1557 |
return false; |
1558 |
} else { |
1559 |
gDisplay->printf("\nInvalid choice, try again.\n"); |
1560 |
} |
1561 |
} |
1562 |
return false; |
1563 |
} |
1564 |
|
1565 |
bool prom_load_boot_file() |
1566 |
{ |
1567 |
if (gPromBootMethod == prombmForce) { |
1568 |
if (gConfig->haveKey("prom_loadfile")) { |
1569 |
String loadfile; |
1570 |
gConfig->getConfigString("prom_loadfile", loadfile); |
1571 |
PromNode *pn = findDevice(gPromBootPath.contentChar(), FIND_DEVICE_FIND, NULL); |
1572 |
if (pn) { |
1573 |
gBootNodeID = pn->getPHandle(); |
1574 |
String dev, rest; |
1575 |
gPromBootPath.leftSplit(':', dev, rest); |
1576 |
String partNum, rest2; |
1577 |
rest.leftSplit(',', partNum, rest2); |
1578 |
uint32 p; |
1579 |
if (partNum.toInt32(p)) gBootPartNum = p; |
1580 |
} |
1581 |
|
1582 |
LocalFile f(loadfile); |
1583 |
// if (!mapped_load_elf_from_chrp(f, 0) |
1584 |
if (!mapped_load_elf(f) |
1585 |
&& !mapped_load_xcoff(f, 0) |
1586 |
&& !mapped_load_chrp(f)) { |
1587 |
IO_PROM_WARN("couldn't load '%y'.\n", &loadfile); |
1588 |
return false; |
1589 |
} |
1590 |
} else { |
1591 |
IO_PROM_ERR("bootmethod is 'force', but no prom_loadfile defined\n"); |
1592 |
return false; |
1593 |
} |
1594 |
} else { |
1595 |
uint32 loadAddr; |
1596 |
uint32 entryAddr; |
1597 |
File *f; |
1598 |
uint32 msize; |
1599 |
bool direct; |
1600 |
if (!prom_user_boot_partition(f, msize, direct, loadAddr, entryAddr)) { |
1601 |
IO_PROM_WARN("Can't boot a partition.\nTry bootmethod 'force' and specify a 'prom_loadfile' in your config-file...\n"); |
1602 |
return false; |
1603 |
} |
1604 |
try { |
1605 |
LocalFile lf("bootfile.dump", IOAM_WRITE, FOM_CREATE); |
1606 |
f->seek(0); |
1607 |
f->copyAllTo(&lf); |
1608 |
} catch (...) { |
1609 |
printf("error dumping bootfile"); |
1610 |
} |
1611 |
if (direct) { |
1612 |
if (!mapped_load_direct(*f, loadAddr, entryAddr)) { |
1613 |
IO_PROM_TRACE("couldn't load.\n"); |
1614 |
return false; |
1615 |
} |
1616 |
} else { |
1617 |
if (!mapped_load_chrp(*f)) { |
1618 |
IO_PROM_TRACE("couldn't load.\n"); |
1619 |
return false; |
1620 |
} |
1621 |
} |
1622 |
delete f; |
1623 |
} |
1624 |
return true; |
1625 |
} |