mirror of
https://github.com/yuzu-emu/unicorn.git
synced 2025-03-23 06:25:12 +00:00
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:
parent
1e75276a89
commit
b427549ce4
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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.
|
||||
*/
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue