summaryrefslogtreecommitdiffstats
path: root/qemu/roms/openbios/arch/ppc/pearpc/main.c
blob: 085494e564c071e049908234588d8ef11d36c14a (plain)
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 "config.h"
#include "libopenbios/bindings.h"
#include "libopenbios/elfload.h"
#include "arch/common/nvram.h"
#include "libc/diskio.h"
#include "libc/vsprintf.h"
#include "pearpc/pearpc.h"
#include "libopenbios/ofmem.h"

static void
transfer_control_to_elf( unsigned long entry )
{
	extern void call_elf( unsigned long 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( 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'\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",
		   (unsigned long)phdr[i].p_vaddr, (unsigned long)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 };
	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], 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();
}