All of lore.kernel.org
 help / color / mirror / Atom feed
* [RFC][Patches] Xen 1GB Page Table Support
@ 2009-03-18 15:48 Huang2, Wei
  2009-03-18 17:20 ` George Dunlap
  0 siblings, 1 reply; 23+ messages in thread
From: Huang2, Wei @ 2009-03-18 15:48 UTC (permalink / raw)
  To: xen-devel; +Cc: george.dunlap, keir.fraser, Tim Deegan


[-- Attachment #1.1: Type: text/plain, Size: 3437 bytes --]

Current Xen supports 2MB super pages for NPT/EPT. The attached patches
extend this feature to support 1GB pages. The PoD (populate-on-demand)
introduced by George Dunlap made P2M modification harder. I tried to
preserve existing PoD design by introducing a 1GB PoD cache list. 

 

Note that 1GB PoD can be dropped if we don't care about 1GB when PoD is
enabled. In this case, we can just split 1GB PDPE into 512x2MB PDE
entries and grab pages from PoD super list. That can pretty much make
1gb_p2m_pod.patch go away.

 

Any comment/suggestion on design idea will be appreciated.

 

Thanks,

 

-Wei

 

 

The following is the description:

=== 1gb_tools.patch ===

Extend existing setup_guest() function. Basically, it tries to allocate
1GB pages whenever available. If this request fails, it falls back to
2MB. If both fail, then 4KB pages will be used.

 

=== 1gb_p2m.patch ===

* p2m_next_level()

Check PSE bit of L3 page table entry. If 1GB is found (PSE=1), we split
1GB into 512 2MB pages.

 

* p2m_set_entry()

Configure the PSE bit of L3 P2M table if page order == 18 (1GB).

 

* p2m_gfn_to_mfn()

Add support for 1GB case when doing gfn to mfn translation. When L3
entry is marked as POPULATE_ON_DEMAND, we call 2m_pod_demand_populate().
Otherwise, we do the regular address translation (gfn ==> mfn).

 

* p2m_gfn_to_mfn_current()

This is similar to p2m_gfn_to_mfn(). When L3 entry s marked as
POPULATE_ON_DEMAND, it demands a populate using
p2m_pod_demand_populate(). Otherwise, it does a normal translation. 1GB
page is taken into consideration.

 

* set_p2m_entry()

Request 1GB page

 

* audit_p2m()

Support 1GB while auditing p2m table.

 

* p2m_change_type_global()

Deal with 1GB page when changing global page type. 

 

=== 1gb_p2m_pod.patch ===

* xen/include/asm-x86/p2m.h

Minor change to deal with PoD. It separates super page cache list into
2MB and 1GB lists. Similarly, we record last gpfn of sweeping for both
2MB and 1GB.

 

* p2m_pod_cache_add()

Check page order and add 1GB super page into PoD 1GB cache list.

 

* p2m_pod_cache_get()

Grab a page from cache list. It tries to break 1GB page into 512 2MB
pages if 2MB PoD list is empty. Similarly, 4KB can be requested from
super pages. The breaking order is 2MB then 1GB.

 

* p2m_pod_cache_target()

This function is used to set PoD cache size. To increase PoD target, we
try to allocate 1GB from xen domheap. If this fails, we try 2MB. If both
fail, we try 4KB which is guaranteed to work.

 

To decrease the target, we use a similar approach. We first try to free
1GB pages from 1GB PoD cache list. If such request fails, we try 2MB PoD
cache list. If both fail, we try 4KB list.

 

* p2m_pod_zero_check_superpage_1gb()

This adds a new function to check for 1GB page. This function is similar
to p2m_pod_zero_check_superpage_2mb().

 

* p2m_pod_zero_check_superpage_1gb()

We add a new function to sweep 1GB page from guest memory. This is the
same as p2m_pod_zero_check_superpage_2mb().

 

* p2m_pod_demand_populate()

The trick of this function is to do remap_and_retry if
p2m_pod_cache_get() fails. When p2m_pod_get() fails, this function will
splits p2m table entry into smaller ones (e.g. 1GB ==> 2MB or 2MB ==>
4KB). That can guarantee populate demands always work.

 

 


[-- Attachment #1.2: Type: text/html, Size: 7376 bytes --]

[-- Attachment #2: 1gb_tools.patch --]
[-- Type: application/octet-stream, Size: 7472 bytes --]

# HG changeset patch
# User root@weisles1064.amd.com
# Date 1236740196 18000
# Node ID 05aeb649fdab9e8cc3bc541dc3a014658a85611f
# Parent  fe4b23bd3a954a640c922202249688eb1b981ce0
1GB nested paging support: tools

diff -r fe4b23bd3a95 -r 05aeb649fdab tools/libxc/xc_hvm_build.c
--- a/tools/libxc/xc_hvm_build.c	Wed Mar 18 13:25:25 2009 +0000
+++ b/tools/libxc/xc_hvm_build.c	Tue Mar 10 21:56:36 2009 -0500
@@ -19,8 +19,10 @@
 
 #include <xen/libelf/libelf.h>
 
-#define SUPERPAGE_PFN_SHIFT  9
-#define SUPERPAGE_NR_PFNS    (1UL << SUPERPAGE_PFN_SHIFT)
+#define SUPERPAGE_2MB_SHIFT   9
+#define SUPERPAGE_2MB_NR_PFNS (1UL << SUPERPAGE_2MB_SHIFT)
+#define SUPERPAGE_1GB_SHIFT   18
+#define SUPERPAGE_1GB_NR_PFNS (1UL << SUPERPAGE_1GB_SHIFT)
 
 #define SPECIALPAGE_BUFIOREQ 0
 #define SPECIALPAGE_XENSTORE 1
@@ -117,6 +119,8 @@ static int setup_guest(int xc_handle,
     uint64_t v_start, v_end;
     int rc;
     xen_capabilities_info_t caps;
+    unsigned long stat_normal_pages = 0, stat_2mb_pages = 0, 
+        stat_1gb_pages = 0;
     int pod_mode = 0;
     
 
@@ -166,35 +170,43 @@ static int setup_guest(int xc_handle,
 
     /*
      * Allocate memory for HVM guest, skipping VGA hole 0xA0000-0xC0000.
-     * We allocate pages in batches of no more than 8MB to ensure that
-     * we can be preempted and hence dom0 remains responsive.
+     *
+     * We attempt to allocate 1GB pages if possible. It falls back on 2MB
+     * pages if 1GB allocation fails. 4KB pages will be used eventually if
+     * both fail.
+     * 
+     * Under 2MB mode, we allocate pages in batches of no more than 8MB to 
+     * ensure that we can be preempted and hence dom0 remains responsive.
      */
     rc = xc_domain_memory_populate_physmap(
         xc_handle, dom, 0xa0, 0, 0, &page_array[0x00]);
     cur_pages = 0xc0;
+    stat_normal_pages = 0xc0;
     while ( (rc == 0) && (nr_pages > cur_pages) )
     {
         /* Clip count to maximum 8MB extent. */
         unsigned long count = nr_pages - cur_pages;
-        if ( count > 2048 )
-            count = 2048;
-
-        /* Clip partial superpage extents to superpage boundaries. */
-        if ( ((cur_pages & (SUPERPAGE_NR_PFNS-1)) != 0) &&
-             (count > (-cur_pages & (SUPERPAGE_NR_PFNS-1))) )
-            count = -cur_pages & (SUPERPAGE_NR_PFNS-1); /* clip s.p. tail */
-        else if ( ((count & (SUPERPAGE_NR_PFNS-1)) != 0) &&
-                  (count > SUPERPAGE_NR_PFNS) )
-            count &= ~(SUPERPAGE_NR_PFNS - 1); /* clip non-s.p. tail */
-
-        /* Attempt to allocate superpage extents. */
-        if ( ((count | cur_pages) & (SUPERPAGE_NR_PFNS - 1)) == 0 )
+        unsigned long max_pages = SUPERPAGE_1GB_NR_PFNS;
+
+        if ( count > max_pages )
+            count = max_pages;
+        
+        /* Take care the corner cases of super page tails */
+        if ( ((cur_pages & (SUPERPAGE_1GB_NR_PFNS-1)) != 0) &&
+             (count > (-cur_pages & (SUPERPAGE_1GB_NR_PFNS-1))) )
+            count = -cur_pages & (SUPERPAGE_1GB_NR_PFNS-1);
+        else if ( ((count & (SUPERPAGE_1GB_NR_PFNS-1)) != 0) &&
+                  (count > SUPERPAGE_1GB_NR_PFNS) )
+            count &= ~(SUPERPAGE_1GB_NR_PFNS - 1);
+
+        /* Attemp to allocate 1GB super page */
+        if ( ((count | cur_pages) & (SUPERPAGE_1GB_NR_PFNS - 1)) == 0 )
         {
             long done;
-            xen_pfn_t sp_extents[count >> SUPERPAGE_PFN_SHIFT];
+            xen_pfn_t sp_extents[count >> SUPERPAGE_1GB_SHIFT];
             struct xen_memory_reservation sp_req = {
-                .nr_extents   = count >> SUPERPAGE_PFN_SHIFT,
-                .extent_order = SUPERPAGE_PFN_SHIFT,
+                .nr_extents   = count >> SUPERPAGE_1GB_SHIFT,
+                .extent_order = SUPERPAGE_1GB_SHIFT,
                 .domid        = dom
             };
 
@@ -203,11 +215,12 @@ static int setup_guest(int xc_handle,
 
             set_xen_guest_handle(sp_req.extent_start, sp_extents);
             for ( i = 0; i < sp_req.nr_extents; i++ )
-                sp_extents[i] = page_array[cur_pages+(i<<SUPERPAGE_PFN_SHIFT)];
+                sp_extents[i] = page_array[cur_pages+(i<<SUPERPAGE_1GB_SHIFT)];
             done = xc_memory_op(xc_handle, XENMEM_populate_physmap, &sp_req);
             if ( done > 0 )
             {
-                done <<= SUPERPAGE_PFN_SHIFT;
+                stat_1gb_pages += done;
+                done <<= SUPERPAGE_1GB_SHIFT;
                 if ( pod_mode && target_pages > cur_pages )
                 {
                     int d = target_pages - cur_pages;
@@ -218,12 +231,60 @@ static int setup_guest(int xc_handle,
             }
         }
 
+        if ( count != 0 )
+        {
+            max_pages = 2048;
+            if ( count > max_pages )
+                count = max_pages;
+            
+            /* Clip partial superpage extents to superpage boundaries. */
+            if ( ((cur_pages & (SUPERPAGE_2MB_NR_PFNS-1)) != 0) &&
+                 (count > (-cur_pages & (SUPERPAGE_2MB_NR_PFNS-1))) )
+                count = -cur_pages & (SUPERPAGE_2MB_NR_PFNS-1);
+            else if ( ((count & (SUPERPAGE_2MB_NR_PFNS-1)) != 0) &&
+                  (count > SUPERPAGE_2MB_NR_PFNS) )
+            count &= ~(SUPERPAGE_2MB_NR_PFNS - 1); /* clip non-s.p. tail */
+
+            /* Attempt to allocate superpage extents. */
+            if ( ((count | cur_pages) & (SUPERPAGE_2MB_NR_PFNS - 1)) == 0 )
+            {
+                long done;
+                xen_pfn_t sp_extents[count >> SUPERPAGE_2MB_SHIFT];
+                struct xen_memory_reservation sp_req = {
+                    .nr_extents   = count >> SUPERPAGE_2MB_SHIFT,
+                    .extent_order = SUPERPAGE_2MB_SHIFT,
+                    .domid        = dom
+                };
+
+                if ( pod_mode )
+                    sp_req.mem_flags = XENMEMF_populate_on_demand;
+
+                set_xen_guest_handle(sp_req.extent_start, sp_extents);
+                for ( i = 0; i < sp_req.nr_extents; i++ )
+                    sp_extents[i] = page_array[cur_pages+(i<<SUPERPAGE_2MB_SHIFT)];
+                done = xc_memory_op(xc_handle, XENMEM_populate_physmap, &sp_req);
+                if ( done > 0 )
+                {
+                    stat_2mb_pages += done;
+                    done <<= SUPERPAGE_2MB_SHIFT;
+                    if ( pod_mode && target_pages > cur_pages )
+                    {
+                        int d = target_pages - cur_pages;
+                        pod_pages += ( done < d ) ? done : d;
+                    }
+                    cur_pages += done;
+                    count -= done;
+                }
+            }
+        }
+
         /* Fall back to 4kB extents. */
         if ( count != 0 )
         {
             rc = xc_domain_memory_populate_physmap(
                 xc_handle, dom, count, 0, 0, &page_array[cur_pages]);
             cur_pages += count;
+            stat_normal_pages += count;
             if ( pod_mode )
                 pod_pages -= count;
         }
@@ -241,6 +302,12 @@ static int setup_guest(int xc_handle,
         goto error_out;
     }
 
+    IPRINTF("PHYSICAL MEMORY ALLOCATION:\n"
+            "  4KB PAGES: 0x%016lx\n"
+            "  2MB PAGES: 0x%016lx\n"
+            "  1GB PAGES: 0x%016lx\n",
+            stat_normal_pages, stat_2mb_pages, stat_1gb_pages);
+    
     if ( loadelfimage(&elf, xc_handle, dom, page_array) != 0 )
         goto error_out;
 

[-- Attachment #3: 1gb_p2m.patch --]
[-- Type: application/octet-stream, Size: 11420 bytes --]

diff -r 05aeb649fdab -r bacd2a71b6ca xen/arch/x86/mm/p2m.c
--- a/xen/arch/x86/mm/p2m.c	Tue Mar 10 21:56:36 2009 -0500
+++ b/xen/arch/x86/mm/p2m.c	Tue Mar 10 22:09:22 2009 -0500
@@ -207,7 +207,36 @@ p2m_next_level(struct domain *d, mfn_t *
 
     ASSERT(l1e_get_flags(*p2m_entry) & (_PAGE_PRESENT|_PAGE_PSE));
 
-    /* split single large page into 4KB page in P2M table */
+    /* split 1GB pages into 2MB pages */
+    if ( type == PGT_l2_page_table && (l1e_get_flags(*p2m_entry) & _PAGE_PSE) )
+    {
+        unsigned long flags, pfn;
+        struct page_info *pg = d->arch.p2m->alloc_page(d);
+        if ( pg == NULL )
+            return 0;
+        page_list_add_tail(pg, &d->arch.p2m->pages);
+        pg->u.inuse.type_info = PGT_l1_page_table | 1 | PGT_validated;
+        pg->count_info = 1;
+        
+        flags = l1e_get_flags(*p2m_entry);
+        pfn = l1e_get_pfn(*p2m_entry);
+        
+        l1_entry = map_domain_page(mfn_x(page_to_mfn(pg)));
+        for ( i = 0; i < L2_PAGETABLE_ENTRIES; i++ )
+        {
+            new_entry = l1e_from_pfn(pfn + (i * L1_PAGETABLE_ENTRIES), flags);
+            paging_write_p2m_entry(d, gfn, l1_entry+i, *table_mfn, new_entry,
+                                   2);
+        }
+        unmap_domain_page(l1_entry);
+        new_entry = l1e_from_pfn(mfn_x(page_to_mfn(pg)),
+                                 __PAGE_HYPERVISOR|_PAGE_USER); //disable PSE
+        paging_write_p2m_entry(d, gfn,
+                               p2m_entry, *table_mfn, new_entry, 3);
+    }
+
+
+    /* split single 2MB large page into 4KB page in P2M table */
     if ( type == PGT_l1_page_table && (l1e_get_flags(*p2m_entry) & _PAGE_PSE) )
     {
         unsigned long flags, pfn;
@@ -1116,6 +1145,7 @@ p2m_set_entry(struct domain *d, unsigned
     l1_pgentry_t *p2m_entry;
     l1_pgentry_t entry_content;
     l2_pgentry_t l2e_content;
+    l3_pgentry_t l3e_content;
     int rv=0;
 
 #if CONFIG_PAGING_LEVELS >= 4
@@ -1125,18 +1155,44 @@ p2m_set_entry(struct domain *d, unsigned
         goto out;
 #endif
     /*
+     * Try to allocate 1GB page table if this feature is supported.
+     *
      * When using PAE Xen, we only allow 33 bits of pseudo-physical
      * address in translated guests (i.e. 8 GBytes).  This restriction
      * comes from wanting to map the P2M table into the 16MB RO_MPT hole
      * in Xen's address space for translated PV guests.
      * When using AMD's NPT on PAE Xen, we are restricted to 4GB.
      */
-    if ( !p2m_next_level(d, &table_mfn, &table, &gfn_remainder, gfn,
-                         L3_PAGETABLE_SHIFT - PAGE_SHIFT,
-                         ((CONFIG_PAGING_LEVELS == 3)
-                          ? (d->arch.hvm_domain.hap_enabled ? 4 : 8)
-                          : L3_PAGETABLE_ENTRIES),
-                         PGT_l2_page_table) )
+    if ( page_order == 18 )
+    {
+        p2m_entry = p2m_find_entry(table, &gfn_remainder, gfn,
+                                   L3_PAGETABLE_SHIFT - PAGE_SHIFT,
+                                   L3_PAGETABLE_ENTRIES);
+        ASSERT(p2m_entry);
+        if ( (l1e_get_flags(*p2m_entry) & _PAGE_PRESENT) &&
+             !(l1e_get_flags(*p2m_entry) & _PAGE_PSE) )
+        {
+            P2M_ERROR("configure P2M table L3 entry with large page\n");
+            domain_crash(d);
+            goto out;
+        }
+        
+        if ( mfn_valid(mfn) )
+            l3e_content = l3e_from_pfn(mfn_x(mfn),
+                                       __PAGE_HYPERVISOR|_PAGE_USER|_PAGE_PSE);
+        else
+            l3e_content = l3e_empty();
+        
+        entry_content.l1 = l3e_content.l3;
+        paging_write_p2m_entry(d, gfn, p2m_entry, table_mfn, entry_content, 3);
+
+    }
+    else if ( !p2m_next_level(d, &table_mfn, &table, &gfn_remainder, gfn,
+                              L3_PAGETABLE_SHIFT - PAGE_SHIFT,
+                              ((CONFIG_PAGING_LEVELS == 3)
+                               ? (d->arch.hvm_domain.hap_enabled ? 4 : 8)
+                               : L3_PAGETABLE_ENTRIES),
+                              PGT_l2_page_table) )
         goto out;
 
     if ( page_order == 0 )
@@ -1158,7 +1214,7 @@ p2m_set_entry(struct domain *d, unsigned
         /* level 1 entry */
         paging_write_p2m_entry(d, gfn, p2m_entry, table_mfn, entry_content, 1);
     }
-    else 
+    else if ( page_order == 9 )
     {
         p2m_entry = p2m_find_entry(table, &gfn_remainder, gfn,
                                    L2_PAGETABLE_SHIFT - PAGE_SHIFT,
@@ -1255,11 +1311,32 @@ p2m_gfn_to_mfn(struct domain *d, unsigne
 #else
         l3e += l3_table_offset(addr);
 #endif
+pod_retry_l3:
         if ( (l3e_get_flags(*l3e) & _PAGE_PRESENT) == 0 )
         {
+            if ( p2m_flags_to_type(l3e_get_flags(*l3e)) == p2m_populate_on_demand )
+            {
+                if ( q != p2m_query )
+                {
+                    if ( !p2m_pod_demand_populate(d, gfn, mfn, 
+                                                  (l1_pgentry_t *)l3e, 18, q) )
+                        goto pod_retry_l3;
+                }
+                else
+                    *t = p2m_populate_on_demand;
+            }
             unmap_domain_page(l3e);
             return _mfn(INVALID_MFN);
         }
+        else if ( (l3e_get_flags(*l3e) & _PAGE_PSE) )
+        {
+            mfn = _mfn(l3e_get_pfn(*l3e) +
+                       l2_table_offset(addr) * L1_PAGETABLE_ENTRIES +
+                       l1_table_offset(addr));
+            unmap_domain_page(l3e);
+            return mfn_valid(mfn) ? mfn : _mfn(INVALID_MFN);
+        }
+
         mfn = _mfn(l3e_get_pfn(*l3e));
         unmap_domain_page(l3e);
     }
@@ -1340,10 +1417,58 @@ static mfn_t p2m_gfn_to_mfn_current(unsi
     {
         l1_pgentry_t l1e = l1e_empty(), *p2m_entry;
         l2_pgentry_t l2e = l2e_empty();
+        l3_pgentry_t l3e = l3e_empty();
         int ret;
 
         ASSERT(gfn < (RO_MPT_VIRT_END - RO_MPT_VIRT_START) 
                / sizeof(l1_pgentry_t));
+
+        /*
+         * Read & process L3
+         */
+        p2m_entry = (l1_pgentry_t *)
+            &__linear_l2_table[l2_linear_offset(RO_MPT_VIRT_START)
+                               + l3_linear_offset(addr)];
+    pod_retry_l3:
+        ret = __copy_from_user(&l3e, p2m_entry, sizeof(l3e));
+
+        if ( ret != 0 || !(l3e_get_flags(l3e) & _PAGE_PRESENT) )
+        {
+            if ( (l3e_get_flags(l3e) & _PAGE_PSE) &&
+                 (p2m_flags_to_type(l3e_get_flags(l3e)) == p2m_populate_on_demand) )
+            {
+                /* The read has succeeded, so we know that mapping exists */
+                if ( q != p2m_query )
+                {
+                    if ( !p2m_pod_demand_populate(current->domain, gfn, mfn,
+                                                  p2m_entry, 18, q) )
+                        goto pod_retry_l3;
+                    p2mt = p2m_invalid;
+                    printk("%s: Allocate 1GB failed!\n", __func__);
+                    goto out;
+                }
+                else
+                {
+                    p2mt = p2m_populate_on_demand;
+                    goto out;
+                }
+            }
+            goto pod_retry_l2;
+        }
+
+        if ( l3e_get_flags(l3e) & _PAGE_PSE )
+        {
+            p2mt = p2m_flags_to_type(l3e_get_flags(l3e));
+            ASSERT(l3e_get_pfn(l3e) != INVALID_MFN || !p2m_is_ram(p2mt));
+            if (p2m_is_valid(p2mt) )
+                mfn = _mfn(l3e_get_pfn(l3e) + 
+                           l2_table_offset(addr) * L1_PAGETABLE_ENTRIES + 
+                           l1_table_offset(addr));
+            else
+                p2mt = p2m_mmio_dm;
+            
+            goto out;
+        }
 
         /*
          * Read & process L2
@@ -1499,7 +1624,9 @@ int set_p2m_entry(struct domain *d, unsi
 
     while ( todo )
     {
-        order = (((gfn | mfn_x(mfn) | todo) & ((1ul << 9) - 1)) == 0) ? 9 : 0;
+        order = ( (((gfn | mfn_x(mfn) | todo) & ((1ul << 18) - 1)) == 0) ) ? 
+                18 :
+                (((gfn | mfn_x(mfn) | todo) & ((1ul << 9) - 1)) == 0) ? 9 : 0;
         rc = d->arch.p2m->set_entry(d, gfn, mfn, order, p2mt);
         gfn += 1ul << order;
         if ( mfn_x(mfn) != INVALID_MFN )
@@ -1752,6 +1879,31 @@ static void audit_p2m(struct domain *d)
                     gfn += 1 << (L3_PAGETABLE_SHIFT - PAGE_SHIFT);
                     continue;
                 }
+
+                /* check for 1GB super page */
+                if ( l3e_get_flags(l3e[i3]) & _PAGE_PSE )
+                {
+                    mfn = l3e_get_pfn(l3e[i3]);
+                    ASSERT(mfn_valid(_mfn(mfn)));
+                    /* we have to cover 512x512 4K pages */
+                    for ( i2 = 0; 
+                          i2 < (L2_PAGETABLE_ENTRIES * L1_PAGETABLE_ENTRIES);
+                          i2++)
+                    {
+                        m2pfn = get_gpfn_from_mfn(mfn+i2);
+                        if ( m2pfn != (gfn + i2) )
+                        {
+                            pmbad++;
+                            P2M_PRINTK("mismatch: gfn %#lx -> mfn %#lx"
+                                       " -> gfn %#lx\n", gfn+i2, mfn+i2,
+                                       m2pfn);
+                            BUG();
+                        }
+                        gfn += 1 << (L3_PAGETABLE_SHIFT - PAGE_SHIFT);
+                        continue;
+                    }
+                }
+
                 l2e = map_domain_page(mfn_x(_mfn(l3e_get_pfn(l3e[i3]))));
                 for ( i2 = 0; i2 < L2_PAGETABLE_ENTRIES; i2++ )
                 {
@@ -2080,7 +2232,7 @@ void p2m_change_type_global(struct domai
     l1_pgentry_t l1e_content;
     l1_pgentry_t *l1e;
     l2_pgentry_t *l2e;
-    mfn_t l1mfn, l2mfn;
+    mfn_t l1mfn, l2mfn, l3mfn;
     int i1, i2;
     l3_pgentry_t *l3e;
     int i3;
@@ -2100,6 +2252,7 @@ void p2m_change_type_global(struct domai
 #if CONFIG_PAGING_LEVELS == 4
     l4e = map_domain_page(mfn_x(pagetable_get_mfn(d->arch.phys_table)));
 #else /* CONFIG_PAGING_LEVELS == 3 */
+    l3mfn = _mfn(mfn_x(pagetable_get_mfn(d->arch.phys_table)));
     l3e = map_domain_page(mfn_x(pagetable_get_mfn(d->arch.phys_table)));
 #endif
 
@@ -2110,6 +2263,7 @@ void p2m_change_type_global(struct domai
         {
             continue;
         }
+        l3mfn = _mfn(l4e_get_pfn(l4e[i4]));
         l3e = map_domain_page(l4e_get_pfn(l4e[i4]));
 #endif
         for ( i3 = 0;
@@ -2120,6 +2274,20 @@ void p2m_change_type_global(struct domai
             {
                 continue;
             }
+            if ( (l3e_get_flags(l3e[i3]) & _PAGE_PSE) )
+            {
+                flags = l3e_get_flags(l3e[i3]);
+                if ( p2m_flags_to_type(flags) != ot )
+                    continue;
+                mfn = l3e_get_pfn(l3e[i3]);
+                gfn = get_gpfn_from_mfn(mfn);
+                flags = p2m_type_to_flags(nt);
+                l1e_content = l1e_from_pfn(mfn, flags | _PAGE_PSE);
+                paging_write_p2m_entry(d, gfn, (l1_pgentry_t *)&l3e[i3],
+                                       l3mfn, l1e_content, 3);
+                continue;
+            }
+
             l2mfn = _mfn(l3e_get_pfn(l3e[i3]));
             l2e = map_domain_page(l3e_get_pfn(l3e[i3]));
             for ( i2 = 0; i2 < L2_PAGETABLE_ENTRIES; i2++ )

[-- Attachment #4: 1gb_p2m_pod.patch --]
[-- Type: application/octet-stream, Size: 19926 bytes --]

# HG changeset patch
# User root@weisles1064.amd.com
# Date 1236743681 18000
# Node ID f4a674aef64d5ea00ebb05b4bf5a45ab32a4ce25
# Parent  bacd2a71b6caadc18031e057edcbf69b45c4b8ec
Xen 1GB nested page table: PoD patches

diff -r bacd2a71b6ca -r f4a674aef64d xen/arch/x86/mm/p2m.c
--- a/xen/arch/x86/mm/p2m.c	Tue Mar 10 22:09:22 2009 -0500
+++ b/xen/arch/x86/mm/p2m.c	Tue Mar 10 22:54:41 2009 -0500
@@ -335,17 +335,19 @@ p2m_pod_cache_add(struct domain *d,
     /* Then add the first one to the appropriate populate-on-demand list */
     switch(order)
     {
+    case 18:
+        page_list_add_tail(page, &p2md->pod.super1gb);
+        break;
     case 9:
-        page_list_add_tail(page, &p2md->pod.super); /* lock: page_alloc */
-        p2md->pod.count += 1 << order;
+        page_list_add_tail(page, &p2md->pod.super2mb); /* lock: page_alloc */
         break;
     case 0:
         page_list_add_tail(page, &p2md->pod.single); /* lock: page_alloc */
-        p2md->pod.count += 1 ;
         break;
     default:
         BUG();
     }
+    p2md->pod.count += 1 << order;
 
     spin_unlock(&d->page_alloc_lock);
 
@@ -353,33 +355,66 @@ p2m_pod_cache_add(struct domain *d,
 }
 
 /* Get a page of size order from the populate-on-demand cache.  Will break
- * down 2-meg pages into singleton pages automatically.  Returns null if
+ * down superpages into singleton pages automatically.  Returns null if
  * a superpage is requested and no superpages are available.  Must be called
  * with the d->page_lock held. */
 static struct page_info * p2m_pod_cache_get(struct domain *d,
                                             unsigned long order)
 {
     struct p2m_domain *p2md = d->arch.p2m;
-    struct page_info *p = NULL;
+    struct page_info *p = NULL, *q;
+    unsigned long mfn;
     int i;
 
-    if ( order == 9 && page_list_empty(&p2md->pod.super) )
+    if ( order == 18 && page_list_empty(&p2md->pod.super1gb) )
     {
         return NULL;
     }
+
+    if ( order == 9 && page_list_empty(&p2md->pod.super2mb) )
+    {
+        /* split 1GB page into 2MB pages */
+        if ( !page_list_empty(&p2md->pod.super1gb) )
+        {
+            printk("%s: breaking up 1GB page into 2MB pages.\n", __func__);
+            p = page_list_remove_head(&p2md->pod.super1gb);
+            mfn = mfn_x(page_to_mfn(p));
+            
+            for ( i = 0; i < (1<<9); i++ )
+            {
+                q = mfn_to_page(_mfn(mfn + (i<<9)));
+                page_list_add_tail(q, &p2md->pod.super2mb);
+            }
+        }
+        else
+            return NULL;
+    }
     else if ( order == 0 && page_list_empty(&p2md->pod.single) )
     {
-        unsigned long mfn;
-        struct page_info *q;
-
-        BUG_ON( page_list_empty(&p2md->pod.super) );
-
+        BUG_ON( page_list_empty(&p2md->pod.super2mb) &&
+                page_list_empty(&p2md->pod.super1gb) );
+
+        if ( !page_list_empty(&p2md->pod.super1gb) &&
+             page_list_empty(&p2md->pod.super2mb) )
+        {
+            printk("%s: breaking up 1GB page into 2MB pages.\n", __func__);
+            p = page_list_remove_head(&p2md->pod.super1gb);
+            mfn = mfn_x(page_to_mfn(p));
+            
+            for ( i = 0; i < (1<<9); i++ )
+            {
+                q = mfn_to_page(_mfn(mfn + (i<<9)));
+                page_list_add_tail(q, &p2md->pod.super2mb);
+            }            
+        }
+
+        
         /* Break up a superpage to make single pages. NB count doesn't
          * need to be adjusted. */
-        printk("%s: Breaking up superpage.\n", __func__);
-        p = page_list_remove_head(&p2md->pod.super);
+        printk("%s: breaking up 2MB page into 4KB pages.\n", __func__);
+        p = page_list_remove_head(&p2md->pod.super2mb);
         mfn = mfn_x(page_to_mfn(p));
-
+            
         for ( i=0; i<(1<<9); i++ )
         {
             q = mfn_to_page(_mfn(mfn+i));
@@ -389,19 +424,22 @@ static struct page_info * p2m_pod_cache_
 
     switch ( order )
     {
+    case 18:
+        BUG_ON( page_list_empty(&p2md->pod.super1gb) );
+        p = page_list_remove_head(&p2md->pod.super1gb);
+        break;
     case 9:
-        BUG_ON( page_list_empty(&p2md->pod.super) );
-        p = page_list_remove_head(&p2md->pod.super);
-        p2md->pod.count -= 1 << order; /* Lock: page_alloc */
+        BUG_ON( page_list_empty(&p2md->pod.super2mb) );
+        p = page_list_remove_head(&p2md->pod.super2mb);
         break;
     case 0:
         BUG_ON( page_list_empty(&p2md->pod.single) );
         p = page_list_remove_head(&p2md->pod.single);
-        p2md->pod.count -= 1;
         break;
     default:
         BUG();
     }
+    p2md->pod.count -= 1 << order; /* Lock: page_alloc */
 
     /* Put the pages back on the domain page_list */
     for ( i = 0 ; i < (1 << order) ; i++ )
@@ -426,14 +464,25 @@ p2m_pod_set_cache_target(struct domain *
         struct page_info * page;
         int order;
 
-        if ( (pod_target - p2md->pod.count) >= (1>>9) )
+        if ( (pod_target - p2md->pod.count) >= (1>>18) )
+            order = 18;
+        else if ( (pod_target - p2md->pod.count) >= (1>>9) )
             order = 9;
         else
             order = 0;
 
+increase_try_another_order:
         page = alloc_domheap_pages(d, order, 0);
-        if ( unlikely(page == NULL) )
-            goto out;
+        if ( unlikely(page == NULL) ) 
+        {
+            if ( order > 0 )
+            {
+                order -= 9;
+                goto increase_try_another_order;
+            }
+            else
+                goto out;
+        }
 
         p2m_pod_cache_add(d, page, order);
     }
@@ -446,19 +495,31 @@ p2m_pod_set_cache_target(struct domain *
         struct page_info * page;
         int order, i;
 
-        /* Grab the lock before checking that pod.super is empty, or the last
-         * entries may disappear before we grab the lock. */
+        /* Grab the lock before checking that pod.super2mb is empty, or the 
+         * last entries may disappear before we grab the lock. */
         spin_lock(&d->page_alloc_lock);
 
-        if ( (p2md->pod.count - pod_target) > (1>>9)
-             && !page_list_empty(&p2md->pod.super) )
+        
+        if ( (p2md->pod.count - pod_target) > (1>>18) )
+            order = 18;
+        else if ( (p2md->pod.count - pod_target) > (1>>9) )
             order = 9;
         else
             order = 0;
 
+decrease_try_another_order:
         page = p2m_pod_cache_get(d, order);
-
-        ASSERT(page != NULL);
+        if ( unlikely(page == NULL) )
+        {
+            if ( order > 0 )
+            {
+                order -= 9;
+                goto decrease_try_another_order;
+            }
+            else
+                goto out;
+        }
+        
 
         spin_unlock(&d->page_alloc_lock);
 
@@ -565,7 +626,20 @@ p2m_pod_empty_cache(struct domain *d)
 
     spin_lock(&d->page_alloc_lock);
 
-    while ( (page = page_list_remove_head(&p2md->pod.super)) )
+    while ( (page = page_list_remove_head(&p2md->pod.super1gb)) )
+    {
+        int i;
+            
+        for ( i = 0 ; i < (1 << 18) ; i++ )
+        {
+            BUG_ON(page_get_owner(page + i) != d);
+            page_list_add_tail(page + i, &d->page_list);
+        }
+
+        p2md->pod.count -= 1<<18;
+    }
+
+    while ( (page = page_list_remove_head(&p2md->pod.super2mb)) )
     {
         int i;
             
@@ -726,12 +800,12 @@ p2m_pod_dump_data(struct domain *d)
            p2md->pod.entry_count, p2md->pod.count);
 }
 
-#define superpage_aligned(_x)  (((_x)&((1<<9)-1))==0)
-
-/* Search for all-zero superpages to be reclaimed as superpages for the
+
+/* Search for all-zero 1GB superpages to be reclaimed as superpages for the
  * PoD cache. Must be called w/ p2m lock held, page_alloc lock not held. */
+#define superpage_1gb_aligned(_x)  (((_x)&((1<<18)-1))==0)
 static int
-p2m_pod_zero_check_superpage(struct domain *d, unsigned long gfn)
+p2m_pod_zero_check_superpage_1gb(struct domain *d, unsigned long gfn)
 {
     mfn_t mfn, mfn0 = _mfn(INVALID_MFN);
     p2m_type_t type, type0 = 0;
@@ -740,7 +814,7 @@ p2m_pod_zero_check_superpage(struct doma
     int i, j;
     int max_ref = 1;
 
-    if ( !superpage_aligned(gfn) )
+    if ( !superpage_1gb_aligned(gfn) )
         goto out;
 
     /* Allow an extra refcount for one shadow pt mapping in shadowed domains */
@@ -749,7 +823,7 @@ p2m_pod_zero_check_superpage(struct doma
 
     /* Look up the mfns, checking to make sure they're the same mfn
      * and aligned, and mapping them. */
-    for ( i=0; i<(1<<9); i++ )
+    for ( i=0; i<(1<<18); i++ )
     {
         
         mfn = gfn_to_mfn_query(d, gfn + i, &type);
@@ -776,7 +850,127 @@ p2m_pod_zero_check_superpage(struct doma
              || ( (mfn_to_page(mfn)->count_info & PGC_allocated) == 0 )
              || ( (mfn_to_page(mfn)->count_info & PGC_page_table) != 0 )
              || ( (mfn_to_page(mfn)->count_info & PGC_count_mask) > max_ref )
-             || !( ( i == 0 && superpage_aligned(mfn_x(mfn0)) )
+             || !( ( i == 0 && superpage_1gb_aligned(mfn_x(mfn0)) )
+                   || ( i != 0 && mfn_x(mfn) == (mfn_x(mfn0) + i) ) ) )
+            goto out;
+    }
+
+    /* Now, do a quick check to see if it may be zero before unmapping. */
+    for ( i=0; i<(1<<18); i++ )
+    {
+        /* Quick zero-check */
+        map = map_domain_page(mfn_x(mfn0) + i);
+
+        for ( j=0; j<16; j++ )
+            if( *(map+j) != 0 )
+                break;
+
+        unmap_domain_page(map);
+
+        if ( j < 16 )
+            goto out;
+
+    }
+
+    /* Try to remove the page, restoring old mapping if it fails. */
+    set_p2m_entry(d, gfn,
+                  _mfn(POPULATE_ON_DEMAND_MFN), 18,
+                  p2m_populate_on_demand);
+
+    /* Make none of the MFNs are used elsewhere... for example, mapped
+     * via the grant table interface, or by qemu.  Allow one refcount for
+     * being allocated to the domain. */
+    for ( i=0; i < (1<<18); i++ )
+    {
+        mfn = _mfn(mfn_x(mfn0) + i);
+        if ( (mfn_to_page(mfn)->count_info & PGC_count_mask) > 1 )
+        {
+            reset = 1;
+            goto out_reset;
+        }
+    }
+
+    /* Finally, do a full zero-check */
+    for ( i=0; i < (1<<18); i++ )
+    {
+        map = map_domain_page(mfn_x(mfn0) + i);
+
+        for ( j=0; j<PAGE_SIZE/sizeof(*map); j++ )
+            if( *(map+j) != 0 )
+            {
+                reset = 1;
+                break;
+            }
+
+        unmap_domain_page(map);
+
+        if ( reset )
+            goto out_reset;
+    }
+
+    /* Finally!  We've passed all the checks, and can add the mfn superpage
+     * back on the PoD cache, and account for the new p2m PoD entries */
+    p2m_pod_cache_add(d, mfn_to_page(mfn0), 18);
+    d->arch.p2m->pod.entry_count += (1<<18);
+
+out_reset:
+    if ( reset )
+        set_p2m_entry(d, gfn, mfn0, 18, type0);
+    
+out:
+    return ret;
+}
+
+/* Search for all-zero 2MB superpages to be reclaimed as superpages for the
+ * PoD cache. Must be called w/ p2m lock held, page_alloc lock not held. */
+#define superpage_2mb_aligned(_x)  (((_x)&((1<<9)-1))==0)
+static int
+p2m_pod_zero_check_superpage_2mb(struct domain *d, unsigned long gfn)
+{
+    mfn_t mfn, mfn0 = _mfn(INVALID_MFN);
+    p2m_type_t type, type0 = 0;
+    unsigned long * map = NULL;
+    int ret=0, reset = 0;
+    int i, j;
+    int max_ref = 1;
+
+    if ( !superpage_2mb_aligned(gfn) )
+        goto out;
+
+    /* Allow an extra refcount for one shadow pt mapping in shadowed domains */
+    if ( paging_mode_shadow(d) )
+        max_ref++;
+
+    /* Look up the mfns, checking to make sure they're the same mfn
+     * and aligned, and mapping them. */
+    for ( i=0; i<(1<<9); i++ )
+    {
+        
+        mfn = gfn_to_mfn_query(d, gfn + i, &type);
+
+        if ( i == 0 )
+        {
+            mfn0 = mfn;
+            type0 = type;
+        }
+
+        /* Conditions that must be met for superpage-superpage:
+         * + All gfns are ram types
+         * + All gfns have the same type
+         * + All of the mfns are allocated to a domain
+         * + None of the mfns are used as pagetables
+         * + The first mfn is 2-meg aligned
+         * + All the other mfns are in sequence
+         * Adding for good measure:
+         * + None of the mfns are likely to be mapped elsewhere (refcount
+         *   2 or less for shadow, 1 for hap)
+         */
+        if ( !p2m_is_ram(type)
+             || type != type0
+             || ( (mfn_to_page(mfn)->count_info & PGC_allocated) == 0 )
+             || ( (mfn_to_page(mfn)->count_info & PGC_page_table) != 0 )
+             || ( (mfn_to_page(mfn)->count_info & PGC_count_mask) > max_ref )
+             || !( ( i == 0 && superpage_2mb_aligned(mfn_x(mfn0)) )
                    || ( i != 0 && mfn_x(mfn) == (mfn_x(mfn0) + i) ) ) )
             goto out;
     }
@@ -943,35 +1137,66 @@ p2m_pod_zero_check(struct domain *d, uns
     
 }
 
+
 #define POD_SWEEP_LIMIT 1024
 static void
-p2m_pod_emergency_sweep_super(struct domain *d)
+p2m_pod_emergency_sweep_super_1gb(struct domain *d)
 {
     struct p2m_domain *p2md = d->arch.p2m;
     unsigned long i, start, limit;
 
-    if ( p2md->pod.reclaim_super == 0 )
-    {
-        p2md->pod.reclaim_super = (p2md->pod.max_guest>>9)<<9;
-        p2md->pod.reclaim_super -= (1<<9);
+    if ( p2md->pod.reclaim_super_1gb == 0 )
+    {
+        p2md->pod.reclaim_super_1gb = (p2md->pod.max_guest>>18)<<18;
+        p2md->pod.reclaim_super_1gb -= (1<<18);
     }
     
-    start = p2md->pod.reclaim_super;
+    start = p2md->pod.reclaim_super_1gb;
     limit = (start > POD_SWEEP_LIMIT) ? (start - POD_SWEEP_LIMIT) : 0;
 
-    for ( i=p2md->pod.reclaim_super ; i > 0 ; i-=(1<<9) )
-    {
-        p2m_pod_zero_check_superpage(d, i);
+    for ( i=p2md->pod.reclaim_super_1gb ; i > 0 ; i-=(1<<18) )
+    {
+        p2m_pod_zero_check_superpage_1gb(d, i);
         /* Stop if we're past our limit and we have found *something*.
          *
          * NB that this is a zero-sum game; we're increasing our cache size
          * by increasing our 'debt'.  Since we hold the p2m lock,
          * (entry_count - count) must remain the same. */
-        if ( !page_list_empty(&p2md->pod.super) &&  i < limit )
+        if ( !page_list_empty(&p2md->pod.super1gb) &&  i < limit )
             break;
     }
 
-    p2md->pod.reclaim_super = i ? i - (1<<9) : 0;
+    p2md->pod.reclaim_super_1gb = i ? i - (1<<18) : 0;
+}
+
+static void
+p2m_pod_emergency_sweep_super_2mb(struct domain *d)
+{
+    struct p2m_domain *p2md = d->arch.p2m;
+    unsigned long i, start, limit;
+
+    if ( p2md->pod.reclaim_super_2mb == 0 )
+    {
+        p2md->pod.reclaim_super_2mb = (p2md->pod.max_guest>>9)<<9;
+        p2md->pod.reclaim_super_2mb -= (1<<9);
+    }
+    
+    start = p2md->pod.reclaim_super_2mb;
+    limit = (start > POD_SWEEP_LIMIT) ? (start - POD_SWEEP_LIMIT) : 0;
+
+    for ( i=p2md->pod.reclaim_super_2mb ; i > 0 ; i-=(1<<9) )
+    {
+        p2m_pod_zero_check_superpage_2mb(d, i);
+        /* Stop if we're past our limit and we have found *something*.
+         *
+         * NB that this is a zero-sum game; we're increasing our cache size
+         * by increasing our 'debt'.  Since we hold the p2m lock,
+         * (entry_count - count) must remain the same. */
+        if ( !page_list_empty(&p2md->pod.super2mb) &&  i < limit )
+            break;
+    }
+
+    p2md->pod.reclaim_super_2mb = i ? i - (1<<9) : 0;
 
 }
 
@@ -1049,13 +1274,17 @@ p2m_pod_demand_populate(struct domain *d
         return 0;
     }
 
+    /* start a sweep for 1gb page */
+    if ( order == 18 && page_list_empty(&p2md->pod.super1gb) )
+        p2m_pod_emergency_sweep_super_1gb(d);
+
     /* If we're low, start a sweep */
-    if ( order == 9 && page_list_empty(&p2md->pod.super) )
-        p2m_pod_emergency_sweep_super(d);
+    if ( order == 9 && page_list_empty(&p2md->pod.super2mb) )
+        p2m_pod_emergency_sweep_super_2mb(d);
 
     if ( page_list_empty(&p2md->pod.single) &&
          ( ( order == 0 )
-           || (order == 9 && page_list_empty(&p2md->pod.super) ) ) )
+           || (order == 9 && page_list_empty(&p2md->pod.super2mb) ) ) )
         p2m_pod_emergency_sweep(d);
 
     /* Keep track of the highest gfn demand-populated by a guest fault */
@@ -1081,6 +1310,15 @@ p2m_pod_demand_populate(struct domain *d
     /* Fill in the entry in the p2m */
     switch ( order )
     {
+    case 18:
+    {
+        l3_pgentry_t l3e_content;
+        
+        l3e_content = l3e_from_pfn(mfn_x(mfn),
+                                   p2m_type_to_flags(p2m_ram_rw) | _PAGE_PSE);
+        entry_content.l1 = l3e_content.l3;
+    }
+    break;
     case 9:
     {
         l2_pgentry_t l2e_content;
@@ -1101,7 +1339,8 @@ p2m_pod_demand_populate(struct domain *d
     gfn_aligned = (gfn >> order) << order;
 
     paging_write_p2m_entry(d, gfn_aligned, p2m_entry, table_mfn,
-                           entry_content, (order==9)?2:1);
+                           entry_content, 
+                           (order==18) ? 3:(order==9) ? 2:1);
 
     for( i = 0 ; i < (1UL << order) ; i++ )
         set_gpfn_from_mfn(mfn_x(mfn) + i, gfn_aligned + i);
@@ -1120,14 +1359,24 @@ out_of_memory:
     domain_crash(d);
     return -1;
 remap_and_retry:
-    BUG_ON(order != 9);
+    BUG_ON(order != 9 && order != 18);
     spin_unlock(&d->page_alloc_lock);
 
-    /* Remap this 2-meg region in singleton chunks */
-    gfn_aligned = (gfn>>order)<<order;
-    for(i=0; i<(1<<order); i++)
-        set_p2m_entry(d, gfn_aligned+i, _mfn(POPULATE_ON_DEMAND_MFN), 0,
-                      p2m_populate_on_demand);
+    /* Remap this super region in smaller chunks */
+    if ( order == 18 )
+    {
+        gfn_aligned = (gfn>>order)<<order;
+        for(i=0; i<(1<<9); i++)
+            set_p2m_entry(d, gfn_aligned+(i<<9), _mfn(POPULATE_ON_DEMAND_MFN),
+                          9, p2m_populate_on_demand);
+    }
+    else if ( order == 9 )
+    {
+        gfn_aligned = (gfn>>order)<<order;
+        for(i=0; i<(1<<order); i++)
+            set_p2m_entry(d, gfn_aligned+i, _mfn(POPULATE_ON_DEMAND_MFN), 0,
+                          p2m_populate_on_demand);
+    }
     audit_p2m(d);
     p2m_unlock(p2md);
     return 0;
@@ -1589,7 +1838,8 @@ int p2m_init(struct domain *d)
     memset(p2m, 0, sizeof(*p2m));
     p2m_lock_init(p2m);
     INIT_PAGE_LIST_HEAD(&p2m->pages);
-    INIT_PAGE_LIST_HEAD(&p2m->pod.super);
+    INIT_PAGE_LIST_HEAD(&p2m->pod.super1gb);
+    INIT_PAGE_LIST_HEAD(&p2m->pod.super2mb);
     INIT_PAGE_LIST_HEAD(&p2m->pod.single);
 
     p2m->set_entry = p2m_set_entry;
diff -r bacd2a71b6ca -r f4a674aef64d xen/include/asm-x86/p2m.h
--- a/xen/include/asm-x86/p2m.h	Tue Mar 10 22:09:22 2009 -0500
+++ b/xen/include/asm-x86/p2m.h	Tue Mar 10 22:54:41 2009 -0500
@@ -148,11 +148,13 @@ struct p2m_domain {
      *   protect moving stuff from the PoD cache to the domain page list.
      */
     struct {
-        struct page_list_head super,   /* List of superpages                */
+        struct page_list_head super1gb,/* List of 1GB superpages            */
+                         super2mb,     /* list of 2MB superpages            */
                          single;       /* Non-super lists                   */
         int              count,        /* # of pages in cache lists         */
                          entry_count;  /* # of pages in p2m marked pod      */
-        unsigned         reclaim_super; /* Last gpfn of a scan */
+        unsigned         reclaim_super_1gb; /* Last gpfn of a 1GB scan */
+        unsigned         reclaim_super_2mb; /* last gpfn of a 2MB scan */
         unsigned         reclaim_single; /* Last gpfn of a scan */
         unsigned         max_guest;    /* gpfn of max guest demand-populate */
     } pod;

[-- Attachment #5: Type: text/plain, Size: 138 bytes --]

_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xensource.com
http://lists.xensource.com/xen-devel

^ permalink raw reply	[flat|nested] 23+ messages in thread

end of thread, other threads:[~2010-01-14  1:36 UTC | newest]

Thread overview: 23+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2009-03-18 15:48 [RFC][Patches] Xen 1GB Page Table Support Huang2, Wei
2009-03-18 17:20 ` George Dunlap
2009-03-18 17:32   ` Keir Fraser
2009-03-18 17:45     ` Huang2, Wei
2009-03-18 19:15       ` Keir Fraser
2009-03-18 17:37   ` Huang2, Wei
2009-03-19  8:07   ` Huang2, Wei
2009-03-19 14:17     ` Dan Magenheimer
2009-03-19 18:51       ` Wei Huang
2009-03-19 19:56         ` Dan Magenheimer
2009-03-19 21:07           ` Wei Huang
2009-03-20  9:45           ` George Dunlap
2009-03-20 13:40             ` Dan Magenheimer
2009-03-20 13:56               ` Wei Huang
2009-03-20 13:59               ` Gianluca Guida
2009-03-20 14:25                 ` George Dunlap
2009-03-20 14:21                   ` Gianluca Guida
2009-03-20 18:16                     ` Gianluca Guida
2009-03-20 18:32                       ` Huang2, Wei
2009-05-19  0:55     ` Keir Fraser
2010-01-13  4:07     ` Xu, Dongxiao
2010-01-13 16:27       ` Wei Huang
2010-01-14  1:36         ` Xu, Dongxiao

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.