]> git.ipfire.org Git - thirdparty/valgrind.git/commitdiff
ARM64: add support for cache management instructions (VEX side):
authorJulian Seward <jseward@acm.org>
Sat, 3 May 2014 21:20:56 +0000 (21:20 +0000)
committerJulian Seward <jseward@acm.org>
Sat, 3 May 2014 21:20:56 +0000 (21:20 +0000)
  dc cvau, regX
  ic ivau, regX
  mrs regX, ctr_el0
Fixes #333228 and #333230.

git-svn-id: svn://svn.valgrind.org/vex/trunk@2851

VEX/priv/guest_arm64_toIR.c
VEX/priv/host_arm64_defs.c
VEX/priv/host_arm64_isel.c
VEX/priv/ir_defs.c
VEX/priv/main_main.c
VEX/pub/libvex.h
VEX/pub/libvex_ir.h
VEX/pub/libvex_trc_values.h

index bb762e07b4bdf89c235d51a823529bc88c867004..e9ad82af8eb198e6953f36a1341455e01091222f 100644 (file)
@@ -4386,7 +4386,8 @@ Bool dis_ARM64_load_store(/*MB_OUT*/DisResult* dres, UInt insn)
 /*------------------------------------------------------------*/
 
 static
-Bool dis_ARM64_branch_etc(/*MB_OUT*/DisResult* dres, UInt insn)
+Bool dis_ARM64_branch_etc(/*MB_OUT*/DisResult* dres, UInt insn,
+                          VexArchInfo* archinfo)
 {
 #  define INSN(_bMax,_bMin)  SLICE_UInt(insn, (_bMax), (_bMin))
 
@@ -4628,8 +4629,93 @@ Bool dis_ARM64_branch_etc(/*MB_OUT*/DisResult* dres, UInt insn)
       DIP("mrs %s, dczid_el0 (FAKED)\n", nameIReg64orZR(tt));
       return True;
    }
+   /* Cases for CTR_EL0
+      We just handle reads, and make up a value from the D and I line
+      sizes in the VexArchInfo we are given, and patch in the following
+      fields that the Foundation model gives ("natively"):
+      CWG = 0b0100, ERG = 0b0100, L1Ip = 0b11
+      D5 3B 00 001 Rt  MRS rT, dczid_el0
+   */
+   if ((INSN(31,0) & 0xFFFFFFE0) == 0xD53B0020) {
+      UInt tt = INSN(4,0);
+      /* Need to generate a value from dMinLine_lg2_szB and
+         dMinLine_lg2_szB.  The value in the register is in 32-bit
+         units, so need to subtract 2 from the values in the
+         VexArchInfo.  We can assume that the values here are valid --
+         disInstr_ARM64 checks them -- so there's no need to deal with
+         out-of-range cases. */
+      vassert(archinfo->arm64_dMinLine_lg2_szB >= 2
+              && archinfo->arm64_dMinLine_lg2_szB <= 17
+              && archinfo->arm64_iMinLine_lg2_szB >= 2
+              && archinfo->arm64_iMinLine_lg2_szB <= 17);
+      UInt val
+         = 0x8440c000 | ((0xF & (archinfo->arm64_dMinLine_lg2_szB - 2)) << 16)
+                      | ((0xF & (archinfo->arm64_iMinLine_lg2_szB - 2)) << 0);
+      putIReg64orZR(tt, mkU64(val));
+      DIP("mrs %s, ctr_el0\n", nameIReg64orZR(tt));
+      return True;
+   }
+
+   /* ------------------ IC_IVAU ------------------ */
+   /* D5 0B 75 001 Rt  ic ivau, rT
+   */
+   if ((INSN(31,0) & 0xFFFFFFE0) == 0xD50B7520) {
+      /* We will always be provided with a valid iMinLine value. */
+      vassert(archinfo->arm64_iMinLine_lg2_szB >= 2
+              && archinfo->arm64_iMinLine_lg2_szB <= 17);
+      /* Round the requested address, in rT, down to the start of the
+         containing block. */
+      UInt   tt      = INSN(4,0);
+      ULong  lineszB = 1ULL << archinfo->arm64_iMinLine_lg2_szB;
+      IRTemp addr    = newTemp(Ity_I64);
+      assign( addr, binop( Iop_And64,
+                           getIReg64orZR(tt),
+                           mkU64(~(lineszB - 1))) );
+      /* Set the invalidation range, request exit-and-invalidate, with
+         continuation at the next instruction. */
+      stmt(IRStmt_Put(OFFB_TISTART, mkexpr(addr)));
+      stmt(IRStmt_Put(OFFB_TILEN,   mkU64(lineszB)));
+      /* be paranoid ... */
+      stmt( IRStmt_MBE(Imbe_Fence) );
+      putPC(mkU64( guest_PC_curr_instr + 4 ));
+      dres->whatNext    = Dis_StopHere;
+      dres->jk_StopHere = Ijk_TInval;
+      DIP("ic ivau, %s\n", nameIReg64orZR(tt));
+      return True;
+   }
 
