* @xn: XN (execute-never) bits
* @s1_is_el0: true if this is S2 of an S1+2 walk for EL0
*/
-static int get_S2prot_noexecute(int s2ap)
+static int get_S2prot(CPUARMState *env, int s2ap, int xn, bool s1_is_el0)
{
int prot = 0;
if (s2ap & 2) {
prot |= PAGE_WRITE;
}
- return prot;
-}
-
-static int get_S2prot(CPUARMState *env, int s2ap, int xn, bool s1_is_el0)
-{
- int prot = get_S2prot_noexecute(s2ap);
if (cpu_isar_feature(any_tts2uxn, env_archcpu(env))) {
switch (xn) {
return prot;
}
+static int get_S2prot_indirect(CPUARMState *env, GetPhysAddrResult *result,
+ int pi_index, int po_index, bool s1_is_el0)
+{
+ /* Last index is (priv, unpriv, ttw) */
+ static const uint8_t perm_table[16][3] = {
+ /* 0 */ { 0, 0, 0 }, /* no access */
+ /* 1 */ { 0, 0, 0 }, /* reserved */
+ /* 2 */ { PAGE_READ, PAGE_READ, PAGE_READ | PAGE_WRITE },
+ /* 3 */ { PAGE_READ, PAGE_READ, PAGE_READ | PAGE_WRITE },
+ /* 4 */ { PAGE_WRITE, PAGE_WRITE, 0 },
+ /* 5 */ { 0, 0, 0 }, /* reserved */
+ /* 6 */ { PAGE_READ, PAGE_READ, PAGE_READ | PAGE_WRITE },
+ /* 7 */ { PAGE_READ, PAGE_READ, PAGE_READ | PAGE_WRITE },
+ /* 8 */ { PAGE_READ, PAGE_READ, PAGE_READ },
+ /* 9 */ { PAGE_READ, PAGE_READ | PAGE_EXEC, PAGE_READ },
+ /* A */ { PAGE_READ | PAGE_EXEC, PAGE_READ, PAGE_READ },
+ /* B */ { PAGE_READ | PAGE_EXEC, PAGE_READ | PAGE_EXEC, PAGE_READ },
+ /* C */ { PAGE_READ | PAGE_WRITE,
+ PAGE_READ | PAGE_WRITE,
+ PAGE_READ | PAGE_WRITE },
+ /* D */ { PAGE_READ | PAGE_WRITE,
+ PAGE_READ | PAGE_WRITE | PAGE_EXEC,
+ PAGE_READ | PAGE_WRITE },
+ /* E */ { PAGE_READ | PAGE_WRITE | PAGE_EXEC,
+ PAGE_READ | PAGE_WRITE,
+ PAGE_READ | PAGE_WRITE },
+ /* F */ { PAGE_READ | PAGE_WRITE | PAGE_EXEC,
+ PAGE_READ | PAGE_WRITE | PAGE_EXEC,
+ PAGE_READ | PAGE_WRITE },
+ };
+
+ uint64_t pir = (env->cp15.scr_el3 & SCR_PIEN ? env->cp15.s2pir_el2 : 0);
+ int s2pi = extract64(pir, pi_index * 4, 4);
+
+ result->f.prot = perm_table[s2pi][2];
+ return perm_table[s2pi][s1_is_el0];
+}
+
/*
* Translate section/page access permissions to protection flags
* @env: CPUARMState
int32_t stride;
int addrsize, inputsize, outputsize;
uint64_t tcr = regime_tcr(env, mmu_idx);
- int ap;
+ int ap, prot;
uint32_t el = regime_el(env, mmu_idx);
uint64_t descaddrmask;
bool aarch64 = arm_el_is_aa64(env, el);
ap = extract32(attrs, 6, 2);
out_space = ptw->cur_space;
if (regime_is_stage2(mmu_idx)) {
+ if (param.pie) {
+ int pi = extract64(attrs, 6, 1)
+ | (extract64(attrs, 51, 1) << 1)
+ | (extract64(attrs, 53, 2) << 2);
+ int po = extract64(attrs, 60, 3);
+ prot = get_S2prot_indirect(env, result, pi, po, ptw->in_s1_is_el0);
+ } else {
+ int xn = extract64(attrs, 53, 2);
+ prot = get_S2prot(env, ap, xn, ptw->in_s1_is_el0);
+ /* Install TTW permissions in f.prot. */
+ result->f.prot = prot & (PAGE_READ | PAGE_WRITE);
+ }
/*
* R_GYNXY: For stage2 in Realm security state, bit 55 is NS.
* The bit remains ignored for other security states.
*/
if (out_space == ARMSS_Realm && extract64(attrs, 55, 1)) {
out_space = ARMSS_NonSecure;
- result->f.prot = get_S2prot_noexecute(ap);
- } else {
- int xn = extract64(attrs, 53, 2);
- result->f.prot = get_S2prot(env, ap, xn, ptw->in_s1_is_el0);
+ prot &= ~PAGE_EXEC;
}
+ result->s2prot = prot;
result->cacheattrs.is_s2_format = true;
result->cacheattrs.attrs = extract32(attrs, 2, 4);
* Note that we modified ptw->in_space earlier for NSTable, but
* result->f.attrs retains a copy of the original security space.
*/
- result->f.prot = get_S1prot_indirect(env, ptw, mmu_idx, pi, po,
- result->f.attrs.space,
- out_space);
+ prot = get_S1prot_indirect(env, ptw, mmu_idx, pi, po,
+ result->f.attrs.space, out_space);
} else {
int xn = extract64(attrs, 54, 1);
int pxn = extract64(attrs, 53, 1);
user_rw = simple_ap_to_rw_prot_is_user(ap, true);
prot_rw = simple_ap_to_rw_prot_is_user(ap, false);
- result->f.prot = get_S1prot(env, mmu_idx, aarch64,
- user_rw, prot_rw, xn, pxn,
- ptw->in_space, out_space);
+ prot = get_S1prot(env, mmu_idx, aarch64, user_rw, prot_rw,
+ xn, pxn, ptw->in_space, out_space);
}
+ result->f.prot = prot;
/* Index into MAIR registers for cache attributes */
attrindx = extract32(attrs, 2, 3);
result->f.tlb_fill_flags = 0;
}
- if (ptw->in_prot_check & ~result->f.prot) {
+ if (ptw->in_prot_check & ~prot) {
fi->type = ARMFault_Permission;
goto do_fault;
}
fi->s2addr = ipa;
/* Combine the S1 and S2 perms. */
- result->f.prot &= s1_prot;
+ result->f.prot = s1_prot & result->s2prot;
/* If S2 fails, return early. */
if (ret) {