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