|
[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 |