:p
atchew
Login
This series continues to further the ongoing work to introduce support for MPU systems in Xen. The patches in this series aim to implement MPU specific p2m functions. Harry Ramsey (2): arm/mpu: Introduce `v8r_el1_msa` device tree property for domains arm/mpu: Implement p2m tables Penny Zheng (1): arm/mpu: implement setup_virt_paging for MPU system docs/misc/arm/device-tree/booting.txt | 12 ++++ xen/arch/arm/arm64/mpu/p2m.c | 80 +++++++++++++++++++++++- xen/arch/arm/dom0less-build.c | 24 +++++++ xen/arch/arm/domain.c | 4 ++ xen/arch/arm/include/asm/arm32/mpu.h | 2 + xen/arch/arm/include/asm/arm64/mpu.h | 2 + xen/arch/arm/include/asm/arm64/sysregs.h | 4 ++ xen/arch/arm/include/asm/cpufeature.h | 13 +++- xen/arch/arm/include/asm/domain.h | 7 +++ xen/arch/arm/include/asm/mpu.h | 5 ++ xen/arch/arm/include/asm/mpu/p2m.h | 12 ++++ xen/arch/arm/include/asm/p2m.h | 5 ++ xen/arch/arm/include/asm/processor.h | 8 +++ xen/arch/arm/mpu/arm32/mm.c | 5 ++ xen/arch/arm/mpu/arm64/mm.c | 5 ++ xen/arch/arm/mpu/p2m.c | 78 ++++++++++++++++++++++- xen/include/public/arch-arm.h | 2 + 17 files changed, 261 insertions(+), 7 deletions(-) -- 2.34.1
From: Penny Zheng <Penny.Zheng@arm.com> Implement setup_virt_paging for aarch64 MPU systems, taking tare of stage 2 address translation regime, IPA bits, supported VMID length configuration and vtcr_el2/vstcr_el2 register programming. Implement also the Armv8-R specific changes to ID_AA64MMFR0_EL1, related to the supported memory system architecture (PMSA/VMSA) and check that when MPU is built, the underlying HW is compatible with PMSA. By default MPU at EL2 and EL1 is required. Signed-off-by: Penny Zheng <penny.zheng@arm.com> Signed-off-by: Wei Chen <wei.chen@arm.com> Signed-off-by: Luca Fancellu <luca.fancellu@arm.com> Signed-off-by: Hari Limaye <hari.limaye@arm.com> Signed-off-by: Harry Ramsey <harry.ramsey@arm.com> --- v3: - Refactor unused code to more relevant commits. - Add P2M print information - Formatting issues - Update commit message v2: - Seperate commit into multiple commits --- xen/arch/arm/arm64/mpu/p2m.c | 80 +++++++++++++++++++++++- xen/arch/arm/include/asm/arm64/sysregs.h | 4 ++ xen/arch/arm/include/asm/cpufeature.h | 13 +++- xen/arch/arm/include/asm/processor.h | 8 +++ 4 files changed, 101 insertions(+), 4 deletions(-) diff --git a/xen/arch/arm/arm64/mpu/p2m.c b/xen/arch/arm/arm64/mpu/p2m.c index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/arm/arm64/mpu/p2m.c +++ b/xen/arch/arm/arm64/mpu/p2m.c @@ -XXX,XX +XXX,XX @@ #include <xen/bug.h> #include <xen/init.h> +#include <xen/lib.h> #include <asm/p2m.h> void __init setup_virt_paging(void) { - BUG_ON("unimplemented"); + register_t vtcr_el2 = READ_SYSREG(VTCR_EL2); + register_t vstcr_el2 = READ_SYSREG(VSTCR_EL2); + + /* PA size */ + const unsigned int pa_range_info[] = {32, 36, 40, 42, 44, 48, 52, 0, + /* Invalid */}; + + /* + * Restrict "p2m_ipa_bits" if needed. As P2M table is always configured + * with IPA bits == PA bits, compare against "pabits". + */ + if ( pa_range_info[system_cpuinfo.mm64.pa_range] < p2m_ipa_bits ) + p2m_ipa_bits = pa_range_info[system_cpuinfo.mm64.pa_range]; + + /* + * The MSA and MSA_frac fields in the ID_AA64MMFR0_EL1 register identify the + * memory system configurations supported. In Armv8-R AArch64, the + * only permitted value for ID_AA64MMFR0_EL1.MSA is 0b1111. + */ + if ( system_cpuinfo.mm64.msa != MM64_MSA_PMSA_SUPPORT ) + goto fault; + + /* Permitted values for ID_AA64MMFR0_EL1.MSA_frac are 0b0001 and 0b0010. */ + if ( (system_cpuinfo.mm64.msa_frac != MM64_MSA_FRAC_PMSA_SUPPORT) && + (system_cpuinfo.mm64.msa_frac != MM64_MSA_FRAC_VMSA_SUPPORT) ) + goto fault; + + /* Stage 1 EL1&0 translation regime uses PMSAv8 by default */ + vtcr_el2 &= ~VTCR_MSA; + + /* + * Clear VTCR_EL2.NSA bit to configure non-secure stage 2 translation output + * address space to access the Secure PA space as Armv8r only implements + * secure state. + */ + vtcr_el2 &= ~VTCR_NSA; + + /* + * cpuinfo sanitization makes sure we support 16bits VMID only if all cores + * are supporting it. + * + * Set the VS bit only if 16 bit VIMD is supported. + */ + if ( system_cpuinfo.mm64.vmid_bits == MM64_VMID_16_BITS_SUPPORT ) + { + vtcr_el2 |= VTCR_VS; + max_vmid = MAX_VMID_16_BIT; + } + else + vtcr_el2 &= ~VTCR_VS; + + p2m_vmid_allocator_init(); + + WRITE_SYSREG(vtcr_el2, VTCR_EL2); + + /* + * VSTCR_EL2.SA defines secure stage 2 translation output address space. + * To make sure that all stage 2 translations for the Secure PA space access + * the Secure PA space, we keep SA bit as 0. + * + * VSTCR_EL2.SC is NS check enable bit. To make sure that Stage 2 NS + * configuration is checked against stage 1 NS configuration in EL1&0 + * translation regime for the given address, and generates a fault if they + * are different, we set SC bit 1. + */ + vstcr_el2 &= ~VSTCR_EL2_SA; + vstcr_el2 |= VSTCR_EL2_SC; + WRITE_SYSREG(vstcr_el2, VSTCR_EL2); + + printk("P2M: %d-bit IPA with %d-bit PA and %d-bit VMID\n", + p2m_ipa_bits, + pa_range_info[system_cpuinfo.mm64.pa_range], + ( MAX_VMID == MAX_VMID_16_BIT ) ? 16 : 8); + + return; + + fault: + panic("Hardware with no PMSAv8-64 support in any translation regime\n"); } /* diff --git a/xen/arch/arm/include/asm/arm64/sysregs.h b/xen/arch/arm/include/asm/arm64/sysregs.h index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/arm/include/asm/arm64/sysregs.h +++ b/xen/arch/arm/include/asm/arm64/sysregs.h @@ -XXX,XX +XXX,XX @@ #define ZCR_ELx_LEN_SIZE 9 #define ZCR_ELx_LEN_MASK 0x1ff +/* Virtualization Secure Translation Control Register */ +#define VSTCR_EL2_SA (_AC(0x1,U) << 30) +#define VSTCR_EL2_SC (_AC(0x1,U) << 20) + #ifdef CONFIG_MPU /* * The Armv8-R AArch64 architecture always executes code in Secure diff --git a/xen/arch/arm/include/asm/cpufeature.h b/xen/arch/arm/include/asm/cpufeature.h index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/arm/include/asm/cpufeature.h +++ b/xen/arch/arm/include/asm/cpufeature.h @@ -XXX,XX +XXX,XX @@ struct cpuinfo_arm { unsigned long tgranule_16K:4; unsigned long tgranule_64K:4; unsigned long tgranule_4K:4; +#ifdef CONFIG_MPU + unsigned long __res0:16; + unsigned long msa:4; + unsigned long msa_frac:4; + unsigned long __res1:8; +#else unsigned long tgranule_16k_2:4; unsigned long tgranule_64k_2:4; unsigned long tgranule_4k_2:4; @@ -XXX,XX +XXX,XX @@ struct cpuinfo_arm { unsigned long __res0:8; unsigned long fgt:4; unsigned long ecv:4; +#endif /* MMFR1 */ unsigned long hafdbs:4; @@ -XXX,XX +XXX,XX @@ struct cpuinfo_arm { unsigned long xnx:4; unsigned long twed:4; unsigned long ets:4; - unsigned long __res1:4; + unsigned long __res2:4; unsigned long afp:4; - unsigned long __res2:12; + unsigned long __res3:12; unsigned long ecbhb:4; /* MMFR2 */ - unsigned long __res3:64; + unsigned long __res4:64; }; } mm64; diff --git a/xen/arch/arm/include/asm/processor.h b/xen/arch/arm/include/asm/processor.h index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/arm/include/asm/processor.h +++ b/xen/arch/arm/include/asm/processor.h @@ -XXX,XX +XXX,XX @@ #define VTCR_RES1 (_AC(1,UL)<<31) +#define VTCR_MSA (_AC(0x1,UL)<<31) +#define VTCR_NSA (_AC(0x1,UL)<<30) + /* HCPTR Hyp. Coprocessor Trap Register */ #define HCPTR_TAM ((_AC(1,U)<<30)) #define HCPTR_TTA ((_AC(1,U)<<20)) /* Trap trace registers */ @@ -XXX,XX +XXX,XX @@ #define MM64_VMID_16_BITS_SUPPORT 0x2 #endif +#define MM64_MSA_PMSA_SUPPORT 0xf +#define MM64_MSA_FRAC_NONE_SUPPORT 0x0 +#define MM64_MSA_FRAC_PMSA_SUPPORT 0x1 +#define MM64_MSA_FRAC_VMSA_SUPPORT 0x2 + #ifndef __ASSEMBLER__ extern register_t __cpu_logical_map[]; -- 2.34.1
From: Harry Ramsey <harry.ramsey@arm.com> Add a new device tree property `v8r_el1_msa` to select the MSA (memory system architecture) at EL1 i.e. MPU(default) or MMU. Signed-off-by: Harry Ramsey <harry.ramsey@arm.com> Signed-off-by: Luca Fancellu <luca.fancellu@arm.com> --- v3: - Improve commit message and device tree property description - Remove macro protection - Remove unused function is_mpu_domain - Code formatting --- docs/misc/arm/device-tree/booting.txt | 12 ++++++++++++ xen/arch/arm/dom0less-build.c | 24 ++++++++++++++++++++++++ xen/arch/arm/domain.c | 4 ++++ xen/arch/arm/include/asm/domain.h | 7 +++++++ xen/arch/arm/include/asm/mpu.h | 5 +++++ xen/arch/arm/mpu/arm32/mm.c | 5 +++++ xen/arch/arm/mpu/arm64/mm.c | 5 +++++ xen/include/public/arch-arm.h | 2 ++ 8 files changed, 64 insertions(+) diff --git a/docs/misc/arm/device-tree/booting.txt b/docs/misc/arm/device-tree/booting.txt index XXXXXXX..XXXXXXX 100644 --- a/docs/misc/arm/device-tree/booting.txt +++ b/docs/misc/arm/device-tree/booting.txt @@ -XXX,XX +XXX,XX @@ with the following properties: Should be used together with scmi-smc-passthrough Xen command line option. +- v8r_el1_msa + + A string property specifying whether, on Armv8-R systems, a domain + should use PMSAv8 (MPU) at EL1 or VMSAv8 (MMU) at EL1. + + - "mmu" + Enables VMSAv8 at EL1. This requires hardware support and is only + optionally available on AArch64. + + - "mpu" + Enables PMSAv8 at EL1. (Default) + Under the "xen,domain" compatible node, one or more sub-nodes are present for the DomU kernel and ramdisk. diff --git a/xen/arch/arm/dom0less-build.c b/xen/arch/arm/dom0less-build.c index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/arm/dom0less-build.c +++ b/xen/arch/arm/dom0less-build.c @@ -XXX,XX +XXX,XX @@ #include <asm/domain_build.h> #include <asm/firmware/sci.h> #include <asm/grant_table.h> +#include <asm/mpu.h> #include <asm/setup.h> #ifdef CONFIG_VGICV2 @@ -XXX,XX +XXX,XX @@ int __init arch_parse_dom0less_node(struct dt_device_node *node, struct xen_domctl_createdomain *d_cfg = &bd->create_cfg; unsigned int flags = bd->create_flags; uint32_t val; + const char *v8r_el1_msa; d_cfg->arch.gic_version = XEN_DOMCTL_CONFIG_GIC_NATIVE; d_cfg->flags |= XEN_DOMCTL_CDF_hvm | XEN_DOMCTL_CDF_hap; @@ -XXX,XX +XXX,XX @@ int __init arch_parse_dom0less_node(struct dt_device_node *node, if ( domu_dt_sci_parse(node, d_cfg) ) panic("Error getting SCI configuration\n"); + if (!dt_property_read_string(node, "v8r_el1_msa", &v8r_el1_msa)) + { +#ifdef CONFIG_MPU + if ( !strcmp(v8r_el1_msa, "mmu") ) + { + if ( !has_v8r_vmsa_support() ) + panic("Platform does not support VMSA at EL1 (v8r_el1_msa)\n"); + d_cfg->arch.v8r_el1_msa = MPU_EL1_VMSA; + } + else if ( !strcmp(v8r_el1_msa, "mpu") ) + { + d_cfg->arch.v8r_el1_msa = MPU_EL1_PMSA; + if ( !(flags & CDF_staticmem) || !(flags & CDF_directmap) ) + panic("PMSA is not valid for domain without static allocation and direct map (v8r_el1_msa)\n"); + } + else + panic("Invalid device tree option for v8r_el1_msa\n"); +#else + panic("'v8r_el1_msa' property found, but CONFIG_MPU not selected\n"); +#endif + } + if ( !dt_property_read_u32(node, "nr_spis", &d_cfg->arch.nr_spis) ) { int vpl011_virq = GUEST_VPL011_SPI; diff --git a/xen/arch/arm/domain.c b/xen/arch/arm/domain.c index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/arm/domain.c +++ b/xen/arch/arm/domain.c @@ -XXX,XX +XXX,XX @@ int arch_domain_create(struct domain *d, if ( (rc = sci_domain_init(d, config)) != 0 ) goto fail; +#ifdef CONFIG_MPU + d->arch.v8r_el1_msa = config->arch.v8r_el1_msa; +#endif + return 0; fail: diff --git a/xen/arch/arm/include/asm/domain.h b/xen/arch/arm/include/asm/domain.h index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/arm/include/asm/domain.h +++ b/xen/arch/arm/include/asm/domain.h @@ -XXX,XX +XXX,XX @@ enum domain_type { #define is_64bit_domain(d) (0) #endif +#define MPU_EL1_PMSA 0 +#define MPU_EL1_VMSA 1 + /* * Is the domain using the host memory layout? * @@ -XXX,XX +XXX,XX @@ struct arch_domain #endif struct resume_info resume_ctx; + +#ifdef CONFIG_MPU + uint8_t v8r_el1_msa; +#endif } __cacheline_aligned; struct arch_vcpu diff --git a/xen/arch/arm/include/asm/mpu.h b/xen/arch/arm/include/asm/mpu.h index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/arm/include/asm/mpu.h +++ b/xen/arch/arm/include/asm/mpu.h @@ -XXX,XX +XXX,XX @@ #ifndef __ASSEMBLER__ +/* + * Utility function to determine if an Armv8-R processor supports VMSA. + */ +bool has_v8r_vmsa_support(void); + /* * Set base address of MPU protection region. * diff --git a/xen/arch/arm/mpu/arm32/mm.c b/xen/arch/arm/mpu/arm32/mm.c index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/arm/mpu/arm32/mm.c +++ b/xen/arch/arm/mpu/arm32/mm.c @@ -XXX,XX +XXX,XX @@ break; \ } +bool has_v8r_vmsa_support(void) +{ + return false; +} + /* * Armv8-R supports direct access and indirect access to the MPU regions through * registers: diff --git a/xen/arch/arm/mpu/arm64/mm.c b/xen/arch/arm/mpu/arm64/mm.c index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/arm/mpu/arm64/mm.c +++ b/xen/arch/arm/mpu/arm64/mm.c @@ -XXX,XX +XXX,XX @@ break; \ } +bool has_v8r_vmsa_support(void) +{ + return system_cpuinfo.mm64.msa_frac == MM64_MSA_FRAC_VMSA_SUPPORT; +} + /* * Armv8-R supports direct access and indirect access to the MPU regions through * registers: diff --git a/xen/include/public/arch-arm.h b/xen/include/public/arch-arm.h index XXXXXXX..XXXXXXX 100644 --- a/xen/include/public/arch-arm.h +++ b/xen/include/public/arch-arm.h @@ -XXX,XX +XXX,XX @@ struct xen_arch_domainconfig { uint32_t clock_frequency; /* IN */ uint8_t arm_sci_type; + /* IN */ + uint8_t v8r_el1_msa; }; #endif /* __XEN__ || __XEN_TOOLS__ */ -- 2.34.1
From: Harry Ramsey <harry.ramsey@arm.com> Implement `p2m_alloc_table`, `p2m_init` and `p2m_final_teardown` for MPU systems. Signed-off-by: Harry Ramsey <harry.ramsey@arm.com> Signed-off-by: Luca Fancellu <luca.fancellu@arm.com> --- v3: - Check for alloc_xenheap_pages allocation - Clear additional page allocated for ARM64 - Add check for INVALID_VCPU_ID - Remove unnecessary function generate_vsctlr - Code formatting fixes --- xen/arch/arm/include/asm/arm32/mpu.h | 2 + xen/arch/arm/include/asm/arm64/mpu.h | 2 + xen/arch/arm/include/asm/mpu/p2m.h | 12 +++++ xen/arch/arm/include/asm/p2m.h | 5 ++ xen/arch/arm/mpu/p2m.c | 78 ++++++++++++++++++++++++++-- 5 files changed, 96 insertions(+), 3 deletions(-) diff --git a/xen/arch/arm/include/asm/arm32/mpu.h b/xen/arch/arm/include/asm/arm32/mpu.h index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/arm/include/asm/arm32/mpu.h +++ b/xen/arch/arm/include/asm/arm32/mpu.h @@ -XXX,XX +XXX,XX @@ */ #define MPU_REGION_RES0 0x0 +#define VSCTLR_VMID_SHIFT 16 + /* Hypervisor Protection Region Base Address Register */ typedef union { struct { diff --git a/xen/arch/arm/include/asm/arm64/mpu.h b/xen/arch/arm/include/asm/arm64/mpu.h index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/arm/include/asm/arm64/mpu.h +++ b/xen/arch/arm/include/asm/arm64/mpu.h @@ -XXX,XX +XXX,XX @@ #define MPU_REGION_RES0 (0xFFFFULL << 48) +#define VSCTLR_VMID_SHIFT 48 + /* Protection Region Base Address Register */ typedef union { struct __packed { diff --git a/xen/arch/arm/include/asm/mpu/p2m.h b/xen/arch/arm/include/asm/mpu/p2m.h index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/arm/include/asm/mpu/p2m.h +++ b/xen/arch/arm/include/asm/mpu/p2m.h @@ -XXX,XX +XXX,XX @@ #ifndef __ARM_MPU_P2M_H__ #define __ARM_MPU_P2M_H__ +#include <xen/bitops.h> +#include <xen/macros.h> +#include <xen/page-size.h> + struct p2m_domain; +/* + * 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) + * and 16 bytes on AArch32 (requiring one 4KB page). + */ +#define P2M_ROOT_PAGES DIV_ROUND_UP(255 * sizeof(pr_t), PAGE_SIZE) +#define P2M_ROOT_ORDER get_count_order(P2M_ROOT_PAGES) + static inline void p2m_clear_root_pages(struct p2m_domain *p2m) {} static inline void p2m_tlb_flush_sync(struct p2m_domain *p2m) {} diff --git a/xen/arch/arm/include/asm/p2m.h b/xen/arch/arm/include/asm/p2m.h index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/arm/include/asm/p2m.h +++ b/xen/arch/arm/include/asm/p2m.h @@ -XXX,XX +XXX,XX @@ struct p2m_domain { /* Current VMID in use */ uint16_t vmid; +#ifdef CONFIG_MMU /* Current Translation Table Base Register for the p2m */ uint64_t vttbr; +#else + /* Current Virtualization System Control Register for the p2m */ + register_t vsctlr; +#endif /* Highest guest frame that's ever been mapped in the p2m */ gfn_t max_mapped_gfn; diff --git a/xen/arch/arm/mpu/p2m.c b/xen/arch/arm/mpu/p2m.c index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/arm/mpu/p2m.c +++ b/xen/arch/arm/mpu/p2m.c @@ -XXX,XX +XXX,XX @@ void p2m_dump_info(struct domain *d) BUG_ON("unimplemented"); } +static int p2m_alloc_table(struct domain *d) +{ + struct p2m_domain *p2m = p2m_get_hostp2m(d); + void *table = alloc_xenheap_pages(P2M_ROOT_ORDER, 0); + + if ( !table ) + { + printk(XENLOG_G_ERR "%pd: p2m: unable to allocate P2M MPU mapping table\n", + d); + return -ENOMEM; + } + + p2m->root = virt_to_page(table); + + for (int i = 0; i < P2M_ROOT_PAGES; i++) + clear_page(page_to_virt(p2m->root + i)); + + return 0; +} + int p2m_init(struct domain *d) { - BUG_ON("unimplemented"); - return -EINVAL; + struct p2m_domain *p2m = p2m_get_hostp2m(d); + int rc = 0; + unsigned int cpu; + + rwlock_init(&p2m->lock); + + p2m->vmid = INVALID_VMID; + p2m->max_mapped_gfn = _gfn(0); + p2m->lowest_mapped_gfn = _gfn(ULONG_MAX); + + p2m->default_access = p2m_access_rwx; + /* mem_access is NOT supported in MPU system. */ + p2m->mem_access_enabled = false; + + /* Ensure that the type chosen is large enough for MAX_VIRT_CPUS. */ + BUILD_BUG_ON((1 << (sizeof(p2m->last_vcpu_ran[0]) * 8)) < MAX_VIRT_CPUS); + BUILD_BUG_ON((1 << (sizeof(p2m->last_vcpu_ran[0]) * 8)) < INVALID_VCPU_ID); + + for_each_possible_cpu(cpu) + p2m->last_vcpu_ran[cpu] = INVALID_VCPU_ID; + + /* + * "Trivial" initialization is now complete. Set the backpointer so that + * p2m_teardown() and related functions know to do something. + */ + p2m->domain = d; + + rc = p2m_alloc_vmid(d); + if ( rc ) + return rc; + + p2m->vsctlr = ((register_t)p2m->vmid << VSCTLR_VMID_SHIFT); + + rc = p2m_alloc_table(d); + if ( rc ) + { + p2m_free_vmid(d); + return rc; + } + + return 0; } void p2m_save_state(struct vcpu *p) @@ -XXX,XX +XXX,XX @@ void p2m_restore_state(struct vcpu *n) void p2m_final_teardown(struct domain *d) { - BUG_ON("unimplemented"); + struct p2m_domain *p2m = p2m_get_hostp2m(d); + + /* p2m not actually initialized */ + if ( !p2m->domain ) + return; + + if ( p2m->root ) + free_xenheap_pages(page_to_virt(p2m->root), P2M_ROOT_ORDER); + + p2m->root = NULL; + + p2m_free_vmid(d); + + p2m->domain = NULL; } bool p2m_resolve_translation_fault(struct domain *d, gfn_t gfn) -- 2.34.1
This series continues to further the ongoing work to introduce support for MPU systems in Xen. The patches in this series aim to implement MPU specific p2m functions. This serie is based on staging 99912d346009fda1e7fb1510c9501fbab17e92a0. Harry Ramsey (2): arm/mpu: Introduce `v8r_el1_msa` device tree property for domains arm/mpu: Implement p2m tables Penny Zheng (1): arm/mpu: implement setup_virt_paging for MPU systems docs/misc/arm/device-tree/booting.txt | 14 ++++ xen/arch/arm/arm64/mpu/p2m.c | 80 ++++++++++++++++++++- xen/arch/arm/dom0less-build.c | 3 + xen/arch/arm/domain.c | 4 ++ xen/arch/arm/include/asm/arm32/mpu.h | 2 + xen/arch/arm/include/asm/arm64/mpu.h | 2 + xen/arch/arm/include/asm/arm64/sysregs.h | 4 ++ xen/arch/arm/include/asm/cpufeature.h | 13 +++- xen/arch/arm/include/asm/domain.h | 4 ++ xen/arch/arm/include/asm/domain_build.h | 8 +++ xen/arch/arm/include/asm/mmu/domain-build.h | 46 ++++++++++++ xen/arch/arm/include/asm/mpu.h | 5 ++ xen/arch/arm/include/asm/mpu/domain-build.h | 27 +++++++ xen/arch/arm/include/asm/mpu/p2m.h | 12 ++++ xen/arch/arm/include/asm/p2m.h | 5 ++ xen/arch/arm/include/asm/processor.h | 8 +++ xen/arch/arm/mpu/Makefile | 1 + xen/arch/arm/mpu/arm32/mm.c | 5 ++ xen/arch/arm/mpu/arm64/mm.c | 5 ++ xen/arch/arm/mpu/domain-build.c | 76 ++++++++++++++++++++ xen/arch/arm/mpu/p2m.c | 78 +++++++++++++++++++- xen/include/public/arch-arm.h | 7 ++ xen/include/public/domctl.h | 4 +- 23 files changed, 404 insertions(+), 9 deletions(-) create mode 100644 xen/arch/arm/include/asm/mmu/domain-build.h create mode 100644 xen/arch/arm/include/asm/mpu/domain-build.h create mode 100644 xen/arch/arm/mpu/domain-build.c -- 2.34.1
From: Penny Zheng <Penny.Zheng@arm.com> Implement setup_virt_paging for AArch64 MPU systems, taking care of stage 2 address translation regime, IPA bits, supported VMID length configuration and VTCR_EL2/VSTCR_EL2 register programming. Implement also the Armv8-R specific changes to ID_AA64MMFR0_EL1, related to the supported memory system architecture (PMSA/VMSA) and check that when MPU is built, the underlying HW is compatible with PMSA. By default MPU at EL2 and EL1 is required. Signed-off-by: Penny Zheng <penny.zheng@arm.com> Signed-off-by: Wei Chen <wei.chen@arm.com> Signed-off-by: Luca Fancellu <luca.fancellu@arm.com> Signed-off-by: Hari Limaye <hari.limaye@arm.com> Signed-off-by: Harry Ramsey <harry.ramsey@arm.com> --- v4: - Fixed typo in the comments - Fixed typo in the commit title and message - moved p2m_vmid_allocator_init() after write of VTCR_EL2 - Fixed printf format specifier %d -> %u v3: - Refactor unused code to more relevant commits. - Add P2M print information - Formatting issues - Update commit message v2: - Separate commit into multiple commits --- xen/arch/arm/arm64/mpu/p2m.c | 80 +++++++++++++++++++++++- xen/arch/arm/include/asm/arm64/sysregs.h | 4 ++ xen/arch/arm/include/asm/cpufeature.h | 13 +++- xen/arch/arm/include/asm/processor.h | 8 +++ 4 files changed, 101 insertions(+), 4 deletions(-) diff --git a/xen/arch/arm/arm64/mpu/p2m.c b/xen/arch/arm/arm64/mpu/p2m.c index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/arm/arm64/mpu/p2m.c +++ b/xen/arch/arm/arm64/mpu/p2m.c @@ -XXX,XX +XXX,XX @@ #include <xen/bug.h> #include <xen/init.h> +#include <xen/lib.h> #include <asm/p2m.h> void __init setup_virt_paging(void) { - BUG_ON("unimplemented"); + register_t vtcr_el2 = READ_SYSREG(VTCR_EL2); + register_t vstcr_el2 = READ_SYSREG(VSTCR_EL2); + + /* PA size */ + const unsigned int pa_range_info[] = {32, 36, 40, 42, 44, 48, 52, 0, + /* Invalid */}; + + /* + * Restrict "p2m_ipa_bits" if needed. As P2M table is always configured + * with IPA bits == PA bits, compare against PA size. + */ + if ( pa_range_info[system_cpuinfo.mm64.pa_range] < p2m_ipa_bits ) + p2m_ipa_bits = pa_range_info[system_cpuinfo.mm64.pa_range]; + + /* + * The MSA and MSA_frac fields in the ID_AA64MMFR0_EL1 register identify the + * memory system configurations supported. In Armv8-R AArch64, the + * only permitted value for ID_AA64MMFR0_EL1.MSA is 0b1111. + */ + if ( system_cpuinfo.mm64.msa != MM64_MSA_PMSA_SUPPORT ) + goto fault; + + /* Permitted values for ID_AA64MMFR0_EL1.MSA_frac are 0b0001 and 0b0010. */ + if ( (system_cpuinfo.mm64.msa_frac != MM64_MSA_FRAC_PMSA_SUPPORT) && + (system_cpuinfo.mm64.msa_frac != MM64_MSA_FRAC_VMSA_SUPPORT) ) + goto fault; + + /* Stage 1 EL1&0 translation regime uses PMSAv8 by default */ + vtcr_el2 &= ~VTCR_MSA; + + /* + * Clear VTCR_EL2.NSA bit to configure non-secure stage 2 translation output + * address space to access the Secure PA space as Armv8-R only implements + * secure state. + */ + vtcr_el2 &= ~VTCR_NSA; + + /* + * cpuinfo sanitization makes sure we support 16-bits VMID only if all cores + * are supporting it. + * + * Set the VS bit only if 16 bit VMID is supported. + */ + if ( system_cpuinfo.mm64.vmid_bits == MM64_VMID_16_BITS_SUPPORT ) + { + vtcr_el2 |= VTCR_VS; + max_vmid = MAX_VMID_16_BIT; + } + else + vtcr_el2 &= ~VTCR_VS; + + WRITE_SYSREG(vtcr_el2, VTCR_EL2); + + p2m_vmid_allocator_init(); + + /* + * VSTCR_EL2.SA defines secure stage 2 translation output address space. + * To make sure that all stage 2 translations for the Secure PA space access + * the Secure PA space, we keep SA bit as 0. + * + * VSTCR_EL2.SC is NS check enable bit. To make sure that Stage 2 NS + * configuration is checked against stage 1 NS configuration in EL1&0 + * translation regime for the given address, and generates a fault if they + * are different, we set SC bit 1. + */ + vstcr_el2 &= ~VSTCR_EL2_SA; + vstcr_el2 |= VSTCR_EL2_SC; + WRITE_SYSREG(vstcr_el2, VSTCR_EL2); + + printk("P2M: %u-bit IPA with %u-bit PA and %u-bit VMID\n", + p2m_ipa_bits, + pa_range_info[system_cpuinfo.mm64.pa_range], + ( MAX_VMID == MAX_VMID_16_BIT ) ? 16 : 8); + + return; + + fault: + panic("Hardware with no PMSAv8-64 support in any translation regime\n"); } /* diff --git a/xen/arch/arm/include/asm/arm64/sysregs.h b/xen/arch/arm/include/asm/arm64/sysregs.h index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/arm/include/asm/arm64/sysregs.h +++ b/xen/arch/arm/include/asm/arm64/sysregs.h @@ -XXX,XX +XXX,XX @@ #define ZCR_ELx_LEN_SIZE 9 #define ZCR_ELx_LEN_MASK 0x1ff +/* Virtualization Secure Translation Control Register */ +#define VSTCR_EL2_SA (_AC(0x1,U) << 30) +#define VSTCR_EL2_SC (_AC(0x1,U) << 20) + #ifdef CONFIG_MPU /* * The Armv8-R AArch64 architecture always executes code in Secure diff --git a/xen/arch/arm/include/asm/cpufeature.h b/xen/arch/arm/include/asm/cpufeature.h index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/arm/include/asm/cpufeature.h +++ b/xen/arch/arm/include/asm/cpufeature.h @@ -XXX,XX +XXX,XX @@ struct cpuinfo_arm { unsigned long tgranule_16K:4; unsigned long tgranule_64K:4; unsigned long tgranule_4K:4; +#ifdef CONFIG_MPU + unsigned long __res0:16; + unsigned long msa:4; + unsigned long msa_frac:4; + unsigned long __res1:8; +#else unsigned long tgranule_16k_2:4; unsigned long tgranule_64k_2:4; unsigned long tgranule_4k_2:4; @@ -XXX,XX +XXX,XX @@ struct cpuinfo_arm { unsigned long __res0:8; unsigned long fgt:4; unsigned long ecv:4; +#endif /* MMFR1 */ unsigned long hafdbs:4; @@ -XXX,XX +XXX,XX @@ struct cpuinfo_arm { unsigned long xnx:4; unsigned long twed:4; unsigned long ets:4; - unsigned long __res1:4; + unsigned long __res2:4; unsigned long afp:4; - unsigned long __res2:12; + unsigned long __res3:12; unsigned long ecbhb:4; /* MMFR2 */ - unsigned long __res3:64; + unsigned long __res4:64; }; } mm64; diff --git a/xen/arch/arm/include/asm/processor.h b/xen/arch/arm/include/asm/processor.h index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/arm/include/asm/processor.h +++ b/xen/arch/arm/include/asm/processor.h @@ -XXX,XX +XXX,XX @@ #define VTCR_RES1 (_AC(1,UL)<<31) +#define VTCR_MSA (_AC(0x1,UL)<<31) +#define VTCR_NSA (_AC(0x1,UL)<<30) + /* HCPTR Hyp. Coprocessor Trap Register */ #define HCPTR_TAM ((_AC(1,U)<<30)) #define HCPTR_TTA ((_AC(1,U)<<20)) /* Trap trace registers */ @@ -XXX,XX +XXX,XX @@ #define MM64_VMID_16_BITS_SUPPORT 0x2 #endif +#define MM64_MSA_PMSA_SUPPORT 0xf +#define MM64_MSA_FRAC_NONE_SUPPORT 0x0 +#define MM64_MSA_FRAC_PMSA_SUPPORT 0x1 +#define MM64_MSA_FRAC_VMSA_SUPPORT 0x2 + #ifndef __ASSEMBLER__ extern register_t __cpu_logical_map[]; -- 2.34.1
From: Harry Ramsey <harry.ramsey@arm.com> Add a new device tree property `v8r_el1_msa` to select the MSA (memory system architecture) at EL1 for Armv8-R architecture: MPU or MMU, the former is the default if the property is not passed. The check and setting of this new input parameter for the guest configuration is performed in arch_domain_create() instead of the more usual arch_sanitise_domain_config() because the former has access to the Xen internal guest creation flags which are required to ensure PMSA can work (domain requires static allocation and direct mapping). The property is valid only when used on MPU systems and will result in a panic on MMU ones. Bumped XEN_DOMCTL_INTERFACE_VERSION because of the new domctl input parameter. Signed-off-by: Harry Ramsey <harry.ramsey@arm.com> Signed-off-by: Luca Fancellu <luca.fancellu@arm.com> --- v4: - Rework the patch to have the v8r_el1_msa input parameter more enclosed in the Armv8-A (mmu)/Armv8-R (mpu) space. v3: - Improve commit message and device tree property description - Remove macro protection - Remove unused function is_mpu_domain - Code formatting --- docs/misc/arm/device-tree/booting.txt | 14 ++++ xen/arch/arm/dom0less-build.c | 3 + xen/arch/arm/domain.c | 4 ++ xen/arch/arm/include/asm/domain.h | 4 ++ xen/arch/arm/include/asm/domain_build.h | 8 +++ xen/arch/arm/include/asm/mmu/domain-build.h | 46 +++++++++++++ xen/arch/arm/include/asm/mpu.h | 5 ++ xen/arch/arm/include/asm/mpu/domain-build.h | 27 ++++++++ xen/arch/arm/mpu/Makefile | 1 + xen/arch/arm/mpu/arm32/mm.c | 5 ++ xen/arch/arm/mpu/arm64/mm.c | 5 ++ xen/arch/arm/mpu/domain-build.c | 76 +++++++++++++++++++++ xen/include/public/arch-arm.h | 7 ++ xen/include/public/domctl.h | 4 +- 14 files changed, 207 insertions(+), 2 deletions(-) create mode 100644 xen/arch/arm/include/asm/mmu/domain-build.h create mode 100644 xen/arch/arm/include/asm/mpu/domain-build.h create mode 100644 xen/arch/arm/mpu/domain-build.c diff --git a/docs/misc/arm/device-tree/booting.txt b/docs/misc/arm/device-tree/booting.txt index XXXXXXX..XXXXXXX 100644 --- a/docs/misc/arm/device-tree/booting.txt +++ b/docs/misc/arm/device-tree/booting.txt @@ -XXX,XX +XXX,XX @@ with the following properties: Should be used together with scmi-smc-passthrough Xen command line option. +- v8r_el1_msa + + A string property specifying whether, on Armv8-R systems, a domain + should use PMSAv8 (MPU) at EL1 or VMSAv8 (MMU) at EL1. + + - "mmu" + Enables VMSAv8 at EL1. This requires hardware support and is only + optionally available on AArch64. + + - "mpu" + Enables PMSAv8 at EL1. This is the default behaviour when the property is + not passed. This configuration requires static allocation (xen,static-mem) + and direct mapping (direct-map). + Under the "xen,domain" compatible node, one or more sub-nodes are present for the DomU kernel and ramdisk. diff --git a/xen/arch/arm/dom0less-build.c b/xen/arch/arm/dom0less-build.c index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/arm/dom0less-build.c +++ b/xen/arch/arm/dom0less-build.c @@ -XXX,XX +XXX,XX @@ #include <asm/domain_build.h> #include <asm/firmware/sci.h> #include <asm/grant_table.h> +#include <asm/mpu.h> #include <asm/setup.h> #ifdef CONFIG_VGICV2 @@ -XXX,XX +XXX,XX @@ int __init arch_parse_dom0less_node(struct dt_device_node *node, if ( domu_dt_sci_parse(node, d_cfg) ) panic("Error getting SCI configuration\n"); + arch_dt_v8r_el1_msa_parse(node, d_cfg); + if ( !dt_property_read_u32(node, "nr_spis", &d_cfg->arch.nr_spis) ) { int vpl011_virq = GUEST_VPL011_SPI; diff --git a/xen/arch/arm/domain.c b/xen/arch/arm/domain.c index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/arm/domain.c +++ b/xen/arch/arm/domain.c @@ -XXX,XX +XXX,XX @@ #include <asm/cpuerrata.h> #include <asm/cpufeature.h> #include <asm/current.h> +#include <asm/domain_build.h> #include <asm/event.h> #include <asm/gic.h> #include <asm/guest_atomics.h> @@ -XXX,XX +XXX,XX @@ int arch_domain_create(struct domain *d, if ( (rc = sci_domain_init(d, config)) != 0 ) goto fail; + if ( (rc = arch_set_v8r_el1_msa(d, config, flags)) != 0 ) + goto fail; + return 0; fail: diff --git a/xen/arch/arm/include/asm/domain.h b/xen/arch/arm/include/asm/domain.h index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/arm/include/asm/domain.h +++ b/xen/arch/arm/include/asm/domain.h @@ -XXX,XX +XXX,XX @@ struct arch_domain #endif struct resume_info resume_ctx; + +#ifdef CONFIG_MPU + uint8_t v8r_el1_msa; +#endif } __cacheline_aligned; struct arch_vcpu diff --git a/xen/arch/arm/include/asm/domain_build.h b/xen/arch/arm/include/asm/domain_build.h index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/arm/include/asm/domain_build.h +++ b/xen/arch/arm/include/asm/domain_build.h @@ -XXX,XX +XXX,XX @@ #include <xen/fdt-kernel.h> #include <xen/sched.h> +#if defined(CONFIG_MMU) +#include <asm/mmu/domain-build.h> +#elif defined(CONFIG_MPU) +#include <asm/mpu/domain-build.h> +#else +# error "Unknown memory management layout" +#endif + typedef __be32 gic_interrupt_t[3]; int make_psci_node(void *fdt); void evtchn_allocate(struct domain *d); diff --git a/xen/arch/arm/include/asm/mmu/domain-build.h b/xen/arch/arm/include/asm/mmu/domain-build.h new file mode 100644 index XXXXXXX..XXXXXXX --- /dev/null +++ b/xen/arch/arm/include/asm/mmu/domain-build.h @@ -XXX,XX +XXX,XX @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#ifndef __ARM_MMU_DOMAIN_BUILD_H__ +#define __ARM_MMU_DOMAIN_BUILD_H__ + +#include <xen/device_tree.h> +#include <xen/errno.h> +#include <xen/sched.h> +#include <xen/types.h> +#include <public/domctl.h> + +static inline +void arch_dt_v8r_el1_msa_parse(struct dt_device_node *node, + struct xen_domctl_createdomain *d_cfg) +{ + const char *v8r_el1_msa; + + if ( !dt_property_read_string(node, "v8r_el1_msa", &v8r_el1_msa) ) + panic("'v8r_el1_msa' property found, but CONFIG_MPU not selected\n"); +} + +static inline +int arch_set_v8r_el1_msa(struct domain *d, + const struct xen_domctl_createdomain *config, + unsigned int flags) +{ + if ( config->arch.v8r_el1_msa ) + { + dprintk(XENLOG_INFO, + "arch.v8r_el1_msa set, but CONFIG_MPU not selected\n"); + return -EINVAL; + } + + return 0; +} + +#endif /* __ARM_MMU_DOMAIN_BUILD_H__ */ + +/* + * Local variables: + * mode: C + * c-file-style: "BSD" + * c-basic-offset: 4 + * indent-tabs-mode: nil + * End: + */ diff --git a/xen/arch/arm/include/asm/mpu.h b/xen/arch/arm/include/asm/mpu.h index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/arm/include/asm/mpu.h +++ b/xen/arch/arm/include/asm/mpu.h @@ -XXX,XX +XXX,XX @@ #ifndef __ASSEMBLER__ +/* + * Utility function to determine if an Armv8-R processor supports VMSA. + */ +bool has_v8r_vmsa_support(void); + /* * Set base address of MPU protection region. * diff --git a/xen/arch/arm/include/asm/mpu/domain-build.h b/xen/arch/arm/include/asm/mpu/domain-build.h new file mode 100644 index XXXXXXX..XXXXXXX --- /dev/null +++ b/xen/arch/arm/include/asm/mpu/domain-build.h @@ -XXX,XX +XXX,XX @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#ifndef __ARM_MPU_DOMAIN_BUILD_H__ +#define __ARM_MPU_DOMAIN_BUILD_H__ + +#include <xen/device_tree.h> +#include <xen/sched.h> +#include <xen/types.h> +#include <public/domctl.h> + +void arch_dt_v8r_el1_msa_parse(struct dt_device_node *node, + struct xen_domctl_createdomain *d_cfg); + +int arch_set_v8r_el1_msa(struct domain *d, + const struct xen_domctl_createdomain *config, + unsigned int flags); + +#endif /* __ARM_MPU_DOMAIN_BUILD_H__ */ + +/* + * Local variables: + * mode: C + * c-file-style: "BSD" + * c-basic-offset: 4 + * indent-tabs-mode: nil + * End: + */ diff --git a/xen/arch/arm/mpu/Makefile b/xen/arch/arm/mpu/Makefile index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/arm/mpu/Makefile +++ b/xen/arch/arm/mpu/Makefile @@ -XXX,XX +XXX,XX @@ obj-$(CONFIG_ARM_32) += arm32/ obj-$(CONFIG_ARM_64) += arm64/ +obj-y += domain-build.o obj-y += domain-page.o obj-y += mm.o obj-y += p2m.o diff --git a/xen/arch/arm/mpu/arm32/mm.c b/xen/arch/arm/mpu/arm32/mm.c index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/arm/mpu/arm32/mm.c +++ b/xen/arch/arm/mpu/arm32/mm.c @@ -XXX,XX +XXX,XX @@ break; \ } +bool has_v8r_vmsa_support(void) +{ + return false; +} + /* * Armv8-R supports direct access and indirect access to the MPU regions through * registers: diff --git a/xen/arch/arm/mpu/arm64/mm.c b/xen/arch/arm/mpu/arm64/mm.c index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/arm/mpu/arm64/mm.c +++ b/xen/arch/arm/mpu/arm64/mm.c @@ -XXX,XX +XXX,XX @@ break; \ } +bool has_v8r_vmsa_support(void) +{ + return system_cpuinfo.mm64.msa_frac == MM64_MSA_FRAC_VMSA_SUPPORT; +} + /* * Armv8-R supports direct access and indirect access to the MPU regions through * registers: diff --git a/xen/arch/arm/mpu/domain-build.c b/xen/arch/arm/mpu/domain-build.c new file mode 100644 index XXXXXXX..XXXXXXX --- /dev/null +++ b/xen/arch/arm/mpu/domain-build.c @@ -XXX,XX +XXX,XX @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#include <xen/device_tree.h> +#include <xen/domain.h> +#include <xen/errno.h> +#include <xen/init.h> +#include <xen/types.h> +#include <xen/sched.h> +#include <asm/mpu.h> +#include <asm/mpu/domain-build.h> +#include <public/arch-arm.h> +#include <public/domctl.h> + +void __init arch_dt_v8r_el1_msa_parse(struct dt_device_node *node, + struct xen_domctl_createdomain *d_cfg) +{ + const char *v8r_el1_msa; + + d_cfg->arch.v8r_el1_msa = XEN_DOMCTL_CONFIG_ARM_V8R_EL1_MSA_NONE; + + if ( !dt_property_read_string(node, "v8r_el1_msa", &v8r_el1_msa) ) + { + if ( !strcmp(v8r_el1_msa, "mmu") ) + d_cfg->arch.v8r_el1_msa = XEN_DOMCTL_CONFIG_ARM_V8R_EL1_MSA_VMSA; + else if ( !strcmp(v8r_el1_msa, "mpu") ) + d_cfg->arch.v8r_el1_msa = XEN_DOMCTL_CONFIG_ARM_V8R_EL1_MSA_PMSA; + else + panic("Invalid device tree option for v8r_el1_msa\n"); + } +} + +int arch_set_v8r_el1_msa(struct domain *d, + const struct xen_domctl_createdomain *config, + unsigned int flags) +{ + switch ( config->arch.v8r_el1_msa ) + { + case XEN_DOMCTL_CONFIG_ARM_V8R_EL1_MSA_NONE: + fallthrough; + case XEN_DOMCTL_CONFIG_ARM_V8R_EL1_MSA_PMSA: + if ( !(flags & CDF_staticmem) || !(flags & CDF_directmap) ) + { + dprintk(XENLOG_INFO, + "PMSA is not valid for domain without static allocation and direct map (v8r_el1_msa)\n"); + return -EINVAL; + } + break; + + case XEN_DOMCTL_CONFIG_ARM_V8R_EL1_MSA_VMSA: + if ( !has_v8r_vmsa_support() ) + { + dprintk(XENLOG_INFO, + "Platform does not support VMSA at EL1 (v8r_el1_msa)\n"); + return -EINVAL; + } + break; + + default: + dprintk(XENLOG_INFO, "Unsupported arch.v8r_el1_msa value (%u)\n", + config->arch.v8r_el1_msa); + return -EINVAL; + } + + d->arch.v8r_el1_msa = config->arch.v8r_el1_msa; + + return 0; +} + +/* + * Local variables: + * mode: C + * c-file-style: "BSD" + * c-basic-offset: 4 + * indent-tabs-mode: nil + * End: + */ diff --git a/xen/include/public/arch-arm.h b/xen/include/public/arch-arm.h index XXXXXXX..XXXXXXX 100644 --- a/xen/include/public/arch-arm.h +++ b/xen/include/public/arch-arm.h @@ -XXX,XX +XXX,XX @@ DEFINE_XEN_GUEST_HANDLE(vcpu_guest_context_t); #define XEN_DOMCTL_CONFIG_ARM_SCI_NONE 0 #define XEN_DOMCTL_CONFIG_ARM_SCI_SCMI_SMC 1 +#define XEN_DOMCTL_CONFIG_ARM_V8R_EL1_MSA_NONE 0 +#define XEN_DOMCTL_CONFIG_ARM_V8R_EL1_MSA_PMSA 1 +#define XEN_DOMCTL_CONFIG_ARM_V8R_EL1_MSA_VMSA 2 + struct xen_arch_domainconfig { /* IN/OUT */ uint8_t gic_version; @@ -XXX,XX +XXX,XX @@ struct xen_arch_domainconfig { uint32_t clock_frequency; /* IN */ uint8_t arm_sci_type; + /* IN */ + uint8_t v8r_el1_msa; + uint16_t pad; }; #endif /* __XEN__ || __XEN_TOOLS__ */ diff --git a/xen/include/public/domctl.h b/xen/include/public/domctl.h index XXXXXXX..XXXXXXX 100644 --- a/xen/include/public/domctl.h +++ b/xen/include/public/domctl.h @@ -XXX,XX +XXX,XX @@ * fields) don't require a change of the version. * Stable ops are NOT covered by XEN_DOMCTL_INTERFACE_VERSION! * - * Last version bump: Xen 4.19 + * Last version bump: Xen 4.22 */ -#define XEN_DOMCTL_INTERFACE_VERSION 0x00000017 +#define XEN_DOMCTL_INTERFACE_VERSION 0x00000018 /* * NB. xen_domctl.domain is an IN/OUT parameter for this operation. -- 2.34.1
From: Harry Ramsey <harry.ramsey@arm.com> Implement `p2m_alloc_table`, `p2m_init` and `p2m_final_teardown` for MPU systems. Signed-off-by: Harry Ramsey <harry.ramsey@arm.com> Signed-off-by: Luca Fancellu <luca.fancellu@arm.com> --- v4: - no changes v3: - Check for alloc_xenheap_pages allocation - Clear additional page allocated for ARM64 - Add check for INVALID_VCPU_ID - Remove unnecessary function generate_vsctlr - Code formatting fixes --- xen/arch/arm/include/asm/arm32/mpu.h | 2 + xen/arch/arm/include/asm/arm64/mpu.h | 2 + xen/arch/arm/include/asm/mpu/p2m.h | 12 +++++ xen/arch/arm/include/asm/p2m.h | 5 ++ xen/arch/arm/mpu/p2m.c | 78 ++++++++++++++++++++++++++-- 5 files changed, 96 insertions(+), 3 deletions(-) diff --git a/xen/arch/arm/include/asm/arm32/mpu.h b/xen/arch/arm/include/asm/arm32/mpu.h index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/arm/include/asm/arm32/mpu.h +++ b/xen/arch/arm/include/asm/arm32/mpu.h @@ -XXX,XX +XXX,XX @@ */ #define MPU_REGION_RES0 0x0 +#define VSCTLR_VMID_SHIFT 16 + /* Hypervisor Protection Region Base Address Register */ typedef union { struct { diff --git a/xen/arch/arm/include/asm/arm64/mpu.h b/xen/arch/arm/include/asm/arm64/mpu.h index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/arm/include/asm/arm64/mpu.h +++ b/xen/arch/arm/include/asm/arm64/mpu.h @@ -XXX,XX +XXX,XX @@ #define MPU_REGION_RES0 (0xFFFFULL << 48) +#define VSCTLR_VMID_SHIFT 48 + /* Protection Region Base Address Register */ typedef union { struct __packed { diff --git a/xen/arch/arm/include/asm/mpu/p2m.h b/xen/arch/arm/include/asm/mpu/p2m.h index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/arm/include/asm/mpu/p2m.h +++ b/xen/arch/arm/include/asm/mpu/p2m.h @@ -XXX,XX +XXX,XX @@ #ifndef __ARM_MPU_P2M_H__ #define __ARM_MPU_P2M_H__ +#include <xen/bitops.h> +#include <xen/macros.h> +#include <xen/page-size.h> + struct p2m_domain; +/* + * 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) + * and 16 bytes on AArch32 (requiring one 4KB page). + */ +#define P2M_ROOT_PAGES DIV_ROUND_UP(255 * sizeof(pr_t), PAGE_SIZE) +#define P2M_ROOT_ORDER get_count_order(P2M_ROOT_PAGES) + static inline void p2m_clear_root_pages(struct p2m_domain *p2m) {} static inline void p2m_tlb_flush_sync(struct p2m_domain *p2m) {} diff --git a/xen/arch/arm/include/asm/p2m.h b/xen/arch/arm/include/asm/p2m.h index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/arm/include/asm/p2m.h +++ b/xen/arch/arm/include/asm/p2m.h @@ -XXX,XX +XXX,XX @@ struct p2m_domain { /* Current VMID in use */ uint16_t vmid; +#ifdef CONFIG_MMU /* Current Translation Table Base Register for the p2m */ uint64_t vttbr; +#else + /* Current Virtualization System Control Register for the p2m */ + register_t vsctlr; +#endif /* Highest guest frame that's ever been mapped in the p2m */ gfn_t max_mapped_gfn; diff --git a/xen/arch/arm/mpu/p2m.c b/xen/arch/arm/mpu/p2m.c index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/arm/mpu/p2m.c +++ b/xen/arch/arm/mpu/p2m.c @@ -XXX,XX +XXX,XX @@ void p2m_dump_info(struct domain *d) BUG_ON("unimplemented"); } +static int p2m_alloc_table(struct domain *d) +{ + struct p2m_domain *p2m = p2m_get_hostp2m(d); + void *table = alloc_xenheap_pages(P2M_ROOT_ORDER, 0); + + if ( !table ) + { + printk(XENLOG_G_ERR "%pd: p2m: unable to allocate P2M MPU mapping table\n", + d); + return -ENOMEM; + } + + p2m->root = virt_to_page(table); + + for (int i = 0; i < P2M_ROOT_PAGES; i++) + clear_page(page_to_virt(p2m->root + i)); + + return 0; +} + int p2m_init(struct domain *d) { - BUG_ON("unimplemented"); - return -EINVAL; + struct p2m_domain *p2m = p2m_get_hostp2m(d); + int rc = 0; + unsigned int cpu; + + rwlock_init(&p2m->lock); + + p2m->vmid = INVALID_VMID; + p2m->max_mapped_gfn = _gfn(0); + p2m->lowest_mapped_gfn = _gfn(ULONG_MAX); + + p2m->default_access = p2m_access_rwx; + /* mem_access is NOT supported in MPU system. */ + p2m->mem_access_enabled = false; + + /* Ensure that the type chosen is large enough for MAX_VIRT_CPUS. */ + BUILD_BUG_ON((1 << (sizeof(p2m->last_vcpu_ran[0]) * 8)) < MAX_VIRT_CPUS); + BUILD_BUG_ON((1 << (sizeof(p2m->last_vcpu_ran[0]) * 8)) < INVALID_VCPU_ID); + + for_each_possible_cpu(cpu) + p2m->last_vcpu_ran[cpu] = INVALID_VCPU_ID; + + /* + * "Trivial" initialization is now complete. Set the backpointer so that + * p2m_teardown() and related functions know to do something. + */ + p2m->domain = d; + + rc = p2m_alloc_vmid(d); + if ( rc ) + return rc; + + p2m->vsctlr = ((register_t)p2m->vmid << VSCTLR_VMID_SHIFT); + + rc = p2m_alloc_table(d); + if ( rc ) + { + p2m_free_vmid(d); + return rc; + } + + return 0; } void p2m_save_state(struct vcpu *p) @@ -XXX,XX +XXX,XX @@ void p2m_restore_state(struct vcpu *n) void p2m_final_teardown(struct domain *d) { - BUG_ON("unimplemented"); + struct p2m_domain *p2m = p2m_get_hostp2m(d); + + /* p2m not actually initialized */ + if ( !p2m->domain ) + return; + + if ( p2m->root ) + free_xenheap_pages(page_to_virt(p2m->root), P2M_ROOT_ORDER); + + p2m->root = NULL; + + p2m_free_vmid(d); + + p2m->domain = NULL; } bool p2m_resolve_translation_fault(struct domain *d, gfn_t gfn) -- 2.34.1