Author: sewardj
Date: Sat May 3 21:20:56 2014
New Revision: 2851
Log:
ARM64: add support for cache management instructions (VEX side):
dc cvau, regX
ic ivau, regX
mrs regX, ctr_el0
Fixes #333228 and #333230.
Modified:
trunk/priv/guest_arm64_toIR.c
trunk/priv/host_arm64_defs.c
trunk/priv/host_arm64_isel.c
trunk/priv/ir_defs.c
trunk/priv/main_main.c
trunk/pub/libvex.h
trunk/pub/libvex_ir.h
trunk/pub/libvex_trc_values.h
Modified: trunk/priv/guest_arm64_toIR.c
==============================================================================
--- trunk/priv/guest_arm64_toIR.c (original)
+++ trunk/priv/guest_arm64_toIR.c Sat May 3 21:20:56 2014
@@ -4386,7 +4386,8 @@
/*------------------------------------------------------------*/
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 @@
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;
+ }
- /* ------------------ ISB, DSB ------------------ */
+ /* ------------------ 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;
+ }
+
+ /* ------------------ 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 @@
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 @@
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 @@
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,
Modified: trunk/priv/host_arm64_defs.c
==============================================================================
--- trunk/priv/host_arm64_defs.c (original)
+++ trunk/priv/host_arm64_defs.c Sat May 3 21:20:56 2014
@@ -4461,7 +4461,8 @@
//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;
Modified: trunk/priv/host_arm64_isel.c
==============================================================================
--- trunk/priv/host_arm64_isel.c (original)
+++ trunk/priv/host_arm64_isel.c Sat May 3 21:20:56 2014
@@ -6915,7 +6915,8 @@
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);
Modified: trunk/priv/ir_defs.c
==============================================================================
--- trunk/priv/ir_defs.c (original)
+++ trunk/priv/ir_defs.c Sat May 3 21:20:56 2014
@@ -1413,6 +1413,7 @@
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;
Modified: trunk/priv/main_main.c
==============================================================================
--- trunk/priv/main_main.c (original)
+++ trunk/priv/main_main.c Sat May 3 21:20:56 2014
@@ -92,6 +92,7 @@
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 @@
/* 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;
Modified: trunk/pub/libvex.h
==============================================================================
--- trunk/pub/libvex.h (original)
+++ trunk/pub/libvex.h Sat May 3 21:20:56 2014
@@ -276,9 +276,14 @@
/* 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;
Modified: trunk/pub/libvex_ir.h
==============================================================================
--- trunk/pub/libvex_ir.h (original)
+++ trunk/pub/libvex_ir.h Sat May 3 21:20:56 2014
@@ -2082,6 +2082,10 @@
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 @@
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 */
Modified: trunk/pub/libvex_trc_values.h
==============================================================================
--- trunk/pub/libvex_trc_values.h (original)
+++ trunk/pub/libvex_trc_values.h Sat May 3 21:20:56 2014
@@ -46,15 +46,12 @@
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 */
|