diff -r 1b863ae2bf1e tools/libxc/xc_hvm_build.c --- a/tools/libxc/xc_hvm_build.c Wed Dec 05 09:59:23 2007 +0000 +++ b/tools/libxc/xc_hvm_build.c Thu Dec 06 19:27:24 2007 -0600 @@ -21,7 +21,8 @@ #define SCRATCH_PFN 0xFFFFF -static void build_e820map(void *e820_page, unsigned long long mem_size) +static void build_e820map(void *e820_page, unsigned long long mem_size, + unsigned long long mem_size_low) { struct e820entry *e820entry = (struct e820entry *)(((unsigned char *)e820_page) + HVM_E820_OFFSET); @@ -77,17 +78,25 @@ static void build_e820map(void *e820_pag e820entry[nr_map].type = E820_RESERVED; nr_map++; - /* Low RAM goes here. Remove 3 pages for ioreq, bufioreq, and xenstore. */ + /* Low RAM goes here. */ e820entry[nr_map].addr = 0x100000; - e820entry[nr_map].size = mem_size - 0x100000 - PAGE_SIZE * 3; + e820entry[nr_map].size = mem_size_low - 0x100000 - PAGE_SIZE * 3; e820entry[nr_map].type = E820_RAM; nr_map++; /* Explicitly reserve space for special pages (ioreq and xenstore). */ - e820entry[nr_map].addr = mem_size - PAGE_SIZE * 3; + e820entry[nr_map].addr = mem_size_low; e820entry[nr_map].size = PAGE_SIZE * 3; e820entry[nr_map].type = E820_RESERVED; nr_map++; + + if (mem_size > mem_size_low) + { + e820entry[nr_map].addr = 0x40000000; + e820entry[nr_map].size = mem_size - 0x40000000; + e820entry[nr_map].type = E820_RAM; + nr_map++; + } if ( extra_mem_size ) { @@ -158,16 +167,30 @@ static int setup_guest(int xc_handle, uint64_t v_start, v_end; int rc; xen_capabilities_info_t caps; + int memsize_low = 32; + unsigned long nr_pages_low, nr_pages_1g; /* An HVM guest must be initialised with at least 2MB memory. */ if ( memsize < 2 ) goto error_out; + /* Align memory on 1G pages, if possible. */ + nr_pages += 3; + nr_pages_low = nr_pages; + nr_pages_1g = 0; + v_start = 0; + v_end = nr_pages << PAGE_SHIFT; + if ( memsize_low && memsize_low < 1024 && memsize >= 1024 + memsize_low ) + { + nr_pages_low = (unsigned long)memsize_low << (20 - PAGE_SHIFT); + nr_pages_low += 3; + nr_pages_1g = nr_pages - nr_pages_low; + v_end = (1024UL << 20) + (nr_pages_1g << PAGE_SHIFT); + } + nr_pages = v_end >> PAGE_SHIFT; if ( elf_init(&elf, image, image_size) != 0 ) goto error_out; elf_parse_binary(&elf); - v_start = 0; - v_end = (unsigned long long)memsize << 20; if ( xc_version(xc_handle, XENVER_capabilities, &caps) != 0 ) { @@ -203,9 +226,15 @@ static int setup_guest(int xc_handle, /* Allocate memory for HVM guest, skipping VGA hole 0xA0000-0xC0000. */ rc = xc_domain_memory_populate_physmap( xc_handle, dom, 0xa0, 0, 0, &page_array[0x00]); + /* Allocate first chunk. ("low memory") */ if ( rc == 0 ) rc = xc_domain_memory_populate_physmap( - xc_handle, dom, nr_pages - 0xc0, 0, 0, &page_array[0xc0]); + xc_handle, dom, nr_pages_low - 0xc0, 0, 0, &page_array[0xc0]); + /* Allocate second chunk. ("high memory") */ + if ( rc == 0 && nr_pages_1g ) + rc = xc_domain_memory_populate_physmap( + xc_handle, dom, nr_pages_1g, 0, 0, + &page_array[0x40000]); if ( rc != 0 ) { PERROR("Could not allocate memory for HVM guest.\n"); @@ -220,7 +249,8 @@ static int setup_guest(int xc_handle, HVM_E820_PAGE >> PAGE_SHIFT)) == NULL ) goto error_out; memset(e820_page, 0, PAGE_SIZE); - build_e820map(e820_page, v_end); + build_e820map(e820_page, v_end, + nr_pages_1g ? (nr_pages_low << PAGE_SHIFT) : v_end); munmap(e820_page, PAGE_SIZE); /* Map and initialise shared_info page. */ @@ -239,7 +269,9 @@ static int setup_guest(int xc_handle, sizeof(shared_info->evtchn_mask)); munmap(shared_info, PAGE_SIZE); - if ( v_end > HVM_BELOW_4G_RAM_END ) + if ( nr_pages_1g ) + shared_page_nr = nr_pages_low - 1; + else if ( v_end > HVM_BELOW_4G_RAM_END ) shared_page_nr = (HVM_BELOW_4G_RAM_END >> PAGE_SHIFT) - 1; else shared_page_nr = (v_end >> PAGE_SHIFT) - 1; diff -r 1b863ae2bf1e xen/arch/x86/mm/p2m.c --- a/xen/arch/x86/mm/p2m.c Wed Dec 05 09:59:23 2007 +0000 +++ b/xen/arch/x86/mm/p2m.c Thu Dec 06 19:27:24 2007 -0600 @@ -202,7 +202,8 @@ p2m_next_level(struct domain *d, mfn_t * // Returns 0 on error (out of memory) static int -set_p2m_entry(struct domain *d, unsigned long gfn, mfn_t mfn, p2m_type_t p2mt) +__set_p2m_entry(struct domain *d, unsigned long gfn, mfn_t mfn, + p2m_type_t p2mt, unsigned int order) { // XXX -- this might be able to be faster iff current->domain == d mfn_t table_mfn = pagetable_get_mfn(d->arch.phys_table); @@ -217,6 +218,18 @@ set_p2m_entry(struct domain *d, unsigned L4_PAGETABLE_SHIFT - PAGE_SHIFT, L4_PAGETABLE_ENTRIES, PGT_l3_page_table) ) goto out; + if (order == 18) { + if ((gfn & ((1 << order) - 1)) != 0 || (mfn & ((1 << order) - 1)) != 0) + goto out; + p2m_entry = p2m_find_entry(table, &gfn_remainder, gfn, + L3_PAGETABLE_SHIFT - PAGE_SHIFT, + L3_PAGETABLE_ENTRIES); + entry_content = l1e_from_pfn(mfn_x(mfn), + p2m_type_to_flags(p2mt) | _PAGE_PSE); + paging_write_p2m_entry(d, gfn, p2m_entry, table_mfn, entry_content, 3); + rv = 1; + goto out; + } #endif #if CONFIG_PAGING_LEVELS >= 3 /* @@ -233,6 +246,18 @@ set_p2m_entry(struct domain *d, unsigned : L3_PAGETABLE_ENTRIES), PGT_l2_page_table) ) goto out; + if (order == 9) { + if ((gfn & ((1 << order) - 1)) != 0 || (mfn & ((1 << order) - 1)) != 0) + goto out; + p2m_entry = p2m_find_entry(table, &gfn_remainder, gfn, + L2_PAGETABLE_SHIFT - PAGE_SHIFT, + L2_PAGETABLE_ENTRIES); + entry_content = l1e_from_pfn(mfn_x(mfn), + p2m_type_to_flags(p2mt) | _PAGE_PSE); + paging_write_p2m_entry(d, gfn, p2m_entry, table_mfn, entry_content, 2); + rv = 1; + goto out; + } #endif if ( !p2m_next_level(d, &table_mfn, &table, &gfn_remainder, gfn, L2_PAGETABLE_SHIFT - PAGE_SHIFT, @@ -266,6 +291,11 @@ set_p2m_entry(struct domain *d, unsigned return rv; } +static inline int +set_p2m_entry(struct domain *d, unsigned long gfn, mfn_t mfn, p2m_type_t p2mt) +{ + return __set_p2m_entry(d, gfn, mfn, p2mt, 0); +} /* Init the datastructures for later use by the p2m code */ void p2m_init(struct domain *d) @@ -400,6 +430,7 @@ gfn_to_mfn_foreign(struct domain *d, uns paddr_t addr = ((paddr_t)gfn) << PAGE_SHIFT; l2_pgentry_t *l2e; l1_pgentry_t *l1e; + unsigned long flags; ASSERT(paging_mode_translate(d)); @@ -441,25 +472,39 @@ gfn_to_mfn_foreign(struct domain *d, uns #else l3e += l3_table_offset(addr); #endif - if ( (l3e_get_flags(*l3e) & _PAGE_PRESENT) == 0 ) + flags = l3e_get_flags(*l3e); + if ( (flags & _PAGE_PRESENT) == 0 ) { unmap_domain_page(l3e); return _mfn(INVALID_MFN); } mfn = _mfn(l3e_get_pfn(*l3e)); unmap_domain_page(l3e); + if ( (flags & _PAGE_PSE) != 0 ) + { + mfn += (gfn & ((1UL << (L3_PAGETABLE_SHIFT - PAGE_SHIFT)) - 1)); + *t = p2m_flags_to_type(flags); + return mfn; + } } #endif l2e = map_domain_page(mfn_x(mfn)); l2e += l2_table_offset(addr); - if ( (l2e_get_flags(*l2e) & _PAGE_PRESENT) == 0 ) + flags = l2e_get_flags(*l2e); + if ( (flags & _PAGE_PRESENT) == 0 ) { unmap_domain_page(l2e); return _mfn(INVALID_MFN); } mfn = _mfn(l2e_get_pfn(*l2e)); unmap_domain_page(l2e); + if ( (flags & _PAGE_PSE) != 0 ) + { + mfn += (gfn & ((1UL << (L2_PAGETABLE_SHIFT - PAGE_SHIFT)) - 1)); + *t = p2m_flags_to_type(flags); + return mfn; + } l1e = map_domain_page(mfn_x(mfn)); l1e += l1_table_offset(addr); @@ -689,8 +734,8 @@ guest_physmap_remove_page(struct domain } int -guest_physmap_add_entry(struct domain *d, unsigned long gfn, - unsigned long mfn, p2m_type_t t) +__guest_physmap_add_entry(struct domain *d, unsigned long gfn, + unsigned long mfn, p2m_type_t t, unsigned int order) { unsigned long ogfn; p2m_type_t ot; @@ -747,9 +792,13 @@ guest_physmap_add_entry(struct domain *d if ( mfn_valid(_mfn(mfn)) ) { - if ( !set_p2m_entry(d, gfn, _mfn(mfn), t) ) + if ( !__set_p2m_entry(d, gfn, _mfn(mfn), t, order) ) rc = -EINVAL; - set_gpfn_from_mfn(mfn, gfn); + { + unsigned int i; + for (i = 0; i < (1 << order); i++) + set_gpfn_from_mfn(mfn + i, gfn + i); + } } else { diff -r 1b863ae2bf1e xen/common/memory.c --- a/xen/common/memory.c Wed Dec 05 09:59:23 2007 +0000 +++ b/xen/common/memory.c Thu Dec 06 19:27:24 2007 -0600 @@ -90,6 +90,81 @@ static void increase_reservation(struct a->nr_done = i; } +static int try_extent(xen_pfn_t gpfn, XEN_GUEST_HANDLE(xen_pfn_t) list, + unsigned int off, unsigned int maxoff, + unsigned int order) +{ + unsigned int i; + unsigned int o = 1 << order; + xen_pfn_t cgpfn; + + if ( (gpfn & (o - 1)) != 0 ) + return 0; + if ( off + o > maxoff) + return 0; + + for (i = off + 1; i < o; i++) + { + if ( unlikely(__copy_from_guest_offset(&cgpfn, list, i, 1)) ) + return -1; + if ( gpfn + i - off != cgpfn) + return 0; + } + + return 1; +} + +static unsigned int try_larger_extents(struct domain *d, xen_pfn_t gpfn, + XEN_GUEST_HANDLE(xen_pfn_t) list, + unsigned int off, unsigned int maxoff, + unsigned int order) +{ + unsigned int ret_order; + int ret; + + if (!paging_mode_hap(d)) + return 0; + switch (order) + { + case 18: + ret_order = 9; + break; + + case 9: + ret_order = 0; + break; + + case 0: + ret = 0; + ret_order = 18; + ret = try_extent(gpfn, list, off, maxoff, ret_order); + if (ret > 0) + break; + if (ret < 0) + { + ret_order = ~0; + break; + } + ret_order = 9; + ret = try_extent(gpfn, list, off, maxoff, ret_order); + if (ret > 0) + break; + if (ret < 0) + { + ret_order = ~0; + break; + } + ret_order = 0; + break; + + default: + ret_order = 0; + BUG(); + } + + return ret_order; +} + static void populate_physmap(struct memop_args *a) { struct page_info *page; @@ -97,6 +172,9 @@ static void populate_physmap(struct memo xen_pfn_t gpfn, mfn; struct domain *d = a->domain; unsigned int cpu = select_local_cpu(d); + unsigned int extent_order; + unsigned long incr; + unsigned long o; if ( !guest_handle_okay(a->extent_list, a->nr_extents) ) return; @@ -105,7 +183,7 @@ static void populate_physmap(struct memo !multipage_allocation_permitted(current->domain) ) return; - for ( i = a->nr_done; i < a->nr_extents; i++ ) + for ( i = a->nr_done; i < a->nr_extents; i += incr ) { if ( hypercall_preempt_check() ) { @@ -115,33 +193,67 @@ static void populate_physmap(struct memo if ( unlikely(__copy_from_guest_offset(&gpfn, a->extent_list, i, 1)) ) goto out; - - page = __alloc_domheap_pages(d, cpu, a->extent_order, a->memflags); + extent_order = a->extent_order; + if (!extent_order) + { + extent_order = try_larger_extents(d, gpfn, a->extent_list, + i, a->nr_extents, 0); + if (extent_order == ~0) + goto out; + } + + page = __alloc_domheap_pages(d, cpu, extent_order, a->memflags); if ( unlikely(page == NULL) ) { - gdprintk(XENLOG_INFO, "Could not allocate order=%d extent: " - "id=%d memflags=%x (%ld of %d)\n", - a->extent_order, d->domain_id, a->memflags, - i, a->nr_extents); - goto out; - } + if (extent_order != a->extent_order) + { + do + { + extent_order = try_larger_extents(d, gpfn, a->extent_list, + i, a->nr_extents, + extent_order); + page = __alloc_domheap_pages(d, cpu, extent_order, + a->memflags); + if (page) + break; + } + while (extent_order); + } + if ( unlikely(page == NULL) ) + { + gdprintk(XENLOG_INFO, "Could not allocate order=%d extent: " + "id=%d memflags=%x (%ld of %d)\n", + a->extent_order, d->domain_id, a->memflags, + i, a->nr_extents); + goto out; + } + } + o = 1 << extent_order; + if (extent_order == a->extent_order) + incr = 1; + else + incr = o; mfn = page_to_mfn(page); if ( unlikely(paging_mode_translate(d)) ) { - for ( j = 0; j < (1 << a->extent_order); j++ ) - if ( guest_physmap_add_page(d, gpfn + j, mfn + j) ) + if ( guest_physmap_add_page_order(d, gpfn, mfn, extent_order) ) + goto out; + } + else + { + for ( j = 0; j < o; j++ ) + set_gpfn_from_mfn(mfn + j, gpfn + j); + + /* Inform the domain of the new page's machine address. */ + for ( j = 0; j < incr; j++ ) + { + if ( unlikely(__copy_to_guest_offset(a->extent_list, i + j, + &mfn, 1)) ) goto out; - } - else - { - for ( j = 0; j < (1 << a->extent_order); j++ ) - set_gpfn_from_mfn(mfn + j, gpfn + j); - - /* Inform the domain of the new page's machine address. */ - if ( unlikely(__copy_to_guest_offset(a->extent_list, i, &mfn, 1)) ) - goto out; + mfn++; + } } } diff -r 1b863ae2bf1e xen/include/asm-x86/p2m.h --- a/xen/include/asm-x86/p2m.h Wed Dec 05 09:59:23 2007 +0000 +++ b/xen/include/asm-x86/p2m.h Thu Dec 06 19:27:24 2007 -0600 @@ -93,6 +93,9 @@ static inline p2m_type_t p2m_flags_to_ty return (flags >> 9) & 0x7; } +/* Read another domain's P2M table, mapping pages as we go */ +mfn_t gfn_to_mfn_foreign(struct domain *d, unsigned long gfn, p2m_type_t *t); + /* Read the current domain's p2m table (through the linear mapping). */ static inline mfn_t gfn_to_mfn_current(unsigned long gfn, p2m_type_t *t) { @@ -102,6 +105,9 @@ static inline mfn_t gfn_to_mfn_current(u * XXX marked as RAM was considered to be emulated MMIO space. * XXX Once we start explicitly registering MMIO regions in the p2m * XXX we will return p2m_invalid for unmapped gfns */ + + if ( paging_mode_hap(current->domain) ) + return gfn_to_mfn_foreign(current->domain, gfn, t); if ( gfn <= current->domain->arch.p2m.max_mapped_pfn ) { @@ -131,9 +137,6 @@ static inline mfn_t gfn_to_mfn_current(u *t = p2mt; return mfn; } - -/* Read another domain's P2M table, mapping pages as we go */ -mfn_t gfn_to_mfn_foreign(struct domain *d, unsigned long gfn, p2m_type_t *t); /* General conversion function from gfn to mfn */ #define gfn_to_mfn(d, g, t) _gfn_to_mfn((d), (g), (t)) @@ -201,8 +204,16 @@ void p2m_teardown(struct domain *d); void p2m_teardown(struct domain *d); /* Add a page to a domain's p2m table */ -int guest_physmap_add_entry(struct domain *d, unsigned long gfn, - unsigned long mfn, p2m_type_t t); +int __guest_physmap_add_entry(struct domain *d, unsigned long gfn, + unsigned long mfn, p2m_type_t t, + unsigned int order); + +static inline int +guest_physmap_add_entry(struct domain *d, unsigned long gfn, + unsigned long mfn, p2m_type_t t) +{ + return __guest_physmap_add_entry(d, gfn, mfn, t, 0); +} /* Untyped version for RAM only, for compatibility * @@ -212,6 +223,14 @@ static inline int guest_physmap_add_page unsigned long mfn) { return guest_physmap_add_entry(d, gfn, mfn, p2m_ram_rw); +} + +static inline int guest_physmap_add_page_order(struct domain *d, + unsigned long gfn, + unsigned long mfn, + unsigned int order) +{ + return __guest_physmap_add_entry(d, gfn, mfn, p2m_ram_rw, order); } /* Remove a page from a domain's p2m table */