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 301d946e07SAvi Kivity extern idt_entry_t boot_idt[256]; 317d36db35SAvi Kivity 3223ba7b39SGleb Natapov void set_idt_entry(int vec, void *addr, int dpl) 337d36db35SAvi Kivity { 341d946e07SAvi Kivity idt_entry_t *e = &boot_idt[vec]; 357d36db35SAvi Kivity memset(e, 0, sizeof *e); 367d36db35SAvi Kivity e->offset0 = (unsigned long)addr; 377d36db35SAvi Kivity e->selector = read_cs(); 387d36db35SAvi Kivity e->ist = 0; 397d36db35SAvi Kivity e->type = 14; 407d36db35SAvi Kivity e->dpl = dpl; 417d36db35SAvi Kivity e->p = 1; 427d36db35SAvi Kivity e->offset1 = (unsigned long)addr >> 16; 4323ba7b39SGleb Natapov #ifdef __x86_64__ 447d36db35SAvi Kivity e->offset2 = (unsigned long)addr >> 32; 4523ba7b39SGleb Natapov #endif 467d36db35SAvi Kivity } 477d36db35SAvi Kivity 48a4b87a16SGleb Natapov void set_idt_sel(int vec, u16 sel) 49a4b87a16SGleb Natapov { 501d946e07SAvi Kivity idt_entry_t *e = &boot_idt[vec]; 51a4b87a16SGleb Natapov e->selector = sel; 52a4b87a16SGleb Natapov } 537d36db35SAvi Kivity 547d36db35SAvi Kivity struct ex_record { 557d36db35SAvi Kivity unsigned long rip; 567d36db35SAvi Kivity unsigned long handler; 577d36db35SAvi Kivity }; 587d36db35SAvi Kivity 597d36db35SAvi Kivity extern struct ex_record exception_table_start, exception_table_end; 607d36db35SAvi Kivity 61af11bd88SGleb Natapov static void check_exception_table(struct ex_regs *regs) 627d36db35SAvi Kivity { 637d36db35SAvi Kivity struct ex_record *ex; 647d36db35SAvi Kivity unsigned ex_val; 657d36db35SAvi Kivity 667d36db35SAvi Kivity ex_val = regs->vector | (regs->error_code << 16); 677d36db35SAvi Kivity 687d36db35SAvi Kivity asm("mov %0, %%gs:4" : : "r"(ex_val)); 697d36db35SAvi Kivity 707d36db35SAvi Kivity for (ex = &exception_table_start; ex != &exception_table_end; ++ex) { 717d36db35SAvi Kivity if (ex->rip == regs->rip) { 727d36db35SAvi Kivity regs->rip = ex->handler; 737d36db35SAvi Kivity return; 747d36db35SAvi Kivity } 757d36db35SAvi Kivity } 76af11bd88SGleb Natapov printf("unhandled excecption %d\n", regs->vector); 77af11bd88SGleb Natapov exit(7); 78af11bd88SGleb Natapov } 79af11bd88SGleb Natapov 80af11bd88SGleb Natapov static void (*exception_handlers[32])(struct ex_regs *regs); 81af11bd88SGleb Natapov 82af11bd88SGleb Natapov 83af11bd88SGleb Natapov void handle_exception(u8 v, void (*func)(struct ex_regs *regs)) 84af11bd88SGleb Natapov { 85af11bd88SGleb Natapov if (v < 32) 86af11bd88SGleb Natapov exception_handlers[v] = func; 87af11bd88SGleb Natapov } 88af11bd88SGleb Natapov 89af11bd88SGleb Natapov #ifndef __x86_64__ 90af11bd88SGleb Natapov __attribute__((regparm(1))) 91af11bd88SGleb Natapov #endif 92af11bd88SGleb Natapov void do_handle_exception(struct ex_regs *regs) 93af11bd88SGleb Natapov { 94af11bd88SGleb Natapov if (regs->vector < 32 && exception_handlers[regs->vector]) { 95af11bd88SGleb Natapov exception_handlers[regs->vector](regs); 96af11bd88SGleb Natapov return; 97af11bd88SGleb Natapov } 98af11bd88SGleb Natapov printf("unhandled cpu excecption %d\n", regs->vector); 99af11bd88SGleb Natapov if (regs->vector == 14) 100af11bd88SGleb Natapov printf("PF at %p addr %p\n", regs->rip, read_cr2()); 1017d36db35SAvi Kivity exit(7); 1027d36db35SAvi Kivity } 1037d36db35SAvi Kivity 10423ba7b39SGleb Natapov #ifdef __x86_64__ 10523ba7b39SGleb Natapov # define R "r" 10623ba7b39SGleb Natapov # define W "q" 10723ba7b39SGleb Natapov # define S "8" 10823ba7b39SGleb Natapov #else 10923ba7b39SGleb Natapov # define R "e" 11023ba7b39SGleb Natapov # define W "l" 11123ba7b39SGleb Natapov # define S "4" 11223ba7b39SGleb Natapov #endif 11323ba7b39SGleb Natapov 114af11bd88SGleb Natapov #define EX(NAME, N) extern char NAME##_fault; \ 115af11bd88SGleb Natapov asm (".pushsection .text \n\t" \ 116af11bd88SGleb Natapov #NAME"_fault: \n\t" \ 117af11bd88SGleb Natapov "push"W" $0 \n\t" \ 118af11bd88SGleb Natapov "push"W" $"#N" \n\t" \ 119af11bd88SGleb Natapov "jmp __handle_exception \n\t" \ 120af11bd88SGleb Natapov ".popsection") 121af11bd88SGleb Natapov 122af11bd88SGleb Natapov #define EX_E(NAME, N) extern char NAME##_fault; \ 123af11bd88SGleb Natapov asm (".pushsection .text \n\t" \ 124af11bd88SGleb Natapov #NAME"_fault: \n\t" \ 125af11bd88SGleb Natapov "push"W" $"#N" \n\t" \ 126af11bd88SGleb Natapov "jmp __handle_exception \n\t" \ 127af11bd88SGleb Natapov ".popsection") 128af11bd88SGleb Natapov 129af11bd88SGleb Natapov EX(de, 0); 130af11bd88SGleb Natapov EX(db, 1); 131af11bd88SGleb Natapov EX(nmi, 2); 132af11bd88SGleb Natapov EX(bp, 3); 133af11bd88SGleb Natapov EX(of, 4); 134af11bd88SGleb Natapov EX(br, 5); 135af11bd88SGleb Natapov EX(ud, 6); 136af11bd88SGleb Natapov EX(nm, 7); 137af11bd88SGleb Natapov EX_E(df, 8); 138af11bd88SGleb Natapov EX_E(ts, 10); 139af11bd88SGleb Natapov EX_E(np, 11); 140af11bd88SGleb Natapov EX_E(ss, 12); 141af11bd88SGleb Natapov EX_E(gp, 13); 142af11bd88SGleb Natapov EX_E(pf, 14); 143af11bd88SGleb Natapov EX(mf, 16); 144af11bd88SGleb Natapov EX_E(ac, 17); 145af11bd88SGleb Natapov EX(mc, 18); 146af11bd88SGleb Natapov EX(xm, 19); 147af11bd88SGleb Natapov 1487d36db35SAvi Kivity asm (".pushsection .text \n\t" 149af11bd88SGleb Natapov "__handle_exception: \n\t" 15023ba7b39SGleb Natapov #ifdef __x86_64__ 1517d36db35SAvi Kivity "push %r15; push %r14; push %r13; push %r12 \n\t" 1527d36db35SAvi Kivity "push %r11; push %r10; push %r9; push %r8 \n\t" 15323ba7b39SGleb Natapov #endif 15423ba7b39SGleb Natapov "push %"R"di; push %"R"si; push %"R"bp; sub $"S", %"R"sp \n\t" 15523ba7b39SGleb Natapov "push %"R"bx; push %"R"dx; push %"R"cx; push %"R"ax \n\t" 156c3b91807SGleb Natapov #ifdef __x86_64__ 15723ba7b39SGleb Natapov "mov %"R"sp, %"R"di \n\t" 158c3b91807SGleb Natapov #else 159c3b91807SGleb Natapov "mov %"R"sp, %"R"ax \n\t" 160c3b91807SGleb Natapov #endif 1617d36db35SAvi Kivity "call do_handle_exception \n\t" 16223ba7b39SGleb Natapov "pop %"R"ax; pop %"R"cx; pop %"R"dx; pop %"R"bx \n\t" 16323ba7b39SGleb Natapov "add $"S", %"R"sp; pop %"R"bp; pop %"R"si; pop %"R"di \n\t" 16423ba7b39SGleb Natapov #ifdef __x86_64__ 1657d36db35SAvi Kivity "pop %r8; pop %r9; pop %r10; pop %r11 \n\t" 1667d36db35SAvi Kivity "pop %r12; pop %r13; pop %r14; pop %r15 \n\t" 16723ba7b39SGleb Natapov #endif 16823ba7b39SGleb Natapov "add $"S", %"R"sp \n\t" 16923ba7b39SGleb Natapov "add $"S", %"R"sp \n\t" 17023ba7b39SGleb Natapov "iret"W" \n\t" 1717d36db35SAvi Kivity ".popsection"); 1727d36db35SAvi Kivity 173af11bd88SGleb Natapov static void *idt_handlers[32] = { 174af11bd88SGleb Natapov [0] = &de_fault, 175af11bd88SGleb Natapov [1] = &db_fault, 176af11bd88SGleb Natapov [2] = &nmi_fault, 177af11bd88SGleb Natapov [3] = &bp_fault, 178af11bd88SGleb Natapov [4] = &of_fault, 179af11bd88SGleb Natapov [5] = &br_fault, 180af11bd88SGleb Natapov [6] = &ud_fault, 181af11bd88SGleb Natapov [7] = &nm_fault, 182af11bd88SGleb Natapov [8] = &df_fault, 183af11bd88SGleb Natapov [10] = &ts_fault, 184af11bd88SGleb Natapov [11] = &np_fault, 185af11bd88SGleb Natapov [12] = &ss_fault, 186af11bd88SGleb Natapov [13] = &gp_fault, 187af11bd88SGleb Natapov [14] = &pf_fault, 188af11bd88SGleb Natapov [16] = &mf_fault, 189af11bd88SGleb Natapov [17] = &ac_fault, 190af11bd88SGleb Natapov [18] = &mc_fault, 191af11bd88SGleb Natapov [19] = &xm_fault, 192af11bd88SGleb Natapov }; 1937d36db35SAvi Kivity 1947d36db35SAvi Kivity void setup_idt(void) 1957d36db35SAvi Kivity { 196af11bd88SGleb Natapov int i; 1974751cffbSAvi Kivity static bool idt_initialized = false; 1984751cffbSAvi Kivity 1994751cffbSAvi Kivity if (idt_initialized) { 2004751cffbSAvi Kivity return; 2014751cffbSAvi Kivity } 2024751cffbSAvi Kivity idt_initialized = true; 203af11bd88SGleb Natapov for (i = 0; i < 32; i++) 204af11bd88SGleb Natapov if (idt_handlers[i]) 205af11bd88SGleb Natapov set_idt_entry(i, idt_handlers[i], 0); 206af11bd88SGleb Natapov handle_exception(0, check_exception_table); 207af11bd88SGleb Natapov handle_exception(6, check_exception_table); 208af11bd88SGleb Natapov handle_exception(13, check_exception_table); 2097d36db35SAvi Kivity } 2107d36db35SAvi Kivity 2117d36db35SAvi Kivity unsigned exception_vector(void) 2127d36db35SAvi Kivity { 2137d36db35SAvi Kivity unsigned short vector; 2147d36db35SAvi Kivity 2157d36db35SAvi Kivity asm("mov %%gs:4, %0" : "=rm"(vector)); 2167d36db35SAvi Kivity return vector; 2177d36db35SAvi Kivity } 2187d36db35SAvi Kivity 2197d36db35SAvi Kivity unsigned exception_error_code(void) 2207d36db35SAvi Kivity { 2217d36db35SAvi Kivity unsigned short error_code; 2227d36db35SAvi Kivity 2237d36db35SAvi Kivity asm("mov %%gs:6, %0" : "=rm"(error_code)); 2247d36db35SAvi Kivity return error_code; 2257d36db35SAvi Kivity } 226d21b4f12SGleb Natapov 227d21b4f12SGleb Natapov #ifndef __x86_64__ 228d21b4f12SGleb Natapov /* 229d21b4f12SGleb Natapov * GDT, with 6 entries: 230d21b4f12SGleb Natapov * 0x00 - NULL descriptor 231d21b4f12SGleb Natapov * 0x08 - Code segment 232d21b4f12SGleb Natapov * 0x10 - Data segment 233d21b4f12SGleb Natapov * 0x18 - Not presend code segment 234d21b4f12SGleb Natapov * 0x20 - Primery task 235d21b4f12SGleb Natapov * 0x28 - Interrupt task 236*b01c8823SKevin Wolf * 237*b01c8823SKevin Wolf * 0x30 to 0x48 - Free to use for test cases 238d21b4f12SGleb Natapov */ 239d21b4f12SGleb Natapov 240*b01c8823SKevin Wolf static gdt_entry_t gdt[10]; 241d21b4f12SGleb Natapov #define TSS_GDT_OFFSET 4 242d21b4f12SGleb Natapov 243d21b4f12SGleb Natapov void set_gdt_entry(int num, u32 base, u32 limit, u8 access, u8 gran) 244d21b4f12SGleb Natapov { 245d21b4f12SGleb Natapov /* Setup the descriptor base address */ 246d21b4f12SGleb Natapov gdt[num].base_low = (base & 0xFFFF); 247d21b4f12SGleb Natapov gdt[num].base_middle = (base >> 16) & 0xFF; 248d21b4f12SGleb Natapov gdt[num].base_high = (base >> 24) & 0xFF; 249d21b4f12SGleb Natapov 250d21b4f12SGleb Natapov /* Setup the descriptor limits */ 251d21b4f12SGleb Natapov gdt[num].limit_low = (limit & 0xFFFF); 252d21b4f12SGleb Natapov gdt[num].granularity = ((limit >> 16) & 0x0F); 253d21b4f12SGleb Natapov 254d21b4f12SGleb Natapov /* Finally, set up the granularity and access flags */ 255d21b4f12SGleb Natapov gdt[num].granularity |= (gran & 0xF0); 256d21b4f12SGleb Natapov gdt[num].access = access; 257d21b4f12SGleb Natapov } 258d21b4f12SGleb Natapov 259d21b4f12SGleb Natapov void setup_gdt(void) 260d21b4f12SGleb Natapov { 261d21b4f12SGleb Natapov struct descriptor_table_ptr gp; 262d21b4f12SGleb Natapov /* Setup the GDT pointer and limit */ 263d21b4f12SGleb Natapov gp.limit = sizeof(gdt) - 1; 264d21b4f12SGleb Natapov gp.base = (ulong)&gdt; 265d21b4f12SGleb Natapov 266d21b4f12SGleb Natapov memset(gdt, 0, sizeof(gdt)); 267d21b4f12SGleb Natapov 268d21b4f12SGleb Natapov /* Our NULL descriptor */ 269d21b4f12SGleb Natapov set_gdt_entry(0, 0, 0, 0, 0); 270d21b4f12SGleb Natapov 271d21b4f12SGleb Natapov /* The second entry is our Code Segment. The base address 272d21b4f12SGleb Natapov * is 0, the limit is 4GBytes, it uses 4KByte granularity, 273d21b4f12SGleb Natapov * uses 32-bit opcodes, and is a Code Segment descriptor. */ 274d21b4f12SGleb Natapov set_gdt_entry(1, 0, 0xFFFFFFFF, 0x9A, 0xcf); 275d21b4f12SGleb Natapov 276d21b4f12SGleb Natapov /* The third entry is our Data Segment. It's EXACTLY the 277d21b4f12SGleb Natapov * same as our code segment, but the descriptor type in 278d21b4f12SGleb Natapov * this entry's access byte says it's a Data Segment */ 279d21b4f12SGleb Natapov set_gdt_entry(2, 0, 0xFFFFFFFF, 0x92, 0xcf); 280d21b4f12SGleb Natapov 281d21b4f12SGleb Natapov /* Same as code register above but not present */ 282d21b4f12SGleb Natapov set_gdt_entry(3, 0, 0xFFFFFFFF, 0x1A, 0xcf); 283d21b4f12SGleb Natapov 284d21b4f12SGleb Natapov 285d21b4f12SGleb Natapov /* Flush out the old GDT and install the new changes! */ 286d21b4f12SGleb Natapov lgdt(&gp); 287d21b4f12SGleb Natapov 288d21b4f12SGleb Natapov asm volatile ("mov %0, %%ds\n\t" 289d21b4f12SGleb Natapov "mov %0, %%es\n\t" 290d21b4f12SGleb Natapov "mov %0, %%fs\n\t" 291d21b4f12SGleb Natapov "mov %0, %%gs\n\t" 292d21b4f12SGleb Natapov "mov %0, %%ss\n\t" 293d21b4f12SGleb Natapov "jmp $0x08, $.Lflush2\n\t" 294d21b4f12SGleb Natapov ".Lflush2: "::"r"(0x10)); 295d21b4f12SGleb Natapov } 296d21b4f12SGleb Natapov 297*b01c8823SKevin Wolf void set_idt_task_gate(int vec, u16 sel) 298d21b4f12SGleb Natapov { 299b319491dSAvi Kivity idt_entry_t *e = &boot_idt[vec]; 300d21b4f12SGleb Natapov 301d21b4f12SGleb Natapov memset(e, 0, sizeof *e); 302d21b4f12SGleb Natapov 303d21b4f12SGleb Natapov e->selector = sel; 304d21b4f12SGleb Natapov e->ist = 0; 305d21b4f12SGleb Natapov e->type = 5; 306d21b4f12SGleb Natapov e->dpl = 0; 307d21b4f12SGleb Natapov e->p = 1; 308d21b4f12SGleb Natapov } 309d21b4f12SGleb Natapov 310d21b4f12SGleb Natapov /* 311d21b4f12SGleb Natapov * 0 - main task 312d21b4f12SGleb Natapov * 1 - interrupt task 313d21b4f12SGleb Natapov */ 314d21b4f12SGleb Natapov 315d21b4f12SGleb Natapov static tss32_t tss[2]; 316d21b4f12SGleb Natapov static char tss_stack[2][4096]; 317d21b4f12SGleb Natapov 318d21b4f12SGleb Natapov void setup_tss32(void) 319d21b4f12SGleb Natapov { 320d21b4f12SGleb Natapov u16 desc_size = sizeof(tss32_t); 321d21b4f12SGleb Natapov int i; 322d21b4f12SGleb Natapov 323d21b4f12SGleb Natapov for (i = 0; i < 2; i++) { 324d21b4f12SGleb Natapov tss[i].cr3 = read_cr3(); 325d21b4f12SGleb Natapov tss[i].ss0 = tss[i].ss1 = tss[i].ss2 = 0x10; 326d21b4f12SGleb Natapov tss[i].esp = tss[i].esp0 = tss[i].esp1 = tss[i].esp2 = 327e4a34e01SGleb Natapov (u32)tss_stack[i] + 4096; 328d21b4f12SGleb Natapov tss[i].cs = 0x08; 329d21b4f12SGleb Natapov tss[i].ds = tss[i].es = tss[i].fs = tss[i].gs = tss[i].ss = 0x10; 330d21b4f12SGleb Natapov tss[i].iomap_base = (u16)desc_size; 331d21b4f12SGleb Natapov set_gdt_entry(TSS_GDT_OFFSET + i, (u32)&tss[i], 332d21b4f12SGleb Natapov desc_size - 1, 0x89, 0x0f); 333d21b4f12SGleb Natapov } 334d21b4f12SGleb Natapov 335d21b4f12SGleb Natapov ltr(TSS_MAIN); 336d21b4f12SGleb Natapov } 337d21b4f12SGleb Natapov 338d21b4f12SGleb Natapov void set_intr_task_gate(int e, void *fn) 339d21b4f12SGleb Natapov { 340d21b4f12SGleb Natapov tss[1].eip = (u32)fn; 341d21b4f12SGleb Natapov set_idt_task_gate(e, TSS_INTR); 342d21b4f12SGleb Natapov } 343d21b4f12SGleb Natapov 344d21b4f12SGleb Natapov void print_current_tss_info(void) 345d21b4f12SGleb Natapov { 346d21b4f12SGleb Natapov u16 tr = str(); 347d21b4f12SGleb Natapov int i = (tr == TSS_MAIN) ? 0 : 1; 348d21b4f12SGleb Natapov 349d21b4f12SGleb Natapov if (tr != TSS_MAIN && tr != TSS_INTR) 350d21b4f12SGleb Natapov printf("Unknown TSS %x\n", tr); 351d21b4f12SGleb Natapov else 352d21b4f12SGleb Natapov printf("TR=%x Main TSS back link %x. Current TSS back link %x\n", 353d21b4f12SGleb Natapov tr, tss[0].prev, tss[i].prev); 354d21b4f12SGleb Natapov } 355d21b4f12SGleb Natapov #endif 356