Tests may use the stack during execution. It's easy to miss allocating one, so automatically point %esp to the stack when initializing "inregs". Also remove the initialization of ".esp" in "test_movzx_movsx" as it doesn't appear to be required. Signed-off-by: Bill Wendling <morbo@xxxxxxxxxx> --- x86/realmode.c | 158 +++++++++++++++++++++++++++++-------------------- 1 file changed, 95 insertions(+), 63 deletions(-) diff --git a/x86/realmode.c b/x86/realmode.c index 629a221..f5967ef 100644 --- a/x86/realmode.c +++ b/x86/realmode.c @@ -11,6 +11,10 @@ typedef unsigned short u16; typedef unsigned u32; typedef unsigned long long u64; +#ifndef NULL +#define NULL ((void*)0) +#endif + void realmode_start(void); void test_function(void); @@ -140,8 +144,22 @@ struct insn_desc { u16 len; }; +struct { + u32 stack[128]; + char top[]; +} tmp_stack; + static struct regs inregs, outregs; +static inline void init_inregs(struct regs *regs) +{ + inregs = (struct regs){ 0 }; + if (regs) + inregs = *regs; + if (!inregs.esp) + inregs.esp = (unsigned long)&tmp_stack.top; +} + static void exec_in_big_real_mode(struct insn_desc *insn) { unsigned long tmp; @@ -302,7 +320,8 @@ static void test_shld(void) { MK_INSN(shld_test, "shld $8,%edx,%eax\n\t"); - inregs = (struct regs){ .eax = 0xbe, .edx = 0xef000000 }; + init_inregs(&(struct regs){ .eax = 0xbe, .edx = 0xef000000 }); + exec_in_big_real_mode(&insn_shld_test); report("shld", ~0, outregs.eax == 0xbeef); } @@ -315,7 +334,7 @@ static void test_mov_imm(void) MK_INSN(mov_r8_imm_2, "mov $0x34, %al"); MK_INSN(mov_r8_imm_3, "mov $0x12, %ah\n\t" "mov $0x34, %al\n\t"); - inregs = (struct regs){ 0 }; + init_inregs(NULL); exec_in_big_real_mode(&insn_mov_r16_imm_1); report("mov 1", R_AX, outregs.eax == 1234); @@ -342,7 +361,7 @@ static void test_sub_imm(void) MK_INSN(sub_r8_imm_1, "mov $0x12, %ah\n\t" "sub $0x10, %ah\n\t"); MK_INSN(sub_r8_imm_2, "mov $0x34, %al\n\t" "sub $0x10, %al\n\t"); - inregs = (struct regs){ 0 }; + init_inregs(NULL); exec_in_big_real_mode(&insn_sub_r16_imm_1); report("sub 1", R_AX, outregs.eax == 1224); @@ -366,7 +385,7 @@ static void test_xor_imm(void) MK_INSN(xor_r8_imm_1, "mov $0x12, %ah\n\t" "xor $0x12, %ah\n\t"); MK_INSN(xor_r8_imm_2, "mov $0x34, %al\n\t" "xor $0x34, %al\n\t"); - inregs = (struct regs){ 0 }; + init_inregs(NULL); exec_in_big_real_mode(&insn_xor_r16_imm_1); report("xor 1", R_AX, outregs.eax == 0); @@ -392,7 +411,7 @@ static void test_cmp_imm(void) MK_INSN(cmp_test3, "mov $0x34, %al\n\t" "cmp $0x24, %al\n\t"); - inregs = (struct regs){ 0 }; + init_inregs(NULL); /* test cmp imm8 with AL */ /* ZF: (bit 6) Zero Flag becomes 1 if an operation results @@ -415,7 +434,7 @@ static void test_add_imm(void) MK_INSN(add_test2, "mov $0x12, %eax \n\t" "add $0x21, %al\n\t"); - inregs = (struct regs){ 0 }; + init_inregs(NULL); exec_in_big_real_mode(&insn_add_test1); report("add 1", ~0, outregs.eax == 0x55555555); @@ -433,7 +452,7 @@ static void test_eflags_insn(void) MK_INSN(cld, "cld"); MK_INSN(std, "std"); - inregs = (struct regs){ 0 }; + init_inregs(NULL); exec_in_big_real_mode(&insn_clc); report("clc", ~0, (outregs.eflags & 1) == 0); @@ -484,7 +503,7 @@ static void test_io(void) "mov $0x00000000, %eax \n\t" "in %dx, %eax \n\t"); - inregs = (struct regs){ 0 }; + init_inregs(NULL); exec_in_big_real_mode(&insn_io_test1); report("pio 1", R_AX, outregs.eax == 0xff); @@ -513,12 +532,8 @@ extern void retf_imm(void); static void test_call(void) { - u32 esp[16]; u32 addr; - inregs = (struct regs){ 0 }; - inregs.esp = (u32)&esp[ARRAY_SIZE(esp)]; - MK_INSN(call1, "mov $test_function, %eax \n\t" "call *%eax\n\t"); MK_INSN(call_near1, "jmp 2f\n\t" @@ -535,6 +550,8 @@ static void test_call(void) MK_INSN(ret_imm, "sub $10, %sp; jmp 2f; 1: retw $10; 2: callw 1b"); MK_INSN(retf_imm, "sub $10, %sp; lcallw $0, $retf_imm"); + init_inregs(NULL); + exec_in_big_real_mode(&insn_call1); report("call 1", R_AX, outregs.eax == 0x1234); @@ -572,7 +589,7 @@ static void test_jcc_short(void) "mov $0x1234, %eax\n\t" "1:\n\t"); - inregs = (struct regs){ 0 }; + init_inregs(NULL); exec_in_big_real_mode(&insn_jnz_short1); report("jnz short 1", ~0, 1); @@ -595,7 +612,7 @@ static void test_jcc_near(void) MK_INSN(jmp_near1, ".byte 0xE9, 0x06, 0x00\n\t" "mov $0x1234, %eax\n\t"); - inregs = (struct regs){ 0 }; + init_inregs(NULL); exec_in_big_real_mode(&insn_jnz_near1); report("jnz near 1", 0, 1); @@ -609,14 +626,13 @@ static void test_jcc_near(void) static void test_long_jmp(void) { - u32 esp[16]; - - inregs = (struct regs){ 0 }; - inregs.esp = (u32)&esp[ARRAY_SIZE(esp)]; MK_INSN(long_jmp, "call 1f\n\t" "jmp 2f\n\t" "1: jmp $0, $test_function\n\t" "2:\n\t"); + + init_inregs(NULL); + exec_in_big_real_mode(&insn_long_jmp); report("jmp far 1", R_AX, outregs.eax == 0x1234); } @@ -658,7 +674,7 @@ static void test_push_pop(void) "xor $0x12340000, %esp \n\t" "pop %bx"); - inregs = (struct regs){ 0 }; + init_inregs(NULL); exec_in_big_real_mode(&insn_push32); report("push/pop 1", R_AX|R_BX, @@ -691,17 +707,12 @@ static void test_null(void) { MK_INSN(null, ""); - inregs = (struct regs){ 0 }; + init_inregs(NULL); exec_in_big_real_mode(&insn_null); report("null", 0, 1); } -struct { - char stack[500]; - char top[]; -} tmp_stack; - static void test_pusha_popa(void) { MK_INSN(pusha, "pusha\n\t" @@ -726,7 +737,7 @@ static void test_pusha_popa(void) "popa\n\t" ); - inregs = (struct regs){ .eax = 0, .ebx = 1, .ecx = 2, .edx = 3, .esi = 4, .edi = 5, .ebp = 6, .esp = (unsigned long)&tmp_stack.top }; + init_inregs(&(struct regs){ .eax = 0, .ebx = 1, .ecx = 2, .edx = 3, .esi = 4, .edi = 5, .ebp = 6 }); exec_in_big_real_mode(&insn_pusha); report("pusha/popa 1", 0, 1); @@ -774,7 +785,7 @@ static void test_iret(void) "1: iretw\n\t" "2:\n\t"); - inregs = (struct regs){ 0 }; + init_inregs(NULL); exec_in_big_real_mode(&insn_iret32); report("iret 1", 0, 1); @@ -792,7 +803,7 @@ static void test_iret(void) static void test_int(void) { - inregs = (struct regs){ 0 }; + init_inregs(NULL); *(u32 *)(0x11 * 4) = 0x1000; /* Store a pointer to address 0x1000 in IDT entry 0x11 */ *(u8 *)(0x1000) = 0xcf; /* 0x1000 contains an IRET instruction */ @@ -829,7 +840,7 @@ static void test_imul(void) "mov $4, %ecx\n\t" "imul %ecx\n\t"); - inregs = (struct regs){ 0 }; + init_inregs(NULL); exec_in_big_real_mode(&insn_imul8_1); report("imul 1", R_AX | R_CX | R_DX, (outregs.eax & 0xff) == (u8)-8); @@ -866,7 +877,7 @@ static void test_mul(void) "mov $4, %ecx\n\t" "imul %ecx\n\t"); - inregs = (struct regs){ 0 }; + init_inregs(NULL); exec_in_big_real_mode(&insn_mul8); report("mul 1", R_AX | R_CX | R_DX, (outregs.eax & 0xff) == 8); @@ -892,7 +903,7 @@ static void test_div(void) "mov $5, %ecx\n\t" "div %ecx\n\t"); - inregs = (struct regs){ 0 }; + init_inregs(NULL); exec_in_big_real_mode(&insn_div8); report("div 1", R_AX | R_CX | R_DX, outregs.eax == 384); @@ -920,7 +931,7 @@ static void test_idiv(void) "mov $-2, %ecx\n\t" "idiv %ecx\n\t"); - inregs = (struct regs){ 0 }; + init_inregs(NULL); exec_in_big_real_mode(&insn_idiv8); report("idiv 1", R_AX | R_CX | R_DX, outregs.eax == (u8)-128); @@ -939,7 +950,7 @@ static void test_cbw(void) MK_INSN(cwde, "mov $0xFFFE, %eax \n\t" "cwde\n\t"); - inregs = (struct regs){ 0 }; + init_inregs(NULL); exec_in_big_real_mode(&insn_cbw); report("cbq 1", ~0, outregs.eax == 0xFFFE); @@ -964,7 +975,7 @@ static void test_loopcc(void) "1: dec %eax\n\t" "loopne 1b\n\t"); - inregs = (struct regs){ 0 }; + init_inregs(NULL); exec_in_big_real_mode(&insn_loop); report("LOOPcc short 1", R_AX, outregs.eax == 10); @@ -1243,7 +1254,7 @@ static void test_das(void) MK_INSN(das, "das"); - inregs = (struct regs){ 0 }; + init_inregs(NULL); for (i = 0; i < 1024; ++i) { unsigned tmp = test_cases[i]; @@ -1278,7 +1289,7 @@ static void test_cwd_cdq(void) MK_INSN(cdq_2, "mov $0x10000000, %eax\n\t" "cdq\n\t"); - inregs = (struct regs){ 0 }; + init_inregs(NULL); exec_in_big_real_mode(&insn_cwd_1); report("cwd 1", R_AX | R_DX, @@ -1307,7 +1318,7 @@ static struct { static void test_lds_lss(void) { - inregs = (struct regs){ .ebx = (unsigned long)&desc }; + init_inregs(&(struct regs){ .ebx = (unsigned long)&desc }); MK_INSN(lds, "push %ds\n\t" "lds (%ebx), %eax\n\t" @@ -1376,7 +1387,7 @@ static void test_jcxz(void) "mov $0, %ecx\n\t" "1:\n\t"); - inregs = (struct regs){ 0 }; + init_inregs(NULL); exec_in_big_real_mode(&insn_jcxz1); report("jcxz short 1", 0, 1); @@ -1400,8 +1411,10 @@ static void test_cpuid(void) unsigned function = 0x1234; unsigned eax, ebx, ecx, edx; - inregs.eax = eax = function; - inregs.ecx = ecx = 0; + init_inregs(&(struct regs){ .eax = function }); + + eax = inregs.eax; + ecx = inregs.ecx; asm("cpuid" : "+a"(eax), "=b"(ebx), "+c"(ecx), "=d"(edx)); exec_in_big_real_mode(&insn_cpuid); report("cpuid", R_AX|R_BX|R_CX|R_DX, @@ -1415,10 +1428,11 @@ static void test_ss_base_for_esp_ebp(void) MK_INSN(ssrel2, "mov %ss, %ax; mov %bx, %ss; movl (%ebp,%edi,8), %ebx; mov %ax, %ss"); static unsigned array[] = { 0x12345678, 0, 0, 0, 0x87654321 }; - inregs.ebx = 1; - inregs.ebp = (unsigned)array; + init_inregs(&(struct regs){ .ebx = 1, .ebp = (unsigned)array }); + exec_in_big_real_mode(&insn_ssrel1); report("ss relative addressing (1)", R_AX | R_BX, outregs.ebx == 0x87654321); + inregs.ebx = 1; inregs.ebp = (unsigned)array; inregs.edi = 0; @@ -1434,7 +1448,8 @@ static void test_sgdt_sidt(void) MK_INSN(sidt, "sidtw (%eax)"); struct table_descr x, y; - inregs.eax = (unsigned)&y; + init_inregs(&(struct regs){ .eax = (unsigned)&y }); + asm volatile("sgdtw %0" : "=m"(x)); exec_in_big_real_mode(&insn_sgdt); report("sgdt", 0, x.limit == y.limit && x.base == y.base); @@ -1449,7 +1464,8 @@ static void test_sahf(void) { MK_INSN(sahf, "sahf; pushfw; mov (%esp), %al; popfw"); - inregs.eax = 0xfd00; + init_inregs(&(struct regs){ .eax = 0xfd00 }); + exec_in_big_real_mode(&insn_sahf); report("sahf", R_AX, outregs.eax == (inregs.eax | 0xd7)); } @@ -1458,7 +1474,8 @@ static void test_lahf(void) { MK_INSN(lahf, "pushfw; mov %al, (%esp); popfw; lahf"); - inregs.eax = 0xc7; + init_inregs(&(struct regs){ .eax = 0xc7 }); + exec_in_big_real_mode(&insn_lahf); report("lahf", R_AX, (outregs.eax >> 8) == inregs.eax); } @@ -1470,8 +1487,8 @@ static void test_movzx_movsx(void) MK_INSN(movzsah, "movsx %ah, %ebx"); MK_INSN(movzxah, "movzx %ah, %ebx"); - inregs.eax = 0x1234569c; - inregs.esp = 0xffff; + init_inregs(&(struct regs){ .eax = 0x1234569c }); + exec_in_big_real_mode(&insn_movsx); report("movsx", R_BX, outregs.ebx == (signed char)inregs.eax); exec_in_big_real_mode(&insn_movzx); @@ -1486,7 +1503,8 @@ static void test_bswap(void) { MK_INSN(bswap, "bswap %ecx"); - inregs.ecx = 0x12345678; + init_inregs(&(struct regs){ .ecx = 0x12345678 }); + exec_in_big_real_mode(&insn_bswap); report("bswap", R_CX, outregs.ecx == 0x78563412); } @@ -1495,7 +1513,8 @@ static void test_aad(void) { MK_INSN(aad, "aad"); - inregs.eax = 0x12345678; + init_inregs(&(struct regs){ .eax = 0x12345678 }); + exec_in_big_real_mode(&insn_aad); report("aad", R_AX, outregs.eax == 0x123400d4); } @@ -1504,7 +1523,8 @@ static void test_aam(void) { MK_INSN(aam, "aam"); - inregs.eax = 0x76543210; + init_inregs(&(struct regs){ .eax = 0x76543210 }); + exec_in_big_real_mode(&insn_aam); report("aam", R_AX, outregs.eax == 0x76540106); } @@ -1519,8 +1539,8 @@ static void test_xlat(void) table[i] = i + 1; } - inregs.eax = 0x89abcdef; - inregs.ebx = (u32)table; + init_inregs(&(struct regs){ .eax = 0x89abcdef, .ebx = (u32)table }); + exec_in_big_real_mode(&insn_xlat); report("xlat", R_AX, outregs.eax == 0x89abcdf0); } @@ -1530,7 +1550,8 @@ static void test_salc(void) MK_INSN(clc_salc, "clc; .byte 0xd6"); MK_INSN(stc_salc, "stc; .byte 0xd6"); - inregs.eax = 0x12345678; + init_inregs(&(struct regs){ .eax = 0x12345678 }); + exec_in_big_real_mode(&insn_clc_salc); report("salc (1)", R_AX, outregs.eax == 0x12345600); exec_in_big_real_mode(&insn_stc_salc); @@ -1542,8 +1563,7 @@ static void test_fninit(void) u16 fcw = -1, fsw = -1; MK_INSN(fninit, "fninit ; fnstsw (%eax) ; fnstcw (%ebx)"); - inregs.eax = (u32)&fsw; - inregs.ebx = (u32)&fcw; + init_inregs(&(struct regs){ .eax = (u32)&fsw, .ebx = (u32)&fcw }); exec_in_big_real_mode(&insn_fninit); report("fninit", 0, fsw == 0 && (fcw & 0x103f) == 0x003f); @@ -1576,7 +1596,8 @@ static u32 cycles_in_big_real_mode(struct insn_desc *insn) { u64 start, end; - inregs.ecx = PERF_COUNT; + init_inregs(&(struct regs){ .ecx = PERF_COUNT }); + exec_in_big_real_mode(insn); start = ((u64)outregs.esi << 32) | outregs.ebx; end = ((u64)outregs.edx << 32) | outregs.eax; @@ -1624,7 +1645,9 @@ static void test_perf_memory_load(void) u32 cyc, tmp; MK_INSN_PERF(perf_memory_load, "cmp $0, (%edi)"); - inregs.edi = (u32)&tmp; + + init_inregs(&(struct regs){ .edi = (u32)&tmp }); + cyc = cycles_in_big_real_mode(&insn_perf_memory_load); print_serial_u32((cyc - perf_baseline) / PERF_COUNT); print_serial(" cycles/emulated memory load instruction\n"); @@ -1635,7 +1658,9 @@ static void test_perf_memory_store(void) u32 cyc, tmp; MK_INSN_PERF(perf_memory_store, "mov %ax, (%edi)"); - inregs.edi = (u32)&tmp; + + init_inregs(&(struct regs){ .edi = (u32)&tmp }); + cyc = cycles_in_big_real_mode(&insn_perf_memory_store); print_serial_u32((cyc - perf_baseline) / PERF_COUNT); print_serial(" cycles/emulated memory store instruction\n"); @@ -1646,7 +1671,9 @@ static void test_perf_memory_rmw(void) u32 cyc, tmp; MK_INSN_PERF(perf_memory_rmw, "add $1, (%edi)"); - inregs.edi = (u32)&tmp; + + init_inregs(&(struct regs){ .edi = (u32)&tmp }); + cyc = cycles_in_big_real_mode(&insn_perf_memory_rmw); print_serial_u32((cyc - perf_baseline) / PERF_COUNT); print_serial(" cycles/emulated memory RMW instruction\n"); @@ -1656,8 +1683,9 @@ static void test_dr_mod(void) { MK_INSN(drmod, "movl %ebx, %dr0\n\t" ".byte 0x0f \n\t .byte 0x21 \n\t .byte 0x0\n\t"); - inregs.eax = 0xdead; - inregs.ebx = 0xaced; + + init_inregs(&(struct regs){ .eax = 0xdead, .ebx = 0xaced }); + exec_in_big_real_mode(&insn_drmod); report("mov dr with mod bits", R_AX | R_BX, outregs.eax == 0xaced); } @@ -1670,7 +1698,9 @@ static void test_smsw(void) "movl %ebx, %cr0\n\t" "smswl %eax\n\t" "movl %ecx, %cr0\n\t"); - inregs.eax = 0x12345678; + + init_inregs(&(struct regs){ .eax = 0x12345678 }); + exec_in_big_real_mode(&insn_smsw); report("smsw", R_AX | R_BX | R_CX, outregs.eax == outregs.ebx); } @@ -1678,7 +1708,9 @@ static void test_smsw(void) static void test_xadd(void) { MK_INSN(xadd, "xaddl %eax, %eax\n\t"); - inregs.eax = 0x12345678; + + init_inregs(&(struct regs){ .eax = 0x12345678 }); + exec_in_big_real_mode(&insn_xadd); report("xadd", R_AX, outregs.eax == inregs.eax * 2); } -- 2.24.0.rc1.363.gb1bccd3e3d-goog