[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [PATCH 8/8] arm/mpu: Save/restore VTCR_EL2 on vCPU context switch


  • To: Luca Fancellu <luca.fancellu@xxxxxxx>, <xen-devel@xxxxxxxxxxxxxxxxxxxx>
  • From: "Halder, Ayan Kumar" <ayankuma@xxxxxxx>
  • Date: Fri, 10 Jul 2026 17:08:22 +0100
  • Arc-authentication-results: i=1; mx.microsoft.com 1; spf=pass (sender ip is 165.204.84.17) smtp.rcpttodomain=arm.com smtp.mailfrom=amd.com; dmarc=pass (p=quarantine sp=quarantine pct=100) action=none header.from=amd.com; dkim=none (message not signed); arc=none (0)
  • Arc-message-signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com; s=arcselector10001; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-AntiSpam-MessageData-ChunkCount:X-MS-Exchange-AntiSpam-MessageData-0:X-MS-Exchange-AntiSpam-MessageData-1; bh=Q9OADA1cNgoK6OKrhNzNUPutpeu3/dqCjn6Z/Yrmr80=; b=sf4DSubFZc9IXuK/XfRbaxtcyCx5kZjaDQTI/l7PE6aQ/U5JtjJN9T3XAH4obXphUH8OK9Y6h9WO0FYepuUtSnEHquuEFa9xIEY+NMakTgkZ7i5UJCntSkn4DNpfrkEWv01F43IfiOaqulcjuzI2qB9bLbXnSqXBZTu4gJgGoKZeV/z9DmrQqZ10nLBCpfzSUgjAAxd3XAvXOy7bfirAEaSkFI3cADqdAeFElSHVg9lmzAgOWxFqd3UANTNgHoY6XLY7L+xAZck17plX6r2TLfYK4UMMSyhxSYkdiO4U4DfmEO50Cru0olu5KLhUk5/O/hVDrULD6msDZkcx7pI7tQ==
  • Arc-seal: i=1; a=rsa-sha256; s=arcselector10001; d=microsoft.com; cv=none; b=F8v1CTeZkXaxID60fuHbV3yr2RgBm1a305mnCKbu++r7TWRk40SOWaE2vfkWKRq1nuTGsbPFP9GJyB+MU87+yANuh2Kd8AJ6q52RHLo6gshSaV2bAKsjdAqbo4A4eMewm0Pdnn/p8Jvf0UZKJa9D7KfXzw91TBc2NvlgeWyKI2Ld+cK+YDDSk+A6TIU+kfH39L+/VPJjsLO48p3P0MpKhDmMRrpydTZKL5MXu91hG5C1/ncMpg1LKly8fg/rU3SfCACtG3UIHxlhgQsMJi4bUG8I50YEAIry1l3Wzfyvl3xgonWPp6WUVM1VF0cXDDxIPDHbZ5Agj1ot0tbxp0MaAg==
  • Authentication-results: eu.smtp.expurgate.cloud; dkim=pass header.s=selector1 header.d=amd.com header.i="@amd.com" header.h="From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck"
  • Cc: Stefano Stabellini <sstabellini@xxxxxxxxxx>, Julien Grall <julien@xxxxxxx>, Bertrand Marquis <bertrand.marquis@xxxxxxx>, Michal Orzel <michal.orzel@xxxxxxx>, Volodymyr Babchuk <Volodymyr_Babchuk@xxxxxxxx>
  • Delivery-date: Fri, 10 Jul 2026 16:08:54 +0000
  • List-id: Xen developer discussion <xen-devel.lists.xenproject.org>

Hi Luca,

On 20/04/2026 15:25, Luca Fancellu wrote:
On AArch64 MPU systems, the VTCR register contains the MSA bit that determines
if the guest is using MPU or MMU at EL1, which is required to be
saved/restored on vCPU context switch.

On AArch64 MPU systems the VTCR_EL2 register configuration will be saved
during setup_virt_paging and will be placed in a new member of
'struct arch_vcpu' named vtcr_el2, to be retrieved by context switch.

AArch32 MPU systems and MMU systems don't need to save/restore this
register because they don't have any MSA bit and related functionality,
so for these architecture a stub is provided.

Signed-off-by: Luca Fancellu <luca.fancellu@xxxxxxx>
---
  xen/arch/arm/arm64/mpu/p2m.c                | 15 +++++++++++++++
  xen/arch/arm/domain.c                       |  2 ++
  xen/arch/arm/include/asm/domain.h           |  5 +++++
  xen/arch/arm/include/asm/mmu/domain-build.h |  2 ++
  xen/arch/arm/include/asm/mpu/domain-build.h |  6 ++++++
  xen/arch/arm/include/asm/mpu/p2m.h          | 10 ++++++++++
  xen/arch/arm/mpu/domain-build.c             | 17 +++++++++++++++++
  xen/arch/arm/mpu/p2m.c                      |  4 ++++
  8 files changed, 61 insertions(+)

diff --git a/xen/arch/arm/arm64/mpu/p2m.c b/xen/arch/arm/arm64/mpu/p2m.c
index a1ec9fcd6195..350cbd7ae94c 100644
--- a/xen/arch/arm/arm64/mpu/p2m.c
+++ b/xen/arch/arm/arm64/mpu/p2m.c
@@ -3,8 +3,12 @@
  #include <xen/bug.h>
  #include <xen/init.h>
  #include <xen/lib.h>
+#include <xen/sched.h>
  #include <asm/p2m.h>
+/* VTCR_EL2 value to be configured for the boot CPU. */
+register_t __read_mostly vtcr;
+
  void __init setup_virt_paging(void)
  {
      register_t vtcr_el2 = READ_SYSREG(VTCR_EL2);
@@ -58,6 +62,7 @@ void __init setup_virt_paging(void)
      else
          vtcr_el2 &= ~VTCR_VS;
+ vtcr = vtcr_el2;
      WRITE_SYSREG(vtcr_el2, VTCR_EL2);
p2m_vmid_allocator_init();
@@ -89,6 +94,16 @@ void __init setup_virt_paging(void)
      panic("Hardware with no PMSAv8-64 support in any translation regime\n");
  }
+void p2m_save_vtcr(struct vcpu *p)
+{
+    p->arch.vtcr_el2 = READ_SYSREG(VTCR_EL2);
+}
+
VTCR_EL2 is an EL2 register the guest cannot touch, and set_v8r_vtcr_msa()
already fixes each vCPU's value at creation. Reading it back on every save is
redundant
+void p2m_restore_vtcr(struct vcpu *n)
+{
+    WRITE_SYSREG(n->arch.vtcr_el2, VTCR_EL2);
+}
+
  /*
   * Local variables:
   * mode: C
diff --git a/xen/arch/arm/domain.c b/xen/arch/arm/domain.c
index 221b1f8a7f9d..e928301d7cb0 100644
--- a/xen/arch/arm/domain.c
+++ b/xen/arch/arm/domain.c
@@ -538,6 +538,8 @@ int arch_vcpu_create(struct vcpu *v)
      if ( get_ssbd_state() == ARM_SSBD_RUNTIME )
          v->arch.cpu_info->flags |= CPUINFO_WORKAROUND_2_FLAG;
+ arch_set_vtcr_msa(v);
+
      if ( is_mpu_domain(v->domain) )
          allocate_el1_mpu_regions(v);
diff --git a/xen/arch/arm/include/asm/domain.h b/xen/arch/arm/include/asm/domain.h
index 44c304ef8aa9..3ab004518427 100644
--- a/xen/arch/arm/include/asm/domain.h
+++ b/xen/arch/arm/include/asm/domain.h
@@ -203,6 +203,11 @@ struct arch_vcpu
      uint32_t cpacr;
#ifdef CONFIG_MPU
+#ifdef CONFIG_ARM_64
+    /* Virtualization Translation Control Register */
+    uint64_t vtcr_el2;
+#endif
+
      /* EL1 MPU memory regions */
      pr_t *mpu_regions;
  #endif
diff --git a/xen/arch/arm/include/asm/mmu/domain-build.h 
b/xen/arch/arm/include/asm/mmu/domain-build.h
index 3e0d9a6a2a08..0919c0097da9 100644
--- a/xen/arch/arm/include/asm/mmu/domain-build.h
+++ b/xen/arch/arm/include/asm/mmu/domain-build.h
@@ -34,6 +34,8 @@ int arch_set_v8r_el1_msa(struct domain *d,
      return 0;
  }
+static inline void arch_set_vtcr_msa(struct vcpu *v) {}
+
  #endif /* __ARM_MMU_DOMAIN_BUILD_H__ */
/*
diff --git a/xen/arch/arm/include/asm/mpu/domain-build.h 
b/xen/arch/arm/include/asm/mpu/domain-build.h
index 463cd85b5b7e..8d3a743219ce 100644
--- a/xen/arch/arm/include/asm/mpu/domain-build.h
+++ b/xen/arch/arm/include/asm/mpu/domain-build.h
@@ -15,6 +15,12 @@ int arch_set_v8r_el1_msa(struct domain *d,
                           const struct xen_domctl_createdomain *config,
                           unsigned int flags);
+#ifdef CONFIG_ARM_64
+void arch_set_vtcr_msa(struct vcpu *v);
+#else
+static inline void arch_set_vtcr_msa(struct vcpu *v) {}
+#endif
+
  #endif /* __ARM_MPU_DOMAIN_BUILD_H__ */
/*
diff --git a/xen/arch/arm/include/asm/mpu/p2m.h 
b/xen/arch/arm/include/asm/mpu/p2m.h
index d0ec8a77a15a..1628148ba578 100644
--- a/xen/arch/arm/include/asm/mpu/p2m.h
+++ b/xen/arch/arm/include/asm/mpu/p2m.h
@@ -9,6 +9,8 @@
struct p2m_domain; +extern register_t vtcr;
+
  /*
   * The architecture allows at most 255 EL2 MPU memory regions. The size of the
   * MPU structure entry (pr_t) is 32 Bytes on AArch64 (requiring two 4KB pages)
@@ -36,6 +38,14 @@ static inline bool region_is_p2m_valid(pr_t *pr)
      return (pr->p2m_type != p2m_invalid);
  }
+#ifdef CONFIG_ARM_64
+void p2m_save_vtcr(struct vcpu *p);
+void p2m_restore_vtcr(struct vcpu *n);
+#else
+static inline void p2m_save_vtcr(struct vcpu *p) {}
+static inline void p2m_restore_vtcr(struct vcpu *n) {}
+#endif
+
  #endif /* __ARM_MPU_P2M_H__ */
/*
diff --git a/xen/arch/arm/mpu/domain-build.c b/xen/arch/arm/mpu/domain-build.c
index 1bdd0ffedebb..19e504f7149e 100644
--- a/xen/arch/arm/mpu/domain-build.c
+++ b/xen/arch/arm/mpu/domain-build.c
@@ -8,6 +8,7 @@
  #include <xen/sched.h>
  #include <asm/mpu.h>
  #include <asm/mpu/domain-build.h>
+#include <asm/mpu/p2m.h>
  #include <public/arch-arm.h>
  #include <public/domctl.h>
@@ -66,6 +67,22 @@ int arch_set_v8r_el1_msa(struct domain *d,
      return 0;
  }
+#ifdef CONFIG_ARM_64
+void arch_set_vtcr_msa(struct vcpu *v)
+{
+    /*
+     * When ID_AA64MMFR0_EL1.MSA_frac is 0b0010 (MM64_MSA_FRAC_VMSA_SUPPORT),
+     * then VTCR_EL2.MSA determines the memory system architecture enabled
+     * at stage 1 of the Secure EL1&0 translation regime.
+     */
+    v->arch.vtcr_el2 = vtcr;
+    if ( is_mpu_domain(v->domain) )
+        v->arch.vtcr_el2 &= ~VTCR_MSA;
+    else
+        v->arch.vtcr_el2 |= VTCR_MSA;
+}
+#endif
+
  /*
   * Local variables:
   * mode: C
diff --git a/xen/arch/arm/mpu/p2m.c b/xen/arch/arm/mpu/p2m.c
index 06c92a3ef41b..b41abd8f2d37 100644
--- a/xen/arch/arm/mpu/p2m.c
+++ b/xen/arch/arm/mpu/p2m.c
@@ -357,6 +357,8 @@ void p2m_save_state(struct vcpu *p)
p->arch.sctlr = READ_SYSREG(SCTLR_EL1); + p2m_save_vtcr(p);
+
      if ( p2m_xenmpu_update(p2m, false) )
          panic("Failed to offline P2M MPU memory mapping\n");
  }
@@ -369,6 +371,8 @@ void p2m_restore_state(struct vcpu *n)
      WRITE_SYSREG(n->arch.sctlr, SCTLR_EL1);
      WRITE_SYSREG(n->arch.hcr_el2, HCR_EL2);
+ p2m_restore_vtcr(n);
+
      WRITE_SYSREG(p2m->vsctlr, VSCTLR_EL2);
      if ( p2m_xenmpu_update(p2m, true) )
          panic("Failed to online P2M MPU memory mapping\n");
- Ayan



 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.