17d36db35SAvi Kivity #include "libcflat.h" 2e7c37968SGleb Natapov #include "desc.h" 323ba7b39SGleb Natapov #include "processor.h" 47d36db35SAvi Kivity 57d36db35SAvi Kivity typedef struct { 67d36db35SAvi Kivity unsigned short offset0; 77d36db35SAvi Kivity unsigned short selector; 87d36db35SAvi Kivity unsigned short ist : 3; 97d36db35SAvi Kivity unsigned short : 5; 107d36db35SAvi Kivity unsigned short type : 4; 117d36db35SAvi Kivity unsigned short : 1; 127d36db35SAvi Kivity unsigned short dpl : 2; 137d36db35SAvi Kivity unsigned short p : 1; 147d36db35SAvi Kivity unsigned short offset1; 1523ba7b39SGleb Natapov #ifdef __x86_64__ 167d36db35SAvi Kivity unsigned offset2; 177d36db35SAvi Kivity unsigned reserved; 1823ba7b39SGleb Natapov #endif 197d36db35SAvi Kivity } idt_entry_t; 207d36db35SAvi Kivity 21d21b4f12SGleb Natapov typedef struct { 22d21b4f12SGleb Natapov u16 limit_low; 23d21b4f12SGleb Natapov u16 base_low; 24d21b4f12SGleb Natapov u8 base_middle; 25d21b4f12SGleb Natapov u8 access; 26d21b4f12SGleb Natapov u8 granularity; 27d21b4f12SGleb Natapov u8 base_high; 28d21b4f12SGleb Natapov } gdt_entry_t; 29d21b4f12SGleb Natapov 30d21b4f12SGleb Natapov typedef struct { 31d21b4f12SGleb Natapov u16 prev; 32d21b4f12SGleb Natapov u16 res1; 33d21b4f12SGleb Natapov u32 esp0; 34d21b4f12SGleb Natapov u16 ss0; 35d21b4f12SGleb Natapov u16 res2; 36d21b4f12SGleb Natapov u32 esp1; 37d21b4f12SGleb Natapov u16 ss1; 38d21b4f12SGleb Natapov u16 res3; 39d21b4f12SGleb Natapov u32 esp2; 40d21b4f12SGleb Natapov u16 ss2; 41d21b4f12SGleb Natapov u16 res4; 42d21b4f12SGleb Natapov u32 cr3; 43d21b4f12SGleb Natapov u32 eip; 44d21b4f12SGleb Natapov u32 eflags; 45d21b4f12SGleb Natapov u32 eax, ecx, edx, ebx, esp, ebp, esi, edi; 46d21b4f12SGleb Natapov u16 es; 47d21b4f12SGleb Natapov u16 res5; 48d21b4f12SGleb Natapov u16 cs; 49d21b4f12SGleb Natapov u16 res6; 50d21b4f12SGleb Natapov u16 ss; 51d21b4f12SGleb Natapov u16 res7; 52d21b4f12SGleb Natapov u16 ds; 53d21b4f12SGleb Natapov u16 res8; 54d21b4f12SGleb Natapov u16 fs; 55d21b4f12SGleb Natapov u16 res9; 56d21b4f12SGleb Natapov u16 gs; 57d21b4f12SGleb Natapov u16 res10; 58d21b4f12SGleb Natapov u16 ldt; 59d21b4f12SGleb Natapov u16 res11; 60d21b4f12SGleb Natapov u16 t:1; 61d21b4f12SGleb Natapov u16 res12:15; 62d21b4f12SGleb Natapov u16 iomap_base; 63d21b4f12SGleb Natapov } tss32_t; 64d21b4f12SGleb Natapov 657d36db35SAvi Kivity static idt_entry_t idt[256]; 667d36db35SAvi Kivity 6723ba7b39SGleb Natapov void load_lidt(idt_entry_t *idt, int nentries) 687d36db35SAvi Kivity { 6923ba7b39SGleb Natapov struct descriptor_table_ptr dt; 707d36db35SAvi Kivity 717d36db35SAvi Kivity dt.limit = nentries * sizeof(*idt) - 1; 7223ba7b39SGleb Natapov dt.base = (unsigned long)idt; 7323ba7b39SGleb Natapov lidt(&dt); 747d36db35SAvi Kivity asm volatile ("lidt %0" : : "m"(dt)); 757d36db35SAvi Kivity } 767d36db35SAvi Kivity 7723ba7b39SGleb Natapov void set_idt_entry(int vec, void *addr, int dpl) 787d36db35SAvi Kivity { 7923ba7b39SGleb Natapov idt_entry_t *e = &idt[vec]; 807d36db35SAvi Kivity memset(e, 0, sizeof *e); 817d36db35SAvi Kivity e->offset0 = (unsigned long)addr; 827d36db35SAvi Kivity e->selector = read_cs(); 837d36db35SAvi Kivity e->ist = 0; 847d36db35SAvi Kivity e->type = 14; 857d36db35SAvi Kivity e->dpl = dpl; 867d36db35SAvi Kivity e->p = 1; 877d36db35SAvi Kivity e->offset1 = (unsigned long)addr >> 16; 8823ba7b39SGleb Natapov #ifdef __x86_64__ 897d36db35SAvi Kivity e->offset2 = (unsigned long)addr >> 32; 9023ba7b39SGleb Natapov #endif 917d36db35SAvi Kivity } 927d36db35SAvi Kivity 937d36db35SAvi Kivity struct ex_regs { 947d36db35SAvi Kivity unsigned long rax, rcx, rdx, rbx; 957d36db35SAvi Kivity unsigned long dummy, rbp, rsi, rdi; 9623ba7b39SGleb Natapov #ifdef __x86_64__ 977d36db35SAvi Kivity unsigned long r8, r9, r10, r11; 987d36db35SAvi Kivity unsigned long r12, r13, r14, r15; 9923ba7b39SGleb Natapov #endif 1007d36db35SAvi Kivity unsigned long vector; 1017d36db35SAvi Kivity unsigned long error_code; 1027d36db35SAvi Kivity unsigned long rip; 1037d36db35SAvi Kivity unsigned long cs; 1047d36db35SAvi Kivity unsigned long rflags; 1057d36db35SAvi Kivity }; 1067d36db35SAvi Kivity 1077d36db35SAvi Kivity struct ex_record { 1087d36db35SAvi Kivity unsigned long rip; 1097d36db35SAvi Kivity unsigned long handler; 1107d36db35SAvi Kivity }; 1117d36db35SAvi Kivity 1127d36db35SAvi Kivity extern struct ex_record exception_table_start, exception_table_end; 1137d36db35SAvi Kivity 114*c3b91807SGleb Natapov #ifndef __x86_64__ 115*c3b91807SGleb Natapov __attribute__((regparm(1))) 116*c3b91807SGleb Natapov #endif 1177d36db35SAvi Kivity void do_handle_exception(struct ex_regs *regs) 1187d36db35SAvi Kivity { 1197d36db35SAvi Kivity struct ex_record *ex; 1207d36db35SAvi Kivity unsigned ex_val; 1217d36db35SAvi Kivity 1227d36db35SAvi Kivity ex_val = regs->vector | (regs->error_code << 16); 1237d36db35SAvi Kivity 1247d36db35SAvi Kivity asm("mov %0, %%gs:4" : : "r"(ex_val)); 1257d36db35SAvi Kivity 1267d36db35SAvi Kivity for (ex = &exception_table_start; ex != &exception_table_end; ++ex) { 1277d36db35SAvi Kivity if (ex->rip == regs->rip) { 1287d36db35SAvi Kivity regs->rip = ex->handler; 1297d36db35SAvi Kivity return; 1307d36db35SAvi Kivity } 1317d36db35SAvi Kivity } 1327d36db35SAvi Kivity printf("unhandled excecption\n"); 1337d36db35SAvi Kivity exit(7); 1347d36db35SAvi Kivity } 1357d36db35SAvi Kivity 13623ba7b39SGleb Natapov #ifdef __x86_64__ 13723ba7b39SGleb Natapov # define R "r" 13823ba7b39SGleb Natapov # define W "q" 13923ba7b39SGleb Natapov # define S "8" 14023ba7b39SGleb Natapov #else 14123ba7b39SGleb Natapov # define R "e" 14223ba7b39SGleb Natapov # define W "l" 14323ba7b39SGleb Natapov # define S "4" 14423ba7b39SGleb Natapov #endif 14523ba7b39SGleb Natapov 1467d36db35SAvi Kivity asm (".pushsection .text \n\t" 1477d36db35SAvi Kivity "ud_fault: \n\t" 14823ba7b39SGleb Natapov "push"W" $0 \n\t" 14923ba7b39SGleb Natapov "push"W" $6 \n\t" 1507d36db35SAvi Kivity "jmp handle_exception \n\t" 1517d36db35SAvi Kivity 1527d36db35SAvi Kivity "gp_fault: \n\t" 15323ba7b39SGleb Natapov "push"W" $13 \n\t" 1547d36db35SAvi Kivity "jmp handle_exception \n\t" 1557d36db35SAvi Kivity 156597e0ef2SAvi Kivity "de_fault: \n\t" 15723ba7b39SGleb Natapov "push"W" $0 \n\t" 15823ba7b39SGleb Natapov "push"W" $0 \n\t" 159597e0ef2SAvi Kivity "jmp handle_exception \n\t" 160597e0ef2SAvi Kivity 1617d36db35SAvi Kivity "handle_exception: \n\t" 16223ba7b39SGleb Natapov #ifdef __x86_64__ 1637d36db35SAvi Kivity "push %r15; push %r14; push %r13; push %r12 \n\t" 1647d36db35SAvi Kivity "push %r11; push %r10; push %r9; push %r8 \n\t" 16523ba7b39SGleb Natapov #endif 16623ba7b39SGleb Natapov "push %"R"di; push %"R"si; push %"R"bp; sub $"S", %"R"sp \n\t" 16723ba7b39SGleb Natapov "push %"R"bx; push %"R"dx; push %"R"cx; push %"R"ax \n\t" 168*c3b91807SGleb Natapov #ifdef __x86_64__ 16923ba7b39SGleb Natapov "mov %"R"sp, %"R"di \n\t" 170*c3b91807SGleb Natapov #else 171*c3b91807SGleb Natapov "mov %"R"sp, %"R"ax \n\t" 172*c3b91807SGleb Natapov #endif 1737d36db35SAvi Kivity "call do_handle_exception \n\t" 17423ba7b39SGleb Natapov "pop %"R"ax; pop %"R"cx; pop %"R"dx; pop %"R"bx \n\t" 17523ba7b39SGleb Natapov "add $"S", %"R"sp; pop %"R"bp; pop %"R"si; pop %"R"di \n\t" 17623ba7b39SGleb Natapov #ifdef __x86_64__ 1777d36db35SAvi Kivity "pop %r8; pop %r9; pop %r10; pop %r11 \n\t" 1787d36db35SAvi Kivity "pop %r12; pop %r13; pop %r14; pop %r15 \n\t" 17923ba7b39SGleb Natapov #endif 18023ba7b39SGleb Natapov "add $"S", %"R"sp \n\t" 18123ba7b39SGleb Natapov "add $"S", %"R"sp \n\t" 18223ba7b39SGleb Natapov "iret"W" \n\t" 1837d36db35SAvi Kivity ".popsection"); 1847d36db35SAvi Kivity 1857d36db35SAvi Kivity 1867d36db35SAvi Kivity void setup_idt(void) 1877d36db35SAvi Kivity { 188597e0ef2SAvi Kivity extern char ud_fault, gp_fault, de_fault; 1897d36db35SAvi Kivity 19023ba7b39SGleb Natapov load_lidt(idt, 256); 19123ba7b39SGleb Natapov set_idt_entry(0, &de_fault, 0); 19223ba7b39SGleb Natapov set_idt_entry(6, &ud_fault, 0); 19323ba7b39SGleb Natapov set_idt_entry(13, &gp_fault, 0); 1947d36db35SAvi Kivity } 1957d36db35SAvi Kivity 1967d36db35SAvi Kivity unsigned exception_vector(void) 1977d36db35SAvi Kivity { 1987d36db35SAvi Kivity unsigned short vector; 1997d36db35SAvi Kivity 2007d36db35SAvi Kivity asm("mov %%gs:4, %0" : "=rm"(vector)); 2017d36db35SAvi Kivity return vector; 2027d36db35SAvi Kivity } 2037d36db35SAvi Kivity 2047d36db35SAvi Kivity unsigned exception_error_code(void) 2057d36db35SAvi Kivity { 2067d36db35SAvi Kivity unsigned short error_code; 2077d36db35SAvi Kivity 2087d36db35SAvi Kivity asm("mov %%gs:6, %0" : "=rm"(error_code)); 2097d36db35SAvi Kivity return error_code; 2107d36db35SAvi Kivity } 211d21b4f12SGleb Natapov 212d21b4f12SGleb Natapov #ifndef __x86_64__ 213d21b4f12SGleb Natapov /* 214d21b4f12SGleb Natapov * GDT, with 6 entries: 215d21b4f12SGleb Natapov * 0x00 - NULL descriptor 216d21b4f12SGleb Natapov * 0x08 - Code segment 217d21b4f12SGleb Natapov * 0x10 - Data segment 218d21b4f12SGleb Natapov * 0x18 - Not presend code segment 219d21b4f12SGleb Natapov * 0x20 - Primery task 220d21b4f12SGleb Natapov * 0x28 - Interrupt task 221d21b4f12SGleb Natapov */ 222d21b4f12SGleb Natapov 223d21b4f12SGleb Natapov static gdt_entry_t gdt[6]; 224d21b4f12SGleb Natapov #define TSS_GDT_OFFSET 4 225d21b4f12SGleb Natapov 226d21b4f12SGleb Natapov void set_gdt_entry(int num, u32 base, u32 limit, u8 access, u8 gran) 227d21b4f12SGleb Natapov { 228d21b4f12SGleb Natapov /* Setup the descriptor base address */ 229d21b4f12SGleb Natapov gdt[num].base_low = (base & 0xFFFF); 230d21b4f12SGleb Natapov gdt[num].base_middle = (base >> 16) & 0xFF; 231d21b4f12SGleb Natapov gdt[num].base_high = (base >> 24) & 0xFF; 232d21b4f12SGleb Natapov 233d21b4f12SGleb Natapov /* Setup the descriptor limits */ 234d21b4f12SGleb Natapov gdt[num].limit_low = (limit & 0xFFFF); 235d21b4f12SGleb Natapov gdt[num].granularity = ((limit >> 16) & 0x0F); 236d21b4f12SGleb Natapov 237d21b4f12SGleb Natapov /* Finally, set up the granularity and access flags */ 238d21b4f12SGleb Natapov gdt[num].granularity |= (gran & 0xF0); 239d21b4f12SGleb Natapov gdt[num].access = access; 240d21b4f12SGleb Natapov } 241d21b4f12SGleb Natapov 242d21b4f12SGleb Natapov void setup_gdt(void) 243d21b4f12SGleb Natapov { 244d21b4f12SGleb Natapov struct descriptor_table_ptr gp; 245d21b4f12SGleb Natapov /* Setup the GDT pointer and limit */ 246d21b4f12SGleb Natapov gp.limit = sizeof(gdt) - 1; 247d21b4f12SGleb Natapov gp.base = (ulong)&gdt; 248d21b4f12SGleb Natapov 249d21b4f12SGleb Natapov memset(gdt, 0, sizeof(gdt)); 250d21b4f12SGleb Natapov 251d21b4f12SGleb Natapov /* Our NULL descriptor */ 252d21b4f12SGleb Natapov set_gdt_entry(0, 0, 0, 0, 0); 253d21b4f12SGleb Natapov 254d21b4f12SGleb Natapov /* The second entry is our Code Segment. The base address 255d21b4f12SGleb Natapov * is 0, the limit is 4GBytes, it uses 4KByte granularity, 256d21b4f12SGleb Natapov * uses 32-bit opcodes, and is a Code Segment descriptor. */ 257d21b4f12SGleb Natapov set_gdt_entry(1, 0, 0xFFFFFFFF, 0x9A, 0xcf); 258d21b4f12SGleb Natapov 259d21b4f12SGleb Natapov /* The third entry is our Data Segment. It's EXACTLY the 260d21b4f12SGleb Natapov * same as our code segment, but the descriptor type in 261d21b4f12SGleb Natapov * this entry's access byte says it's a Data Segment */ 262d21b4f12SGleb Natapov set_gdt_entry(2, 0, 0xFFFFFFFF, 0x92, 0xcf); 263d21b4f12SGleb Natapov 264d21b4f12SGleb Natapov /* Same as code register above but not present */ 265d21b4f12SGleb Natapov set_gdt_entry(3, 0, 0xFFFFFFFF, 0x1A, 0xcf); 266d21b4f12SGleb Natapov 267d21b4f12SGleb Natapov 268d21b4f12SGleb Natapov /* Flush out the old GDT and install the new changes! */ 269d21b4f12SGleb Natapov lgdt(&gp); 270d21b4f12SGleb Natapov 271d21b4f12SGleb Natapov asm volatile ("mov %0, %%ds\n\t" 272d21b4f12SGleb Natapov "mov %0, %%es\n\t" 273d21b4f12SGleb Natapov "mov %0, %%fs\n\t" 274d21b4f12SGleb Natapov "mov %0, %%gs\n\t" 275d21b4f12SGleb Natapov "mov %0, %%ss\n\t" 276d21b4f12SGleb Natapov "jmp $0x08, $.Lflush2\n\t" 277d21b4f12SGleb Natapov ".Lflush2: "::"r"(0x10)); 278d21b4f12SGleb Natapov } 279d21b4f12SGleb Natapov 280d21b4f12SGleb Natapov static void set_idt_task_gate(int vec, u16 sel) 281d21b4f12SGleb Natapov { 282d21b4f12SGleb Natapov idt_entry_t *e = &idt[vec]; 283d21b4f12SGleb Natapov 284d21b4f12SGleb Natapov memset(e, 0, sizeof *e); 285d21b4f12SGleb Natapov 286d21b4f12SGleb Natapov e->selector = sel; 287d21b4f12SGleb Natapov e->ist = 0; 288d21b4f12SGleb Natapov e->type = 5; 289d21b4f12SGleb Natapov e->dpl = 0; 290d21b4f12SGleb Natapov e->p = 1; 291d21b4f12SGleb Natapov } 292d21b4f12SGleb Natapov 293d21b4f12SGleb Natapov /* 294d21b4f12SGleb Natapov * 0 - main task 295d21b4f12SGleb Natapov * 1 - interrupt task 296d21b4f12SGleb Natapov */ 297d21b4f12SGleb Natapov 298d21b4f12SGleb Natapov static tss32_t tss[2]; 299d21b4f12SGleb Natapov static char tss_stack[2][4096]; 300d21b4f12SGleb Natapov 301d21b4f12SGleb Natapov void setup_tss32(void) 302d21b4f12SGleb Natapov { 303d21b4f12SGleb Natapov u16 desc_size = sizeof(tss32_t); 304d21b4f12SGleb Natapov int i; 305d21b4f12SGleb Natapov 306d21b4f12SGleb Natapov for (i = 0; i < 2; i++) { 307d21b4f12SGleb Natapov tss[i].cr3 = read_cr3(); 308d21b4f12SGleb Natapov tss[i].ss0 = tss[i].ss1 = tss[i].ss2 = 0x10; 309d21b4f12SGleb Natapov tss[i].esp = tss[i].esp0 = tss[i].esp1 = tss[i].esp2 = 310d21b4f12SGleb Natapov (u32)tss_stack[i]; 311d21b4f12SGleb Natapov tss[i].cs = 0x08; 312d21b4f12SGleb Natapov tss[i].ds = tss[i].es = tss[i].fs = tss[i].gs = tss[i].ss = 0x10; 313d21b4f12SGleb Natapov tss[i].iomap_base = (u16)desc_size; 314d21b4f12SGleb Natapov set_gdt_entry(TSS_GDT_OFFSET + i, (u32)&tss[i], 315d21b4f12SGleb Natapov desc_size - 1, 0x89, 0x0f); 316d21b4f12SGleb Natapov } 317d21b4f12SGleb Natapov 318d21b4f12SGleb Natapov ltr(TSS_MAIN); 319d21b4f12SGleb Natapov } 320d21b4f12SGleb Natapov 321d21b4f12SGleb Natapov void set_intr_task_gate(int e, void *fn) 322d21b4f12SGleb Natapov { 323d21b4f12SGleb Natapov tss[1].eip = (u32)fn; 324d21b4f12SGleb Natapov set_idt_task_gate(e, TSS_INTR); 325d21b4f12SGleb Natapov } 326d21b4f12SGleb Natapov 327d21b4f12SGleb Natapov void print_current_tss_info(void) 328d21b4f12SGleb Natapov { 329d21b4f12SGleb Natapov u16 tr = str(); 330d21b4f12SGleb Natapov int i = (tr == TSS_MAIN) ? 0 : 1; 331d21b4f12SGleb Natapov 332d21b4f12SGleb Natapov if (tr != TSS_MAIN && tr != TSS_INTR) 333d21b4f12SGleb Natapov printf("Unknown TSS %x\n", tr); 334d21b4f12SGleb Natapov else 335d21b4f12SGleb Natapov printf("TR=%x Main TSS back link %x. Current TSS back link %x\n", 336d21b4f12SGleb Natapov tr, tss[0].prev, tss[i].prev); 337d21b4f12SGleb Natapov } 338d21b4f12SGleb Natapov #endif 339