-   /* ------------------ ISB, DSB ------------------ */
+   /* ------------------ DC_CVAU ------------------ */
+   /* D5 0B 7B 001 Rt  dc cvau, rT
+   */
+   if ((INSN(31,0) & 0xFFFFFFE0) == 0xD50B7B20) {
+      /* Exactly the same scheme as for IC IVAU, except we observe the
+         dMinLine size, and request an Ijk_InvalData instead of
+         Ijk_TInval. */
+      /* We will always be provided with a valid dMinLine value. */
+      vassert(archinfo->arm64_dMinLine_lg2_szB >= 2
+              && archinfo->arm64_dMinLine_lg2_szB <= 17);
+      /* Round the requested address, in rT, down to the start of the
+         containing block. */
+      UInt   tt      = INSN(4,0);
+      ULong  lineszB = 1ULL << archinfo->arm64_dMinLine_lg2_szB;
+      IRTemp addr    = newTemp(Ity_I64);
+      assign( addr, binop( Iop_And64,
+                           getIReg64orZR(tt),
+                           mkU64(~(lineszB - 1))) );
+      /* Set the flush range, request exit-and-flush, with
+         continuation at the next instruction. */
+      stmt(IRStmt_Put(OFFB_TISTART, mkexpr(addr)));
+      stmt(IRStmt_Put(OFFB_TILEN,   mkU64(lineszB)));
+      /* be paranoid ... */
+      stmt( IRStmt_MBE(Imbe_Fence) );
+      putPC(mkU64( guest_PC_curr_instr + 4 ));
+      dres->whatNext    = Dis_StopHere;
+      dres->jk_StopHere = Ijk_FlushDCache;
+      DIP("dc cvau, %s\n", nameIReg64orZR(tt));
+      return True;
+   }
+
+   /* ------------------ ISB, DMB, DSB ------------------ */
    if (INSN(31,0) == 0xD5033FDF) {
       stmt(IRStmt_MBE(Imbe_Fence));
       DIP("isb\n");
@@ -4640,6 +4726,11 @@ Bool dis_ARM64_branch_etc(/*MB_OUT*/DisResult* dres, UInt insn)
       DIP("dmb ish\n");
       return True;
    }
