xref: /haiku/src/system/boot/platform/bios_ia32/start.cpp (revision a127b88ecbfab58f64944c98aa47722a18e363b2)
1 /*
2  * Copyright 2003-2010, Axel Dörfler, axeld@pinc-software.de.
3  * Distributed under the terms of the MIT License.
4  */
5 
6 
7 #include <string.h>
8 
9 #include <KernelExport.h>
10 
11 #include <arch/x86/arch_cpu.h>
12 
13 #include <boot/arch/x86/arch_cpu.h>
14 #include <boot/arch/x86/arch_hpet.h>
15 #include <boot/platform.h>
16 #include <boot/heap.h>
17 #include <boot/stage2.h>
18 
19 #include "acpi.h"
20 #include "apm.h"
21 #include "bios.h"
22 #include "console.h"
23 #include "cpu.h"
24 #include "debug.h"
25 #include "interrupts.h"
26 #include "keyboard.h"
27 #include "long.h"
28 #include "mmu.h"
29 #include "multiboot.h"
30 #include "serial.h"
31 #include "smp.h"
32 
33 
34 #define HEAP_SIZE ((1024 + 256) * 1024)
35 
36 
37 // GCC defined globals
38 extern void (*__ctor_list)(void);
39 extern void (*__ctor_end)(void);
40 extern uint8 __bss_start;
41 extern uint8 _end;
42 
43 extern "C" int main(stage2_args *args);
44 extern "C" void _start(void);
45 
46 
47 uint32 sBootOptions;
48 
49 
50 static void
51 clear_bss(void)
52 {
53 	memset(&__bss_start, 0, &_end - &__bss_start);
54 }
55 
56 
57 static void
58 call_ctors(void)
59 {
60 	void (**f)(void);
61 
62 	for (f = &__ctor_list; f < &__ctor_end; f++) {
63 		(**f)();
64 	}
65 }
66 
67 
68 extern "C" uint32
69 platform_boot_options(void)
70 {
71 #if 0
72 	if (!gKernelArgs.fb.enabled)
73 		sBootOptions |= check_for_boot_keys();
74 #endif
75 	return sBootOptions;
76 }
77 
78 
79 /*!	Target function of the SMP trampoline code.
80 	The trampoline code should have the pgdir and a gdt set up for us,
81 	along with us being on the final stack for this processor. We need
82 	to set up the local APIC and load the global idt and gdt. When we're
83 	done, we'll jump into the kernel with the cpu number as an argument.
84 */
85 static void
86 smp_start_kernel(void)
87 {
88 	uint32 curr_cpu = smp_get_current_cpu();
89 
90 	//TRACE(("smp_cpu_ready: entry cpu %ld\n", curr_cpu));
91 
92 	preloaded_elf32_image *image = static_cast<preloaded_elf32_image *>(
93 		gKernelArgs.kernel_image.Pointer());
94 
95 	// Important.  Make sure supervisor threads can fault on read only pages...
96 	asm("movl %%eax, %%cr0" : : "a" ((1 << 31) | (1 << 16) | (1 << 5) | 1));
97 	asm("cld");
98 	asm("fninit");
99 
100 	// Set up idt
101 	set_debug_idt();
102 
103 	// Set up gdt
104 	struct gdt_idt_descr gdt_descr;
105 	gdt_descr.limit = sizeof(gBootGDT) - 1;
106 	gdt_descr.base = gBootGDT;
107 
108 	asm("lgdt	%0;"
109 		: : "m" (gdt_descr));
110 
111 	asm("pushl  %0; "					// push the cpu number
112 		"pushl 	%1;	"					// kernel args
113 		"pushl 	$0x0;"					// dummy retval for call to main
114 		"pushl 	%2;	"					// this is the start address
115 		"ret;		"					// jump.
116 		: : "g" (curr_cpu), "g" (&gKernelArgs),
117 			"g" (image->elf_header.e_entry));
118 
119 	panic("kernel returned!\n");
120 }
121 
122 
123 extern "C" void
124 platform_start_kernel(void)
125 {
126 	// 64-bit kernel entry is all handled in long.cpp
127 	if (gKernelArgs.kernel_image->elf_class == ELFCLASS64) {
128 		long_start_kernel();
129 		return;
130 	}
131 
132 	static struct kernel_args *args = &gKernelArgs;
133 		// something goes wrong when we pass &gKernelArgs directly
134 		// to the assembler inline below - might be a bug in GCC
135 		// or I don't see something important...
136 	addr_t stackTop
137 		= gKernelArgs.cpu_kstack[0].start + gKernelArgs.cpu_kstack[0].size;
138 
139 	preloaded_elf32_image *image = static_cast<preloaded_elf32_image *>(
140 		gKernelArgs.kernel_image.Pointer());
141 
142 	smp_init_other_cpus();
143 	debug_cleanup();
144 	mmu_init_for_kernel();
145 
146 	// We're about to enter the kernel -- disable console output.
147 	stdout = NULL;
148 
149 	smp_boot_other_cpus(smp_start_kernel);
150 
151 	dprintf("kernel entry at %lx\n", image->elf_header.e_entry);
152 
153 	asm("movl	%0, %%eax;	"			// move stack out of way
154 		"movl	%%eax, %%esp; "
155 		: : "m" (stackTop));
156 	asm("pushl  $0x0; "					// we're the BSP cpu (0)
157 		"pushl 	%0;	"					// kernel args
158 		"pushl 	$0x0;"					// dummy retval for call to main
159 		"pushl 	%1;	"					// this is the start address
160 		"ret;		"					// jump.
161 		: : "g" (args), "g" (image->elf_header.e_entry));
162 
163 	panic("kernel returned!\n");
164 }
165 
166 
167 extern "C" void
168 platform_exit(void)
169 {
170 	// reset the system using the keyboard controller
171 	out8(0xfe, 0x64);
172 }
173 
174 
175 extern "C" void
176 _start(void)
177 {
178 	stage2_args args;
179 
180 	asm("cld");			// Ain't nothing but a GCC thang.
181 	asm("fninit");		// initialize floating point unit
182 
183 	clear_bss();
184 	call_ctors();
185 		// call C++ constructors before doing anything else
186 
187 	args.heap_size = HEAP_SIZE;
188 	args.arguments = NULL;
189 
190 	serial_init();
191 	serial_enable();
192 	interrupts_init();
193 	console_init();
194 	cpu_init();
195 	mmu_init();
196 	debug_init_post_mmu();
197 	parse_multiboot_commandline(&args);
198 
199 	// reading the keyboard doesn't seem to work in graphics mode
200 	// (maybe a bochs problem)
201 	sBootOptions = check_for_boot_keys();
202 //	if (sBootOptions & BOOT_OPTION_DEBUG_OUTPUT)
203 //		serial_enable();
204 
205 	apm_init();
206 	acpi_init();
207 	smp_init();
208 	hpet_init();
209 	dump_multiboot_info();
210 	main(&args);
211 }
212 
213