17d36db35SAvi Kivity #include "libcflat.h" 2e7c37968SGleb Natapov #include "desc.h" 323ba7b39SGleb Natapov #include "processor.h" 4*03f37ef2SPaolo Bonzini #include <setjmp.h> 57d36db35SAvi Kivity 623ba7b39SGleb Natapov void set_idt_entry(int vec, void *addr, int dpl) 77d36db35SAvi Kivity { 81d946e07SAvi Kivity idt_entry_t *e = &boot_idt[vec]; 97d36db35SAvi Kivity memset(e, 0, sizeof *e); 107d36db35SAvi Kivity e->offset0 = (unsigned long)addr; 117d36db35SAvi Kivity e->selector = read_cs(); 127d36db35SAvi Kivity e->ist = 0; 137d36db35SAvi Kivity e->type = 14; 147d36db35SAvi Kivity e->dpl = dpl; 157d36db35SAvi Kivity e->p = 1; 167d36db35SAvi Kivity e->offset1 = (unsigned long)addr >> 16; 1723ba7b39SGleb Natapov #ifdef __x86_64__ 187d36db35SAvi Kivity e->offset2 = (unsigned long)addr >> 32; 1923ba7b39SGleb Natapov #endif 207d36db35SAvi Kivity } 217d36db35SAvi Kivity 227488d290SPaolo Bonzini void set_idt_dpl(int vec, u16 dpl) 237488d290SPaolo Bonzini { 247488d290SPaolo Bonzini idt_entry_t *e = &boot_idt[vec]; 257488d290SPaolo Bonzini e->dpl = dpl; 267488d290SPaolo Bonzini } 277488d290SPaolo Bonzini 28a4b87a16SGleb Natapov void set_idt_sel(int vec, u16 sel) 29a4b87a16SGleb Natapov { 301d946e07SAvi Kivity idt_entry_t *e = &boot_idt[vec]; 31a4b87a16SGleb Natapov e->selector = sel; 32a4b87a16SGleb Natapov } 337d36db35SAvi Kivity 347d36db35SAvi Kivity struct ex_record { 357d36db35SAvi Kivity unsigned long rip; 367d36db35SAvi Kivity unsigned long handler; 377d36db35SAvi Kivity }; 387d36db35SAvi Kivity 397d36db35SAvi Kivity extern struct ex_record exception_table_start, exception_table_end; 407d36db35SAvi Kivity 41af11bd88SGleb Natapov static void check_exception_table(struct ex_regs *regs) 427d36db35SAvi Kivity { 437d36db35SAvi Kivity struct ex_record *ex; 447d36db35SAvi Kivity unsigned ex_val; 457d36db35SAvi Kivity 4673f9822eSNadav Amit ex_val = regs->vector | (regs->error_code << 16) | 4773f9822eSNadav Amit (((regs->rflags >> 16) & 1) << 8); 487d36db35SAvi Kivity asm("mov %0, %%gs:4" : : "r"(ex_val)); 497d36db35SAvi Kivity 507d36db35SAvi Kivity for (ex = &exception_table_start; ex != &exception_table_end; ++ex) { 517d36db35SAvi Kivity if (ex->rip == regs->rip) { 527d36db35SAvi Kivity regs->rip = ex->handler; 537d36db35SAvi Kivity return; 547d36db35SAvi Kivity } 557d36db35SAvi Kivity } 5674d51c58SLevente Kurusa printf("unhandled exception %d\n", regs->vector); 57af11bd88SGleb Natapov exit(7); 58af11bd88SGleb Natapov } 59af11bd88SGleb Natapov 60af11bd88SGleb Natapov static void (*exception_handlers[32])(struct ex_regs *regs); 61af11bd88SGleb Natapov 62af11bd88SGleb Natapov 63af11bd88SGleb Natapov void handle_exception(u8 v, void (*func)(struct ex_regs *regs)) 64af11bd88SGleb Natapov { 65af11bd88SGleb Natapov if (v < 32) 66af11bd88SGleb Natapov exception_handlers[v] = func; 67af11bd88SGleb Natapov } 68af11bd88SGleb Natapov 69af11bd88SGleb Natapov #ifndef __x86_64__ 70af11bd88SGleb Natapov __attribute__((regparm(1))) 71af11bd88SGleb Natapov #endif 72af11bd88SGleb Natapov void do_handle_exception(struct ex_regs *regs) 73af11bd88SGleb Natapov { 74af11bd88SGleb Natapov if (regs->vector < 32 && exception_handlers[regs->vector]) { 75af11bd88SGleb Natapov exception_handlers[regs->vector](regs); 76af11bd88SGleb Natapov return; 77af11bd88SGleb Natapov } 7874d51c58SLevente Kurusa printf("unhandled cpu exception %d\n", regs->vector); 79af11bd88SGleb Natapov if (regs->vector == 14) 80af11bd88SGleb Natapov printf("PF at %p addr %p\n", regs->rip, read_cr2()); 817d36db35SAvi Kivity exit(7); 827d36db35SAvi Kivity } 837d36db35SAvi Kivity 84af11bd88SGleb Natapov #define EX(NAME, N) extern char NAME##_fault; \ 85af11bd88SGleb Natapov asm (".pushsection .text \n\t" \ 86af11bd88SGleb Natapov #NAME"_fault: \n\t" \ 87af11bd88SGleb Natapov "push"W" $0 \n\t" \ 88af11bd88SGleb Natapov "push"W" $"#N" \n\t" \ 89af11bd88SGleb Natapov "jmp __handle_exception \n\t" \ 90af11bd88SGleb Natapov ".popsection") 91af11bd88SGleb Natapov 92af11bd88SGleb Natapov #define EX_E(NAME, N) extern char NAME##_fault; \ 93af11bd88SGleb Natapov asm (".pushsection .text \n\t" \ 94af11bd88SGleb Natapov #NAME"_fault: \n\t" \ 95af11bd88SGleb Natapov "push"W" $"#N" \n\t" \ 96af11bd88SGleb Natapov "jmp __handle_exception \n\t" \ 97af11bd88SGleb Natapov ".popsection") 98af11bd88SGleb Natapov 99af11bd88SGleb Natapov EX(de, 0); 100af11bd88SGleb Natapov EX(db, 1); 101af11bd88SGleb Natapov EX(nmi, 2); 102af11bd88SGleb Natapov EX(bp, 3); 103af11bd88SGleb Natapov EX(of, 4); 104af11bd88SGleb Natapov EX(br, 5); 105af11bd88SGleb Natapov EX(ud, 6); 106af11bd88SGleb Natapov EX(nm, 7); 107af11bd88SGleb Natapov EX_E(df, 8); 108af11bd88SGleb Natapov EX_E(ts, 10); 109af11bd88SGleb Natapov EX_E(np, 11); 110af11bd88SGleb Natapov EX_E(ss, 12); 111af11bd88SGleb Natapov EX_E(gp, 13); 112af11bd88SGleb Natapov EX_E(pf, 14); 113af11bd88SGleb Natapov EX(mf, 16); 114af11bd88SGleb Natapov EX_E(ac, 17); 115af11bd88SGleb Natapov EX(mc, 18); 116af11bd88SGleb Natapov EX(xm, 19); 117af11bd88SGleb Natapov 1187d36db35SAvi Kivity asm (".pushsection .text \n\t" 119af11bd88SGleb Natapov "__handle_exception: \n\t" 12023ba7b39SGleb Natapov #ifdef __x86_64__ 1217d36db35SAvi Kivity "push %r15; push %r14; push %r13; push %r12 \n\t" 1227d36db35SAvi Kivity "push %r11; push %r10; push %r9; push %r8 \n\t" 12323ba7b39SGleb Natapov #endif 12423ba7b39SGleb Natapov "push %"R "di; push %"R "si; push %"R "bp; sub $"S", %"R "sp \n\t" 12523ba7b39SGleb Natapov "push %"R "bx; push %"R "dx; push %"R "cx; push %"R "ax \n\t" 126c3b91807SGleb Natapov #ifdef __x86_64__ 12723ba7b39SGleb Natapov "mov %"R "sp, %"R "di \n\t" 128c3b91807SGleb Natapov #else 129c3b91807SGleb Natapov "mov %"R "sp, %"R "ax \n\t" 130c3b91807SGleb Natapov #endif 1317d36db35SAvi Kivity "call do_handle_exception \n\t" 13223ba7b39SGleb Natapov "pop %"R "ax; pop %"R "cx; pop %"R "dx; pop %"R "bx \n\t" 13323ba7b39SGleb Natapov "add $"S", %"R "sp; pop %"R "bp; pop %"R "si; pop %"R "di \n\t" 13423ba7b39SGleb Natapov #ifdef __x86_64__ 1357d36db35SAvi Kivity "pop %r8; pop %r9; pop %r10; pop %r11 \n\t" 1367d36db35SAvi Kivity "pop %r12; pop %r13; pop %r14; pop %r15 \n\t" 13723ba7b39SGleb Natapov #endif 13823ba7b39SGleb Natapov "add $"S", %"R "sp \n\t" 13923ba7b39SGleb Natapov "add $"S", %"R "sp \n\t" 14023ba7b39SGleb Natapov "iret"W" \n\t" 1417d36db35SAvi Kivity ".popsection"); 1427d36db35SAvi Kivity 143af11bd88SGleb Natapov static void *idt_handlers[32] = { 144af11bd88SGleb Natapov [0] = &de_fault, 145af11bd88SGleb Natapov [1] = &db_fault, 146af11bd88SGleb Natapov [2] = &nmi_fault, 147af11bd88SGleb Natapov [3] = &bp_fault, 148af11bd88SGleb Natapov [4] = &of_fault, 149af11bd88SGleb Natapov [5] = &br_fault, 150af11bd88SGleb Natapov [6] = &ud_fault, 151af11bd88SGleb Natapov [7] = &nm_fault, 152af11bd88SGleb Natapov [8] = &df_fault, 153af11bd88SGleb Natapov [10] = &ts_fault, 154af11bd88SGleb Natapov [11] = &np_fault, 155af11bd88SGleb Natapov [12] = &ss_fault, 156af11bd88SGleb Natapov [13] = &gp_fault, 157af11bd88SGleb Natapov [14] = &pf_fault, 158af11bd88SGleb Natapov [16] = &mf_fault, 159af11bd88SGleb Natapov [17] = &ac_fault, 160af11bd88SGleb Natapov [18] = &mc_fault, 161af11bd88SGleb Natapov [19] = &xm_fault, 162af11bd88SGleb Natapov }; 1637d36db35SAvi Kivity 1647d36db35SAvi Kivity void setup_idt(void) 1657d36db35SAvi Kivity { 166af11bd88SGleb Natapov int i; 1674751cffbSAvi Kivity static bool idt_initialized = false; 1684751cffbSAvi Kivity 1694751cffbSAvi Kivity if (idt_initialized) { 1704751cffbSAvi Kivity return; 1714751cffbSAvi Kivity } 1724751cffbSAvi Kivity idt_initialized = true; 173af11bd88SGleb Natapov for (i = 0; i < 32; i++) 174af11bd88SGleb Natapov if (idt_handlers[i]) 175af11bd88SGleb Natapov set_idt_entry(i, idt_handlers[i], 0); 176af11bd88SGleb Natapov handle_exception(0, check_exception_table); 177af11bd88SGleb Natapov handle_exception(6, check_exception_table); 178af11bd88SGleb Natapov handle_exception(13, check_exception_table); 1797d36db35SAvi Kivity } 1807d36db35SAvi Kivity 1817d36db35SAvi Kivity unsigned exception_vector(void) 1827d36db35SAvi Kivity { 18373f9822eSNadav Amit unsigned char vector; 1847d36db35SAvi Kivity 18573f9822eSNadav Amit asm("movb %%gs:4, %0" : "=q"(vector)); 1867d36db35SAvi Kivity return vector; 1877d36db35SAvi Kivity } 1887d36db35SAvi Kivity 1897d36db35SAvi Kivity unsigned exception_error_code(void) 1907d36db35SAvi Kivity { 1917d36db35SAvi Kivity unsigned short error_code; 1927d36db35SAvi Kivity 1937d36db35SAvi Kivity asm("mov %%gs:6, %0" : "=rm"(error_code)); 1947d36db35SAvi Kivity return error_code; 1957d36db35SAvi Kivity } 196d21b4f12SGleb Natapov 19773f9822eSNadav Amit bool exception_rflags_rf(void) 19873f9822eSNadav Amit { 19973f9822eSNadav Amit unsigned char rf_flag; 20073f9822eSNadav Amit 20173f9822eSNadav Amit asm("movb %%gs:5, %b0" : "=q"(rf_flag)); 20273f9822eSNadav Amit return rf_flag & 1; 20373f9822eSNadav Amit } 20473f9822eSNadav Amit 205309ca07bSPaolo Bonzini static char intr_alt_stack[4096]; 206309ca07bSPaolo Bonzini 207d21b4f12SGleb Natapov #ifndef __x86_64__ 208d21b4f12SGleb Natapov /* 209d21b4f12SGleb Natapov * GDT, with 6 entries: 210d21b4f12SGleb Natapov * 0x00 - NULL descriptor 21169d8fe0eSPaolo Bonzini * 0x08 - Code segment (ring 0) 21269d8fe0eSPaolo Bonzini * 0x10 - Data segment (ring 0) 21369d8fe0eSPaolo Bonzini * 0x18 - Not present code segment (ring 0) 21469d8fe0eSPaolo Bonzini * 0x20 - Code segment (ring 3) 21569d8fe0eSPaolo Bonzini * 0x28 - Data segment (ring 3) 21669d8fe0eSPaolo Bonzini * 0x30 - Interrupt task 21769d8fe0eSPaolo Bonzini * 0x38 to 0x78 - Free to use for test cases 2188f4755faSPaolo Bonzini * 0x80 - Primary task (CPU 0) 219d21b4f12SGleb Natapov */ 220d21b4f12SGleb Natapov 22167961d18SPaolo Bonzini void set_gdt_entry(int sel, u32 base, u32 limit, u8 access, u8 gran) 222d21b4f12SGleb Natapov { 22367961d18SPaolo Bonzini int num = sel >> 3; 22467961d18SPaolo Bonzini 225d21b4f12SGleb Natapov /* Setup the descriptor base address */ 2268f4755faSPaolo Bonzini gdt32[num].base_low = (base & 0xFFFF); 2278f4755faSPaolo Bonzini gdt32[num].base_middle = (base >> 16) & 0xFF; 2288f4755faSPaolo Bonzini gdt32[num].base_high = (base >> 24) & 0xFF; 229d21b4f12SGleb Natapov 230d21b4f12SGleb Natapov /* Setup the descriptor limits */ 2318f4755faSPaolo Bonzini gdt32[num].limit_low = (limit & 0xFFFF); 2328f4755faSPaolo Bonzini gdt32[num].granularity = ((limit >> 16) & 0x0F); 233d21b4f12SGleb Natapov 234d21b4f12SGleb Natapov /* Finally, set up the granularity and access flags */ 2358f4755faSPaolo Bonzini gdt32[num].granularity |= (gran & 0xF0); 2368f4755faSPaolo Bonzini gdt32[num].access = access; 237d21b4f12SGleb Natapov } 238d21b4f12SGleb Natapov 2395b0bf08bSPaolo Bonzini void set_gdt_task_gate(u16 sel, u16 tss_sel) 2405b0bf08bSPaolo Bonzini { 2415b0bf08bSPaolo Bonzini set_gdt_entry(sel, tss_sel, 0, 0x85, 0); // task, present 2425b0bf08bSPaolo Bonzini } 2435b0bf08bSPaolo Bonzini 244b01c8823SKevin Wolf void set_idt_task_gate(int vec, u16 sel) 245d21b4f12SGleb Natapov { 246b319491dSAvi Kivity idt_entry_t *e = &boot_idt[vec]; 247d21b4f12SGleb Natapov 248d21b4f12SGleb Natapov memset(e, 0, sizeof *e); 249d21b4f12SGleb Natapov 250d21b4f12SGleb Natapov e->selector = sel; 251d21b4f12SGleb Natapov e->ist = 0; 252d21b4f12SGleb Natapov e->type = 5; 253d21b4f12SGleb Natapov e->dpl = 0; 254d21b4f12SGleb Natapov e->p = 1; 255d21b4f12SGleb Natapov } 256d21b4f12SGleb Natapov 257d21b4f12SGleb Natapov /* 258d21b4f12SGleb Natapov * 0 - main task 259d21b4f12SGleb Natapov * 1 - interrupt task 260d21b4f12SGleb Natapov */ 261d21b4f12SGleb Natapov 2625b0bf08bSPaolo Bonzini tss32_t tss_intr; 263d21b4f12SGleb Natapov 264d21b4f12SGleb Natapov void setup_tss32(void) 265d21b4f12SGleb Natapov { 266d21b4f12SGleb Natapov u16 desc_size = sizeof(tss32_t); 267d21b4f12SGleb Natapov 2688f4755faSPaolo Bonzini tss.cr3 = read_cr3(); 2698f4755faSPaolo Bonzini tss_intr.cr3 = read_cr3(); 2708f4755faSPaolo Bonzini tss_intr.ss0 = tss_intr.ss1 = tss_intr.ss2 = 0x10; 2718f4755faSPaolo Bonzini tss_intr.esp = tss_intr.esp0 = tss_intr.esp1 = tss_intr.esp2 = 272309ca07bSPaolo Bonzini (u32)intr_alt_stack + 4096; 2738f4755faSPaolo Bonzini tss_intr.cs = 0x08; 2748f4755faSPaolo Bonzini tss_intr.ds = tss_intr.es = tss_intr.fs = tss_intr.gs = tss_intr.ss = 0x10; 2758f4755faSPaolo Bonzini tss_intr.iomap_base = (u16)desc_size; 2768f4755faSPaolo Bonzini set_gdt_entry(TSS_INTR, (u32)&tss_intr, desc_size - 1, 0x89, 0x0f); 277d21b4f12SGleb Natapov } 278d21b4f12SGleb Natapov 279d21b4f12SGleb Natapov void set_intr_task_gate(int e, void *fn) 280d21b4f12SGleb Natapov { 2818f4755faSPaolo Bonzini tss_intr.eip = (u32)fn; 282d21b4f12SGleb Natapov set_idt_task_gate(e, TSS_INTR); 283d21b4f12SGleb Natapov } 284d21b4f12SGleb Natapov 285309ca07bSPaolo Bonzini void setup_alt_stack(void) 286309ca07bSPaolo Bonzini { 287309ca07bSPaolo Bonzini setup_tss32(); 288309ca07bSPaolo Bonzini } 289309ca07bSPaolo Bonzini 290309ca07bSPaolo Bonzini void set_intr_alt_stack(int e, void *fn) 291309ca07bSPaolo Bonzini { 292309ca07bSPaolo Bonzini set_intr_task_gate(e, fn); 293309ca07bSPaolo Bonzini } 294309ca07bSPaolo Bonzini 295d21b4f12SGleb Natapov void print_current_tss_info(void) 296d21b4f12SGleb Natapov { 297d21b4f12SGleb Natapov u16 tr = str(); 298d21b4f12SGleb Natapov 299d21b4f12SGleb Natapov if (tr != TSS_MAIN && tr != TSS_INTR) 300d21b4f12SGleb Natapov printf("Unknown TSS %x\n", tr); 301d21b4f12SGleb Natapov else 3028f4755faSPaolo Bonzini printf("TR=%x (%s) Main TSS back link %x. Intr TSS back link %x\n", 3038f4755faSPaolo Bonzini tr, tr ? "interrupt" : "main", tss.prev, tss_intr.prev); 304d21b4f12SGleb Natapov } 305309ca07bSPaolo Bonzini #else 306309ca07bSPaolo Bonzini void set_intr_alt_stack(int e, void *addr) 307309ca07bSPaolo Bonzini { 308309ca07bSPaolo Bonzini set_idt_entry(e, addr, 0); 309309ca07bSPaolo Bonzini boot_idt[e].ist = 1; 310309ca07bSPaolo Bonzini } 311309ca07bSPaolo Bonzini 312309ca07bSPaolo Bonzini void setup_alt_stack(void) 313309ca07bSPaolo Bonzini { 314309ca07bSPaolo Bonzini tss.ist1 = (u64)intr_alt_stack + 4096; 315309ca07bSPaolo Bonzini } 316d21b4f12SGleb Natapov #endif 317e3f363c4SJan Kiszka 318e3f363c4SJan Kiszka static bool exception; 319*03f37ef2SPaolo Bonzini static jmp_buf *exception_jmpbuf; 320*03f37ef2SPaolo Bonzini 321*03f37ef2SPaolo Bonzini static void exception_handler_longjmp(void) 322*03f37ef2SPaolo Bonzini { 323*03f37ef2SPaolo Bonzini longjmp(*exception_jmpbuf, 1); 324*03f37ef2SPaolo Bonzini } 325e3f363c4SJan Kiszka 326e3f363c4SJan Kiszka static void exception_handler(struct ex_regs *regs) 327e3f363c4SJan Kiszka { 328*03f37ef2SPaolo Bonzini /* longjmp must happen after iret, so do not do it now. */ 329e3f363c4SJan Kiszka exception = true; 330*03f37ef2SPaolo Bonzini regs->rip = (unsigned long)&exception_handler_longjmp; 331e3f363c4SJan Kiszka } 332e3f363c4SJan Kiszka 333e3f363c4SJan Kiszka bool test_for_exception(unsigned int ex, void (*trigger_func)(void *data), 334e3f363c4SJan Kiszka void *data) 335e3f363c4SJan Kiszka { 336e3f363c4SJan Kiszka handle_exception(ex, exception_handler); 337e3f363c4SJan Kiszka exception = false; 338e3f363c4SJan Kiszka trigger_func(data); 339e3f363c4SJan Kiszka handle_exception(ex, NULL); 340e3f363c4SJan Kiszka return exception; 341e3f363c4SJan Kiszka } 342e3f363c4SJan Kiszka 343*03f37ef2SPaolo Bonzini void __set_exception_jmpbuf(jmp_buf *addr) 344e3f363c4SJan Kiszka { 345*03f37ef2SPaolo Bonzini exception_jmpbuf = addr; 346e3f363c4SJan Kiszka } 347