xref: /kvm-unit-tests/lib/x86/desc.h (revision 4c8a99ca02252d4a2bee43f4558fe47ce5ab7ec0)
1 #ifndef _X86_DESC_H_
2 #define _X86_DESC_H_
3 
4 #include <setjmp.h>
5 
6 #ifdef __ASSEMBLY__
7 #define __ASM_FORM(x, ...)	x,## __VA_ARGS__
8 #else
9 #define __ASM_FORM(x, ...)	" " xstr(x,##__VA_ARGS__) " "
10 #endif
11 
12 #ifndef __x86_64__
13 #define __ASM_SEL(a,b)		__ASM_FORM(a)
14 #else
15 #define __ASM_SEL(a,b)		__ASM_FORM(b)
16 #endif
17 
18 void setup_idt(void);
19 void load_idt(void);
20 void setup_alt_stack(void);
21 
22 struct ex_regs {
23 	unsigned long rax, rcx, rdx, rbx;
24 	unsigned long dummy, rbp, rsi, rdi;
25 #ifdef __x86_64__
26 	unsigned long r8, r9, r10, r11;
27 	unsigned long r12, r13, r14, r15;
28 #endif
29 	unsigned long vector;
30 	unsigned long error_code;
31 	unsigned long rip;
32 	unsigned long cs;
33 	unsigned long rflags;
34 #ifdef __x86_64__
35 	unsigned long rsp;
36 	unsigned long ss;
37 #endif
38 };
39 
40 typedef void (*handler)(struct ex_regs *regs);
41 
42 typedef struct {
43 	u16 prev;
44 	u16 res1;
45 	u32 esp0;
46 	u16 ss0;
47 	u16 res2;
48 	u32 esp1;
49 	u16 ss1;
50 	u16 res3;
51 	u32 esp2;
52 	u16 ss2;
53 	u16 res4;
54 	u32 cr3;
55 	u32 eip;
56 	u32 eflags;
57 	u32 eax, ecx, edx, ebx, esp, ebp, esi, edi;
58 	u16 es;
59 	u16 res5;
60 	u16 cs;
61 	u16 res6;
62 	u16 ss;
63 	u16 res7;
64 	u16 ds;
65 	u16 res8;
66 	u16 fs;
67 	u16 res9;
68 	u16 gs;
69 	u16 res10;
70 	u16 ldt;
71 	u16 res11;
72 	u16 t:1;
73 	u16 res12:15;
74 	u16 iomap_base;
75 } tss32_t;
76 
77 typedef struct  __attribute__((packed)) {
78 	u32 res1;
79 	u64 rsp0;
80 	u64 rsp1;
81 	u64 rsp2;
82 	u64 res2;
83 	u64 ist1;
84 	u64 ist2;
85 	u64 ist3;
86 	u64 ist4;
87 	u64 ist5;
88 	u64 ist6;
89 	u64 ist7;
90 	u64 res3;
91 	u16 res4;
92 	u16 iomap_base;
93 } tss64_t;
94 
95 #define __ASM_TRY(prefix, catch)				\
96 	"movl $0, %%gs:4\n\t"					\
97 	".pushsection .data.ex\n\t"				\
98 	__ASM_SEL(.long, .quad) " 1111f,  " catch "\n\t"	\
99 	".popsection \n\t"					\
100 	prefix "\n\t"						\
101 	"1111:"
102 
103 #define ASM_TRY(catch) __ASM_TRY("", catch)
104 
105 /* Forced emulation prefix, used to invoke the emulator unconditionally. */
106 #define KVM_FEP "ud2; .byte 'k', 'v', 'm';"
107 #define ASM_TRY_FEP(catch) __ASM_TRY(KVM_FEP, catch)
108 
109 static inline bool is_fep_available(void)
110 {
111 	/*
112 	 * Use the non-FEP ASM_TRY() as KVM will inject a #UD on the prefix
113 	 * itself if forced emulation is not available.
114 	 */
115 	asm goto(ASM_TRY("%l[fep_unavailable]")
116 		 KVM_FEP "nop\n\t"
117 		 ::: "memory" : fep_unavailable);
118 	return true;
119 fep_unavailable:
120 	return false;
121 }
122 
123 /*
124  * selector     32-bit                        64-bit
125  * 0x00         NULL descriptor               NULL descriptor
126  * 0x08         ring-0 code segment (32-bit)  ring-0 code segment (64-bit)
127  * 0x10         ring-0 data segment (32-bit)  ring-0 data segment (32/64-bit)
128  * 0x18         ring-0 code segment (P=0)     ring-0 code segment (64-bit, P=0)
129  * 0x20         intr_alt_stack TSS            ring-0 code segment (32-bit)
130  * 0x28         ring-0 code segment (16-bit)  same
131  * 0x30         ring-0 data segment (16-bit)  same
132  * 0x38 (0x3b)  ring-3 code segment (32-bit)  same
133  * 0x40 (0x43)  ring-3 data segment (32-bit)  ring-3 data segment (32/64-bit)
134  * 0x48 (0x4b)  **unused**                    ring-3 code segment (64-bit)
135  * 0x50-0x78    free to use for test cases    same
136  * 0x80-0x870   primary TSS (CPU 0..254)      same
137  * 0x878-0x1068 percpu area (CPU 0..254)      not used
138  *
139  * Note that the same segment can be used for 32-bit and 64-bit data segments
140  * (the L bit is only defined for code segments)
141  *
142  * Selectors 0x08-0x10 and 0x3b-0x4b are set up for use with the SYSCALL
143  * and SYSRET instructions.
144  */
145 
146 #define KERNEL_CS   0x08
147 #define KERNEL_DS   0x10
148 #define NP_SEL      0x18
149 #ifdef __x86_64__
150 #define KERNEL_CS32 0x20
151 #else
152 #define TSS_INTR    0x20
153 #endif
154 #define KERNEL_CS16 0x28
155 #define KERNEL_DS16 0x30
156 #define USER_CS32   0x3b
157 #define USER_DS     0x43
158 #ifdef __x86_64__
159 #define USER_CS64   0x4b
160 #endif
161 
162 /* Synonyms */
163 #define KERNEL_DS32 KERNEL_DS
164 #define USER_DS32   USER_DS
165 
166 #ifdef __x86_64__
167 #define KERNEL_CS64 KERNEL_CS
168 #define USER_CS     USER_CS64
169 #define KERNEL_DS64 KERNEL_DS
170 #define USER_DS64   USER_DS
171 #else
172 #define KERNEL_CS32 KERNEL_CS
173 #define USER_CS     USER_CS32
174 #endif
175 
176 #define FIRST_SPARE_SEL 0x50
177 #define TSS_MAIN 0x80
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 load_gdt_tss(size_t tss_offset);
250 void set_intr_alt_stack(int e, void *fn);
251 void print_current_tss_info(void);
252 handler handle_exception(u8 v, handler fn);
253 void unhandled_exception(struct ex_regs *regs, bool cpu);
254 const char* exception_mnemonic(int vector);
255 
256 bool test_for_exception(unsigned int ex, void (*trigger_func)(void *data),
257 			void *data);
258 void __set_exception_jmpbuf(jmp_buf *addr);
259 #define set_exception_jmpbuf(jmpbuf) \
260 	(setjmp(jmpbuf) ? : (__set_exception_jmpbuf(&(jmpbuf)), 0))
261 
262 static inline void *get_idt_addr(idt_entry_t *entry)
263 {
264 	uintptr_t addr = entry->offset0 | ((u32)entry->offset1 << 16);
265 #ifdef __x86_64__
266 	addr |= (u64)entry->offset2 << 32;
267 #endif
268 	return (void *)addr;
269 }
270 
271 extern gdt_entry_t *get_tss_descr(void);
272 extern unsigned long get_gdt_entry_base(gdt_entry_t *entry);
273 extern unsigned long get_gdt_entry_limit(gdt_entry_t *entry);
274 
275 #endif
276