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
38extern void (*__ctor_list)(void);
39extern void (*__ctor_end)(void);
40extern uint8 __bss_start;
41extern uint8 _end;
42
43extern "C" int main(stage2_args *args);
44extern "C" void _start(void);
45
46
47uint32 sBootOptions;
48
49
50static void
51clear_bss(void)
52{
53	memset(&__bss_start, 0, &_end - &__bss_start);
54}
55
56
57static void
58call_ctors(void)
59{
60	void (**f)(void);
61
62	for (f = &__ctor_list; f < &__ctor_end; f++) {
63		(**f)();
64	}
65}
66
67
68extern "C" uint32
69platform_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*/
85static void
86smp_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
123extern "C" void
124platform_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
167extern "C" void
168platform_exit(void)
169{
170	// reset the system using the keyboard controller
171	out8(0xfe, 0x64);
172}
173
174
175extern "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