xref: /kvm-unit-tests/lib/x86/desc.c (revision 597e0ef2d3f22d5a394ea3378ca655997d648349)
17d36db35SAvi Kivity #include "idt.h"
27d36db35SAvi Kivity #include "libcflat.h"
37d36db35SAvi Kivity 
47d36db35SAvi Kivity typedef struct {
57d36db35SAvi Kivity     unsigned short offset0;
67d36db35SAvi Kivity     unsigned short selector;
77d36db35SAvi Kivity     unsigned short ist : 3;
87d36db35SAvi Kivity     unsigned short : 5;
97d36db35SAvi Kivity     unsigned short type : 4;
107d36db35SAvi Kivity     unsigned short : 1;
117d36db35SAvi Kivity     unsigned short dpl : 2;
127d36db35SAvi Kivity     unsigned short p : 1;
137d36db35SAvi Kivity     unsigned short offset1;
147d36db35SAvi Kivity     unsigned offset2;
157d36db35SAvi Kivity     unsigned reserved;
167d36db35SAvi Kivity } idt_entry_t;
177d36db35SAvi Kivity 
187d36db35SAvi Kivity static idt_entry_t idt[256];
197d36db35SAvi Kivity 
207d36db35SAvi Kivity typedef struct {
217d36db35SAvi Kivity     unsigned short limit;
227d36db35SAvi Kivity     unsigned long linear_addr;
237d36db35SAvi Kivity } __attribute__((packed)) descriptor_table_t;
247d36db35SAvi Kivity 
257d36db35SAvi Kivity void lidt(idt_entry_t *idt, int nentries)
267d36db35SAvi Kivity {
277d36db35SAvi Kivity     descriptor_table_t dt;
287d36db35SAvi Kivity 
297d36db35SAvi Kivity     dt.limit = nentries * sizeof(*idt) - 1;
307d36db35SAvi Kivity     dt.linear_addr = (unsigned long)idt;
317d36db35SAvi Kivity     asm volatile ("lidt %0" : : "m"(dt));
327d36db35SAvi Kivity }
337d36db35SAvi Kivity 
347d36db35SAvi Kivity unsigned short read_cs()
357d36db35SAvi Kivity {
367d36db35SAvi Kivity     unsigned short r;
377d36db35SAvi Kivity 
387d36db35SAvi Kivity     asm volatile ("mov %%cs, %0" : "=r"(r));
397d36db35SAvi Kivity     return r;
407d36db35SAvi Kivity }
417d36db35SAvi Kivity 
427d36db35SAvi Kivity void set_idt_entry(idt_entry_t *e, void *addr, int dpl)
437d36db35SAvi Kivity {
447d36db35SAvi Kivity     memset(e, 0, sizeof *e);
457d36db35SAvi Kivity     e->offset0 = (unsigned long)addr;
467d36db35SAvi Kivity     e->selector = read_cs();
477d36db35SAvi Kivity     e->ist = 0;
487d36db35SAvi Kivity     e->type = 14;
497d36db35SAvi Kivity     e->dpl = dpl;
507d36db35SAvi Kivity     e->p = 1;
517d36db35SAvi Kivity     e->offset1 = (unsigned long)addr >> 16;
527d36db35SAvi Kivity     e->offset2 = (unsigned long)addr >> 32;
537d36db35SAvi Kivity }
547d36db35SAvi Kivity 
557d36db35SAvi Kivity struct ex_regs {
567d36db35SAvi Kivity     unsigned long rax, rcx, rdx, rbx;
577d36db35SAvi Kivity     unsigned long dummy, rbp, rsi, rdi;
587d36db35SAvi Kivity     unsigned long r8, r9, r10, r11;
597d36db35SAvi Kivity     unsigned long r12, r13, r14, r15;
607d36db35SAvi Kivity     unsigned long vector;
617d36db35SAvi Kivity     unsigned long error_code;
627d36db35SAvi Kivity     unsigned long rip;
637d36db35SAvi Kivity     unsigned long cs;
647d36db35SAvi Kivity     unsigned long rflags;
657d36db35SAvi Kivity };
667d36db35SAvi Kivity 
677d36db35SAvi Kivity struct ex_record {
687d36db35SAvi Kivity     unsigned long rip;
697d36db35SAvi Kivity     unsigned long handler;
707d36db35SAvi Kivity };
717d36db35SAvi Kivity 
727d36db35SAvi Kivity extern struct ex_record exception_table_start, exception_table_end;
737d36db35SAvi Kivity 
747d36db35SAvi Kivity void do_handle_exception(struct ex_regs *regs)
757d36db35SAvi Kivity {
767d36db35SAvi Kivity     struct ex_record *ex;
777d36db35SAvi Kivity     unsigned ex_val;
787d36db35SAvi Kivity 
797d36db35SAvi Kivity     ex_val = regs->vector | (regs->error_code << 16);
807d36db35SAvi Kivity 
817d36db35SAvi Kivity     asm("mov %0, %%gs:4" : : "r"(ex_val));
827d36db35SAvi Kivity 
837d36db35SAvi Kivity     for (ex = &exception_table_start; ex != &exception_table_end; ++ex) {
847d36db35SAvi Kivity         if (ex->rip == regs->rip) {
857d36db35SAvi Kivity             regs->rip = ex->handler;
867d36db35SAvi Kivity             return;
877d36db35SAvi Kivity         }
887d36db35SAvi Kivity     }
897d36db35SAvi Kivity     printf("unhandled excecption\n");
907d36db35SAvi Kivity     exit(7);
917d36db35SAvi Kivity }
927d36db35SAvi Kivity 
937d36db35SAvi Kivity asm (".pushsection .text \n\t"
947d36db35SAvi Kivity      "ud_fault: \n\t"
957d36db35SAvi Kivity      "pushq $0 \n\t"
967d36db35SAvi Kivity      "pushq $6 \n\t"
977d36db35SAvi Kivity      "jmp handle_exception \n\t"
987d36db35SAvi Kivity 
997d36db35SAvi Kivity      "gp_fault: \n\t"
1007d36db35SAvi Kivity      "pushq $13 \n\t"
1017d36db35SAvi Kivity      "jmp handle_exception \n\t"
1027d36db35SAvi Kivity 
103*597e0ef2SAvi Kivity      "de_fault: \n\t"
104*597e0ef2SAvi Kivity      "pushq $0 \n\t"
105*597e0ef2SAvi Kivity      "pushq $0 \n\t"
106*597e0ef2SAvi Kivity      "jmp handle_exception \n\t"
107*597e0ef2SAvi Kivity 
1087d36db35SAvi Kivity      "handle_exception: \n\t"
1097d36db35SAvi Kivity      "push %r15; push %r14; push %r13; push %r12 \n\t"
1107d36db35SAvi Kivity      "push %r11; push %r10; push %r9; push %r8 \n\t"
1117d36db35SAvi Kivity      "push %rdi; push %rsi; push %rbp; sub $8, %rsp \n\t"
1127d36db35SAvi Kivity      "push %rbx; push %rdx; push %rcx; push %rax \n\t"
1137d36db35SAvi Kivity      "mov %rsp, %rdi \n\t"
1147d36db35SAvi Kivity      "call do_handle_exception \n\t"
1157d36db35SAvi Kivity      "pop %rax; pop %rcx; pop %rdx; pop %rbx \n\t"
1167d36db35SAvi Kivity      "add $8, %rsp; pop %rbp; pop %rsi; pop %rdi \n\t"
1177d36db35SAvi Kivity      "pop %r8; pop %r9; pop %r10; pop %r11 \n\t"
1187d36db35SAvi Kivity      "pop %r12; pop %r13; pop %r14; pop %r15 \n\t"
1197d36db35SAvi Kivity      "add $16, %rsp \n\t"
1207d36db35SAvi Kivity      "iretq \n\t"
1217d36db35SAvi Kivity      ".popsection");
1227d36db35SAvi Kivity 
1237d36db35SAvi Kivity 
1247d36db35SAvi Kivity void setup_idt(void)
1257d36db35SAvi Kivity {
126*597e0ef2SAvi Kivity     extern char ud_fault, gp_fault, de_fault;
1277d36db35SAvi Kivity 
1287d36db35SAvi Kivity     lidt(idt, 256);
129*597e0ef2SAvi Kivity     set_idt_entry(&idt[0], &de_fault, 0);
1307d36db35SAvi Kivity     set_idt_entry(&idt[6], &ud_fault, 0);
1317d36db35SAvi Kivity     set_idt_entry(&idt[13], &gp_fault, 0);
1327d36db35SAvi Kivity }
1337d36db35SAvi Kivity 
1347d36db35SAvi Kivity unsigned exception_vector(void)
1357d36db35SAvi Kivity {
1367d36db35SAvi Kivity     unsigned short vector;
1377d36db35SAvi Kivity 
1387d36db35SAvi Kivity     asm("mov %%gs:4, %0" : "=rm"(vector));
1397d36db35SAvi Kivity     return vector;
1407d36db35SAvi Kivity }
1417d36db35SAvi Kivity 
1427d36db35SAvi Kivity unsigned exception_error_code(void)
1437d36db35SAvi Kivity {
1447d36db35SAvi Kivity     unsigned short error_code;
1457d36db35SAvi Kivity 
1467d36db35SAvi Kivity     asm("mov %%gs:6, %0" : "=rm"(error_code));
1477d36db35SAvi Kivity     return error_code;
1487d36db35SAvi Kivity }
149