]> git.ipfire.org Git - thirdparty/valgrind.git/commitdiff
x86 front end: implement in/out insns.
authorJulian Seward <jseward@acm.org>
Sat, 29 Oct 2005 19:19:51 +0000 (19:19 +0000)
committerJulian Seward <jseward@acm.org>
Sat, 29 Oct 2005 19:19:51 +0000 (19:19 +0000)
git-svn-id: svn://svn.valgrind.org/vex/trunk@1425

VEX/priv/guest-x86/gdefs.h
VEX/priv/guest-x86/ghelpers.c
VEX/priv/guest-x86/toIR.c

index 39c6e49857c69482731fa9eaa084b0992f92c1bb..235befc19b2aa32d9f895f2b2301d522ba3ed2f0 100644 (file)
@@ -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 );
 
index 464cedb45089de31a0650fc700e8fa173fba2277..2db2eae4dcf202b14b4a02bdbe3c25ab39d91e08 100644 (file)
@@ -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.                               ---*/
 /*---------------------------------------------------------------*/
index 7a86bf6d2c9a5bc9a9139f50a4179d71dc2dc84f..0a8dea27f67c876b16d8e80394aa6a23e7042d6a 100644 (file)
@@ -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) ---------- */