1/*
2 * Copyright 2003-2010, Axel Dörfler, axeld@pinc-software.de.
3 * Copyright 2011, Alexander von Gluck, kallisti5@unixzen.com
4 * Distributed under the terms of the MIT License.
5 */
6
7
8#include <string.h>
9
10#include <OS.h>
11
12#include <boot/platform.h>
13#include <boot/stage2.h>
14#include <boot/heap.h>
15#include <platform/openfirmware/openfirmware.h>
16#include <platform_arch.h>
17
18#include "console.h"
19#include "machine.h"
20#include "real_time_clock.h"
21
22
23#define HEAP_SIZE 65536
24
25
26extern "C" void _start(uint32 _unused1, uint32 _unused2,
27	void *openFirmwareEntry);
28extern "C" void start(void *openFirmwareEntry);
29
30// GCC defined globals
31extern void (*__ctor_list)(void);
32extern void (*__ctor_end)(void);
33extern uint8 __bss_start;
34extern uint8 _end;
35
36uint32 gMachine;
37static uint32 sBootOptions;
38
39
40static void
41call_ctors(void)
42{
43	void (**f)(void);
44
45	for (f = &__ctor_list; f < &__ctor_end; f++) {
46		(**f)();
47	}
48}
49
50
51static void
52clear_bss(void)
53{
54	memset(&__bss_start, 0, &_end - &__bss_start);
55}
56
57
58static void
59determine_machine(void)
60{
61	gMachine = MACHINE_UNKNOWN;
62
63	int root = of_finddevice("/");
64	char buffer[64];
65	int length;
66
67	// TODO : Probe other OpenFirmware platforms and set gMachine as needed
68
69	if ((length = of_getprop(root, "device_type", buffer, sizeof(buffer) - 1))
70		!= OF_FAILED) {
71		buffer[length] = '\0';
72		if (!strcasecmp("chrp", buffer))
73			gMachine = MACHINE_CHRP;
74		else if (!strcasecmp("bootrom", buffer))
75			gMachine = MACHINE_MAC;
76	} else
77		gMachine = MACHINE_MAC;
78
79	if ((length = of_getprop(root, "model", buffer, sizeof(buffer) - 1))
80		!= OF_FAILED) {
81		buffer[length] = '\0';
82		if (!strcasecmp("pegasos", buffer))
83			gMachine |= MACHINE_PEGASOS;
84	}
85
86	if ((length = of_getprop(root, "name", buffer, sizeof(buffer) - 1))
87		!= OF_FAILED) {
88		buffer[length] = '\0';
89		if (!strcasecmp("openbiosteam,openbios", buffer))
90			gMachine |= MACHINE_QEMU;
91	}
92}
93
94
95extern "C" void
96platform_start_kernel(void)
97{
98	preloaded_elf32_image* image = static_cast<preloaded_elf32_image*>(
99		gKernelArgs.kernel_image.Pointer());
100
101	addr_t kernelEntry = image->elf_header.e_entry;
102	addr_t stackTop = gKernelArgs.cpu_kstack[0].start
103		+ gKernelArgs.cpu_kstack[0].size;
104
105	printf("kernel entry at %p\n", (void*)kernelEntry);
106	printf("kernel stack top: %p\n", (void*)stackTop);
107
108	/* TODO: ?
109	mmu_init_for_kernel();
110	smp_boot_other_cpus();
111	*/
112
113	status_t error = arch_start_kernel(&gKernelArgs, kernelEntry, stackTop);
114
115	panic("Kernel returned! Return value: %ld\n", error);
116}
117
118
119extern "C" void
120platform_exit(void)
121{
122	of_interpret("reset-all", 0, 0);
123}
124
125
126extern "C" uint32
127platform_boot_options(void)
128{
129	return sBootOptions;
130}
131
132
133extern "C" void
134_start(uint32 _unused1, uint32 _unused3, void *openFirmwareEntry)
135{
136	// According to the PowerPC bindings, OpenFirmware should have created
137	// a stack of 32kB or higher for us at this point
138
139	clear_bss();
140	call_ctors();
141		// call C++ constructors before doing anything else
142
143	start(openFirmwareEntry);
144}
145
146
147extern "C" void
148start(void *openFirmwareEntry)
149{
150	char bootargs[512];
151
152	// stage2 args - might be set via the command line one day
153	stage2_args args;
154	args.heap_size = HEAP_SIZE;
155	args.arguments = NULL;
156
157	of_init((int (*)(void*))openFirmwareEntry);
158
159	// check for arguments
160	if (of_getprop(gChosen, "bootargs", bootargs, sizeof(bootargs))
161			!= OF_FAILED) {
162		static const char *sArgs[] = { NULL, NULL };
163		sArgs[0] = (const char *)bootargs;
164		args.arguments = sArgs;
165	}
166
167	determine_machine();
168	console_init();
169
170	if ((gMachine & MACHINE_QEMU) != 0)
171		dprintf("OpenBIOS (QEMU?) OpenFirmware machine detected\n");
172	else if ((gMachine & MACHINE_PEGASOS) != 0)
173		dprintf("Pegasos PowerPC machine detected\n");
174	else
175		dprintf("Apple PowerPC machine assumed\n");
176
177	// Initialize and take over MMU and set the OpenFirmware callbacks - it
178	// will ask us for memory after that instead of maintaining it itself
179	// (the kernel will need to adjust the callback later on as well)
180	arch_mmu_init();
181
182	if (boot_arch_cpu_init() != B_OK)
183		of_exit();
184
185	if (init_real_time_clock() != B_OK)
186		of_exit();
187
188	// check for key presses once
189	sBootOptions = 0;
190	int key = console_check_for_key();
191	if (key == 32) {
192		// space bar: option menu
193		sBootOptions |= BOOT_OPTION_MENU;
194	} else if (key == 27) {
195		// ESC: debug output
196		sBootOptions |= BOOT_OPTION_DEBUG_OUTPUT;
197	}
198
199	gKernelArgs.platform_args.openfirmware_entry = openFirmwareEntry;
200
201	main(&args);
202		// if everything goes fine, main() never returns
203
204	of_exit();
205}
206