xref: /kvm-unit-tests/lib/x86/desc.h (revision 0b7501c3b516bde6bd3d74b17e6af76b6aa2a116)
1 #ifndef _X86_DESC_H_
2 #define _X86_DESC_H_
3 
4 #include <setjmp.h>
5 
6 void setup_idt(void);
7 void load_idt(void);
8 void setup_alt_stack(void);
9 
10 struct ex_regs {
11 	unsigned long rax, rcx, rdx, rbx;
12 	unsigned long dummy, rbp, rsi, rdi;
13 #ifdef __x86_64__
14 	unsigned long r8, r9, r10, r11;
15 	unsigned long r12, r13, r14, r15;
16 #endif
17 	unsigned long vector;
18 	unsigned long error_code;
19 	unsigned long rip;
20 	unsigned long cs;
21 	unsigned long rflags;
22 #ifdef __x86_64__
23 	unsigned long rsp;
24 	unsigned long ss;
25 #endif
26 };
27 
28 typedef void (*handler)(struct ex_regs *regs);
29 
30 typedef struct {
31 	u16 prev;
32 	u16 res1;
33 	u32 esp0;
34 	u16 ss0;
35 	u16 res2;
36 	u32 esp1;
37 	u16 ss1;
38 	u16 res3;
39 	u32 esp2;
40 	u16 ss2;
41 	u16 res4;
42 	u32 cr3;
43 	u32 eip;
44 	u32 eflags;
45 	u32 eax, ecx, edx, ebx, esp, ebp, esi, edi;
46 	u16 es;
47 	u16 res5;
48 	u16 cs;
49 	u16 res6;
50 	u16 ss;
51 	u16 res7;
52 	u16 ds;
53 	u16 res8;
54 	u16 fs;
55 	u16 res9;
56 	u16 gs;
57 	u16 res10;
58 	u16 ldt;
59 	u16 res11;
60 	u16 t:1;
61 	u16 res12:15;
62 	u16 iomap_base;
63 } tss32_t;
64 
65 typedef struct  __attribute__((packed)) {
66 	u32 res1;
67 	u64 rsp0;
68 	u64 rsp1;
69 	u64 rsp2;
70 	u64 res2;
71 	u64 ist1;
72 	u64 ist2;
73 	u64 ist3;
74 	u64 ist4;
75 	u64 ist5;
76 	u64 ist6;
77 	u64 ist7;
78 	u64 res3;
79 	u16 res4;
80 	u16 iomap_base;
81 } tss64_t;
82 
83 #ifdef __x86_64
84 #define ASM_TRY(catch)			\
85 	"movl $0, %%gs:4 \n\t"		\
86 	".pushsection .data.ex \n\t"	\
87 	".quad 1111f, " catch "\n\t"	\
88 	".popsection \n\t"		\
89 	"1111:"
90 #else
91 #define ASM_TRY(catch)			\
92 	"movl $0, %%gs:4 \n\t"		\
93 	".pushsection .data.ex \n\t"	\
94 	".long 1111f, " catch "\n\t"	\
95 	".popsection \n\t"		\
96 	"1111:"
97 #endif
98 
99 /*
100  * selector     32-bit                        64-bit
101  * 0x00         NULL descriptor               NULL descriptor
102  * 0x08         ring-0 code segment (32-bit)  ring-0 code segment (64-bit)
103  * 0x10         ring-0 data segment (32-bit)  ring-0 data segment (32/64-bit)
104  * 0x18         ring-0 code segment (P=0)     ring-0 code segment (64-bit, P=0)
105  * 0x20         intr_alt_stack TSS            ring-0 code segment (32-bit)
106  * 0x28         ring-0 code segment (16-bit)  same
107  * 0x30         ring-0 data segment (16-bit)  same
108  * 0x38 (0x3b)  ring-3 code segment (32-bit)  same
109  * 0x40 (0x43)  ring-3 data segment (32-bit)  ring-3 data segment (32/64-bit)
110  * 0x48 (0x4b)  **unused**                    ring-3 code segment (64-bit)
111  * 0x50-0x78    free to use for test cases    same
112  * 0x80-0x870   primary TSS (CPU 0..254)      same
113  * 0x878-0x1068 percpu area (CPU 0..254)      not used
114  *
115  * Note that the same segment can be used for 32-bit and 64-bit data segments
116  * (the L bit is only defined for code segments)
117  *
118  * Selectors 0x08-0x10 and 0x3b-0x4b are set up for use with the SYSCALL
119  * and SYSRET instructions.
120  */
121 
122 #define KERNEL_CS   0x08
123 #define KERNEL_DS   0x10
124 #define NP_SEL      0x18
125 #ifdef __x86_64__
126 #define KERNEL_CS32 0x20
127 #else
128 #define TSS_INTR    0x20
129 #endif
130 #define KERNEL_CS16 0x28
131 #define KERNEL_DS16 0x30
132 #define USER_CS32   0x3b
133 #define USER_DS     0x43
134 #ifdef __x86_64__
135 #define USER_CS64   0x4b
136 #endif
137 
138 /* Synonyms */
139 #define KERNEL_DS32 KERNEL_DS
140 #define USER_DS32   USER_DS
141 
142 #ifdef __x86_64__
143 #define KERNEL_CS64 KERNEL_CS
144 #define USER_CS     USER_CS64
145 #define KERNEL_DS64 KERNEL_DS
146 #define USER_DS64   USER_DS
147 #else
148 #define KERNEL_CS32 KERNEL_CS
149 #define USER_CS     USER_CS32
150 #endif
151 
152 #define FIRST_SPARE_SEL 0x50
153 #define TSS_MAIN 0x80
154 
155 typedef struct {
156 	unsigned short offset0;
157 	unsigned short selector;
158 	unsigned short ist : 3;
159 	unsigned short : 5;
160 	unsigned short type : 4;
161 	unsigned short : 1;
162 	unsigned short dpl : 2;
163 	unsigned short p : 1;
164 	unsigned short offset1;
165 #ifdef __x86_64__
166 	unsigned offset2;
167 	unsigned reserved;
168 #endif
169 } idt_entry_t;
170 
171 typedef struct {
172 	uint16_t limit1;
173 	uint16_t base1;
174 	uint8_t  base2;
175 	union {
176 		uint16_t  type_limit_flags;      /* Type and limit flags */
177 		struct {
178 			uint16_t type:4;
179 			uint16_t s:1;
180 			uint16_t dpl:2;
181 			uint16_t p:1;
182 			uint16_t limit2:4;
183 			uint16_t avl:1;
184 			uint16_t l:1;
185 			uint16_t db:1;
186 			uint16_t g:1;
187 		} __attribute__((__packed__));
188 	} __attribute__((__packed__));
189 	uint8_t  base3;
190 } __attribute__((__packed__)) gdt_entry_t;
191 
192 #ifdef __x86_64__
193 struct system_desc64 {
194 	gdt_entry_t common;
195 	uint32_t base4;
196 	uint32_t zero;
197 } __attribute__((__packed__));
198 #endif
199 
200 #define DESC_BUSY 2
201 
202 extern idt_entry_t boot_idt[256];
203 
204 #ifndef __x86_64__
205 extern tss32_t tss[];
206 extern tss32_t tss_intr;
207 void set_gdt_task_gate(u16 tss_sel, u16 sel);
208 void set_idt_task_gate(int vec, u16 sel);
209 void set_intr_task_gate(int vec, void *fn);
210 void setup_tss32(void);
211 #else
212 extern tss64_t tss[];
213 #endif
214 extern gdt_entry_t gdt[];
215 
216 unsigned exception_vector(void);
217 int write_cr4_checking(unsigned long val);
218 unsigned exception_error_code(void);
219 bool exception_rflags_rf(void);
220 void set_desc_entry(idt_entry_t *e, size_t e_sz, void *addr,
221 		    u16 sel, u16 type, u16 dpl);
222 void set_idt_entry(int vec, void *addr, int dpl);
223 void set_idt_sel(int vec, u16 sel);
224 void set_idt_dpl(int vec, u16 dpl);
225 void set_gdt_entry(int sel, unsigned long base, u32 limit, u8 access, u8 gran);
226 void load_gdt_tss(size_t tss_offset);
227 void set_intr_alt_stack(int e, void *fn);
228 void print_current_tss_info(void);
229 handler handle_exception(u8 v, handler fn);
230 void unhandled_exception(struct ex_regs *regs, bool cpu);
231 const char* exception_mnemonic(int vector);
232 
233 bool test_for_exception(unsigned int ex, void (*trigger_func)(void *data),
234 			void *data);
235 void __set_exception_jmpbuf(jmp_buf *addr);
236 #define set_exception_jmpbuf(jmpbuf) \
237 	(setjmp(jmpbuf) ? : (__set_exception_jmpbuf(&(jmpbuf)), 0))
238 
239 static inline void *get_idt_addr(idt_entry_t *entry)
240 {
241 	uintptr_t addr = entry->offset0 | ((u32)entry->offset1 << 16);
242 #ifdef __x86_64__
243 	addr |= (u64)entry->offset2 << 32;
244 #endif
245 	return (void *)addr;
246 }
247 
248 extern gdt_entry_t *get_tss_descr(void);
249 extern unsigned long get_gdt_entry_base(gdt_entry_t *entry);
250 extern unsigned long get_gdt_entry_limit(gdt_entry_t *entry);
251 
252 #endif
253