xref: /kvm-unit-tests/lib/x86/desc.h (revision 486a097c9842b49be41daaa60ae919a5472dfa49)
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  
167  extern bool is_fep_available;
168  
169  typedef struct {
170  	unsigned short offset0;
171  	unsigned short selector;
172  	unsigned short ist : 3;
173  	unsigned short : 5;
174  	unsigned short type : 4;
175  	unsigned short : 1;
176  	unsigned short dpl : 2;
177  	unsigned short p : 1;
178  	unsigned short offset1;
179  #ifdef __x86_64__
180  	unsigned offset2;
181  	unsigned reserved;
182  #endif
183  } idt_entry_t;
184  
185  typedef struct {
186  	uint16_t limit1;
187  	uint16_t base1;
188  	uint8_t  base2;
189  	union {
190  		uint16_t  type_limit_flags;      /* Type and limit flags */
191  		struct {
192  			uint16_t type:4;
193  			uint16_t s:1;
194  			uint16_t dpl:2;
195  			uint16_t p:1;
196  			uint16_t limit2:4;
197  			uint16_t avl:1;
198  			uint16_t l:1;
199  			uint16_t db:1;
200  			uint16_t g:1;
201  		} __attribute__((__packed__));
202  	} __attribute__((__packed__));
203  	uint8_t  base3;
204  } __attribute__((__packed__)) gdt_entry_t;
205  
206  #ifdef __x86_64__
207  struct system_desc64 {
208  	gdt_entry_t common;
209  	uint32_t base4;
210  	uint32_t zero;
211  } __attribute__((__packed__));
212  #endif
213  
214  #define DESC_BUSY 2
215  
216  extern idt_entry_t boot_idt[256];
217  
218  #ifndef __x86_64__
219  extern tss32_t tss[];
220  extern tss32_t tss_intr;
221  void set_gdt_task_gate(u16 tss_sel, u16 sel);
222  void set_idt_task_gate(int vec, u16 sel);
223  void set_intr_task_gate(int vec, void *fn);
224  void setup_tss32(void);
225  #else
226  extern tss64_t tss[];
227  #endif
228  extern gdt_entry_t gdt[];
229  
230  unsigned exception_vector(void);
231  unsigned exception_error_code(void);
232  bool exception_rflags_rf(void);
233  void set_desc_entry(idt_entry_t *e, size_t e_sz, void *addr,
234  		    u16 sel, u16 type, u16 dpl);
235  void set_idt_entry(int vec, void *addr, int dpl);
236  void set_idt_sel(int vec, u16 sel);
237  void set_idt_dpl(int vec, u16 dpl);
238  void set_gdt_entry(int sel, unsigned long base, u32 limit, u8 access, u8 gran);
239  void set_gdt_entry_base(int sel, unsigned long base);
240  void clear_tss_busy(int sel);
241  void load_gdt_tss(size_t tss_offset);
242  void set_intr_alt_stack(int e, void *fn);
243  void print_current_tss_info(void);
244  handler handle_exception(u8 v, handler fn);
245  void unhandled_exception(struct ex_regs *regs, bool cpu);
246  const char* exception_mnemonic(int vector);
247  
248  bool test_for_exception(unsigned int ex, void (*trigger_func)(void *data),
249  			void *data);
250  void __set_exception_jmpbuf(jmp_buf *addr);
251  #define set_exception_jmpbuf(jmpbuf) \
252  	(setjmp(jmpbuf) ? : (__set_exception_jmpbuf(&(jmpbuf)), 0))
253  
get_idt_addr(idt_entry_t * entry)254  static inline void *get_idt_addr(idt_entry_t *entry)
255  {
256  	uintptr_t addr = entry->offset0 | ((u32)entry->offset1 << 16);
257  #ifdef __x86_64__
258  	addr |= (u64)entry->offset2 << 32;
259  #endif
260  	return (void *)addr;
261  }
262  
263  extern gdt_entry_t *get_gdt_entry(u16 sel);
264  extern gdt_entry_t *get_tss_descr(void);
265  gdt_entry_t *get_ldt_descr(void);
266  
267  extern unsigned long get_gdt_entry_base(gdt_entry_t *entry);
268  extern unsigned long get_gdt_entry_limit(gdt_entry_t *entry);
269  
270  #define __asm_safe(fep, insn, inputs...)				\
271  ({									\
272  	asm volatile(__ASM_TRY(fep, "1f")				\
273  		     insn "\n\t"					\
274  		     "1:\n\t"						\
275  		     :							\
276  		     : inputs						\
277  		     : "memory");					\
278  	exception_vector();						\
279  })
280  
281  #define asm_safe(insn, inputs...)					\
282  	__asm_safe("", insn, inputs)
283  
284  #define asm_fep_safe(insn, inputs...)				\
285  	__asm_safe_out1(KVM_FEP, insn,, inputs)
286  
287  #define __asm_safe_out1(fep, insn, output, inputs...)			\
288  ({									\
289  	asm volatile(__ASM_TRY(fep, "1f")				\
290  		     insn "\n\t"					\
291  		     "1:\n\t"						\
292  		     : output						\
293  		     : inputs						\
294  		     : "memory");					\
295  	exception_vector();						\
296  })
297  
298  #define asm_safe_out1(insn, output, inputs...)				\
299  	__asm_safe_out1("", insn, output, inputs)
300  
301  #define asm_fep_safe_out1(insn, output, inputs...)			\
302  	__asm_safe_out1(KVM_FEP, insn, output, inputs)
303  
304  #define __asm_safe_out2(fep, insn, output1, output2, inputs...)		\
305  ({									\
306  	asm volatile(__ASM_TRY(fep, "1f")				\
307  		     insn "\n\t"					\
308  		     "1:\n\t"						\
309  		     : output1, output2					\
310  		     : inputs						\
311  		     : "memory");					\
312  	exception_vector();						\
313  })
314  
315  #define asm_safe_out2(fep, insn, output1, output2, inputs...)		\
316  	__asm_safe_out2("", insn, output1, output2, inputs)
317  
318  #define asm_fep_safe_out2(insn, output1, output2, inputs...)		\
319  	__asm_safe_out2(KVM_FEP, insn, output1, output2, inputs)
320  
321  #define __asm_safe_report(want, insn, inputs...)			\
322  do {									\
323  	int vector = asm_safe(insn, inputs);				\
324  									\
325  	report(vector == want, "Expected %s on '%s', got %s",		\
326  	       want ? exception_mnemonic(want) : "SUCCESS",		\
327  	       insn,							\
328  	       vector ? exception_mnemonic(vector) : "SUCCESS");	\
329  } while (0)
330  
331  #define asm_safe_report(insn, inputs...)				\
332  	__asm_safe_report(0, insn, inputs)
333  
334  #define asm_safe_report_ex __asm_safe_report
335  
336  
337  #endif /* __ASSEMBLER__ */
338  
339  #endif /* _X86_DESC_H_ */
340