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