xref: /haiku/src/system/boot/platform/bios_ia32/start.cpp (revision fc7456e9b1ec38c941134ed6d01c438cf289381e)
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 // 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 
87 	//TRACE(("smp_cpu_ready: entry cpu %ld\n", curr_cpu));
88 
89 	preloaded_elf32_image *image = static_cast<preloaded_elf32_image *>(
90 		gKernelArgs.kernel_image.Pointer());
91 
92 	// Important.  Make sure supervisor threads can fault on read only pages...
93 	asm("movl %%eax, %%cr0" : : "a" ((1 << 31) | (1 << 16) | (1 << 5) | 1));
94 	asm("cld");
95 	asm("fninit");
96 
97 	// Set up idt
98 	set_debug_idt();
99 
100 	// Set up gdt
101 	struct gdt_idt_descr gdt_descr;
102 	gdt_descr.limit = sizeof(gBootGDT) - 1;
103 	gdt_descr.base = gBootGDT;
104 
105 	asm("lgdt	%0;"
106 		: : "m" (gdt_descr));
107 
108 	asm("pushl  %0; "					// push the cpu number
109 		"pushl 	%1;	"					// kernel args
110 		"pushl 	$0x0;"					// dummy retval for call to main
111 		"pushl 	%2;	"					// this is the start address
112 		"ret;		"					// jump.
113 		: : "g" (curr_cpu), "g" (&gKernelArgs),
114 			"g" (image->elf_header.e_entry));
115 
116 	panic("kernel returned!\n");
117 }
118 
119 
120 extern "C" void
121 platform_start_kernel(void)
122 {
123 	// 64-bit kernel entry is all handled in long.cpp
124 	if (gKernelArgs.kernel_image->elf_class == ELFCLASS64) {
125 		long_start_kernel();
126 		return;
127 	}
128 
129 	static struct kernel_args *args = &gKernelArgs;
130 		// something goes wrong when we pass &gKernelArgs directly
131 		// to the assembler inline below - might be a bug in GCC
132 		// or I don't see something important...
133 	addr_t stackTop
134 		= gKernelArgs.cpu_kstack[0].start + gKernelArgs.cpu_kstack[0].size;
135 
136 	preloaded_elf32_image *image = static_cast<preloaded_elf32_image *>(
137 		gKernelArgs.kernel_image.Pointer());
138 
139 	smp_init_other_cpus();
140 	debug_cleanup();
141 	mmu_init_for_kernel();
142 
143 	// We're about to enter the kernel -- disable console output.
144 	stdout = NULL;
145 
146 	smp_boot_other_cpus(smp_start_kernel);
147 
148 	dprintf("kernel entry at %x\n", image->elf_header.e_entry);
149 
150 	asm("movl	%0, %%eax;	"			// move stack out of way
151 		"movl	%%eax, %%esp; "
152 		: : "m" (stackTop));
153 	asm("pushl  $0x0; "					// we're the BSP cpu (0)
154 		"pushl 	%0;	"					// kernel args
155 		"pushl 	$0x0;"					// dummy retval for call to main
156 		"pushl 	%1;	"					// this is the start address
157 		"ret;		"					// jump.
158 		: : "g" (args), "g" (image->elf_header.e_entry));
159 
160 	panic("kernel returned!\n");
161 }
162 
163 
164 extern "C" void
165 platform_exit(void)
166 {
167 	// reset the system using the keyboard controller
168 	out8(0xfe, 0x64);
169 }
170 
171 
172 extern "C" void
173 _start(void)
174 {
175 	stage2_args args;
176 
177 	asm("cld");			// Ain't nothing but a GCC thang.
178 	asm("fninit");		// initialize floating point unit
179 
180 	clear_bss();
181 	call_ctors();
182 		// call C++ constructors before doing anything else
183 
184 	args.heap_size = 0;
185 	args.arguments = NULL;
186 
187 	serial_init();
188 	serial_enable();
189 	interrupts_init();
190 	console_init();
191 	cpu_init();
192 	mmu_init();
193 	debug_init_post_mmu();
194 	parse_multiboot_commandline(&args);
195 
196 	// reading the keyboard doesn't seem to work in graphics mode
197 	// (maybe a bochs problem)
198 	sBootOptions = check_for_boot_keys();
199 //	if (sBootOptions & BOOT_OPTION_DEBUG_OUTPUT)
200 //		serial_enable();
201 
202 	apm_init();
203 	acpi_init();
204 	smp_init();
205 	hpet_init();
206 	dump_multiboot_info();
207 	main(&args);
208 }
209 
210