|
|
1.1 root 1: /*
2: * Creation Date: <2002/10/02 22:24:24 samuel>
3: * Time-stamp: <2004/03/27 01:57:55 samuel>
4: *
5: * <main.c>
6: *
7: *
8: *
9: * Copyright (C) 2002, 2003, 2004 Samuel Rydh ([email protected])
10: *
11: * This program is free software; you can redistribute it and/or
12: * modify it under the terms of the GNU General Public License
13: * as published by the Free Software Foundation
14: *
15: */
16:
17:
18: #include "config.h"
19: #include "libopenbios/bindings.h"
20: #include "libopenbios/elfload.h"
21: #include "arch/common/nvram.h"
22: #include "libc/diskio.h"
23: #include "libc/vsprintf.h"
24: #include "mol/mol.h"
25: #include "libopenbios/ofmem.h"
26: #include "osi_calls.h"
27: #include "ablk_sh.h"
28: #include "boothelper_sh.h"
29:
30:
31: static void patch_newworld_rom( char *start, size_t size );
32: static void newworld_timer_hack( char *start, size_t size );
33:
34: static void
35: transfer_control_to_elf( unsigned long entry )
36: {
37: extern void call_elf( unsigned long entry );
38: printk("Starting ELF boot loader\n");
39: call_elf( entry );
40:
41: fatal_error("call_elf returned unexpectedly\n");
42: }
43:
44: static int
45: load_elf_rom( unsigned long *entry, int fd )
46: {
47: int i, lszz_offs, elf_offs;
48: char buf[128], *addr;
49: Elf_ehdr ehdr;
50: Elf_phdr *phdr;
51: size_t s;
52:
53: printk("Loading '%s' from '%s'\n", get_file_path(fd),
54: get_volume_name(fd) );
55:
56: /* the ELF-image (usually) starts at offset 0x4000 */
57: if( (elf_offs=find_elf(fd)) < 0 ) {
58: printk("----> %s is not an ELF image\n", buf );
59: exit(1);
60: }
61: if( !(phdr=elf_readhdrs(fd, elf_offs, &ehdr)) )
62: fatal_error("elf_readhdrs failed\n");
63:
64: *entry = ehdr.e_entry;
65:
66: /* load segments. Compressed ROM-image assumed to be located immediately
67: * after the last segment */
68: lszz_offs = elf_offs;
69: for( i=0; i<ehdr.e_phnum; i++ ) {
70: /* p_memsz, p_flags */
71: s = MIN( phdr[i].p_filesz, phdr[i].p_memsz );
72: seek_io( fd, elf_offs + phdr[i].p_offset );
73:
74: /* printk("filesz: %08lX memsz: %08lX p_offset: %08lX p_vaddr %08lX\n",
75: phdr[i].p_filesz, phdr[i].p_memsz, phdr[i].p_offset,
76: phdr[i].p_vaddr ); */
77:
78: if( phdr[i].p_vaddr != phdr[i].p_paddr )
79: printk("WARNING: ELF segment virtual addr != physical addr\n");
80: lszz_offs = MAX( lszz_offs, elf_offs + phdr[i].p_offset + phdr[i].p_filesz );
81: if( !s )
82: continue;
83: if( ofmem_claim( phdr[i].p_vaddr, phdr[i].p_memsz, 0 ) == -1 )
84: fatal_error("Claim failed!\n");
85:
86: addr = (char*)phdr[i].p_vaddr;
87: if( read_io(fd, addr, s) != s )
88: fatal_error("read failed\n");
89:
90: /* patch CODE segment */
91: if( *entry >= phdr[i].p_vaddr && *entry < phdr[i].p_vaddr + s ) {
92: patch_newworld_rom( (char*)phdr[i].p_vaddr, s );
93: newworld_timer_hack( (char*)phdr[i].p_vaddr, s );
94: }
95: flush_icache_range( addr, addr+s );
96:
97: /* printk("ELF ROM-section loaded at %08lX (size %08lX)\n",
98: (unsigned long)phdr[i].p_vaddr, (unsigned long)phdr[i].p_memsz );*/
99: }
100: free( phdr );
101: return lszz_offs;
102: }
103:
104:
105: /************************************************************************/
106: /* newworld ROM loading */
107: /************************************************************************/
108:
109: #define ROM_BASE 0x1100000 /* where we decide to put things */
110:
111: /* fix bug present in the 2.4 and the 3.0 Apple ROM */
112: static void
113: patch_newworld_rom( char *start, size_t size )
114: {
115: int s;
116: unsigned long mark[] = { 0x7c7d1b78, /* mr r29,r3 */
117: 0x7c9c2378, /* mr r28,r4 */
118: 0x7cc33378, /* mr r3,r6 */
119: 0x7c864214, /* add r4,r6,r8 <------ BUG -- */
120: 0x80b10000, /* lwz r5,0(r17) */
121: 0x38a500e8 }; /* addi r5,r5,232 */
122:
123: /* Correcting add r4,r6,r8 ----> addi r4,r6,8 */
124: for( s=0; s<size-sizeof(mark); s+=4 )
125: if( memcmp( start+s, mark, sizeof(mark)) == 0 ) {
126: printk("FIXING ROM BUG @ %X!\n", s+12);
127: ((unsigned long*)(start+s))[3] = 0x38860008; /* addi r4,r6,8 */
128: }
129: }
130:
131: /* This hack is only needed on machines with a timebase slower than 12.5 MHz
132: * (50 MHz bus frequency). Typically only old, accelerated machines fall
133: * into this category. The cause of the problem is an overflow in Apple's
134: * calibration routine.
135: */
136: static void
137: newworld_timer_hack( char *start, size_t size )
138: {
139: int s;
140: unsigned long mark[] = { 0x7d0000a6, 0x5507045e, 0x7ce00124, 0x4c00012c,
141: 0x38e00000, 0x3c80000f, 0x6084ffff, 0x98830c00,
142: 0x7c0006ac, 0x98830a00, 0x7c0006ac, 0x7c9603a6,
143: 0x4c00012c, 0x7cb602a6, 0x2c050000, 0x4181fff8,
144: 0x7c0004ac, 0x88830a00, 0x7c0006ac, 0x88a30800,
145: 0x7c0006ac, 0x88c30a00, 0x7c0006ac, 0x7c043040,
146: 0x40a2ffe4, 0x5085442e, 0x7ca500d0, 0x54a5043e,
147: 0x7c053840, 0x7ca72b78, 0x4082ff9c, 0x7ca32b78,
148: 0x7d000124, 0x4c00012c, 0x4e800020
149: };
150:
151: /* return #via ticks corresponding to 0xfffff DEC ticks (VIA frequency == 47/60 MHz) */
152: for( s=0; s < size-sizeof(mark); s+=4 ) {
153: if( !memcmp( start+s, mark, sizeof(mark)) ) {
154: extern char timer_calib_start[], timer_calib_end[];
155: extern unsigned long nw_dec_calibration;
156: int hz = OSI_UsecsToMticks(1000);
157: nw_dec_calibration = OSI_MticksToUsecs(0xfffff*47)/60;
158: memcpy( start + s, timer_calib_start, timer_calib_end - timer_calib_start );
159:
160: printk("Timer calibration fix: %d.%02d MHz [%ld]\n",
161: hz/1000, (hz/10)%100, nw_dec_calibration );
162: break;
163: }
164: }
165: }
166:
167: static unsigned long
168: load_newworld_rom( int fd )
169: {
170: int lszz_offs, lszz_size;
171: unsigned long entry, data[2];
172: phandle_t ph;
173:
174: lszz_offs = load_elf_rom( &entry, fd );
175: seek_io( fd, -1 );
176: lszz_size = tell(fd) - lszz_offs;
177: seek_io( fd, lszz_offs );
178:
179: /* printk("Compressed ROM image: offset %08X, size %08X loaded at %08x\n",
180: lszz_offs, lszz_size, ROM_BASE ); */
181:
182: if( ofmem_claim(ROM_BASE, lszz_size, 0) == -1 )
183: fatal_error("Claim failure (lszz)!\n");
184:
185: read_io( fd, (char*)ROM_BASE, lszz_size );
186:
187: /* Fix the /rom/macos/AAPL,toolbox-image,lzss property (phys, size) */
188: #if 0
189: if( (ph=prom_create_node("/rom/macos/")) == -1 )
190: fatal_error("Failed creating /rom/macos/");
191: #else
192: ph = find_dev("/rom/macos");
193: #endif
194: data[0] = ROM_BASE;
195: data[1] = lszz_size;
196: set_property( ph, "AAPL,toolbox-image,lzss", (char*)data, sizeof(data) );
197:
198: /* The 7.8 rom (MacOS 9.2) uses AAPL,toolbox-parcels instead of
199: * AAPL,toolbox-image,lzss. It probably doesn't hurt to have it
200: * always present (we don't have an easy way to determine ROM version...)
201: */
202: set_property( ph, "AAPL,toolbox-parcels", (char*)data, sizeof(data) );
203: return entry;
204: }
205:
206: static int
207: search_nwrom( int fd, int fast )
208: {
209: char *s, buf[128];
210: int found = 0;
211:
212: if( fast ) {
213: int ind;
214: found = !reopen( fd, "\\\\:tbxi" );
215: for( ind=0; !found && (s=BootHGetStrResInd("macos_rompath", buf, sizeof(buf), ind++, 0)) ; )
216: found = !reopen( fd, s );
217: for( ind=0; !found && (s=BootHGetStrResInd("macos_rompath_", buf, sizeof(buf), ind++, 0)) ; )
218: found = !reopen( fd, s );
219: } else {
220: printk("Searching %s for a 'Mac OS ROM' file\n", get_volume_name(fd) );
221: if( !(found=reopen_nwrom(fd)) ) {
222: printk(" \n**** HINT ***************************************************\n");
223: printk("* The booting can be speeded up by adding the line\n");
224: printk("* macos_rompath: '%s'\n", get_file_path(fd) );
225: printk("* to the /etc/mol/molrc.macos (recommended).\n");
226: printk("*************************************************************\n \n");
227: }
228: }
229: return found;
230: }
231:
232: static void
233: encode_bootpath( const char *spec, const char *args )
234: {
235: phandle_t chosen_ph = find_dev("/chosen");
236: set_property( chosen_ph, "bootpath", spec, strlen(spec)+1 );
237: set_property( chosen_ph, "bootargs", args, strlen(args)+1 );
238: }
239:
240: static char *
241: newworld_load( const char *node_path, const char *spec, int do_search )
242: {
243: char *p, *entry, buf[80];
244: int fd, len;
245:
246: if( (fd=open_io(spec)) == -1 )
247: return NULL;
248:
249: if( !search_nwrom(fd, do_search) ) {
250: close_io(fd);
251: return NULL;
252: }
253: printk("Boot Disk: %s [%s]\n", spec, get_fstype(fd) );
254:
255: entry = (char*)load_newworld_rom( fd );
256:
257: #if 1
258: PUSH_ih( get_ih_from_fd(fd) );
259: fword("get-instance-path");
260: len = POP();
261: p = (char*)POP();
262: buf[0] = 0;
263: if( len < sizeof(buf) ) {
264: memcpy( buf, p, len );
265: buf[len] =0;
266: }
267: strcat( buf, "/x@:" );
268: printk("boot_path: %s\n", buf );
269: encode_bootpath( buf, "" );
270: #endif
271: close_io( fd );
272: return entry;
273: }
274:
275: static void
276: newworld_startup( void )
277: {
278: int i, j, bootunit, type, fd;
279: ablk_disk_info_t info;
280: char *entry = NULL;
281: char spec[80];
282: phandle_t ph;
283:
284: char path[]="/pci/pci-bridge/mol-blk";
285: if( !(ph=find_dev(path)) )
286: fatal_error("MOLBlockDriver node not found\n");
287:
288: /* user-specified newworld ROMs take precedence */
289: if( (fd=open_io("pseudo:,nwrom")) >= 0 ) {
290: entry = (char*)load_newworld_rom( fd );
291: close_io( fd );
292: }
293:
294: /* determine boot volume */
295: for( bootunit=-1, type=0; bootunit==-1 && type<3 ; type++ ) {
296: for( i=0; !OSI_ABlkDiskInfo(0, i, &info) ; i++ ) {
297: if( type<=1 && !(info.flags & ABLK_BOOT_HINT) )
298: continue;
299: if( type>1 && (info.flags & ABLK_BOOT_HINT) )
300: continue;
301:
302: for( j=0; !entry && j<32; j++ ) {
303: snprintf( spec, sizeof(spec), "%s/disk@%x:%d",
304: path, i, j );
305: entry = newworld_load( path, spec, (!type || type==2) );
306: }
307: if( entry ) {
308: bootunit = i;
309: break;
310: }
311: }
312: }
313:
314: if( entry ) {
315: OSI_ABlkBlessDisk( 0 /*channel*/, bootunit );
316:
317: update_nvram();
318: transfer_control_to_elf( (unsigned long)entry );
319: /* won't come here */
320: return;
321: }
322:
323: printk("\n--- No bootable disk was found! -----------------------------\n");
324: printk("If this is an oldworld machine, try booting from the MacOS\n");
325: printk("install CD and install MacOS from within MOL.\n");
326: printk("-------------------------------------------------------------\n");
327: exit(1);
328: }
329:
330:
331: /************************************************************************/
332: /* yaboot booting */
333: /************************************************************************/
334:
335: static void
336: yaboot_startup( void )
337: {
338: const char *paths[] = { "pseudo:,ofclient", "pseudo:,yaboot", NULL };
339: unsigned long entry;
340: int i, fd;
341:
342: for( i=0; paths[i]; i++ ) {
343: if( (fd=open_io(paths[i])) == -1 )
344: continue;
345: (void) load_elf_rom( &entry, fd );
346: close_io( fd );
347: encode_bootpath( paths[i], "" );
348:
349: update_nvram();
350: transfer_control_to_elf( entry );
351: /* won't come here */
352: }
353: printk("*** Boot failure! No secondary bootloader specified ***\n");
354: exit(1);
355: }
356:
357:
358: /************************************************************************/
359: /* entry */
360: /************************************************************************/
361:
362: void
363: boot( void )
364: {
365: fword("update-chosen");
366: if( find_dev("/mol-platform") )
367: yaboot_startup();
368: else
369: newworld_startup();
370: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.