1 #include <stdbool.h> 2 #include <stdint.h> 3 4 #include <sys/kconfig.h> 5 #include <sys/kassert.h> 6 #include <sys/kmem.h> 7 #include <sys/mp.h> 8 #include <sys/irq.h> 9 #include <sys/spinlock.h> 10 11 #include <machine/amd64.h> 12 #include <machine/ioapic.h> 13 #include <machine/lapic.h> 14 #include <machine/trap.h> 15 #include <machine/pmap.h> 16 #include <machine/mp.h> 17 18 #include <sys/thread.h> 19 #include <sys/disk.h> 20 #include <sys/bufcache.h> 21 #include <sys/vfs.h> 22 #include <sys/elf64.h> 23 24 #include "../dev/console.h" 25 26 extern void KTime_Init(); 27 extern void KTimer_Init(); 28 extern void RTC_Init(); 29 extern void PS2_Init(); 30 extern void PCI_Init(); 31 extern void IDE_Init(); 32 extern void MachineBoot_AddMem(); 33 extern void Loader_LoadInit(); 34 extern void PAlloc_LateInit(); 35 36 #define GDT_MAX 8 37 38 static SegmentDescriptor GDT[MAX_CPUS][GDT_MAX]; 39 static PseudoDescriptor GDTDescriptor[MAX_CPUS]; 40 TaskStateSegment64 TSS[MAX_CPUS]; 41 42 static char df_stack[4096]; 43 44 /** 45 * Machine_GDTInit -- 46 * 47 * Configures the Global Descriptor Table (GDT) that lists all segments and 48 * privilege levels in x86. 64-bit mode uses flat 64-bit segments and doesn't 49 * support offsets and limits except for the special FS/GS segment registers. 50 * We create four segments for the kernel code/data and user code/data. 51 */ 52 static void Machine_GDTInit()53Machine_GDTInit() 54 { 55 uint64_t offset; 56 uint64_t tmp; 57 int c = CPU(); 58 59 kprintf("Initializing GDT... "); // Caused pagefault?? 60 61 GDT[c][0] = 0x0; 62 GDT[c][1] = 0x00AF9A000000FFFFULL; /* Kernel CS */ 63 GDT[c][2] = 0x00CF92000000FFFFULL; /* Kernel DS */ 64 GDT[c][3] = 0x0; 65 66 // TSS 67 offset = (uint64_t)&TSS[c]; 68 GDT[c][4] = sizeof(TaskStateSegment64); 69 tmp = offset & 0x00FFFFFF; 70 GDT[c][4] |= (tmp << 16); 71 tmp = offset & 0xFF000000; 72 GDT[c][4] |= (tmp << 56); 73 GDT[c][4] |= 0x89ULL << 40; 74 GDT[c][5] = offset >> 32; 75 76 GDT[c][6] = 0x00AFFA000000FFFFULL; /* User CS */ 77 GDT[c][7] = 0x00CFF2000000FFFFULL; /* User DS */ 78 79 GDTDescriptor[c].off = (uint64_t)&GDT[c]; 80 GDTDescriptor[c].lim = 8*GDT_MAX - 1; 81 82 lgdt(&GDTDescriptor[c]); 83 84 kprintf("Done!\n"); 85 } 86 87 /** 88 * Machine_TSSInit -- 89 * 90 * Configures the Task State Segment (TSS) that specifies the kernel stack 91 * pointer during an interrupt. 92 */ 93 static void Machine_TSSInit()94Machine_TSSInit() 95 { 96 int c = CPU(); 97 98 kprintf("Initializing TSS... "); 99 100 TSS[c]._unused0 = 0; 101 TSS[c]._unused1 = 0; 102 TSS[c]._unused2 = 0; 103 TSS[c]._unused3 = 0; 104 TSS[c]._unused4 = 0; 105 TSS[c].ist1 = ((uint64_t)&df_stack) + 4096; 106 TSS[c].ist2 = 0x0; 107 TSS[c].ist3 = 0x0; 108 TSS[c].ist4 = 0x0; 109 TSS[c].ist5 = 0x0; 110 TSS[c].ist6 = 0x0; 111 TSS[c].ist7 = 0x0; 112 TSS[c].rsp0 = ((uint64_t)&df_stack) + 4096; 113 TSS[c].rsp1 = 0; 114 TSS[c].rsp2 = 0; 115 116 ltr(SEL_TSS); 117 118 kprintf("Done!\n"); 119 } 120 121 /** 122 * Machine_SyscallInit -- 123 * 124 * Configure the model specific registers (MSRs) that specify how to transfer 125 * control to the operating system when the system call instruction is invoked. 126 */ 127 static void Machine_SyscallInit()128Machine_SyscallInit() 129 { 130 kprintf("Initializing Syscall... "); 131 132 wrmsr(MSR_STAR, (uint64_t)SEL_KCS << 32 | (uint64_t)SEL_UCS << 48); 133 wrmsr(MSR_LSTAR, 0); 134 wrmsr(MSR_CSTAR, 0); 135 wrmsr(MSR_SFMASK, 0); 136 137 kprintf("Done!\n"); 138 } 139 140 /** 141 * Machine_EarlyInit -- 142 * 143 * Initializes early kernel state. 144 */ 145 void Machine_EarlyInit()146Machine_EarlyInit() 147 { 148 Spinlock_EarlyInit(); 149 Critical_Init(); 150 Critical_Enter(); 151 WaitChannel_EarlyInit(); 152 Console_Init(); 153 PAlloc_Init(); 154 } 155 156 static void Machine_IdleThread(void * test)157Machine_IdleThread(void *test) 158 { 159 while (1) { enable_interrupts(); hlt(); } 160 } 161 162 /** 163 * Machine_Init -- 164 * 165 * At this point the assembly startup code has setup temporary processor data 166 * structures sufficient to execute C code and make it through this 167 * initialization routine. 168 */ Machine_Init()169void Machine_Init() 170 { 171 /* 172 * Initialize Processor State 173 */ 174 Machine_GDTInit(); 175 Machine_TSSInit(); 176 Trap_Init(); 177 Machine_SyscallInit(); 178 clts(); // Enable FPU/XMM 179 180 /* 181 * Initialize Memory Allocation and Virtual Memory 182 */ 183 PAlloc_AddRegion(DMPA2VA(16*1024*1024), 16*1024*1024); 184 PMap_Init(); 185 XMem_Init(); 186 PAlloc_LateInit(); 187 MachineBoot_AddMem(); 188 189 /* 190 * Initialize Time Keeping 191 */ 192 KTime_Init(); 193 RTC_Init(); // Finishes initializing KTime 194 195 /* 196 * Initialize Interrupts 197 */ 198 IRQ_Init(); 199 LAPIC_Init(); 200 IOAPIC_Init(); 201 IOAPIC_Enable(0); // Enable timer interrupts 202 Thread_Init(); 203 204 KTimer_Init(); // Depends on RTC and KTime 205 206 /* 207 * Initialize Additional Processors 208 */ 209 MP_Init(); 210 211 /* 212 * Initialize Basic Devices 213 */ 214 PS2_Init(); // PS2 Keyboard 215 PCI_Init(); // PCI BUS 216 IDE_Init(); // IDE Disk Controller 217 BufCache_Init(); 218 219 /* 220 * Open the primary disk and mount the root file system 221 */ 222 Disk *root = Disk_GetByID(0, 0); 223 if (!root) 224 Panic("No boot disk!"); 225 VFS_MountRoot(root); 226 227 Critical_Exit(); 228 229 /* 230 * Create the idle thread 231 */ 232 Thread *thr = Thread_KThreadCreate(&Machine_IdleThread, NULL); 233 if (thr == NULL) { 234 kprintf("Couldn't create idle thread!\n"); 235 } 236 Sched_SetRunnable(thr); 237 238 /* 239 * Load the init processor 240 */ 241 Loader_LoadInit(); 242 243 breakpoint(); 244 } 245 246 /** 247 * Machine_InitAP -- 248 * 249 * Shorter initialization routine for co-processors. 250 */ Machine_InitAP()251void Machine_InitAP() 252 { 253 Critical_Enter(); 254 255 // Setup CPU state 256 Trap_InitAP(); 257 PMap_InitAP(); 258 Machine_GDTInit(); 259 Machine_TSSInit(); 260 Machine_SyscallInit(); 261 clts(); // Enable FPU/XMM 262 263 // Setup LAPIC 264 LAPIC_Init(); 265 266 // Boot processor 267 MP_InitAP(); 268 Thread_InitAP(); 269 Critical_Exit(); 270 271 Machine_IdleThread(NULL); 272 } 273 274