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 ((1024 + 256) * 1024) 33 34 35 // GCC defined globals 36 extern void (*__ctor_list)(void); 37 extern void (*__ctor_end)(void); 38 extern uint8 __bss_start; 39 extern uint8 _end; 40 41 extern "C" int main(stage2_args *args); 42 extern "C" void _start(void); 43 44 45 uint32 sBootOptions; 46 47 48 static void 49 clear_bss(void) 50 { 51 memset(&__bss_start, 0, &_end - &__bss_start); 52 } 53 54 55 static void 56 call_ctors(void) 57 { 58 void (**f)(void); 59 60 for (f = &__ctor_list; f < &__ctor_end; f++) { 61 (**f)(); 62 } 63 } 64 65 66 extern "C" uint32 67 platform_boot_options(void) 68 { 69 #if 0 70 if (!gKernelArgs.fb.enabled) 71 sBootOptions |= check_for_boot_keys(); 72 #endif 73 return sBootOptions; 74 } 75 76 77 /*! Target function of the SMP trampoline code. 78 The trampoline code should have the pgdir and a gdt set up for us, 79 along with us being on the final stack for this processor. We need 80 to set up the local APIC and load the global idt and gdt. When we're 81 done, we'll jump into the kernel with the cpu number as an argument. 82 */ 83 static void 84 smp_start_kernel(void) 85 { 86 uint32 curr_cpu = smp_get_current_cpu(); 87 88 //TRACE(("smp_cpu_ready: entry cpu %ld\n", curr_cpu)); 89 90 preloaded_elf32_image *image = static_cast<preloaded_elf32_image *>( 91 gKernelArgs.kernel_image.Pointer()); 92 93 // Important. Make sure supervisor threads can fault on read only pages... 94 asm("movl %%eax, %%cr0" : : "a" ((1 << 31) | (1 << 16) | (1 << 5) | 1)); 95 asm("cld"); 96 asm("fninit"); 97 98 // Set up idt 99 set_debug_idt(); 100 101 // Set up gdt 102 struct gdt_idt_descr gdt_descr; 103 gdt_descr.limit = sizeof(gBootGDT) - 1; 104 gdt_descr.base = gBootGDT; 105 106 asm("lgdt %0;" 107 : : "m" (gdt_descr)); 108 109 asm("pushl %0; " // push the cpu number 110 "pushl %1; " // kernel args 111 "pushl $0x0;" // dummy retval for call to main 112 "pushl %2; " // this is the start address 113 "ret; " // jump. 114 : : "g" (curr_cpu), "g" (&gKernelArgs), 115 "g" (image->elf_header.e_entry)); 116 117 panic("kernel returned!\n"); 118 } 119 120 121 extern "C" void 122 platform_start_kernel(void) 123 { 124 // 64-bit kernel entry is all handled in long.cpp 125 if (gKernelArgs.kernel_image->elf_class == ELFCLASS64) { 126 long_start_kernel(); 127 return; 128 } 129 130 static struct kernel_args *args = &gKernelArgs; 131 // something goes wrong when we pass &gKernelArgs directly 132 // to the assembler inline below - might be a bug in GCC 133 // or I don't see something important... 134 addr_t stackTop 135 = gKernelArgs.cpu_kstack[0].start + gKernelArgs.cpu_kstack[0].size; 136 137 preloaded_elf32_image *image = static_cast<preloaded_elf32_image *>( 138 gKernelArgs.kernel_image.Pointer()); 139 140 smp_init_other_cpus(); 141 debug_cleanup(); 142 mmu_init_for_kernel(); 143 144 // We're about to enter the kernel -- disable console output. 145 stdout = NULL; 146 147 smp_boot_other_cpus(smp_start_kernel); 148 149 dprintf("kernel entry at %lx\n", image->elf_header.e_entry); 150 151 asm("movl %0, %%eax; " // move stack out of way 152 "movl %%eax, %%esp; " 153 : : "m" (stackTop)); 154 asm("pushl $0x0; " // we're the BSP cpu (0) 155 "pushl %0; " // kernel args 156 "pushl $0x0;" // dummy retval for call to main 157 "pushl %1; " // this is the start address 158 "ret; " // jump. 159 : : "g" (args), "g" (image->elf_header.e_entry)); 160 161 panic("kernel returned!\n"); 162 } 163 164 165 extern "C" void 166 platform_exit(void) 167 { 168 // reset the system using the keyboard controller 169 out8(0xfe, 0x64); 170 } 171 172 173 extern "C" void 174 _start(void) 175 { 176 stage2_args args; 177 178 asm("cld"); // Ain't nothing but a GCC thang. 179 asm("fninit"); // initialize floating point unit 180 181 clear_bss(); 182 call_ctors(); 183 // call C++ constructors before doing anything else 184 185 args.heap_size = HEAP_SIZE; 186 args.arguments = NULL; 187 188 serial_init(); 189 serial_enable(); 190 interrupts_init(); 191 console_init(); 192 cpu_init(); 193 mmu_init(); 194 debug_init_post_mmu(); 195 parse_multiboot_commandline(&args); 196 197 // reading the keyboard doesn't seem to work in graphics mode 198 // (maybe a bochs problem) 199 sBootOptions = check_for_boot_keys(); 200 // if (sBootOptions & BOOT_OPTION_DEBUG_OUTPUT) 201 // serial_enable(); 202 203 apm_init(); 204 acpi_init(); 205 smp_init(); 206 hpet_init(); 207 dump_multiboot_info(); 208 main(&args); 209 } 210 211