]> git.ipfire.org Git - thirdparty/valgrind.git/commitdiff
Support in{b,w,l} and out{b,w,l} on amd64. Fixes #152357.
authorJulian Seward <jseward@acm.org>
Tue, 20 Nov 2007 17:29:08 +0000 (17:29 +0000)
committerJulian Seward <jseward@acm.org>
Tue, 20 Nov 2007 17:29:08 +0000 (17:29 +0000)
git-svn-id: svn://svn.valgrind.org/vex/trunk@1799

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

index 87a92b8db8d0a3892108efba6ce6928e56f6eb10..0d50e488736782518c6a13ca1634270d1969e5de 100644 (file)
@@ -158,6 +158,10 @@ extern void  amd64g_dirtyhelper_FXSAVE ( VexGuestAMD64State*, HWord );
 
 extern ULong amd64g_dirtyhelper_RDTSC ( void );
 
+extern ULong amd64g_dirtyhelper_IN  ( ULong portno, ULong sz/*1,2 or 4*/ );
+extern void  amd64g_dirtyhelper_OUT ( ULong portno, ULong data, 
+                                      ULong sz/*1,2 or 4*/ );
+
 //extern void  amd64g_dirtyhelper_CPUID_sse0 ( VexGuestAMD64State* );
 //extern void  amd64g_dirtyhelper_CPUID_sse1 ( VexGuestAMD64State* );
 //extern void  amd64g_dirtyhelper_CPUID_sse2 ( VexGuestAMD64State* );
index f4a49a0683dfd401c4839f86495cf1878653bbad..b6aa3289ddfc6a8b8c445045f2d56ec11fdf8dc1 100644 (file)
@@ -1981,6 +1981,66 @@ ULong amd64g_dirtyhelper_RDTSC ( void )
 }
 
 
