xref: /kvm-unit-tests/lib/x86/isr.c (revision d3aacb4f57d05f74f2030dbe12e7dfd6aa1b273d)
1 #include "libcflat.h"
2 #include "isr.h"
3 #include "vm.h"
4 #include "desc.h"
5 
6 extern char isr_entry_point[];
7 
8 asm (
9     "isr_entry_point: \n"
10 #ifdef __x86_64__
11     "push %r15 \n\t"
12     "push %r14 \n\t"
13     "push %r13 \n\t"
14     "push %r12 \n\t"
15     "push %r11 \n\t"
16     "push %r10 \n\t"
17     "push %r9  \n\t"
18     "push %r8  \n\t"
19 #endif
20     "push %"R "di \n\t"
21     "push %"R "si \n\t"
22     "push %"R "bp \n\t"
23     "push %"R "sp \n\t"
24     "push %"R "bx \n\t"
25     "push %"R "dx \n\t"
26     "push %"R "cx \n\t"
27     "push %"R "ax \n\t"
28 #ifdef __x86_64__
29     "mov %rsp, %rdi \n\t"
30     "callq *8*16(%rsp) \n\t"
31 #else
32     "push %esp \n\t"
33     "calll *4+4*8(%esp) \n\t"
34     "add $4, %esp \n\t"
35 #endif
36     "pop %"R "ax \n\t"
37     "pop %"R "cx \n\t"
38     "pop %"R "dx \n\t"
39     "pop %"R "bx \n\t"
40     "pop %"R "bp \n\t"
41     "pop %"R "bp \n\t"
42     "pop %"R "si \n\t"
43     "pop %"R "di \n\t"
44 #ifdef __x86_64__
45     "pop %r8  \n\t"
46     "pop %r9  \n\t"
47     "pop %r10 \n\t"
48     "pop %r11 \n\t"
49     "pop %r12 \n\t"
50     "pop %r13 \n\t"
51     "pop %r14 \n\t"
52     "pop %r15 \n\t"
53 #endif
54     ".globl isr_iret_ip\n\t"
55 #ifdef __x86_64__
56     "add $8, %rsp \n\t"
57     "isr_iret_ip: \n\t"
58     "iretq \n\t"
59 #else
60     "add $4, %esp \n\t"
61     "isr_iret_ip: \n\t"
62     "iretl \n\t"
63 #endif
64     );
65 
66 void handle_irq(unsigned vec, void (*func)(isr_regs_t *regs))
67 {
68     u8 *thunk = vmalloc(50);
69 
70     set_idt_entry(vec, thunk, 0);
71 
72 #ifdef __x86_64__
73     /* sub $8, %rsp */
74     *thunk++ = 0x48; *thunk++ = 0x83; *thunk++ = 0xec; *thunk++ = 0x08;
75     /* mov $func_low, %(rsp) */
76     *thunk++ = 0xc7; *thunk++ = 0x04; *thunk++ = 0x24;
77     *(u32 *)thunk = (ulong)func; thunk += 4;
78     /* mov $func_high, %(rsp+4) */
79     *thunk++ = 0xc7; *thunk++ = 0x44; *thunk++ = 0x24; *thunk++ = 0x04;
80     *(u32 *)thunk = (ulong)func >> 32; thunk += 4;
81     /* jmp isr_entry_point */
82     *thunk ++ = 0xe9;
83     *(u32 *)thunk = (ulong)isr_entry_point - (ulong)(thunk + 4);
84 #else
85     /* push $func */
86     *thunk++ = 0x68;
87     *(u32 *)thunk = (ulong)func; thunk += 4;
88     /* jmp isr_entry_point */
89     *thunk++ = 0xe9;
90     *(u32 *)thunk = (ulong)isr_entry_point - (ulong)(thunk + 4);
91 #endif
92 }
93 
94 void handle_external_interrupt(int vector)
95 {
96 #ifdef __x86_64__
97 	unsigned long tmp;
98 #endif
99 	idt_entry_t *idt = &boot_idt[vector];
100 	unsigned long entry =
101 	    idt->offset0 | ((unsigned long)idt->offset1 << 16) |
102 	    ((unsigned long)idt->offset2 << 32);
103 
104 	asm volatile(
105 #ifdef __x86_64__
106 		     "mov %%rsp, %[sp]\n\t"
107 		     "and $0xfffffffffffffff0, %%rsp\n\t"
108 		     "push $%c[ss]\n\t"
109 		     "push %[sp]\n\t"
110 #endif
111 		     "pushf\n\t"
112 		     "orl $0x200, (%%rsp)\n\t"
113 		     "push $%c[cs]\n\t"
114 		     "call *%[entry]\n\t"
115 		     :
116 #ifdef __x86_64__
117 		     [sp]"=&r"(tmp)
118 #endif
119 		     :
120 		     [entry]"r"(entry),
121 		     [ss]"i"(KERNEL_DS),
122 		     [cs]"i"(KERNEL_CS)
123 		     );
124 }
125