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 190d21b4f12SGleb Natapov #ifndef __x86_64__ 191d21b4f12SGleb Natapov /* 192d21b4f12SGleb Natapov * GDT, with 6 entries: 193d21b4f12SGleb Natapov * 0x00 - NULL descriptor 194*69d8fe0eSPaolo Bonzini * 0x08 - Code segment (ring 0) 195*69d8fe0eSPaolo Bonzini * 0x10 - Data segment (ring 0) 196*69d8fe0eSPaolo Bonzini * 0x18 - Not present code segment (ring 0) 197*69d8fe0eSPaolo Bonzini * 0x20 - Code segment (ring 3) 198*69d8fe0eSPaolo Bonzini * 0x28 - Data segment (ring 3) 199*69d8fe0eSPaolo Bonzini * 0x30 - Interrupt task 200*69d8fe0eSPaolo Bonzini * 0x38 to 0x78 - Free to use for test cases 2018f4755faSPaolo Bonzini * 0x80 - Primary task (CPU 0) 202d21b4f12SGleb Natapov */ 203d21b4f12SGleb Natapov 20467961d18SPaolo Bonzini void set_gdt_entry(int sel, u32 base, u32 limit, u8 access, u8 gran) 205d21b4f12SGleb Natapov { 20667961d18SPaolo Bonzini int num = sel >> 3; 20767961d18SPaolo Bonzini 208d21b4f12SGleb Natapov /* Setup the descriptor base address */ 2098f4755faSPaolo Bonzini gdt32[num].base_low = (base & 0xFFFF); 2108f4755faSPaolo Bonzini gdt32[num].base_middle = (base >> 16) & 0xFF; 2118f4755faSPaolo Bonzini gdt32[num].base_high = (base >> 24) & 0xFF; 212d21b4f12SGleb Natapov 213d21b4f12SGleb Natapov /* Setup the descriptor limits */ 2148f4755faSPaolo Bonzini gdt32[num].limit_low = (limit & 0xFFFF); 2158f4755faSPaolo Bonzini gdt32[num].granularity = ((limit >> 16) & 0x0F); 216d21b4f12SGleb Natapov 217d21b4f12SGleb Natapov /* Finally, set up the granularity and access flags */ 2188f4755faSPaolo Bonzini gdt32[num].granularity |= (gran & 0xF0); 2198f4755faSPaolo Bonzini gdt32[num].access = access; 220d21b4f12SGleb Natapov } 221d21b4f12SGleb Natapov 2225b0bf08bSPaolo Bonzini void set_gdt_task_gate(u16 sel, u16 tss_sel) 2235b0bf08bSPaolo Bonzini { 2245b0bf08bSPaolo Bonzini set_gdt_entry(sel, tss_sel, 0, 0x85, 0); // task, present 2255b0bf08bSPaolo Bonzini } 2265b0bf08bSPaolo Bonzini 227b01c8823SKevin Wolf void set_idt_task_gate(int vec, u16 sel) 228d21b4f12SGleb Natapov { 229b319491dSAvi Kivity idt_entry_t *e = &boot_idt[vec]; 230d21b4f12SGleb Natapov 231d21b4f12SGleb Natapov memset(e, 0, sizeof *e); 232d21b4f12SGleb Natapov 233d21b4f12SGleb Natapov e->selector = sel; 234d21b4f12SGleb Natapov e->ist = 0; 235d21b4f12SGleb Natapov e->type = 5; 236d21b4f12SGleb Natapov e->dpl = 0; 237d21b4f12SGleb Natapov e->p = 1; 238d21b4f12SGleb Natapov } 239d21b4f12SGleb Natapov 240d21b4f12SGleb Natapov /* 241d21b4f12SGleb Natapov * 0 - main task 242d21b4f12SGleb Natapov * 1 - interrupt task 243d21b4f12SGleb Natapov */ 244d21b4f12SGleb Natapov 2455b0bf08bSPaolo Bonzini tss32_t tss_intr; 2468f4755faSPaolo Bonzini static char tss_stack[4096]; 247d21b4f12SGleb Natapov 248d21b4f12SGleb Natapov void setup_tss32(void) 249d21b4f12SGleb Natapov { 250d21b4f12SGleb Natapov u16 desc_size = sizeof(tss32_t); 251d21b4f12SGleb Natapov 2528f4755faSPaolo Bonzini tss.cr3 = read_cr3(); 2538f4755faSPaolo Bonzini tss_intr.cr3 = read_cr3(); 2548f4755faSPaolo Bonzini tss_intr.ss0 = tss_intr.ss1 = tss_intr.ss2 = 0x10; 2558f4755faSPaolo Bonzini tss_intr.esp = tss_intr.esp0 = tss_intr.esp1 = tss_intr.esp2 = 2568f4755faSPaolo Bonzini (u32)tss_stack + 4096; 2578f4755faSPaolo Bonzini tss_intr.cs = 0x08; 2588f4755faSPaolo Bonzini tss_intr.ds = tss_intr.es = tss_intr.fs = tss_intr.gs = tss_intr.ss = 0x10; 2598f4755faSPaolo Bonzini tss_intr.iomap_base = (u16)desc_size; 2608f4755faSPaolo Bonzini set_gdt_entry(TSS_INTR, (u32)&tss_intr, desc_size - 1, 0x89, 0x0f); 261d21b4f12SGleb Natapov } 262d21b4f12SGleb Natapov 263d21b4f12SGleb Natapov void set_intr_task_gate(int e, void *fn) 264d21b4f12SGleb Natapov { 2658f4755faSPaolo Bonzini tss_intr.eip = (u32)fn; 266d21b4f12SGleb Natapov set_idt_task_gate(e, TSS_INTR); 267d21b4f12SGleb Natapov } 268d21b4f12SGleb Natapov 269d21b4f12SGleb Natapov void print_current_tss_info(void) 270d21b4f12SGleb Natapov { 271d21b4f12SGleb Natapov u16 tr = str(); 272d21b4f12SGleb Natapov 273d21b4f12SGleb Natapov if (tr != TSS_MAIN && tr != TSS_INTR) 274d21b4f12SGleb Natapov printf("Unknown TSS %x\n", tr); 275d21b4f12SGleb Natapov else 2768f4755faSPaolo Bonzini printf("TR=%x (%s) Main TSS back link %x. Intr TSS back link %x\n", 2778f4755faSPaolo Bonzini tr, tr ? "interrupt" : "main", tss.prev, tss_intr.prev); 278d21b4f12SGleb Natapov } 279d21b4f12SGleb Natapov #endif 280e3f363c4SJan Kiszka 281e3f363c4SJan Kiszka static bool exception; 282e3f363c4SJan Kiszka static void *exception_return; 283e3f363c4SJan Kiszka 284e3f363c4SJan Kiszka static void exception_handler(struct ex_regs *regs) 285e3f363c4SJan Kiszka { 286e3f363c4SJan Kiszka exception = true; 287e3f363c4SJan Kiszka regs->rip = (unsigned long)exception_return; 288e3f363c4SJan Kiszka } 289e3f363c4SJan Kiszka 290e3f363c4SJan Kiszka bool test_for_exception(unsigned int ex, void (*trigger_func)(void *data), 291e3f363c4SJan Kiszka void *data) 292e3f363c4SJan Kiszka { 293e3f363c4SJan Kiszka handle_exception(ex, exception_handler); 294e3f363c4SJan Kiszka exception = false; 295e3f363c4SJan Kiszka trigger_func(data); 296e3f363c4SJan Kiszka handle_exception(ex, NULL); 297e3f363c4SJan Kiszka return exception; 298e3f363c4SJan Kiszka } 299e3f363c4SJan Kiszka 300e3f363c4SJan Kiszka void set_exception_return(void *addr) 301e3f363c4SJan Kiszka { 302e3f363c4SJan Kiszka exception_return = addr; 303e3f363c4SJan Kiszka } 304