Message ID | 20230124000027.3565716-15-richard.henderson@linaro.org |
---|---|
State | New |
Headers | show |
Series | target/arm: Implement FEAT_RME | expand |
On Tue, 24 Jan 2023 at 00:02, Richard Henderson <richard.henderson@linaro.org> wrote: > > While Root and Realm may read and write data from other spaces, > neither may execute from other pa spaces. > > This happens for Stage1 EL3, EL2, EL2&0, but stage2 EL1&0. > > Signed-off-by: Richard Henderson <richard.henderson@linaro.org> > --- > target/arm/ptw.c | 66 ++++++++++++++++++++++++++++++++++++++++++------ > 1 file changed, 58 insertions(+), 8 deletions(-) > > diff --git a/target/arm/ptw.c b/target/arm/ptw.c > index 849f5e89ca..6b6f8195eb 100644 > --- a/target/arm/ptw.c > +++ b/target/arm/ptw.c > @@ -909,7 +909,7 @@ do_fault: > * @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, bool s1_is_el0) > +static int get_S2prot_noexecute(int s2ap) > { > int prot = 0; > > @@ -919,6 +919,12 @@ static int get_S2prot(CPUARMState *env, int s2ap, int xn, bool s1_is_el0) > 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) { > @@ -956,12 +962,14 @@ static int get_S2prot(CPUARMState *env, int s2ap, int xn, bool s1_is_el0) > * @mmu_idx: MMU index indicating required translation regime > * @is_aa64: TRUE if AArch64 > * @ap: The 2-bit simple AP (AP[2:1]) > - * @ns: NS (non-secure) bit > * @xn: XN (execute-never) bit > * @pxn: PXN (privileged execute-never) bit > + * @in_pa: The original input pa space > + * @out_pa: The output pa space, modified by NSTable, NS, and NSE > */ > static int get_S1prot(CPUARMState *env, ARMMMUIdx mmu_idx, bool is_aa64, > - int ap, int ns, int xn, int pxn) > + int ap, int xn, int pxn, > + ARMSecuritySpace in_pa, ARMSecuritySpace out_pa) > { > bool is_user = regime_is_user(env, mmu_idx); > int prot_rw, user_rw; > @@ -982,8 +990,39 @@ static int get_S1prot(CPUARMState *env, ARMMMUIdx mmu_idx, bool is_aa64, > } > } > > - if (ns && arm_is_secure(env) && (env->cp15.scr_el3 & SCR_SIF)) { > - return prot_rw; Ah, this looks like it fixes the bug introduced in patch 12; I guess some of this needs rearranging between patches. > + if (in_pa != out_pa) { > + switch (in_pa) { > + case ARMSS_Root: > + /* > + * R_ZWRVD: permission fault for insn fetched from non-Root, > + * I_WWBFB: SIF has no effect in EL3. > + */ > + return prot_rw; > + case ARMSS_Realm: > + /* > + * R_PKTDS: permission fault for insn fetched from non-Realm, > + * for Realm EL2 or EL2&0. The corresponding fault for EL1&0 > + * happens during any stage2 translation. > + */ > + switch (mmu_idx) { > + case ARMMMUIdx_E2: > + case ARMMMUIdx_E20_0: > + case ARMMMUIdx_E20_2: > + case ARMMMUIdx_E20_2_PAN: > + return prot_rw; > + default: > + break; > + } > + break; > + case ARMSS_Secure: > + if (env->cp15.scr_el3 & SCR_SIF) { > + return prot_rw; > + } > + break; > + default: > + /* Input NonSecure must have output NonSecure. */ > + g_assert_not_reached(); > + } > } > > /* TODO have_wxn should be replaced with > @@ -1556,12 +1595,16 @@ static bool get_phys_addr_lpae(CPUARMState *env, S1Translate *ptw, > /* > * R_GYNXY: For stage2 in Realm security state, bit 55 is NS. > * The bit remains ignored for other security states. > + * R_YMCSL: Executing an insn fetched from non-Realm causes > + * a stage2 permission fault. > */ > if (out_space == ARMSS_Realm && extract64(attrs, 55, 1)) { > out_space = ARMSS_NonSecure; > + result->f.prot = get_S2prot_noexecute(ap); > + } else { > + xn = extract64(attrs, 53, 2); > + result->f.prot = get_S2prot(env, ap, xn, s1_is_el0); > } > - xn = extract64(attrs, 53, 2); > - result->f.prot = get_S2prot(env, ap, xn, s1_is_el0); > } else { > int ns = extract32(attrs, 5, 1); > switch (out_space) { > @@ -1613,7 +1656,14 @@ static bool get_phys_addr_lpae(CPUARMState *env, S1Translate *ptw, > } > xn = extract64(attrs, 54, 1); > pxn = extract64(attrs, 53, 1); > - result->f.prot = get_S1prot(env, mmu_idx, aarch64, ap, ns, xn, pxn); > + > + /* > + * Note that we modified ptw->in_space earlier for NSTable, > + * and result->f.attrs was initialized by get_phys_addr, so > + * that retains a copy of the original security space. > + */ > + result->f.prot = get_S1prot(env, mmu_idx, aarch64, ap, xn, pxn, > + result->f.attrs.space, out_space); > } > > if (!(result->f.prot & (1 << access_type))) { > -- > 2.34.1 thanks -- PMM
diff --git a/target/arm/ptw.c b/target/arm/ptw.c index 849f5e89ca..6b6f8195eb 100644 --- a/target/arm/ptw.c +++ b/target/arm/ptw.c @@ -909,7 +909,7 @@ do_fault: * @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, bool s1_is_el0) +static int get_S2prot_noexecute(int s2ap) { int prot = 0; @@ -919,6 +919,12 @@ static int get_S2prot(CPUARMState *env, int s2ap, int xn, bool s1_is_el0) 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) { @@ -956,12 +962,14 @@ static int get_S2prot(CPUARMState *env, int s2ap, int xn, bool s1_is_el0) * @mmu_idx: MMU index indicating required translation regime * @is_aa64: TRUE if AArch64 * @ap: The 2-bit simple AP (AP[2:1]) - * @ns: NS (non-secure) bit * @xn: XN (execute-never) bit * @pxn: PXN (privileged execute-never) bit + * @in_pa: The original input pa space + * @out_pa: The output pa space, modified by NSTable, NS, and NSE */ static int get_S1prot(CPUARMState *env, ARMMMUIdx mmu_idx, bool is_aa64, - int ap, int ns, int xn, int pxn) + int ap, int xn, int pxn, + ARMSecuritySpace in_pa, ARMSecuritySpace out_pa) { bool is_user = regime_is_user(env, mmu_idx); int prot_rw, user_rw; @@ -982,8 +990,39 @@ static int get_S1prot(CPUARMState *env, ARMMMUIdx mmu_idx, bool is_aa64, } } - if (ns && arm_is_secure(env) && (env->cp15.scr_el3 & SCR_SIF)) { - return prot_rw; + if (in_pa != out_pa) { + switch (in_pa) { + case ARMSS_Root: + /* + * R_ZWRVD: permission fault for insn fetched from non-Root, + * I_WWBFB: SIF has no effect in EL3. + */ + return prot_rw; + case ARMSS_Realm: + /* + * R_PKTDS: permission fault for insn fetched from non-Realm, + * for Realm EL2 or EL2&0. The corresponding fault for EL1&0 + * happens during any stage2 translation. + */ + switch (mmu_idx) { + case ARMMMUIdx_E2: + case ARMMMUIdx_E20_0: + case ARMMMUIdx_E20_2: + case ARMMMUIdx_E20_2_PAN: + return prot_rw; + default: + break; + } + break; + case ARMSS_Secure: + if (env->cp15.scr_el3 & SCR_SIF) { + return prot_rw; + } + break; + default: + /* Input NonSecure must have output NonSecure. */ + g_assert_not_reached(); + } } /* TODO have_wxn should be replaced with @@ -1556,12 +1595,16 @@ static bool get_phys_addr_lpae(CPUARMState *env, S1Translate *ptw, /* * R_GYNXY: For stage2 in Realm security state, bit 55 is NS. * The bit remains ignored for other security states. + * R_YMCSL: Executing an insn fetched from non-Realm causes + * a stage2 permission fault. */ if (out_space == ARMSS_Realm && extract64(attrs, 55, 1)) { out_space = ARMSS_NonSecure; + result->f.prot = get_S2prot_noexecute(ap); + } else { + xn = extract64(attrs, 53, 2); + result->f.prot = get_S2prot(env, ap, xn, s1_is_el0); } - xn = extract64(attrs, 53, 2); - result->f.prot = get_S2prot(env, ap, xn, s1_is_el0); } else { int ns = extract32(attrs, 5, 1); switch (out_space) { @@ -1613,7 +1656,14 @@ static bool get_phys_addr_lpae(CPUARMState *env, S1Translate *ptw, } xn = extract64(attrs, 54, 1); pxn = extract64(attrs, 53, 1); - result->f.prot = get_S1prot(env, mmu_idx, aarch64, ap, ns, xn, pxn); + + /* + * Note that we modified ptw->in_space earlier for NSTable, + * and result->f.attrs was initialized by get_phys_addr, so + * that retains a copy of the original security space. + */ + result->f.prot = get_S1prot(env, mmu_idx, aarch64, ap, xn, pxn, + result->f.attrs.space, out_space); } if (!(result->f.prot & (1 << access_type))) {
While Root and Realm may read and write data from other spaces, neither may execute from other pa spaces. This happens for Stage1 EL3, EL2, EL2&0, but stage2 EL1&0. Signed-off-by: Richard Henderson <richard.henderson@linaro.org> --- target/arm/ptw.c | 66 ++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 58 insertions(+), 8 deletions(-)