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 (128 * 1024) 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 struct gdt_idt_descr idt_descr; 87 struct gdt_idt_descr gdt_descr; 88 89 //TRACE(("smp_cpu_ready: entry cpu %ld\n", curr_cpu)); 90 91 preloaded_elf32_image *image = static_cast<preloaded_elf32_image *>( 92 gKernelArgs.kernel_image.Pointer()); 93 94 // Important. Make sure supervisor threads can fault on read only pages... 95 asm("movl %%eax, %%cr0" : : "a" ((1 << 31) | (1 << 16) | (1 << 5) | 1)); 96 asm("cld"); 97 asm("fninit"); 98 99 // Set up the final idt 100 idt_descr.limit = IDT_LIMIT - 1; 101 idt_descr.base = (uint32 *)(addr_t)gKernelArgs.arch_args.vir_idt; 102 103 asm("lidt %0;" 104 : : "m" (idt_descr)); 105 106 // Set up the final gdt 107 gdt_descr.limit = GDT_LIMIT - 1; 108 gdt_descr.base = (uint32 *)gKernelArgs.arch_args.vir_gdt; 109 110 asm("lgdt %0;" 111 : : "m" (gdt_descr)); 112 113 asm("pushl %0; " // push the cpu number 114 "pushl %1; " // kernel args 115 "pushl $0x0;" // dummy retval for call to main 116 "pushl %2; " // this is the start address 117 "ret; " // jump. 118 : : "g" (curr_cpu), "g" (&gKernelArgs), 119 "g" (image->elf_header.e_entry)); 120 121 panic("kernel returned!\n"); 122 } 123 124 125 extern "C" void 126 platform_start_kernel(void) 127 { 128 // 64-bit kernel entry is all handled in long.cpp 129 if (gKernelArgs.kernel_image->elf_class == ELFCLASS64) { 130 long_start_kernel(); 131 return; 132 } 133 134 static struct kernel_args *args = &gKernelArgs; 135 // something goes wrong when we pass &gKernelArgs directly 136 // to the assembler inline below - might be a bug in GCC 137 // or I don't see something important... 138 addr_t stackTop 139 = gKernelArgs.cpu_kstack[0].start + gKernelArgs.cpu_kstack[0].size; 140 141 preloaded_elf32_image *image = static_cast<preloaded_elf32_image *>( 142 gKernelArgs.kernel_image.Pointer()); 143 144 smp_init_other_cpus(); 145 debug_cleanup(); 146 mmu_init_for_kernel(); 147 148 // We're about to enter the kernel -- disable console output. 149 stdout = NULL; 150 151 smp_boot_other_cpus(smp_start_kernel); 152 153 dprintf("kernel entry at %lx\n", image->elf_header.e_entry); 154 155 asm("movl %0, %%eax; " // move stack out of way 156 "movl %%eax, %%esp; " 157 : : "m" (stackTop)); 158 asm("pushl $0x0; " // we're the BSP cpu (0) 159 "pushl %0; " // kernel args 160 "pushl $0x0;" // dummy retval for call to main 161 "pushl %1; " // this is the start address 162 "ret; " // jump. 163 : : "g" (args), "g" (image->elf_header.e_entry)); 164 165 panic("kernel returned!\n"); 166 } 167 168 169 extern "C" void 170 platform_exit(void) 171 { 172 // reset the system using the keyboard controller 173 out8(0xfe, 0x64); 174 } 175 176 177 extern "C" void 178 _start(void) 179 { 180 stage2_args args; 181 182 asm("cld"); // Ain't nothing but a GCC thang. 183 asm("fninit"); // initialize floating point unit 184 185 clear_bss(); 186 call_ctors(); 187 // call C++ constructors before doing anything else 188 189 args.heap_size = HEAP_SIZE; 190 args.arguments = NULL; 191 192 serial_init(); 193 serial_enable(); 194 interrupts_init(); 195 console_init(); 196 cpu_init(); 197 mmu_init(); 198 debug_init_post_mmu(); 199 parse_multiboot_commandline(&args); 200 201 // reading the keyboard doesn't seem to work in graphics mode 202 // (maybe a bochs problem) 203 sBootOptions = check_for_boot_keys(); 204 // if (sBootOptions & BOOT_OPTION_DEBUG_OUTPUT) 205 // serial_enable(); 206 207 apm_init(); 208 acpi_init(); 209 smp_init(); 210 hpet_init(); 211 dump_multiboot_info(); 212 main(&args); 213 } 214 215