All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v2 0/2] target/arm: Fix handling of VSTCR_EL2.SW and VTCR_EL2.NSW
@ 2023-05-04 13:54 Peter Maydell
  2023-05-04 13:54 ` [PATCH v2 1/2] target/arm: Don't allow stage 2 page table walks to downgrade to NS Peter Maydell
  2023-05-04 13:54 ` [PATCH v2 2/2] target/arm: Fix handling of SW and NSW bits for stage 2 walks Peter Maydell
  0 siblings, 2 replies; 4+ messages in thread
From: Peter Maydell @ 2023-05-04 13:54 UTC (permalink / raw)
  To: qemu-arm, qemu-devel; +Cc: Richard Henderson

When FEAT_SEL2 (secure EL2) is implemented, the bits
VSTCR_EL2.SW and VTCR_EL2.NSW allow the guest to set things up
so that the stage 2 walk for an IPA is done to the other
address space, eg
 * a stage 2 walk for an NS IPA done to secure physical memory
   (where the translation table base address and other parameters
   for the walk come from the NS control registers VTTBR_EL2
   and VTCR_EL2)
 * a stage 2 walk for an S IPA done to non-secure physical memory
   (where the parameters from the walk come from the S control
   registers VSTTBR_EL2 and VSTCR_EL2)
We tried to implement this, but didn't get it right. In particular
the code is somewhat confused about whether it should handle
SW/NSW before doing a stage 2 walk (it does this for the s2
walk on the result of the s1 walk) or after doing a stage 2
walk (it does this for the s2 walks it does for s1 ptw loads).

Version 1 of this patchseries seemed to fix the reported bug,
but after more thought about this area of the code I think
it wasn't really completely addressing the issue. In particular
I suspect that in cases where we cache the result in an S2 TLB
we might not DTRT when we hit in the cache later.

So in v2 I've addressed the problem in a somewhat different way:

(1) when we call get_phys_addr_lpae() to do a stage 2 walk we
need to consistently get the ptw parameters right:
 * .in_ptw_idx should be ptw_idx_for_stage_2() of the .in_mmu_idx
   (where ptw_idx_for_stage_2() is a new function that determines
   whether we should be loading descriptors from S or NS, based
   on among other things the SW and NSW bits)
 * .in_secure should be true if .in_mmu_idx is Stage2_S

(2) S1_ptw_translate() should not do anything with the SW/NSW bits;
instead it just says "do an S2 walk" and trusts that the
(security state, address) tuple it effectively gets back from
that walk is the correct one.

This fixes https://gitlab.com/qemu-project/qemu/-/issues/1600 .

Changes v1->v2:
 * patch 1 is the same (and has been reviewed)
 * patch 2 is entirely different

Peter Maydell (2):
  target/arm: Don't allow stage 2 page table walks to downgrade to NS
  target/arm: Fix handling of SW and NSW bits for stage 2 walks

 target/arm/ptw.c | 81 ++++++++++++++++++++++++++++++++----------------
 1 file changed, 54 insertions(+), 27 deletions(-)

-- 
2.34.1



^ permalink raw reply	[flat|nested] 4+ messages in thread

* [PATCH v2 1/2] target/arm: Don't allow stage 2 page table walks to downgrade to NS
  2023-05-04 13:54 [PATCH v2 0/2] target/arm: Fix handling of VSTCR_EL2.SW and VTCR_EL2.NSW Peter Maydell
@ 2023-05-04 13:54 ` Peter Maydell
  2023-05-04 13:54 ` [PATCH v2 2/2] target/arm: Fix handling of SW and NSW bits for stage 2 walks Peter Maydell
  1 sibling, 0 replies; 4+ messages in thread
From: Peter Maydell @ 2023-05-04 13:54 UTC (permalink / raw)
  To: qemu-arm, qemu-devel; +Cc: Richard Henderson

