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/platform.h> 15 #include <boot/heap.h> 16 #include <boot/stage2.h> 17 18 #include "acpi.h" 19 #include "apm.h" 20 #include "bios.h" 21 #include "console.h" 22 #include "cpu.h" 23 #include "debug.h" 24 #include "hpet.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 38 extern void (*__ctor_list)(void); 39 extern void (*__ctor_end)(void); 40 extern uint8 __bss_start; 41 extern uint8 _end; 42 43 extern "C" int main(stage2_args *args); 44 extern "C" void _start(void); 45 46 47 uint32 sBootOptions; 48 49 50 static void 51 clear_bss(void) 52 { 53 memset(&__bss_start, 0, &_end - &__bss_start); 54 } 55 56 57 static void 58 call_ctors(void) 59 { 60 void (**f)(void); 61 62 for (f = &__ctor_list; f < &__ctor_end; f++) { 63 (**f)(); 64 } 65 } 66 67 68 extern "C" uint32 69 platform_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 */ 85 static void 86 smp_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 123 extern "C" void 124 platform_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 167 extern "C" void 168 platform_exit(void) 169 { 170 // reset the system using the keyboard controller 171 out8(0xfe, 0x64); 172 } 173 174 175 extern "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