diff --git a/xen/arch/arm/include/asm/arm32/mpu.h b/xen/arch/arm/include/asm/arm32/mpu.h index 2cf0f8cbac..d565230f84 100644 --- a/xen/arch/arm/include/asm/arm32/mpu.h +++ b/xen/arch/arm/include/asm/arm32/mpu.h @@ -11,6 +11,8 @@ */ #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 4f694190a8..8b86a03fee 100644 --- a/xen/arch/arm/include/asm/arm64/mpu.h +++ b/xen/arch/arm/include/asm/arm64/mpu.h @@ -7,6 +7,8 @@ #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 e46d9e757a..1484c75b55 100644 --- a/xen/arch/arm/include/asm/mpu/p2m.h +++ b/xen/arch/arm/include/asm/mpu/p2m.h @@ -3,8 +3,16 @@ #ifndef __ARM_MPU_P2M_H__ #define __ARM_MPU_P2M_H__ +#include +#include +#include +#include + struct p2m_domain; +#define P2M_ROOT_PAGES DIV_ROUND_UP(MAX_MPU_REGION_NR * 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 23500713a1..4a4913716b 100644 --- a/xen/arch/arm/include/asm/p2m.h +++ b/xen/arch/arm/include/asm/p2m.h @@ -51,8 +51,13 @@ 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 f7fb58ab6a..f3ca8a4ab3 100644 --- a/xen/arch/arm/mpu/p2m.c +++ b/xen/arch/arm/mpu/p2m.c @@ -28,10 +28,63 @@ 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); + unsigned int i; + + 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 ( i = 0; i < P2M_ROOT_PAGES; i++ ) + clear_page(table + (i * PAGE_SIZE)); + + 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 on 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); + + return p2m_alloc_table(d); } void p2m_save_state(struct vcpu *p) @@ -46,7 +99,20 @@ 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)