From: Julian Seward Date: Sat, 29 Oct 2005 19:19:51 +0000 (+0000) Subject: x86 front end: implement in/out insns. X-Git-Tag: svn/VALGRIND_3_1_1^2~66 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=10ef643f71ddda64b3b1de31f73ed368dcdb0a8f;p=thirdparty%2Fvalgrind.git x86 front end: implement in/out insns. git-svn-id: svn://svn.valgrind.org/vex/trunk@1425 --- diff --git a/VEX/priv/guest-x86/gdefs.h b/VEX/priv/guest-x86/gdefs.h index 39c6e49857..235befc19b 100644 --- a/VEX/priv/guest-x86/gdefs.h +++ b/VEX/priv/guest-x86/gdefs.h @@ -156,6 +156,10 @@ extern void x86g_dirtyhelper_FSTENV ( VexGuestX86State*, HWord ); extern ULong x86g_dirtyhelper_RDTSC ( void ); +extern UInt x86g_dirtyhelper_IN ( UInt portno, UInt sz/*1,2 or 4*/ ); +extern void x86g_dirtyhelper_OUT ( UInt portno, UInt data, + UInt sz/*1,2 or 4*/ ); + extern VexEmWarn x86g_dirtyhelper_FRSTOR ( VexGuestX86State*, HWord ); diff --git a/VEX/priv/guest-x86/ghelpers.c b/VEX/priv/guest-x86/ghelpers.c index 464cedb450..2db2eae4dc 100644 --- a/VEX/priv/guest-x86/ghelpers.c +++ b/VEX/priv/guest-x86/ghelpers.c @@ -1882,6 +1882,66 @@ void x86g_dirtyhelper_CPUID_sse2 ( VexGuestX86State* st ) } +/* CALLED FROM GENERATED CODE */ +/* DIRTY HELPER (non-referentially-transparent) */ +/* Horrible hack. On non-x86 platforms, return 0. */ +UInt x86g_dirtyhelper_IN ( UInt portno, UInt sz/*1,2 or 4*/ ) +{ +# if defined(__i386__) + UInt r = 0; + portno &= 0xFFFF; + switch (sz) { + case 4: + __asm__ __volatile__("movl $0,%%eax; inl %w1,%0" + : "=a" (r) : "Nd" (portno)); + break; + case 2: + __asm__ __volatile__("movl $0,%%eax; inw %w1,%w0" + : "=a" (r) : "Nd" (portno)); + break; + case 1: + __asm__ __volatile__("movl $0,%%eax; inb %w1,%b0" + : "=a" (r) : "Nd" (portno)); + break; + default: + break; + } + return r; +# else + return 0; +# endif +} + + +/* CALLED FROM GENERATED CODE */ +/* DIRTY HELPER (non-referentially-transparent) */ +/* Horrible hack. On non-x86 platforms, do nothing. */ +void x86g_dirtyhelper_OUT ( UInt portno, UInt data, UInt sz/*1,2 or 4*/ ) +{ +# if defined(__i386__) + portno &= 0xFFFF; + switch (sz) { + case 4: + __asm__ __volatile__("outl %0, %w1" + : : "a" (data), "Nd" (portno)); + break; + case 2: + __asm__ __volatile__("outw %w0, %w1" + : : "a" (data), "Nd" (portno)); + break; + case 1: + __asm__ __volatile__("outb %b0, %w1" + : : "a" (data), "Nd" (portno)); + break; + default: + break; + } +# else + return 0; +# endif +} + + /*---------------------------------------------------------------*/ /*--- Helpers for MMX/SSE/SSE2. ---*/ /*---------------------------------------------------------------*/ diff --git a/VEX/priv/guest-x86/toIR.c b/VEX/priv/guest-x86/toIR.c index 7a86bf6d2c..0a8dea27f6 100644 --- a/VEX/priv/guest-x86/toIR.c +++ b/VEX/priv/guest-x86/toIR.c @@ -11602,78 +11602,102 @@ DisResult disInstr_X86_WRK ( //-- //-- DIP("xlat%c [ebx]\n", nameISize(sz)); //-- break; -//-- -//-- /* ------------------------ IN / OUT ----------------------- */ -//-- -//-- case 0xE4: /* IN ib, %al */ -//-- case 0xE5: /* IN ib, %{e}ax */ -//-- case 0xEC: /* IN (%dx),%al */ -//-- case 0xED: /* IN (%dx),%{e}ax */ -//-- t1 = newTemp(cb); -//-- t2 = newTemp(cb); -//-- t3 = newTemp(cb); -//-- -//-- uInstr0(cb, CALLM_S, 0); -//-- /* operand size? */ -//-- uInstr2(cb, MOV, 4, Literal, 0, TempReg, t1); -//-- uLiteral(cb, ( opc == 0xE4 || opc == 0xEC ) ? 1 : sz); -//-- uInstr1(cb, PUSH, 4, TempReg, t1); -//-- /* port number ? */ -//-- if ( opc == 0xE4 || opc == 0xE5 ) { -//-- abyte = getUChar(eip); eip++; -//-- uInstr2(cb, MOV, 4, Literal, 0, TempReg, t2); -//-- uLiteral(cb, abyte); -//-- } -//-- else -//-- uInstr2(cb, GET, 4, ArchReg, R_EDX, TempReg, t2); -//-- -//-- uInstr1(cb, PUSH, 4, TempReg, t2); -//-- uInstr1(cb, CALLM, 0, Lit16, VGOFF_(helper_IN)); -//-- uFlagsRWU(cb, FlagsEmpty, FlagsEmpty, FlagsEmpty); -//-- uInstr1(cb, POP, 4, TempReg, t2); -//-- uInstr1(cb, CLEAR, 0, Lit16, 4); -//-- uInstr0(cb, CALLM_E, 0); -//-- uInstr2(cb, PUT, 4, TempReg, t2, ArchReg, R_EAX); -//-- if ( opc == 0xE4 || opc == 0xE5 ) { -//-- DIP("in 0x%x, %%eax/%%ax/%%al\n", getUChar(eip-1) ); -//-- } else { -//-- DIP("in (%%dx), %%eax/%%ax/%%al\n"); -//-- } -//-- break; -//-- case 0xE6: /* OUT %al,ib */ -//-- case 0xE7: /* OUT %{e}ax,ib */ -//-- case 0xEE: /* OUT %al,(%dx) */ -//-- case 0xEF: /* OUT %{e}ax,(%dx) */ -//-- t1 = newTemp(cb); -//-- t2 = newTemp(cb); -//-- t3 = newTemp(cb); -//-- -//-- uInstr0(cb, CALLM_S, 0); -//-- /* operand size? */ -//-- uInstr2(cb, MOV, 4, Literal, 0, TempReg, t1); -//-- uLiteral(cb, ( opc == 0xE6 || opc == 0xEE ) ? 1 : sz); -//-- uInstr1(cb, PUSH, 4, TempReg, t1); -//-- /* port number ? */ -//-- if ( opc == 0xE6 || opc == 0xE7 ) { -//-- abyte = getUChar(eip); eip++; -//-- uInstr2(cb, MOV, 4, Literal, 0, TempReg, t2); -//-- uLiteral(cb, abyte); -//-- } -//-- else -//-- uInstr2(cb, GET, 4, ArchReg, R_EDX, TempReg, t2); -//-- uInstr1(cb, PUSH, 4, TempReg, t2); -//-- uInstr2(cb, GET, 4, ArchReg, R_EAX, TempReg, t3); -//-- uInstr1(cb, PUSH, 4, TempReg, t3); -//-- uInstr1(cb, CALLM, 0, Lit16, VGOFF_(helper_OUT)); -//-- uFlagsRWU(cb, FlagsEmpty, FlagsEmpty, FlagsEmpty); -//-- uInstr1(cb, CLEAR, 0, Lit16, 12); -//-- uInstr0(cb, CALLM_E, 0); -//-- if ( opc == 0xE4 || opc == 0xE5 ) { -//-- DIP("out %%eax/%%ax/%%al, 0x%x\n", getUChar(eip-1) ); -//-- } else { -//-- DIP("out %%eax/%%ax/%%al, (%%dx)\n"); -//-- } -//-- break; + + /* ------------------------ IN / OUT ----------------------- */ + + case 0xE4: /* IN imm8, AL */ + sz = 1; + t1 = newTemp(Ity_I32); + abyte = getIByte(delta); delta++; + assign(t1, mkU32( abyte & 0xFF )); + DIP("in%c $%d,%s\n", nameISize(sz), (Int)abyte, nameIReg(sz,R_EAX)); + goto do_IN; + case 0xE5: /* IN imm8, eAX */ + vassert(sz == 2 || sz == 4); + t1 = newTemp(Ity_I32); + abyte = getIByte(delta); delta++; + assign(t1, mkU32( abyte & 0xFF )); + DIP("in%c $%d,%s\n", nameISize(sz), (Int)abyte, nameIReg(sz,R_EAX)); + goto do_IN; + case 0xEC: /* IN %DX, AL */ + sz = 1; + t1 = newTemp(Ity_I32); + assign(t1, unop(Iop_16Uto32, getIReg(2, R_EDX))); + DIP("in%c %s,%s\n", nameISize(sz), nameIReg(2,R_EDX), + nameIReg(sz,R_EAX)); + goto do_IN; + case 0xED: /* IN %DX, eAX */ + vassert(sz == 2 || sz == 4); + t1 = newTemp(Ity_I32); + assign(t1, unop(Iop_16Uto32, getIReg(2, R_EDX))); + DIP("in%c %s,%s\n", nameISize(sz), nameIReg(2,R_EDX), + nameIReg(sz,R_EAX)); + goto do_IN; + do_IN: { + /* At this point, sz indicates the width, and t1 is a 32-bit + value giving port number. */ + IRDirty* d; + vassert(sz == 1 || sz == 2 || sz == 4); + ty = szToITy(sz); + t2 = newTemp(Ity_I32); + d = unsafeIRDirty_1_N( + t2, + 0/*regparms*/, + "x86g_dirtyhelper_IN", + &x86g_dirtyhelper_IN, + mkIRExprVec_2( mkexpr(t1), mkU32(sz) ) + ); + /* do the call, dumping the result in t2. */ + stmt( IRStmt_Dirty(d) ); + putIReg(sz, R_EAX, narrowTo( ty, mkexpr(t2) ) ); + break; + } + + case 0xE6: /* OUT AL, imm8 */ + sz = 1; + t1 = newTemp(Ity_I32); + abyte = getIByte(delta); delta++; + assign( t1, mkU32( abyte & 0xFF ) ); + DIP("out%c %s,$%d\n", nameISize(sz), nameIReg(sz,R_EAX), (Int)abyte); + goto do_OUT; + case 0xE7: /* OUT eAX, imm8 */ + vassert(sz == 2 || sz == 4); + t1 = newTemp(Ity_I32); + abyte = getIByte(delta); delta++; + assign( t1, mkU32( abyte & 0xFF ) ); + DIP("out%c %s,$%d\n", nameISize(sz), nameIReg(sz,R_EAX), (Int)abyte); + goto do_OUT; + case 0xEE: /* OUT AL, %DX */ + sz = 1; + t1 = newTemp(Ity_I32); + assign( t1, unop(Iop_16Uto32, getIReg(2, R_EDX)) ); + DIP("out%c %s,%s\n", nameISize(sz), nameIReg(sz,R_EAX), + nameIReg(2,R_EDX)); + goto do_OUT; + case 0xEF: /* OUT eAX, %DX */ + vassert(sz == 2 || sz == 4); + t1 = newTemp(Ity_I32); + assign( t1, unop(Iop_16Uto32, getIReg(2, R_EDX)) ); + DIP("out%c %s,%s\n", nameISize(sz), nameIReg(sz,R_EAX), + nameIReg(2,R_EDX)); + goto do_OUT; + do_OUT: { + /* At this point, sz indicates the width, and t1 is a 32-bit + value giving port number. */ + IRDirty* d; + vassert(sz == 1 || sz == 2 || sz == 4); + ty = szToITy(sz); + d = unsafeIRDirty_0_N( + 0/*regparms*/, + "x86g_dirtyhelper_OUT", + &x86g_dirtyhelper_OUT, + mkIRExprVec_3( mkexpr(t1), + widenUto32( getIReg(sz, R_EAX) ), + mkU32(sz) ) + ); + stmt( IRStmt_Dirty(d) ); + break; + } /* ------------------------ (Grp1 extensions) ---------- */