Save/Restore clobbered register and struct initialization
v3 cover Save/Restore clobbered register and struct initialization
- Some tests may clobber the %es register, causing problems later on.
- Many tests require a stack, but it's easy to forget to allocate one. Use an initialization function to set it automagically.
Bill Wendling (2):
x86: realmode: save and restore %es
x86: realmode: initialize inregs with a stack
x86/realmode.c | 149 ++++++++++++++++++++++++++++++++++--------------- 1 file changed, 105 insertions(+), 44 deletions(-)
Signature · 1 line
2.24.0.rc1.363.gb1bccd3e3d-goog
PATCH v3 1/2 x86: realmode: save and restore %es
Some of the code test sequences (e.g. push_es) clobber ES. That causes trouble for future rep string instructions. So save and restore ES around the test code sequence in exec_in_big_real_mode.
--- x86/realmode.c | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-)
x86/realmode.c +9 -5
@@ -164,7 +164,10 @@ static void exec_in_big_real_mode(struct insn_desc *insn)"and $-2, %[tmp] \n\t" "mov %[tmp], %%cr0 \n\t" -"pushw %[save]+36; popfw \n\t" +/* Save ES, because it is clobbered by some tests. */ +"pushw %%es \n\t" + +"pushw %[save]+36; popfw \n\t" "xchg %%eax, %[save]+0 \n\t" "xchg %%ebx, %[save]+4 \n\t" "xchg %%ecx, %[save]+8 \n\t"
@@ -190,6 +193,9 @@ static void exec_in_big_real_mode(struct insn_desc *insn)"pushfl \n\t" "popl %[save]+36 \n\t" +/* Restore ES for future rep string operations. */ +"popw %%es \n\t" +/* Restore DF for the harness code */ "cld\n\t" "xor %[tmp], %[tmp] \n\t"
@@ -1312,10 +1318,8 @@ static void test_lds_lss(void) outregs.eax == (unsigned long )desc.address && outregs.ebx == desc.sel); -MK_INSN (les,"push %es\n\t" -"les (%ebx), %eax\n\t" -"mov %es, %ebx\n\t" -"pop %es\n\t" ); +MK_INSN (les,"les (%ebx), %eax\n\t" +"mov %es, %ebx\n\t" );exec_in_big_real_mode (&insn_les); report("les", R_AX | R_BX, outregs.eax == (unsigned long)desc.address &&
Signature · 1 line
2.24.0.rc1.363.gb1bccd3e3d-goog
Paolo Bonzini
maintainerRe: [kvm-unit-tests PATCH v3 1/2] x86: realmode: save and restore %es
Quoted 3 lines · Bill Wendling
Some of the code test sequences (e.g.
push_es) clobber ES. That causes trouble for future rep string instructions. So save and restore ES around the test code sequence inexec_in_big_real_mode.
You mean pop_es. Applied with that change.
Paolo
Re: [kvm-unit-tests PATCH v3 1/2] x86: realmode: save and restore %es
Quoted 7 lines · Paolo Bonzini
Quoted 3 lines · Bill Wendling
Some of the code test sequences (e.g.
push_es) clobber ES. That causes trouble for future rep string instructions. So save and restore ES around the test code sequence inexec_in_big_real_mode.You mean
pop_es. Applied with that change.
I think push_es and pop_es are both guilty of clobbering %es:
MK_INSN(push_es, "mov $0x231, %bx\n\t" //Just write a dummy value to see if it gets overwritten
"mov $0x123, %ax\n\t"
"mov %ax, %es\n\t" <======= Here
"push %es\n\t"
"pop %bx \n\t"
);
MK_INSN(pop_es, "push %ax\n\t"
"pop %es\n\t" <======== Here
"mov %es, %bx\n\t"
);
Paolo Bonzini
maintainerRe: [kvm-unit-tests PATCH v3 1/2] x86: realmode: save and restore %es
Quoted 19 lines · Jim Mattson
Quoted 7 lines · Paolo Bonzini
Quoted 3 lines · Bill Wendling
Some of the code test sequences (e.g.
push_es) clobber ES. That causes trouble for future rep string instructions. So save and restore ES around the test code sequence inexec_in_big_real_mode.You mean
pop_es. Applied with that change.I think
push_esandpop_esare both guilty of clobbering %es:MK_INSN(push_es, "mov $0x231, %bx\n\t" //Just write a dummy value to see if it gets overwritten
"mov $0x123, %ax\n\t"
"mov %ax, %es\n\t" <======= Here
"push %es\n\t"
"pop %bx \n\t"
);
Quoted 4 lines
MK_INSN(pop_es, "push %ax\n\t"
"pop %es\n\t" <======== Here
"mov %es, %bx\n\t"
);
Intel vs AT&T always gets me...
Paolo
PATCH v3 2/2 x86: realmode: initialize inregs with a stack
In reply to Bill WendlingTests 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.
--- x86/realmode.c | 158 +++++++++++++++++++++++++++++-------------------- 1 file changed, 95 insertions(+), 63 deletions(-)
x86/realmode.c +95 -63
@@ -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 }); + asmvolatile ("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 ); }
Signature · 1 line
2.24.0.rc1.363.gb1bccd3e3d-goog
Re: [kvm-unit-tests PATCH v3 2/2] x86: realmode: initialize inregs with a stack
Quoted 521 lines · Bill Wendling
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 <[email protected]>--- x86/realmode.c | 158 +++++++++++++++++++++++++++++-------------------- 1 file changed, 95 insertions(+), 63 deletions(-)x86/realmode.c +92
-62@@ -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 }); + asmvolatile ("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); }
x86/realmode.c static void test_smsw(void) · line 1716
Quoted 10 lines
x86/realmode.c +3
-1@@ -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 ); }
Applied, thanks.
Paolo