[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Xen-devel] [RFC PATCH] xen/arm: Add 4-level page table for stage 2 translation
From: Vijaya Kumar K <Vijaya.Kumar@xxxxxxxxxxxxxxxxxx> To support 48-bit Physical Address support, add 4-level page tables for stage 2 translation.By default stage 1 and stage 2 translation at EL2 are with 4-levels Configure TCR_EL2.IPS and VTCR_EL2.PS based on platform supported PA range at runtime Signed-off-by: Vijaya Kumar K <Vijaya.Kumar@xxxxxxxxxxxxxxxxxx> --- xen/arch/arm/arm64/head.S | 7 ++- xen/arch/arm/mm.c | 11 +++- xen/arch/arm/p2m.c | 132 ++++++++++++++++++++++++++++++++++----- xen/include/asm-arm/p2m.h | 5 +- xen/include/asm-arm/page.h | 117 ++++++++++++++++++++++++++++++---- xen/include/asm-arm/processor.h | 14 ++++- 6 files changed, 249 insertions(+), 37 deletions(-) diff --git a/xen/arch/arm/arm64/head.S b/xen/arch/arm/arm64/head.S index d151724..c0e0362 100644 --- a/xen/arch/arm/arm64/head.S +++ b/xen/arch/arm/arm64/head.S @@ -224,13 +224,16 @@ skip_bss: ldr x0, =MAIRVAL msr mair_el2, x0 + mrs x1, ID_AA64MMFR0_EL1 + /* Set up the HTCR: - * PASize -- 40 bits / 1TB + * PASize -- based on ID_AA64MMFR0_EL1.PARange value * Top byte is used * PT walks use Outer-Shareable accesses, * PT walks are write-back, write-allocate in both cache levels, * Full 64-bit address space goes through this table. */ - ldr x0, =0x80822500 + ldr x0, =TCR_VAL_40PA + bfi x0, x1, #16, #3 msr tcr_el2, x0 /* Set up the SCTLR_EL2: diff --git a/xen/arch/arm/mm.c b/xen/arch/arm/mm.c index 305879f..d577b23 100644 --- a/xen/arch/arm/mm.c +++ b/xen/arch/arm/mm.c @@ -382,13 +382,18 @@ void __cpuinit setup_virt_paging(void) /* SH0=00, ORGN0=IRGN0=01 * SL0=01 (Level-1) * ARVv7: T0SZ=(1)1000 = -8 (32-(-8) = 40 bit physical addresses) * ARMv8: T0SZ=01 1000 = 24 (64-24 = 40 bit physical addresses) * PS=010 == 40 bits */ #ifdef CONFIG_ARM_32 - WRITE_SYSREG32(0x80002558, VTCR_EL2); + WRITE_SYSREG32(VTCR_VAL, VTCR_EL2); #else - WRITE_SYSREG32(0x80022558, VTCR_EL2); + /* Change PS to 48 and T0SZ = 16 SL0 - 2 to take VA 48 bit */ + if ( current_cpu_data.mm64.pa_range == VTCR_PS_48BIT ) + WRITE_SYSREG32(VTCR_VAL_48PA, VTCR_EL2); + else + /* Consider by default 40 PA support for ARM64 */ + WRITE_SYSREG32(VTCR_VAL_40PA, VTCR_EL2); #endif isb(); } diff --git a/xen/arch/arm/p2m.c b/xen/arch/arm/p2m.c index d00c882..bdaab46 100644 --- a/xen/arch/arm/p2m.c +++ b/xen/arch/arm/p2m.c @@ -10,29 +10,38 @@ #include <asm/hardirq.h> #include <asm/page.h> +#ifdef CONFIG_ARM_64 +/* Zeroeth level is of 1 page size */ +#define P2M_FIRST_ORDER 0 +#else /* First level P2M is 2 consecutive pages */ #define P2M_FIRST_ORDER 1 +#endif #define P2M_FIRST_ENTRIES (LPAE_ENTRIES<<P2M_FIRST_ORDER) void dump_p2m_lookup(struct domain *d, paddr_t addr) { struct p2m_domain *p2m = &d->arch.p2m; - lpae_t *first; + lpae_t *lookup; printk("dom%d IPA 0x%"PRIpaddr"\n", d->domain_id, addr); +#ifdef CONFIG_ARM_64 + if ( zeroeth_linear_offset(addr) > LPAE_ENTRIES ) +#else if ( first_linear_offset(addr) > LPAE_ENTRIES ) +#endif { - printk("Cannot dump addresses in second of first level pages...\n"); + printk("Cannot dump addresses in second of first(ARM32)/zeroeth(ARM64) level pages...\n"); return; } printk("P2M @ %p mfn:0x%lx\n", - p2m->first_level, page_to_mfn(p2m->first_level)); + p2m->lookup_level, page_to_mfn(p2m->lookup_level)); - first = __map_domain_page(p2m->first_level); - dump_pt_walk(first, addr); - unmap_domain_page(first); + lookup = __map_domain_page(p2m->lookup_level); + dump_pt_walk(lookup, addr); + unmap_domain_page(lookup); } void p2m_load_VTTBR(struct domain *d) @@ -44,6 +53,20 @@ void p2m_load_VTTBR(struct domain *d) isb(); /* Ensure update is visible */ } +#ifdef CONFIG_ARM_64 +/* + * Map zeroeth level page that addr contains. + */ +static lpae_t *p2m_map_zeroeth(struct p2m_domain *p2m, paddr_t addr) +{ + if ( zeroeth_linear_offset(addr) >= LPAE_ENTRIES ) + return NULL; + + return __map_domain_page(p2m->lookup_level); +} + +#else + static int p2m_first_level_index(paddr_t addr) { /* @@ -64,10 +87,11 @@ static lpae_t *p2m_map_first(struct p2m_domain *p2m, paddr_t addr) if ( first_linear_offset(addr) >= P2M_FIRST_ENTRIES ) return NULL; - page = p2m->first_level + p2m_first_level_index(addr); + page = p2m->lookup_level + p2m_first_level_index(addr); return __map_domain_page(page); } +#endif /* * Lookup the MFN corresponding to a domain's PFN. @@ -79,6 +103,9 @@ paddr_t p2m_lookup(struct domain *d, paddr_t paddr, p2m_type_t *t) { struct p2m_domain *p2m = &d->arch.p2m; lpae_t pte, *first = NULL, *second = NULL, *third = NULL; +#ifdef CONFIG_ARM_64 + lpae_t *zeroeth = NULL; +#endif paddr_t maddr = INVALID_PADDR; p2m_type_t _t; @@ -89,9 +116,29 @@ paddr_t p2m_lookup(struct domain *d, paddr_t paddr, p2m_type_t *t) spin_lock(&p2m->lock); +#ifdef CONFIG_ARM_64 + zeroeth = p2m_map_zeroeth(p2m, paddr); + if ( !zeroeth ) + goto err; + + pte = zeroeth[zeroeth_table_offset(paddr)]; + /* Zeroeth level does not support block translation + * so pte.p2m.table should be always set. + * Just check for valid bit + */ + if ( !pte.p2m.valid ) + goto done; + +#else first = p2m_map_first(p2m, paddr); if ( !first ) goto err; +#endif + +#ifdef CONFIG_ARM_64 + /* Map first level table */ + first = map_domain_page(pte.p2m.base); +#endif pte = first[first_table_offset(paddr)]; if ( !pte.p2m.valid || !pte.p2m.table ) @@ -120,6 +167,9 @@ done: if (third) unmap_domain_page(third); if (second) unmap_domain_page(second); if (first) unmap_domain_page(first); +#ifdef CONFIG_ARM_64 + if (zeroeth) unmap_domain_page(zeroeth); +#endif err: spin_unlock(&p2m->lock); @@ -244,8 +294,14 @@ static int apply_p2m_changes(struct domain *d, struct p2m_domain *p2m = &d->arch.p2m; lpae_t *first = NULL, *second = NULL, *third = NULL; paddr_t addr; - unsigned long cur_first_page = ~0, - cur_first_offset = ~0, +#ifdef CONFIG_ARM_64 + lpae_t *zeroeth = NULL; + unsigned long cur_zeroeth_page = ~0, + cur_zeroeth_offset = ~0; +#else + unsigned long cur_first_page = ~0; +#endif + unsigned long cur_first_offset = ~0, cur_second_offset = ~0; unsigned long count = 0; unsigned int flush = 0; @@ -260,6 +316,37 @@ static int apply_p2m_changes(struct domain *d, addr = start_gpaddr; while ( addr < end_gpaddr ) { +#ifdef CONFIG_ARM_64 + /* Find zeoeth offset and Map zeroeth page */ + if ( cur_zeroeth_page != zeroeth_table_offset(addr) ) + { + if ( zeroeth ) unmap_domain_page(zeroeth); + zeroeth = p2m_map_zeroeth(p2m, addr); + if ( !zeroeth ) + { + rc = -EINVAL; + goto out; + } + cur_zeroeth_page = zeroeth_table_offset(addr); + } + + if ( !zeroeth[zeroeth_table_offset(addr)].p2m.valid ) + { + if ( !populate ) + { + addr = (addr + ZEROETH_SIZE) & ZEROETH_MASK; + continue; + } + rc = p2m_create_table(d, &zeroeth[zeroeth_table_offset(addr)]); + if ( rc < 0 ) + { + printk("p2m_populate_ram: L0 failed\n"); + goto out; + } + } + + BUG_ON(!zeroeth[zeroeth_table_offset(addr)].p2m.valid); +#else if ( cur_first_page != p2m_first_level_index(addr) ) { if ( first ) unmap_domain_page(first); @@ -271,7 +358,16 @@ static int apply_p2m_changes(struct domain *d, } cur_first_page = p2m_first_level_index(addr); } +#endif +#ifdef CONFIG_ARM_64 + if ( cur_zeroeth_offset != zeroeth_table_offset(addr) ) + { + if ( first ) unmap_domain_page(first); + first = map_domain_page(zeroeth[zeroeth_table_offset(addr)].p2m.base); + cur_zeroeth_offset = zeroeth_table_offset(addr); + } +#endif if ( !first[first_table_offset(addr)].p2m.valid ) { if ( !populate ) @@ -279,7 +375,6 @@ static int apply_p2m_changes(struct domain *d, addr = (addr + FIRST_SIZE) & FIRST_MASK; continue; } - rc = p2m_create_table(d, &first[first_table_offset(addr)]); if ( rc < 0 ) { @@ -287,7 +382,6 @@ static int apply_p2m_changes(struct domain *d, goto out; } } - BUG_ON(!first[first_table_offset(addr)].p2m.valid); if ( cur_first_offset != first_table_offset(addr) ) @@ -305,7 +399,6 @@ static int apply_p2m_changes(struct domain *d, addr = (addr + SECOND_SIZE) & SECOND_MASK; continue; } - rc = p2m_create_table(d, &second[second_table_offset(addr)]); if ( rc < 0 ) { printk("p2m_populate_ram: L2 failed\n"); @@ -435,6 +528,9 @@ out: if (third) unmap_domain_page(third); if (second) unmap_domain_page(second); if (first) unmap_domain_page(first); +#ifdef CONFIG_ARM_64 + if ( zeroeth ) unmap_domain_page(zeroeth); +#endif if ( d != current->domain ) p2m_load_VTTBR(current->domain); @@ -500,13 +596,15 @@ int p2m_alloc_table(struct domain *d) clear_page(p); unmap_domain_page(p); +#ifdef CONFIG_ARM_32 p = __map_domain_page(page + 1); clear_page(p); unmap_domain_page(p); +#endif - p2m->first_level = page; + p2m->lookup_level = page; - d->arch.vttbr = page_to_maddr(p2m->first_level) + d->arch.vttbr = page_to_maddr(p2m->lookup_level) | ((uint64_t)p2m->vmid&0xff)<<48; p2m_load_VTTBR(d); @@ -587,9 +685,9 @@ void p2m_teardown(struct domain *d) while ( (pg = page_list_remove_head(&p2m->pages)) ) free_domheap_page(pg); - free_domheap_pages(p2m->first_level, P2M_FIRST_ORDER); + free_domheap_pages(p2m->lookup_level, P2M_FIRST_ORDER); - p2m->first_level = NULL; + p2m->lookup_level = NULL; p2m_free_vmid(d); @@ -613,7 +711,7 @@ int p2m_init(struct domain *d) d->arch.vttbr = 0; - p2m->first_level = NULL; + p2m->lookup_level = NULL; p2m->max_mapped_gfn = 0; p2m->lowest_mapped_gfn = ULONG_MAX; diff --git a/xen/include/asm-arm/p2m.h b/xen/include/asm-arm/p2m.h index 3b39c45..3aa3623 100644 --- a/xen/include/asm-arm/p2m.h +++ b/xen/include/asm-arm/p2m.h @@ -13,8 +13,9 @@ struct p2m_domain { /* Pages used to construct the p2m */ struct page_list_head pages; - /* Root of p2m page tables, 2 contiguous pages */ - struct page_info *first_level; + /* ARMv7: Root of p2m page tables, 2 contiguous pages */ + /* ARMv8: Look up table is zeroeth level */ + struct page_info *lookup_level; /* Current VMID in use */ uint8_t vmid; diff --git a/xen/include/asm-arm/page.h b/xen/include/asm-arm/page.h index 905beb8..8477206 100644 --- a/xen/include/asm-arm/page.h +++ b/xen/include/asm-arm/page.h @@ -6,12 +6,13 @@ #include <public/xen.h> #include <asm/processor.h> +#ifdef CONFIG_ARM_64 +#define PADDR_BITS 48 +#else #define PADDR_BITS 40 +#endif #define PADDR_MASK ((1ULL << PADDR_BITS)-1) -#define VADDR_BITS 32 -#define VADDR_MASK (~0UL) - /* Shareability values for the LPAE entries */ #define LPAE_SH_NON_SHAREABLE 0x0 #define LPAE_SH_UNPREDICTALE 0x1 @@ -40,6 +41,94 @@ #define MAIR1VAL 0xff000004 #define MAIRVAL (MAIR0VAL|MAIR1VAL<<32) +/* + * VTCR register configuration for stage 2 translation + */ +#define VTCR_TOSZ_40BIT 24 +#define VTCR_TOSZ_48BIT 16 +#define VTCR_SL0_0 0x2 +#define VTCR_SL0_1 0x1 +#define VTCR_SL0_2 0x0 +#define VTCR_SL0_SHIFT 6 +#define VTCR_IRGN0_NC 0x0 +#define VTCR_IRGN0_WBWA 0x1 +#define VTCR_IRGN0_WT 0x2 +#define VTCR_IRGN0_WB 0x3 +#define VTCR_IRGN0_SHIFT 8 +#define VTCR_ORGN0_NC 0x0 +#define VTCR_ORGN0_WBWA 0x1 +#define VTCR_ORGN0_WT 0x2 +#define VTCR_ORGN0_WB 0x3 +#define VTCR_ORGN0_SHIFT 10 +#define VTCR_SH0_NS 0x0 +#define VTCR_SH0_OS 0x2 +#define VTCR_SH0_IS 0x3 +#define VTCR_SH0_SHIFT 12 +#define VTCR_TG0_4K 0x0 +#define VTCR_TG0_64K 0x1 +#define VTCR_TG0_SHIFT 14 +#define VTCR_PS_32BIT 0x0 +#define VTCR_PS_40BIT 0x2 +#define VTCR_PS_48BIT 0x5 +#define VTCR_PS_SHIFT 16 + +#ifdef CONFIG_ARM_64 +/* 48 bit VA to 48 bit PA */ +#define VTCR_VAL_48PA ((VTCR_TOSZ_48BIT) | \ + (VTCR_SL0_0 << VTCR_SL0_SHIFT) | \ + (VTCR_IRGN0_WBWA << VTCR_IRGN0_SHIFT) | \ + (VTCR_ORGN0_WBWA << VTCR_ORGN0_SHIFT) | \ + (VTCR_SH0_OS << VTCR_SH0_SHIFT) | \ + (VTCR_TG0_4K << VTCR_TG0_SHIFT) | \ + (VTCR_PS_48BIT << VTCR_PS_SHIFT)) + +/* 40 bit VA to 40 bit PA */ +#define VTCR_VAL_40PA ((VTCR_TOSZ_40BIT) | \ + (VTCR_SL0_1 << VTCR_SL0_SHIFT) | \ + (VTCR_IRGN0_WBWA << VTCR_IRGN0_SHIFT) | \ + (VTCR_ORGN0_WBWA << VTCR_ORGN0_SHIFT) | \ + (VTCR_SH0_OS << VTCR_SH0_SHIFT) | \ + (VTCR_TG0_4K << VTCR_TG0_SHIFT) | \ + (VTCR_PS_40BIT << VTCR_PS_SHIFT)) +#else +/* 40 bit VA to 32 bit PA */ +#define VTCR_VAL ((VTCR_TOSZ_40BIT) | \ + (VTCR_SL0_1 << VTCR_SL0_SHIFT) | \ + (VTCR_IRGN0_WBWA << VTCR_IRGN0_SHIFT) | \ + (VTCR_ORGN0_WBWA << VTCR_ORGN0_SHIFT) | \ + (VTCR_SH0_OS << VTCR_SH0_SHIFT) | \ + (VTCR_TG0_4K << VTCR_TG0_SHIFT) | \ + (VTCR_PS_32BIT << VTCR_PS_SHIFT)) +#endif + +/* TCR register configuration for Xen Stage 1 translation*/ + +#define TCR_TBI_USE_TBYTE 0x0 +#define TCR_TBI_SHIFT 20 + +#ifdef CONFIG_ARM_64 +/* + * 48 bit VA to 40 bit PA + * if platform supports 48 bit PA update runtime in head.S + */ +#define TCR_VAL_40PA ((VTCR_TOSZ_48BIT) | \ + (VTCR_IRGN0_WBWA << VTCR_IRGN0_SHIFT) | \ + (VTCR_ORGN0_WBWA << VTCR_ORGN0_SHIFT) | \ + (VTCR_SH0_OS << VTCR_SH0_SHIFT) | \ + (VTCR_TG0_4K << VTCR_TG0_SHIFT) | \ + (VTCR_PS_40BIT << VTCR_PS_SHIFT) | \ + (TCR_TBI_USE_TBYTE << TCR_TBI_SHIFT)) +#endif + /* * Attribute Indexes. * @@ -109,9 +198,10 @@ typedef struct __packed { unsigned long af:1; /* Access Flag */ unsigned long ng:1; /* Not-Global */ - /* The base address must be appropriately aligned for Block entries */ - unsigned long base:28; /* Base address of block or next table */ - unsigned long sbz:12; /* Must be zero */ + /* The base address must be appropriately aligned for Block entries. + * base now can hold upto 36 bits to support 48 PA */ + unsigned long base:36; /* Base address of block or next table */ + unsigned long sbz:4; /* Must be zero */ /* These seven bits are only used in Block entries and are ignored * in Table entries. */ @@ -144,9 +234,10 @@ typedef struct __packed { unsigned long af:1; /* Access Flag */ unsigned long sbz4:1; - /* The base address must be appropriately aligned for Block entries */ - unsigned long base:28; /* Base address of block or next table */ - unsigned long sbz3:12; + /* The base address must be appropriately aligned for Block entries. + * base now can hold upto 36 bits to support 48 PA */ + unsigned long base:36; /* Base address of block or next table */ + unsigned long sbz3:4; /* These seven bits are only used in Block entries and are ignored * in Table entries. */ @@ -169,10 +260,12 @@ typedef struct __packed { unsigned long pad2:10; - /* The base address must be appropriately aligned for Block entries */ - unsigned long base:28; /* Base address of block or next table */ + /* The base address must be appropriately aligned for Block entries. + * base now can hold upto 36 bits to support 48 PA */ + unsigned long base:36; /* Base address of block or next table */ - unsigned long pad1:24; + //unsigned long pad1:24; + unsigned long pad1:16; } lpae_walk_t; typedef union { diff --git a/xen/include/asm-arm/processor.h b/xen/include/asm-arm/processor.h index 06e638f..1355d81 100644 --- a/xen/include/asm-arm/processor.h +++ b/xen/include/asm-arm/processor.h @@ -173,9 +173,21 @@ struct cpuinfo_arm { uint64_t bits[2]; } aux64; - struct { + union { uint64_t bits[2]; + struct { + unsigned long pa_range:4; + unsigned long asid_bits:4; + unsigned long bigend:4; + unsigned long secure_ns:4; + unsigned long bigend_el0:4; + unsigned long tgranule_16K:4; + unsigned long tgranule_64K:4; + unsigned long tgranule_4K:4; + unsigned long __res0:32; + }; } mm64; + struct { uint64_t bits[2]; -- 1.7.9.5 _______________________________________________ Xen-devel mailing list Xen-devel@xxxxxxxxxxxxx http://lists.xen.org/xen-devel
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |