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);
+}
+
+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");