1 asm(".code16gcc"); 2 3 typedef unsigned char u8; 4 typedef unsigned short u16; 5 typedef unsigned u32; 6 typedef unsigned long long u64; 7 8 void test_function(void); 9 10 asm( 11 "test_function: \n\t" 12 "mov $0x1234, %eax \n\t" 13 "ret" 14 ); 15 16 static int strlen(const char *str) 17 { 18 int n; 19 20 for (n = 0; *str; ++str) 21 ++n; 22 return n; 23 } 24 25 static void print_serial(const char *buf) 26 { 27 unsigned long len = strlen(buf); 28 29 asm volatile ("cld; addr32/rep/outsb" : "+S"(buf), "+c"(len) : "d"(0xf1)); 30 } 31 32 static void exit(int code) 33 { 34 asm volatile("out %0, %1" : : "a"(code), "d"((short)0xf4)); 35 } 36 37 struct regs { 38 u32 eax, ebx, ecx, edx; 39 u32 esi, edi, esp, ebp; 40 u32 eip, eflags; 41 }; 42 43 static u64 gdt[] = { 44 0, 45 0x00cf9b000000ffffull, // flat 32-bit code segment 46 0x00cf93000000ffffull, // flat 32-bit data segment 47 }; 48 49 static struct { 50 u16 limit; 51 void *base; 52 } __attribute__((packed)) gdt_descr = { 53 sizeof(gdt) - 1, 54 gdt, 55 }; 56 57 static void exec_in_big_real_mode(const struct regs *inregs, 58 struct regs *outregs, 59 const u8 *insn, int insn_len) 60 { 61 unsigned long tmp; 62 static struct regs save; 63 int i; 64 extern u8 test_insn[], test_insn_end[]; 65 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 70 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" 80 81 "pushw %[save]+36; popfw \n\t" 82 "xchg %%eax, %[save]+0 \n\t" 83 "xchg %%ebx, %[save]+4 \n\t" 84 "xchg %%ecx, %[save]+8 \n\t" 85 "xchg %%edx, %[save]+12 \n\t" 86 "xchg %%esi, %[save]+16 \n\t" 87 "xchg %%edi, %[save]+20 \n\t" 88 "xchg %%esp, %[save]+24 \n\t" 89 "xchg %%ebp, %[save]+28 \n\t" 90 91 "test_insn: . = . + 32\n\t" 92 "test_insn_end: \n\t" 93 94 "xchg %%eax, %[save]+0 \n\t" 95 "xchg %%ebx, %[save]+4 \n\t" 96 "xchg %%ecx, %[save]+8 \n\t" 97 "xchg %%edx, %[save]+12 \n\t" 98 "xchg %%esi, %[save]+16 \n\t" 99 "xchg %%edi, %[save]+20 \n\t" 100 "xchg %%esp, %[save]+24 \n\t" 101 "xchg %%ebp, %[save]+28 \n\t" 102 103 /* Save EFLAGS in outregs*/ 104 "pushfl \n\t" 105 "popl %[save]+36 \n\t" 106 107 "xor %[tmp], %[tmp] \n\t" 108 "mov %[tmp], %%gs \n\t" 109 : [tmp]"=&r"(tmp), [save]"+m"(save) 110 : [gdt_descr]"m"(gdt_descr), [bigseg]"r"((short)16) 111 : "cc", "memory" 112 ); 113 *outregs = save; 114 } 115 116 #define R_AX 1 117 #define R_BX 2 118 #define R_CX 4 119 #define R_DX 8 120 #define R_SI 16 121 #define R_DI 32 122 #define R_SP 64 123 #define R_BP 128 124 125 int regs_equal(const struct regs *r1, const struct regs *r2, int ignore) 126 { 127 const u32 *p1 = &r1->eax, *p2 = &r2->eax; // yuck 128 int i; 129 130 for (i = 0; i < 8; ++i) 131 if (!(ignore & (1 << i)) && p1[i] != p2[i]) 132 return 0; 133 return 1; 134 } 135 136 #define MK_INSN(name, str) \ 137 asm ( \ 138 ".text 1\n\t" \ 139 "insn_" #name ": " str " \n\t" \ 140 "insn_" #name "_end: \n\t" \ 141 ".text\n\t" \ 142 ); \ 143 extern u8 insn_##name[], insn_##name##_end[] 144 145 void test_xchg(void) 146 { 147 struct regs inregs = { .eax = 0, .ebx = 1, .ecx = 2, .edx = 3, .esi = 4, .edi = 5, .ebp = 6, .esp = 7}, outregs; 148 149 MK_INSN(xchg_test1, "xchg %eax,%eax\n\t"); 150 MK_INSN(xchg_test2, "xchg %eax,%ebx\n\t"); 151 MK_INSN(xchg_test3, "xchg %eax,%ecx\n\t"); 152 MK_INSN(xchg_test4, "xchg %eax,%edx\n\t"); 153 MK_INSN(xchg_test5, "xchg %eax,%esi\n\t"); 154 MK_INSN(xchg_test6, "xchg %eax,%edi\n\t"); 155 MK_INSN(xchg_test7, "xchg %eax,%ebp\n\t"); 156 MK_INSN(xchg_test8, "xchg %eax,%esp\n\t"); 157 158 exec_in_big_real_mode(&inregs, &outregs, 159 insn_xchg_test1, 160 insn_xchg_test1_end - insn_xchg_test1); 161 162 if (!regs_equal(&inregs, &outregs, 0)) 163 print_serial("xchg test 1: FAIL\n"); 164 else 165 print_serial("xchg test 1: PASS\n"); 166 167 exec_in_big_real_mode(&inregs, &outregs, 168 insn_xchg_test2, 169 insn_xchg_test2_end - insn_xchg_test2); 170 171 if (!regs_equal(&inregs, &outregs, R_AX | R_BX) || 172 outregs.eax != inregs.ebx || 173 outregs.ebx != inregs.eax) 174 print_serial("xchg test 2: FAIL\n"); 175 else 176 print_serial("xchg test 2: PASS\n"); 177 178 exec_in_big_real_mode(&inregs, &outregs, 179 insn_xchg_test3, 180 insn_xchg_test3_end - insn_xchg_test3); 181 182 if (!regs_equal(&inregs, &outregs, R_AX | R_CX) || 183 outregs.eax != inregs.ecx || 184 outregs.ecx != inregs.eax) 185 print_serial("xchg test 3: FAIL\n"); 186 else 187 print_serial("xchg test 3: PASS\n"); 188 189 exec_in_big_real_mode(&inregs, &outregs, 190 insn_xchg_test4, 191 insn_xchg_test4_end - insn_xchg_test4); 192 193 if (!regs_equal(&inregs, &outregs, R_AX | R_DX) || 194 outregs.eax != inregs.edx || 195 outregs.edx != inregs.eax) 196 print_serial("xchg test 4: FAIL\n"); 197 else 198 print_serial("xchg test 4: PASS\n"); 199 200 exec_in_big_real_mode(&inregs, &outregs, 201 insn_xchg_test5, 202 insn_xchg_test5_end - insn_xchg_test5); 203 204 if (!regs_equal(&inregs, &outregs, R_AX | R_SI) || 205 outregs.eax != inregs.esi || 206 outregs.esi != inregs.eax) 207 print_serial("xchg test 5: FAIL\n"); 208 else 209 print_serial("xchg test 5: PASS\n"); 210 211 exec_in_big_real_mode(&inregs, &outregs, 212 insn_xchg_test6, 213 insn_xchg_test6_end - insn_xchg_test6); 214 215 if (!regs_equal(&inregs, &outregs, R_AX | R_DI) || 216 outregs.eax != inregs.edi || 217 outregs.edi != inregs.eax) 218 print_serial("xchg test 6: FAIL\n"); 219 else 220 print_serial("xchg test 6: PASS\n"); 221 222 exec_in_big_real_mode(&inregs, &outregs, 223 insn_xchg_test7, 224 insn_xchg_test7_end - insn_xchg_test7); 225 226 if (!regs_equal(&inregs, &outregs, R_AX | R_BP) || 227 outregs.eax != inregs.ebp || 228 outregs.ebp != inregs.eax) 229 print_serial("xchg test 7: FAIL\n"); 230 else 231 print_serial("xchg test 7: PASS\n"); 232 233 exec_in_big_real_mode(&inregs, &outregs, 234 insn_xchg_test8, 235 insn_xchg_test8_end - insn_xchg_test8); 236 237 if (!regs_equal(&inregs, &outregs, R_AX | R_SP) || 238 outregs.eax != inregs.esp || 239 outregs.esp != inregs.eax) 240 print_serial("xchg test 8: FAIL\n"); 241 else 242 print_serial("xchg test 8: PASS\n"); 243 } 244 245 void test_shld(void) 246 { 247 struct regs inregs = { .eax = 0xbe, .edx = 0xef000000 }, outregs; 248 MK_INSN(shld_test, "shld $8,%edx,%eax\n\t"); 249 250 exec_in_big_real_mode(&inregs, &outregs, 251 insn_shld_test, 252 insn_shld_test_end - insn_shld_test); 253 if (outregs.eax != 0xbeef) 254 print_serial("shld: FAIL\n"); 255 else 256 print_serial("shld: PASS\n"); 257 } 258 259 void test_mov_imm(void) 260 { 261 struct regs inregs = { 0 }, outregs; 262 MK_INSN(mov_r32_imm_1, "mov $1234567890, %eax"); 263 MK_INSN(mov_r16_imm_1, "mov $1234, %ax"); 264 MK_INSN(mov_r8_imm_1, "mov $0x12, %ah"); 265 MK_INSN(mov_r8_imm_2, "mov $0x34, %al"); 266 MK_INSN(mov_r8_imm_3, "mov $0x12, %ah\n\t" "mov $0x34, %al\n\t"); 267 268 exec_in_big_real_mode(&inregs, &outregs, 269 insn_mov_r16_imm_1, 270 insn_mov_r16_imm_1_end - insn_mov_r16_imm_1); 271 if (!regs_equal(&inregs, &outregs, R_AX) || outregs.eax != 1234) 272 print_serial("mov test 1: FAIL\n"); 273 else 274 print_serial("mov test 1: PASS\n"); 275 276 /* test mov $imm, %eax */ 277 exec_in_big_real_mode(&inregs, &outregs, 278 insn_mov_r32_imm_1, 279 insn_mov_r32_imm_1_end - insn_mov_r32_imm_1); 280 if (!regs_equal(&inregs, &outregs, R_AX) || outregs.eax != 1234567890) 281 print_serial("mov test 2: FAIL\n"); 282 else 283 print_serial("mov test 2: PASS\n"); 284 285 /* test mov $imm, %al/%ah */ 286 exec_in_big_real_mode(&inregs, &outregs, 287 insn_mov_r8_imm_1, 288 insn_mov_r8_imm_1_end - insn_mov_r8_imm_1); 289 if (!regs_equal(&inregs, &outregs, R_AX) || outregs.eax != 0x1200) 290 print_serial("mov test 3: FAIL\n"); 291 else 292 print_serial("mov test 3: PASS\n"); 293 294 exec_in_big_real_mode(&inregs, &outregs, 295 insn_mov_r8_imm_2, 296 insn_mov_r8_imm_2_end - insn_mov_r8_imm_2); 297 if (!regs_equal(&inregs, &outregs, R_AX) || outregs.eax != 0x34) 298 print_serial("mov test 4: FAIL\n"); 299 else 300 print_serial("mov test 4: PASS\n"); 301 302 exec_in_big_real_mode(&inregs, &outregs, 303 insn_mov_r8_imm_3, 304 insn_mov_r8_imm_3_end - insn_mov_r8_imm_3); 305 if (!regs_equal(&inregs, &outregs, R_AX) || outregs.eax != 0x1234) 306 print_serial("mov test 5: FAIL\n"); 307 else 308 print_serial("mov test 5: PASS\n"); 309 } 310 311 void test_sub_imm(void) 312 { 313 struct regs inregs = { 0 }, outregs; 314 MK_INSN(sub_r32_imm_1, "mov $1234567890, %eax\n\t" "sub $10, %eax\n\t"); 315 MK_INSN(sub_r16_imm_1, "mov $1234, %ax\n\t" "sub $10, %ax\n\t"); 316 MK_INSN(sub_r8_imm_1, "mov $0x12, %ah\n\t" "sub $0x10, %ah\n\t"); 317 MK_INSN(sub_r8_imm_2, "mov $0x34, %al\n\t" "sub $0x10, %al\n\t"); 318 319 exec_in_big_real_mode(&inregs, &outregs, 320 insn_sub_r16_imm_1, 321 insn_sub_r16_imm_1_end - insn_sub_r16_imm_1); 322 if (!regs_equal(&inregs, &outregs, R_AX) || outregs.eax != 1224) 323 print_serial("sub test 1: FAIL\n"); 324 else 325 print_serial("sub test 1: PASS\n"); 326 327 /* test mov $imm, %eax */ 328 exec_in_big_real_mode(&inregs, &outregs, 329 insn_sub_r32_imm_1, 330 insn_sub_r32_imm_1_end - insn_sub_r32_imm_1); 331 if (!regs_equal(&inregs, &outregs, R_AX) || outregs.eax != 1234567880) 332 print_serial("sub test 2: FAIL\n"); 333 else 334 print_serial("sub test 2: PASS\n"); 335 336 /* test mov $imm, %al/%ah */ 337 exec_in_big_real_mode(&inregs, &outregs, 338 insn_sub_r8_imm_1, 339 insn_sub_r8_imm_1_end - insn_sub_r8_imm_1); 340 if (!regs_equal(&inregs, &outregs, R_AX) || outregs.eax != 0x0200) 341 print_serial("sub test 3: FAIL\n"); 342 else 343 print_serial("sub test 3: PASS\n"); 344 345 exec_in_big_real_mode(&inregs, &outregs, 346 insn_sub_r8_imm_2, 347 insn_sub_r8_imm_2_end - insn_sub_r8_imm_2); 348 if (!regs_equal(&inregs, &outregs, R_AX) || outregs.eax != 0x24) 349 print_serial("sub test 4: FAIL\n"); 350 else 351 print_serial("sub test 4: PASS\n"); 352 } 353 354 355 void test_xor_imm(void) 356 { 357 struct regs inregs = { 0 }, outregs; 358 MK_INSN(xor_r32_imm_1, "mov $1234567890, %eax\n\t" "xor $1234567890, %eax\n\t"); 359 MK_INSN(xor_r16_imm_1, "mov $1234, %ax\n\t" "xor $1234, %ax\n\t"); 360 MK_INSN(xor_r8_imm_1, "mov $0x12, %ah\n\t" "xor $0x12, %ah\n\t"); 361 MK_INSN(xor_r8_imm_2, "mov $0x34, %al\n\t" "xor $0x34, %al\n\t"); 362 363 exec_in_big_real_mode(&inregs, &outregs, 364 insn_xor_r16_imm_1, 365 insn_xor_r16_imm_1_end - insn_xor_r16_imm_1); 366 if (!regs_equal(&inregs, &outregs, R_AX) || outregs.eax != 0) 367 print_serial("xor test 1: FAIL\n"); 368 else 369 print_serial("xor test 1: PASS\n"); 370 371 /* test mov $imm, %eax */ 372 exec_in_big_real_mode(&inregs, &outregs, 373 insn_xor_r32_imm_1, 374 insn_xor_r32_imm_1_end - insn_xor_r32_imm_1); 375 if (!regs_equal(&inregs, &outregs, R_AX) || outregs.eax != 0) 376 print_serial("xor test 2: FAIL\n"); 377 else 378 print_serial("xor test 2: PASS\n"); 379 380 /* test mov $imm, %al/%ah */ 381 exec_in_big_real_mode(&inregs, &outregs, 382 insn_xor_r8_imm_1, 383 insn_xor_r8_imm_1_end - insn_xor_r8_imm_1); 384 if (!regs_equal(&inregs, &outregs, R_AX) || outregs.eax != 0) 385 print_serial("xor test 3: FAIL\n"); 386 else 387 print_serial("xor test 3: PASS\n"); 388 389 exec_in_big_real_mode(&inregs, &outregs, 390 insn_xor_r8_imm_2, 391 insn_xor_r8_imm_2_end - insn_xor_r8_imm_2); 392 if (!regs_equal(&inregs, &outregs, R_AX) || outregs.eax != 0) 393 print_serial("xor test 4: FAIL\n"); 394 else 395 print_serial("xor test 4: PASS\n"); 396 } 397 398 void test_cmp_imm(void) 399 { 400 struct regs inregs = { 0 }, outregs; 401 MK_INSN(cmp_test1, "mov $0x34, %al\n\t" 402 "cmp $0x34, %al\n\t"); 403 MK_INSN(cmp_test2, "mov $0x34, %al\n\t" 404 "cmp $0x39, %al\n\t"); 405 MK_INSN(cmp_test3, "mov $0x34, %al\n\t" 406 "cmp $0x24, %al\n\t"); 407 408 /* test cmp imm8 with AL */ 409 /* ZF: (bit 6) Zero Flag becomes 1 if an operation results 410 * in a 0 writeback, or 0 register 411 */ 412 exec_in_big_real_mode(&inregs, &outregs, 413 insn_cmp_test1, 414 insn_cmp_test1_end - insn_cmp_test1); 415 if ((outregs.eflags & (1<<6)) != (1<<6)) 416 print_serial("cmp test 1: FAIL\n"); 417 else 418 print_serial("cmp test 1: PASS\n"); 419 420 exec_in_big_real_mode(&inregs, &outregs, 421 insn_cmp_test2, 422 insn_cmp_test2_end - insn_cmp_test2); 423 if ((outregs.eflags & (1<<6)) != 0) 424 print_serial("cmp test 2: FAIL\n"); 425 else 426 print_serial("cmp test 2: PASS\n"); 427 428 exec_in_big_real_mode(&inregs, &outregs, 429 insn_cmp_test3, 430 insn_cmp_test3_end - insn_cmp_test3); 431 if ((outregs.eflags & (1<<6)) != 0) 432 print_serial("cmp test 3: FAIL\n"); 433 else 434 print_serial("cmp test 3: PASS\n"); 435 } 436 437 void test_add_imm(void) 438 { 439 struct regs inregs = { 0 }, outregs; 440 MK_INSN(add_test1, "mov $0x43211234, %eax \n\t" 441 "add $0x12344321, %eax \n\t"); 442 MK_INSN(add_test2, "mov $0x12, %eax \n\t" 443 "add $0x21, %al\n\t"); 444 445 exec_in_big_real_mode(&inregs, &outregs, 446 insn_add_test1, 447 insn_add_test1_end - insn_add_test1); 448 if (outregs.eax != 0x55555555) 449 print_serial("add test 1: FAIL\n"); 450 else 451 print_serial("add test 1: PASS\n"); 452 453 exec_in_big_real_mode(&inregs, &outregs, 454 insn_add_test2, 455 insn_add_test2_end - insn_add_test2); 456 if (outregs.eax != 0x33) 457 print_serial("add test 2: FAIL\n"); 458 else 459 print_serial("add test 2: PASS\n"); 460 } 461 462 void test_eflags_insn(void) 463 { 464 struct regs inregs = { 0 }, outregs; 465 MK_INSN(clc, "clc"); 466 MK_INSN(stc, "stc"); 467 MK_INSN(cli, "cli"); 468 MK_INSN(sti, "sti"); 469 MK_INSN(cld, "cld"); 470 MK_INSN(std, "std"); 471 472 exec_in_big_real_mode(&inregs, &outregs, 473 insn_clc, 474 insn_clc_end - insn_clc); 475 if (outregs.eflags & 1) 476 print_serial("clc test: FAIL\n"); 477 else 478 print_serial("clc test: PASS\n"); 479 480 exec_in_big_real_mode(&inregs, &outregs, 481 insn_stc, 482 insn_stc_end - insn_stc); 483 if (!(outregs.eflags & 1)) 484 print_serial("stc test: FAIL\n"); 485 else 486 print_serial("stc test: PASS\n"); 487 488 exec_in_big_real_mode(&inregs, &outregs, 489 insn_cli, 490 insn_cli_end - insn_cli); 491 if (outregs.eflags & (1 << 9)) 492 print_serial("cli test: FAIL\n"); 493 else 494 print_serial("cli test: PASS\n"); 495 496 exec_in_big_real_mode(&inregs, &outregs, 497 insn_sti, 498 insn_sti_end - insn_sti); 499 if (!(outregs.eflags & (1 << 9))) 500 print_serial("sti test: FAIL\n"); 501 else 502 print_serial("sti test: PASS\n"); 503 504 exec_in_big_real_mode(&inregs, &outregs, 505 insn_cld, 506 insn_cld_end - insn_cld); 507 if (outregs.eflags & (1 << 10)) 508 print_serial("cld test: FAIL\n"); 509 else 510 print_serial("cld test: PASS\n"); 511 512 exec_in_big_real_mode(&inregs, &outregs, 513 insn_std, 514 insn_std_end - insn_std); 515 if (!(outregs.eflags & (1 << 10))) 516 print_serial("std test: FAIL\n"); 517 else 518 print_serial("std test: PASS\n"); 519 } 520 521 void test_io(void) 522 { 523 struct regs inregs = { 0 }, outregs; 524 MK_INSN(io_test1, "mov $0xff, %al \n\t" 525 "out %al, $0xe0 \n\t" 526 "mov $0x00, %al \n\t" 527 "in $0xe0, %al \n\t"); 528 MK_INSN(io_test2, "mov $0xffff, %ax \n\t" 529 "out %ax, $0xe0 \n\t" 530 "mov $0x0000, %ax \n\t" 531 "in $0xe0, %ax \n\t"); 532 MK_INSN(io_test3, "mov $0xffffffff, %eax \n\t" 533 "out %eax, $0xe0 \n\t" 534 "mov $0x000000, %eax \n\t" 535 "in $0xe0, %eax \n\t"); 536 MK_INSN(io_test4, "mov $0xe0, %dx \n\t" 537 "mov $0xff, %al \n\t" 538 "out %al, %dx \n\t" 539 "mov $0x00, %al \n\t" 540 "in %dx, %al \n\t"); 541 MK_INSN(io_test5, "mov $0xe0, %dx \n\t" 542 "mov $0xffff, %ax \n\t" 543 "out %ax, %dx \n\t" 544 "mov $0x0000, %ax \n\t" 545 "in %dx, %ax \n\t"); 546 MK_INSN(io_test6, "mov $0xe0, %dx \n\t" 547 "mov $0xffffffff, %eax \n\t" 548 "out %eax, %dx \n\t" 549 "mov $0x00000000, %eax \n\t" 550 "in %dx, %eax \n\t"); 551 552 exec_in_big_real_mode(&inregs, &outregs, 553 insn_io_test1, 554 insn_io_test1_end - insn_io_test1); 555 556 if (!regs_equal(&inregs, &outregs, R_AX) || outregs.eax != 0xff) 557 print_serial("I/O test 1: FAIL\n"); 558 else 559 print_serial("I/O test 1: PASS\n"); 560 561 exec_in_big_real_mode(&inregs, &outregs, 562 insn_io_test2, 563 insn_io_test2_end - insn_io_test2); 564 565 if (!regs_equal(&inregs, &outregs, R_AX) || outregs.eax != 0xffff) 566 print_serial("I/O test 2: FAIL\n"); 567 else 568 print_serial("I/O test 2: PASS\n"); 569 570 exec_in_big_real_mode(&inregs, &outregs, 571 insn_io_test3, 572 insn_io_test3_end - insn_io_test3); 573 574 if (!regs_equal(&inregs, &outregs, R_AX) || outregs.eax != 0xffffffff) 575 print_serial("I/O test 3: FAIL\n"); 576 else 577 print_serial("I/O test 3: PASS\n"); 578 579 exec_in_big_real_mode(&inregs, &outregs, 580 insn_io_test4, 581 insn_io_test4_end - insn_io_test4); 582 583 if (!regs_equal(&inregs, &outregs, R_AX|R_DX) || outregs.eax != 0xff) 584 print_serial("I/O test 4: FAIL\n"); 585 else 586 print_serial("I/O test 4: PASS\n"); 587 588 exec_in_big_real_mode(&inregs, &outregs, 589 insn_io_test5, 590 insn_io_test5_end - insn_io_test5); 591 592 if (!regs_equal(&inregs, &outregs, R_AX|R_DX) || outregs.eax != 0xffff) 593 print_serial("I/O test 5: FAIL\n"); 594 else 595 print_serial("I/O test 5: PASS\n"); 596 597 exec_in_big_real_mode(&inregs, &outregs, 598 insn_io_test6, 599 insn_io_test6_end - insn_io_test6); 600 601 if (!regs_equal(&inregs, &outregs, R_AX|R_DX) || outregs.eax != 0xffffffff) 602 print_serial("I/O test 6: FAIL\n"); 603 else 604 print_serial("I/O test 6: PASS\n"); 605 } 606 607 void test_call(void) 608 { 609 struct regs inregs = { 0 }, outregs; 610 u32 esp[16]; 611 612 inregs.esp = (u32)esp; 613 614 MK_INSN(call1, "mov $test_function, %eax \n\t" 615 "call *%eax\n\t"); 616 MK_INSN(call_near1, "jmp 2f\n\t" 617 "1: mov $0x1234, %eax\n\t" 618 "ret\n\t" 619 "2: call 1b\t"); 620 MK_INSN(call_near2, "call 1f\n\t" 621 "jmp 2f\n\t" 622 "1: mov $0x1234, %eax\n\t" 623 "ret\n\t" 624 "2:\t"); 625 626 exec_in_big_real_mode(&inregs, &outregs, 627 insn_call1, 628 insn_call1_end - insn_call1); 629 if(!regs_equal(&inregs, &outregs, R_AX) || outregs.eax != 0x1234) 630 print_serial("Call Test 1: FAIL\n"); 631 else 632 print_serial("Call Test 1: PASS\n"); 633 634 exec_in_big_real_mode(&inregs, &outregs, 635 insn_call_near1, insn_call_near1_end - insn_call_near1); 636 if(!regs_equal(&inregs, &outregs, R_AX) || outregs.eax != 0x1234) 637 print_serial("Call near Test 1: FAIL\n"); 638 else 639 print_serial("Call near Test 1: PASS\n"); 640 641 exec_in_big_real_mode(&inregs, &outregs, 642 insn_call_near2, insn_call_near2_end - insn_call_near2); 643 if(!regs_equal(&inregs, &outregs, R_AX) || outregs.eax != 0x1234) 644 print_serial("Call near Test 2: FAIL\n"); 645 else 646 print_serial("Call near Test 2: PASS\n"); 647 } 648 649 void test_jcc_short(void) 650 { 651 struct regs inregs = { 0 }, outregs; 652 MK_INSN(jnz_short1, "jnz 1f\n\t" 653 "mov $0x1234, %eax\n\t" 654 "1:\n\t"); 655 MK_INSN(jnz_short2, "1:\n\t" 656 "cmp $0x1234, %eax\n\t" 657 "mov $0x1234, %eax\n\t" 658 "jnz 1b\n\t"); 659 MK_INSN(jmp_short1, "jmp 1f\n\t" 660 "mov $0x1234, %eax\n\t" 661 "1:\n\t"); 662 663 exec_in_big_real_mode(&inregs, &outregs, 664 insn_jnz_short1, insn_jnz_short1_end - insn_jnz_short1); 665 if(!regs_equal(&inregs, &outregs, 0)) 666 print_serial("JNZ short Test 1: FAIL\n"); 667 else 668 print_serial("JNZ short Test 1: PASS\n"); 669 670 exec_in_big_real_mode(&inregs, &outregs, 671 insn_jnz_short2, insn_jnz_short2_end - insn_jnz_short2); 672 if(!regs_equal(&inregs, &outregs, R_AX) || !(outregs.eflags & (1 << 6))) 673 print_serial("JNZ short Test 2: FAIL\n"); 674 else 675 print_serial("JNZ short Test 2: PASS\n"); 676 677 exec_in_big_real_mode(&inregs, &outregs, 678 insn_jmp_short1, insn_jmp_short1_end - insn_jmp_short1); 679 if(!regs_equal(&inregs, &outregs, 0)) 680 print_serial("JMP short Test 1: FAIL\n"); 681 else 682 print_serial("JMP short Test 1: PASS\n"); 683 } 684 685 void test_jcc_near(void) 686 { 687 struct regs inregs = { 0 }, outregs; 688 /* encode near jmp manually. gas will not do it if offsets < 127 byte */ 689 MK_INSN(jnz_near1, ".byte 0x0f, 0x85, 0x06, 0x00\n\t" 690 "mov $0x1234, %eax\n\t"); 691 MK_INSN(jnz_near2, "cmp $0x1234, %eax\n\t" 692 "mov $0x1234, %eax\n\t" 693 ".byte 0x0f, 0x85, 0xf0, 0xff\n\t"); 694 MK_INSN(jmp_near1, ".byte 0xE9, 0x06, 0x00\n\t" 695 "mov $0x1234, %eax\n\t"); 696 697 exec_in_big_real_mode(&inregs, &outregs, 698 insn_jnz_near1, insn_jnz_near1_end - insn_jnz_near1); 699 if(!regs_equal(&inregs, &outregs, 0)) 700 print_serial("JNZ near Test 1: FAIL\n"); 701 else 702 print_serial("JNZ near Test 1: PASS\n"); 703 704 exec_in_big_real_mode(&inregs, &outregs, 705 insn_jnz_near2, insn_jnz_near2_end - insn_jnz_near2); 706 if(!regs_equal(&inregs, &outregs, R_AX) || !(outregs.eflags & (1 << 6))) 707 print_serial("JNZ near Test 2: FAIL\n"); 708 else 709 print_serial("JNZ near Test 2: PASS\n"); 710 711 exec_in_big_real_mode(&inregs, &outregs, 712 insn_jmp_near1, insn_jmp_near1_end - insn_jmp_near1); 713 if(!regs_equal(&inregs, &outregs, 0)) 714 print_serial("JMP near Test 1: FAIL\n"); 715 else 716 print_serial("JMP near Test 1: PASS\n"); 717 } 718 719 void test_long_jmp() 720 { 721 struct regs inregs = { 0 }, outregs; 722 u32 esp[16]; 723 724 inregs.esp = (u32)esp; 725 MK_INSN(long_jmp, "call 1f\n\t" 726 "jmp 2f\n\t" 727 "1: jmp $0, $test_function\n\t" 728 "2:\n\t"); 729 exec_in_big_real_mode(&inregs, &outregs, 730 insn_long_jmp, 731 insn_long_jmp_end - insn_long_jmp); 732 if(!regs_equal(&inregs, &outregs, R_AX) || outregs.eax != 0x1234) 733 print_serial("Long JMP Test: FAIL\n"); 734 else 735 print_serial("Long JMP Test: PASS\n"); 736 } 737 738 void test_push_pop() 739 { 740 struct regs inregs = { 0 }, outregs; 741 MK_INSN(push32, "mov $0x12345678, %eax\n\t" 742 "push %eax\n\t" 743 "pop %ebx\n\t"); 744 MK_INSN(push16, "mov $0x1234, %ax\n\t" 745 "push %ax\n\t" 746 "pop %bx\n\t"); 747 748 MK_INSN(push_es, "mov $0x231, %bx\n\t" //Just write a dummy value to see if it gets overwritten 749 "mov $0x123, %ax\n\t" 750 "mov %ax, %es\n\t" 751 "push %es\n\t" 752 "pop %bx \n\t" 753 ); 754 MK_INSN(pop_es, "push %ax\n\t" 755 "pop %es\n\t" 756 "mov %es, %bx\n\t" 757 ); 758 MK_INSN(push_pop_ss, "push %ss\n\t" 759 "pushw %ax\n\t" 760 "popw %ss\n\t" 761 "mov %ss, %bx\n\t" 762 "pop %ss\n\t" 763 ); 764 MK_INSN(push_pop_fs, "push %fs\n\t" 765 "pushl %eax\n\t" 766 "popl %fs\n\t" 767 "mov %fs, %ebx\n\t" 768 "pop %fs\n\t" 769 ); 770 771 exec_in_big_real_mode(&inregs, &outregs, 772 insn_push32, 773 insn_push32_end - insn_push32); 774 if (!regs_equal(&inregs, &outregs, R_AX|R_BX) || outregs.eax != outregs.ebx || outregs.eax != 0x12345678) 775 print_serial("Push/Pop Test 1: FAIL\n"); 776 else 777 print_serial("Push/Pop Test 1: PASS\n"); 778 779 exec_in_big_real_mode(&inregs, &outregs, 780 insn_push16, 781 insn_push16_end - insn_push16); 782 783 if (!regs_equal(&inregs, &outregs, R_AX|R_BX) || outregs.eax != outregs.ebx || outregs.eax != 0x1234) 784 print_serial("Push/Pop Test 2: FAIL\n"); 785 else 786 print_serial("Push/Pop Test 2: PASS\n"); 787 788 exec_in_big_real_mode(&inregs, &outregs, 789 insn_push_es, 790 insn_push_es_end - insn_push_es); 791 if (!regs_equal(&inregs, &outregs, R_AX|R_BX) || outregs.ebx != outregs.eax || outregs.eax != 0x123) 792 print_serial("Push/Pop Test 3: FAIL\n"); 793 else 794 print_serial("Push/Pop Test 3: PASS\n"); 795 796 exec_in_big_real_mode(&inregs, &outregs, 797 insn_pop_es, 798 insn_pop_es_end - insn_pop_es); 799 800 if (!regs_equal(&inregs, &outregs, R_AX|R_BX) || outregs.ebx != outregs.eax) 801 print_serial("Push/Pop Test 4: FAIL\n"); 802 else 803 print_serial("Push/Pop Test 4: PASS\n"); 804 805 exec_in_big_real_mode(&inregs, &outregs, 806 insn_push_pop_ss, 807 insn_push_pop_ss_end - insn_push_pop_ss); 808 809 if (!regs_equal(&inregs, &outregs, R_AX|R_BX) || outregs.ebx != outregs.eax) 810 print_serial("Push/Pop Test 5: FAIL\n"); 811 else 812 print_serial("Push/Pop Test 5: PASS\n"); 813 814 exec_in_big_real_mode(&inregs, &outregs, 815 insn_push_pop_fs, 816 insn_push_pop_fs_end - insn_push_pop_fs); 817 818 if (!regs_equal(&inregs, &outregs, R_AX|R_BX) || outregs.ebx != outregs.eax) 819 print_serial("Push/Pop Test 6: FAIL\n"); 820 else 821 print_serial("Push/Pop Test 6: PASS\n"); 822 } 823 824 void test_null(void) 825 { 826 struct regs inregs = { 0 }, outregs; 827 exec_in_big_real_mode(&inregs, &outregs, 0, 0); 828 if (!regs_equal(&inregs, &outregs, 0)) 829 print_serial("null test: FAIL\n"); 830 else 831 print_serial("null test: PASS\n"); 832 } 833 834 struct { 835 char stack[500]; 836 char top[]; 837 } tmp_stack; 838 839 void test_pusha_popa() 840 { 841 struct regs inregs = { .eax = 0, .ebx = 1, .ecx = 2, .edx = 3, .esi = 4, .edi = 5, .ebp = 6, .esp = (unsigned long)&tmp_stack.top }, outregs; 842 843 MK_INSN(pusha, "pusha\n\t" 844 "pop %edi\n\t" 845 "pop %esi\n\t" 846 "pop %ebp\n\t" 847 "add $4, %esp\n\t" 848 "pop %ebx\n\t" 849 "pop %edx\n\t" 850 "pop %ecx\n\t" 851 "pop %eax\n\t" 852 ); 853 854 MK_INSN(popa, "push %eax\n\t" 855 "push %ecx\n\t" 856 "push %edx\n\t" 857 "push %ebx\n\t" 858 "push %esp\n\t" 859 "push %ebp\n\t" 860 "push %esi\n\t" 861 "push %edi\n\t" 862 "popa\n\t" 863 ); 864 865 exec_in_big_real_mode(&inregs, &outregs, 866 insn_pusha, 867 insn_pusha_end - insn_pusha); 868 869 if (!regs_equal(&inregs, &outregs, 0)) 870 print_serial("Pusha/Popa Test1: FAIL\n"); 871 else 872 print_serial("Pusha/Popa Test1: PASS\n"); 873 874 exec_in_big_real_mode(&inregs, &outregs, 875 insn_popa, 876 insn_popa_end - insn_popa); 877 if (!regs_equal(&inregs, &outregs, 0)) 878 print_serial("Pusha/Popa Test2: FAIL\n"); 879 else 880 print_serial("Pusha/Popa Test2: PASS\n"); 881 } 882 883 void test_iret() 884 { 885 struct regs inregs = { 0 }, outregs; 886 887 MK_INSN(iret32, "pushf\n\t" 888 "pushl %cs\n\t" 889 "call 1f\n\t" /* a near call will push eip onto the stack */ 890 "jmp 2f\n\t" 891 "1: iret\n\t" 892 "2:\n\t" 893 ); 894 895 MK_INSN(iret16, "pushfw\n\t" 896 "pushw %cs\n\t" 897 "callw 1f\n\t" 898 "jmp 2f\n\t" 899 "1: iretw\n\t" 900 "2:\n\t"); 901 902 MK_INSN(iret_flags32, "pushfl\n\t" 903 "popl %eax\n\t" 904 "andl $~0x2, %eax\n\t" 905 "orl $0xffc08028, %eax\n\t" 906 "pushl %eax\n\t" 907 "pushl %cs\n\t" 908 "call 1f\n\t" 909 "jmp 2f\n\t" 910 "1: iret\n\t" 911 "2:\n\t"); 912 913 MK_INSN(iret_flags16, "pushfw\n\t" 914 "popw %ax\n\t" 915 "and $~0x2, %ax\n\t" 916 "or $0x8028, %ax\n\t" 917 "pushw %ax\n\t" 918 "pushw %cs\n\t" 919 "callw 1f\n\t" 920 "jmp 2f\n\t" 921 "1: iretw\n\t" 922 "2:\n\t"); 923 924 exec_in_big_real_mode(&inregs, &outregs, 925 insn_iret32, 926 insn_iret32_end - insn_iret32); 927 928 if (!regs_equal(&inregs, &outregs, 0)) 929 print_serial("iret Test 1: FAIL\n"); 930 else 931 print_serial("iret Test 1: PASS\n"); 932 933 exec_in_big_real_mode(&inregs, &outregs, 934 insn_iret16, 935 insn_iret16_end - insn_iret16); 936 937 if (!regs_equal(&inregs, &outregs, 0)) 938 print_serial("iret Test 2: FAIL\n"); 939 else 940 print_serial("iret Test 2: PASS\n"); 941 942 exec_in_big_real_mode(&inregs, &outregs, 943 insn_iret_flags32, 944 insn_iret_flags32_end - insn_iret_flags32); 945 946 if (!regs_equal(&inregs, &outregs, R_AX)) 947 print_serial("iret Test 3: FAIL\n"); 948 else 949 print_serial("iret Test 3: PASS\n"); 950 951 exec_in_big_real_mode(&inregs, &outregs, 952 insn_iret_flags16, 953 insn_iret_flags16_end - insn_iret_flags16); 954 955 if (!regs_equal(&inregs, &outregs, R_AX)) 956 print_serial("iret Test 4: FAIL\n"); 957 else 958 print_serial("iret Test 4: PASS\n"); 959 } 960 961 void test_int() 962 { 963 struct regs inregs = { 0 }, outregs; 964 965 *(u32 *)(0x11 * 4) = 0x1000; /* Store a pointer to address 0x1000 in IDT entry 0x11 */ 966 *(u8 *)(0x1000) = 0xcf; /* 0x1000 contains an IRET instruction */ 967 968 MK_INSN(int11, "int $0x11\n\t"); 969 970 exec_in_big_real_mode(&inregs, &outregs, 971 insn_int11, 972 insn_int11_end - insn_int11); 973 974 if (!regs_equal(&inregs, &outregs, 0)) 975 print_serial("int Test 1: FAIL\n"); 976 else 977 print_serial("int Test 1: PASS\n"); 978 } 979 980 void test_imul() 981 { 982 struct regs inregs = { 0 }, outregs; 983 984 MK_INSN(imul8_1, "mov $2, %al\n\t" 985 "mov $-4, %cx\n\t" 986 "imul %cl\n\t"); 987 988 MK_INSN(imul16_1, "mov $2, %ax\n\t" 989 "mov $-4, %cx\n\t" 990 "imul %cx\n\t"); 991 992 MK_INSN(imul32_1, "mov $2, %eax\n\t" 993 "mov $-4, %ecx\n\t" 994 "imul %ecx\n\t"); 995 996 MK_INSN(imul8_2, "mov $0x12340002, %eax\n\t" 997 "mov $4, %cx\n\t" 998 "imul %cl\n\t"); 999 1000 MK_INSN(imul16_2, "mov $2, %ax\n\t" 1001 "mov $4, %cx\n\t" 1002 "imul %cx\n\t"); 1003 1004 MK_INSN(imul32_2, "mov $2, %eax\n\t" 1005 "mov $4, %ecx\n\t" 1006 "imul %ecx\n\t"); 1007 1008 exec_in_big_real_mode(&inregs, &outregs, 1009 insn_imul8_1, 1010 insn_imul8_1_end - insn_imul8_1); 1011 1012 if (!regs_equal(&inregs, &outregs, R_AX | R_CX | R_DX) || (outregs.eax & 0xff) != (u8)-8) 1013 print_serial("imul Test 1: FAIL\n"); 1014 else 1015 print_serial("imul Test 1: PASS\n"); 1016 1017 exec_in_big_real_mode(&inregs, &outregs, 1018 insn_imul16_1, 1019 insn_imul16_1_end - insn_imul16_1); 1020 1021 if (!regs_equal(&inregs, &outregs, R_AX | R_CX | R_DX) || outregs.eax != (u16)-8) 1022 print_serial("imul Test 2: FAIL\n"); 1023 else 1024 print_serial("imul Test 2: PASS\n"); 1025 1026 exec_in_big_real_mode(&inregs, &outregs, 1027 insn_imul32_1, 1028 insn_imul32_1_end - insn_imul32_1); 1029 1030 if (!regs_equal(&inregs, &outregs, R_AX | R_CX | R_DX) || outregs.eax != (u32)-8) 1031 print_serial("imul Test 3: FAIL\n"); 1032 else 1033 print_serial("imul Test 3: PASS\n"); 1034 1035 exec_in_big_real_mode(&inregs, &outregs, 1036 insn_imul8_2, 1037 insn_imul8_2_end - insn_imul8_2); 1038 1039 if (!regs_equal(&inregs, &outregs, R_AX | R_CX | R_DX) || (outregs.eax & 0xffff) != 8 || 1040 (outregs.eax & 0xffff0000) != 0x12340000) 1041 print_serial("imul Test 4: FAIL\n"); 1042 else 1043 print_serial("imul Test 4: PASS\n"); 1044 1045 exec_in_big_real_mode(&inregs, &outregs, 1046 insn_imul16_2, 1047 insn_imul16_2_end - insn_imul16_2); 1048 1049 if (!regs_equal(&inregs, &outregs, R_AX | R_CX | R_DX) || outregs.eax != 8) 1050 print_serial("imul Test 5: FAIL\n"); 1051 else 1052 print_serial("imul Test 5: PASS\n"); 1053 1054 exec_in_big_real_mode(&inregs, &outregs, 1055 insn_imul32_2, 1056 insn_imul32_2_end - insn_imul32_2); 1057 1058 if (!regs_equal(&inregs, &outregs, R_AX | R_CX | R_DX) || outregs.eax != 8) 1059 print_serial("imul Test 6: FAIL\n"); 1060 else 1061 print_serial("imul Test 6: PASS\n"); 1062 } 1063 1064 void test_mul() 1065 { 1066 struct regs inregs = { 0 }, outregs; 1067 1068 MK_INSN(mul8, "mov $2, %al\n\t" 1069 "mov $4, %cx\n\t" 1070 "imul %cl\n\t"); 1071 1072 MK_INSN(mul16, "mov $2, %ax\n\t" 1073 "mov $4, %cx\n\t" 1074 "imul %cx\n\t"); 1075 1076 MK_INSN(mul32, "mov $2, %eax\n\t" 1077 "mov $4, %ecx\n\t" 1078 "imul %ecx\n\t"); 1079 1080 exec_in_big_real_mode(&inregs, &outregs, 1081 insn_mul8, 1082 insn_mul8_end - insn_mul8); 1083 1084 if (!regs_equal(&inregs, &outregs, R_AX | R_CX | R_DX) || (outregs.eax & 0xff) != 8) 1085 print_serial("mul Test 1: FAIL\n"); 1086 else 1087 print_serial("mul Test 1: PASS\n"); 1088 1089 exec_in_big_real_mode(&inregs, &outregs, 1090 insn_mul16, 1091 insn_mul16_end - insn_mul16); 1092 1093 if (!regs_equal(&inregs, &outregs, R_AX | R_CX | R_DX) || outregs.eax != 8) 1094 print_serial("mul Test 2: FAIL\n"); 1095 else 1096 print_serial("mul Test 2: PASS\n"); 1097 1098 exec_in_big_real_mode(&inregs, &outregs, 1099 insn_mul32, 1100 insn_mul32_end - insn_mul32); 1101 1102 if (!regs_equal(&inregs, &outregs, R_AX | R_CX | R_DX) || outregs.eax != 8) 1103 print_serial("mul Test 3: FAIL\n"); 1104 else 1105 print_serial("mul Test 3: PASS\n"); 1106 } 1107 1108 void test_div() 1109 { 1110 struct regs inregs = { 0 }, outregs; 1111 1112 MK_INSN(div8, "mov $257, %ax\n\t" 1113 "mov $2, %cl\n\t" 1114 "div %cl\n\t"); 1115 1116 MK_INSN(div16, "mov $512, %ax\n\t" 1117 "mov $5, %cx\n\t" 1118 "div %cx\n\t"); 1119 1120 MK_INSN(div32, "mov $512, %eax\n\t" 1121 "mov $5, %ecx\n\t" 1122 "div %ecx\n\t"); 1123 1124 exec_in_big_real_mode(&inregs, &outregs, 1125 insn_div8, 1126 insn_div8_end - insn_div8); 1127 1128 if (!regs_equal(&inregs, &outregs, R_AX | R_CX | R_DX) || outregs.eax != 384) 1129 print_serial("div Test 1: FAIL\n"); 1130 else 1131 print_serial("div Test 1: PASS\n"); 1132 1133 exec_in_big_real_mode(&inregs, &outregs, 1134 insn_div16, 1135 insn_div16_end - insn_div16); 1136 1137 if (!regs_equal(&inregs, &outregs, R_AX | R_CX | R_DX) || outregs.eax != 102 || 1138 outregs.edx != 2) 1139 print_serial("div Test 2: FAIL\n"); 1140 else 1141 print_serial("div Test 2: PASS\n"); 1142 1143 exec_in_big_real_mode(&inregs, &outregs, 1144 insn_div32, 1145 insn_div32_end - insn_div32); 1146 1147 if (!regs_equal(&inregs, &outregs, R_AX | R_CX | R_DX) || outregs.eax != 102 || 1148 outregs.edx != 2) 1149 print_serial("div Test 3: FAIL\n"); 1150 else 1151 print_serial("div Test 3: PASS\n"); 1152 } 1153 1154 void test_idiv() 1155 { 1156 struct regs inregs = { 0 }, outregs; 1157 1158 MK_INSN(idiv8, "mov $256, %ax\n\t" 1159 "mov $-2, %cl\n\t" 1160 "idiv %cl\n\t"); 1161 1162 MK_INSN(idiv16, "mov $512, %ax\n\t" 1163 "mov $-2, %cx\n\t" 1164 "idiv %cx\n\t"); 1165 1166 MK_INSN(idiv32, "mov $512, %eax\n\t" 1167 "mov $-2, %ecx\n\t" 1168 "idiv %ecx\n\t"); 1169 1170 exec_in_big_real_mode(&inregs, &outregs, 1171 insn_idiv8, 1172 insn_idiv8_end - insn_idiv8); 1173 1174 if (!regs_equal(&inregs, &outregs, R_AX | R_CX | R_DX) || outregs.eax != (u8)-128) 1175 print_serial("idiv Test 1: FAIL\n"); 1176 else 1177 print_serial("idiv Test 1: PASS\n"); 1178 1179 exec_in_big_real_mode(&inregs, &outregs, 1180 insn_idiv16, 1181 insn_idiv16_end - insn_idiv16); 1182 1183 if (!regs_equal(&inregs, &outregs, R_AX | R_CX | R_DX) || outregs.eax != (u16)-256) 1184 print_serial("idiv Test 2: FAIL\n"); 1185 else 1186 print_serial("idiv Test 2: PASS\n"); 1187 1188 exec_in_big_real_mode(&inregs, &outregs, 1189 insn_idiv32, 1190 insn_idiv32_end - insn_idiv32); 1191 1192 if (!regs_equal(&inregs, &outregs, R_AX | R_CX | R_DX) || outregs.eax != (u32)-256) 1193 print_serial("idiv Test 3: FAIL\n"); 1194 else 1195 print_serial("idiv Test 3: PASS\n"); 1196 } 1197 1198 void test_cbw(void) 1199 { 1200 struct regs inregs = { 0 }, outregs; 1201 1202 MK_INSN(cbw, "mov $0xFE, %eax \n\t" 1203 "cbw\n\t"); 1204 MK_INSN(cwde, "mov $0xFFFE, %eax \n\t" 1205 "cwde\n\t"); 1206 1207 exec_in_big_real_mode(&inregs, &outregs, 1208 insn_cbw, 1209 insn_cbw_end - insn_cbw); 1210 if (outregs.eax != 0xFFFE) 1211 print_serial("cbw test1: FAIL\n"); 1212 else 1213 print_serial("cbw test 1: PASS\n"); 1214 1215 exec_in_big_real_mode(&inregs, &outregs, 1216 insn_cwde, 1217 insn_cwde_end - insn_cwde); 1218 if (outregs.eax != 0xFFFFFFFE) 1219 print_serial("cwde test1: FAIL\n"); 1220 else 1221 print_serial("cwde test 1: PASS\n"); 1222 } 1223 1224 void test_loopcc(void) 1225 { 1226 struct regs inregs = { 0 }, outregs; 1227 1228 MK_INSN(loop, "mov $10, %ecx\n\t" 1229 "1: inc %eax\n\t" 1230 "loop 1b\n\t"); 1231 1232 MK_INSN(loope, "mov $10, %ecx\n\t" 1233 "mov $1, %eax\n\t" 1234 "1: dec %eax\n\t" 1235 "loope 1b\n\t"); 1236 1237 MK_INSN(loopne, "mov $10, %ecx\n\t" 1238 "mov $5, %eax\n\t" 1239 "1: dec %eax\n\t" 1240 "loopne 1b\n\t"); 1241 1242 exec_in_big_real_mode(&inregs, &outregs, 1243 insn_loop, insn_loop_end - insn_loop); 1244 if(!regs_equal(&inregs, &outregs, R_AX) || outregs.eax != 10) 1245 print_serial("LOOPcc short Test 1: FAIL\n"); 1246 else 1247 print_serial("LOOPcc short Test 1: PASS\n"); 1248 1249 exec_in_big_real_mode(&inregs, &outregs, 1250 insn_loope, insn_loope_end - insn_loope); 1251 if(!regs_equal(&inregs, &outregs, R_AX | R_CX) || 1252 outregs.eax != -1 || outregs.ecx != 8) 1253 print_serial("LOOPcc short Test 2: FAIL\n"); 1254 else 1255 print_serial("LOOPcc short Test 2: PASS\n"); 1256 1257 exec_in_big_real_mode(&inregs, &outregs, 1258 insn_loopne, insn_loopne_end - insn_loopne); 1259 if(!regs_equal(&inregs, &outregs, R_AX | R_CX) || 1260 outregs.eax != 0 || outregs.ecx != 5) 1261 print_serial("LOOPcc short Test 3: FAIL\n"); 1262 else 1263 print_serial("LOOPcc short Test 3: PASS\n"); 1264 } 1265 1266 void realmode_start(void) 1267 { 1268 test_null(); 1269 1270 test_shld(); 1271 test_push_pop(); 1272 test_pusha_popa(); 1273 test_mov_imm(); 1274 test_cmp_imm(); 1275 test_add_imm(); 1276 test_sub_imm(); 1277 test_xor_imm(); 1278 test_io(); 1279 test_eflags_insn(); 1280 test_jcc_short(); 1281 test_jcc_near(); 1282 /* test_call() uses short jump so call it after testing jcc */ 1283 test_call(); 1284 /* long jmp test uses call near so test it after testing call */ 1285 test_long_jmp(); 1286 test_xchg(); 1287 test_iret(); 1288 test_int(); 1289 test_imul(); 1290 test_mul(); 1291 test_div(); 1292 test_idiv(); 1293 test_loopcc(); 1294 test_cbw(); 1295 1296 exit(0); 1297 } 1298 1299 unsigned long long r_gdt[] = { 0, 0x9b000000ffff, 0x93000000ffff }; 1300 1301 struct __attribute__((packed)) { 1302 unsigned short limit; 1303 void *base; 1304 } r_gdt_descr = { sizeof(r_gdt) - 1, &r_gdt }; 1305 1306 asm( 1307 ".section .init \n\t" 1308 1309 ".code32 \n\t" 1310 1311 "mb_magic = 0x1BADB002 \n\t" 1312 "mb_flags = 0x0 \n\t" 1313 1314 "# multiboot header \n\t" 1315 ".long mb_magic, mb_flags, 0 - (mb_magic + mb_flags) \n\t" 1316 1317 ".globl start \n\t" 1318 ".data \n\t" 1319 ". = . + 4096 \n\t" 1320 "stacktop: \n\t" 1321 1322 ".text \n\t" 1323 "start: \n\t" 1324 "lgdt r_gdt_descr \n\t" 1325 "ljmp $8, $1f; 1: \n\t" 1326 ".code16gcc \n\t" 1327 "mov $16, %eax \n\t" 1328 "mov %ax, %ds \n\t" 1329 "mov %ax, %es \n\t" 1330 "mov %ax, %fs \n\t" 1331 "mov %ax, %gs \n\t" 1332 "mov %ax, %ss \n\t" 1333 "mov %cr0, %eax \n\t" 1334 "btc $0, %eax \n\t" 1335 "mov %eax, %cr0 \n\t" 1336 "ljmp $0, $realmode_entry \n\t" 1337 1338 "realmode_entry: \n\t" 1339 1340 "xor %ax, %ax \n\t" 1341 "mov %ax, %ds \n\t" 1342 "mov %ax, %es \n\t" 1343 "mov %ax, %ss \n\t" 1344 "mov %ax, %fs \n\t" 1345 "mov %ax, %gs \n\t" 1346 "mov $stacktop, %esp\n\t" 1347 "ljmp $0, $realmode_start \n\t" 1348 1349 ".code16gcc \n\t" 1350 ); 1351