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