kvm: qemu: expose MSI capability to guest
[kvm-userspace.git] / user / test / x86 / realmode.c
blobf6d5326588da6196f3ac28a9b64eb930a9fb59c6
1 asm(".code16gcc");
3 typedef unsigned char u8;
4 typedef unsigned short u16;
5 typedef unsigned u32;
6 typedef unsigned long long u64;
8 void test_function(void);
10 asm(
11 "test_function: \n\t"
12 "mov $0x1234, %eax \n\t"
13 "ret"
16 static int strlen(const char *str)
18 int n;
20 for (n = 0; *str; ++str)
21 ++n;
22 return n;
25 static void print_serial(const char *buf)
27 unsigned long len = strlen(buf);
29 asm volatile ("addr32/rep/outsb" : "+S"(buf), "+c"(len) : "d"(0xf1));
32 static void exit(int code)
34 asm volatile("out %0, %1" : : "a"(code), "d"((short)0xf4));
37 struct regs {
38 u32 eax, ebx, ecx, edx;
39 u32 esi, edi, esp, ebp;
40 u32 eip, eflags;
43 static u64 gdt[] = {
45 0x00cf9b000000ffffull, // flat 32-bit code segment
46 0x00cf93000000ffffull, // flat 32-bit data segment
49 static struct {
50 u16 limit;
51 void *base;
52 } __attribute__((packed)) gdt_descr = {
53 sizeof(gdt) - 1,
54 gdt,
57 static void exec_in_big_real_mode(const struct regs *inregs,
58 struct regs *outregs,
59 const u8 *insn, int insn_len)
61 unsigned long tmp;
62 static struct regs save;
63 int i;
64 extern u8 test_insn[], test_insn_end[];
66 for (i = 0; i < insn_len; ++i)
67 test_insn[i] = insn[i];
68 for (; i < test_insn_end - test_insn; ++i)
69 test_insn[i] = 0x90; // nop
71 save = *inregs;
72 asm volatile(
73 "lgdtl %[gdt_descr] \n\t"
74 "mov %%cr0, %[tmp] \n\t"
75 "or $1, %[tmp] \n\t"
76 "mov %[tmp], %%cr0 \n\t"
77 "mov %[bigseg], %%gs \n\t"
78 "and $-2, %[tmp] \n\t"
79 "mov %[tmp], %%cr0 \n\t"
81 "xchg %%eax, %[save]+0 \n\t"
82 "xchg %%ebx, %[save]+4 \n\t"
83 "xchg %%ecx, %[save]+8 \n\t"
84 "xchg %%edx, %[save]+12 \n\t"
85 "xchg %%esi, %[save]+16 \n\t"
86 "xchg %%edi, %[save]+20 \n\t"
87 "xchg %%esp, %[save]+24 \n\t"
88 "xchg %%ebp, %[save]+28 \n\t"
90 "test_insn: . = . + 16\n\t"
91 "test_insn_end: \n\t"
93 "xchg %%eax, %[save]+0 \n\t"
94 "xchg %%ebx, %[save]+4 \n\t"
95 "xchg %%ecx, %[save]+8 \n\t"
96 "xchg %%edx, %[save]+12 \n\t"
97 "xchg %%esi, %[save]+16 \n\t"
98 "xchg %%edi, %[save]+20 \n\t"
99 "xchg %%esp, %[save]+24 \n\t"
100 "xchg %%ebp, %[save]+28 \n\t"
102 /* Save EFLAGS in outregs*/
103 "pushfl \n\t"
104 "popl %[save]+36 \n\t"
106 "xor %[tmp], %[tmp] \n\t"
107 "mov %[tmp], %%gs \n\t"
108 : [tmp]"=&r"(tmp), [save]"+m"(save)
109 : [gdt_descr]"m"(gdt_descr), [bigseg]"r"((short)16)
110 : "cc", "memory"
112 *outregs = save;
115 #define R_AX 1
116 #define R_BX 2
117 #define R_CX 4
118 #define R_DX 8
119 #define R_SI 16
120 #define R_DI 32
121 #define R_SP 64
122 #define R_BP 128
124 int regs_equal(const struct regs *r1, const struct regs *r2, int ignore)
126 const u32 *p1 = &r1->eax, *p2 = &r2->eax; // yuck
127 int i;
129 for (i = 0; i < 8; ++i)
130 if (!(ignore & (1 << i)) && p1[i] != p2[i])
131 return 0;
132 return 1;
135 #define MK_INSN(name, str) \
136 asm ( \
137 ".pushsection \".text\" \n\t" \
138 "insn_" #name ": " str " \n\t" \
139 "insn_" #name "_end: \n\t" \
140 ".popsection \n\t" \
141 ); \
142 extern u8 insn_##name[], insn_##name##_end[]
144 void test_shld(void)
146 struct regs inregs = { .eax = 0xbe, .edx = 0xef000000 }, outregs;
147 MK_INSN(shld_test, "shld $8,%edx,%eax\n\t");
149 exec_in_big_real_mode(&inregs, &outregs,
150 insn_shld_test,
151 insn_shld_test_end - insn_shld_test);
152 if (outregs.eax != 0xbeef)
153 print_serial("shld: failure\n");
154 else
155 print_serial("shld: success\n");
158 void test_mov_imm(void)
160 struct regs inregs = { 0 }, outregs;
161 MK_INSN(mov_r32_imm_1, "mov $1234567890, %eax");
162 MK_INSN(mov_r16_imm_1, "mov $1234, %ax");
163 MK_INSN(mov_r8_imm_1, "mov $0x12, %ah");
164 MK_INSN(mov_r8_imm_2, "mov $0x34, %al");
165 MK_INSN(mov_r8_imm_3, "mov $0x12, %ah\n\t" "mov $0x34, %al\n\t");
167 exec_in_big_real_mode(&inregs, &outregs,
168 insn_mov_r16_imm_1,
169 insn_mov_r16_imm_1_end - insn_mov_r16_imm_1);
170 if (!regs_equal(&inregs, &outregs, R_AX) || outregs.eax != 1234)
171 print_serial("mov test 1: FAIL\n");
173 /* test mov $imm, %eax */
174 exec_in_big_real_mode(&inregs, &outregs,
175 insn_mov_r32_imm_1,
176 insn_mov_r32_imm_1_end - insn_mov_r32_imm_1);
177 if (!regs_equal(&inregs, &outregs, R_AX) || outregs.eax != 1234567890)
178 print_serial("mov test 2: FAIL\n");
180 /* test mov $imm, %al/%ah */
181 exec_in_big_real_mode(&inregs, &outregs,
182 insn_mov_r8_imm_1,
183 insn_mov_r8_imm_1_end - insn_mov_r8_imm_1);
184 if (!regs_equal(&inregs, &outregs, R_AX) || outregs.eax != 0x1200)
185 print_serial("mov test 3: FAIL\n");
186 exec_in_big_real_mode(&inregs, &outregs,
187 insn_mov_r8_imm_2,
188 insn_mov_r8_imm_2_end - insn_mov_r8_imm_2);
189 if (!regs_equal(&inregs, &outregs, R_AX) || outregs.eax != 0x34)
190 print_serial("mov test 4: FAIL\n");
191 exec_in_big_real_mode(&inregs, &outregs,
192 insn_mov_r8_imm_3,
193 insn_mov_r8_imm_3_end - insn_mov_r8_imm_3);
194 if (!regs_equal(&inregs, &outregs, R_AX) || outregs.eax != 0x1234)
195 print_serial("mov test 5: FAIL\n");
198 void test_cmp_imm(void)
200 struct regs inregs = { 0 }, outregs;
201 MK_INSN(cmp_test1, "mov $0x34, %al\n\t"
202 "cmp $0x34, %al\n\t");
203 MK_INSN(cmp_test2, "mov $0x34, %al\n\t"
204 "cmp $0x39, %al\n\t");
205 MK_INSN(cmp_test3, "mov $0x34, %al\n\t"
206 "cmp $0x24, %al\n\t");
208 /* test cmp imm8 with AL */
209 /* ZF: (bit 6) Zero Flag becomes 1 if an operation results
210 * in a 0 writeback, or 0 register
212 exec_in_big_real_mode(&inregs, &outregs,
213 insn_cmp_test1,
214 insn_cmp_test1_end - insn_cmp_test1);
215 if ((outregs.eflags & (1<<6)) != (1<<6))
216 print_serial("cmp test 1: FAIL\n");
218 exec_in_big_real_mode(&inregs, &outregs,
219 insn_cmp_test2,
220 insn_cmp_test2_end - insn_cmp_test2);
221 if ((outregs.eflags & (1<<6)) != 0)
222 print_serial("cmp test 2: FAIL\n");
224 exec_in_big_real_mode(&inregs, &outregs,
225 insn_cmp_test3,
226 insn_cmp_test3_end - insn_cmp_test3);
227 if ((outregs.eflags & (1<<6)) != 0)
228 print_serial("cmp test 3: FAIL\n");
231 void test_add_imm(void)
233 struct regs inregs = { 0 }, outregs;
234 MK_INSN(add_test1, "mov $0x43211234, %eax \n\t"
235 "add $0x12344321, %eax \n\t");
236 MK_INSN(add_test2, "mov $0x12, %eax \n\t"
237 "add $0x21, %al\n\t");
239 exec_in_big_real_mode(&inregs, &outregs,
240 insn_add_test1,
241 insn_add_test1_end - insn_add_test1);
242 if (outregs.eax != 0x55555555)
243 print_serial("add test 1: FAIL\n");
245 exec_in_big_real_mode(&inregs, &outregs,
246 insn_add_test2,
247 insn_add_test2_end - insn_add_test2);
248 if (outregs.eax != 0x33)
249 print_serial("add test 2: FAIL\n");
252 void test_eflags_insn(void)
254 struct regs inregs = { 0 }, outregs;
255 MK_INSN(clc, "clc");
256 MK_INSN(cli, "cli");
257 MK_INSN(sti, "sti");
258 MK_INSN(cld, "cld");
259 MK_INSN(std, "std");
261 exec_in_big_real_mode(&inregs, &outregs,
262 insn_clc,
263 insn_clc_end - insn_clc);
264 if (outregs.eflags & 1)
265 print_serial("clc test: FAIL\n");
267 exec_in_big_real_mode(&inregs, &outregs,
268 insn_cli,
269 insn_cli_end - insn_cli);
270 if (outregs.eflags & (1 << 9))
271 print_serial("cli test: FAIL\n");
273 exec_in_big_real_mode(&inregs, &outregs,
274 insn_sti,
275 insn_sti_end - insn_sti);
276 if (!(outregs.eflags & (1 << 9)))
277 print_serial("sti test: FAIL\n");
279 exec_in_big_real_mode(&inregs, &outregs,
280 insn_cld,
281 insn_cld_end - insn_cld);
282 if (outregs.eflags & (1 << 10))
283 print_serial("cld test: FAIL\n");
285 exec_in_big_real_mode(&inregs, &outregs,
286 insn_std,
287 insn_std_end - insn_std);
288 if (!(outregs.eflags & (1 << 10)))
289 print_serial("std test: FAIL\n");
292 void test_io(void)
294 struct regs inregs = { 0 }, outregs;
295 MK_INSN(io_test1, "mov $0xff, %al \n\t"
296 "out %al, $0x10 \n\t"
297 "in $0x10, %al \n\t");
298 MK_INSN(io_test2, "mov $0xffff, %ax \n\t"
299 "out %ax, $0x10 \n\t"
300 "in $0x10, %ax \n\t");
301 MK_INSN(io_test3, "mov $0xffffffff, %eax \n\t"
302 "out %eax, $0x10 \n\t"
303 "in $0x10, %eax \n\t");
304 MK_INSN(io_test4, "mov $0x10, %dx \n\t"
305 "mov $0xff, %al \n\t"
306 "out %al, %dx \n\t"
307 "in %dx, %al \n\t");
308 MK_INSN(io_test5, "mov $0x10, %dx \n\t"
309 "mov $0xffff, %ax \n\t"
310 "out %ax, %dx \n\t"
311 "in %dx, %ax \n\t");
312 MK_INSN(io_test6, "mov $0x10, %dx \n\t"
313 "mov $0xffffffff, %eax \n\t"
314 "out %eax, %dx \n\t"
315 "in %dx, %eax \n\t");
317 exec_in_big_real_mode(&inregs, &outregs,
318 insn_io_test1,
319 insn_io_test1_end - insn_io_test1);
321 if (!regs_equal(&inregs, &outregs, R_AX) || outregs.eax != 0xff)
322 print_serial("I/O test 1: FAIL\n");
324 exec_in_big_real_mode(&inregs, &outregs,
325 insn_io_test2,
326 insn_io_test2_end - insn_io_test2);
328 if (!regs_equal(&inregs, &outregs, R_AX) || outregs.eax != 0xffff)
329 print_serial("I/O test 2: FAIL\n");
331 exec_in_big_real_mode(&inregs, &outregs,
332 insn_io_test3,
333 insn_io_test3_end - insn_io_test3);
335 if (!regs_equal(&inregs, &outregs, R_AX) || outregs.eax != 0xffffffff)
336 print_serial("I/O test 3: FAIL\n");
338 exec_in_big_real_mode(&inregs, &outregs,
339 insn_io_test4,
340 insn_io_test4_end - insn_io_test4);
342 if (!regs_equal(&inregs, &outregs, R_AX|R_DX) || outregs.eax != 0xff)
343 print_serial("I/O test 4: FAIL\n");
345 exec_in_big_real_mode(&inregs, &outregs,
346 insn_io_test5,
347 insn_io_test5_end - insn_io_test5);
349 if (!regs_equal(&inregs, &outregs, R_AX|R_DX) || outregs.eax != 0xffff)
350 print_serial("I/O test 5: FAIL\n");
352 exec_in_big_real_mode(&inregs, &outregs,
353 insn_io_test6,
354 insn_io_test6_end - insn_io_test6);
356 if (!regs_equal(&inregs, &outregs, R_AX|R_DX) || outregs.eax != 0xffffffff)
357 print_serial("I/O test 6: FAIL\n");
361 void test_call(void)
363 struct regs inregs = { 0 }, outregs;
364 MK_INSN(call1, "mov $test_function, %eax \n\t"
365 "call *%eax\n\t");
367 exec_in_big_real_mode(&inregs, &outregs,
368 insn_call1,
369 insn_call1_end - insn_call1);
370 if(!regs_equal(&inregs, &outregs, R_AX) || outregs.eax != 0x1234)
371 print_serial("Call Test 1: FAIL\n");
374 void test_null(void)
376 struct regs inregs = { 0 }, outregs;
377 exec_in_big_real_mode(&inregs, &outregs, 0, 0);
378 if (!regs_equal(&inregs, &outregs, 0))
379 print_serial("null test: FAIL\n");
382 void start(void)
384 test_null();
386 test_shld();
387 test_mov_imm();
388 test_cmp_imm();
389 test_add_imm();
390 test_io();
391 test_eflags_insn();
393 exit(0);
396 asm(
397 ".data \n\t"
398 ". = . + 4096 \n\t"
399 "stacktop: \n\t"
400 ".text \n\t"
401 "init: \n\t"
402 "xor %ax, %ax \n\t"
403 "mov %ax, %ds \n\t"
404 "mov %ax, %es \n\t"
405 "mov %ax, %ss \n\t"
406 "mov $0x4000, %cx \n\t"
407 "xor %esi, %esi \n\t"
408 "mov %esi, %edi \n\t"
409 "rep/addr32/cs/movsl \n\t"
410 "mov $stacktop, %sp\n\t"
411 "ljmp $0, $start \n\t"
412 ".pushsection .boot, \"ax\" \n\t"
413 "ljmp $0xf000, $init \n\t"
414 ".popsection"