target/arm: Implement ARMv8.2-TTS2UXN

The ARMv8.2-TTS2UXN feature extends the XN field in stage 2
translation table descriptors from just bit [54] to bits [54:53],
allowing stage 2 to control execution permissions separately for EL0
and EL1. Implement the new semantics of the XN field and enable
the feature for our 'max' CPU.

Backports commit ce3125bed935a12e619a8253c19340ecaa899347 from qemu
This commit is contained in:
Peter Maydell 2020-05-07 08:49:16 -04:00 committed by Lioncash
parent 1e75276a89
commit b427549ce4
4 changed files with 49 additions and 6 deletions

View file

@ -1921,6 +1921,7 @@ static void arm_max_initfn(struct uc_struct *uc, Object *obj, void *opaque)
t = FIELD_DP32(t, ID_MMFR4, HPDS, 1); /* AA32HPD */
t = FIELD_DP32(t, ID_MMFR4, AC2, 1); /* ACTLR2, HACTLR2 */
t = FIELD_DP32(t, ID_MMFR4, CNP, 1); /* TTCNP */
t = FIELD_DP32(t, ID_MMFR4, XNX, 1); /* TTS2UXN */
cpu->isar.id_mmfr4 = t;
}
}

View file

@ -3471,6 +3471,11 @@ static inline bool isar_feature_aa32_ccidx(const ARMISARegisters *id)
return FIELD_EX32(id->id_mmfr4, ID_MMFR4, CCIDX) != 0;
}
static inline bool isar_feature_aa32_tts2uxn(const ARMISARegisters *id)
{
return FIELD_EX32(id->id_mmfr4, ID_MMFR4, XNX) != 0;
}
/*
* 64-bit feature tests via id registers.
*/
@ -3683,6 +3688,11 @@ static inline bool isar_feature_aa64_ccidx(const ARMISARegisters *id)
return FIELD_EX64(id->id_aa64mmfr2, ID_AA64MMFR2, CCIDX) != 0;
}
static inline bool isar_feature_aa64_tts2uxn(const ARMISARegisters *id)
{
return FIELD_EX64(id->id_aa64mmfr1, ID_AA64MMFR1, XNX) != 0;
}
/*
* Feature tests for "does this exist in either 32-bit or 64-bit?"
*/
@ -3711,6 +3721,11 @@ static inline bool isar_feature_any_ccidx(const ARMISARegisters *id)
return isar_feature_aa64_ccidx(id) || isar_feature_aa32_ccidx(id);
}
static inline bool isar_feature_any_tts2uxn(const ARMISARegisters *id)
{
return isar_feature_aa64_tts2uxn(id) || isar_feature_aa32_tts2uxn(id);
}
/*
* Forward to the above feature tests given an ARMCPU pointer.
*/

View file

@ -317,6 +317,7 @@ static void aarch64_max_initfn(struct uc_struct *uc, Object *obj, void *opaque)
t = FIELD_DP64(t, ID_AA64MMFR1, VH, 1);
t = FIELD_DP64(t, ID_AA64MMFR1, PAN, 2); /* ATS1E1 */
t = FIELD_DP64(t, ID_AA64MMFR1, VMIDBITS, 2); /* VMID16 */
t = FIELD_DP64(t, ID_AA64MMFR1, XNX, 1); /* TTS2UXN */
cpu->isar.id_aa64mmfr1 = t;
t = cpu->isar.id_aa64mmfr2;
@ -349,6 +350,7 @@ static void aarch64_max_initfn(struct uc_struct *uc, Object *obj, void *opaque)
u = FIELD_DP32(u, ID_MMFR4, HPDS, 1); /* AA32HPD */
u = FIELD_DP32(u, ID_MMFR4, AC2, 1); /* ACTLR2, HACTLR2 */
u = FIELD_DP32(u, ID_MMFR4, CNP, 1); /* TTCNP */
u = FIELD_DP32(u, ID_MMFR4, XNX, 1); /* TTS2UXN */
cpu->isar.id_mmfr4 = u;
u = cpu->isar.id_aa64dfr0;

View file

@ -9654,9 +9654,10 @@ simple_ap_to_rw_prot(CPUARMState *env, ARMMMUIdx mmu_idx, int ap)
*
* @env: CPUARMState
* @s2ap: The 2-bit stage2 access permissions (S2AP)
* @xn: XN (execute-never) bit
* @xn: XN (execute-never) bits
* @s1_is_el0: true if this is S2 of an S1+2 walk for EL0
*/
static int get_S2prot(CPUARMState *env, int s2ap, int xn)
static int get_S2prot(CPUARMState *env, int s2ap, int xn, bool s1_is_el0)
{
int prot = 0;
@ -9666,9 +9667,32 @@ static int get_S2prot(CPUARMState *env, int s2ap, int xn)
if (s2ap & 2) {
prot |= PAGE_WRITE;
}
if (!xn) {
if (arm_el_is_aa64(env, 2) || prot & PAGE_READ) {
if (cpu_isar_feature(any_tts2uxn, env_archcpu(env))) {
switch (xn) {
case 0:
prot |= PAGE_EXEC;
break;
case 1:
if (s1_is_el0) {
prot |= PAGE_EXEC;
}
break;
case 2:
break;
case 3:
if (!s1_is_el0) {
prot |= PAGE_EXEC;
}
break;
default:
g_assert_not_reached();
}
} else {
if (!extract32(xn, 1, 1)) {
if (arm_el_is_aa64(env, 2) || prot & PAGE_READ) {
prot |= PAGE_EXEC;
}
}
}
return prot;
@ -10665,13 +10689,14 @@ static bool get_phys_addr_lpae(CPUARMState *env, target_ulong address,
}
ap = extract32(attrs, 4, 2);
xn = extract32(attrs, 12, 1);
if (mmu_idx == ARMMMUIdx_Stage2) {
ns = true;
*prot = get_S2prot(env, ap, xn);
xn = extract32(attrs, 11, 2);
*prot = get_S2prot(env, ap, xn, s1_is_el0);
} else {
ns = extract32(attrs, 3, 1);
xn = extract32(attrs, 12, 1);
pxn = extract32(attrs, 11, 1);
*prot = get_S1prot(env, mmu_idx, aarch64, ap, ns, xn, pxn);
}