xref: /kvm-unit-tests/lib/x86/desc.c (revision c3b91807ccb653a5e58b01b5d355dbc7a27eab63)
17d36db35SAvi Kivity #include "libcflat.h"
2e7c37968SGleb Natapov #include "desc.h"
323ba7b39SGleb Natapov #include "processor.h"
47d36db35SAvi Kivity 
57d36db35SAvi Kivity typedef struct {
67d36db35SAvi Kivity     unsigned short offset0;
77d36db35SAvi Kivity     unsigned short selector;
87d36db35SAvi Kivity     unsigned short ist : 3;
97d36db35SAvi Kivity     unsigned short : 5;
107d36db35SAvi Kivity     unsigned short type : 4;
117d36db35SAvi Kivity     unsigned short : 1;
127d36db35SAvi Kivity     unsigned short dpl : 2;
137d36db35SAvi Kivity     unsigned short p : 1;
147d36db35SAvi Kivity     unsigned short offset1;
1523ba7b39SGleb Natapov #ifdef __x86_64__
167d36db35SAvi Kivity     unsigned offset2;
177d36db35SAvi Kivity     unsigned reserved;
1823ba7b39SGleb Natapov #endif
197d36db35SAvi Kivity } idt_entry_t;
207d36db35SAvi Kivity 
21d21b4f12SGleb Natapov typedef struct {
22d21b4f12SGleb Natapov 	u16 limit_low;
23d21b4f12SGleb Natapov 	u16 base_low;
24d21b4f12SGleb Natapov 	u8 base_middle;
25d21b4f12SGleb Natapov 	u8 access;
26d21b4f12SGleb Natapov 	u8 granularity;
27d21b4f12SGleb Natapov 	u8 base_high;
28d21b4f12SGleb Natapov } gdt_entry_t;
29d21b4f12SGleb Natapov 
30d21b4f12SGleb Natapov typedef struct {
31d21b4f12SGleb Natapov 	u16 prev;
32d21b4f12SGleb Natapov 	u16 res1;
33d21b4f12SGleb Natapov 	u32 esp0;
34d21b4f12SGleb Natapov 	u16 ss0;
35d21b4f12SGleb Natapov 	u16 res2;
36d21b4f12SGleb Natapov 	u32 esp1;
37d21b4f12SGleb Natapov 	u16 ss1;
38d21b4f12SGleb Natapov 	u16 res3;
39d21b4f12SGleb Natapov 	u32 esp2;
40d21b4f12SGleb Natapov 	u16 ss2;
41d21b4f12SGleb Natapov 	u16 res4;
42d21b4f12SGleb Natapov 	u32 cr3;
43d21b4f12SGleb Natapov 	u32 eip;
44d21b4f12SGleb Natapov 	u32 eflags;
45d21b4f12SGleb Natapov 	u32 eax, ecx, edx, ebx, esp, ebp, esi, edi;
46d21b4f12SGleb Natapov 	u16 es;
47d21b4f12SGleb Natapov 	u16 res5;
48d21b4f12SGleb Natapov 	u16 cs;
49d21b4f12SGleb Natapov 	u16 res6;
50d21b4f12SGleb Natapov 	u16 ss;
51d21b4f12SGleb Natapov 	u16 res7;
52d21b4f12SGleb Natapov 	u16 ds;
53d21b4f12SGleb Natapov 	u16 res8;
54d21b4f12SGleb Natapov 	u16 fs;
55d21b4f12SGleb Natapov 	u16 res9;
56d21b4f12SGleb Natapov 	u16 gs;
57d21b4f12SGleb Natapov 	u16 res10;
58d21b4f12SGleb Natapov 	u16 ldt;
59d21b4f12SGleb Natapov 	u16 res11;
60d21b4f12SGleb Natapov 	u16 t:1;
61d21b4f12SGleb Natapov 	u16 res12:15;
62d21b4f12SGleb Natapov 	u16 iomap_base;
63d21b4f12SGleb Natapov } tss32_t;
64d21b4f12SGleb Natapov 
657d36db35SAvi Kivity static idt_entry_t idt[256];
667d36db35SAvi Kivity 
6723ba7b39SGleb Natapov void load_lidt(idt_entry_t *idt, int nentries)
687d36db35SAvi Kivity {
6923ba7b39SGleb Natapov     struct descriptor_table_ptr dt;
707d36db35SAvi Kivity 
717d36db35SAvi Kivity     dt.limit = nentries * sizeof(*idt) - 1;
7223ba7b39SGleb Natapov     dt.base = (unsigned long)idt;
7323ba7b39SGleb Natapov     lidt(&dt);
747d36db35SAvi Kivity     asm volatile ("lidt %0" : : "m"(dt));
757d36db35SAvi Kivity }
767d36db35SAvi Kivity 
7723ba7b39SGleb Natapov void set_idt_entry(int vec, void *addr, int dpl)
787d36db35SAvi Kivity {
7923ba7b39SGleb Natapov     idt_entry_t *e = &idt[vec];
807d36db35SAvi Kivity     memset(e, 0, sizeof *e);
817d36db35SAvi Kivity     e->offset0 = (unsigned long)addr;
827d36db35SAvi Kivity     e->selector = read_cs();
837d36db35SAvi Kivity     e->ist = 0;
847d36db35SAvi Kivity     e->type = 14;
857d36db35SAvi Kivity     e->dpl = dpl;
867d36db35SAvi Kivity     e->p = 1;
877d36db35SAvi Kivity     e->offset1 = (unsigned long)addr >> 16;
8823ba7b39SGleb Natapov #ifdef __x86_64__
897d36db35SAvi Kivity     e->offset2 = (unsigned long)addr >> 32;
9023ba7b39SGleb Natapov #endif
917d36db35SAvi Kivity }
927d36db35SAvi Kivity 
937d36db35SAvi Kivity struct ex_regs {
947d36db35SAvi Kivity     unsigned long rax, rcx, rdx, rbx;
957d36db35SAvi Kivity     unsigned long dummy, rbp, rsi, rdi;
9623ba7b39SGleb Natapov #ifdef __x86_64__
977d36db35SAvi Kivity     unsigned long r8, r9, r10, r11;
987d36db35SAvi Kivity     unsigned long r12, r13, r14, r15;
9923ba7b39SGleb Natapov #endif
1007d36db35SAvi Kivity     unsigned long vector;
1017d36db35SAvi Kivity     unsigned long error_code;
1027d36db35SAvi Kivity     unsigned long rip;
1037d36db35SAvi Kivity     unsigned long cs;
1047d36db35SAvi Kivity     unsigned long rflags;
1057d36db35SAvi Kivity };
1067d36db35SAvi Kivity 
1077d36db35SAvi Kivity struct ex_record {
1087d36db35SAvi Kivity     unsigned long rip;
1097d36db35SAvi Kivity     unsigned long handler;
1107d36db35SAvi Kivity };
1117d36db35SAvi Kivity 
1127d36db35SAvi Kivity extern struct ex_record exception_table_start, exception_table_end;
1137d36db35SAvi Kivity 
114*c3b91807SGleb Natapov #ifndef __x86_64__
115*c3b91807SGleb Natapov __attribute__((regparm(1)))
116*c3b91807SGleb Natapov #endif
1177d36db35SAvi Kivity void do_handle_exception(struct ex_regs *regs)
1187d36db35SAvi Kivity {
1197d36db35SAvi Kivity     struct ex_record *ex;
1207d36db35SAvi Kivity     unsigned ex_val;
1217d36db35SAvi Kivity 
1227d36db35SAvi Kivity     ex_val = regs->vector | (regs->error_code << 16);
1237d36db35SAvi Kivity 
1247d36db35SAvi Kivity     asm("mov %0, %%gs:4" : : "r"(ex_val));
1257d36db35SAvi Kivity 
1267d36db35SAvi Kivity     for (ex = &exception_table_start; ex != &exception_table_end; ++ex) {
1277d36db35SAvi Kivity         if (ex->rip == regs->rip) {
1287d36db35SAvi Kivity             regs->rip = ex->handler;
1297d36db35SAvi Kivity             return;
1307d36db35SAvi Kivity         }
1317d36db35SAvi Kivity     }
1327d36db35SAvi Kivity     printf("unhandled excecption\n");
1337d36db35SAvi Kivity     exit(7);
1347d36db35SAvi Kivity }
1357d36db35SAvi Kivity 
13623ba7b39SGleb Natapov #ifdef __x86_64__
13723ba7b39SGleb Natapov #  define R "r"
13823ba7b39SGleb Natapov #  define W "q"
13923ba7b39SGleb Natapov #  define S "8"
14023ba7b39SGleb Natapov #else
14123ba7b39SGleb Natapov #  define R "e"
14223ba7b39SGleb Natapov #  define W "l"
14323ba7b39SGleb Natapov #  define S "4"
14423ba7b39SGleb Natapov #endif
14523ba7b39SGleb Natapov 
1467d36db35SAvi Kivity asm (".pushsection .text \n\t"
1477d36db35SAvi Kivity      "ud_fault: \n\t"
14823ba7b39SGleb Natapov      "push"W" $0 \n\t"
14923ba7b39SGleb Natapov      "push"W" $6 \n\t"
1507d36db35SAvi Kivity      "jmp handle_exception \n\t"
1517d36db35SAvi Kivity 
1527d36db35SAvi Kivity      "gp_fault: \n\t"
15323ba7b39SGleb Natapov      "push"W" $13 \n\t"
1547d36db35SAvi Kivity      "jmp handle_exception \n\t"
1557d36db35SAvi Kivity 
156597e0ef2SAvi Kivity      "de_fault: \n\t"
15723ba7b39SGleb Natapov      "push"W" $0 \n\t"
15823ba7b39SGleb Natapov      "push"W" $0 \n\t"
159597e0ef2SAvi Kivity      "jmp handle_exception \n\t"
160597e0ef2SAvi Kivity 
1617d36db35SAvi Kivity      "handle_exception: \n\t"
16223ba7b39SGleb Natapov #ifdef __x86_64__
1637d36db35SAvi Kivity      "push %r15; push %r14; push %r13; push %r12 \n\t"
1647d36db35SAvi Kivity      "push %r11; push %r10; push %r9; push %r8 \n\t"
16523ba7b39SGleb Natapov #endif
16623ba7b39SGleb Natapov      "push %"R"di; push %"R"si; push %"R"bp; sub $"S", %"R"sp \n\t"
16723ba7b39SGleb Natapov      "push %"R"bx; push %"R"dx; push %"R"cx; push %"R"ax \n\t"
168*c3b91807SGleb Natapov #ifdef __x86_64__
16923ba7b39SGleb Natapov      "mov %"R"sp, %"R"di \n\t"
170*c3b91807SGleb Natapov #else
171*c3b91807SGleb Natapov      "mov %"R"sp, %"R"ax \n\t"
172*c3b91807SGleb Natapov #endif
1737d36db35SAvi Kivity      "call do_handle_exception \n\t"
17423ba7b39SGleb Natapov      "pop %"R"ax; pop %"R"cx; pop %"R"dx; pop %"R"bx \n\t"
17523ba7b39SGleb Natapov      "add $"S", %"R"sp; pop %"R"bp; pop %"R"si; pop %"R"di \n\t"
17623ba7b39SGleb Natapov #ifdef __x86_64__
1777d36db35SAvi Kivity      "pop %r8; pop %r9; pop %r10; pop %r11 \n\t"
1787d36db35SAvi Kivity      "pop %r12; pop %r13; pop %r14; pop %r15 \n\t"
17923ba7b39SGleb Natapov #endif
18023ba7b39SGleb Natapov      "add $"S", %"R"sp \n\t"
18123ba7b39SGleb Natapov      "add $"S", %"R"sp \n\t"
18223ba7b39SGleb Natapov      "iret"W" \n\t"
1837d36db35SAvi Kivity      ".popsection");
1847d36db35SAvi Kivity 
1857d36db35SAvi Kivity 
1867d36db35SAvi Kivity void setup_idt(void)
1877d36db35SAvi Kivity {
188597e0ef2SAvi Kivity     extern char ud_fault, gp_fault, de_fault;
1897d36db35SAvi Kivity 
19023ba7b39SGleb Natapov     load_lidt(idt, 256);
19123ba7b39SGleb Natapov     set_idt_entry(0, &de_fault, 0);
19223ba7b39SGleb Natapov     set_idt_entry(6, &ud_fault, 0);
19323ba7b39SGleb Natapov     set_idt_entry(13, &gp_fault, 0);
1947d36db35SAvi Kivity }
1957d36db35SAvi Kivity 
1967d36db35SAvi Kivity unsigned exception_vector(void)
1977d36db35SAvi Kivity {
1987d36db35SAvi Kivity     unsigned short vector;
1997d36db35SAvi Kivity 
2007d36db35SAvi Kivity     asm("mov %%gs:4, %0" : "=rm"(vector));
2017d36db35SAvi Kivity     return vector;
2027d36db35SAvi Kivity }
2037d36db35SAvi Kivity 
2047d36db35SAvi Kivity unsigned exception_error_code(void)
2057d36db35SAvi Kivity {
2067d36db35SAvi Kivity     unsigned short error_code;
2077d36db35SAvi Kivity 
2087d36db35SAvi Kivity     asm("mov %%gs:6, %0" : "=rm"(error_code));
2097d36db35SAvi Kivity     return error_code;
2107d36db35SAvi Kivity }
211d21b4f12SGleb Natapov 
212d21b4f12SGleb Natapov #ifndef __x86_64__
213d21b4f12SGleb Natapov /*
214d21b4f12SGleb Natapov  * GDT, with 6 entries:
215d21b4f12SGleb Natapov  * 0x00 - NULL descriptor
216d21b4f12SGleb Natapov  * 0x08 - Code segment
217d21b4f12SGleb Natapov  * 0x10 - Data segment
218d21b4f12SGleb Natapov  * 0x18 - Not presend code segment
219d21b4f12SGleb Natapov  * 0x20 - Primery task
220d21b4f12SGleb Natapov  * 0x28 - Interrupt task
221d21b4f12SGleb Natapov  */
222d21b4f12SGleb Natapov 
223d21b4f12SGleb Natapov static gdt_entry_t gdt[6];
224d21b4f12SGleb Natapov #define TSS_GDT_OFFSET 4
225d21b4f12SGleb Natapov 
226d21b4f12SGleb Natapov void set_gdt_entry(int num, u32 base,  u32 limit, u8 access, u8 gran)
227d21b4f12SGleb Natapov {
228d21b4f12SGleb Natapov 	/* Setup the descriptor base address */
229d21b4f12SGleb Natapov 	gdt[num].base_low = (base & 0xFFFF);
230d21b4f12SGleb Natapov 	gdt[num].base_middle = (base >> 16) & 0xFF;
231d21b4f12SGleb Natapov 	gdt[num].base_high = (base >> 24) & 0xFF;
232d21b4f12SGleb Natapov 
233d21b4f12SGleb Natapov 	/* Setup the descriptor limits */
234d21b4f12SGleb Natapov 	gdt[num].limit_low = (limit & 0xFFFF);
235d21b4f12SGleb Natapov 	gdt[num].granularity = ((limit >> 16) & 0x0F);
236d21b4f12SGleb Natapov 
237d21b4f12SGleb Natapov 	/* Finally, set up the granularity and access flags */
238d21b4f12SGleb Natapov 	gdt[num].granularity |= (gran & 0xF0);
239d21b4f12SGleb Natapov 	gdt[num].access = access;
240d21b4f12SGleb Natapov }
241d21b4f12SGleb Natapov 
242d21b4f12SGleb Natapov void setup_gdt(void)
243d21b4f12SGleb Natapov {
244d21b4f12SGleb Natapov 	struct descriptor_table_ptr gp;
245d21b4f12SGleb Natapov 	/* Setup the GDT pointer and limit */
246d21b4f12SGleb Natapov 	gp.limit = sizeof(gdt) - 1;
247d21b4f12SGleb Natapov 	gp.base = (ulong)&gdt;
248d21b4f12SGleb Natapov 
249d21b4f12SGleb Natapov 	memset(gdt, 0, sizeof(gdt));
250d21b4f12SGleb Natapov 
251d21b4f12SGleb Natapov 	/* Our NULL descriptor */
252d21b4f12SGleb Natapov 	set_gdt_entry(0, 0, 0, 0, 0);
253d21b4f12SGleb Natapov 
254d21b4f12SGleb Natapov 	/* The second entry is our Code Segment. The base address
255d21b4f12SGleb Natapov 	 *  is 0, the limit is 4GBytes, it uses 4KByte granularity,
256d21b4f12SGleb Natapov 	 *  uses 32-bit opcodes, and is a Code Segment descriptor. */
257d21b4f12SGleb Natapov 	set_gdt_entry(1, 0, 0xFFFFFFFF, 0x9A, 0xcf);
258d21b4f12SGleb Natapov 
259d21b4f12SGleb Natapov 	/* The third entry is our Data Segment. It's EXACTLY the
260d21b4f12SGleb Natapov 	 *  same as our code segment, but the descriptor type in
261d21b4f12SGleb Natapov 	 *  this entry's access byte says it's a Data Segment */
262d21b4f12SGleb Natapov 	set_gdt_entry(2, 0, 0xFFFFFFFF, 0x92, 0xcf);
263d21b4f12SGleb Natapov 
264d21b4f12SGleb Natapov 	/* Same as code register above but not present */
265d21b4f12SGleb Natapov 	set_gdt_entry(3, 0, 0xFFFFFFFF, 0x1A, 0xcf);
266d21b4f12SGleb Natapov 
267d21b4f12SGleb Natapov 
268d21b4f12SGleb Natapov 	/* Flush out the old GDT and install the new changes! */
269d21b4f12SGleb Natapov 	lgdt(&gp);
270d21b4f12SGleb Natapov 
271d21b4f12SGleb Natapov 	asm volatile ("mov %0, %%ds\n\t"
272d21b4f12SGleb Natapov 		      "mov %0, %%es\n\t"
273d21b4f12SGleb Natapov 		      "mov %0, %%fs\n\t"
274d21b4f12SGleb Natapov 		      "mov %0, %%gs\n\t"
275d21b4f12SGleb Natapov 		      "mov %0, %%ss\n\t"
276d21b4f12SGleb Natapov 		      "jmp $0x08, $.Lflush2\n\t"
277d21b4f12SGleb Natapov 		      ".Lflush2: "::"r"(0x10));
278d21b4f12SGleb Natapov }
279d21b4f12SGleb Natapov 
280d21b4f12SGleb Natapov static void set_idt_task_gate(int vec, u16 sel)
281d21b4f12SGleb Natapov {
282d21b4f12SGleb Natapov     idt_entry_t *e = &idt[vec];
283d21b4f12SGleb Natapov 
284d21b4f12SGleb Natapov     memset(e, 0, sizeof *e);
285d21b4f12SGleb Natapov 
286d21b4f12SGleb Natapov     e->selector = sel;
287d21b4f12SGleb Natapov     e->ist = 0;
288d21b4f12SGleb Natapov     e->type = 5;
289d21b4f12SGleb Natapov     e->dpl = 0;
290d21b4f12SGleb Natapov     e->p = 1;
291d21b4f12SGleb Natapov }
292d21b4f12SGleb Natapov 
293d21b4f12SGleb Natapov /*
294d21b4f12SGleb Natapov  * 0 - main task
295d21b4f12SGleb Natapov  * 1 - interrupt task
296d21b4f12SGleb Natapov  */
297d21b4f12SGleb Natapov 
298d21b4f12SGleb Natapov static tss32_t tss[2];
299d21b4f12SGleb Natapov static char tss_stack[2][4096];
300d21b4f12SGleb Natapov 
301d21b4f12SGleb Natapov void setup_tss32(void)
302d21b4f12SGleb Natapov {
303d21b4f12SGleb Natapov 	u16 desc_size = sizeof(tss32_t);
304d21b4f12SGleb Natapov 	int i;
305d21b4f12SGleb Natapov 
306d21b4f12SGleb Natapov 	for (i = 0; i < 2; i++) {
307d21b4f12SGleb Natapov 		tss[i].cr3 = read_cr3();
308d21b4f12SGleb Natapov 		tss[i].ss0 = tss[i].ss1 = tss[i].ss2 = 0x10;
309d21b4f12SGleb Natapov 		tss[i].esp = tss[i].esp0 = tss[i].esp1 = tss[i].esp2 =
310d21b4f12SGleb Natapov 			(u32)tss_stack[i];
311d21b4f12SGleb Natapov 		tss[i].cs = 0x08;
312d21b4f12SGleb Natapov 		tss[i].ds = tss[i].es = tss[i].fs = tss[i].gs = tss[i].ss = 0x10;
313d21b4f12SGleb Natapov 		tss[i].iomap_base = (u16)desc_size;
314d21b4f12SGleb Natapov 		set_gdt_entry(TSS_GDT_OFFSET + i, (u32)&tss[i],
315d21b4f12SGleb Natapov 			     desc_size - 1, 0x89, 0x0f);
316d21b4f12SGleb Natapov 	}
317d21b4f12SGleb Natapov 
318d21b4f12SGleb Natapov 	ltr(TSS_MAIN);
319d21b4f12SGleb Natapov }
320d21b4f12SGleb Natapov 
321d21b4f12SGleb Natapov void set_intr_task_gate(int e, void *fn)
322d21b4f12SGleb Natapov {
323d21b4f12SGleb Natapov 	tss[1].eip = (u32)fn;
324d21b4f12SGleb Natapov 	set_idt_task_gate(e, TSS_INTR);
325d21b4f12SGleb Natapov }
326d21b4f12SGleb Natapov 
327d21b4f12SGleb Natapov void print_current_tss_info(void)
328d21b4f12SGleb Natapov {
329d21b4f12SGleb Natapov 	u16 tr = str();
330d21b4f12SGleb Natapov 	int i = (tr == TSS_MAIN) ? 0 : 1;
331d21b4f12SGleb Natapov 
332d21b4f12SGleb Natapov 	if (tr != TSS_MAIN && tr != TSS_INTR)
333d21b4f12SGleb Natapov 		printf("Unknown TSS %x\n", tr);
334d21b4f12SGleb Natapov 	else
335d21b4f12SGleb Natapov 		printf("TR=%x Main TSS back link %x. Current TSS back link %x\n",
336d21b4f12SGleb Natapov                tr, tss[0].prev, tss[i].prev);
337d21b4f12SGleb Natapov }
338d21b4f12SGleb Natapov #endif
339