xref: /kvm-unit-tests/lib/x86/desc.h (revision c8a8a35827d7cda24021c18a95c1652c87805b62)
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