1 #ifndef _X86_DESC_H_
2 #define _X86_DESC_H_
3
4 /*
5 * selector 32-bit 64-bit
6 * 0x00 NULL descriptor NULL descriptor
7 * 0x08 ring-0 code segment (32-bit) ring-0 code segment (64-bit)
8 * 0x10 ring-0 data segment (32-bit) ring-0 data segment (32/64-bit)
9 * 0x18 ring-0 code segment (P=0) ring-0 code segment (64-bit, P=0)
10 * 0x20 intr_alt_stack TSS ring-0 code segment (32-bit)
11 * 0x28 ring-0 code segment (16-bit) same
12 * 0x30 ring-0 data segment (16-bit) same
13 * 0x38 (0x3b) ring-3 code segment (32-bit) same
14 * 0x40 (0x43) ring-3 data segment (32-bit) ring-3 data segment (32/64-bit)
15 * 0x48 (0x4b) **unused** ring-3 code segment (64-bit)
16 * 0x50-0x78 free to use for test cases same
17 * 0x80-0x870 primary TSS (CPU 0..254) same
18 * 0x878-0x1068 percpu area (CPU 0..254) not used
19 *
20 * Note that the same segment can be used for 32-bit and 64-bit data segments
21 * (the L bit is only defined for code segments)
22 *
23 * Selectors 0x08-0x10 and 0x3b-0x4b are set up for use with the SYSCALL
24 * and SYSRET instructions.
25 */
26
27 #define KERNEL_CS 0x08
28 #define KERNEL_DS 0x10
29 #define NP_SEL 0x18
30 #ifdef __x86_64__
31 #define KERNEL_CS32 0x20
32 #else
33 #define TSS_INTR 0x20
34 #endif
35 #define KERNEL_CS16 0x28
36 #define KERNEL_DS16 0x30
37 #define USER_CS32 0x3b
38 #define USER_DS 0x43
39 #ifdef __x86_64__
40 #define USER_CS64 0x4b
41 #endif
42
43 /* Synonyms */
44 #define KERNEL_DS32 KERNEL_DS
45 #define USER_DS32 USER_DS
46
47 #ifdef __x86_64__
48 #define KERNEL_CS64 KERNEL_CS
49 #define USER_CS USER_CS64
50 #define KERNEL_DS64 KERNEL_DS
51 #define USER_DS64 USER_DS
52 #else
53 #define KERNEL_CS32 KERNEL_CS
54 #define USER_CS USER_CS32
55 #endif
56
57 #define FIRST_SPARE_SEL 0x50
58 #define TSS_MAIN 0x80
59
60 #ifdef __ASSEMBLER__
61 #define __ASM_FORM(x, ...) x,## __VA_ARGS__
62 #else
63 #define __ASM_FORM(x, ...) " " xstr(x,##__VA_ARGS__) " "
64 #endif
65
66 #ifndef __x86_64__
67 #define __ASM_SEL(a,b) __ASM_FORM(a)
68 #else
69 #define __ASM_SEL(a,b) __ASM_FORM(b)
70 #endif
71
72 #ifndef __ASSEMBLER__
73
74 #include <setjmp.h>
75
76 void setup_idt(void);
77 void load_idt(void);
78 void setup_alt_stack(void);
79
80 struct ex_regs {
81 unsigned long rax, rcx, rdx, rbx;
82 unsigned long dummy, rbp, rsi, rdi;
83 #ifdef __x86_64__
84 unsigned long r8, r9, r10, r11;
85 unsigned long r12, r13, r14, r15;
86 #endif
87 unsigned long vector;
88 unsigned long error_code;
89 unsigned long rip;
90 unsigned long cs;
91 unsigned long rflags;
92 #ifdef __x86_64__
93 unsigned long rsp;
94 unsigned long ss;
95 #endif
96 };
97
98 typedef void (*handler)(struct ex_regs *regs);
99
100 typedef struct {
101 u16 prev;
102 u16 res1;
103 u32 esp0;
104 u16 ss0;
105 u16 res2;
106 u32 esp1;
107 u16 ss1;
108 u16 res3;
109 u32 esp2;
110 u16 ss2;
111 u16 res4;
112 u32 cr3;
113 u32 eip;
114 u32 eflags;
115 u32 eax, ecx, edx, ebx, esp, ebp, esi, edi;
116 u16 es;
117 u16 res5;
118 u16 cs;
119 u16 res6;
120 u16 ss;
121 u16 res7;
122 u16 ds;
123 u16 res8;
124 u16 fs;
125 u16 res9;
126 u16 gs;
127 u16 res10;
128 u16 ldt;
129 u16 res11;
130 u16 t:1;
131 u16 res12:15;
132 u16 iomap_base;
133 } tss32_t;
134
135 typedef struct __attribute__((packed)) {
136 u32 res1;
137 u64 rsp0;
138 u64 rsp1;
139 u64 rsp2;
140 u64 res2;
141 u64 ist1;
142 u64 ist2;
143 u64 ist3;
144 u64 ist4;
145 u64 ist5;
146 u64 ist6;
147 u64 ist7;
148 u64 res3;
149 u16 res4;
150 u16 iomap_base;
151 } tss64_t;
152
153 #define __ASM_TRY(prefix, catch) \
154 "movl $0, %%gs:4\n\t" \
155 ".pushsection .data.ex\n\t" \
156 __ASM_SEL(.long, .quad) " 1111f, " catch "\n\t" \
157 ".popsection \n\t" \
158 prefix "\n\t" \
159 "1111:"
160
161 #define ASM_TRY(catch) __ASM_TRY("", catch)
162
163 /* Forced emulation prefix, used to invoke the emulator unconditionally. */
164 #define KVM_FEP "ud2; .byte 'k', 'v', 'm';"
165 #define ASM_TRY_FEP(catch) __ASM_TRY(KVM_FEP, catch)
166
is_fep_available(void)167 static inline bool is_fep_available(void)
168 {
169 /*
170 * Use the non-FEP ASM_TRY() as KVM will inject a #UD on the prefix
171 * itself if forced emulation is not available.
172 */
173 asm goto(ASM_TRY("%l[fep_unavailable]")
174 KVM_FEP "nop\n\t"
175 ::: "memory" : fep_unavailable);
176 return true;
177 fep_unavailable:
178 return false;
179 }
180
181 typedef struct {
182 unsigned short offset0;
183 unsigned short selector;
184 unsigned short ist : 3;
185 unsigned short : 5;
186 unsigned short type : 4;
187 unsigned short : 1;
188 unsigned short dpl : 2;
189 unsigned short p : 1;
190 unsigned short offset1;
191 #ifdef __x86_64__
192 unsigned offset2;
193 unsigned reserved;
194 #endif
195 } idt_entry_t;
196
197 typedef struct {
198 uint16_t limit1;
199 uint16_t base1;
200 uint8_t base2;
201 union {
202 uint16_t type_limit_flags; /* Type and limit flags */
203 struct {
204 uint16_t type:4;
205 uint16_t s:1;
206 uint16_t dpl:2;
207 uint16_t p:1;
208 uint16_t limit2:4;
209 uint16_t avl:1;
210 uint16_t l:1;
211 uint16_t db:1;
212 uint16_t g:1;
213 } __attribute__((__packed__));
214 } __attribute__((__packed__));
215 uint8_t base3;
216 } __attribute__((__packed__)) gdt_entry_t;
217
218 #ifdef __x86_64__
219 struct system_desc64 {
220 gdt_entry_t common;
221 uint32_t base4;
222 uint32_t zero;
223 } __attribute__((__packed__));
224 #endif
225
226 #define DESC_BUSY 2
227
228 extern idt_entry_t boot_idt[256];
229
230 #ifndef __x86_64__
231 extern tss32_t tss[];
232 extern tss32_t tss_intr;
233 void set_gdt_task_gate(u16 tss_sel, u16 sel);
234 void set_idt_task_gate(int vec, u16 sel);
235 void set_intr_task_gate(int vec, void *fn);
236 void setup_tss32(void);
237 #else
238 extern tss64_t tss[];
239 #endif
240 extern gdt_entry_t gdt[];
241
242 unsigned exception_vector(void);
243 unsigned exception_error_code(void);
244 bool exception_rflags_rf(void);
245 void set_desc_entry(idt_entry_t *e, size_t e_sz, void *addr,
246 u16 sel, u16 type, u16 dpl);
247 void set_idt_entry(int vec, void *addr, int dpl);
248 void set_idt_sel(int vec, u16 sel);
249 void set_idt_dpl(int vec, u16 dpl);
250 void set_gdt_entry(int sel, unsigned long base, u32 limit, u8 access, u8 gran);
251 void set_gdt_entry_base(int sel, unsigned long base);
252 void clear_tss_busy(int sel);
253 void load_gdt_tss(size_t tss_offset);
254 void set_intr_alt_stack(int e, void *fn);
255 void print_current_tss_info(void);
256 handler handle_exception(u8 v, handler fn);
257 void unhandled_exception(struct ex_regs *regs, bool cpu);
258 const char* exception_mnemonic(int vector);
259
260 bool test_for_exception(unsigned int ex, void (*trigger_func)(void *data),
261 void *data);
262 void __set_exception_jmpbuf(jmp_buf *addr);
263 #define set_exception_jmpbuf(jmpbuf) \
264 (setjmp(jmpbuf) ? : (__set_exception_jmpbuf(&(jmpbuf)), 0))
265
get_idt_addr(idt_entry_t * entry)266 static inline void *get_idt_addr(idt_entry_t *entry)
267 {
268 uintptr_t addr = entry->offset0 | ((u32)entry->offset1 << 16);
269 #ifdef __x86_64__
270 addr |= (u64)entry->offset2 << 32;
271 #endif
272 return (void *)addr;
273 }
274
275 extern gdt_entry_t *get_gdt_entry(u16 sel);
276 extern gdt_entry_t *get_tss_descr(void);
277 gdt_entry_t *get_ldt_descr(void);
278
279 extern unsigned long get_gdt_entry_base(gdt_entry_t *entry);
280 extern unsigned long get_gdt_entry_limit(gdt_entry_t *entry);
281
282 #define __asm_safe(fep, insn, inputs...) \
283 ({ \
284 asm volatile(__ASM_TRY(fep, "1f") \
285 insn "\n\t" \
286 "1:\n\t" \
287 : \
288 : inputs \
289 : "memory"); \
290 exception_vector(); \
291 })
292
293 #define asm_safe(insn, inputs...) \
294 __asm_safe("", insn, inputs)
295
296 #define asm_fep_safe(insn, inputs...) \
297 __asm_safe_out1(KVM_FEP, insn,, inputs)
298
299 #define __asm_safe_out1(fep, insn, output, inputs...) \
300 ({ \
301 asm volatile(__ASM_TRY(fep, "1f") \
302 insn "\n\t" \
303 "1:\n\t" \
304 : output \
305 : inputs \
306 : "memory"); \
307 exception_vector(); \
308 })
309
310 #define asm_safe_out1(insn, output, inputs...) \
311 __asm_safe_out1("", insn, output, inputs)
312
313 #define asm_fep_safe_out1(insn, output, inputs...) \
314 __asm_safe_out1(KVM_FEP, insn, output, inputs)
315
316 #define __asm_safe_out2(fep, insn, output1, output2, inputs...) \
317 ({ \
318 asm volatile(__ASM_TRY(fep, "1f") \
319 insn "\n\t" \
320 "1:\n\t" \
321 : output1, output2 \
322 : inputs \
323 : "memory"); \
324 exception_vector(); \
325 })
326
327 #define asm_safe_out2(fep, insn, output1, output2, inputs...) \
328 __asm_safe_out2("", insn, output1, output2, inputs)
329
330 #define asm_fep_safe_out2(insn, output1, output2, inputs...) \
331 __asm_safe_out2(KVM_FEP, insn, output1, output2, inputs)
332
333 #define __asm_safe_report(want, insn, inputs...) \
334 do { \
335 int vector = asm_safe(insn, inputs); \
336 \
337 report(vector == want, "Expected %s on '%s', got %s", \
338 want ? exception_mnemonic(want) : "SUCCESS", \
339 insn, \
340 vector ? exception_mnemonic(vector) : "SUCCESS"); \
341 } while (0)
342
343 #define asm_safe_report(insn, inputs...) \
344 __asm_safe_report(0, insn, inputs)
345
346 #define asm_safe_report_ex __asm_safe_report
347
348
349 #endif /* __ASSEMBLER__ */
350
351 #endif /* _X86_DESC_H_ */
352