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