xref: /kvm-unit-tests/x86/taskswitch.c (revision 7d36db351752e29ad27eaafe3f102de7064e429b)
1*7d36db35SAvi Kivity /*
2*7d36db35SAvi Kivity  * Copyright 2010 Siemens AG
3*7d36db35SAvi Kivity  * Author: Jan Kiszka
4*7d36db35SAvi Kivity  *
5*7d36db35SAvi Kivity  * Released under GPLv2.
6*7d36db35SAvi Kivity  */
7*7d36db35SAvi Kivity 
8*7d36db35SAvi Kivity #include "libcflat.h"
9*7d36db35SAvi Kivity 
10*7d36db35SAvi Kivity #define FIRST_SPARE_SEL		0x18
11*7d36db35SAvi Kivity 
12*7d36db35SAvi Kivity struct exception_frame {
13*7d36db35SAvi Kivity 	unsigned long error_code;
14*7d36db35SAvi Kivity 	unsigned long ip;
15*7d36db35SAvi Kivity 	unsigned long cs;
16*7d36db35SAvi Kivity 	unsigned long flags;
17*7d36db35SAvi Kivity };
18*7d36db35SAvi Kivity 
19*7d36db35SAvi Kivity struct tss32 {
20*7d36db35SAvi Kivity 	unsigned short prev;
21*7d36db35SAvi Kivity 	unsigned short res1;
22*7d36db35SAvi Kivity 	unsigned long esp0;
23*7d36db35SAvi Kivity 	unsigned short ss0;
24*7d36db35SAvi Kivity 	unsigned short res2;
25*7d36db35SAvi Kivity 	unsigned long esp1;
26*7d36db35SAvi Kivity 	unsigned short ss1;
27*7d36db35SAvi Kivity 	unsigned short res3;
28*7d36db35SAvi Kivity 	unsigned long esp2;
29*7d36db35SAvi Kivity 	unsigned short ss2;
30*7d36db35SAvi Kivity 	unsigned short res4;
31*7d36db35SAvi Kivity 	unsigned long cr3;
32*7d36db35SAvi Kivity 	unsigned long eip;
33*7d36db35SAvi Kivity 	unsigned long eflags;
34*7d36db35SAvi Kivity 	unsigned long eax, ecx, edx, ebx, esp, ebp, esi, edi;
35*7d36db35SAvi Kivity 	unsigned short es;
36*7d36db35SAvi Kivity 	unsigned short res5;
37*7d36db35SAvi Kivity 	unsigned short cs;
38*7d36db35SAvi Kivity 	unsigned short res6;
39*7d36db35SAvi Kivity 	unsigned short ss;
40*7d36db35SAvi Kivity 	unsigned short res7;
41*7d36db35SAvi Kivity 	unsigned short ds;
42*7d36db35SAvi Kivity 	unsigned short res8;
43*7d36db35SAvi Kivity 	unsigned short fs;
44*7d36db35SAvi Kivity 	unsigned short res9;
45*7d36db35SAvi Kivity 	unsigned short gs;
46*7d36db35SAvi Kivity 	unsigned short res10;
47*7d36db35SAvi Kivity 	unsigned short ldt;
48*7d36db35SAvi Kivity 	unsigned short res11;
49*7d36db35SAvi Kivity 	unsigned short t:1;
50*7d36db35SAvi Kivity 	unsigned short res12:15;
51*7d36db35SAvi Kivity 	unsigned short iomap_base;
52*7d36db35SAvi Kivity };
53*7d36db35SAvi Kivity 
54*7d36db35SAvi Kivity static char main_stack[4096];
55*7d36db35SAvi Kivity static char fault_stack[4096];
56*7d36db35SAvi Kivity static struct tss32 main_tss;
57*7d36db35SAvi Kivity static struct tss32 fault_tss;
58*7d36db35SAvi Kivity 
59*7d36db35SAvi Kivity static unsigned long long gdt[] __attribute__((aligned(16))) = {
60*7d36db35SAvi Kivity 	0,
61*7d36db35SAvi Kivity 	0x00cf9b000000ffffull,
62*7d36db35SAvi Kivity 	0x00cf93000000ffffull,
63*7d36db35SAvi Kivity 	0, 0,	/* TSS segments */
64*7d36db35SAvi Kivity 	0,	/* task return gate */
65*7d36db35SAvi Kivity };
66*7d36db35SAvi Kivity 
67*7d36db35SAvi Kivity static unsigned long long gdtr;
68*7d36db35SAvi Kivity 
69*7d36db35SAvi Kivity void fault_entry(void);
70*7d36db35SAvi Kivity 
71*7d36db35SAvi Kivity static __attribute__((used, regparm(1))) void
72*7d36db35SAvi Kivity fault_handler(unsigned long error_code)
73*7d36db35SAvi Kivity {
74*7d36db35SAvi Kivity 	unsigned short *desc;
75*7d36db35SAvi Kivity 
76*7d36db35SAvi Kivity 	printf("fault at %x:%x, prev task %x, error code %x\n",
77*7d36db35SAvi Kivity 	       main_tss.cs, main_tss.eip, fault_tss.prev, error_code);
78*7d36db35SAvi Kivity 
79*7d36db35SAvi Kivity 	main_tss.eip += 2;
80*7d36db35SAvi Kivity 
81*7d36db35SAvi Kivity 	desc = (unsigned short *)&gdt[3];
82*7d36db35SAvi Kivity 	desc[2] &= ~0x0200;
83*7d36db35SAvi Kivity 
84*7d36db35SAvi Kivity 	desc = (unsigned short *)&gdt[5];
85*7d36db35SAvi Kivity 	desc[0] = 0;
86*7d36db35SAvi Kivity 	desc[1] = fault_tss.prev;
87*7d36db35SAvi Kivity 	desc[2] = 0x8500;
88*7d36db35SAvi Kivity 	desc[3] = 0;
89*7d36db35SAvi Kivity }
90*7d36db35SAvi Kivity 
91*7d36db35SAvi Kivity asm (
92*7d36db35SAvi Kivity 	"fault_entry:\n"
93*7d36db35SAvi Kivity 	"	mov (%esp),%eax\n"
94*7d36db35SAvi Kivity 	"	call fault_handler\n"
95*7d36db35SAvi Kivity 	"	jmp $0x28, $0\n"
96*7d36db35SAvi Kivity );
97*7d36db35SAvi Kivity 
98*7d36db35SAvi Kivity static void setup_tss(struct tss32 *tss, void *entry,
99*7d36db35SAvi Kivity 		      void *stack_base, unsigned long stack_size)
100*7d36db35SAvi Kivity {
101*7d36db35SAvi Kivity 	unsigned long cr3;
102*7d36db35SAvi Kivity 	unsigned short cs, ds;
103*7d36db35SAvi Kivity 
104*7d36db35SAvi Kivity 	asm ("mov %%cr3,%0" : "=r" (cr3));
105*7d36db35SAvi Kivity 	asm ("mov %%cs,%0" : "=r" (cs));
106*7d36db35SAvi Kivity 	asm ("mov %%ds,%0" : "=r" (ds));
107*7d36db35SAvi Kivity 
108*7d36db35SAvi Kivity 	tss->ss0 = tss->ss1 = tss->ss2 = tss->ss = ds;
109*7d36db35SAvi Kivity 	tss->esp0 = tss->esp1 = tss->esp2 = tss->esp =
110*7d36db35SAvi Kivity 		(unsigned long)stack_base + stack_size;
111*7d36db35SAvi Kivity 	tss->ds = tss->es = tss->fs = tss->gs = ds;
112*7d36db35SAvi Kivity 	tss->cs = cs;
113*7d36db35SAvi Kivity 	tss->eip = (unsigned long)entry;
114*7d36db35SAvi Kivity 	tss->cr3 = cr3;
115*7d36db35SAvi Kivity }
116*7d36db35SAvi Kivity 
117*7d36db35SAvi Kivity static void setup_tss_desc(unsigned short tss_sel, struct tss32 *tss)
118*7d36db35SAvi Kivity {
119*7d36db35SAvi Kivity 	unsigned long addr = (unsigned long)tss;
120*7d36db35SAvi Kivity 	unsigned short *desc;
121*7d36db35SAvi Kivity 
122*7d36db35SAvi Kivity 	desc = (unsigned short *)&gdt[tss_sel/8];
123*7d36db35SAvi Kivity 	desc[0] = sizeof(*tss) - 1;
124*7d36db35SAvi Kivity 	desc[1] = addr;
125*7d36db35SAvi Kivity 	desc[2] = 0x8900 | ((addr & 0x00ff0000) >> 16);
126*7d36db35SAvi Kivity 	desc[3] = (addr & 0xff000000) >> 16;
127*7d36db35SAvi Kivity }
128*7d36db35SAvi Kivity 
129*7d36db35SAvi Kivity static void set_intr_task(unsigned short tss_sel, int intr, struct tss32 *tss)
130*7d36db35SAvi Kivity {
131*7d36db35SAvi Kivity 	unsigned short *desc = (void *)(intr* sizeof(long) * 2);
132*7d36db35SAvi Kivity 
133*7d36db35SAvi Kivity 	setup_tss_desc(tss_sel, tss);
134*7d36db35SAvi Kivity 
135*7d36db35SAvi Kivity 	desc[0] = 0;
136*7d36db35SAvi Kivity 	desc[1] = tss_sel;
137*7d36db35SAvi Kivity 	desc[2] = 0x8500;
138*7d36db35SAvi Kivity 	desc[3] = 0;
139*7d36db35SAvi Kivity }
140*7d36db35SAvi Kivity 
141*7d36db35SAvi Kivity int main(int ac, char **av)
142*7d36db35SAvi Kivity {
143*7d36db35SAvi Kivity 	const long invalid_segment = 0x1234;
144*7d36db35SAvi Kivity 
145*7d36db35SAvi Kivity 	gdtr = ((unsigned long long)(unsigned long)&gdt << 16) |
146*7d36db35SAvi Kivity 		(sizeof(gdt) - 1);
147*7d36db35SAvi Kivity 	asm ("lgdt %0" : : "m" (gdtr));
148*7d36db35SAvi Kivity 
149*7d36db35SAvi Kivity 	setup_tss(&main_tss, 0, main_stack, sizeof(main_stack));
150*7d36db35SAvi Kivity 	setup_tss_desc(FIRST_SPARE_SEL, &main_tss);
151*7d36db35SAvi Kivity 	asm ("ltr %0" : : "r" ((unsigned short)FIRST_SPARE_SEL));
152*7d36db35SAvi Kivity 
153*7d36db35SAvi Kivity 	setup_tss(&fault_tss, fault_entry, fault_stack, sizeof(fault_stack));
154*7d36db35SAvi Kivity 	set_intr_task(FIRST_SPARE_SEL+8, 13, &fault_tss);
155*7d36db35SAvi Kivity 
156*7d36db35SAvi Kivity 	asm (
157*7d36db35SAvi Kivity 		"mov %0,%%es\n"
158*7d36db35SAvi Kivity 		: : "r" (invalid_segment) : "edi"
159*7d36db35SAvi Kivity 	);
160*7d36db35SAvi Kivity 
161*7d36db35SAvi Kivity 	printf("post fault\n");
162*7d36db35SAvi Kivity 
163*7d36db35SAvi Kivity 	return 0;
164*7d36db35SAvi Kivity }
165