Bit 63 in a Table descriptor is only the NSTable bit for stage 1
translations; in stage 2 it is RES0.  We were incorrectly looking at
it all the time.

This causes problems if:
 * the stage 2 table descriptor was incorrectly setting the RES0 bit
 * we are doing a stage 2 translation in Secure address space for
   a NonSecure stage 1 regime -- in this case we would incorrectly
   do an immediate downgrade to NonSecure

A bug elsewhere in the code currently prevents us from getting
to the second situation, but when we fix that it will be possible.

Cc: qemu-stable@nongnu.org
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
---
 target/arm/ptw.c | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/target/arm/ptw.c b/target/arm/ptw.c
index bd75da8dbcf..8ac6d9b1d0c 100644
--- a/target/arm/ptw.c
+++ b/target/arm/ptw.c
@@ -1415,17 +1415,18 @@ static bool get_phys_addr_lpae(CPUARMState *env, S1Translate *ptw,
     descaddrmask &= ~indexmask_grainsize;
 
     /*
-     * Secure accesses start with the page table in secure memory and
+     * Secure stage 1 accesses start with the page table in secure memory and
      * can be downgraded to non-secure at any step. Non-secure accesses
      * remain non-secure. We implement this by just ORing in the NSTable/NS
      * bits at each step.
+     * Stage 2 never gets this kind of downgrade.
      */
     tableattrs = is_secure ? 0 : (1 << 4);
 
  next_level:
     descaddr |= (address >> (stride * (4 - level))) & indexmask;
     descaddr &= ~7ULL;
-    nstable = extract32(tableattrs, 4, 1);
+    nstable = !regime_is_stage2(mmu_idx) && extract32(tableattrs, 4, 1);
     if (nstable) {
         /*
          * Stage2_S -> Stage2 or Phys_S -> Phys_NS
-- 
2.34.1



^ permalink raw reply related	[flat|nested] 4+ messages in thread

* [PATCH v2 2/2] target/arm: Fix handling of SW and NSW bits for stage 2 walks
  2023-05-04 13:54 [PATCH v2 0/2] target/arm: Fix handling of VSTCR_EL2.SW and VTCR_EL2.NSW Peter Maydell
  2023-05-04 13:54 ` [PATCH v2 1/2] target/arm: Don't allow stage 2 page table walks to downgrade to NS Peter Maydell
@ 2023-05-04 13:54 ` Peter Maydell
  2023-05-05 15:53   ` Richard Henderson
  1 sibling, 1 reply; 4+ messages in thread
From: Peter Maydell @ 2023-05-04 13:54 UTC (permalink / raw)
  To: qemu-arm, qemu-devel; +Cc: Richard Henderson

We currently don't correctly handle the VSTCR_EL2.SW and VTCR_EL2.NSW
configuration bits.  These allow configuration of whether the stage 2
page table walks for Secure IPA and NonSecure IPA should do their
descriptor reads from Secure or NonSecure physical addresses. (This
is separate from how the translation table base address and other
parameters are set: an NS IPA always uses VTTBR_EL2 and VTCR_EL2
for its base address and walk parameters, regardless of the NSW bit,
and similarly for Secure.)

Provide a new function ptw_idx_for_stage_2() which returns the
MMU index to use for descriptor reads, and use it to set up
the .in_ptw_idx wherever we call get_phys_addr_lpae().

For a stage 2 walk, wherever we call get_phys_addr_lpae():
 * .in_ptw_idx should be ptw_idx_for_stage_2() of the .in_mmu_idx
 * .in_secure should be true if .in_mmu_idx is Stage2_S

This allows us to correct S1_ptw_translate() so that it consistently
always sets its (out_secure, out_phys) to the result it gets from the
S2 walk (either by calling get_phys_addr_lpae() or by TLB lookup).
This makes better conceptual sense because the S2 walk should return
us an (address space, address) tuple, not an address that we then
randomly assign to S or NS.

Our previous handling of SW and NSW was broken, so guest code
trying to use these bits to put the s2 page tables in the "other"
address space wouldn't work correctly.

Cc: qemu-stable@nongnu.org
Resolves: https://gitlab.com/qemu-project/qemu/-/issues/1600
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
 target/arm/ptw.c | 76 ++++++++++++++++++++++++++++++++----------------
 1 file changed, 51 insertions(+), 25 deletions(-)

diff --git a/target/arm/ptw.c b/target/arm/ptw.c
index 8ac6d9b1d0c..a89aa70b8b2 100644
--- a/target/arm/ptw.c
+++ b/target/arm/ptw.c
@@ -103,6 +103,37 @@ ARMMMUIdx arm_stage1_mmu_idx(CPUARMState *env)
     return stage_1_mmu_idx(arm_mmu_idx(env));
 }
 
+/*
+ * Return where we should do ptw loads from for a stage 2 walk.
+ * This depends on whether the address we are looking up is a
+ * Secure IPA or a NonSecure IPA, which we know from whether this is
+ * Stage2 or Stage2_S.
+ * If this is the Secure EL1&0 regime we need to check the NSW and SW bits.
+ */
+static ARMMMUIdx ptw_idx_for_stage_2(CPUARMState *env, ARMMMUIdx stage2idx)
+{
+    bool s2walk_secure;
+
+    /*
+     * We're OK to check the current state of the CPU here because
+     * (1) we always invalidate all TLBs when the SCR_EL3.NS bit changes
+     * (2) there's no way to do a lookup that cares about Stage 2 for a
+     * different security state to the current one for AArch64, and AArch32
+     * never has a secure EL2. (AArch32 ATS12NSO[UP][RW] allow EL3 to do
+     * an NS stage 1+2 lookup while the NS bit is 0.)
+     */
+    if (!arm_is_secure_below_el3(env) || !arm_el_is_aa64(env, 3)) {
+        return ARMMMUIdx_Phys_NS;
+    }
+    if (stage2idx == ARMMMUIdx_Stage2_S) {
+        s2walk_secure = !(env->cp15.vstcr_el2 & VSTCR_SW);
+    } else {
+        s2walk_secure = !(env->cp15.vtcr_el2 & VTCR_NSW);
+    }
+    return s2walk_secure ? ARMMMUIdx_Phys_S : ARMMMUIdx_Phys_NS;
+
+}
+
 static bool regime_translation_big_endian(CPUARMState *env, ARMMMUIdx mmu_idx)
 {
     return (regime_sctlr(env, mmu_idx) & SCTLR_EE) != 0;
@@ -220,7 +251,6 @@ static bool S1_ptw_translate(CPUARMState *env, S1Translate *ptw,
     ARMMMUIdx mmu_idx = ptw->in_mmu_idx;
     ARMMMUIdx s2_mmu_idx = ptw->in_ptw_idx;
     uint8_t pte_attrs;
-    bool pte_secure;
 
     ptw->out_virt = addr;
 
@@ -232,8 +262,8 @@ static bool S1_ptw_translate(CPUARMState *env, S1Translate *ptw,
         if (regime_is_stage2(s2_mmu_idx)) {
             S1Translate s2ptw = {
                 .in_mmu_idx = s2_mmu_idx,
-                .in_ptw_idx = is_secure ? ARMMMUIdx_Phys_S : ARMMMUIdx_Phys_NS,
-                .in_secure = is_secure,
+                .in_ptw_idx = ptw_idx_for_stage_2(env, s2_mmu_idx),
+                .in_secure = s2_mmu_idx == ARMMMUIdx_Stage2_S,
                 .in_debug = true,
             };
             GetPhysAddrResult s2 = { };
@@ -244,12 +274,12 @@ static bool S1_ptw_translate(CPUARMState *env, S1Translate *ptw,
             }
             ptw->out_phys = s2.f.phys_addr;
             pte_attrs = s2.cacheattrs.attrs;
-            pte_secure = s2.f.attrs.secure;
+            ptw->out_secure = s2.f.attrs.secure;
         } else {
             /* Regime is physical. */
             ptw->out_phys = addr;
             pte_attrs = 0;
-            pte_secure = is_secure;
+            ptw->out_secure = s2_mmu_idx == ARMMMUIdx_Phys_S;
         }
         ptw->out_host = NULL;
         ptw->out_rw = false;
@@ -270,7 +300,7 @@ static bool S1_ptw_translate(CPUARMState *env, S1Translate *ptw,
         ptw->out_phys = full->phys_addr | (addr & ~TARGET_PAGE_MASK);
         ptw->out_rw = full->prot & PAGE_WRITE;
         pte_attrs = full->pte_attrs;
-        pte_secure = full->attrs.secure;
+        ptw->out_secure = full->attrs.secure;
 #else
         g_assert_not_reached();
 #endif
@@ -293,11 +323,6 @@ static bool S1_ptw_translate(CPUARMState *env, S1Translate *ptw,
         }
     }
 
-    /* Check if page table walk is to secure or non-secure PA space. */
-    ptw->out_secure = (is_secure
-                       && !(pte_secure
-                            ? env->cp15.vstcr_el2 & VSTCR_SW
-                            : env->cp15.vtcr_el2 & VTCR_NSW));
     ptw->out_be = regime_translation_big_endian(env, mmu_idx);
     return true;
 
@@ -2726,7 +2751,7 @@ static bool get_phys_addr_twostage(CPUARMState *env, S1Translate *ptw,
     hwaddr ipa;
     int s1_prot, s1_lgpgsz;
     bool is_secure = ptw->in_secure;
-    bool ret, ipa_secure, s2walk_secure;
+    bool ret, ipa_secure;
     ARMCacheAttrs cacheattrs1;
     bool is_el0;
     uint64_t hcr;
@@ -2740,20 +2765,11 @@ static bool get_phys_addr_twostage(CPUARMState *env, S1Translate *ptw,
 
     ipa = result->f.phys_addr;
     ipa_secure = result->f.attrs.secure;
-    if (is_secure) {
-        /* Select TCR based on the NS bit from the S1 walk. */
-        s2walk_secure = !(ipa_secure
-                          ? env->cp15.vstcr_el2 & VSTCR_SW
-                          : env->cp15.vtcr_el2 & VTCR_NSW);
-    } else {
-        assert(!ipa_secure);
-        s2walk_secure = false;
-    }
 
     is_el0 = ptw->in_mmu_idx == ARMMMUIdx_Stage1_E0;
-    ptw->in_mmu_idx = s2walk_secure ? ARMMMUIdx_Stage2_S : ARMMMUIdx_Stage2;
-    ptw->in_ptw_idx = s2walk_secure ? ARMMMUIdx_Phys_S : ARMMMUIdx_Phys_NS;
-    ptw->in_secure = s2walk_secure;
+    ptw->in_mmu_idx = ipa_secure ? ARMMMUIdx_Stage2_S : ARMMMUIdx_Stage2;
+    ptw->in_secure = ipa_secure;
+    ptw->in_ptw_idx = ptw_idx_for_stage_2(env, ptw->in_mmu_idx);
 
     /*
      * S1 is done, now do S2 translation.
@@ -2861,6 +2877,16 @@ static bool get_phys_addr_with_struct(CPUARMState *env, S1Translate *ptw,
         ptw->in_ptw_idx = is_secure ? ARMMMUIdx_Stage2_S : ARMMMUIdx_Stage2;
         break;
 
+    case ARMMMUIdx_Stage2:
+    case ARMMMUIdx_Stage2_S:
+        /*
+         * Second stage lookup uses physical for ptw; whether this is S or
+         * NS may depend on the SW/NSW bits if this is a stage 2 lookup for
+         * the Secure EL2&0 regime.
+         */
+        ptw->in_ptw_idx = ptw_idx_for_stage_2(env, mmu_idx);
+        break;
+
     case ARMMMUIdx_E10_0:
         s1_mmu_idx = ARMMMUIdx_Stage1_E0;
         goto do_twostage;
@@ -2884,7 +2910,7 @@ static bool get_phys_addr_with_struct(CPUARMState *env, S1Translate *ptw,
         /* fall through */
 
     default:
-        /* Single stage and second stage uses physical for ptw. */
+        /* Single stage uses physical for ptw. */
         ptw->in_ptw_idx = is_secure ? ARMMMUIdx_Phys_S : ARMMMUIdx_Phys_NS;
         break;
     }
-- 
2.34.1



^ permalink raw reply related	[flat|nested] 4+ messages in thread

* Re: [PATCH v2 2/2] target/arm: Fix handling of SW and NSW bits for stage 2 walks
  2023-05-04 13:54 ` [PATCH v2 2/2] target/arm: Fix handling of SW and NSW bits for stage 2 walks Peter Maydell
@ 2023-05-05 15:53   ` Richard Henderson
  0 siblings, 0 replies; 4+ messages in thread
From: Richard Henderson @ 2023-05-05 15:53 UTC (permalink / raw)
  To: Peter Maydell, qemu-arm, qemu-devel

On 5/4/23 14:54, Peter Maydell wrote:
> We currently don't correctly handle the VSTCR_EL2.SW and VTCR_EL2.NSW
> configuration bits.  These allow configuration of whether the stage 2
> page table walks for Secure IPA and NonSecure IPA should do their
> descriptor reads from Secure or NonSecure physical addresses. (This
> is separate from how the translation table base address and other
> parameters are set: an NS IPA always uses VTTBR_EL2 and VTCR_EL2
> for its base address and walk parameters, regardless of the NSW bit,
> and similarly for Secure.)
> 
> Provide a new function ptw_idx_for_stage_2() which returns the
> MMU index to use for descriptor reads, and use it to set up
> the .in_ptw_idx wherever we call get_phys_addr_lpae().
> 
> For a stage 2 walk, wherever we call get_phys_addr_lpae():
>   * .in_ptw_idx should be ptw_idx_for_stage_2() of the .in_mmu_idx
>   * .in_secure should be true if .in_mmu_idx is Stage2_S
> 
> This allows us to correct S1_ptw_translate() so that it consistently
> always sets its (out_secure, out_phys) to the result it gets from the
> S2 walk (either by calling get_phys_addr_lpae() or by TLB lookup).
> This makes better conceptual sense because the S2 walk should return
> us an (address space, address) tuple, not an address that we then
> randomly assign to S or NS.
> 
> Our previous handling of SW and NSW was broken, so guest code
> trying to use these bits to put the s2 page tables in the "other"
> address space wouldn't work correctly.
> 
> Cc:qemu-stable@nongnu.org
> Resolves:https://gitlab.com/qemu-project/qemu/-/issues/1600
> Signed-off-by: Peter Maydell<peter.maydell@linaro.org>
> ---
>   target/arm/ptw.c | 76 ++++++++++++++++++++++++++++++++----------------
>   1 file changed, 51 insertions(+), 25 deletions(-)

Reviewed-by: Richard Henderson <richard.henderson@linaro.org>

r~


^ permalink raw reply	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2023-05-05 15:53 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2023-05-04 13:54 [PATCH v2 0/2] target/arm: Fix handling of VSTCR_EL2.SW and VTCR_EL2.NSW Peter Maydell
2023-05-04 13:54 ` [PATCH v2 1/2] target/arm: Don't allow stage 2 page table walks to downgrade to NS Peter Maydell
2023-05-04 13:54 ` [PATCH v2 2/2] target/arm: Fix handling of SW and NSW bits for stage 2 walks Peter Maydell
2023-05-05 15:53   ` Richard Henderson

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.