xref: /kvm-unit-tests/lib/x86/desc.h (revision 4c5d37137baf4e965b557ef7d912ea1a80526776)
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 __ASSEMBLY__
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 #include <setjmp.h>
73 
74 void setup_idt(void);
75 void load_idt(void);
76 void setup_alt_stack(void);
77 
78 struct ex_regs {
79 	unsigned long rax, rcx, rdx, rbx;
80 	unsigned long dummy, rbp, rsi, rdi;
81 #ifdef __x86_64__
82 	unsigned long r8, r9, r10, r11;
83 	unsigned long r12, r13, r14, r15;
84 #endif
85 	unsigned long vector;
86 	unsigned long error_code;
87 	unsigned long rip;
88 	unsigned long cs;
89 	unsigned long rflags;
90 #ifdef __x86_64__
91 	unsigned long rsp;
92 	unsigned long ss;
93 #endif
94 };
95 
96 typedef void (*handler)(struct ex_regs *regs);
97 
98 typedef struct {
99 	u16 prev;
100 	u16 res1;
101 	u32 esp0;
102 	u16 ss0;
103 	u16 res2;
104 	u32 esp1;
105 	u16 ss1;
106 	u16 res3;
107 	u32 esp2;
108 	u16 ss2;
109 	u16 res4;
110 	u32 cr3;
111 	u32 eip;
112 	u32 eflags;
113 	u32 eax, ecx, edx, ebx, esp, ebp, esi, edi;
114 	u16 es;
115 	u16 res5;
116 	u16 cs;
117 	u16 res6;
118 	u16 ss;
119 	u16 res7;
120 	u16 ds;
121 	u16 res8;
122 	u16 fs;
123 	u16 res9;
124 	u16 gs;
125 	u16 res10;
126 	u16 ldt;
127 	u16 res11;
128 	u16 t:1;
129 	u16 res12:15;
130 	u16 iomap_base;
131 } tss32_t;
132 
133 typedef struct  __attribute__((packed)) {
134 	u32 res1;
135 	u64 rsp0;
136 	u64 rsp1;
137 	u64 rsp2;
138 	u64 res2;
139 	u64 ist1;
140 	u64 ist2;
141 	u64 ist3;
142 	u64 ist4;
143 	u64 ist5;
144 	u64 ist6;
145 	u64 ist7;
146 	u64 res3;
147 	u16 res4;
148 	u16 iomap_base;
149 } tss64_t;
150 
151 #define __ASM_TRY(prefix, catch)				\
152 	"movl $0, %%gs:4\n\t"					\
153 	".pushsection .data.ex\n\t"				\
154 	__ASM_SEL(.long, .quad) " 1111f,  " catch "\n\t"	\
155 	".popsection \n\t"					\
156 	prefix "\n\t"						\
157 	"1111:"
158 
159 #define ASM_TRY(catch) __ASM_TRY("", catch)
160 
161 /* Forced emulation prefix, used to invoke the emulator unconditionally. */
162 #define KVM_FEP "ud2; .byte 'k', 'v', 'm';"
163 #define ASM_TRY_FEP(catch) __ASM_TRY(KVM_FEP, catch)
164 
165 static inline bool is_fep_available(void)
166 {
167 	/*
168 	 * Use the non-FEP ASM_TRY() as KVM will inject a #UD on the prefix
169 	 * itself if forced emulation is not available.
170 	 */
171 	asm goto(ASM_TRY("%l[fep_unavailable]")
172 		 KVM_FEP "nop\n\t"
173 		 ::: "memory" : fep_unavailable);
174 	return true;
175 fep_unavailable:
176 	return false;
177 }
178 
179 typedef struct {
180 	unsigned short offset0;
181 	unsigned short selector;
182 	unsigned short ist : 3;
183 	unsigned short : 5;
184 	unsigned short type : 4;
185 	unsigned short : 1;
186 	unsigned short dpl : 2;
187 	unsigned short p : 1;
188 	unsigned short offset1;
189 #ifdef __x86_64__
190 	unsigned offset2;
191 	unsigned reserved;
192 #endif
193 } idt_entry_t;
194 
195 typedef struct {
196 	uint16_t limit1;
197 	uint16_t base1;
198 	uint8_t  base2;
199 	union {
200 		uint16_t  type_limit_flags;      /* Type and limit flags */
201 		struct {
202 			uint16_t type:4;
203 			uint16_t s:1;
204 			uint16_t dpl:2;
205 			uint16_t p:1;
206 			uint16_t limit2:4;
207 			uint16_t avl:1;
208 			uint16_t l:1;
209 			uint16_t db:1;
210 			uint16_t g:1;
211 		} __attribute__((__packed__));
212 	} __attribute__((__packed__));
213 	uint8_t  base3;
214 } __attribute__((__packed__)) gdt_entry_t;
215 
216 #ifdef __x86_64__
217 struct system_desc64 {
218 	gdt_entry_t common;
219 	uint32_t base4;
220 	uint32_t zero;
221 } __attribute__((__packed__));
222 #endif
223 
224 #define DESC_BUSY 2
225 
226 extern idt_entry_t boot_idt[256];
227 
228 #ifndef __x86_64__
229 extern tss32_t tss[];
230 extern tss32_t tss_intr;
231 void set_gdt_task_gate(u16 tss_sel, u16 sel);
232 void set_idt_task_gate(int vec, u16 sel);
233 void set_intr_task_gate(int vec, void *fn);
234 void setup_tss32(void);
235 #else
236 extern tss64_t tss[];
237 #endif
238 extern gdt_entry_t gdt[];
239 
240 unsigned exception_vector(void);
241 unsigned exception_error_code(void);
242 bool exception_rflags_rf(void);
243 void set_desc_entry(idt_entry_t *e, size_t e_sz, void *addr,
244 		    u16 sel, u16 type, u16 dpl);
245 void set_idt_entry(int vec, void *addr, int dpl);
246 void set_idt_sel(int vec, u16 sel);
247 void set_idt_dpl(int vec, u16 dpl);
248 void set_gdt_entry(int sel, unsigned long base, u32 limit, u8 access, u8 gran);
249 void set_gdt_entry_base(int sel, unsigned long base);
250 void clear_tss_busy(int sel);
251 void load_gdt_tss(size_t tss_offset);
252 void set_intr_alt_stack(int e, void *fn);
253 void print_current_tss_info(void);
254 handler handle_exception(u8 v, handler fn);
255 void unhandled_exception(struct ex_regs *regs, bool cpu);
256 const char* exception_mnemonic(int vector);
257 
258 bool test_for_exception(unsigned int ex, void (*trigger_func)(void *data),
259 			void *data);
260 void __set_exception_jmpbuf(jmp_buf *addr);
261 #define set_exception_jmpbuf(jmpbuf) \
262 	(setjmp(jmpbuf) ? : (__set_exception_jmpbuf(&(jmpbuf)), 0))
263 
264 static inline void *get_idt_addr(idt_entry_t *entry)
265 {
266 	uintptr_t addr = entry->offset0 | ((u32)entry->offset1 << 16);
267 #ifdef __x86_64__
268 	addr |= (u64)entry->offset2 << 32;
269 #endif
270 	return (void *)addr;
271 }
272 
273 extern gdt_entry_t *get_gdt_entry(u16 sel);
274 extern gdt_entry_t *get_tss_descr(void);
275 gdt_entry_t *get_ldt_descr(void);
276 
277 extern unsigned long get_gdt_entry_base(gdt_entry_t *entry);
278 extern unsigned long get_gdt_entry_limit(gdt_entry_t *entry);
279 
280 #define __asm_safe(fep, insn, inputs...)				\
281 ({									\
282 	asm volatile(__ASM_TRY(fep, "1f")				\
283 		     insn "\n\t"					\
284 		     "1:\n\t"						\
285 		     :							\
286 		     : inputs						\
287 		     : "memory");					\
288 	exception_vector();						\
289 })
290 
291 #define asm_safe(insn, inputs...)					\
292 	__asm_safe("", insn, inputs)
293 
294 #define asm_fep_safe(insn, inputs...)				\
295 	__asm_safe_out1(KVM_FEP, insn,, inputs)
296 
297 #define __asm_safe_out1(fep, insn, output, inputs...)			\
298 ({									\
299 	asm volatile(__ASM_TRY(fep, "1f")				\
300 		     insn "\n\t"					\
301 		     "1:\n\t"						\
302 		     : output						\
303 		     : inputs						\
304 		     : "memory");					\
305 	exception_vector();						\
306 })
307 
308 #define asm_safe_out1(insn, output, inputs...)				\
309 	__asm_safe_out1("", insn, output, inputs)
310 
311 #define asm_fep_safe_out1(insn, output, inputs...)			\
312 	__asm_safe_out1(KVM_FEP, insn, output, inputs)
313 
314 #define __asm_safe_out2(fep, insn, output1, output2, inputs...)		\
315 ({									\
316 	asm volatile(__ASM_TRY(fep, "1f")				\
317 		     insn "\n\t"					\
318 		     "1:\n\t"						\
319 		     : output1, output2					\
320 		     : inputs						\
321 		     : "memory");					\
322 	exception_vector();						\
323 })
324 
325 #define asm_safe_out2(fep, insn, output1, output2, inputs...)		\
326 	__asm_safe_out2("", insn, output1, output2, inputs)
327 
328 #define asm_fep_safe_out2(insn, output1, output2, inputs...)		\
329 	__asm_safe_out2(KVM_FEP, insn, output1, output2, inputs)
330 
331 #define __asm_safe_report(want, insn, inputs...)			\
332 do {									\
333 	int vector = asm_safe(insn, inputs);				\
334 									\
335 	report(vector == want, "Expected %s on '%s', got %s",		\
336 	       want ? exception_mnemonic(want) : "SUCCESS",		\
337 	       insn,							\
338 	       vector ? exception_mnemonic(vector) : "SUCCESS");	\
339 } while (0)
340 
341 #define asm_safe_report(insn, inputs...)				\
342 	__asm_safe_report(0, insn, inputs)
343 
344 #define asm_safe_report_ex __asm_safe_report
345 
346 #endif
347