2 * Creation Date: <2002/10/02 22:24:24 samuel>
3 * Time-stamp: <2004/03/27 01:57:55 samuel>
9 * Copyright (C) 2002, 2003, 2004 Samuel Rydh (samuel@ibrium.se)
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
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"
25 #include "libopenbios/ofmem.h"
26 #include "osi_calls.h"
28 #include "boothelper_sh.h"
31 static void patch_newworld_rom( char *start, size_t size );
32 static void newworld_timer_hack( char *start, size_t size );
35 transfer_control_to_elf( unsigned long entry )
37 extern void call_elf( unsigned long entry );
38 printk("Starting ELF boot loader\n");
41 fatal_error("call_elf returned unexpectedly\n");
45 load_elf_rom( unsigned long *entry, int fd )
47 int i, lszz_offs, elf_offs;
53 printk("Loading '%s' from '%s'\n", get_file_path(fd),
54 get_volume_name(fd) );
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 );
61 if( !(phdr=elf_readhdrs(fd, elf_offs, &ehdr)) )
62 fatal_error("elf_readhdrs failed\n");
64 *entry = ehdr.e_entry;
66 /* load segments. Compressed ROM-image assumed to be located immediately
67 * after the last segment */
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 );
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,
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 );
83 if( ofmem_claim( phdr[i].p_vaddr, phdr[i].p_memsz, 0 ) == -1 )
84 fatal_error("Claim failed!\n");
86 addr = (char*)phdr[i].p_vaddr;
87 if( read_io(fd, addr, s) != s )
88 fatal_error("read failed\n");
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 );
95 flush_icache_range( addr, addr+s );
97 /* printk("ELF ROM-section loaded at %08lX (size %08lX)\n",
98 (unsigned long)phdr[i].p_vaddr, (unsigned long)phdr[i].p_memsz );*/
105 /************************************************************************/
106 /* newworld ROM loading */
107 /************************************************************************/
109 #define ROM_BASE 0x1100000 /* where we decide to put things */
111 /* fix bug present in the 2.4 and the 3.0 Apple ROM */
113 patch_newworld_rom( char *start, size_t size )
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 */
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 */
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.
137 newworld_timer_hack( char *start, size_t size )
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
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 );
160 printk("Timer calibration fix: %d.%02d MHz [%ld]\n",
161 hz/1000, (hz/10)%100, nw_dec_calibration );
168 load_newworld_rom( int fd )
170 int lszz_offs, lszz_size;
171 unsigned long entry, data[2];
174 lszz_offs = load_elf_rom( &entry, fd );
176 lszz_size = tell(fd) - lszz_offs;
177 seek_io( fd, lszz_offs );
179 /* printk("Compressed ROM image: offset %08X, size %08X loaded at %08x\n",
180 lszz_offs, lszz_size, ROM_BASE ); */
182 if( ofmem_claim(ROM_BASE, lszz_size, 0) == -1 )
183 fatal_error("Claim failure (lszz)!\n");
185 read_io( fd, (char*)ROM_BASE, lszz_size );
187 /* Fix the /rom/macos/AAPL,toolbox-image,lzss property (phys, size) */
189 if( (ph=prom_create_node("/rom/macos/")) == -1 )
190 fatal_error("Failed creating /rom/macos/");
192 ph = find_dev("/rom/macos");
196 set_property( ph, "AAPL,toolbox-image,lzss", (char*)data, sizeof(data) );
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...)
202 set_property( ph, "AAPL,toolbox-parcels", (char*)data, sizeof(data) );
207 search_nwrom( int fd, int fast )
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 );
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");
233 encode_bootpath( const char *spec, const char *args )
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 );
241 newworld_load( const char *node_path, const char *spec, int do_search )
243 char *p, *entry, buf[80];
246 if( (fd=open_io(spec)) == -1 )
249 if( !search_nwrom(fd, do_search) ) {
253 printk("Boot Disk: %s [%s]\n", spec, get_fstype(fd) );
255 entry = (char*)load_newworld_rom( fd );
258 PUSH_ih( get_ih_from_fd(fd) );
259 fword("get-instance-path");
263 if( len < sizeof(buf) ) {
264 memcpy( buf, p, len );
267 strcat( buf, "/x@:" );
268 printk("boot_path: %s\n", buf );
269 encode_bootpath( buf, "" );
276 newworld_startup( void )
278 int i, j, bootunit, type, fd;
279 ablk_disk_info_t info;
284 char path[]="/pci/pci-bridge/mol-blk";
285 if( !(ph=find_dev(path)) )
286 fatal_error("MOLBlockDriver node not found\n");
288 /* user-specified newworld ROMs take precedence */
289 if( (fd=open_io("pseudo:,nwrom")) >= 0 ) {
290 entry = (char*)load_newworld_rom( fd );
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) )
299 if( type>1 && (info.flags & ABLK_BOOT_HINT) )
302 for( j=0; !entry && j<32; j++ ) {
303 snprintf( spec, sizeof(spec), "%s/disk@%x:%d",
305 entry = newworld_load( path, spec, (!type || type==2) );
315 OSI_ABlkBlessDisk( 0 /*channel*/, bootunit );
318 transfer_control_to_elf( (unsigned long)entry );
319 /* won't come here */
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");
331 /************************************************************************/
333 /************************************************************************/
336 yaboot_startup( void )
338 const char *paths[] = { "pseudo:,ofclient", "pseudo:,yaboot", NULL };
342 for( i=0; paths[i]; i++ ) {
343 if( (fd=open_io(paths[i])) == -1 )
345 (void) load_elf_rom( &entry, fd );
347 encode_bootpath( paths[i], "" );
350 transfer_control_to_elf( entry );
351 /* won't come here */
353 printk("*** Boot failure! No secondary bootloader specified ***\n");
358 /************************************************************************/
360 /************************************************************************/
365 fword("update-chosen");
366 if( find_dev("/mol-platform") )