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