1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145
|
/*
* Creation Date: <2004/08/28 18:38:22 greg>
* Time-stamp: <2004/08/28 18:38:22 greg>
*
* <main.c>
*
* Copyright (C) 2004 Greg Watson
*
* Based on MOL specific code which is
* 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 "openbios/config.h"
#include "openbios/bindings.h"
#include "openbios/elfload.h"
#include "openbios/nvram.h"
#include "libc/diskio.h"
#include "libc/vsprintf.h"
#include "pearpc/pearpc.h"
#include "ofmem.h"
static void
transfer_control_to_elf( ulong entry )
{
extern void call_elf( ulong entry );
printk("Starting ELF image at 0x%08lX\n", entry);
call_elf( 0x400000 );
//call_elf( entry );
fatal_error("call_elf returned unexpectedly\n");
}
static int
load_elf_rom( ulong *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'\n", get_file_path(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<ehdr.e_phnum; i++ ) {
/* p_memsz, p_flags */
s = MIN( phdr[i].p_filesz, phdr[i].p_memsz );
seek_io( fd, elf_offs + phdr[i].p_offset );
/* printk("filesz: %08lX memsz: %08lX p_offset: %08lX p_vaddr %08lX\n",
phdr[i].p_filesz, phdr[i].p_memsz, phdr[i].p_offset,
phdr[i].p_vaddr ); */
if( phdr[i].p_vaddr != phdr[i].p_paddr )
printk("WARNING: ELF segment virtual addr != physical addr\n");
lszz_offs = MAX( lszz_offs, elf_offs + phdr[i].p_offset + phdr[i].p_filesz );
if( !s )
continue;
if( ofmem_claim( phdr[i].p_vaddr, phdr[i].p_memsz, 0 ) == -1 )
fatal_error("Claim failed!\n");
addr = (char*)phdr[i].p_vaddr;
if( read_io(fd, addr, s) != s )
fatal_error("read failed\n");
#if 0
/* patch CODE segment */
if( *entry >= 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 );
}
#endif
flush_icache_range( addr, addr+s );
/*printk("ELF ROM-section loaded at %08lX (size %08lX)\n",
(ulong)phdr[i].p_vaddr, (ulong)phdr[i].p_memsz );*/
}
free( phdr );
return lszz_offs;
}
static void
encode_bootpath( const char *spec, const char *args )
{
phandle_t chosen_ph = find_dev("/chosen");
set_property( chosen_ph, "bootpath", spec, strlen(spec)+1 );
set_property( chosen_ph, "bootargs", args, strlen(args)+1 );
}
/************************************************************************/
/* pearpc booting */
/************************************************************************/
static void
pearpc_startup( void )
{
const char *paths[] = { "hd:0,\\zImage.chrp", NULL };
const char *args[] = { "root=/dev/hda2 console=ttyS0,115200", NULL };
ulong 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], args[i] );
update_nvram();
transfer_control_to_elf( entry );
/* won't come here */
}
printk("*** Boot failure! No secondary bootloader specified ***\n");
}
/************************************************************************/
/* entry */
/************************************************************************/
void
boot( void )
{
fword("update-chosen");
pearpc_startup();
}
|