* Copyright 2003-2010, Axel DΓΆrfler, axeld@pinc-software.de.
* Distributed under the terms of the MIT License.
*/
#include <string.h>
#include <KernelExport.h>
#include <arch/x86/arch_cpu.h>
#include <boot/arch/x86/arch_cpu.h>
#include <boot/arch/x86/arch_hpet.h>
#include <boot/platform.h>
#include <boot/heap.h>
#include <boot/stage2.h>
#include "acpi.h"
#include "apm.h"
#include "bios.h"
#include "console.h"
#include "cpu.h"
#include "debug.h"
#include "interrupts.h"
#include "keyboard.h"
#include "long.h"
#include "mmu.h"
#include "multiboot.h"
#include "serial.h"
#include "smp.h"
#define HEAP_SIZE ((1024 + 256) * 1024)
extern void (*__ctor_list)(void);
extern void (*__ctor_end)(void);
extern uint8 __bss_start;
extern uint8 _end;
extern "C" int main(stage2_args *args);
extern "C" void _start(void);
uint32 sBootOptions;
static void
clear_bss(void)
{
memset(&__bss_start, 0, &_end - &__bss_start);
}
static void
call_ctors(void)
{
void (**f)(void);
for (f = &__ctor_list; f < &__ctor_end; f++) {
(**f)();
}
}
extern "C" uint32
platform_boot_options(void)
{
#if 0
if (!gKernelArgs.fb.enabled)
sBootOptions |= check_for_boot_keys();
#endif
return sBootOptions;
}
The trampoline code should have the pgdir and a gdt set up for us,
along with us being on the final stack for this processor. We need
to set up the local APIC and load the global idt and gdt. When we're
done, we'll jump into the kernel with the cpu number as an argument.
*/
static void
smp_start_kernel(void)
{
uint32 curr_cpu = smp_get_current_cpu();
preloaded_elf32_image *image = static_cast<preloaded_elf32_image *>(
gKernelArgs.kernel_image.Pointer());
asm("movl %%eax, %%cr0" : : "a" ((1 << 31) | (1 << 16) | (1 << 5) | 1));
asm("cld");
asm("fninit");
set_debug_idt();
struct gdt_idt_descr gdt_descr;
gdt_descr.limit = sizeof(gBootGDT) - 1;
gdt_descr.base = gBootGDT;
asm("lgdt %0;"
: : "m" (gdt_descr));
asm("pushl %0; "
"pushl %1; "
"pushl $0x0;"
"pushl %2; "
"ret; "
: : "g" (curr_cpu), "g" (&gKernelArgs),
"g" (image->elf_header.e_entry));
panic("kernel returned!\n");
}
extern "C" void
platform_start_kernel(void)
{
if (gKernelArgs.kernel_image->elf_class == ELFCLASS64) {
long_start_kernel();
return;
}
static struct kernel_args *args = &gKernelArgs;
addr_t stackTop
= gKernelArgs.cpu_kstack[0].start + gKernelArgs.cpu_kstack[0].size;
preloaded_elf32_image *image = static_cast<preloaded_elf32_image *>(
gKernelArgs.kernel_image.Pointer());
smp_init_other_cpus();
debug_cleanup();
mmu_init_for_kernel();
stdout = NULL;
smp_boot_other_cpus(smp_start_kernel);
dprintf("kernel entry at %lx\n", image->elf_header.e_entry);
asm("movl %0, %%eax; "
"movl %%eax, %%esp; "
: : "m" (stackTop));
asm("pushl $0x0; "
"pushl %0; "
"pushl $0x0;"
"pushl %1; "
"ret; "
: : "g" (args), "g" (image->elf_header.e_entry));
panic("kernel returned!\n");
}
extern "C" void
platform_exit(void)
{
out8(0xfe, 0x64);
}
extern "C" void
_start(void)
{
stage2_args args;
asm("cld");
asm("fninit");
clear_bss();
call_ctors();
args.heap_size = HEAP_SIZE;
args.arguments = NULL;
serial_init();
interrupts_init();
console_init();
cpu_init();
mmu_init();
debug_init_post_mmu();
parse_multiboot_commandline(&args);
sBootOptions = check_for_boot_keys();
if (sBootOptions & BOOT_OPTION_DEBUG_OUTPUT)
serial_enable();
apm_init();
acpi_init();
smp_init();
hpet_init();
dump_multiboot_info();
main(&args);
}