xref: /kvm-unit-tests/x86/taskswitch2.c (revision d21b4f1216592171a358c7d17f81b4aab08aebea)
1*d21b4f12SGleb Natapov #include "libcflat.h"
2*d21b4f12SGleb Natapov #include "desc.h"
3*d21b4f12SGleb Natapov #include "apic-defs.h"
4*d21b4f12SGleb Natapov #include "apic.h"
5*d21b4f12SGleb Natapov #include "processor.h"
6*d21b4f12SGleb Natapov 
7*d21b4f12SGleb Natapov #define xstr(s) str(s)
8*d21b4f12SGleb Natapov #define str(s) #s
9*d21b4f12SGleb Natapov 
10*d21b4f12SGleb Natapov static volatile int test_count;
11*d21b4f12SGleb Natapov static volatile unsigned int test_divider;
12*d21b4f12SGleb Natapov 
13*d21b4f12SGleb Natapov static int g_fail;
14*d21b4f12SGleb Natapov static int g_tests;
15*d21b4f12SGleb Natapov 
16*d21b4f12SGleb Natapov static inline void io_delay(void)
17*d21b4f12SGleb Natapov {
18*d21b4f12SGleb Natapov }
19*d21b4f12SGleb Natapov 
20*d21b4f12SGleb Natapov static void report(const char *msg, int pass)
21*d21b4f12SGleb Natapov {
22*d21b4f12SGleb Natapov     ++g_tests;
23*d21b4f12SGleb Natapov     printf("%s: %s\n", msg, (pass ? "PASS" : "FAIL"));
24*d21b4f12SGleb Natapov     if (!pass)
25*d21b4f12SGleb Natapov         ++g_fail;
26*d21b4f12SGleb Natapov }
27*d21b4f12SGleb Natapov 
28*d21b4f12SGleb Natapov static void nmi_tss(void)
29*d21b4f12SGleb Natapov {
30*d21b4f12SGleb Natapov start:
31*d21b4f12SGleb Natapov 	printf("NMI task is running\n");
32*d21b4f12SGleb Natapov 	print_current_tss_info();
33*d21b4f12SGleb Natapov 	test_count++;
34*d21b4f12SGleb Natapov 	asm volatile ("iret");
35*d21b4f12SGleb Natapov 	goto start;
36*d21b4f12SGleb Natapov }
37*d21b4f12SGleb Natapov 
38*d21b4f12SGleb Natapov static void de_tss(void)
39*d21b4f12SGleb Natapov {
40*d21b4f12SGleb Natapov start:
41*d21b4f12SGleb Natapov 	printf("DE task is running\n");
42*d21b4f12SGleb Natapov 	print_current_tss_info();
43*d21b4f12SGleb Natapov 	test_divider = 10;
44*d21b4f12SGleb Natapov 	test_count++;
45*d21b4f12SGleb Natapov 	asm volatile ("iret");
46*d21b4f12SGleb Natapov 	goto start;
47*d21b4f12SGleb Natapov }
48*d21b4f12SGleb Natapov 
49*d21b4f12SGleb Natapov static void of_tss(void)
50*d21b4f12SGleb Natapov {
51*d21b4f12SGleb Natapov start:
52*d21b4f12SGleb Natapov 	printf("OF task is running\n");
53*d21b4f12SGleb Natapov 	print_current_tss_info();
54*d21b4f12SGleb Natapov 	test_count++;
55*d21b4f12SGleb Natapov 	asm volatile ("iret");
56*d21b4f12SGleb Natapov 	goto start;
57*d21b4f12SGleb Natapov }
58*d21b4f12SGleb Natapov 
59*d21b4f12SGleb Natapov static void bp_tss(void)
60*d21b4f12SGleb Natapov {
61*d21b4f12SGleb Natapov start:
62*d21b4f12SGleb Natapov 	printf("BP task is running\n");
63*d21b4f12SGleb Natapov 	print_current_tss_info();
64*d21b4f12SGleb Natapov 	test_count++;
65*d21b4f12SGleb Natapov 	asm volatile ("iret");
66*d21b4f12SGleb Natapov 	goto start;
67*d21b4f12SGleb Natapov }
68*d21b4f12SGleb Natapov 
69*d21b4f12SGleb Natapov static void jmp_tss(void)
70*d21b4f12SGleb Natapov {
71*d21b4f12SGleb Natapov start:
72*d21b4f12SGleb Natapov 	printf("JMP to task succeeded\n");
73*d21b4f12SGleb Natapov 	print_current_tss_info();
74*d21b4f12SGleb Natapov 	test_count++;
75*d21b4f12SGleb Natapov 	asm volatile ("ljmp $" xstr(TSS_MAIN) ", $0");
76*d21b4f12SGleb Natapov 	goto start;
77*d21b4f12SGleb Natapov }
78*d21b4f12SGleb Natapov 
79*d21b4f12SGleb Natapov static void irq_tss(void)
80*d21b4f12SGleb Natapov {
81*d21b4f12SGleb Natapov start:
82*d21b4f12SGleb Natapov 	printf("IRQ task is running\n");
83*d21b4f12SGleb Natapov 	print_current_tss_info();
84*d21b4f12SGleb Natapov 	test_count++;
85*d21b4f12SGleb Natapov 	asm volatile ("iret");
86*d21b4f12SGleb Natapov 	test_count++;
87*d21b4f12SGleb Natapov 	printf("IRQ task restarts after iret.\n");
88*d21b4f12SGleb Natapov 	goto start;
89*d21b4f12SGleb Natapov }
90*d21b4f12SGleb Natapov 
91*d21b4f12SGleb Natapov int main()
92*d21b4f12SGleb Natapov {
93*d21b4f12SGleb Natapov 	unsigned int res;
94*d21b4f12SGleb Natapov 
95*d21b4f12SGleb Natapov 	setup_idt();
96*d21b4f12SGleb Natapov 	setup_gdt();
97*d21b4f12SGleb Natapov 	setup_tss32();
98*d21b4f12SGleb Natapov 
99*d21b4f12SGleb Natapov 	/* test that int $2 triggers task gate */
100*d21b4f12SGleb Natapov 	test_count = 0;
101*d21b4f12SGleb Natapov 	set_intr_task_gate(2, nmi_tss);
102*d21b4f12SGleb Natapov 	printf("Triggering nmi 2\n");
103*d21b4f12SGleb Natapov 	asm volatile ("int $2");
104*d21b4f12SGleb Natapov 	printf("Return from nmi %d\n", test_count);
105*d21b4f12SGleb Natapov 	report("NMI int $2", test_count == 1);
106*d21b4f12SGleb Natapov 
107*d21b4f12SGleb Natapov 	/* test that external NMI triggers task gate */
108*d21b4f12SGleb Natapov 	test_count = 0;
109*d21b4f12SGleb Natapov 	set_intr_task_gate(2, nmi_tss);
110*d21b4f12SGleb Natapov 	printf("Triggering nmi through APIC\n");
111*d21b4f12SGleb Natapov 	apic_icr_write(APIC_DEST_PHYSICAL | APIC_DM_NMI | APIC_INT_ASSERT, 0);
112*d21b4f12SGleb Natapov 	io_delay();
113*d21b4f12SGleb Natapov 	printf("Return from APIC nmi\n");
114*d21b4f12SGleb Natapov 	report("NMI external", test_count == 1);
115*d21b4f12SGleb Natapov 
116*d21b4f12SGleb Natapov 	/* test that external interrupt triggesr task gate */
117*d21b4f12SGleb Natapov 	test_count = 0;
118*d21b4f12SGleb Natapov 	printf("Trigger IRQ from APIC\n");
119*d21b4f12SGleb Natapov 	set_intr_task_gate(0xf0, irq_tss);
120*d21b4f12SGleb Natapov 	irq_enable();
121*d21b4f12SGleb Natapov 	apic_icr_write(APIC_DEST_SELF | APIC_DEST_PHYSICAL | APIC_DM_FIXED | APIC_INT_ASSERT | 0xf0, 0);
122*d21b4f12SGleb Natapov 	io_delay();
123*d21b4f12SGleb Natapov 	irq_disable();
124*d21b4f12SGleb Natapov 	printf("Return from APIC IRQ\n");
125*d21b4f12SGleb Natapov 	report("IRQ external", test_count == 1);
126*d21b4f12SGleb Natapov 
127*d21b4f12SGleb Natapov 	/* test that HW exception triggesr task gate */
128*d21b4f12SGleb Natapov 	set_intr_task_gate(0, de_tss);
129*d21b4f12SGleb Natapov 	printf("Try to devide by 0\n");
130*d21b4f12SGleb Natapov 	asm volatile ("divl %3": "=a"(res)
131*d21b4f12SGleb Natapov 		      : "d"(0), "a"(1500), "m"(test_divider));
132*d21b4f12SGleb Natapov 	printf("Result is %d\n", res);
133*d21b4f12SGleb Natapov 	report("DE exeption", res == 150);
134*d21b4f12SGleb Natapov 
135*d21b4f12SGleb Natapov 	/* test if call HW exeption DE by int $0 triggers task gate */
136*d21b4f12SGleb Natapov 	test_count = 0;
137*d21b4f12SGleb Natapov 	set_intr_task_gate(0, de_tss);
138*d21b4f12SGleb Natapov 	printf("Call int 0\n");
139*d21b4f12SGleb Natapov 	asm volatile ("int $0");
140*d21b4f12SGleb Natapov 	printf("Return from int 0\n");
141*d21b4f12SGleb Natapov 	report("int $0", test_count == 1);
142*d21b4f12SGleb Natapov 
143*d21b4f12SGleb Natapov 	/* test if HW exception OF triggers task gate */
144*d21b4f12SGleb Natapov 	test_count = 0;
145*d21b4f12SGleb Natapov 	set_intr_task_gate(4, of_tss);
146*d21b4f12SGleb Natapov 	printf("Call into\n");
147*d21b4f12SGleb Natapov 	asm volatile ("addb $127, %b0\ninto"::"a"(127));
148*d21b4f12SGleb Natapov 	printf("Return from into\n");
149*d21b4f12SGleb Natapov 	report("OF exeption", test_count);
150*d21b4f12SGleb Natapov 
151*d21b4f12SGleb Natapov 	/* test if HW exception BP triggers task gate */
152*d21b4f12SGleb Natapov 	test_count = 0;
153*d21b4f12SGleb Natapov 	set_intr_task_gate(3, bp_tss);
154*d21b4f12SGleb Natapov 	printf("Call int 3\n");
155*d21b4f12SGleb Natapov 	asm volatile ("int $3");
156*d21b4f12SGleb Natapov 	printf("Return from int 3\n");
157*d21b4f12SGleb Natapov 	report("BP exeption", test_count == 1);
158*d21b4f12SGleb Natapov 
159*d21b4f12SGleb Natapov 	/* test that calling a task by lcall works */
160*d21b4f12SGleb Natapov 	test_count = 0;
161*d21b4f12SGleb Natapov 	set_intr_task_gate(0, irq_tss);
162*d21b4f12SGleb Natapov 	printf("Calling task by lcall\n");
163*d21b4f12SGleb Natapov 	/* hlt opcode is 0xf4 I use destination IP 0xf4f4f4f4 to catch
164*d21b4f12SGleb Natapov 	   incorrect instruction length calculation */
165*d21b4f12SGleb Natapov 	asm volatile("lcall $" xstr(TSS_INTR) ", $0xf4f4f4f4");
166*d21b4f12SGleb Natapov 	printf("Return from call\n");
167*d21b4f12SGleb Natapov 	report("lcall", test_count == 1);
168*d21b4f12SGleb Natapov 
169*d21b4f12SGleb Natapov 	/* call the same task again and check that it restarted after iret */
170*d21b4f12SGleb Natapov 	test_count = 0;
171*d21b4f12SGleb Natapov 	asm volatile("lcall $" xstr(TSS_INTR) ", $0xf4f4f4f4");
172*d21b4f12SGleb Natapov 	report("lcall2", test_count == 2);
173*d21b4f12SGleb Natapov 
174*d21b4f12SGleb Natapov 	/* test that calling a task by ljmp works */
175*d21b4f12SGleb Natapov 	test_count = 0;
176*d21b4f12SGleb Natapov 	set_intr_task_gate(0, jmp_tss);
177*d21b4f12SGleb Natapov 	printf("Jumping to a task by ljmp\n");
178*d21b4f12SGleb Natapov 	asm volatile ("ljmp $" xstr(TSS_INTR) ", $0xf4f4f4f4");
179*d21b4f12SGleb Natapov 	printf("Jump back succeeded\n");
180*d21b4f12SGleb Natapov 	report("ljmp", test_count == 1);
181*d21b4f12SGleb Natapov 
182*d21b4f12SGleb Natapov 	printf("\nsummary: %d tests, %d failures\n", g_tests, g_fail);
183*d21b4f12SGleb Natapov 
184*d21b4f12SGleb Natapov 	return g_fail != 0;
185*d21b4f12SGleb Natapov }
186