xref: /haiku/src/system/boot/platform/openfirmware/start.cpp (revision e6eaad8615c4734498b9b800847d18bbe62782fa)
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 	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 
119 extern "C" void
120 platform_exit(void)
121 {
122 	of_interpret("reset-all", 0, 0);
123 }
124 
125 
126 extern "C" uint32
127 platform_boot_options(void)
128 {
129 	return sBootOptions;
130 }
131 
132 
133 extern "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 
147 extern "C" void
148 start(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 		args.arguments_count = 1;
166 	}
167 
168 	determine_machine();
169 	console_init();
170 
171 	if ((gMachine & MACHINE_QEMU) != 0)
172 		dprintf("OpenBIOS (QEMU?) OpenFirmware machine detected\n");
173 	else if ((gMachine & MACHINE_PEGASOS) != 0)
174 		dprintf("Pegasos PowerPC machine detected\n");
175 	else
176 		dprintf("Apple PowerPC machine assumed\n");
177 
178 	// Initialize and take over MMU and set the OpenFirmware callbacks - it
179 	// will ask us for memory after that instead of maintaining it itself
180 	// (the kernel will need to adjust the callback later on as well)
181 	arch_mmu_init();
182 
183 	if (boot_arch_cpu_init() != B_OK)
184 		of_exit();
185 
186 	if (init_real_time_clock() != B_OK)
187 		of_exit();
188 
189 	// check for key presses once
190 	sBootOptions = 0;
191 	int key = console_check_for_key();
192 	if (key == 32) {
193 		// space bar: option menu
194 		sBootOptions |= BOOT_OPTION_MENU;
195 	} else if (key == 27) {
196 		// ESC: debug output
197 		sBootOptions |= BOOT_OPTION_DEBUG_OUTPUT;
198 	}
199 
200 	gKernelArgs.platform_args.openfirmware_entry = openFirmwareEntry;
201 
202 	main(&args);
203 		// if everything goes fine, main() never returns
204 
205 	of_exit();
206 }
207