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 "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" 89 90 "test_insn: . = . + 32\n\t" 91 "test_insn_end: \n\t" 92 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" 101 102 /* Save EFLAGS in outregs*/ 103 "pushfl \n\t" 104 "popl %[save]+36 \n\t" 105 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" 111 ); 112 *outregs = save; 113 } 114 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 123 124 int regs_equal(const struct regs *r1, const struct regs *r2, int ignore) 125 { 126 const u32 *p1 = &r1->eax, *p2 = &r2->eax; // yuck 127 int i; 128 129 for (i = 0; i < 8; ++i) 130 if (!(ignore & (1 << i)) && p1[i] != p2[i]) 131 return 0; 132 return 1; 133 } 134 135 #define MK_INSN(name, str) \ 136 asm ( \ 137 ".text 1\n\t" \ 138 "insn_" #name ": " str " \n\t" \ 139 "insn_" #name "_end: \n\t" \ 140 ".text\n\t" \ 141 ); \ 142 extern u8 insn_##name[], insn_##name##_end[] 143 144 void test_xchg(void) 145 { 146 struct regs inregs = { .eax = 0, .ebx = 1, .ecx = 2, .edx = 3, .esi = 4, .edi = 5, .ebp = 6, .esp = 7}, outregs; 147 148 MK_INSN(xchg_test1, "xchg %eax,%eax\n\t"); 149 MK_INSN(xchg_test2, "xchg %eax,%ebx\n\t"); 150 MK_INSN(xchg_test3, "xchg %eax,%ecx\n\t"); 151 MK_INSN(xchg_test4, "xchg %eax,%edx\n\t"); 152 MK_INSN(xchg_test5, "xchg %eax,%esi\n\t"); 153 MK_INSN(xchg_test6, "xchg %eax,%edi\n\t"); 154 MK_INSN(xchg_test7, "xchg %eax,%ebp\n\t"); 155 MK_INSN(xchg_test8, "xchg %eax,%esp\n\t"); 156 157 exec_in_big_real_mode(&inregs, &outregs, 158 insn_xchg_test1, 159 insn_xchg_test1_end - insn_xchg_test1); 160 161 if (!regs_equal(&inregs, &outregs, 0)) 162 print_serial("xchg test 1: FAIL\n"); 163 else 164 print_serial("xchg test 1: PASS\n"); 165 166 exec_in_big_real_mode(&inregs, &outregs, 167 insn_xchg_test2, 168 insn_xchg_test2_end - insn_xchg_test2); 169 170 if (!regs_equal(&inregs, &outregs, R_AX | R_BX) || 171 outregs.eax != inregs.ebx || 172 outregs.ebx != inregs.eax) 173 print_serial("xchg test 2: FAIL\n"); 174 else 175 print_serial("xchg test 2: PASS\n"); 176 177 exec_in_big_real_mode(&inregs, &outregs, 178 insn_xchg_test3, 179 insn_xchg_test3_end - insn_xchg_test3); 180 181 if (!regs_equal(&inregs, &outregs, R_AX | R_CX) || 182 outregs.eax != inregs.ecx || 183 outregs.ecx != inregs.eax) 184 print_serial("xchg test 3: FAIL\n"); 185 else 186 print_serial("xchg test 3: PASS\n"); 187 188 exec_in_big_real_mode(&inregs, &outregs, 189 insn_xchg_test4, 190 insn_xchg_test4_end - insn_xchg_test4); 191 192 if (!regs_equal(&inregs, &outregs, R_AX | R_DX) || 193 outregs.eax != inregs.edx || 194 outregs.edx != inregs.eax) 195 print_serial("xchg test 4: FAIL\n"); 196 else 197 print_serial("xchg test 4: PASS\n"); 198 199 exec_in_big_real_mode(&inregs, &outregs, 200 insn_xchg_test5, 201 insn_xchg_test5_end - insn_xchg_test5); 202 203 if (!regs_equal(&inregs, &outregs, R_AX | R_SI) || 204 outregs.eax != inregs.esi || 205 outregs.esi != inregs.eax) 206 print_serial("xchg test 5: FAIL\n"); 207 else 208 print_serial("xchg test 5: PASS\n"); 209 210 exec_in_big_real_mode(&inregs, &outregs, 211 insn_xchg_test6, 212 insn_xchg_test6_end - insn_xchg_test6); 213 214 if (!regs_equal(&inregs, &outregs, R_AX | R_DI) || 215 outregs.eax != inregs.edi || 216 outregs.edi != inregs.eax) 217 print_serial("xchg test 6: FAIL\n"); 218 else 219 print_serial("xchg test 6: PASS\n"); 220 221 exec_in_big_real_mode(&inregs, &outregs, 222 insn_xchg_test7, 223 insn_xchg_test7_end - insn_xchg_test7); 224 225 if (!regs_equal(&inregs, &outregs, R_AX | R_BP) || 226 outregs.eax != inregs.ebp || 227 outregs.ebp != inregs.eax) 228 print_serial("xchg test 7: FAIL\n"); 229 else 230 print_serial("xchg test 7: PASS\n"); 231 232 exec_in_big_real_mode(&inregs, &outregs, 233 insn_xchg_test8, 234 insn_xchg_test8_end - insn_xchg_test8); 235 236 if (!regs_equal(&inregs, &outregs, R_AX | R_SP) || 237 outregs.eax != inregs.esp || 238 outregs.esp != inregs.eax) 239 print_serial("xchg test 8: FAIL\n"); 240 else 241 print_serial("xchg test 8: PASS\n"); 242 } 243 244 void test_shld(void) 245 { 246 struct regs inregs = { .eax = 0xbe, .edx = 0xef000000 }, outregs; 247 MK_INSN(shld_test, "shld $8,%edx,%eax\n\t"); 248 249 exec_in_big_real_mode(&inregs, &outregs, 250 insn_shld_test, 251 insn_shld_test_end - insn_shld_test); 252 if (outregs.eax != 0xbeef) 253 print_serial("shld: FAIL\n"); 254 else 255 print_serial("shld: PASS\n"); 256 } 257 258 void test_mov_imm(void) 259 { 260 struct regs inregs = { 0 }, outregs; 261 MK_INSN(mov_r32_imm_1, "mov $1234567890, %eax"); 262 MK_INSN(mov_r16_imm_1, "mov $1234, %ax"); 263 MK_INSN(mov_r8_imm_1, "mov $0x12, %ah"); 264 MK_INSN(mov_r8_imm_2, "mov $0x34, %al"); 265 MK_INSN(mov_r8_imm_3, "mov $0x12, %ah\n\t" "mov $0x34, %al\n\t"); 266 267 exec_in_big_real_mode(&inregs, &outregs, 268 insn_mov_r16_imm_1, 269 insn_mov_r16_imm_1_end - insn_mov_r16_imm_1); 270 if (!regs_equal(&inregs, &outregs, R_AX) || outregs.eax != 1234) 271 print_serial("mov test 1: FAIL\n"); 272 else 273 print_serial("mov test 1: PASS\n"); 274 275 /* test mov $imm, %eax */ 276 exec_in_big_real_mode(&inregs, &outregs, 277 insn_mov_r32_imm_1, 278 insn_mov_r32_imm_1_end - insn_mov_r32_imm_1); 279 if (!regs_equal(&inregs, &outregs, R_AX) || outregs.eax != 1234567890) 280 print_serial("mov test 2: FAIL\n"); 281 else 282 print_serial("mov test 2: PASS\n"); 283 284 /* test mov $imm, %al/%ah */ 285 exec_in_big_real_mode(&inregs, &outregs, 286 insn_mov_r8_imm_1, 287 insn_mov_r8_imm_1_end - insn_mov_r8_imm_1); 288 if (!regs_equal(&inregs, &outregs, R_AX) || outregs.eax != 0x1200) 289 print_serial("mov test 3: FAIL\n"); 290 else 291 print_serial("mov test 3: PASS\n"); 292 293 exec_in_big_real_mode(&inregs, &outregs, 294 insn_mov_r8_imm_2, 295 insn_mov_r8_imm_2_end - insn_mov_r8_imm_2); 296 if (!regs_equal(&inregs, &outregs, R_AX) || outregs.eax != 0x34) 297 print_serial("mov test 4: FAIL\n"); 298 else 299 print_serial("mov test 4: PASS\n"); 300 301 exec_in_big_real_mode(&inregs, &outregs, 302 insn_mov_r8_imm_3, 303 insn_mov_r8_imm_3_end - insn_mov_r8_imm_3); 304 if (!regs_equal(&inregs, &outregs, R_AX) || outregs.eax != 0x1234) 305 print_serial("mov test 5: FAIL\n"); 306 else 307 print_serial("mov test 5: PASS\n"); 308 } 309 310 void test_sub_imm(void) 311 { 312 struct regs inregs = { 0 }, outregs; 313 MK_INSN(sub_r32_imm_1, "mov $1234567890, %eax\n\t" "sub $10, %eax\n\t"); 314 MK_INSN(sub_r16_imm_1, "mov $1234, %ax\n\t" "sub $10, %ax\n\t"); 315 MK_INSN(sub_r8_imm_1, "mov $0x12, %ah\n\t" "sub $0x10, %ah\n\t"); 316 MK_INSN(sub_r8_imm_2, "mov $0x34, %al\n\t" "sub $0x10, %al\n\t"); 317 318 exec_in_big_real_mode(&inregs, &outregs, 319 insn_sub_r16_imm_1, 320 insn_sub_r16_imm_1_end - insn_sub_r16_imm_1); 321 if (!regs_equal(&inregs, &outregs, R_AX) || outregs.eax != 1224) 322 print_serial("sub test 1: FAIL\n"); 323 else 324 print_serial("sub test 1: PASS\n"); 325 326 /* test mov $imm, %eax */ 327 exec_in_big_real_mode(&inregs, &outregs, 328 insn_sub_r32_imm_1, 329 insn_sub_r32_imm_1_end - insn_sub_r32_imm_1); 330 if (!regs_equal(&inregs, &outregs, R_AX) || outregs.eax != 1234567880) 331 print_serial("sub test 2: FAIL\n"); 332 else 333 print_serial("sub test 2: PASS\n"); 334 335 /* test mov $imm, %al/%ah */ 336 exec_in_big_real_mode(&inregs, &outregs, 337 insn_sub_r8_imm_1, 338 insn_sub_r8_imm_1_end - insn_sub_r8_imm_1); 339 if (!regs_equal(&inregs, &outregs, R_AX) || outregs.eax != 0x0200) 340 print_serial("sub test 3: FAIL\n"); 341 else 342 print_serial("sub test 3: PASS\n"); 343 344 exec_in_big_real_mode(&inregs, &outregs, 345 insn_sub_r8_imm_2, 346 insn_sub_r8_imm_2_end - insn_sub_r8_imm_2); 347 if (!regs_equal(&inregs, &outregs, R_AX) || outregs.eax != 0x24) 348 print_serial("sub test 4: FAIL\n"); 349 else 350 print_serial("sub test 4: PASS\n"); 351 } 352 353 354 void test_xor_imm(void) 355 { 356 struct regs inregs = { 0 }, outregs; 357 MK_INSN(xor_r32_imm_1, "mov $1234567890, %eax\n\t" "xor $1234567890, %eax\n\t"); 358 MK_INSN(xor_r16_imm_1, "mov $1234, %ax\n\t" "xor $1234, %ax\n\t"); 359 MK_INSN(xor_r8_imm_1, "mov $0x12, %ah\n\t" "xor $0x12, %ah\n\t"); 360 MK_INSN(xor_r8_imm_2, "mov $0x34, %al\n\t" "xor $0x34, %al\n\t"); 361 362 exec_in_big_real_mode(&inregs, &outregs, 363 insn_xor_r16_imm_1, 364 insn_xor_r16_imm_1_end - insn_xor_r16_imm_1); 365 if (!regs_equal(&inregs, &outregs, R_AX) || outregs.eax != 0) 366 print_serial("xor test 1: FAIL\n"); 367 else 368 print_serial("xor test 1: PASS\n"); 369 370 /* test mov $imm, %eax */ 371 exec_in_big_real_mode(&inregs, &outregs, 372 insn_xor_r32_imm_1, 373 insn_xor_r32_imm_1_end - insn_xor_r32_imm_1); 374 if (!regs_equal(&inregs, &outregs, R_AX) || outregs.eax != 0) 375 print_serial("xor test 2: FAIL\n"); 376 else 377 print_serial("xor test 2: PASS\n"); 378 379 /* test mov $imm, %al/%ah */ 380 exec_in_big_real_mode(&inregs, &outregs, 381 insn_xor_r8_imm_1, 382 insn_xor_r8_imm_1_end - insn_xor_r8_imm_1); 383 if (!regs_equal(&inregs, &outregs, R_AX) || outregs.eax != 0) 384 print_serial("xor test 3: FAIL\n"); 385 else 386 print_serial("xor test 3: PASS\n"); 387 388 exec_in_big_real_mode(&inregs, &outregs, 389 insn_xor_r8_imm_2, 390 insn_xor_r8_imm_2_end - insn_xor_r8_imm_2); 391 if (!regs_equal(&inregs, &outregs, R_AX) || outregs.eax != 0) 392 print_serial("xor test 4: FAIL\n"); 393 else 394 print_serial("xor test 4: PASS\n"); 395 } 396 397 void test_cmp_imm(void) 398 { 399 struct regs inregs = { 0 }, outregs; 400 MK_INSN(cmp_test1, "mov $0x34, %al\n\t" 401 "cmp $0x34, %al\n\t"); 402 MK_INSN(cmp_test2, "mov $0x34, %al\n\t" 403 "cmp $0x39, %al\n\t"); 404 MK_INSN(cmp_test3, "mov $0x34, %al\n\t" 405 "cmp $0x24, %al\n\t"); 406 407 /* test cmp imm8 with AL */ 408 /* ZF: (bit 6) Zero Flag becomes 1 if an operation results 409 * in a 0 writeback, or 0 register 410 */ 411 exec_in_big_real_mode(&inregs, &outregs, 412 insn_cmp_test1, 413 insn_cmp_test1_end - insn_cmp_test1); 414 if ((outregs.eflags & (1<<6)) != (1<<6)) 415 print_serial("cmp test 1: FAIL\n"); 416 else 417 print_serial("cmp test 1: PASS\n"); 418 419 exec_in_big_real_mode(&inregs, &outregs, 420 insn_cmp_test2, 421 insn_cmp_test2_end - insn_cmp_test2); 422 if ((outregs.eflags & (1<<6)) != 0) 423 print_serial("cmp test 2: FAIL\n"); 424 else 425 print_serial("cmp test 2: PASS\n"); 426 427 exec_in_big_real_mode(&inregs, &outregs, 428 insn_cmp_test3, 429 insn_cmp_test3_end - insn_cmp_test3); 430 if ((outregs.eflags & (1<<6)) != 0) 431 print_serial("cmp test 3: FAIL\n"); 432 else 433 print_serial("cmp test 3: PASS\n"); 434 } 435 436 void test_add_imm(void) 437 { 438 struct regs inregs = { 0 }, outregs; 439 MK_INSN(add_test1, "mov $0x43211234, %eax \n\t" 440 "add $0x12344321, %eax \n\t"); 441 MK_INSN(add_test2, "mov $0x12, %eax \n\t" 442 "add $0x21, %al\n\t"); 443 444 exec_in_big_real_mode(&inregs, &outregs, 445 insn_add_test1, 446 insn_add_test1_end - insn_add_test1); 447 if (outregs.eax != 0x55555555) 448 print_serial("add test 1: FAIL\n"); 449 else 450 print_serial("add test 1: PASS\n"); 451 452 exec_in_big_real_mode(&inregs, &outregs, 453 insn_add_test2, 454 insn_add_test2_end - insn_add_test2); 455 if (outregs.eax != 0x33) 456 print_serial("add test 2: FAIL\n"); 457 else 458 print_serial("add test 2: PASS\n"); 459 } 460 461 void test_eflags_insn(void) 462 { 463 struct regs inregs = { 0 }, outregs; 464 MK_INSN(clc, "clc"); 465 MK_INSN(cli, "cli"); 466 MK_INSN(sti, "sti"); 467 MK_INSN(cld, "cld"); 468 MK_INSN(std, "std"); 469 470 exec_in_big_real_mode(&inregs, &outregs, 471 insn_clc, 472 insn_clc_end - insn_clc); 473 if (outregs.eflags & 1) 474 print_serial("clc test: FAIL\n"); 475 else 476 print_serial("clc test: PASS\n"); 477 478 exec_in_big_real_mode(&inregs, &outregs, 479 insn_cli, 480 insn_cli_end - insn_cli); 481 if (outregs.eflags & (1 << 9)) 482 print_serial("cli test: FAIL\n"); 483 else 484 print_serial("cli test: PASS\n"); 485 486 exec_in_big_real_mode(&inregs, &outregs, 487 insn_sti, 488 insn_sti_end - insn_sti); 489 if (!(outregs.eflags & (1 << 9))) 490 print_serial("sti test: FAIL\n"); 491 else 492 print_serial("sti test: PASS\n"); 493 494 exec_in_big_real_mode(&inregs, &outregs, 495 insn_cld, 496 insn_cld_end - insn_cld); 497 if (outregs.eflags & (1 << 10)) 498 print_serial("cld test: FAIL\n"); 499 else 500 print_serial("cld test: PASS\n"); 501 502 exec_in_big_real_mode(&inregs, &outregs, 503 insn_std, 504 insn_std_end - insn_std); 505 if (!(outregs.eflags & (1 << 10))) 506 print_serial("std test: FAIL\n"); 507 else 508 print_serial("std test: PASS\n"); 509 } 510 511 void test_io(void) 512 { 513 struct regs inregs = { 0 }, outregs; 514 MK_INSN(io_test1, "mov $0xff, %al \n\t" 515 "out %al, $0xe0 \n\t" 516 "mov $0x00, %al \n\t" 517 "in $0xe0, %al \n\t"); 518 MK_INSN(io_test2, "mov $0xffff, %ax \n\t" 519 "out %ax, $0xe0 \n\t" 520 "mov $0x0000, %ax \n\t" 521 "in $0xe0, %ax \n\t"); 522 MK_INSN(io_test3, "mov $0xffffffff, %eax \n\t" 523 "out %eax, $0xe0 \n\t" 524 "mov $0x000000, %eax \n\t" 525 "in $0xe0, %eax \n\t"); 526 MK_INSN(io_test4, "mov $0xe0, %dx \n\t" 527 "mov $0xff, %al \n\t" 528 "out %al, %dx \n\t" 529 "mov $0x00, %al \n\t" 530 "in %dx, %al \n\t"); 531 MK_INSN(io_test5, "mov $0xe0, %dx \n\t" 532 "mov $0xffff, %ax \n\t" 533 "out %ax, %dx \n\t" 534 "mov $0x0000, %ax \n\t" 535 "in %dx, %ax \n\t"); 536 MK_INSN(io_test6, "mov $0xe0, %dx \n\t" 537 "mov $0xffffffff, %eax \n\t" 538 "out %eax, %dx \n\t" 539 "mov $0x00000000, %eax \n\t" 540 "in %dx, %eax \n\t"); 541 542 exec_in_big_real_mode(&inregs, &outregs, 543 insn_io_test1, 544 insn_io_test1_end - insn_io_test1); 545 546 if (!regs_equal(&inregs, &outregs, R_AX) || outregs.eax != 0xff) 547 print_serial("I/O test 1: FAIL\n"); 548 else 549 print_serial("I/O test 1: PASS\n"); 550 551 exec_in_big_real_mode(&inregs, &outregs, 552 insn_io_test2, 553 insn_io_test2_end - insn_io_test2); 554 555 if (!regs_equal(&inregs, &outregs, R_AX) || outregs.eax != 0xffff) 556 print_serial("I/O test 2: FAIL\n"); 557 else 558 print_serial("I/O test 2: PASS\n"); 559 560 exec_in_big_real_mode(&inregs, &outregs, 561 insn_io_test3, 562 insn_io_test3_end - insn_io_test3); 563 564 if (!regs_equal(&inregs, &outregs, R_AX) || outregs.eax != 0xffffffff) 565 print_serial("I/O test 3: FAIL\n"); 566 else 567 print_serial("I/O test 3: PASS\n"); 568 569 exec_in_big_real_mode(&inregs, &outregs, 570 insn_io_test4, 571 insn_io_test4_end - insn_io_test4); 572 573 if (!regs_equal(&inregs, &outregs, R_AX|R_DX) || outregs.eax != 0xff) 574 print_serial("I/O test 4: FAIL\n"); 575 else 576 print_serial("I/O test 4: PASS\n"); 577 578 exec_in_big_real_mode(&inregs, &outregs, 579 insn_io_test5, 580 insn_io_test5_end - insn_io_test5); 581 582 if (!regs_equal(&inregs, &outregs, R_AX|R_DX) || outregs.eax != 0xffff) 583 print_serial("I/O test 5: FAIL\n"); 584 else 585 print_serial("I/O test 5: PASS\n"); 586 587 exec_in_big_real_mode(&inregs, &outregs, 588 insn_io_test6, 589 insn_io_test6_end - insn_io_test6); 590 591 if (!regs_equal(&inregs, &outregs, R_AX|R_DX) || outregs.eax != 0xffffffff) 592 print_serial("I/O test 6: FAIL\n"); 593 else 594 print_serial("I/O test 6: PASS\n"); 595 } 596 597 void test_call(void) 598 { 599 struct regs inregs = { 0 }, outregs; 600 u32 esp[16]; 601 602 inregs.esp = (u32)esp; 603 604 MK_INSN(call1, "mov $test_function, %eax \n\t" 605 "call *%eax\n\t"); 606 MK_INSN(call_near1, "jmp 2f\n\t" 607 "1: mov $0x1234, %eax\n\t" 608 "ret\n\t" 609 "2: call 1b\t"); 610 MK_INSN(call_near2, "call 1f\n\t" 611 "jmp 2f\n\t" 612 "1: mov $0x1234, %eax\n\t" 613 "ret\n\t" 614 "2:\t"); 615 616 exec_in_big_real_mode(&inregs, &outregs, 617 insn_call1, 618 insn_call1_end - insn_call1); 619 if(!regs_equal(&inregs, &outregs, R_AX) || outregs.eax != 0x1234) 620 print_serial("Call Test 1: FAIL\n"); 621 else 622 print_serial("Call Test 1: PASS\n"); 623 624 exec_in_big_real_mode(&inregs, &outregs, 625 insn_call_near1, insn_call_near1_end - insn_call_near1); 626 if(!regs_equal(&inregs, &outregs, R_AX) || outregs.eax != 0x1234) 627 print_serial("Call near Test 1: FAIL\n"); 628 else 629 print_serial("Call near Test 1: PASS\n"); 630 631 exec_in_big_real_mode(&inregs, &outregs, 632 insn_call_near2, insn_call_near2_end - insn_call_near2); 633 if(!regs_equal(&inregs, &outregs, R_AX) || outregs.eax != 0x1234) 634 print_serial("Call near Test 2: FAIL\n"); 635 else 636 print_serial("Call near Test 2: PASS\n"); 637 } 638 639 void test_jcc_short(void) 640 { 641 struct regs inregs = { 0 }, outregs; 642 MK_INSN(jnz_short1, "jnz 1f\n\t" 643 "mov $0x1234, %eax\n\t" 644 "1:\n\t"); 645 MK_INSN(jnz_short2, "1:\n\t" 646 "cmp $0x1234, %eax\n\t" 647 "mov $0x1234, %eax\n\t" 648 "jnz 1b\n\t"); 649 MK_INSN(jmp_short1, "jmp 1f\n\t" 650 "mov $0x1234, %eax\n\t" 651 "1:\n\t"); 652 653 exec_in_big_real_mode(&inregs, &outregs, 654 insn_jnz_short1, insn_jnz_short1_end - insn_jnz_short1); 655 if(!regs_equal(&inregs, &outregs, 0)) 656 print_serial("JNZ short Test 1: FAIL\n"); 657 else 658 print_serial("JNZ short Test 1: PASS\n"); 659 660 exec_in_big_real_mode(&inregs, &outregs, 661 insn_jnz_short2, insn_jnz_short2_end - insn_jnz_short2); 662 if(!regs_equal(&inregs, &outregs, R_AX) || !(outregs.eflags & (1 << 6))) 663 print_serial("JNZ short Test 2: FAIL\n"); 664 else 665 print_serial("JNZ short Test 2: PASS\n"); 666 667 exec_in_big_real_mode(&inregs, &outregs, 668 insn_jmp_short1, insn_jmp_short1_end - insn_jmp_short1); 669 if(!regs_equal(&inregs, &outregs, 0)) 670 print_serial("JMP short Test 1: FAIL\n"); 671 else 672 print_serial("JMP short Test 1: PASS\n"); 673 } 674 675 void test_jcc_near(void) 676 { 677 struct regs inregs = { 0 }, outregs; 678 /* encode near jmp manually. gas will not do it if offsets < 127 byte */ 679 MK_INSN(jnz_near1, ".byte 0x0f, 0x85, 0x06, 0x00\n\t" 680 "mov $0x1234, %eax\n\t"); 681 MK_INSN(jnz_near2, "cmp $0x1234, %eax\n\t" 682 "mov $0x1234, %eax\n\t" 683 ".byte 0x0f, 0x85, 0xf0, 0xff\n\t"); 684 MK_INSN(jmp_near1, ".byte 0xE9, 0x06, 0x00\n\t" 685 "mov $0x1234, %eax\n\t"); 686 687 exec_in_big_real_mode(&inregs, &outregs, 688 insn_jnz_near1, insn_jnz_near1_end - insn_jnz_near1); 689 if(!regs_equal(&inregs, &outregs, 0)) 690 print_serial("JNZ near Test 1: FAIL\n"); 691 else 692 print_serial("JNZ near Test 1: PASS\n"); 693 694 exec_in_big_real_mode(&inregs, &outregs, 695 insn_jnz_near2, insn_jnz_near2_end - insn_jnz_near2); 696 if(!regs_equal(&inregs, &outregs, R_AX) || !(outregs.eflags & (1 << 6))) 697 print_serial("JNZ near Test 2: FAIL\n"); 698 else 699 print_serial("JNZ near Test 2: PASS\n"); 700 701 exec_in_big_real_mode(&inregs, &outregs, 702 insn_jmp_near1, insn_jmp_near1_end - insn_jmp_near1); 703 if(!regs_equal(&inregs, &outregs, 0)) 704 print_serial("JMP near Test 1: FAIL\n"); 705 else 706 print_serial("JMP near Test 1: PASS\n"); 707 } 708 709 void test_long_jmp() 710 { 711 struct regs inregs = { 0 }, outregs; 712 u32 esp[16]; 713 714 inregs.esp = (u32)esp; 715 MK_INSN(long_jmp, "call 1f\n\t" 716 "jmp 2f\n\t" 717 "1: jmp $0, $test_function\n\t" 718 "2:\n\t"); 719 exec_in_big_real_mode(&inregs, &outregs, 720 insn_long_jmp, 721 insn_long_jmp_end - insn_long_jmp); 722 if(!regs_equal(&inregs, &outregs, R_AX) || outregs.eax != 0x1234) 723 print_serial("Long JMP Test: FAIL\n"); 724 else 725 print_serial("Long JMP Test: PASS\n"); 726 } 727 void test_push_pop() 728 { 729 struct regs inregs = { 0 }, outregs; 730 MK_INSN(push32, "mov $0x12345678, %eax\n\t" 731 "push %eax\n\t" 732 "pop %ebx\n\t"); 733 MK_INSN(push16, "mov $0x1234, %ax\n\t" 734 "push %ax\n\t" 735 "pop %bx\n\t"); 736 737 MK_INSN(push_es, "mov $0x231, %bx\n\t" //Just write a dummy value to see if it gets overwritten 738 "mov $0x123, %ax\n\t" 739 "mov %ax, %es\n\t" 740 "push %es\n\t" 741 "pop %bx \n\t" 742 ); 743 MK_INSN(pop_es, "push %ax\n\t" 744 "pop %es\n\t" 745 "mov %es, %bx\n\t" 746 ); 747 MK_INSN(push_pop_ss, "push %ss\n\t" 748 "pushw %ax\n\t" 749 "popw %ss\n\t" 750 "mov %ss, %bx\n\t" 751 "pop %ss\n\t" 752 ); 753 MK_INSN(push_pop_fs, "push %fs\n\t" 754 "pushl %eax\n\t" 755 "popl %fs\n\t" 756 "mov %fs, %ebx\n\t" 757 "pop %fs\n\t" 758 ); 759 760 exec_in_big_real_mode(&inregs, &outregs, 761 insn_push32, 762 insn_push32_end - insn_push32); 763 if (!regs_equal(&inregs, &outregs, R_AX|R_BX) || outregs.eax != outregs.ebx || outregs.eax != 0x12345678) 764 print_serial("Push/Pop Test 1: FAIL\n"); 765 else 766 print_serial("Push/Pop Test 1: PASS\n"); 767 768 exec_in_big_real_mode(&inregs, &outregs, 769 insn_push16, 770 insn_push16_end - insn_push16); 771 772 if (!regs_equal(&inregs, &outregs, R_AX|R_BX) || outregs.eax != outregs.ebx || outregs.eax != 0x1234) 773 print_serial("Push/Pop Test 2: FAIL\n"); 774 else 775 print_serial("Push/Pop Test 2: PASS\n"); 776 777 exec_in_big_real_mode(&inregs, &outregs, 778 insn_push_es, 779 insn_push_es_end - insn_push_es); 780 if (!regs_equal(&inregs, &outregs, R_AX|R_BX) || outregs.ebx != outregs.eax || outregs.eax != 0x123) 781 print_serial("Push/Pop Test 3: FAIL\n"); 782 else 783 print_serial("Push/Pop Test 3: PASS\n"); 784 785 exec_in_big_real_mode(&inregs, &outregs, 786 insn_pop_es, 787 insn_pop_es_end - insn_pop_es); 788 789 if (!regs_equal(&inregs, &outregs, R_AX|R_BX) || outregs.ebx != outregs.eax) 790 print_serial("Push/Pop Test 4: FAIL\n"); 791 else 792 print_serial("Push/Pop Test 4: PASS\n"); 793 794 exec_in_big_real_mode(&inregs, &outregs, 795 insn_push_pop_ss, 796 insn_push_pop_ss_end - insn_push_pop_ss); 797 798 if (!regs_equal(&inregs, &outregs, R_AX|R_BX) || outregs.ebx != outregs.eax) 799 print_serial("Push/Pop Test 5: FAIL\n"); 800 else 801 print_serial("Push/Pop Test 5: PASS\n"); 802 803 exec_in_big_real_mode(&inregs, &outregs, 804 insn_push_pop_fs, 805 insn_push_pop_fs_end - insn_push_pop_fs); 806 807 if (!regs_equal(&inregs, &outregs, R_AX|R_BX) || outregs.ebx != outregs.eax) 808 print_serial("Push/Pop Test 6: FAIL\n"); 809 else 810 print_serial("Push/Pop Test 6: PASS\n"); 811 } 812 813 void test_null(void) 814 { 815 struct regs inregs = { 0 }, outregs; 816 exec_in_big_real_mode(&inregs, &outregs, 0, 0); 817 if (!regs_equal(&inregs, &outregs, 0)) 818 print_serial("null test: FAIL\n"); 819 else 820 print_serial("null test: PASS\n"); 821 } 822 823 struct { 824 char stack[500]; 825 char top[]; 826 } tmp_stack; 827 828 void test_pusha_popa() 829 { 830 struct regs inregs = { .eax = 0, .ebx = 1, .ecx = 2, .edx = 3, .esi = 4, .edi = 5, .ebp = 6, .esp = (unsigned long)&tmp_stack.top }, outregs; 831 832 MK_INSN(pusha, "pusha\n\t" 833 "pop %edi\n\t" 834 "pop %esi\n\t" 835 "pop %ebp\n\t" 836 "add $4, %esp\n\t" 837 "pop %ebx\n\t" 838 "pop %edx\n\t" 839 "pop %ecx\n\t" 840 "pop %eax\n\t" 841 ); 842 843 MK_INSN(popa, "push %eax\n\t" 844 "push %ecx\n\t" 845 "push %edx\n\t" 846 "push %ebx\n\t" 847 "push %esp\n\t" 848 "push %ebp\n\t" 849 "push %esi\n\t" 850 "push %edi\n\t" 851 "popa\n\t" 852 ); 853 854 exec_in_big_real_mode(&inregs, &outregs, 855 insn_pusha, 856 insn_pusha_end - insn_pusha); 857 858 if (!regs_equal(&inregs, &outregs, 0)) 859 print_serial("Pusha/Popa Test1: FAIL\n"); 860 else 861 print_serial("Pusha/Popa Test1: PASS\n"); 862 863 exec_in_big_real_mode(&inregs, &outregs, 864 insn_popa, 865 insn_popa_end - insn_popa); 866 if (!regs_equal(&inregs, &outregs, 0)) 867 print_serial("Pusha/Popa Test2: FAIL\n"); 868 else 869 print_serial("Pusha/Popa Test2: PASS\n"); 870 } 871 872 void test_iret() 873 { 874 struct regs inregs = { 0 }, outregs; 875 876 MK_INSN(iret32, "pushf\n\t" 877 "pushl %cs\n\t" 878 "call 1f\n\t" /* a near call will push eip onto the stack */ 879 "jmp 2f\n\t" 880 "1: iret\n\t" 881 "2:\n\t" 882 ); 883 884 MK_INSN(iret16, "pushfw\n\t" 885 "pushw %cs\n\t" 886 "callw 1f\n\t" 887 "jmp 2f\n\t" 888 "1: iretw\n\t" 889 "2:\n\t"); 890 891 MK_INSN(iret_flags32, "pushfl\n\t" 892 "popl %eax\n\t" 893 "andl $~0x2, %eax\n\t" 894 "orl $0xffc08028, %eax\n\t" 895 "pushl %eax\n\t" 896 "pushl %cs\n\t" 897 "call 1f\n\t" 898 "jmp 2f\n\t" 899 "1: iret\n\t" 900 "2:\n\t"); 901 902 MK_INSN(iret_flags16, "pushfw\n\t" 903 "popw %ax\n\t" 904 "and $~0x2, %ax\n\t" 905 "or $0x8028, %ax\n\t" 906 "pushw %ax\n\t" 907 "pushw %cs\n\t" 908 "callw 1f\n\t" 909 "jmp 2f\n\t" 910 "1: iretw\n\t" 911 "2:\n\t"); 912 913 exec_in_big_real_mode(&inregs, &outregs, 914 insn_iret32, 915 insn_iret32_end - insn_iret32); 916 917 if (!regs_equal(&inregs, &outregs, 0)) 918 print_serial("iret Test 1: FAIL\n"); 919 else 920 print_serial("iret Test 1: PASS\n"); 921 922 exec_in_big_real_mode(&inregs, &outregs, 923 insn_iret16, 924 insn_iret16_end - insn_iret16); 925 926 if (!regs_equal(&inregs, &outregs, 0)) 927 print_serial("iret Test 2: FAIL\n"); 928 else 929 print_serial("iret Test 2: PASS\n"); 930 931 exec_in_big_real_mode(&inregs, &outregs, 932 insn_iret_flags32, 933 insn_iret_flags32_end - insn_iret_flags32); 934 935 if (!regs_equal(&inregs, &outregs, R_AX)) 936 print_serial("iret Test 3: FAIL\n"); 937 else 938 print_serial("iret Test 3: PASS\n"); 939 940 exec_in_big_real_mode(&inregs, &outregs, 941 insn_iret_flags16, 942 insn_iret_flags16_end - insn_iret_flags16); 943 944 if (!regs_equal(&inregs, &outregs, R_AX)) 945 print_serial("iret Test 4: FAIL\n"); 946 else 947 print_serial("iret Test 4: PASS\n"); 948 } 949 950 void realmode_start(void) 951 { 952 test_null(); 953 954 test_shld(); 955 test_push_pop(); 956 test_pusha_popa(); 957 test_mov_imm(); 958 test_cmp_imm(); 959 test_add_imm(); 960 test_sub_imm(); 961 test_xor_imm(); 962 test_io(); 963 test_eflags_insn(); 964 test_jcc_short(); 965 test_jcc_near(); 966 /* test_call() uses short jump so call it after testing jcc */ 967 test_call(); 968 /* long jmp test uses call near so test it after testing call */ 969 test_long_jmp(); 970 test_xchg(); 971 test_iret(); 972 973 exit(0); 974 } 975 976 unsigned long long r_gdt[] = { 0, 0x9b000000ffff, 0x93000000ffff }; 977 978 struct __attribute__((packed)) { 979 unsigned short limit; 980 void *base; 981 } r_gdt_descr = { sizeof(r_gdt) - 1, &r_gdt }; 982 983 asm( 984 ".section .init \n\t" 985 986 ".code32 \n\t" 987 988 "mb_magic = 0x1BADB002 \n\t" 989 "mb_flags = 0x0 \n\t" 990 991 "# multiboot header \n\t" 992 ".long mb_magic, mb_flags, 0 - (mb_magic + mb_flags) \n\t" 993 994 ".globl start \n\t" 995 ".data \n\t" 996 ". = . + 4096 \n\t" 997 "stacktop: \n\t" 998 999 ".text \n\t" 1000 "start: \n\t" 1001 "lgdt r_gdt_descr \n\t" 1002 "ljmp $8, $1f; 1: \n\t" 1003 ".code16gcc \n\t" 1004 "mov $16, %eax \n\t" 1005 "mov %ax, %ds \n\t" 1006 "mov %ax, %es \n\t" 1007 "mov %ax, %fs \n\t" 1008 "mov %ax, %gs \n\t" 1009 "mov %ax, %ss \n\t" 1010 "mov %cr0, %eax \n\t" 1011 "btc $0, %eax \n\t" 1012 "mov %eax, %cr0 \n\t" 1013 "ljmp $0, $realmode_entry \n\t" 1014 1015 "realmode_entry: \n\t" 1016 1017 "xor %ax, %ax \n\t" 1018 "mov %ax, %ds \n\t" 1019 "mov %ax, %es \n\t" 1020 "mov %ax, %ss \n\t" 1021 "mov %ax, %fs \n\t" 1022 "mov %ax, %gs \n\t" 1023 "mov $stacktop, %esp\n\t" 1024 "ljmp $0, $realmode_start \n\t" 1025 1026 ".code16gcc \n\t" 1027 ); 1028