1/*
2 * Copyright 2003-2010, Axel D��rfler, axeld@pinc-software.de.
3 * Copyright 2011, Alexander von Gluck, kallisti5@unixzen.com
4 * Copyright 2019, Adrien Destugues, pulkomandy@pulkomandy.tk
5 * Distributed under the terms of the MIT License.
6 */
7
8
9#include "start.h"
10
11#include <string.h>
12
13#include <OS.h>
14
15#include <boot/platform.h>
16#include <boot/stage2.h>
17#include <boot/heap.h>
18#include <platform/openfirmware/openfirmware.h>
19#include <platform_arch.h>
20
21#include "console.h"
22#include "machine.h"
23#include "real_time_clock.h"
24
25
26#define HEAP_SIZE (512 * 1024)
27
28
29// GCC defined globals
30extern void (*__ctor_list)(void);
31extern void (*__ctor_end)(void);
32
33uint32 gMachine;
34static uint32 sBootOptions;
35
36
37void
38call_ctors(void)
39{
40	void (**f)(void);
41
42	for (f = &__ctor_list; f < &__ctor_end; f++) {
43		(**f)();
44	}
45}
46
47
48static addr_t
49get_kernel_entry(void)
50{
51	if (gKernelArgs.kernel_image->elf_class == ELFCLASS64) {
52		preloaded_elf64_image *image = static_cast<preloaded_elf64_image *>(
53			gKernelArgs.kernel_image.Pointer());
54		return image->elf_header.e_entry;
55	} else if (gKernelArgs.kernel_image->elf_class == ELFCLASS32) {
56		preloaded_elf32_image *image = static_cast<preloaded_elf32_image *>(
57			gKernelArgs.kernel_image.Pointer());
58		return image->elf_header.e_entry;
59	}
60	panic("Unknown kernel format! Not 32-bit or 64-bit!");
61	return 0;
62}
63
64
65extern "C" void
66platform_start_kernel(void)
67{
68	addr_t kernelEntry = get_kernel_entry();
69	addr_t stackTop = gKernelArgs.cpu_kstack[0].start
70		+ gKernelArgs.cpu_kstack[0].size;
71
72	printf("kernel entry at %p\n", (void*)kernelEntry);
73	printf("kernel stack top: %p\n", (void*)stackTop);
74
75	/* TODO: ?
76	mmu_init_for_kernel();
77	smp_boot_other_cpus();
78	*/
79
80	status_t error = arch_start_kernel(&gKernelArgs, kernelEntry, stackTop);
81
82	panic("Kernel returned! Return value: %" B_PRId32 "\n", error);
83}
84
85
86extern "C" void
87platform_exit(void)
88{
89	of_interpret("reset-all", 0, 0);
90}
91
92
93extern "C" uint32
94platform_boot_options(void)
95{
96	return sBootOptions;
97}
98
99
100extern "C" void
101start(void *openFirmwareEntry)
102{
103	static char bootargs[512];
104
105	// stage2 args - might be set via the command line one day
106	stage2_args args;
107	args.heap_size = HEAP_SIZE;
108	args.arguments = NULL;
109
110	if (of_init((intptr_t (*)(void*))openFirmwareEntry) != B_OK)
111		return;
112
113	// check for arguments
114	if (of_getprop(gChosen, "bootargs", bootargs, sizeof(bootargs))
115			!= OF_FAILED) {
116		static const char *sArgs[] = { NULL, NULL };
117		sArgs[0] = (const char *)bootargs;
118		args.arguments = sArgs;
119		args.arguments_count = 1;
120	}
121
122	determine_machine();
123	if (console_init() != B_OK)
124		return;
125
126#ifdef __powerpc__
127	if ((gMachine & MACHINE_QEMU) != 0)
128		dprintf("OpenBIOS (QEMU?) OpenFirmware machine detected\n");
129	else if ((gMachine & MACHINE_PEGASOS) != 0)
130		dprintf("Pegasos PowerPC machine detected\n");
131	else
132		dprintf("Apple PowerPC machine assumed\n");
133#endif
134
135	// Initialize and take over MMU and set the OpenFirmware callbacks - it
136	// will ask us for memory after that instead of maintaining it itself
137	// (the kernel will need to adjust the callback later on as well)
138	arch_mmu_init();
139
140	if (boot_arch_cpu_init() != B_OK)
141		of_exit();
142
143	init_real_time_clock();
144
145	// check for key presses once
146	sBootOptions = 0;
147	int key = console_check_for_key();
148	if (key == 32) {
149		// space bar: option menu
150		sBootOptions |= BOOT_OPTION_MENU;
151	} else if (key == 27) {
152		// ESC: debug output
153		sBootOptions |= BOOT_OPTION_DEBUG_OUTPUT;
154	}
155
156	gKernelArgs.platform_args.openfirmware_entry = openFirmwareEntry;
157
158	main(&args);
159		// if everything goes fine, main() never returns
160
161	of_exit();
162}
163