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 #ifdef __x86_64__ 105 # define R "r" 106 # define W "q" 107 # define S "8" 108 #else 109 # define R "e" 110 # define W "l" 111 # define S "4" 112 #endif 113 114 #define EX(NAME, N) extern char NAME##_fault; \ 115 asm (".pushsection .text \n\t" \ 116 #NAME"_fault: \n\t" \ 117 "push"W" $0 \n\t" \ 118 "push"W" $"#N" \n\t" \ 119 "jmp __handle_exception \n\t" \ 120 ".popsection") 121 122 #define EX_E(NAME, N) extern char NAME##_fault; \ 123 asm (".pushsection .text \n\t" \ 124 #NAME"_fault: \n\t" \ 125 "push"W" $"#N" \n\t" \ 126 "jmp __handle_exception \n\t" \ 127 ".popsection") 128 129 EX(de, 0); 130 EX(db, 1); 131 EX(nmi, 2); 132 EX(bp, 3); 133 EX(of, 4); 134 EX(br, 5); 135 EX(ud, 6); 136 EX(nm, 7); 137 EX_E(df, 8); 138 EX_E(ts, 10); 139 EX_E(np, 11); 140 EX_E(ss, 12); 141 EX_E(gp, 13); 142 EX_E(pf, 14); 143 EX(mf, 16); 144 EX_E(ac, 17); 145 EX(mc, 18); 146 EX(xm, 19); 147 148 asm (".pushsection .text \n\t" 149 "__handle_exception: \n\t" 150 #ifdef __x86_64__ 151 "push %r15; push %r14; push %r13; push %r12 \n\t" 152 "push %r11; push %r10; push %r9; push %r8 \n\t" 153 #endif 154 "push %"R"di; push %"R"si; push %"R"bp; sub $"S", %"R"sp \n\t" 155 "push %"R"bx; push %"R"dx; push %"R"cx; push %"R"ax \n\t" 156 #ifdef __x86_64__ 157 "mov %"R"sp, %"R"di \n\t" 158 #else 159 "mov %"R"sp, %"R"ax \n\t" 160 #endif 161 "call do_handle_exception \n\t" 162 "pop %"R"ax; pop %"R"cx; pop %"R"dx; pop %"R"bx \n\t" 163 "add $"S", %"R"sp; pop %"R"bp; pop %"R"si; pop %"R"di \n\t" 164 #ifdef __x86_64__ 165 "pop %r8; pop %r9; pop %r10; pop %r11 \n\t" 166 "pop %r12; pop %r13; pop %r14; pop %r15 \n\t" 167 #endif 168 "add $"S", %"R"sp \n\t" 169 "add $"S", %"R"sp \n\t" 170 "iret"W" \n\t" 171 ".popsection"); 172 173 static void *idt_handlers[32] = { 174 [0] = &de_fault, 175 [1] = &db_fault, 176 [2] = &nmi_fault, 177 [3] = &bp_fault, 178 [4] = &of_fault, 179 [5] = &br_fault, 180 [6] = &ud_fault, 181 [7] = &nm_fault, 182 [8] = &df_fault, 183 [10] = &ts_fault, 184 [11] = &np_fault, 185 [12] = &ss_fault, 186 [13] = &gp_fault, 187 [14] = &pf_fault, 188 [16] = &mf_fault, 189 [17] = &ac_fault, 190 [18] = &mc_fault, 191 [19] = &xm_fault, 192 }; 193 194 void setup_idt(void) 195 { 196 int i; 197 static bool idt_initialized = false; 198 199 if (idt_initialized) { 200 return; 201 } 202 idt_initialized = true; 203 for (i = 0; i < 32; i++) 204 if (idt_handlers[i]) 205 set_idt_entry(i, idt_handlers[i], 0); 206 handle_exception(0, check_exception_table); 207 handle_exception(6, check_exception_table); 208 handle_exception(13, check_exception_table); 209 } 210 211 unsigned exception_vector(void) 212 { 213 unsigned short vector; 214 215 asm("mov %%gs:4, %0" : "=rm"(vector)); 216 return vector; 217 } 218 219 unsigned exception_error_code(void) 220 { 221 unsigned short error_code; 222 223 asm("mov %%gs:6, %0" : "=rm"(error_code)); 224 return error_code; 225 } 226 227 #ifndef __x86_64__ 228 /* 229 * GDT, with 6 entries: 230 * 0x00 - NULL descriptor 231 * 0x08 - Code segment 232 * 0x10 - Data segment 233 * 0x18 - Not presend code segment 234 * 0x20 - Primery task 235 * 0x28 - Interrupt task 236 * 237 * 0x30 to 0x48 - Free to use for test cases 238 */ 239 240 static gdt_entry_t gdt[10]; 241 #define TSS_GDT_OFFSET 4 242 243 void set_gdt_entry(int num, u32 base, u32 limit, u8 access, u8 gran) 244 { 245 /* Setup the descriptor base address */ 246 gdt[num].base_low = (base & 0xFFFF); 247 gdt[num].base_middle = (base >> 16) & 0xFF; 248 gdt[num].base_high = (base >> 24) & 0xFF; 249 250 /* Setup the descriptor limits */ 251 gdt[num].limit_low = (limit & 0xFFFF); 252 gdt[num].granularity = ((limit >> 16) & 0x0F); 253 254 /* Finally, set up the granularity and access flags */ 255 gdt[num].granularity |= (gran & 0xF0); 256 gdt[num].access = access; 257 } 258 259 void setup_gdt(void) 260 { 261 struct descriptor_table_ptr gp; 262 /* Setup the GDT pointer and limit */ 263 gp.limit = sizeof(gdt) - 1; 264 gp.base = (ulong)&gdt; 265 266 memset(gdt, 0, sizeof(gdt)); 267 268 /* Our NULL descriptor */ 269 set_gdt_entry(0, 0, 0, 0, 0); 270 271 /* The second entry is our Code Segment. The base address 272 * is 0, the limit is 4GBytes, it uses 4KByte granularity, 273 * uses 32-bit opcodes, and is a Code Segment descriptor. */ 274 set_gdt_entry(1, 0, 0xFFFFFFFF, 0x9A, 0xcf); 275 276 /* The third entry is our Data Segment. It's EXACTLY the 277 * same as our code segment, but the descriptor type in 278 * this entry's access byte says it's a Data Segment */ 279 set_gdt_entry(2, 0, 0xFFFFFFFF, 0x92, 0xcf); 280 281 /* Same as code register above but not present */ 282 set_gdt_entry(3, 0, 0xFFFFFFFF, 0x1A, 0xcf); 283 284 285 /* Flush out the old GDT and install the new changes! */ 286 lgdt(&gp); 287 288 asm volatile ("mov %0, %%ds\n\t" 289 "mov %0, %%es\n\t" 290 "mov %0, %%fs\n\t" 291 "mov %0, %%gs\n\t" 292 "mov %0, %%ss\n\t" 293 "jmp $0x08, $.Lflush2\n\t" 294 ".Lflush2: "::"r"(0x10)); 295 } 296 297 void set_idt_task_gate(int vec, u16 sel) 298 { 299 idt_entry_t *e = &boot_idt[vec]; 300 301 memset(e, 0, sizeof *e); 302 303 e->selector = sel; 304 e->ist = 0; 305 e->type = 5; 306 e->dpl = 0; 307 e->p = 1; 308 } 309 310 /* 311 * 0 - main task 312 * 1 - interrupt task 313 */ 314 315 static tss32_t tss[2]; 316 static char tss_stack[2][4096]; 317 318 void setup_tss32(void) 319 { 320 u16 desc_size = sizeof(tss32_t); 321 int i; 322 323 for (i = 0; i < 2; i++) { 324 tss[i].cr3 = read_cr3(); 325 tss[i].ss0 = tss[i].ss1 = tss[i].ss2 = 0x10; 326 tss[i].esp = tss[i].esp0 = tss[i].esp1 = tss[i].esp2 = 327 (u32)tss_stack[i] + 4096; 328 tss[i].cs = 0x08; 329 tss[i].ds = tss[i].es = tss[i].fs = tss[i].gs = tss[i].ss = 0x10; 330 tss[i].iomap_base = (u16)desc_size; 331 set_gdt_entry(TSS_GDT_OFFSET + i, (u32)&tss[i], 332 desc_size - 1, 0x89, 0x0f); 333 } 334 335 ltr(TSS_MAIN); 336 } 337 338 void set_intr_task_gate(int e, void *fn) 339 { 340 tss[1].eip = (u32)fn; 341 set_idt_task_gate(e, TSS_INTR); 342 } 343 344 void print_current_tss_info(void) 345 { 346 u16 tr = str(); 347 int i = (tr == TSS_MAIN) ? 0 : 1; 348 349 if (tr != TSS_MAIN && tr != TSS_INTR) 350 printf("Unknown TSS %x\n", tr); 351 else 352 printf("TR=%x Main TSS back link %x. Current TSS back link %x\n", 353 tr, tss[0].prev, tss[i].prev); 354 } 355 #endif 356