1 #include "libcflat.h" 2 #include "desc.h" 3 #include "processor.h" 4 5 typedef struct { 6 unsigned short offset0; 7 unsigned short selector; 8 unsigned short ist : 3; 9 unsigned short : 5; 10 unsigned short type : 4; 11 unsigned short : 1; 12 unsigned short dpl : 2; 13 unsigned short p : 1; 14 unsigned short offset1; 15 #ifdef __x86_64__ 16 unsigned offset2; 17 unsigned reserved; 18 #endif 19 } idt_entry_t; 20 21 typedef struct { 22 u16 limit_low; 23 u16 base_low; 24 u8 base_middle; 25 u8 access; 26 u8 granularity; 27 u8 base_high; 28 } gdt_entry_t; 29 30 extern idt_entry_t boot_idt[256]; 31 32 void set_idt_entry(int vec, void *addr, int dpl) 33 { 34 idt_entry_t *e = &boot_idt[vec]; 35 memset(e, 0, sizeof *e); 36 e->offset0 = (unsigned long)addr; 37 e->selector = read_cs(); 38 e->ist = 0; 39 e->type = 14; 40 e->dpl = dpl; 41 e->p = 1; 42 e->offset1 = (unsigned long)addr >> 16; 43 #ifdef __x86_64__ 44 e->offset2 = (unsigned long)addr >> 32; 45 #endif 46 } 47 48 void set_idt_sel(int vec, u16 sel) 49 { 50 idt_entry_t *e = &boot_idt[vec]; 51 e->selector = sel; 52 } 53 54 struct ex_record { 55 unsigned long rip; 56 unsigned long handler; 57 }; 58 59 extern struct ex_record exception_table_start, exception_table_end; 60 61 static void check_exception_table(struct ex_regs *regs) 62 { 63 struct ex_record *ex; 64 unsigned ex_val; 65 66 ex_val = regs->vector | (regs->error_code << 16); 67 68 asm("mov %0, %%gs:4" : : "r"(ex_val)); 69 70 for (ex = &exception_table_start; ex != &exception_table_end; ++ex) { 71 if (ex->rip == regs->rip) { 72 regs->rip = ex->handler; 73 return; 74 } 75 } 76 printf("unhandled excecption %d\n", regs->vector); 77 exit(7); 78 } 79 80 static void (*exception_handlers[32])(struct ex_regs *regs); 81 82 83 void handle_exception(u8 v, void (*func)(struct ex_regs *regs)) 84 { 85 if (v < 32) 86 exception_handlers[v] = func; 87 } 88 89 #ifndef __x86_64__ 90 __attribute__((regparm(1))) 91 #endif 92 void do_handle_exception(struct ex_regs *regs) 93 { 94 if (regs->vector < 32 && exception_handlers[regs->vector]) { 95 exception_handlers[regs->vector](regs); 96 return; 97 } 98 printf("unhandled cpu excecption %d\n", regs->vector); 99 if (regs->vector == 14) 100 printf("PF at %p addr %p\n", regs->rip, read_cr2()); 101 exit(7); 102 } 103 104 #define EX(NAME, N) extern char NAME##_fault; \ 105 asm (".pushsection .text \n\t" \ 106 #NAME"_fault: \n\t" \ 107 "push"W" $0 \n\t" \ 108 "push"W" $"#N" \n\t" \ 109 "jmp __handle_exception \n\t" \ 110 ".popsection") 111 112 #define EX_E(NAME, N) extern char NAME##_fault; \ 113 asm (".pushsection .text \n\t" \ 114 #NAME"_fault: \n\t" \ 115 "push"W" $"#N" \n\t" \ 116 "jmp __handle_exception \n\t" \ 117 ".popsection") 118 119 EX(de, 0); 120 EX(db, 1); 121 EX(nmi, 2); 122 EX(bp, 3); 123 EX(of, 4); 124 EX(br, 5); 125 EX(ud, 6); 126 EX(nm, 7); 127 EX_E(df, 8); 128 EX_E(ts, 10); 129 EX_E(np, 11); 130 EX_E(ss, 12); 131 EX_E(gp, 13); 132 EX_E(pf, 14); 133 EX(mf, 16); 134 EX_E(ac, 17); 135 EX(mc, 18); 136 EX(xm, 19); 137 138 asm (".pushsection .text \n\t" 139 "__handle_exception: \n\t" 140 #ifdef __x86_64__ 141 "push %r15; push %r14; push %r13; push %r12 \n\t" 142 "push %r11; push %r10; push %r9; push %r8 \n\t" 143 #endif 144 "push %"R"di; push %"R"si; push %"R"bp; sub $"S", %"R"sp \n\t" 145 "push %"R"bx; push %"R"dx; push %"R"cx; push %"R"ax \n\t" 146 #ifdef __x86_64__ 147 "mov %"R"sp, %"R"di \n\t" 148 #else 149 "mov %"R"sp, %"R"ax \n\t" 150 #endif 151 "call do_handle_exception \n\t" 152 "pop %"R"ax; pop %"R"cx; pop %"R"dx; pop %"R"bx \n\t" 153 "add $"S", %"R"sp; pop %"R"bp; pop %"R"si; pop %"R"di \n\t" 154 #ifdef __x86_64__ 155 "pop %r8; pop %r9; pop %r10; pop %r11 \n\t" 156 "pop %r12; pop %r13; pop %r14; pop %r15 \n\t" 157 #endif 158 "add $"S", %"R"sp \n\t" 159 "add $"S", %"R"sp \n\t" 160 "iret"W" \n\t" 161 ".popsection"); 162 163 static void *idt_handlers[32] = { 164 [0] = &de_fault, 165 [1] = &db_fault, 166 [2] = &nmi_fault, 167 [3] = &bp_fault, 168 [4] = &of_fault, 169 [5] = &br_fault, 170 [6] = &ud_fault, 171 [7] = &nm_fault, 172 [8] = &df_fault, 173 [10] = &ts_fault, 174 [11] = &np_fault, 175 [12] = &ss_fault, 176 [13] = &gp_fault, 177 [14] = &pf_fault, 178 [16] = &mf_fault, 179 [17] = &ac_fault, 180 [18] = &mc_fault, 181 [19] = &xm_fault, 182 }; 183 184 void setup_idt(void) 185 { 186 int i; 187 static bool idt_initialized = false; 188 189 if (idt_initialized) { 190 return; 191 } 192 idt_initialized = true; 193 for (i = 0; i < 32; i++) 194 if (idt_handlers[i]) 195 set_idt_entry(i, idt_handlers[i], 0); 196 handle_exception(0, check_exception_table); 197 handle_exception(6, check_exception_table); 198 handle_exception(13, check_exception_table); 199 } 200 201 unsigned exception_vector(void) 202 { 203 unsigned short vector; 204 205 asm("mov %%gs:4, %0" : "=rm"(vector)); 206 return vector; 207 } 208 209 unsigned exception_error_code(void) 210 { 211 unsigned short error_code; 212 213 asm("mov %%gs:6, %0" : "=rm"(error_code)); 214 return error_code; 215 } 216 217 #ifndef __x86_64__ 218 /* 219 * GDT, with 6 entries: 220 * 0x00 - NULL descriptor 221 * 0x08 - Code segment 222 * 0x10 - Data segment 223 * 0x18 - Not presend code segment 224 * 0x20 - Primery task 225 * 0x28 - Interrupt task 226 * 227 * 0x30 to 0x48 - Free to use for test cases 228 */ 229 230 static gdt_entry_t gdt[10]; 231 232 void set_gdt_entry(int sel, u32 base, u32 limit, u8 access, u8 gran) 233 { 234 int num = sel >> 3; 235 236 /* Setup the descriptor base address */ 237 gdt[num].base_low = (base & 0xFFFF); 238 gdt[num].base_middle = (base >> 16) & 0xFF; 239 gdt[num].base_high = (base >> 24) & 0xFF; 240 241 /* Setup the descriptor limits */ 242 gdt[num].limit_low = (limit & 0xFFFF); 243 gdt[num].granularity = ((limit >> 16) & 0x0F); 244 245 /* Finally, set up the granularity and access flags */ 246 gdt[num].granularity |= (gran & 0xF0); 247 gdt[num].access = access; 248 } 249 250 void setup_gdt(void) 251 { 252 struct descriptor_table_ptr gp; 253 /* Setup the GDT pointer and limit */ 254 gp.limit = sizeof(gdt) - 1; 255 gp.base = (ulong)&gdt; 256 257 memset(gdt, 0, sizeof(gdt)); 258 259 /* Our NULL descriptor */ 260 set_gdt_entry(0, 0, 0, 0, 0); 261 262 /* The second entry is our Code Segment. The base address 263 * is 0, the limit is 4GBytes, it uses 4KByte granularity, 264 * uses 32-bit opcodes, and is a Code Segment descriptor. */ 265 set_gdt_entry(KERNEL_CS, 0, 0xFFFFFFFF, 0x9A, 0xcf); 266 267 /* The third entry is our Data Segment. It's EXACTLY the 268 * same as our code segment, but the descriptor type in 269 * this entry's access byte says it's a Data Segment */ 270 set_gdt_entry(KERNEL_DS, 0, 0xFFFFFFFF, 0x92, 0xcf); 271 272 /* Same as code register above but not present */ 273 set_gdt_entry(NP_SEL, 0, 0xFFFFFFFF, 0x1A, 0xcf); 274 275 276 /* Flush out the old GDT and install the new changes! */ 277 lgdt(&gp); 278 279 asm volatile ("mov %0, %%ds\n\t" 280 "mov %0, %%es\n\t" 281 "mov %0, %%fs\n\t" 282 "mov %0, %%gs\n\t" 283 "mov %0, %%ss\n\t" 284 "jmp $" xstr(KERNEL_CS), $.Lflush2\n\t" 285 ".Lflush2: "::"r"(0x10)); 286 } 287 288 void set_idt_task_gate(int vec, u16 sel) 289 { 290 idt_entry_t *e = &boot_idt[vec]; 291 292 memset(e, 0, sizeof *e); 293 294 e->selector = sel; 295 e->ist = 0; 296 e->type = 5; 297 e->dpl = 0; 298 e->p = 1; 299 } 300 301 /* 302 * 0 - main task 303 * 1 - interrupt task 304 */ 305 306 static tss32_t tss[2]; 307 static char tss_stack[2][4096]; 308 309 void setup_tss32(void) 310 { 311 u16 desc_size = sizeof(tss32_t); 312 int i; 313 314 for (i = 0; i < 2; i++) { 315 tss[i].cr3 = read_cr3(); 316 tss[i].ss0 = tss[i].ss1 = tss[i].ss2 = 0x10; 317 tss[i].esp = tss[i].esp0 = tss[i].esp1 = tss[i].esp2 = 318 (u32)tss_stack[i] + 4096; 319 tss[i].cs = KERNEL_CS; 320 tss[i].ds = tss[i].es = tss[i].fs = tss[i].gs = 321 tss[i].ss = KERNEL_DS; 322 tss[i].iomap_base = (u16)desc_size; 323 set_gdt_entry(TSS_MAIN + (i << 3), (u32)&tss[i], 324 desc_size - 1, 0x89, 0x0f); 325 } 326 327 ltr(TSS_MAIN); 328 } 329 330 void set_intr_task_gate(int e, void *fn) 331 { 332 tss[1].eip = (u32)fn; 333 set_idt_task_gate(e, TSS_INTR); 334 } 335 336 void print_current_tss_info(void) 337 { 338 u16 tr = str(); 339 int i = (tr == TSS_MAIN) ? 0 : 1; 340 341 if (tr != TSS_MAIN && tr != TSS_INTR) 342 printf("Unknown TSS %x\n", tr); 343 else 344 printf("TR=%x Main TSS back link %x. Current TSS back link %x\n", 345 tr, tss[0].prev, tss[i].prev); 346 } 347 #endif 348 349 static bool exception; 350 static void *exception_return; 351 352 static void exception_handler(struct ex_regs *regs) 353 { 354 exception = true; 355 regs->rip = (unsigned long)exception_return; 356 } 357 358 bool test_for_exception(unsigned int ex, void (*trigger_func)(void *data), 359 void *data) 360 { 361 handle_exception(ex, exception_handler); 362 exception = false; 363 trigger_func(data); 364 handle_exception(ex, NULL); 365 return exception; 366 } 367 368 void set_exception_return(void *addr) 369 { 370 exception_return = addr; 371 } 372