[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] Re: [Xen-devel] [PATCH V2 3/4] arm: allocate per-PCPU domheap pagetable pages
At 11:19 +0100 on 23 Apr (1366715994), Ian Campbell wrote: > The domheap mappings are supposed to be per-PCPU. Therefore xen_pgtable > becomes a per-PCPU variable and we allocate and setup the page tables for each > secondary PCPU just before we tell it to come up. > > Each secondary PCPU starts out on the boot page table but switches to its own > page tables ASAP. > > The boot PCPU uses the boot pagetables as its own. > > Signed-off-by: Ian Campbell <ian.campbell@xxxxxxxxxx> > --- > v2: Coding style fixes. > Use DOMHEAP_SECOND_PAGES instead of "2" > Flush the secondary CPU's pagetables on CPU0 when we create/write them not > on the secondary CPU. > --- > xen/arch/arm/mm.c | 137 > +++++++++++++++++++++++++++++++++++++----- > xen/arch/arm/smpboot.c | 6 ++ > xen/include/asm-arm/config.h | 4 + > xen/include/asm-arm/mm.h | 4 +- > 4 files changed, 135 insertions(+), 16 deletions(-) > > diff --git a/xen/arch/arm/mm.c b/xen/arch/arm/mm.c > index 3cb852b..58ce4e1 100644 > --- a/xen/arch/arm/mm.c > +++ b/xen/arch/arm/mm.c > @@ -39,22 +39,47 @@ > > struct domain *dom_xen, *dom_io, *dom_cow; > > -/* Static start-of-day pagetables that we use before the allocators are up */ > -/* boot_pgtable == root of the trie (zeroeth level on 64-bit, first on > 32-bit) */ > +/* Static start-of-day pagetables that we use before the > + * allocators are up. These go on to become the boot CPUs real pagetables. ^'s > + */ > lpae_t boot_pgtable[LPAE_ENTRIES] __attribute__((__aligned__(4096))); > #ifdef CONFIG_ARM_64 > lpae_t boot_first[LPAE_ENTRIES] __attribute__((__aligned__(4096))); > #endif > -/* N.B. The second-level table is 4 contiguous pages long, and covers > - * all addresses from 0 to 0xffffffff. Offsets into it are calculated > - * with second_linear_offset(), not second_table_offset(). */ > + > +/* > + * xen_pgtable and xen_dommap are per-PCPU and are allocated before > + * bringing up each CPU. On 64-bit a first level table is also allocated. > + * > + * xen_second, xen_fixmap and xen_xenmap are shared between all PCPUS. s/PCPUS/PCPUs/ > + */ > + > +/* Per-CPU pagetable pages */ > +/* xen_pgtable == root of the trie (zeroeth level on 64-bit, first on > 32-bit) */ > +static DEFINE_PER_CPU(lpae_t *, xen_pgtable); > +/* xen_dommap == pages used by map_domain_page, these pages contain > + * the second level pagetables which mapp the domheap region > + * DOMHEAP_VIRT_START...DOMHEAP_VIRT_END in 2MB chunks. */ > +static DEFINE_PER_CPU(lpae_t *, xen_dommap); > + > +/* Common pagetable leaves */ > +/* Second level page tables. > + * > + * The second-level table is 2 contiguous pages long, and covers all > + * addresses from 0 to 0x7fffffff. Can we keep the comment about using second_linear_offset to access xen_second? > + * > + * Addresses 0x80000000 to 0xffffffff are covered by the per-cpu > + * xen_domheap mappings described above. However we allocate 4 pages > + * here for use in the boot page tables and the second two pages > + * become the boot CPUs xen_dommap pages. > + */ > lpae_t xen_second[LPAE_ENTRIES*4] __attribute__((__aligned__(4096*4))); > +/* First level page table used for fixmap */ > lpae_t xen_fixmap[LPAE_ENTRIES] __attribute__((__aligned__(4096))); > +/* First level page table used to map Xen itself with the XN bit set > + * as appropriate. */ > static lpae_t xen_xenmap[LPAE_ENTRIES] __attribute__((__aligned__(4096))); > > -/* boot_pgtable becomes the boot processors pagetable, eventually this will > - * become a per-cpu variable */ > -#define xen_pgtable boot_pgtable > > /* Non-boot CPUs use this to find the correct pagetables. */ > uint64_t boot_ttbr; > @@ -107,12 +132,17 @@ done: > void dump_hyp_walk(vaddr_t addr) > { > uint64_t ttbr = READ_SYSREG64(TTBR0_EL2); > + lpae_t *pgtable = this_cpu(xen_pgtable); > > - printk("Walking Hypervisor VA 0x%"PRIvaddr" via TTBR 0x%016"PRIx64"\n", > - addr, ttbr); > + printk("Walking Hypervisor VA 0x%"PRIvaddr" " > + "on CPU%d via TTBR 0x%016"PRIx64"\n", > + addr, smp_processor_id(), ttbr); > > - BUG_ON( (lpae_t *)(unsigned long)(ttbr - phys_offset) != xen_pgtable ); > - dump_pt_walk(xen_pgtable, addr); > + if ( smp_processor_id() == 0 ) > + BUG_ON( (lpae_t *)(unsigned long)(ttbr - phys_offset) != pgtable ); > + else > + BUG_ON( virt_to_maddr(pgtable) != ttbr ); > + dump_pt_walk(pgtable, addr); > } > > /* Map a 4k page in a fixmap entry */ > @@ -138,7 +168,7 @@ void clear_fixmap(unsigned map) > void *map_domain_page(unsigned long mfn) > { > unsigned long flags; > - lpae_t *map = xen_second + second_linear_offset(DOMHEAP_VIRT_START); > + lpae_t *map = this_cpu(xen_dommap); > unsigned long slot_mfn = mfn & ~LPAE_ENTRY_MASK; > vaddr_t va; > lpae_t pte; > @@ -204,7 +234,7 @@ void *map_domain_page(unsigned long mfn) > void unmap_domain_page(const void *va) > { > unsigned long flags; > - lpae_t *map = xen_second + second_linear_offset(DOMHEAP_VIRT_START); > + lpae_t *map = this_cpu(xen_dommap); > int slot = ((unsigned long) va - DOMHEAP_VIRT_START) >> SECOND_SHIFT; > > local_irq_save(flags); > @@ -219,7 +249,7 @@ void unmap_domain_page(const void *va) > > unsigned long domain_page_map_to_mfn(const void *va) > { > - lpae_t *map = xen_second + second_linear_offset(DOMHEAP_VIRT_START); > + lpae_t *map = this_cpu(xen_dommap); > int slot = ((unsigned long) va - DOMHEAP_VIRT_START) >> SECOND_SHIFT; > unsigned long offset = ((unsigned long)va>>THIRD_SHIFT) & > LPAE_ENTRY_MASK; > > @@ -362,11 +392,88 @@ void __init setup_pagetables(unsigned long > boot_phys_offset, paddr_t xen_paddr) > WRITE_SYSREG32(READ_SYSREG32(SCTLR_EL2) | SCTLR_WXN, SCTLR_EL2); > /* Flush everything after setting WXN bit. */ > flush_xen_text_tlb(); > + > + per_cpu(xen_pgtable, 0) = boot_pgtable; > + per_cpu(xen_dommap, 0) = xen_second + > + second_linear_offset(DOMHEAP_VIRT_START); > + > + /* Some of these slots may have been used during start of day and/or > + * relocation. Make sure they are clear now. */ > + memset(this_cpu(xen_dommap), 0, DOMHEAP_SECOND_PAGES*PAGE_SIZE); > + flush_xen_dcache_va_range(this_cpu(xen_dommap), > + DOMHEAP_SECOND_PAGES*PAGE_SIZE); > +} > + > +int init_secondary_pagetables(int cpu) > +{ > + lpae_t *root, *first, *domheap, pte; > + int i; > + > + root = alloc_xenheap_page(); > +#ifdef CONFIG_ARM_64 > + first = alloc_xenheap_page(); > +#else > + first = root; /* root == first level on 32-bit 3-level trie */ > +#endif > + domheap = > alloc_xenheap_pages(get_order_from_pages(DOMHEAP_SECOND_PAGES), 0); > + > + if ( root == NULL || domheap == NULL || first == NULL ) > + { > + printk("Not enough free memory for secondary CPU%d pagetables\n", > cpu); > + free_xenheap_pages(domheap, > get_order_from_pages(DOMHEAP_SECOND_PAGES)); > +#ifdef CONFIG_ARM_64 > + free_xenheap_page(first); > +#endif > + free_xenheap_page(root); > + return -ENOMEM; > + } > + > + /* Initialise root pagetable from root of boot tables */ > + memcpy(root, boot_pgtable, PAGE_SIZE); > + > +#ifdef CONFIG_ARM_64 > + /* Initialise first pagetable from first level of boot tables, and > + * hook into the new root. */ > + memcpy(first, boot_first, PAGE_SIZE); > + pte = mfn_to_xen_entry(virt_to_mfn(first)); > + pte.pt.table = 1; > + write_pte(root, pte); > +#endif > + > + /* Ensure the domheap has no stray mappings */ > + memset(domheap, 0, DOMHEAP_SECOND_PAGES*PAGE_SIZE); > + > + /* Update the first level mapping to reference the local CPUs > + * domheap mapping pages. */ > + for ( i = 0; i < DOMHEAP_SECOND_PAGES; i++ ) > + { > + pte = mfn_to_xen_entry(virt_to_mfn(domheap+i*LPAE_ENTRIES)); > + pte.pt.table = 1; > + > write_pte(&first[first_table_offset(DOMHEAP_VIRT_START+i*FIRST_SIZE)], pte); > + } > + > + flush_xen_dcache_va_range(root, PAGE_SIZE); > + flush_xen_dcache_va_range(domheap, DOMHEAP_SECOND_PAGES*PAGE_SIZE); Don't we need to flush 'first' as well? > + > + per_cpu(xen_pgtable, cpu) = root; > + per_cpu(xen_dommap, cpu) = domheap; > + > + return 0; > } > > /* MMU setup for secondary CPUS (which already have paging enabled) */ > void __cpuinit mmu_init_secondary_cpu(void) > { > + uint64_t ttbr; > + > + /* Change to this CPUs pagetables */ > + flush_xen_text_tlb(); > + > + ttbr = (uintptr_t) virt_to_maddr(this_cpu(xen_pgtable)); > + WRITE_SYSREG64(ttbr, TTBR0_EL2); isb() here, to make sure the CP write completes? > + dsb(); /* Ensure visibility of HTTBR update */ > + flush_xen_text_tlb(); > + > /* From now on, no mapping may be both writable and executable. */ > WRITE_SYSREG32(READ_SYSREG32(SCTLR_EL2) | SCTLR_WXN, SCTLR_EL2); > flush_xen_text_tlb(); > diff --git a/xen/arch/arm/smpboot.c b/xen/arch/arm/smpboot.c > index bd353c8..8011987 100644 > --- a/xen/arch/arm/smpboot.c > +++ b/xen/arch/arm/smpboot.c > @@ -220,6 +220,12 @@ void stop_cpu(void) > /* Bring up a remote CPU */ > int __cpu_up(unsigned int cpu) > { > + int rc; > + > + rc = init_secondary_pagetables(cpu); > + if ( rc < 0 ) > + return rc; > + > /* Tell the remote CPU which stack to boot on. */ > init_stack = idle_vcpu[cpu]->arch.stack; > > diff --git a/xen/include/asm-arm/config.h b/xen/include/asm-arm/config.h > index 8be8563..79f6353 100644 > --- a/xen/include/asm-arm/config.h > +++ b/xen/include/asm-arm/config.h > @@ -98,12 +98,16 @@ > #define EARLY_VMAP_VIRT_START mk_unsigned_long(0x10000000) > #define XENHEAP_VIRT_START mk_unsigned_long(0x40000000) > #define DOMHEAP_VIRT_START mk_unsigned_long(0x80000000) > +#define DOMHEAP_VIRT_END mk_unsigned_long(0xffffffff) > > #define EARLY_VMAP_VIRT_END XENHEAP_VIRT_START > #define HYPERVISOR_VIRT_START XEN_VIRT_START > > #define DOMHEAP_ENTRIES 1024 /* 1024 2MB mapping slots */ > > +/* Number domheap pagetable pages require at the second level (2MB mappings) > */ ^of ^d Cheers, Tim. _______________________________________________ Xen-devel mailing list Xen-devel@xxxxxxxxxxxxx http://lists.xen.org/xen-devel
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |