xref: /haiku/src/system/boot/platform/openfirmware/start.cpp (revision 0044a8c39ab5721051b6279506d1a8c511e20453)
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 
26 extern "C" void _start(uint32 _unused1, uint32 _unused2,
27 	void *openFirmwareEntry);
28 extern "C" void start(void *openFirmwareEntry);
29 
30 // GCC defined globals
31 extern void (*__ctor_list)(void);
32 extern void (*__ctor_end)(void);
33 extern uint8 __bss_start;
34 extern uint8 _end;
35 
36 uint32 gMachine;
37 static uint32 sBootOptions;
38 
39 
40 static void
41 call_ctors(void)
42 {
43 	void (**f)(void);
44 
45 	for (f = &__ctor_list; f < &__ctor_end; f++) {
46 		(**f)();
47 	}
48 }
49 
50 
51 static void
52 clear_bss(void)
53 {
54 	memset(&__bss_start, 0, &_end - &__bss_start);
55 }
56 
57 
58 static void
59 determine_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 
95 extern "C" void
96 platform_start_kernel(void)
97 {
98 	addr_t kernelEntry = gKernelArgs.kernel_image.elf_header.e_entry;
99 	addr_t stackTop = gKernelArgs.cpu_kstack[0].start
100 		+ gKernelArgs.cpu_kstack[0].size;
101 
102 	printf("kernel entry at %p\n", (void*)kernelEntry);
103 	printf("kernel stack top: %p\n", (void*)stackTop);
104 
105 	/* TODO: ?
106 	mmu_init_for_kernel();
107 	smp_boot_other_cpus();
108 	*/
109 
110 	status_t error = arch_start_kernel(&gKernelArgs, kernelEntry, stackTop);
111 
112 	panic("Kernel returned! Return value: %ld\n", error);
113 }
114 
115 
116 extern "C" void
117 platform_exit(void)
118 {
119 	of_interpret("reset-all", 0, 0);
120 }
121 
122 
123 extern "C" uint32
124 platform_boot_options(void)
125 {
126 	return sBootOptions;
127 }
128 
129 
130 extern "C" void
131 _start(uint32 _unused1, uint32 _unused3, void *openFirmwareEntry)
132 {
133 	// According to the PowerPC bindings, OpenFirmware should have created
134 	// a stack of 32kB or higher for us at this point
135 
136 	clear_bss();
137 	call_ctors();
138 		// call C++ constructors before doing anything else
139 
140 	start(openFirmwareEntry);
141 }
142 
143 
144 extern "C" void
145 start(void *openFirmwareEntry)
146 {
147 	char bootargs[512];
148 
149 	// stage2 args - might be set via the command line one day
150 	stage2_args args;
151 	args.heap_size = HEAP_SIZE;
152 	args.arguments = NULL;
153 
154 	of_init((int (*)(void*))openFirmwareEntry);
155 
156 	// check for arguments
157 	if (of_getprop(gChosen, "bootargs", bootargs, sizeof(bootargs))
158 			!= OF_FAILED) {
159 		static const char *sArgs[] = { NULL, NULL };
160 		sArgs[0] = (const char *)bootargs;
161 		args.arguments = sArgs;
162 	}
163 
164 	determine_machine();
165 	console_init();
166 
167 	if ((gMachine & MACHINE_QEMU) != 0)
168 		dprintf("OpenBIOS (QEMU?) OpenFirmware machine detected\n");
169 	else if ((gMachine & MACHINE_PEGASOS) != 0)
170 		dprintf("Pegasos PowerPC machine detected\n");
171 	else
172 		dprintf("Apple PowerPC machine assumed\n");
173 
174 	// Initialize and take over MMU and set the OpenFirmware callbacks - it
175 	// will ask us for memory after that instead of maintaining it itself
176 	// (the kernel will need to adjust the callback later on as well)
177 	arch_mmu_init();
178 
179 	if (boot_arch_cpu_init() != B_OK)
180 		of_exit();
181 
182 	if (init_real_time_clock() != B_OK)
183 		of_exit();
184 
185 	// check for key presses once
186 	sBootOptions = 0;
187 	int key = console_check_for_key();
188 	if (key == 32) {
189 		// space bar: option menu
190 		sBootOptions |= BOOT_OPTION_MENU;
191 	} else if (key == 27) {
192 		// ESC: debug output
193 		sBootOptions |= BOOT_OPTION_DEBUG_OUTPUT;
194 	}
195 
196 	gKernelArgs.platform_args.openfirmware_entry = openFirmwareEntry;
197 
198 	main(&args);
199 		// if everything goes fine, main() never returns
200 
201 	of_exit();
202 }
203