/* * Creation Date: <2002/10/02 22:24:24 samuel> * Time-stamp: <2004/03/27 01:57:55 samuel> * * * * * * Copyright (C) 2002, 2003, 2004 Samuel Rydh (samuel@ibrium.se) * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation * */ #include "config.h" #include "libopenbios/bindings.h" #include "libopenbios/elfload.h" #include "arch/common/nvram.h" #include "libc/diskio.h" #include "libc/vsprintf.h" #include "mol/mol.h" #include "libopenbios/ofmem.h" #include "osi_calls.h" #include "ablk_sh.h" #include "boothelper_sh.h" static void patch_newworld_rom( char *start, size_t size ); static void newworld_timer_hack( char *start, size_t size ); static void transfer_control_to_elf( unsigned long entry ) { extern void call_elf( unsigned long entry ); printk("Starting ELF boot loader\n"); call_elf( entry ); fatal_error("call_elf returned unexpectedly\n"); } static int load_elf_rom( unsigned long *entry, int fd ) { int i, lszz_offs, elf_offs; char buf[128], *addr; Elf_ehdr ehdr; Elf_phdr *phdr; size_t s; printk("Loading '%s' from '%s'\n", get_file_path(fd), get_volume_name(fd) ); /* the ELF-image (usually) starts at offset 0x4000 */ if( (elf_offs=find_elf(fd)) < 0 ) { printk("----> %s is not an ELF image\n", buf ); exit(1); } if( !(phdr=elf_readhdrs(fd, elf_offs, &ehdr)) ) fatal_error("elf_readhdrs failed\n"); *entry = ehdr.e_entry; /* load segments. Compressed ROM-image assumed to be located immediately * after the last segment */ lszz_offs = elf_offs; for( i=0; i= phdr[i].p_vaddr && *entry < phdr[i].p_vaddr + s ) { patch_newworld_rom( (char*)phdr[i].p_vaddr, s ); newworld_timer_hack( (char*)phdr[i].p_vaddr, s ); } flush_icache_range( addr, addr+s ); /* printk("ELF ROM-section loaded at %08lX (size %08lX)\n", (unsigned long)phdr[i].p_vaddr, (unsigned long)phdr[i].p_memsz );*/ } free( phdr ); return lszz_offs; } /************************************************************************/ /* newworld ROM loading */ /************************************************************************/ #define ROM_BASE 0x1100000 /* where we decide to put things */ /* fix bug present in the 2.4 and the 3.0 Apple ROM */ static void patch_newworld_rom( char *start, size_t size ) { int s; unsigned long mark[] = { 0x7c7d1b78, /* mr r29,r3 */ 0x7c9c2378, /* mr r28,r4 */ 0x7cc33378, /* mr r3,r6 */ 0x7c864214, /* add r4,r6,r8 <------ BUG -- */ 0x80b10000, /* lwz r5,0(r17) */ 0x38a500e8 }; /* addi r5,r5,232 */ /* Correcting add r4,r6,r8 ----> addi r4,r6,8 */ for( s=0; s= 0 ) { entry = (char*)load_newworld_rom( fd ); close_io( fd ); } /* determine boot volume */ for( bootunit=-1, type=0; bootunit==-1 && type<3 ; type++ ) { for( i=0; !OSI_ABlkDiskInfo(0, i, &info) ; i++ ) { if( type<=1 && !(info.flags & ABLK_BOOT_HINT) ) continue; if( type>1 && (info.flags & ABLK_BOOT_HINT) ) continue; for( j=0; !entry && j<32; j++ ) { snprintf( spec, sizeof(spec), "%s/disk@%x:%d", path, i, j ); entry = newworld_load( path, spec, (!type || type==2) ); } if( entry ) { bootunit = i; break; } } } if( entry ) { OSI_ABlkBlessDisk( 0 /*channel*/, bootunit ); update_nvram(); transfer_control_to_elf( (unsigned long)entry ); /* won't come here */ return; } printk("\n--- No bootable disk was found! -----------------------------\n"); printk("If this is an oldworld machine, try booting from the MacOS\n"); printk("install CD and install MacOS from within MOL.\n"); printk("-------------------------------------------------------------\n"); exit(1); } /************************************************************************/ /* yaboot booting */ /************************************************************************/ static void yaboot_startup( void ) { const char *paths[] = { "pseudo:,ofclient", "pseudo:,yaboot", NULL }; unsigned long entry; int i, fd; for( i=0; paths[i]; i++ ) { if( (fd=open_io(paths[i])) == -1 ) continue; (void) load_elf_rom( &entry, fd ); close_io( fd ); encode_bootpath( paths[i], "" ); update_nvram(); transfer_control_to_elf( entry ); /* won't come here */ } printk("*** Boot failure! No secondary bootloader specified ***\n"); exit(1); } /************************************************************************/ /* entry */ /************************************************************************/ void boot( void ) { fword("update-chosen"); if( find_dev("/mol-platform") ) yaboot_startup(); else newworld_startup(); }