[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Xen-devel] [PATCH 2/6] Change the boot allocator function to support memory add
This patch extend the boot allocator to support memory add. We take different method for boot allocator bitmap for 32/64 system. In x32 , we allocate 512K bitmap to support the whole 16G memory. In x86_64, we don't change the allocation when system bootup, instead, we try to remap the allocator bitmap to some pre-defined virtual address if hot-add happen. We also add several API to allocate the handle boot page from some range. Signed-off-by: Jiang, Yunhong <yunhong.jiang@xxxxxxxxx> Signed-off-by: Wang, shane <shane.wang@xxxxxxxxx> diff -r 54433b197b5a xen/arch/x86/mm.c --- a/xen/arch/x86/mm.c Thu Jun 25 21:41:04 2009 +0800 +++ b/xen/arch/x86/mm.c Thu Jun 25 21:41:20 2009 +0800 @@ -155,7 +155,7 @@ struct domain *dom_xen, *dom_io; /* Frame table and its size in pages. */ struct page_info *__read_mostly frame_table; -unsigned long max_page; +unsigned long max_page, max_boot_page; unsigned long total_pages; #define PAGE_CACHE_ATTRS (_PAGE_PAT|_PAGE_PCD|_PAGE_PWT) @@ -207,6 +207,130 @@ void __init init_frametable(void) memset(frame_table, 0, nr_pages << PAGE_SHIFT); } + +#if defined(__x86_64__) +static int boot_alloc_remapped = 0; +static unsigned long mapped_pages = 0; + +#define round_pgup(_p) (((_p)+(PAGE_SIZE-1))&PAGE_MASK) + +/* + * Extend the boot allocator bitmap and initialize the free/alloc state. + * It avoid copy original bitmap through splitting super page mapping into + * singer page mapping. + * It also use pages between start_pfn/end_pfn as page table page + */ +int arch_extend_boot_allocator(unsigned long start_pfn, + unsigned long end_pfn) +{ + unsigned long n_size, n_pages, i, s_map_pfn, e_map_pfn; + + if ( (start_pfn > end_pfn) || (start_pfn < max_page) ) + return -EINVAL; + + if (!boot_alloc_remapped) + { + unsigned long map_start, map_end, map_end_pfn; + unsigned long offset, o_start, o_end, o_size; + + o_start = virt_to_maddr(alloc_bitmap); + + o_size = max_page / 8; + o_size += sizeof(unsigned long); + o_size = round_pgup(o_size); + o_end = o_start + o_size; + + map_start = o_start & ~((1UL << L2_PAGETABLE_SHIFT) -1UL); + map_end = o_end & ~((1UL << L2_PAGETABLE_SHIFT) -1UL); + map_end_pfn = map_end >> PAGE_SHIFT; + + map_pages_to_xen(BOOTALLOC_VIRT_START, map_start >> PAGE_SHIFT, + ((map_end - map_start) >> PAGE_SHIFT) + 1, + PAGE_HYPERVISOR); + + mapped_pages += (map_end - map_start) >> PAGE_SHIFT; + + /* + * For pages in the end, it may not be 2M aligned + * Try to map them as 4k pages, and add some pages to be 2M aligned + * XXX A cleaner way is to make init_boot_allocator 2M aligned, do we + * care about those extra pages? + */ + for (i = 0; i < (1UL << PAGETABLE_ORDER); i++) + { + if (i < (( o_end >> PAGE_SHIFT ) - map_end_pfn)) + map_pages_to_xen(BOOTALLOC_VIRT_START + + (mapped_pages << PAGE_SHIFT), + map_end_pfn + i, 1, + PAGE_HYPERVISOR); + else + { + struct page_info *pg; + pg = alloc_domheap_page(NULL, 0); + if (!pg) + return -ENOMEM; + map_pages_to_xen(BOOTALLOC_VIRT_START + + (mapped_pages << PAGE_SHIFT), + page_to_mfn(pg), 1, PAGE_HYPERVISOR); + /* Mark the new created dummy page as allocated */ + memset((void *)(BOOTALLOC_VIRT_START + (mapped_pages << PAGE_SHIFT)), 0xFFU, 1UL << PAGE_SHIFT); + } + mapped_pages++; + } + + offset = o_start & ((1UL << L2_PAGETABLE_SHIFT) - 1UL); + + alloc_bitmap = (unsigned long *)(BOOTALLOC_VIRT_START + offset); + smp_mb(); + boot_alloc_remapped = 1; + } + + n_size = end_pfn / 8; + n_size += sizeof(unsigned long); + n_size = round_pgup(n_size); + n_pages = ((unsigned long)alloc_bitmap + n_size - BOOTALLOC_VIRT_START) >> + PAGE_SHIFT; + n_pages += ((1UL << PAGETABLE_ORDER) - 1); + n_pages &= ~((1UL << PAGETABLE_ORDER) - 1); + + ASSERT(!(mapped_pages & ((1UL << PAGETABLE_ORDER) -1)) ); + if ( n_pages <= mapped_pages) + { + map_free(start_pfn, end_pfn - start_pfn + 1); + return start_pfn; + } + + s_map_pfn = start_pfn + (1UL << PAGETABLE_ORDER) - 1; + s_map_pfn = start_pfn & ~((1UL << PAGETABLE_ORDER) - 1); + e_map_pfn = s_map_pfn; + for ( i = mapped_pages; i <= n_pages; i += (1UL << PAGETABLE_ORDER) ) + { + map_pages_to_xen(BOOTALLOC_VIRT_START+ + (i << PAGE_SHIFT), + s_map_pfn + (i << PAGETABLE_ORDER ), + 1UL << PAGETABLE_ORDER, + PAGE_HYPERVISOR); + e_map_pfn += (i << PAGETABLE_ORDER); + } + + /* All new allocated page are marked as allocated initialy */ + memset((unsigned char *)(BOOTALLOC_VIRT_START + + (mapped_pages << PAGE_SHIFT)), + 0xFFU, (n_pages - mapped_pages) << PAGE_SHIFT); + mapped_pages = n_pages; + map_free(start_pfn, s_map_pfn - start_pfn); + map_free(e_map_pfn, end_pfn - e_map_pfn + 1); + + return start_pfn; +} +#else +int arch_extend_boot_allocator(unsigned long start_pfn, + unsigned long end_pfn) +{ + map_free(start_pfn, end_pfn - start_pfn + 1); + return start_pfn; +} +#endif void __init arch_init_memory(void) { @@ -4402,8 +4526,6 @@ int ptwr_do_page_fault(struct vcpu *v, u void free_xen_pagetable(void *v) { - extern int early_boot; - if ( early_boot ) return; diff -r 54433b197b5a xen/arch/x86/setup.c --- a/xen/arch/x86/setup.c Thu Jun 25 21:41:04 2009 +0800 +++ b/xen/arch/x86/setup.c Thu Jun 25 21:41:21 2009 +0800 @@ -765,6 +765,9 @@ void __init __start_xen(unsigned long mb reserve_e820_ram(&boot_e820, initial_images_base, initial_images_end); /* Initialise boot heap. */ +#if defined(CONFIG_X86_32) && defined(CONFIG_MEMORY_HOTPLUG) + max_boot_page = 16UL << (30 - PAGE_SHIFT); +#endif allocator_bitmap_end = init_boot_allocator(__pa(&_end)); #if defined(CONFIG_X86_32) xenheap_initial_phys_start = allocator_bitmap_end; diff -r 54433b197b5a xen/arch/x86/x86_32/mm.c --- a/xen/arch/x86/x86_32/mm.c Thu Jun 25 21:41:04 2009 +0800 +++ b/xen/arch/x86/x86_32/mm.c Thu Jun 25 21:41:21 2009 +0800 @@ -42,7 +42,6 @@ static unsigned long mpt_size; void *alloc_xen_pagetable(void) { - extern int early_boot; extern unsigned long xenheap_initial_phys_start; unsigned long mfn; diff -r 54433b197b5a xen/arch/x86/x86_64/mm.c --- a/xen/arch/x86/x86_64/mm.c Thu Jun 25 21:41:04 2009 +0800 +++ b/xen/arch/x86/x86_64/mm.c Thu Jun 25 21:41:21 2009 +0800 @@ -57,7 +57,6 @@ l2_pgentry_t __attribute__ ((__section__ void *alloc_xen_pagetable(void) { - extern int early_boot; unsigned long mfn; if ( !early_boot ) diff -r 54433b197b5a xen/common/page_alloc.c --- a/xen/common/page_alloc.c Thu Jun 25 21:41:04 2009 +0800 +++ b/xen/common/page_alloc.c Thu Jun 25 21:41:56 2009 +0800 @@ -103,7 +103,7 @@ unsigned long *alloc_bitmap; * *_off == Bit offset within an element of the `alloc_bitmap' array. */ -static void map_alloc(unsigned long first_page, unsigned long nr_pages) +void map_alloc(unsigned long first_page, unsigned long nr_pages) { unsigned long start_off, end_off, curr_idx, end_idx; @@ -131,7 +131,7 @@ static void map_alloc(unsigned long firs } } -static void map_free(unsigned long first_page, unsigned long nr_pages) +void map_free(unsigned long first_page, unsigned long nr_pages) { unsigned long start_off, end_off, curr_idx, end_idx; @@ -178,15 +178,33 @@ paddr_t __init init_boot_allocator(paddr * Allocate space for the allocation bitmap. Include an extra longword * of padding for possible overrun in map_alloc and map_free. */ - bitmap_size = max_page / 8; + bitmap_size = (max_boot_page ? max_boot_page : max_page) / 8; bitmap_size += sizeof(unsigned long); bitmap_size = round_pgup(bitmap_size); alloc_bitmap = (unsigned long *)maddr_to_virt(bitmap_start); /* All allocated by default. */ memset(alloc_bitmap, ~0, bitmap_size); + max_boot_page = max_page; return bitmap_start + bitmap_size; +} + +int extend_boot_allocator(unsigned long spfn, unsigned long epfn) +{ + int rc; + + if (epfn < max_page) + return 0; + + rc = arch_extend_boot_allocator(spfn, epfn); + + if (rc < 0) + return rc; + + max_boot_page = epfn; + + return 0; } void __init init_boot_pages(paddr_t ps, paddr_t pe) @@ -235,15 +253,22 @@ void __init init_boot_pages(paddr_t ps, } } -unsigned long __init alloc_boot_pages( - unsigned long nr_pfns, unsigned long pfn_align) +/* + * allocate nr_pfn with "align" alignement between start ~ end + */ +unsigned long alloc_boot_page_range(unsigned long start, unsigned long end, + unsigned long nr_pfns, unsigned long align) { unsigned long pg, i; - - /* Search backwards to obtain highest available range. */ - for ( pg = (max_page - nr_pfns) & ~(pfn_align - 1); - pg >= first_valid_mfn; - pg = (pg + i - nr_pfns) & ~(pfn_align - 1) ) + if (start < first_valid_mfn) + start = first_valid_mfn; + + if ( (end > max_boot_page) ) + end = max_boot_page; + + for (pg = (end - nr_pfns) & ~(align - 1); + pg >= start; + pg = (pg + i - nr_pfns) & ~(align - 1) ) { for ( i = 0; i < nr_pfns; i++ ) if ( allocated_in_map(pg+i) ) @@ -258,6 +283,11 @@ unsigned long __init alloc_boot_pages( return 0; } +unsigned long __init alloc_boot_pages( + unsigned long nr_pfns, unsigned long pfn_align) +{ + return alloc_boot_page_range(first_valid_mfn, max_page, nr_pfns, pfn_align); +} /************************* @@ -834,7 +864,7 @@ int query_page_offline(unsigned long mfn * latter is not on a MAX_ORDER boundary, then we reserve the page by * not freeing it to the buddy allocator. */ -static void init_heap_pages( +void init_heap_pages( struct page_info *pg, unsigned long nr_pages) { unsigned int nid_curr, nid_prev; @@ -894,15 +924,15 @@ static unsigned long avail_heap_pages( } #define avail_for_domheap(mfn) !(allocated_in_map(mfn) || is_xen_heap_mfn(mfn)) -void __init end_boot_allocator(void) +void end_boot_allocator_range(unsigned long spfn, unsigned long epfn) { unsigned long i, nr = 0; int curr_free, next_free; /* Pages that are free now go to the domain sub-allocator. */ - if ( (curr_free = next_free = avail_for_domheap(first_valid_mfn)) ) - map_alloc(first_valid_mfn, 1); - for ( i = first_valid_mfn; i < max_page; i++ ) + if ( (curr_free = next_free = avail_for_domheap(spfn)) ) + map_alloc(spfn, 1); + for ( i = spfn; i < epfn; i++ ) { curr_free = next_free; next_free = avail_for_domheap(i+1); @@ -918,6 +948,11 @@ void __init end_boot_allocator(void) } if ( nr ) init_heap_pages(mfn_to_page(i - nr), nr); +} + +void __init end_boot_allocator(void) +{ + end_boot_allocator_range(first_valid_mfn, max_page); if ( !dma_bitsize && (num_online_nodes() > 1) ) { @@ -936,6 +971,7 @@ void __init end_boot_allocator(void) printk(" DMA width %u bits", dma_bitsize); printk("\n"); } + #undef avail_for_domheap /* diff -r 54433b197b5a xen/include/asm-ia64/mm.h --- a/xen/include/asm-ia64/mm.h Thu Jun 25 21:41:04 2009 +0800 +++ b/xen/include/asm-ia64/mm.h Thu Jun 25 21:41:21 2009 +0800 @@ -274,6 +274,12 @@ static inline int get_page_and_type(stru } return rc; +} + +int arch_extend_boot_allocator(unsigned long start_pfn, + unsigned long end_pfn) +{ + return -ENOSYS; } #define set_machinetophys(_mfn, _pfn) do { } while(0); diff -r 54433b197b5a xen/include/asm-x86/config.h --- a/xen/include/asm-x86/config.h Thu Jun 25 21:41:04 2009 +0800 +++ b/xen/include/asm-x86/config.h Thu Jun 25 21:41:22 2009 +0800 @@ -162,7 +162,9 @@ extern unsigned int video_mode, video_fl * High read-only compatibility machine-to-phys translation table. * 0xffff828c80000000 - 0xffff828cbfffffff [1GB, 2^30 bytes, PML4:261] * Xen text, static data, bss. - * 0xffff828cc0000000 - 0xffff82ffffffffff [461GB, PML4:261] + * 0xffff828cc0000000 - 0xffff82cfffffffff [1GB, 2^30 bytes, PML4:261] + * Boot allocator bitmap + * 0xffff828cd0000000 - 0xffff82ffffffffff [460GB, PML4:261] * Reserved for future use. * 0xffff830000000000 - 0xffff83ffffffffff [1TB, 2^40 bytes, PML4:262-263] * 1:1 direct mapping of all physical memory. @@ -230,6 +232,9 @@ extern unsigned int video_mode, video_fl /* Slot 261: xen text, static data and bss (1GB). */ #define XEN_VIRT_START (HIRO_COMPAT_MPT_VIRT_END) #define XEN_VIRT_END (XEN_VIRT_START + (1UL << 30)) +/* Slot 261: Boot allocator bitmap (1GB) */ +#define BOOTALLOC_VIRT_START XEN_VIRT_END +#define BOOTALLOC_VIRT_END (BOOTALLOC_VIRT_START + (1UL << 30)) /* Slot 262-263: A direct 1:1 mapping of all of physical memory. */ #define DIRECTMAP_VIRT_START (PML4_ADDR(262)) #define DIRECTMAP_VIRT_END (DIRECTMAP_VIRT_START + PML4_ENTRY_BYTES*2) diff -r 54433b197b5a xen/include/asm-x86/mm.h --- a/xen/include/asm-x86/mm.h Thu Jun 25 21:41:04 2009 +0800 +++ b/xen/include/asm-x86/mm.h Thu Jun 25 21:41:22 2009 +0800 @@ -266,9 +266,13 @@ extern void share_xen_page_with_privileg struct page_info *page, int readonly); extern struct page_info *frame_table; -extern unsigned long max_page; +extern unsigned long max_page, max_boot_page; extern unsigned long total_pages; + +extern int early_boot; void init_frametable(void); +int arch_extend_boot_allocator(unsigned long start_pfn, + unsigned long end_pfn); int free_page_type(struct page_info *page, unsigned long type, int preemptible); diff -r 54433b197b5a xen/include/xen/mm.h --- a/xen/include/xen/mm.h Thu Jun 25 21:41:04 2009 +0800 +++ b/xen/include/xen/mm.h Thu Jun 25 21:41:22 2009 +0800 @@ -38,10 +38,18 @@ struct page_info; /* Boot-time allocator. Turns into generic allocator after bootstrap. */ paddr_t init_boot_allocator(paddr_t bitmap_start); +void map_free(unsigned long first_page, unsigned long nr_pages); +void map_alloc(unsigned long first_page, unsigned long nr_pages); void init_boot_pages(paddr_t ps, paddr_t pe); unsigned long alloc_boot_pages( unsigned long nr_pfns, unsigned long pfn_align); +unsigned long alloc_boot_page_range(unsigned long start, unsigned long end, + unsigned long nr_pfns, unsigned long align); +void init_heap_pages( + struct page_info *pg, unsigned long nr_pages); void end_boot_allocator(void); +void end_boot_allocator_range(unsigned long spfn, unsigned long epfn); +int extend_boot_allocator(unsigned long spfn, unsigned long epfn); /* Xen suballocator. These functions are interrupt-safe. */ void init_xenheap_pages(paddr_t ps, paddr_t pe); Attachment:
boot_allocator.patch _______________________________________________ Xen-devel mailing list Xen-devel@xxxxxxxxxxxxxxxxxxx http://lists.xensource.com/xen-devel
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |