17d36db35SAvi Kivity #include "libcflat.h" 2e7c37968SGleb Natapov #include "desc.h" 323ba7b39SGleb Natapov #include "processor.h" 47d36db35SAvi Kivity 523ba7b39SGleb Natapov void set_idt_entry(int vec, void *addr, int dpl) 67d36db35SAvi Kivity { 71d946e07SAvi Kivity idt_entry_t *e = &boot_idt[vec]; 87d36db35SAvi Kivity memset(e, 0, sizeof *e); 97d36db35SAvi Kivity e->offset0 = (unsigned long)addr; 107d36db35SAvi Kivity e->selector = read_cs(); 117d36db35SAvi Kivity e->ist = 0; 127d36db35SAvi Kivity e->type = 14; 137d36db35SAvi Kivity e->dpl = dpl; 147d36db35SAvi Kivity e->p = 1; 157d36db35SAvi Kivity e->offset1 = (unsigned long)addr >> 16; 1623ba7b39SGleb Natapov #ifdef __x86_64__ 177d36db35SAvi Kivity e->offset2 = (unsigned long)addr >> 32; 1823ba7b39SGleb Natapov #endif 197d36db35SAvi Kivity } 207d36db35SAvi Kivity 21a4b87a16SGleb Natapov void set_idt_sel(int vec, u16 sel) 22a4b87a16SGleb Natapov { 231d946e07SAvi Kivity idt_entry_t *e = &boot_idt[vec]; 24a4b87a16SGleb Natapov e->selector = sel; 25a4b87a16SGleb Natapov } 267d36db35SAvi Kivity 277d36db35SAvi Kivity struct ex_record { 287d36db35SAvi Kivity unsigned long rip; 297d36db35SAvi Kivity unsigned long handler; 307d36db35SAvi Kivity }; 317d36db35SAvi Kivity 327d36db35SAvi Kivity extern struct ex_record exception_table_start, exception_table_end; 337d36db35SAvi Kivity 34af11bd88SGleb Natapov static void check_exception_table(struct ex_regs *regs) 357d36db35SAvi Kivity { 367d36db35SAvi Kivity struct ex_record *ex; 377d36db35SAvi Kivity unsigned ex_val; 387d36db35SAvi Kivity 397d36db35SAvi Kivity ex_val = regs->vector | (regs->error_code << 16); 407d36db35SAvi Kivity 417d36db35SAvi Kivity asm("mov %0, %%gs:4" : : "r"(ex_val)); 427d36db35SAvi Kivity 437d36db35SAvi Kivity for (ex = &exception_table_start; ex != &exception_table_end; ++ex) { 447d36db35SAvi Kivity if (ex->rip == regs->rip) { 457d36db35SAvi Kivity regs->rip = ex->handler; 467d36db35SAvi Kivity return; 477d36db35SAvi Kivity } 487d36db35SAvi Kivity } 49af11bd88SGleb Natapov printf("unhandled excecption %d\n", regs->vector); 50af11bd88SGleb Natapov exit(7); 51af11bd88SGleb Natapov } 52af11bd88SGleb Natapov 53af11bd88SGleb Natapov static void (*exception_handlers[32])(struct ex_regs *regs); 54af11bd88SGleb Natapov 55af11bd88SGleb Natapov 56af11bd88SGleb Natapov void handle_exception(u8 v, void (*func)(struct ex_regs *regs)) 57af11bd88SGleb Natapov { 58af11bd88SGleb Natapov if (v < 32) 59af11bd88SGleb Natapov exception_handlers[v] = func; 60af11bd88SGleb Natapov } 61af11bd88SGleb Natapov 62af11bd88SGleb Natapov #ifndef __x86_64__ 63af11bd88SGleb Natapov __attribute__((regparm(1))) 64af11bd88SGleb Natapov #endif 65af11bd88SGleb Natapov void do_handle_exception(struct ex_regs *regs) 66af11bd88SGleb Natapov { 67af11bd88SGleb Natapov if (regs->vector < 32 && exception_handlers[regs->vector]) { 68af11bd88SGleb Natapov exception_handlers[regs->vector](regs); 69af11bd88SGleb Natapov return; 70af11bd88SGleb Natapov } 71af11bd88SGleb Natapov printf("unhandled cpu excecption %d\n", regs->vector); 72af11bd88SGleb Natapov if (regs->vector == 14) 73af11bd88SGleb Natapov printf("PF at %p addr %p\n", regs->rip, read_cr2()); 747d36db35SAvi Kivity exit(7); 757d36db35SAvi Kivity } 767d36db35SAvi Kivity 77af11bd88SGleb Natapov #define EX(NAME, N) extern char NAME##_fault; \ 78af11bd88SGleb Natapov asm (".pushsection .text \n\t" \ 79af11bd88SGleb Natapov #NAME"_fault: \n\t" \ 80af11bd88SGleb Natapov "push"W" $0 \n\t" \ 81af11bd88SGleb Natapov "push"W" $"#N" \n\t" \ 82af11bd88SGleb Natapov "jmp __handle_exception \n\t" \ 83af11bd88SGleb Natapov ".popsection") 84af11bd88SGleb Natapov 85af11bd88SGleb Natapov #define EX_E(NAME, N) extern char NAME##_fault; \ 86af11bd88SGleb Natapov asm (".pushsection .text \n\t" \ 87af11bd88SGleb Natapov #NAME"_fault: \n\t" \ 88af11bd88SGleb Natapov "push"W" $"#N" \n\t" \ 89af11bd88SGleb Natapov "jmp __handle_exception \n\t" \ 90af11bd88SGleb Natapov ".popsection") 91af11bd88SGleb Natapov 92af11bd88SGleb Natapov EX(de, 0); 93af11bd88SGleb Natapov EX(db, 1); 94af11bd88SGleb Natapov EX(nmi, 2); 95af11bd88SGleb Natapov EX(bp, 3); 96af11bd88SGleb Natapov EX(of, 4); 97af11bd88SGleb Natapov EX(br, 5); 98af11bd88SGleb Natapov EX(ud, 6); 99af11bd88SGleb Natapov EX(nm, 7); 100af11bd88SGleb Natapov EX_E(df, 8); 101af11bd88SGleb Natapov EX_E(ts, 10); 102af11bd88SGleb Natapov EX_E(np, 11); 103af11bd88SGleb Natapov EX_E(ss, 12); 104af11bd88SGleb Natapov EX_E(gp, 13); 105af11bd88SGleb Natapov EX_E(pf, 14); 106af11bd88SGleb Natapov EX(mf, 16); 107af11bd88SGleb Natapov EX_E(ac, 17); 108af11bd88SGleb Natapov EX(mc, 18); 109af11bd88SGleb Natapov EX(xm, 19); 110af11bd88SGleb Natapov 1117d36db35SAvi Kivity asm (".pushsection .text \n\t" 112af11bd88SGleb Natapov "__handle_exception: \n\t" 11323ba7b39SGleb Natapov #ifdef __x86_64__ 1147d36db35SAvi Kivity "push %r15; push %r14; push %r13; push %r12 \n\t" 1157d36db35SAvi Kivity "push %r11; push %r10; push %r9; push %r8 \n\t" 11623ba7b39SGleb Natapov #endif 11723ba7b39SGleb Natapov "push %"R"di; push %"R"si; push %"R"bp; sub $"S", %"R"sp \n\t" 11823ba7b39SGleb Natapov "push %"R"bx; push %"R"dx; push %"R"cx; push %"R"ax \n\t" 119c3b91807SGleb Natapov #ifdef __x86_64__ 12023ba7b39SGleb Natapov "mov %"R"sp, %"R"di \n\t" 121c3b91807SGleb Natapov #else 122c3b91807SGleb Natapov "mov %"R"sp, %"R"ax \n\t" 123c3b91807SGleb Natapov #endif 1247d36db35SAvi Kivity "call do_handle_exception \n\t" 12523ba7b39SGleb Natapov "pop %"R"ax; pop %"R"cx; pop %"R"dx; pop %"R"bx \n\t" 12623ba7b39SGleb Natapov "add $"S", %"R"sp; pop %"R"bp; pop %"R"si; pop %"R"di \n\t" 12723ba7b39SGleb Natapov #ifdef __x86_64__ 1287d36db35SAvi Kivity "pop %r8; pop %r9; pop %r10; pop %r11 \n\t" 1297d36db35SAvi Kivity "pop %r12; pop %r13; pop %r14; pop %r15 \n\t" 13023ba7b39SGleb Natapov #endif 13123ba7b39SGleb Natapov "add $"S", %"R"sp \n\t" 13223ba7b39SGleb Natapov "add $"S", %"R"sp \n\t" 13323ba7b39SGleb Natapov "iret"W" \n\t" 1347d36db35SAvi Kivity ".popsection"); 1357d36db35SAvi Kivity 136af11bd88SGleb Natapov static void *idt_handlers[32] = { 137af11bd88SGleb Natapov [0] = &de_fault, 138af11bd88SGleb Natapov [1] = &db_fault, 139af11bd88SGleb Natapov [2] = &nmi_fault, 140af11bd88SGleb Natapov [3] = &bp_fault, 141af11bd88SGleb Natapov [4] = &of_fault, 142af11bd88SGleb Natapov [5] = &br_fault, 143af11bd88SGleb Natapov [6] = &ud_fault, 144af11bd88SGleb Natapov [7] = &nm_fault, 145af11bd88SGleb Natapov [8] = &df_fault, 146af11bd88SGleb Natapov [10] = &ts_fault, 147af11bd88SGleb Natapov [11] = &np_fault, 148af11bd88SGleb Natapov [12] = &ss_fault, 149af11bd88SGleb Natapov [13] = &gp_fault, 150af11bd88SGleb Natapov [14] = &pf_fault, 151af11bd88SGleb Natapov [16] = &mf_fault, 152af11bd88SGleb Natapov [17] = &ac_fault, 153af11bd88SGleb Natapov [18] = &mc_fault, 154af11bd88SGleb Natapov [19] = &xm_fault, 155af11bd88SGleb Natapov }; 1567d36db35SAvi Kivity 1577d36db35SAvi Kivity void setup_idt(void) 1587d36db35SAvi Kivity { 159af11bd88SGleb Natapov int i; 1604751cffbSAvi Kivity static bool idt_initialized = false; 1614751cffbSAvi Kivity 1624751cffbSAvi Kivity if (idt_initialized) { 1634751cffbSAvi Kivity return; 1644751cffbSAvi Kivity } 1654751cffbSAvi Kivity idt_initialized = true; 166af11bd88SGleb Natapov for (i = 0; i < 32; i++) 167af11bd88SGleb Natapov if (idt_handlers[i]) 168af11bd88SGleb Natapov set_idt_entry(i, idt_handlers[i], 0); 169af11bd88SGleb Natapov handle_exception(0, check_exception_table); 170af11bd88SGleb Natapov handle_exception(6, check_exception_table); 171af11bd88SGleb Natapov handle_exception(13, check_exception_table); 1727d36db35SAvi Kivity } 1737d36db35SAvi Kivity 1747d36db35SAvi Kivity unsigned exception_vector(void) 1757d36db35SAvi Kivity { 1767d36db35SAvi Kivity unsigned short vector; 1777d36db35SAvi Kivity 1787d36db35SAvi Kivity asm("mov %%gs:4, %0" : "=rm"(vector)); 1797d36db35SAvi Kivity return vector; 1807d36db35SAvi Kivity } 1817d36db35SAvi Kivity 1827d36db35SAvi Kivity unsigned exception_error_code(void) 1837d36db35SAvi Kivity { 1847d36db35SAvi Kivity unsigned short error_code; 1857d36db35SAvi Kivity 1867d36db35SAvi Kivity asm("mov %%gs:6, %0" : "=rm"(error_code)); 1877d36db35SAvi Kivity return error_code; 1887d36db35SAvi Kivity } 189d21b4f12SGleb Natapov 190*309ca07bSPaolo Bonzini static char intr_alt_stack[4096]; 191*309ca07bSPaolo Bonzini 192d21b4f12SGleb Natapov #ifndef __x86_64__ 193d21b4f12SGleb Natapov /* 194d21b4f12SGleb Natapov * GDT, with 6 entries: 195d21b4f12SGleb Natapov * 0x00 - NULL descriptor 19669d8fe0eSPaolo Bonzini * 0x08 - Code segment (ring 0) 19769d8fe0eSPaolo Bonzini * 0x10 - Data segment (ring 0) 19869d8fe0eSPaolo Bonzini * 0x18 - Not present code segment (ring 0) 19969d8fe0eSPaolo Bonzini * 0x20 - Code segment (ring 3) 20069d8fe0eSPaolo Bonzini * 0x28 - Data segment (ring 3) 20169d8fe0eSPaolo Bonzini * 0x30 - Interrupt task 20269d8fe0eSPaolo Bonzini * 0x38 to 0x78 - Free to use for test cases 2038f4755faSPaolo Bonzini * 0x80 - Primary task (CPU 0) 204d21b4f12SGleb Natapov */ 205d21b4f12SGleb Natapov 20667961d18SPaolo Bonzini void set_gdt_entry(int sel, u32 base, u32 limit, u8 access, u8 gran) 207d21b4f12SGleb Natapov { 20867961d18SPaolo Bonzini int num = sel >> 3; 20967961d18SPaolo Bonzini 210d21b4f12SGleb Natapov /* Setup the descriptor base address */ 2118f4755faSPaolo Bonzini gdt32[num].base_low = (base & 0xFFFF); 2128f4755faSPaolo Bonzini gdt32[num].base_middle = (base >> 16) & 0xFF; 2138f4755faSPaolo Bonzini gdt32[num].base_high = (base >> 24) & 0xFF; 214d21b4f12SGleb Natapov 215d21b4f12SGleb Natapov /* Setup the descriptor limits */ 2168f4755faSPaolo Bonzini gdt32[num].limit_low = (limit & 0xFFFF); 2178f4755faSPaolo Bonzini gdt32[num].granularity = ((limit >> 16) & 0x0F); 218d21b4f12SGleb Natapov 219d21b4f12SGleb Natapov /* Finally, set up the granularity and access flags */ 2208f4755faSPaolo Bonzini gdt32[num].granularity |= (gran & 0xF0); 2218f4755faSPaolo Bonzini gdt32[num].access = access; 222d21b4f12SGleb Natapov } 223d21b4f12SGleb Natapov 2245b0bf08bSPaolo Bonzini void set_gdt_task_gate(u16 sel, u16 tss_sel) 2255b0bf08bSPaolo Bonzini { 2265b0bf08bSPaolo Bonzini set_gdt_entry(sel, tss_sel, 0, 0x85, 0); // task, present 2275b0bf08bSPaolo Bonzini } 2285b0bf08bSPaolo Bonzini 229b01c8823SKevin Wolf void set_idt_task_gate(int vec, u16 sel) 230d21b4f12SGleb Natapov { 231b319491dSAvi Kivity idt_entry_t *e = &boot_idt[vec]; 232d21b4f12SGleb Natapov 233d21b4f12SGleb Natapov memset(e, 0, sizeof *e); 234d21b4f12SGleb Natapov 235d21b4f12SGleb Natapov e->selector = sel; 236d21b4f12SGleb Natapov e->ist = 0; 237d21b4f12SGleb Natapov e->type = 5; 238d21b4f12SGleb Natapov e->dpl = 0; 239d21b4f12SGleb Natapov e->p = 1; 240d21b4f12SGleb Natapov } 241d21b4f12SGleb Natapov 242d21b4f12SGleb Natapov /* 243d21b4f12SGleb Natapov * 0 - main task 244d21b4f12SGleb Natapov * 1 - interrupt task 245d21b4f12SGleb Natapov */ 246d21b4f12SGleb Natapov 2475b0bf08bSPaolo Bonzini tss32_t tss_intr; 248d21b4f12SGleb Natapov 249d21b4f12SGleb Natapov void setup_tss32(void) 250d21b4f12SGleb Natapov { 251d21b4f12SGleb Natapov u16 desc_size = sizeof(tss32_t); 252d21b4f12SGleb Natapov 2538f4755faSPaolo Bonzini tss.cr3 = read_cr3(); 2548f4755faSPaolo Bonzini tss_intr.cr3 = read_cr3(); 2558f4755faSPaolo Bonzini tss_intr.ss0 = tss_intr.ss1 = tss_intr.ss2 = 0x10; 2568f4755faSPaolo Bonzini tss_intr.esp = tss_intr.esp0 = tss_intr.esp1 = tss_intr.esp2 = 257*309ca07bSPaolo Bonzini (u32)intr_alt_stack + 4096; 2588f4755faSPaolo Bonzini tss_intr.cs = 0x08; 2598f4755faSPaolo Bonzini tss_intr.ds = tss_intr.es = tss_intr.fs = tss_intr.gs = tss_intr.ss = 0x10; 2608f4755faSPaolo Bonzini tss_intr.iomap_base = (u16)desc_size; 2618f4755faSPaolo Bonzini set_gdt_entry(TSS_INTR, (u32)&tss_intr, desc_size - 1, 0x89, 0x0f); 262d21b4f12SGleb Natapov } 263d21b4f12SGleb Natapov 264d21b4f12SGleb Natapov void set_intr_task_gate(int e, void *fn) 265d21b4f12SGleb Natapov { 2668f4755faSPaolo Bonzini tss_intr.eip = (u32)fn; 267d21b4f12SGleb Natapov set_idt_task_gate(e, TSS_INTR); 268d21b4f12SGleb Natapov } 269d21b4f12SGleb Natapov 270*309ca07bSPaolo Bonzini void setup_alt_stack(void) 271*309ca07bSPaolo Bonzini { 272*309ca07bSPaolo Bonzini setup_tss32(); 273*309ca07bSPaolo Bonzini } 274*309ca07bSPaolo Bonzini 275*309ca07bSPaolo Bonzini void set_intr_alt_stack(int e, void *fn) 276*309ca07bSPaolo Bonzini { 277*309ca07bSPaolo Bonzini set_intr_task_gate(e, fn); 278*309ca07bSPaolo Bonzini } 279*309ca07bSPaolo Bonzini 280d21b4f12SGleb Natapov void print_current_tss_info(void) 281d21b4f12SGleb Natapov { 282d21b4f12SGleb Natapov u16 tr = str(); 283d21b4f12SGleb Natapov 284d21b4f12SGleb Natapov if (tr != TSS_MAIN && tr != TSS_INTR) 285d21b4f12SGleb Natapov printf("Unknown TSS %x\n", tr); 286d21b4f12SGleb Natapov else 2878f4755faSPaolo Bonzini printf("TR=%x (%s) Main TSS back link %x. Intr TSS back link %x\n", 2888f4755faSPaolo Bonzini tr, tr ? "interrupt" : "main", tss.prev, tss_intr.prev); 289d21b4f12SGleb Natapov } 290*309ca07bSPaolo Bonzini #else 291*309ca07bSPaolo Bonzini void set_intr_alt_stack(int e, void *addr) 292*309ca07bSPaolo Bonzini { 293*309ca07bSPaolo Bonzini set_idt_entry(e, addr, 0); 294*309ca07bSPaolo Bonzini boot_idt[e].ist = 1; 295*309ca07bSPaolo Bonzini } 296*309ca07bSPaolo Bonzini 297*309ca07bSPaolo Bonzini void setup_alt_stack(void) 298*309ca07bSPaolo Bonzini { 299*309ca07bSPaolo Bonzini tss.ist1 = (u64)intr_alt_stack + 4096; 300*309ca07bSPaolo Bonzini } 301d21b4f12SGleb Natapov #endif 302e3f363c4SJan Kiszka 303e3f363c4SJan Kiszka static bool exception; 304e3f363c4SJan Kiszka static void *exception_return; 305e3f363c4SJan Kiszka 306e3f363c4SJan Kiszka static void exception_handler(struct ex_regs *regs) 307e3f363c4SJan Kiszka { 308e3f363c4SJan Kiszka exception = true; 309e3f363c4SJan Kiszka regs->rip = (unsigned long)exception_return; 310e3f363c4SJan Kiszka } 311e3f363c4SJan Kiszka 312e3f363c4SJan Kiszka bool test_for_exception(unsigned int ex, void (*trigger_func)(void *data), 313e3f363c4SJan Kiszka void *data) 314e3f363c4SJan Kiszka { 315e3f363c4SJan Kiszka handle_exception(ex, exception_handler); 316e3f363c4SJan Kiszka exception = false; 317e3f363c4SJan Kiszka trigger_func(data); 318e3f363c4SJan Kiszka handle_exception(ex, NULL); 319e3f363c4SJan Kiszka return exception; 320e3f363c4SJan Kiszka } 321e3f363c4SJan Kiszka 322e3f363c4SJan Kiszka void set_exception_return(void *addr) 323e3f363c4SJan Kiszka { 324e3f363c4SJan Kiszka exception_return = addr; 325e3f363c4SJan Kiszka } 326