+/* CALLED FROM GENERATED CODE */
+/* DIRTY HELPER (non-referentially-transparent) */
+/* Horrible hack.  On non-amd64 platforms, return 0. */
+ULong amd64g_dirtyhelper_IN ( ULong portno, ULong sz/*1,2 or 4*/ )
+{
+#  if defined(__x86_64__)
+   ULong r = 0;
+   portno &= 0xFFFF;
+   switch (sz) {
+      case 4: 
+         __asm__ __volatile__("movq $0,%%rax; inl %w1,%%eax; movq %%rax,%0" 
+                              : "=a" (r) : "Nd" (portno));
+        break;
+      case 2: 
+         __asm__ __volatile__("movq $0,%%rax; inw %w1,%w0" 
+                              : "=a" (r) : "Nd" (portno));
+        break;
+      case 1: 
+         __asm__ __volatile__("movq $0,%%rax; inb %w1,%b0" 
+                              : "=a" (r) : "Nd" (portno));
+        break;
+      default:
+         break; /* note: no 64-bit version of insn exists */
+   }
+   return r;
+#  else
+   return 0;
+#  endif
+}
+
+
+/* CALLED FROM GENERATED CODE */
+/* DIRTY HELPER (non-referentially-transparent) */
+/* Horrible hack.  On non-amd64 platforms, do nothing. */
+void amd64g_dirtyhelper_OUT ( ULong portno, ULong data, ULong sz/*1,2 or 4*/ )
+{
+#  if defined(__x86_64__)
+   portno &= 0xFFFF;
+   switch (sz) {
+      case 4: 
+         __asm__ __volatile__("movq %0,%%rax; outl %%eax, %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; /* note: no 64-bit version of insn exists */
+   }
+#  else
+   /* do nothing */
+#  endif
+}
+
+
 /*---------------------------------------------------------------*/
 /*--- Helpers for MMX/SSE/SSE2.                               ---*/
 /*---------------------------------------------------------------*/
index 9f32618df8092b3ddf5b132561ca062534d7d9de..00039762283656f7efcfe211eab4dc14a237dd2b 100644 (file)
@@ -971,6 +971,17 @@ static void putIRegRAX ( Int sz, IRExpr* e )
 /* Read/write various widths of %RDX, as it has various
    special-purpose uses. */
 
+static HChar* nameIRegRDX ( Int sz )
+{
+   switch (sz) {
+      case 1: return "%dl";
+      case 2: return "%dx";
+      case 4: return "%edx";
+      case 8: return "%rdx";
+      default: vpanic("nameIRegRDX(amd64)");
+   }
+}
+
 static IRExpr* getIRegRDX ( Int sz )
 {
    vassert(!host_is_bigendian);
@@ -8408,7 +8419,7 @@ DisResult disInstr_AMD64_WRK (
    IRType    ty;
    IRTemp    addr, t0, t1, t2, t3, t4, t5, t6;
    Int       alen;
-   UChar     opc, modrm, /*abyte,*/ pre;
+   UChar     opc, modrm, abyte, pre;
    Long      d64;
    HChar     dis_buf[50];
    Int       am_sz, d_sz, n, n_prefixes;
@@ -13862,78 +13873,104 @@ DisResult disInstr_AMD64_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_I64);
+      abyte = getUChar(delta); delta++;
+      assign(t1, mkU64( abyte & 0xFF ));
+      DIP("in%c $%d,%s\n", nameISize(sz), (Int)abyte, nameIRegRAX(sz));
+      goto do_IN;
+   case 0xE5: /* IN imm8, eAX */
+      if (!(sz == 2 || sz == 4)) goto decode_failure;
+      t1 = newTemp(Ity_I64);
+      abyte = getUChar(delta); delta++;
+      assign(t1, mkU64( abyte & 0xFF ));
+      DIP("in%c $%d,%s\n", nameISize(sz), (Int)abyte, nameIRegRAX(sz));
+      goto do_IN;
+   case 0xEC: /* IN %DX, AL */
+      sz = 1; 
+      t1 = newTemp(Ity_I64);
+      assign(t1, unop(Iop_16Uto64, getIRegRDX(2)));
+      DIP("in%c %s,%s\n", nameISize(sz), nameIRegRDX(2), 
+                                         nameIRegRAX(sz));
+      goto do_IN;
+   case 0xED: /* IN %DX, eAX */
+      if (!(sz == 2 || sz == 4)) goto decode_failure;
+      t1 = newTemp(Ity_I64);
+      assign(t1, unop(Iop_16Uto64, getIRegRDX(2)));
+      DIP("in%c %s,%s\n", nameISize(sz), nameIRegRDX(2), 
+                                         nameIRegRAX(sz));
+      goto do_IN;
+   do_IN: {
+      /* At this point, sz indicates the width, and t1 is a 64-bit
+         value giving port number. */
+      IRDirty* d;
+      if (haveF2orF3(pfx)) goto decode_failure;
+      vassert(sz == 1 || sz == 2 || sz == 4);
+      ty = szToITy(sz);
+      t2 = newTemp(Ity_I64);
+      d = unsafeIRDirty_1_N( 
+             t2,
+             0/*regparms*/, 
+             "amd64g_dirtyhelper_IN", 
+             &amd64g_dirtyhelper_IN,
+             mkIRExprVec_2( mkexpr(t1), mkU64(sz) )
+          );
+      /* do the call, dumping the result in t2. */
+      stmt( IRStmt_Dirty(d) );
+      putIRegRAX(sz, narrowTo( ty, mkexpr(t2) ) );
+      break;
+   }
+
+   case 0xE6: /* OUT AL, imm8 */
+      sz = 1;
+      t1 = newTemp(Ity_I64);
+      abyte = getUChar(delta); delta++;
+      assign( t1, mkU64( abyte & 0xFF ) );
+      DIP("out%c %s,$%d\n", nameISize(sz), nameIRegRAX(sz), (Int)abyte);
+      goto do_OUT;
+   case 0xE7: /* OUT eAX, imm8 */
+      if (!(sz == 2 || sz == 4)) goto decode_failure;
+      t1 = newTemp(Ity_I64);
+      abyte = getUChar(delta); delta++;
+      assign( t1, mkU64( abyte & 0xFF ) );
+      DIP("out%c %s,$%d\n", nameISize(sz), nameIRegRAX(sz), (Int)abyte);
+      goto do_OUT;
+   case 0xEE: /* OUT AL, %DX */
+      sz = 1;
+      t1 = newTemp(Ity_I64);
+      assign( t1, unop(Iop_16Uto64, getIRegRDX(2)) );
+      DIP("out%c %s,%s\n", nameISize(sz), nameIRegRAX(sz),
+                                          nameIRegRDX(2));
+      goto do_OUT;
+   case 0xEF: /* OUT eAX, %DX */
+      if (!(sz == 2 || sz == 4)) goto decode_failure;
+      t1 = newTemp(Ity_I64);
+      assign( t1, unop(Iop_16Uto64, getIRegRDX(2)) );
+      DIP("out%c %s,%s\n", nameISize(sz), nameIRegRAX(sz),
+                                          nameIRegRDX(2));
+      goto do_OUT;
+   do_OUT: {
+      /* At this point, sz indicates the width, and t1 is a 64-bit
+         value giving port number. */
+      IRDirty* d;
+      if (haveF2orF3(pfx)) goto decode_failure;
+      vassert(sz == 1 || sz == 2 || sz == 4);
+      ty = szToITy(sz);
+      d = unsafeIRDirty_0_N( 
+             0/*regparms*/, 
+             "amd64g_dirtyhelper_OUT", 
+             &amd64g_dirtyhelper_OUT,
+             mkIRExprVec_3( mkexpr(t1),
+                            widenUto64( getIRegRAX(sz) ), 
+                            mkU64(sz) )
+          );
+      stmt( IRStmt_Dirty(d) );
+      break;
+   }
 
    /* ------------------------ (Grp1 extensions) ---------- */