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 3973f9822eSNadav Amit ex_val = regs->vector | (regs->error_code << 16) | 4073f9822eSNadav Amit (((regs->rflags >> 16) & 1) << 8); 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 } 49*74d51c58SLevente Kurusa printf("unhandled exception %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 } 71*74d51c58SLevente Kurusa printf("unhandled cpu exception %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 { 17673f9822eSNadav Amit unsigned char vector; 1777d36db35SAvi Kivity 17873f9822eSNadav Amit asm("movb %%gs:4, %0" : "=q"(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 19073f9822eSNadav Amit bool exception_rflags_rf(void) 19173f9822eSNadav Amit { 19273f9822eSNadav Amit unsigned char rf_flag; 19373f9822eSNadav Amit 19473f9822eSNadav Amit asm("movb %%gs:5, %b0" : "=q"(rf_flag)); 19573f9822eSNadav Amit return rf_flag & 1; 19673f9822eSNadav Amit } 19773f9822eSNadav Amit 198309ca07bSPaolo Bonzini static char intr_alt_stack[4096]; 199309ca07bSPaolo Bonzini 200d21b4f12SGleb Natapov #ifndef __x86_64__ 201d21b4f12SGleb Natapov /* 202d21b4f12SGleb Natapov * GDT, with 6 entries: 203d21b4f12SGleb Natapov * 0x00 - NULL descriptor 20469d8fe0eSPaolo Bonzini * 0x08 - Code segment (ring 0) 20569d8fe0eSPaolo Bonzini * 0x10 - Data segment (ring 0) 20669d8fe0eSPaolo Bonzini * 0x18 - Not present code segment (ring 0) 20769d8fe0eSPaolo Bonzini * 0x20 - Code segment (ring 3) 20869d8fe0eSPaolo Bonzini * 0x28 - Data segment (ring 3) 20969d8fe0eSPaolo Bonzini * 0x30 - Interrupt task 21069d8fe0eSPaolo Bonzini * 0x38 to 0x78 - Free to use for test cases 2118f4755faSPaolo Bonzini * 0x80 - Primary task (CPU 0) 212d21b4f12SGleb Natapov */ 213d21b4f12SGleb Natapov 21467961d18SPaolo Bonzini void set_gdt_entry(int sel, u32 base, u32 limit, u8 access, u8 gran) 215d21b4f12SGleb Natapov { 21667961d18SPaolo Bonzini int num = sel >> 3; 21767961d18SPaolo Bonzini 218d21b4f12SGleb Natapov /* Setup the descriptor base address */ 2198f4755faSPaolo Bonzini gdt32[num].base_low = (base & 0xFFFF); 2208f4755faSPaolo Bonzini gdt32[num].base_middle = (base >> 16) & 0xFF; 2218f4755faSPaolo Bonzini gdt32[num].base_high = (base >> 24) & 0xFF; 222d21b4f12SGleb Natapov 223d21b4f12SGleb Natapov /* Setup the descriptor limits */ 2248f4755faSPaolo Bonzini gdt32[num].limit_low = (limit & 0xFFFF); 2258f4755faSPaolo Bonzini gdt32[num].granularity = ((limit >> 16) & 0x0F); 226d21b4f12SGleb Natapov 227d21b4f12SGleb Natapov /* Finally, set up the granularity and access flags */ 2288f4755faSPaolo Bonzini gdt32[num].granularity |= (gran & 0xF0); 2298f4755faSPaolo Bonzini gdt32[num].access = access; 230d21b4f12SGleb Natapov } 231d21b4f12SGleb Natapov 2325b0bf08bSPaolo Bonzini void set_gdt_task_gate(u16 sel, u16 tss_sel) 2335b0bf08bSPaolo Bonzini { 2345b0bf08bSPaolo Bonzini set_gdt_entry(sel, tss_sel, 0, 0x85, 0); // task, present 2355b0bf08bSPaolo Bonzini } 2365b0bf08bSPaolo Bonzini 237b01c8823SKevin Wolf void set_idt_task_gate(int vec, u16 sel) 238d21b4f12SGleb Natapov { 239b319491dSAvi Kivity idt_entry_t *e = &boot_idt[vec]; 240d21b4f12SGleb Natapov 241d21b4f12SGleb Natapov memset(e, 0, sizeof *e); 242d21b4f12SGleb Natapov 243d21b4f12SGleb Natapov e->selector = sel; 244d21b4f12SGleb Natapov e->ist = 0; 245d21b4f12SGleb Natapov e->type = 5; 246d21b4f12SGleb Natapov e->dpl = 0; 247d21b4f12SGleb Natapov e->p = 1; 248d21b4f12SGleb Natapov } 249d21b4f12SGleb Natapov 250d21b4f12SGleb Natapov /* 251d21b4f12SGleb Natapov * 0 - main task 252d21b4f12SGleb Natapov * 1 - interrupt task 253d21b4f12SGleb Natapov */ 254d21b4f12SGleb Natapov 2555b0bf08bSPaolo Bonzini tss32_t tss_intr; 256d21b4f12SGleb Natapov 257d21b4f12SGleb Natapov void setup_tss32(void) 258d21b4f12SGleb Natapov { 259d21b4f12SGleb Natapov u16 desc_size = sizeof(tss32_t); 260d21b4f12SGleb Natapov 2618f4755faSPaolo Bonzini tss.cr3 = read_cr3(); 2628f4755faSPaolo Bonzini tss_intr.cr3 = read_cr3(); 2638f4755faSPaolo Bonzini tss_intr.ss0 = tss_intr.ss1 = tss_intr.ss2 = 0x10; 2648f4755faSPaolo Bonzini tss_intr.esp = tss_intr.esp0 = tss_intr.esp1 = tss_intr.esp2 = 265309ca07bSPaolo Bonzini (u32)intr_alt_stack + 4096; 2668f4755faSPaolo Bonzini tss_intr.cs = 0x08; 2678f4755faSPaolo Bonzini tss_intr.ds = tss_intr.es = tss_intr.fs = tss_intr.gs = tss_intr.ss = 0x10; 2688f4755faSPaolo Bonzini tss_intr.iomap_base = (u16)desc_size; 2698f4755faSPaolo Bonzini set_gdt_entry(TSS_INTR, (u32)&tss_intr, desc_size - 1, 0x89, 0x0f); 270d21b4f12SGleb Natapov } 271d21b4f12SGleb Natapov 272d21b4f12SGleb Natapov void set_intr_task_gate(int e, void *fn) 273d21b4f12SGleb Natapov { 2748f4755faSPaolo Bonzini tss_intr.eip = (u32)fn; 275d21b4f12SGleb Natapov set_idt_task_gate(e, TSS_INTR); 276d21b4f12SGleb Natapov } 277d21b4f12SGleb Natapov 278309ca07bSPaolo Bonzini void setup_alt_stack(void) 279309ca07bSPaolo Bonzini { 280309ca07bSPaolo Bonzini setup_tss32(); 281309ca07bSPaolo Bonzini } 282309ca07bSPaolo Bonzini 283309ca07bSPaolo Bonzini void set_intr_alt_stack(int e, void *fn) 284309ca07bSPaolo Bonzini { 285309ca07bSPaolo Bonzini set_intr_task_gate(e, fn); 286309ca07bSPaolo Bonzini } 287309ca07bSPaolo Bonzini 288d21b4f12SGleb Natapov void print_current_tss_info(void) 289d21b4f12SGleb Natapov { 290d21b4f12SGleb Natapov u16 tr = str(); 291d21b4f12SGleb Natapov 292d21b4f12SGleb Natapov if (tr != TSS_MAIN && tr != TSS_INTR) 293d21b4f12SGleb Natapov printf("Unknown TSS %x\n", tr); 294d21b4f12SGleb Natapov else 2958f4755faSPaolo Bonzini printf("TR=%x (%s) Main TSS back link %x. Intr TSS back link %x\n", 2968f4755faSPaolo Bonzini tr, tr ? "interrupt" : "main", tss.prev, tss_intr.prev); 297d21b4f12SGleb Natapov } 298309ca07bSPaolo Bonzini #else 299309ca07bSPaolo Bonzini void set_intr_alt_stack(int e, void *addr) 300309ca07bSPaolo Bonzini { 301309ca07bSPaolo Bonzini set_idt_entry(e, addr, 0); 302309ca07bSPaolo Bonzini boot_idt[e].ist = 1; 303309ca07bSPaolo Bonzini } 304309ca07bSPaolo Bonzini 305309ca07bSPaolo Bonzini void setup_alt_stack(void) 306309ca07bSPaolo Bonzini { 307309ca07bSPaolo Bonzini tss.ist1 = (u64)intr_alt_stack + 4096; 308309ca07bSPaolo Bonzini } 309d21b4f12SGleb Natapov #endif 310e3f363c4SJan Kiszka 311e3f363c4SJan Kiszka static bool exception; 312e3f363c4SJan Kiszka static void *exception_return; 313e3f363c4SJan Kiszka 314e3f363c4SJan Kiszka static void exception_handler(struct ex_regs *regs) 315e3f363c4SJan Kiszka { 316e3f363c4SJan Kiszka exception = true; 317e3f363c4SJan Kiszka regs->rip = (unsigned long)exception_return; 318e3f363c4SJan Kiszka } 319e3f363c4SJan Kiszka 320e3f363c4SJan Kiszka bool test_for_exception(unsigned int ex, void (*trigger_func)(void *data), 321e3f363c4SJan Kiszka void *data) 322e3f363c4SJan Kiszka { 323e3f363c4SJan Kiszka handle_exception(ex, exception_handler); 324e3f363c4SJan Kiszka exception = false; 325e3f363c4SJan Kiszka trigger_func(data); 326e3f363c4SJan Kiszka handle_exception(ex, NULL); 327e3f363c4SJan Kiszka return exception; 328e3f363c4SJan Kiszka } 329e3f363c4SJan Kiszka 330e3f363c4SJan Kiszka void set_exception_return(void *addr) 331e3f363c4SJan Kiszka { 332e3f363c4SJan Kiszka exception_return = addr; 333e3f363c4SJan Kiszka } 334