|
|
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.