+   if (INSN(31,0) == 0xD5033B9F) {
+      stmt(IRStmt_MBE(Imbe_Fence));
+      DIP("dsb ish\n");
+      return True;
+   }
 
    /* -------------------- NOP -------------------- */
    if (INSN(31,0) == 0xD503201F) {
@@ -7161,7 +7252,7 @@ Bool disInstr_ARM64_WRK (
          break;
       case BITS4(1,0,1,0): case BITS4(1,0,1,1):
          // Branch, exception generation and system instructions
-         ok = dis_ARM64_branch_etc(dres, insn);
+         ok = dis_ARM64_branch_etc(dres, insn, archinfo);
          break;
       case BITS4(0,1,0,0): case BITS4(0,1,1,0):
       case BITS4(1,1,0,0): case BITS4(1,1,1,0):
@@ -7229,6 +7320,11 @@ DisResult disInstr_ARM64 ( IRSB*        irsb_IN,
    host_is_bigendian   = host_bigendian_IN;
    guest_PC_curr_instr = (Addr64)guest_IP;
 
+   /* Sanity checks */
+   /* (x::UInt - 2) <= 15   ===   x >= 2 && x <= 17 (I hope) */
+   vassert((archinfo->arm64_dMinLine_lg2_szB - 2) <= 15);
+   vassert((archinfo->arm64_iMinLine_lg2_szB - 2) <= 15);
+
    /* Try to decode */
    Bool ok = disInstr_ARM64_WRK( &dres,
                                  resteerOkFn, resteerCisOk, callback_opaque,
index bab569cb4cc6ebdcb285270184cdaf7565df9558..51f35b3ca4589709e8f53b087f5c0230e64096c7 100644 (file)
@@ -4461,7 +4461,8 @@ Int emit_ARM64Instr ( /*MB_MOD*/Bool* is_profInc,
             //case Ijk_EmWarn:      trcval = VEX_TRC_JMP_EMWARN;      break;
             //case Ijk_MapFail:     trcval = VEX_TRC_JMP_MAPFAIL;     break;
             case Ijk_NoDecode:    trcval = VEX_TRC_JMP_NODECODE;    break;
-            //case Ijk_TInval:      trcval = VEX_TRC_JMP_TINVAL;      break;
+            case Ijk_TInval:      trcval = VEX_TRC_JMP_TINVAL;      break;
+            case Ijk_FlushDCache: trcval = VEX_TRC_JMP_FLUSHDCACHE; break;
             case Ijk_NoRedir:     trcval = VEX_TRC_JMP_NOREDIR;     break;
             //case Ijk_SigTRAP:     trcval = VEX_TRC_JMP_SIGTRAP;     break;
             //case Ijk_SigSEGV:     trcval = VEX_TRC_JMP_SIGSEGV;     break;
index e9e5c1c226cfd24fe312dc5d5a89a2cde1cf5122..8e9e4f556f7be969b69896b98833cd4976ffbb35 100644 (file)
@@ -6915,7 +6915,8 @@ static void iselNext ( ISelEnv* env,
       case Ijk_NoDecode:
       case Ijk_NoRedir:
       case Ijk_Sys_syscall:
-//ZZ       case Ijk_TInval:
+      case Ijk_TInval:
+      case Ijk_FlushDCache:
 //ZZ       case Ijk_Yield:
       {
          HReg        r    = iselIntExpr_R(env, next);
index f37a161d116ed5e3e8a5d5e4c894ff261e5413c9..8489d220abe3cff80e10d381246f8ec130b67dbc 100644 (file)
@@ -1413,6 +1413,7 @@ void ppIRJumpKind ( IRJumpKind kind )
       case Ijk_NoDecode:      vex_printf("NoDecode"); break;
       case Ijk_MapFail:       vex_printf("MapFail"); break;
       case Ijk_TInval:        vex_printf("Invalidate"); break;
+      case Ijk_FlushDCache:   vex_printf("FlushDCache"); break;
       case Ijk_NoRedir:       vex_printf("NoRedir"); break;
       case Ijk_SigILL:        vex_printf("SigILL"); break;
       case Ijk_SigTRAP:       vex_printf("SigTRAP"); break;
index 93ca478cced1a1c46fc9580cc1506b1e7ed66a0f..ebb8d41af9c8fd013809ae400a7e23dc1401f15b 100644 (file)
@@ -92,6 +92,7 @@ static  Int sdiv32 (  Int x,  Int y ) { return x/y; }
 
 void LibVEX_default_VexControl ( /*OUT*/ VexControl* vcon )
 {
+   vex_bzero(vcon, sizeof(*vcon));
    vcon->iropt_verbosity            = 0;
    vcon->iropt_level                = 2;
    vcon->iropt_register_updates     = VexRegUpdUnwindregsAtMemAccess;
@@ -1225,20 +1226,23 @@ const HChar* LibVEX_ppVexHwCaps ( VexArch arch, UInt hwcaps )
 /* Write default settings info *vai. */
 void LibVEX_default_VexArchInfo ( /*OUT*/VexArchInfo* vai )
 {
+   vex_bzero(vai, sizeof(*vai));
    vai->hwcaps              = 0;
    vai->ppc_icache_line_szB = 0;
    vai->ppc_dcbz_szB        = 0;
    vai->ppc_dcbzl_szB       = 0;
-
+   vai->arm64_dMinLine_lg2_szB  = 0;
+   vai->arm64_iMinLine_lg2_szB  = 0;
    vai->hwcache_info.num_levels = 0;
    vai->hwcache_info.num_caches = 0;
-   vai->hwcache_info.caches = NULL;
+   vai->hwcache_info.caches     = NULL;
    vai->hwcache_info.icaches_maintain_coherence = True;  // whatever
 }
 
 /* Write default settings info *vbi. */
 void LibVEX_default_VexAbiInfo ( /*OUT*/VexAbiInfo* vbi )
 {
+   vex_bzero(vbi, sizeof(*vbi));
    vbi->guest_stack_redzone_size       = 0;
    vbi->guest_amd64_assume_fs_is_zero  = False;
    vbi->guest_amd64_assume_gs_is_0x60  = False;
index 2d408332ee77ae85318375f404a1f2013b796793..6da52ac864834c2c146dbdd2619aae07682ddbdf 100644 (file)
@@ -276,9 +276,14 @@ typedef
       /* PPC32/PPC64 only: size of instruction cache line */
       Int ppc_icache_line_szB;
       /* PPC32/PPC64 only: sizes zeroed by the dcbz/dcbzl instructions
-       * (bug#135264) */
+         (bug#135264) */
       UInt ppc_dcbz_szB;
       UInt ppc_dcbzl_szB; /* 0 means unsupported (SIGILL) */
+      /* ARM64: I- and D- minimum line sizes in log2(bytes), as
+         obtained from ctr_el0.DminLine and .IminLine.  For example, a
+         line size of 64 bytes would be encoded here as 6. */
+      UInt arm64_dMinLine_lg2_szB;
+      UInt arm64_iMinLine_lg2_szB;
    }
    VexArchInfo;
 
index 7acd298128193075ce1eb2d0d4eac64237dbb8a8..d590802441714ed6e1906d4aa39530b4f4dc801c 100644 (file)
@@ -2082,6 +2082,10 @@ extern Bool eqIRAtom ( IRExpr*, IRExpr* );
    ensure that these are filled in with suitable values before issuing
    a jump of kind Ijk_TInval.
 
+   Ijk_TInval requests invalidation of translations taken from the
+   requested range.  Ijk_FlushDCache requests flushing of the D cache
+   for the specified range.
+
    Re Ijk_EmWarn and Ijk_EmFail: the guest state must have a
    pseudo-register guest_EMNOTE, which is 32-bits regardless of the
    host or guest word size.  That register should be made to hold a
@@ -2109,7 +2113,8 @@ typedef
       Ijk_EmFail,         /* emulation critical (FATAL) error; give up */
       Ijk_NoDecode,       /* current instruction cannot be decoded */
       Ijk_MapFail,        /* Vex-provided address translation failed */
-      Ijk_TInval,         /* Invalidate translations before continuing. */
+      Ijk_TInval,         /* Inval icache to PoU in [TISTART, +TILEN) */
+      Ijk_FlushDCache,    /* Clean dcache to PoU in [TISTART, +TILEN) */
       Ijk_NoRedir,        /* Jump to un-redirected guest addr */
       Ijk_SigILL,         /* current instruction synths SIGILL */
       Ijk_SigTRAP,        /* current instruction synths SIGTRAP */
index 58a8e3006ed19e93cad9037c0480afd502df2598..5738ec1b4b411b5582d8fd75938a584e7c47ec9b 100644 (file)
 
    These values should be 61 or above so as not to conflict
    with Valgrind's VG_TRC_ values, which are 60 or below.
-
-   These values *must* be odd (have bit 0 set) because the dispatchers
-   (coregrind/m_dispatch/dispatch-*-*.S) use this fact to distinguish
-   a TRC value from the unchanged baseblock pointer -- which has 0 as
-   its lowest bit.
 */
 
 #define VEX_TRC_JMP_TINVAL     61  /* invalidate translations before
                                       continuing */
+#define VEX_TRC_JMP_FLUSHDCACHE 103 /* flush dcache before continuing */
+
 #define VEX_TRC_JMP_NOREDIR    81  /* jump to undirected guest addr */
 #define VEX_TRC_JMP_SIGTRAP    85  /* deliver trap (SIGTRAP) before
                                       continuing */