xref: /kvm-unit-tests/lib/x86/desc.c (revision b01c882353a20133a3a9ad9bc2fa6fcce3b17471)
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 
301d946e07SAvi Kivity extern idt_entry_t boot_idt[256];
317d36db35SAvi Kivity 
3223ba7b39SGleb Natapov void set_idt_entry(int vec, void *addr, int dpl)
337d36db35SAvi Kivity {
341d946e07SAvi Kivity     idt_entry_t *e = &boot_idt[vec];
357d36db35SAvi Kivity     memset(e, 0, sizeof *e);
367d36db35SAvi Kivity     e->offset0 = (unsigned long)addr;
377d36db35SAvi Kivity     e->selector = read_cs();
387d36db35SAvi Kivity     e->ist = 0;
397d36db35SAvi Kivity     e->type = 14;
407d36db35SAvi Kivity     e->dpl = dpl;
417d36db35SAvi Kivity     e->p = 1;
427d36db35SAvi Kivity     e->offset1 = (unsigned long)addr >> 16;
4323ba7b39SGleb Natapov #ifdef __x86_64__
447d36db35SAvi Kivity     e->offset2 = (unsigned long)addr >> 32;
4523ba7b39SGleb Natapov #endif
467d36db35SAvi Kivity }
477d36db35SAvi Kivity 
48a4b87a16SGleb Natapov void set_idt_sel(int vec, u16 sel)
49a4b87a16SGleb Natapov {
501d946e07SAvi Kivity     idt_entry_t *e = &boot_idt[vec];
51a4b87a16SGleb Natapov     e->selector = sel;
52a4b87a16SGleb Natapov }
537d36db35SAvi Kivity 
547d36db35SAvi Kivity struct ex_record {
557d36db35SAvi Kivity     unsigned long rip;
567d36db35SAvi Kivity     unsigned long handler;
577d36db35SAvi Kivity };
587d36db35SAvi Kivity 
597d36db35SAvi Kivity extern struct ex_record exception_table_start, exception_table_end;
607d36db35SAvi Kivity 
61af11bd88SGleb Natapov static void check_exception_table(struct ex_regs *regs)
627d36db35SAvi Kivity {
637d36db35SAvi Kivity     struct ex_record *ex;
647d36db35SAvi Kivity     unsigned ex_val;
657d36db35SAvi Kivity 
667d36db35SAvi Kivity     ex_val = regs->vector | (regs->error_code << 16);
677d36db35SAvi Kivity 
687d36db35SAvi Kivity     asm("mov %0, %%gs:4" : : "r"(ex_val));
697d36db35SAvi Kivity 
707d36db35SAvi Kivity     for (ex = &exception_table_start; ex != &exception_table_end; ++ex) {
717d36db35SAvi Kivity         if (ex->rip == regs->rip) {
727d36db35SAvi Kivity             regs->rip = ex->handler;
737d36db35SAvi Kivity             return;
747d36db35SAvi Kivity         }
757d36db35SAvi Kivity     }
76af11bd88SGleb Natapov     printf("unhandled excecption %d\n", regs->vector);
77af11bd88SGleb Natapov     exit(7);
78af11bd88SGleb Natapov }
79af11bd88SGleb Natapov 
80af11bd88SGleb Natapov static void (*exception_handlers[32])(struct ex_regs *regs);
81af11bd88SGleb Natapov 
82af11bd88SGleb Natapov 
83af11bd88SGleb Natapov void handle_exception(u8 v, void (*func)(struct ex_regs *regs))
84af11bd88SGleb Natapov {
85af11bd88SGleb Natapov 	if (v < 32)
86af11bd88SGleb Natapov 		exception_handlers[v] = func;
87af11bd88SGleb Natapov }
88af11bd88SGleb Natapov 
89af11bd88SGleb Natapov #ifndef __x86_64__
90af11bd88SGleb Natapov __attribute__((regparm(1)))
91af11bd88SGleb Natapov #endif
92af11bd88SGleb Natapov void do_handle_exception(struct ex_regs *regs)
93af11bd88SGleb Natapov {
94af11bd88SGleb Natapov 	if (regs->vector < 32 && exception_handlers[regs->vector]) {
95af11bd88SGleb Natapov 		exception_handlers[regs->vector](regs);
96af11bd88SGleb Natapov 		return;
97af11bd88SGleb Natapov 	}
98af11bd88SGleb Natapov 	printf("unhandled cpu excecption %d\n", regs->vector);
99af11bd88SGleb Natapov 	if (regs->vector == 14)
100af11bd88SGleb Natapov 		printf("PF at %p addr %p\n", regs->rip, read_cr2());
1017d36db35SAvi Kivity 	exit(7);
1027d36db35SAvi Kivity }
1037d36db35SAvi Kivity 
10423ba7b39SGleb Natapov #ifdef __x86_64__
10523ba7b39SGleb Natapov #  define R "r"
10623ba7b39SGleb Natapov #  define W "q"
10723ba7b39SGleb Natapov #  define S "8"
10823ba7b39SGleb Natapov #else
10923ba7b39SGleb Natapov #  define R "e"
11023ba7b39SGleb Natapov #  define W "l"
11123ba7b39SGleb Natapov #  define S "4"
11223ba7b39SGleb Natapov #endif
11323ba7b39SGleb Natapov 
114af11bd88SGleb Natapov #define EX(NAME, N) extern char NAME##_fault;	\
115af11bd88SGleb Natapov 	asm (".pushsection .text \n\t"		\
116af11bd88SGleb Natapov 	     #NAME"_fault: \n\t"		\
117af11bd88SGleb Natapov 	     "push"W" $0 \n\t"			\
118af11bd88SGleb Natapov 	     "push"W" $"#N" \n\t"		\
119af11bd88SGleb Natapov 	     "jmp __handle_exception \n\t"	\
120af11bd88SGleb Natapov 	     ".popsection")
121af11bd88SGleb Natapov 
122af11bd88SGleb Natapov #define EX_E(NAME, N) extern char NAME##_fault;	\
123af11bd88SGleb Natapov 	asm (".pushsection .text \n\t"		\
124af11bd88SGleb Natapov 	     #NAME"_fault: \n\t"		\
125af11bd88SGleb Natapov 	     "push"W" $"#N" \n\t"		\
126af11bd88SGleb Natapov 	     "jmp __handle_exception \n\t"	\
127af11bd88SGleb Natapov 	     ".popsection")
128af11bd88SGleb Natapov 
129af11bd88SGleb Natapov EX(de, 0);
130af11bd88SGleb Natapov EX(db, 1);
131af11bd88SGleb Natapov EX(nmi, 2);
132af11bd88SGleb Natapov EX(bp, 3);
133af11bd88SGleb Natapov EX(of, 4);
134af11bd88SGleb Natapov EX(br, 5);
135af11bd88SGleb Natapov EX(ud, 6);
136af11bd88SGleb Natapov EX(nm, 7);
137af11bd88SGleb Natapov EX_E(df, 8);
138af11bd88SGleb Natapov EX_E(ts, 10);
139af11bd88SGleb Natapov EX_E(np, 11);
140af11bd88SGleb Natapov EX_E(ss, 12);
141af11bd88SGleb Natapov EX_E(gp, 13);
142af11bd88SGleb Natapov EX_E(pf, 14);
143af11bd88SGleb Natapov EX(mf, 16);
144af11bd88SGleb Natapov EX_E(ac, 17);
145af11bd88SGleb Natapov EX(mc, 18);
146af11bd88SGleb Natapov EX(xm, 19);
147af11bd88SGleb Natapov 
1487d36db35SAvi Kivity asm (".pushsection .text \n\t"
149af11bd88SGleb Natapov      "__handle_exception: \n\t"
15023ba7b39SGleb Natapov #ifdef __x86_64__
1517d36db35SAvi Kivity      "push %r15; push %r14; push %r13; push %r12 \n\t"
1527d36db35SAvi Kivity      "push %r11; push %r10; push %r9; push %r8 \n\t"
15323ba7b39SGleb Natapov #endif
15423ba7b39SGleb Natapov      "push %"R"di; push %"R"si; push %"R"bp; sub $"S", %"R"sp \n\t"
15523ba7b39SGleb Natapov      "push %"R"bx; push %"R"dx; push %"R"cx; push %"R"ax \n\t"
156c3b91807SGleb Natapov #ifdef __x86_64__
15723ba7b39SGleb Natapov      "mov %"R"sp, %"R"di \n\t"
158c3b91807SGleb Natapov #else
159c3b91807SGleb Natapov      "mov %"R"sp, %"R"ax \n\t"
160c3b91807SGleb Natapov #endif
1617d36db35SAvi Kivity      "call do_handle_exception \n\t"
16223ba7b39SGleb Natapov      "pop %"R"ax; pop %"R"cx; pop %"R"dx; pop %"R"bx \n\t"
16323ba7b39SGleb Natapov      "add $"S", %"R"sp; pop %"R"bp; pop %"R"si; pop %"R"di \n\t"
16423ba7b39SGleb Natapov #ifdef __x86_64__
1657d36db35SAvi Kivity      "pop %r8; pop %r9; pop %r10; pop %r11 \n\t"
1667d36db35SAvi Kivity      "pop %r12; pop %r13; pop %r14; pop %r15 \n\t"
16723ba7b39SGleb Natapov #endif
16823ba7b39SGleb Natapov      "add $"S", %"R"sp \n\t"
16923ba7b39SGleb Natapov      "add $"S", %"R"sp \n\t"
17023ba7b39SGleb Natapov      "iret"W" \n\t"
1717d36db35SAvi Kivity      ".popsection");
1727d36db35SAvi Kivity 
173af11bd88SGleb Natapov static void *idt_handlers[32] = {
174af11bd88SGleb Natapov 	[0] = &de_fault,
175af11bd88SGleb Natapov 	[1] = &db_fault,
176af11bd88SGleb Natapov 	[2] = &nmi_fault,
177af11bd88SGleb Natapov 	[3] = &bp_fault,
178af11bd88SGleb Natapov 	[4] = &of_fault,
179af11bd88SGleb Natapov 	[5] = &br_fault,
180af11bd88SGleb Natapov 	[6] = &ud_fault,
181af11bd88SGleb Natapov 	[7] = &nm_fault,
182af11bd88SGleb Natapov 	[8] = &df_fault,
183af11bd88SGleb Natapov 	[10] = &ts_fault,
184af11bd88SGleb Natapov 	[11] = &np_fault,
185af11bd88SGleb Natapov 	[12] = &ss_fault,
186af11bd88SGleb Natapov 	[13] = &gp_fault,
187af11bd88SGleb Natapov 	[14] = &pf_fault,
188af11bd88SGleb Natapov 	[16] = &mf_fault,
189af11bd88SGleb Natapov 	[17] = &ac_fault,
190af11bd88SGleb Natapov 	[18] = &mc_fault,
191af11bd88SGleb Natapov 	[19] = &xm_fault,
192af11bd88SGleb Natapov };
1937d36db35SAvi Kivity 
1947d36db35SAvi Kivity void setup_idt(void)
1957d36db35SAvi Kivity {
196af11bd88SGleb Natapov     int i;
1974751cffbSAvi Kivity     static bool idt_initialized = false;
1984751cffbSAvi Kivity 
1994751cffbSAvi Kivity     if (idt_initialized) {
2004751cffbSAvi Kivity         return;
2014751cffbSAvi Kivity     }
2024751cffbSAvi Kivity     idt_initialized = true;
203af11bd88SGleb Natapov     for (i = 0; i < 32; i++)
204af11bd88SGleb Natapov 	    if (idt_handlers[i])
205af11bd88SGleb Natapov 		    set_idt_entry(i, idt_handlers[i], 0);
206af11bd88SGleb Natapov     handle_exception(0, check_exception_table);
207af11bd88SGleb Natapov     handle_exception(6, check_exception_table);
208af11bd88SGleb Natapov     handle_exception(13, check_exception_table);
2097d36db35SAvi Kivity }
2107d36db35SAvi Kivity 
2117d36db35SAvi Kivity unsigned exception_vector(void)
2127d36db35SAvi Kivity {
2137d36db35SAvi Kivity     unsigned short vector;
2147d36db35SAvi Kivity 
2157d36db35SAvi Kivity     asm("mov %%gs:4, %0" : "=rm"(vector));
2167d36db35SAvi Kivity     return vector;
2177d36db35SAvi Kivity }
2187d36db35SAvi Kivity 
2197d36db35SAvi Kivity unsigned exception_error_code(void)
2207d36db35SAvi Kivity {
2217d36db35SAvi Kivity     unsigned short error_code;
2227d36db35SAvi Kivity 
2237d36db35SAvi Kivity     asm("mov %%gs:6, %0" : "=rm"(error_code));
2247d36db35SAvi Kivity     return error_code;
2257d36db35SAvi Kivity }
226d21b4f12SGleb Natapov 
227d21b4f12SGleb Natapov #ifndef __x86_64__
228d21b4f12SGleb Natapov /*
229d21b4f12SGleb Natapov  * GDT, with 6 entries:
230d21b4f12SGleb Natapov  * 0x00 - NULL descriptor
231d21b4f12SGleb Natapov  * 0x08 - Code segment
232d21b4f12SGleb Natapov  * 0x10 - Data segment
233d21b4f12SGleb Natapov  * 0x18 - Not presend code segment
234d21b4f12SGleb Natapov  * 0x20 - Primery task
235d21b4f12SGleb Natapov  * 0x28 - Interrupt task
236*b01c8823SKevin Wolf  *
237*b01c8823SKevin Wolf  * 0x30 to 0x48 - Free to use for test cases
238d21b4f12SGleb Natapov  */
239d21b4f12SGleb Natapov 
240*b01c8823SKevin Wolf static gdt_entry_t gdt[10];
241d21b4f12SGleb Natapov #define TSS_GDT_OFFSET 4
242d21b4f12SGleb Natapov 
243d21b4f12SGleb Natapov void set_gdt_entry(int num, u32 base,  u32 limit, u8 access, u8 gran)
244d21b4f12SGleb Natapov {
245d21b4f12SGleb Natapov 	/* Setup the descriptor base address */
246d21b4f12SGleb Natapov 	gdt[num].base_low = (base & 0xFFFF);
247d21b4f12SGleb Natapov 	gdt[num].base_middle = (base >> 16) & 0xFF;
248d21b4f12SGleb Natapov 	gdt[num].base_high = (base >> 24) & 0xFF;
249d21b4f12SGleb Natapov 
250d21b4f12SGleb Natapov 	/* Setup the descriptor limits */
251d21b4f12SGleb Natapov 	gdt[num].limit_low = (limit & 0xFFFF);
252d21b4f12SGleb Natapov 	gdt[num].granularity = ((limit >> 16) & 0x0F);
253d21b4f12SGleb Natapov 
254d21b4f12SGleb Natapov 	/* Finally, set up the granularity and access flags */
255d21b4f12SGleb Natapov 	gdt[num].granularity |= (gran & 0xF0);
256d21b4f12SGleb Natapov 	gdt[num].access = access;
257d21b4f12SGleb Natapov }
258d21b4f12SGleb Natapov 
259d21b4f12SGleb Natapov void setup_gdt(void)
260d21b4f12SGleb Natapov {
261d21b4f12SGleb Natapov 	struct descriptor_table_ptr gp;
262d21b4f12SGleb Natapov 	/* Setup the GDT pointer and limit */
263d21b4f12SGleb Natapov 	gp.limit = sizeof(gdt) - 1;
264d21b4f12SGleb Natapov 	gp.base = (ulong)&gdt;
265d21b4f12SGleb Natapov 
266d21b4f12SGleb Natapov 	memset(gdt, 0, sizeof(gdt));
267d21b4f12SGleb Natapov 
268d21b4f12SGleb Natapov 	/* Our NULL descriptor */
269d21b4f12SGleb Natapov 	set_gdt_entry(0, 0, 0, 0, 0);
270d21b4f12SGleb Natapov 
271d21b4f12SGleb Natapov 	/* The second entry is our Code Segment. The base address
272d21b4f12SGleb Natapov 	 *  is 0, the limit is 4GBytes, it uses 4KByte granularity,
273d21b4f12SGleb Natapov 	 *  uses 32-bit opcodes, and is a Code Segment descriptor. */
274d21b4f12SGleb Natapov 	set_gdt_entry(1, 0, 0xFFFFFFFF, 0x9A, 0xcf);
275d21b4f12SGleb Natapov 
276d21b4f12SGleb Natapov 	/* The third entry is our Data Segment. It's EXACTLY the
277d21b4f12SGleb Natapov 	 *  same as our code segment, but the descriptor type in
278d21b4f12SGleb Natapov 	 *  this entry's access byte says it's a Data Segment */
279d21b4f12SGleb Natapov 	set_gdt_entry(2, 0, 0xFFFFFFFF, 0x92, 0xcf);
280d21b4f12SGleb Natapov 
281d21b4f12SGleb Natapov 	/* Same as code register above but not present */
282d21b4f12SGleb Natapov 	set_gdt_entry(3, 0, 0xFFFFFFFF, 0x1A, 0xcf);
283d21b4f12SGleb Natapov 
284d21b4f12SGleb Natapov 
285d21b4f12SGleb Natapov 	/* Flush out the old GDT and install the new changes! */
286d21b4f12SGleb Natapov 	lgdt(&gp);
287d21b4f12SGleb Natapov 
288d21b4f12SGleb Natapov 	asm volatile ("mov %0, %%ds\n\t"
289d21b4f12SGleb Natapov 		      "mov %0, %%es\n\t"
290d21b4f12SGleb Natapov 		      "mov %0, %%fs\n\t"
291d21b4f12SGleb Natapov 		      "mov %0, %%gs\n\t"
292d21b4f12SGleb Natapov 		      "mov %0, %%ss\n\t"
293d21b4f12SGleb Natapov 		      "jmp $0x08, $.Lflush2\n\t"
294d21b4f12SGleb Natapov 		      ".Lflush2: "::"r"(0x10));
295d21b4f12SGleb Natapov }
296d21b4f12SGleb Natapov 
297*b01c8823SKevin Wolf void set_idt_task_gate(int vec, u16 sel)
298d21b4f12SGleb Natapov {
299b319491dSAvi Kivity     idt_entry_t *e = &boot_idt[vec];
300d21b4f12SGleb Natapov 
301d21b4f12SGleb Natapov     memset(e, 0, sizeof *e);
302d21b4f12SGleb Natapov 
303d21b4f12SGleb Natapov     e->selector = sel;
304d21b4f12SGleb Natapov     e->ist = 0;
305d21b4f12SGleb Natapov     e->type = 5;
306d21b4f12SGleb Natapov     e->dpl = 0;
307d21b4f12SGleb Natapov     e->p = 1;
308d21b4f12SGleb Natapov }
309d21b4f12SGleb Natapov 
310d21b4f12SGleb Natapov /*
311d21b4f12SGleb Natapov  * 0 - main task
312d21b4f12SGleb Natapov  * 1 - interrupt task
313d21b4f12SGleb Natapov  */
314d21b4f12SGleb Natapov 
315d21b4f12SGleb Natapov static tss32_t tss[2];
316d21b4f12SGleb Natapov static char tss_stack[2][4096];
317d21b4f12SGleb Natapov 
318d21b4f12SGleb Natapov void setup_tss32(void)
319d21b4f12SGleb Natapov {
320d21b4f12SGleb Natapov 	u16 desc_size = sizeof(tss32_t);
321d21b4f12SGleb Natapov 	int i;
322d21b4f12SGleb Natapov 
323d21b4f12SGleb Natapov 	for (i = 0; i < 2; i++) {
324d21b4f12SGleb Natapov 		tss[i].cr3 = read_cr3();
325d21b4f12SGleb Natapov 		tss[i].ss0 = tss[i].ss1 = tss[i].ss2 = 0x10;
326d21b4f12SGleb Natapov 		tss[i].esp = tss[i].esp0 = tss[i].esp1 = tss[i].esp2 =
327e4a34e01SGleb Natapov 			(u32)tss_stack[i] + 4096;
328d21b4f12SGleb Natapov 		tss[i].cs = 0x08;
329d21b4f12SGleb Natapov 		tss[i].ds = tss[i].es = tss[i].fs = tss[i].gs = tss[i].ss = 0x10;
330d21b4f12SGleb Natapov 		tss[i].iomap_base = (u16)desc_size;
331d21b4f12SGleb Natapov 		set_gdt_entry(TSS_GDT_OFFSET + i, (u32)&tss[i],
332d21b4f12SGleb Natapov 			     desc_size - 1, 0x89, 0x0f);
333d21b4f12SGleb Natapov 	}
334d21b4f12SGleb Natapov 
335d21b4f12SGleb Natapov 	ltr(TSS_MAIN);
336d21b4f12SGleb Natapov }
337d21b4f12SGleb Natapov 
338d21b4f12SGleb Natapov void set_intr_task_gate(int e, void *fn)
339d21b4f12SGleb Natapov {
340d21b4f12SGleb Natapov 	tss[1].eip = (u32)fn;
341d21b4f12SGleb Natapov 	set_idt_task_gate(e, TSS_INTR);
342d21b4f12SGleb Natapov }
343d21b4f12SGleb Natapov 
344d21b4f12SGleb Natapov void print_current_tss_info(void)
345d21b4f12SGleb Natapov {
346d21b4f12SGleb Natapov 	u16 tr = str();
347d21b4f12SGleb Natapov 	int i = (tr == TSS_MAIN) ? 0 : 1;
348d21b4f12SGleb Natapov 
349d21b4f12SGleb Natapov 	if (tr != TSS_MAIN && tr != TSS_INTR)
350d21b4f12SGleb Natapov 		printf("Unknown TSS %x\n", tr);
351d21b4f12SGleb Natapov 	else
352d21b4f12SGleb Natapov 		printf("TR=%x Main TSS back link %x. Current TSS back link %x\n",
353d21b4f12SGleb Natapov                tr, tss[0].prev, tss[i].prev);
354d21b4f12SGleb Natapov }
355d21b4f12SGleb Natapov #endif
356