[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Xen-changelog] This patch is to boot 32-bit VMX guest on the 64-bit host.



# HG changeset patch
# User kaf24@xxxxxxxxxxxxxxxxxxxx
# Node ID 8b87d43412bf79367c57ce65da3aed124061c9cc
# Parent  95cfc001ddd1befa7af36067b7505f2ba119a3b5
This patch is to boot 32-bit VMX guest on the 64-bit host.
Double-compile is used to make both 64-bit guest and 32-bit guest can
work, the shadow page-table uses current 64-bit shadow code's structure
to simulate 32-bit guest's 2-level page-table.

Signed-off-by: Chengyuan Li <chengyuan.li@xxxxxxxxx>
Signed-off-by: Xiaohui Xin  <xiaohui.xin@xxxxxxxxx>
Signed-off-by: Jun Nakajima <jun.nakajima@xxxxxxxxx>

diff -r 95cfc001ddd1 -r 8b87d43412bf xen/arch/x86/Makefile
--- a/xen/arch/x86/Makefile     Fri Sep  2 09:02:13 2005
+++ b/xen/arch/x86/Makefile     Fri Sep  2 09:43:32 2005
@@ -17,7 +17,7 @@
 
 OBJS := $(patsubst shadow%.o,,$(OBJS)) # drop all
 ifeq ($(TARGET_SUBARCH),x86_64) 
- OBJS += shadow.o shadow_public.o      # x86_64: new code
+ OBJS += shadow.o shadow_public.o shadow_guest32.o     # x86_64: new code
 endif
 ifeq ($(TARGET_SUBARCH),x86_32) 
  ifneq ($(pae),n)
diff -r 95cfc001ddd1 -r 8b87d43412bf xen/arch/x86/shadow.c
--- a/xen/arch/x86/shadow.c     Fri Sep  2 09:02:13 2005
+++ b/xen/arch/x86/shadow.c     Fri Sep  2 09:43:32 2005
@@ -53,6 +53,9 @@
     struct domain *d, unsigned long gpfn, unsigned long gmfn);
 static void shadow_map_into_current(struct vcpu *v,
     unsigned long va, unsigned int from, unsigned int to);
+static inline void validate_bl2e_change( struct domain *d,
+       guest_root_pgentry_t *new_gle_p, pgentry_64_t *shadow_l3, int index);
+
 #endif
 
 /********
@@ -217,10 +220,38 @@
         }
         else
         {
-            page = alloc_domheap_page(NULL);
-            void *l1 = map_domain_page(page_to_pfn(page));
-            memset(l1, 0, PAGE_SIZE);
-            unmap_domain_page(l1);
+            if (d->arch.ops->guest_paging_levels == PAGING_L2)
+            {
+#if CONFIG_PAGING_LEVELS >= 4
+                /* For 32-bit VMX guest, 2 shadow L1s to simulate 1 guest L1
+                 * So need allocate 2 continues shadow L1 each time.
+                 */
+                page = alloc_domheap_pages(NULL, SL1_ORDER, 0);
+                if (!page)
+                    domain_crash_synchronous();
+
+                void *l1_0 = map_domain_page(page_to_pfn(page));
+                memset(l1_0,0,PAGE_SIZE);
+                unmap_domain_page(l1_0);
+                void *l1_1 = map_domain_page(page_to_pfn(page+1));
+                memset(l1_1,0,PAGE_SIZE);
+                unmap_domain_page(l1_1);
+#else
+                page = alloc_domheap_page(NULL);
+                if (!page)
+                    domain_crash_synchronous();
+                void *l1 = map_domain_page(page_to_pfn(page));
+                memset(l1, 0, PAGE_SIZE);
+                unmap_domain_page(l1);
+#endif
+            }
+            else
+            {
+                page = alloc_domheap_page(NULL);
+                void *l1 = map_domain_page(page_to_pfn(page));
+                memset(l1, 0, PAGE_SIZE);
+                unmap_domain_page(l1);
+            }
         }
     }
     else {
@@ -331,7 +362,21 @@
   fail:
     FSH_LOG("promotion of pfn=%lx mfn=%lx failed!  external gnttab refs?",
             gpfn, gmfn);
-    free_domheap_page(page);
+    if (psh_type == PGT_l1_shadow)
+    {
+        if (d->arch.ops->guest_paging_levels == PAGING_L2)
+        {
+#if CONFIG_PAGING_LEVELS >=4
+            free_domheap_pages(page, SL1_ORDER);
+#else
+            free_domheap_page(page);
+#endif
+        }
+        else
+            free_domheap_page(page);
+    }
+    else
+        free_domheap_page(page);
     return 0;
 }
 
@@ -478,8 +523,10 @@
 { 
     struct vcpu *v = current;
     struct domain *d = v->domain;
-    l1_pgentry_t *gpl1e, *spl1e;
-    l2_pgentry_t gl2e, sl2e;
+    l1_pgentry_t *spl1e;
+    l2_pgentry_t sl2e;
+    guest_l1_pgentry_t *gpl1e;
+    guest_l2_pgentry_t gl2e;
     unsigned long gl1pfn, gl1mfn, sl1mfn;
     int i, init_table = 0;
 
@@ -523,28 +570,49 @@
     ASSERT( !(l2e_get_flags(old_sl2e) & _PAGE_PRESENT) );
 #endif
 
-    if ( !get_shadow_ref(sl1mfn) )
-        BUG();
-    l2pde_general(d, &gl2e, &sl2e, sl1mfn);
-    __guest_set_l2e(v, va, &gl2e);
-    __shadow_set_l2e(v, va, &sl2e);
+#if CONFIG_PAGING_LEVELS >=4
+    if (d->arch.ops->guest_paging_levels == PAGING_L2)
+    {
+        /* for 32-bit VMX guest on 64-bit host, 
+         * need update two L2 entries each time
+         */
+        if ( !get_shadow_ref(sl1mfn))
+                BUG();
+        l2pde_general(d, &gl2e, &sl2e, sl1mfn);
+        __guest_set_l2e(v, va, &gl2e);
+        __shadow_set_l2e(v, va & ~((1<<L2_PAGETABLE_SHIFT_32) - 1), &sl2e);
+        if ( !get_shadow_ref(sl1mfn+1))
+            BUG();
+        sl2e = l2e_empty();
+        l2pde_general(d, &gl2e, &sl2e, sl1mfn+1);
+        __shadow_set_l2e(v,((va & ~((1<<L2_PAGETABLE_SHIFT_32) - 1)) + (1 << 
L2_PAGETABLE_SHIFT)) , &sl2e);
+    } else
+#endif
+    {
+        if ( !get_shadow_ref(sl1mfn) )
+            BUG();
+        l2pde_general(d, &gl2e, &sl2e, sl1mfn);
+        __guest_set_l2e(v, va, &gl2e);
+        __shadow_set_l2e(v, va , &sl2e);
+    }
 
     if ( init_table )
     {
         l1_pgentry_t sl1e;
-        int index = l1_table_offset(va);
+        int index = guest_l1_table_offset(va);
         int min = 1, max = 0;
         
         unsigned long entries, pt_va;
         l1_pgentry_t tmp_sl1e;
-        l1_pgentry_t tmp_gl1e;//Prepare for double compile
-
-
-        entries = PAGE_SIZE / sizeof(l1_pgentry_t);
+        guest_l1_pgentry_t tmp_gl1e;//Prepare for double compile
+
+
+        entries = PAGE_SIZE / sizeof(guest_l1_pgentry_t);
         pt_va = ((va >> L1_PAGETABLE_SHIFT) & ~(entries - 1)) << 
L1_PAGETABLE_SHIFT;
-        gpl1e = (l1_pgentry_t *) __guest_get_l1e(v, pt_va, &tmp_gl1e);
-
-        entries = PAGE_SIZE / sizeof(l1_pgentry_t);
+        gpl1e = (guest_l1_pgentry_t *) __guest_get_l1e(v, pt_va, &tmp_gl1e);
+
+        /* If the PGT_l1_shadow has two continual pages */
+        entries = PAGE_SIZE / sizeof(guest_l1_pgentry_t); //1024 entry!!!
         pt_va = ((va >> L1_PAGETABLE_SHIFT) & ~(entries - 1)) << 
L1_PAGETABLE_SHIFT;
         spl1e = (l1_pgentry_t *) __shadow_get_l1e(v, pt_va, &tmp_sl1e);
 
@@ -555,7 +623,7 @@
         spl1e = &(shadow_linear_pg_table[l1_linear_offset(va) &
                                      ~(L1_PAGETABLE_ENTRIES-1)]);*/
 
-        for ( i = 0; i < L1_PAGETABLE_ENTRIES; i++ )
+        for ( i = 0; i < GUEST_L1_PAGETABLE_ENTRIES; i++ )
         {
             l1pte_propagate_from_guest(d, gpl1e[i], &sl1e);
             if ( (l1e_get_flags(sl1e) & _PAGE_PRESENT) &&
@@ -584,7 +652,7 @@
     }
 }
 
-static void 
+static void
 shadow_set_l1e(unsigned long va, l1_pgentry_t new_spte, int create_l1_shadow)
 {
     struct vcpu *v = current;
@@ -616,7 +684,7 @@
                 perfc_incrc(shadow_set_l1e_unlinked);
                 if ( !get_shadow_ref(sl1mfn) )
                     BUG();
-                l2pde_general(d, &gpde, &sl2e, sl1mfn);
+                l2pde_general(d, (guest_l2_pgentry_t *)&gpde, &sl2e, sl1mfn);
                 __guest_set_l2e(v, va, &gpde);
                 __shadow_set_l2e(v, va, &sl2e);
             }
@@ -651,6 +719,7 @@
     shadow_update_min_max(l2e_get_pfn(sl2e), l1_table_offset(va));
 }
 
+#if CONFIG_PAGING_LEVELS <= 3
 static void shadow_invlpg_32(struct vcpu *v, unsigned long va)
 {
     struct domain *d = v->domain;
@@ -679,6 +748,7 @@
 
     shadow_unlock(d);
 }
+#endif
 
 static struct out_of_sync_entry *
 shadow_alloc_oos_entry(struct domain *d)
@@ -759,8 +829,8 @@
     length = max - min + 1;
     perfc_incr_histo(snapshot_copies, length, PT_UPDATES);
 
-    min *= sizeof(l1_pgentry_t);
-    length *= sizeof(l1_pgentry_t);
+    min *= sizeof(guest_l1_pgentry_t);
+    length *= sizeof(guest_l1_pgentry_t);
 
     original = map_domain_page(gmfn);
     snapshot = map_domain_page(smfn);
@@ -841,7 +911,7 @@
 
         __shadow_get_l4e(v, va, &sl4e);
         if ( !(l4e_get_flags(sl4e) & _PAGE_PRESENT)) {
-            shadow_map_into_current(v, va, L3, L4);
+            shadow_map_into_current(v, va, PAGING_L3, PAGING_L4);
         }
 
         if (!__shadow_get_l3e(v, va, &sl3e)) {
@@ -849,7 +919,7 @@
         }
 
         if ( !(l3e_get_flags(sl3e) & _PAGE_PRESENT)) {
-            shadow_map_into_current(v, va, L2, L3);
+            shadow_map_into_current(v, va, PAGING_L2, PAGING_L3);
         }
     }
 #endif
@@ -887,11 +957,11 @@
  * Returns 0 otherwise.
  */
 static int snapshot_entry_matches(
-    struct domain *d, l1_pgentry_t *guest_pt,
+    struct domain *d, guest_l1_pgentry_t *guest_pt,
     unsigned long gpfn, unsigned index)
 {
     unsigned long smfn = __shadow_status(d, gpfn, PGT_snapshot);
-    l1_pgentry_t *snapshot, gpte; // could be L1s or L2s or ...
+    guest_l1_pgentry_t *snapshot, gpte; // could be L1s or L2s or ...
     int entries_match;
 
     perfc_incrc(snapshot_entry_matches_calls);
@@ -908,7 +978,7 @@
     // This could probably be smarter, but this is sufficent for
     // our current needs.
     //
-    entries_match = !l1e_has_changed(gpte, snapshot[index],
+    entries_match = !guest_l1e_has_changed(gpte, snapshot[index],
                                      PAGE_FLAG_MASK);
 
     unmap_domain_page(snapshot);
@@ -936,10 +1006,10 @@
     unsigned long l2mfn = pagetable_get_pfn(v->arch.guest_table);
 #endif
     unsigned long l2pfn = __mfn_to_gpfn(d, l2mfn);
-    l2_pgentry_t l2e;
+    guest_l2_pgentry_t l2e;
     unsigned long l1pfn, l1mfn;
-    l1_pgentry_t *guest_pt;
-    l1_pgentry_t tmp_gle;
+    guest_l1_pgentry_t *guest_pt;
+    guest_l1_pgentry_t tmp_gle;
     unsigned long pt_va;
 
     ASSERT(shadow_lock_is_acquired(d));
@@ -948,7 +1018,7 @@
     perfc_incrc(shadow_out_of_sync_calls);
 
 #if CONFIG_PAGING_LEVELS >= 4
-    if (d->arch.ops->guest_paging_levels == L4) { /* Mode F */
+    if (d->arch.ops->guest_paging_levels == PAGING_L4) { /* Mode F */
         pgentry_64_t le;
         unsigned long gmfn;
         unsigned long gpfn;
@@ -956,9 +1026,9 @@
 
         gmfn = l2mfn;
         gpfn = l2pfn;
-        guest_pt = (l1_pgentry_t *)v->arch.guest_vtable;
-
-        for (i = L4; i >= L3; i--) {
+        guest_pt = (guest_l1_pgentry_t *)v->arch.guest_vtable;
+
+        for (i = PAGING_L4; i >= PAGING_L3; i--) {
             if ( page_out_of_sync(&frame_table[gmfn]) &&
               !snapshot_entry_matches(
                   d, guest_pt, gpfn, table_offset_64(va, i)) )
@@ -972,7 +1042,7 @@
             if ( !VALID_MFN(gmfn) )
                 return 0;
             /* Todo: check!*/
-            guest_pt = (l1_pgentry_t *)map_domain_page(gmfn);
+            guest_pt = (guest_l1_pgentry_t *)map_domain_page(gmfn);
 
         }
 
@@ -986,13 +1056,13 @@
 #endif
 
     if ( page_out_of_sync(&frame_table[l2mfn]) &&
-         !snapshot_entry_matches(d, (l1_pgentry_t *)v->arch.guest_vtable,
-                                 l2pfn, l2_table_offset(va)) )
+         !snapshot_entry_matches(d, (guest_l1_pgentry_t *)v->arch.guest_vtable,
+                                 l2pfn, guest_l2_table_offset(va)) )
         return 1;
 
     __guest_get_l2e(v, va, &l2e);
-    if ( !(l2e_get_flags(l2e) & _PAGE_PRESENT) || 
-         (l2e_get_flags(l2e) & _PAGE_PSE))
+    if ( !(guest_l2e_get_flags(l2e) & _PAGE_PRESENT) || 
+         (guest_l2e_get_flags(l2e) & _PAGE_PSE))
         return 0;
 
     l1pfn = l2e_get_pfn(l2e);
@@ -1001,20 +1071,20 @@
     // If the l1 pfn is invalid, it can't be out of sync...
     if ( !VALID_MFN(l1mfn) )
         return 0;
-    
-    pt_va = ((va >> L1_PAGETABLE_SHIFT) & ~(L1_PAGETABLE_ENTRIES - 1))
+
+    pt_va = ((va >> L1_PAGETABLE_SHIFT) & ~(GUEST_L1_PAGETABLE_ENTRIES - 1))
       << L1_PAGETABLE_SHIFT;
-    guest_pt = (l1_pgentry_t *) __guest_get_l1e(v, pt_va, &tmp_gle);
+    guest_pt = (guest_l1_pgentry_t *) __guest_get_l1e(v, pt_va, &tmp_gle);
 
     if ( page_out_of_sync(&frame_table[l1mfn]) &&
          !snapshot_entry_matches(
-             d, guest_pt, l1pfn, l1_table_offset(va)) )
+             d, guest_pt, l1pfn, guest_l1_table_offset(va)) )
         return 1;
 
     return 0;
 }
 
-#define GPFN_TO_GPTEPAGE(_gpfn) ((_gpfn) / (PAGE_SIZE / sizeof(l1_pgentry_t)))
+#define GPFN_TO_GPTEPAGE(_gpfn) ((_gpfn) / (PAGE_SIZE / 
sizeof(guest_l1_pgentry_t)))
 static inline unsigned long
 predict_writable_pte_page(struct domain *d, unsigned long gpfn)
 {
@@ -1108,7 +1178,7 @@
         return (found == max_refs_to_find);
     }
 
-    i = readonly_gpfn & (L1_PAGETABLE_ENTRIES - 1);
+    i = readonly_gpfn & (GUEST_L1_PAGETABLE_ENTRIES - 1);
     if ( !l1e_has_changed(pt[i], match, flags) && fix_entry(i) )
     {
         perfc_incrc(remove_write_fast_exit);
@@ -1117,7 +1187,7 @@
         return found;
     }
  
-    for (i = 0; i < L1_PAGETABLE_ENTRIES; i++)
+    for (i = 0; i < GUEST_L1_PAGETABLE_ENTRIES; i++)
     {
         if ( unlikely(!l1e_has_changed(pt[i], match, flags)) && fix_entry(i) )
             break;
@@ -1282,15 +1352,15 @@
         switch ( stype ) {
         case PGT_l1_shadow:
         {
-            l1_pgentry_t *guest1 = guest;
+            guest_l1_pgentry_t *guest1 = guest;
             l1_pgentry_t *shadow1 = shadow;
-            l1_pgentry_t *snapshot1 = snapshot;
+            guest_l1_pgentry_t *snapshot1 = snapshot;
 
             ASSERT(VM_ASSIST(d, VMASST_TYPE_writable_pagetables) ||
                    shadow_mode_write_all(d));
 
             if ( !shadow_mode_refcounts(d) )
-                revalidate_l1(d, guest1, snapshot1);
+                revalidate_l1(d, (l1_pgentry_t *)guest1, (l1_pgentry_t 
*)snapshot1);
 
             if ( !smfn )
                 break;
@@ -1301,7 +1371,7 @@
             for ( i = min_shadow; i <= max_shadow; i++ )
             {
                 if ( (i < min_snapshot) || (i > max_snapshot) ||
-                     l1e_has_changed(guest1[i], snapshot1[i], PAGE_FLAG_MASK) )
+                     guest_l1e_has_changed(guest1[i], snapshot1[i], 
PAGE_FLAG_MASK) )
                 {
                     need_flush |= validate_pte_change(d, guest1[i], 
&shadow1[i]);
 
@@ -1431,32 +1501,36 @@
         {
             int max = -1;
 
-            l4_pgentry_t *guest4 = guest;
+            guest_root_pgentry_t *guest_root = guest;
             l4_pgentry_t *shadow4 = shadow;
-            l4_pgentry_t *snapshot4 = snapshot;
+            guest_root_pgentry_t *snapshot_root = snapshot;
 
             changed = 0;
-            for ( i = 0; i < L4_PAGETABLE_ENTRIES; i++ )
+            for ( i = 0; i < GUEST_ROOT_PAGETABLE_ENTRIES; i++ )
             {
                 if ( !is_guest_l4_slot(i) && !external )
                     continue;
-                l4_pgentry_t new_l4e = guest4[i];
-                if ( l4e_has_changed(new_l4e, snapshot4[i], PAGE_FLAG_MASK))
+                guest_root_pgentry_t new_root_e = guest_root[i];
+                if ( root_entry_has_changed(
+                        new_root_e, snapshot_root[i], PAGE_FLAG_MASK))
                 {
-                    need_flush |= validate_entry_change(
-                      d, (pgentry_64_t *)&new_l4e,
-                      (pgentry_64_t *)&shadow4[i], 
shadow_type_to_level(stype));
-
+                    if (d->arch.ops->guest_paging_levels == PAGING_L4) {
+                        need_flush |= validate_entry_change(
+                          d, (pgentry_64_t *)&new_root_e,
+                          (pgentry_64_t *)&shadow4[i], 
shadow_type_to_level(stype));
+                    } else {
+                        validate_bl2e_change(d, &new_root_e, shadow, i);
+                    }
                     changed++;
                     ESH_LOG("%d: shadow4 mfn: %lx, shadow root: %lx\n", i,
                       smfn, pagetable_get_paddr(current->arch.shadow_table));
                 }
-                if ( l4e_get_intpte(new_l4e) != 0 ) /* FIXME: check flags? */
+                if ( guest_root_get_intpte(new_root_e) != 0 ) /* FIXME: check 
flags? */
                     max = i;
 
                 //  Need a better solution in the long term.
-                if ( !(l4e_get_flags(new_l4e) & _PAGE_PRESENT) &&
-                  unlikely(l4e_get_intpte(new_l4e) != 0) &&
+                if ( !(guest_root_get_flags(new_root_e) & _PAGE_PRESENT) &&
+                  unlikely(guest_root_get_intpte(new_root_e) != 0) &&
                   !unshadow &&
                   (frame_table[smfn].u.inuse.type_info & PGT_pinned) )
                     unshadow = 1;
@@ -1555,8 +1629,14 @@
     if ( shadow_mode_translate(d) )
         need_flush |= resync_all(d, PGT_hl2_shadow);
 #endif
-    need_flush |= resync_all(d, PGT_l2_shadow);
-    need_flush |= resync_all(d, PGT_l3_shadow);
+
+    /*
+     * Fixme: for i386 host
+     */
+    if (d->arch.ops->guest_paging_levels == PAGING_L4) {
+        need_flush |= resync_all(d, PGT_l2_shadow);
+        need_flush |= resync_all(d, PGT_l3_shadow);
+    }
     need_flush |= resync_all(d, PGT_l4_shadow);
 
     if ( need_flush && !unlikely(shadow_mode_external(d)) )
@@ -1566,11 +1646,11 @@
 }
 
 static inline int l1pte_write_fault(
-    struct vcpu *v, l1_pgentry_t *gpte_p, l1_pgentry_t *spte_p,
+    struct vcpu *v, guest_l1_pgentry_t *gpte_p, l1_pgentry_t *spte_p,
     unsigned long va)
 {
     struct domain *d = v->domain;
-    l1_pgentry_t gpte = *gpte_p;
+    guest_l1_pgentry_t gpte = *gpte_p;
     l1_pgentry_t spte;
     unsigned long gpfn = l1e_get_pfn(gpte);
     unsigned long gmfn = __gpfn_to_mfn(d, gpfn);
@@ -1585,8 +1665,8 @@
     }
 
     ASSERT(l1e_get_flags(gpte) & _PAGE_RW);
-    l1e_add_flags(gpte, _PAGE_DIRTY | _PAGE_ACCESSED);
-    spte = l1e_from_pfn(gmfn, l1e_get_flags(gpte) & ~_PAGE_GLOBAL);
+    guest_l1e_add_flags(gpte, _PAGE_DIRTY | _PAGE_ACCESSED);
+    spte = l1e_from_pfn(gmfn, guest_l1e_get_flags(gpte) & ~_PAGE_GLOBAL);
 
     SH_VVLOG("l1pte_write_fault: updating spte=0x%" PRIpte " gpte=0x%" PRIpte,
              l1e_get_intpte(spte), l1e_get_intpte(gpte));
@@ -1604,9 +1684,9 @@
 }
 
 static inline int l1pte_read_fault(
-    struct domain *d, l1_pgentry_t *gpte_p, l1_pgentry_t *spte_p)
+    struct domain *d, guest_l1_pgentry_t *gpte_p, l1_pgentry_t *spte_p)
 { 
-    l1_pgentry_t gpte = *gpte_p;
+    guest_l1_pgentry_t gpte = *gpte_p;
     l1_pgentry_t spte = *spte_p;
     unsigned long pfn = l1e_get_pfn(gpte);
     unsigned long mfn = __gpfn_to_mfn(d, pfn);
@@ -1618,10 +1698,10 @@
         return 0;
     }
 
-    l1e_add_flags(gpte, _PAGE_ACCESSED);
-    spte = l1e_from_pfn(mfn, l1e_get_flags(gpte) & ~_PAGE_GLOBAL);
-
-    if ( shadow_mode_log_dirty(d) || !(l1e_get_flags(gpte) & _PAGE_DIRTY) ||
+    guest_l1e_add_flags(gpte, _PAGE_ACCESSED);
+    spte = l1e_from_pfn(mfn, guest_l1e_get_flags(gpte) & ~_PAGE_GLOBAL);
+
+    if ( shadow_mode_log_dirty(d) || !(guest_l1e_get_flags(gpte) & 
_PAGE_DIRTY) ||
          mfn_is_page_table(mfn) )
     {
         l1e_remove_flags(spte, _PAGE_RW);
@@ -1634,7 +1714,7 @@
 
     return 1;
 }
-
+#if CONFIG_PAGING_LEVELS <= 3
 static int shadow_fault_32(unsigned long va, struct cpu_user_regs *regs)
 {
     l1_pgentry_t gpte, spte, orig_gpte;
@@ -1768,6 +1848,7 @@
     shadow_unlock(d);
     return 0;
 }
+#endif
 
 static int do_update_va_mapping(unsigned long va,
                                 l1_pgentry_t val,
@@ -1787,7 +1868,7 @@
     //
     __shadow_sync_va(v, va);
 
-    l1pte_propagate_from_guest(d, val, &spte);
+    l1pte_propagate_from_guest(d, *(guest_l1_pgentry_t *)&val, &spte);
     shadow_set_l1e(va, spte, 0);
 
     /*
@@ -1848,7 +1929,7 @@
 #if CONFIG_PAGING_LEVELS == 2
     unsigned long hl2mfn;
 #endif
-  
+
     int max_mode = ( shadow_mode_external(d) ? SHM_external
                      : shadow_mode_translate(d) ? SHM_translate
                      : shadow_mode_enabled(d) ? SHM_enable
@@ -1954,17 +2035,6 @@
 #endif
 }
 
-struct shadow_ops MODE_A_HANDLER = {
-    .guest_paging_levels        = 2,
-    .invlpg                     = shadow_invlpg_32,
-    .fault                      = shadow_fault_32,
-    .update_pagetables          = shadow_update_pagetables,
-    .sync_all                   = sync_all,
-    .remove_all_write_access    = remove_all_write_access,
-    .do_update_va_mapping       = do_update_va_mapping,
-    .mark_mfn_out_of_sync       = mark_mfn_out_of_sync,
-    .is_out_of_sync             = is_out_of_sync,
-};
 
 /************************************************************************/
 /************************************************************************/
@@ -2445,12 +2515,90 @@
     BUG();                      /* not implemenated yet */
     return 42;
 }
+static unsigned long gva_to_gpa_pae(unsigned long gva)
+{
+    BUG();
+    return 43;
+}
 #endif
 
 #if CONFIG_PAGING_LEVELS >= 4
 /****************************************************************************/
 /* 64-bit shadow-mode code testing */
 /****************************************************************************/
+/*
+ * validate_bl2e_change()
+ * The code is for 32-bit VMX gues on 64-bit host.
+ * To sync guest L2.
+ */
+
+static inline void
+validate_bl2e_change(
+  struct domain *d,
+  guest_root_pgentry_t *new_gle_p,
+  pgentry_64_t *shadow_l3,
+  int index)
+{
+    int sl3_idx, sl2_idx;
+    unsigned long sl2mfn, sl1mfn;
+    pgentry_64_t *sl2_p;
+
+    /* Using guest l2 pte index to get shadow l3&l2 index
+     * index: 0 ~ 1023, PAGETABLE_ENTRIES: 512
+     */
+    sl3_idx = index / (PAGETABLE_ENTRIES / 2);
+    sl2_idx = (index % (PAGETABLE_ENTRIES / 2)) * 2;
+
+    sl2mfn = entry_get_pfn(shadow_l3[sl3_idx]);
+    sl2_p = (pgentry_64_t *)map_domain_page(sl2mfn);
+
+    validate_pde_change(
+        d, *(guest_l2_pgentry_t *)new_gle_p, (l2_pgentry_t *)&sl2_p[sl2_idx]);
+
+    /* Mapping the second l1 shadow page */
+    if (entry_get_flags(sl2_p[sl2_idx]) & _PAGE_PRESENT) {
+       sl1mfn = entry_get_pfn(sl2_p[sl2_idx]);
+       sl2_p[sl2_idx + 1] =
+            entry_from_pfn(sl1mfn + 1, entry_get_flags(sl2_p[sl2_idx]));
+    }
+    unmap_domain_page(sl2_p);
+
+}
+
+/*
+ * init_bl2() is for 32-bit VMX guest on 64-bit host
+ * Using 1 shadow L4(l3) and 4 shadow L2s to simulate guest L2
+ */
+static inline unsigned long init_bl2(l4_pgentry_t *spl4e, unsigned long smfn)
+{
+    unsigned int count;
+    unsigned long sl2mfn;
+    struct pfn_info *page;
+
+    memset(spl4e, 0, PAGE_SIZE);
+
+    /* Map the self entry, L4&L3 share the same page */
+    spl4e[PAE_SHADOW_SELF_ENTRY] = l4e_from_pfn(smfn, __PAGE_HYPERVISOR);
+
+    /* Allocate 4 shadow L2s */
+    page = alloc_domheap_pages(NULL, SL2_ORDER, 0);
+    if (!page)
+        domain_crash_synchronous();
+
+    for (count = 0; count < PDP_ENTRIES; count++)
+    {
+        sl2mfn = page_to_pfn(page+count);
+        void *l2 = map_domain_page(sl2mfn);
+        memset(l2, 0, PAGE_SIZE);
+        unmap_domain_page(l2);
+        spl4e[count] = l4e_from_pfn(sl2mfn, _PAGE_PRESENT);
+    }
+
+    unmap_domain_page(spl4e);
+    return smfn;
+
+
+}
 
 static unsigned long shadow_l4_table(
   struct domain *d, unsigned long gpfn, unsigned long gmfn)
@@ -2464,11 +2612,16 @@
 
     if ( unlikely(!(smfn = alloc_shadow_page(d, gpfn, gmfn, PGT_l4_shadow))) )
     {
-        printk("Couldn't alloc an L2 shadow for pfn=%lx mfn=%lx\n", gpfn, 
gmfn);
+        printk("Couldn't alloc an L4 shadow for pfn=%lx mfn=%lx\n", gpfn, 
gmfn);
         BUG(); /* XXX Deal gracefully with failure. */
     }
 
     spl4e = (l4_pgentry_t *)map_domain_page(smfn);
+
+    if (d->arch.ops->guest_paging_levels == PAGING_L2) {
+        return init_bl2(spl4e, smfn);
+    }
+
     /* Install hypervisor and 4x linear p.t. mapings. */
     if ( (PGT_base_page_table == PGT_l4_page_table) &&
       !shadow_mode_external(d) )
@@ -2576,7 +2729,7 @@
     pgentry_64_t gle, sle;
     unsigned long gpfn, smfn;
 
-    if (from == L1 && to == L2) {
+    if (from == PAGING_L1 && to == PAGING_L2) {
         shadow_map_l1_into_current_l2(va);
         return;
     }
@@ -2608,7 +2761,7 @@
     if (!(l4e_get_flags(sl4e) & _PAGE_PRESENT)) {
         if (create_l2_shadow) {
             perfc_incrc(shadow_set_l3e_force_map);
-            shadow_map_into_current(v, va, L3, L4);
+            shadow_map_into_current(v, va, PAGING_L3, PAGING_L4);
             __shadow_get_l4e(v, va, &sl4e);
         } else {
             printk("For non VMX shadow, create_l1_shadow:%d\n", 
create_l2_shadow);
@@ -2619,7 +2772,7 @@
     if (!(l3e_get_flags(sl3e) & _PAGE_PRESENT)) {
          if (create_l2_shadow) {
             perfc_incrc(shadow_set_l2e_force_map);
-            shadow_map_into_current(v, va, L2, L3);
+            shadow_map_into_current(v, va, PAGING_L2, PAGING_L3);
             __shadow_get_l3e(v, va, &sl3e);
         } else {
             printk("For non VMX shadow, create_l1_shadow:%d\n", 
create_l2_shadow);
@@ -2655,8 +2808,15 @@
     l1_pgentry_t old_spte;
     l1_pgentry_t sl1e = *(l1_pgentry_t *)sl1e_p;
     int i;
-
-    for (i = L4; i >= L2; i--) {
+    unsigned long orig_va = 0;
+
+    if (d->arch.ops->guest_paging_levels == PAGING_L2) {
+        /* This is for 32-bit VMX guest on 64-bit host */
+        orig_va = va;
+        va = va & (~((1<<L2_PAGETABLE_SHIFT_32)-1));
+    }
+
+    for (i = PAGING_L4; i >= PAGING_L2; i--) {
         if (!__rw_entry(v, va, &sle, SHADOW_ENTRY | GET_ENTRY | i)) {
             printk("<%s> i = %d\n", __func__, i);
             BUG();
@@ -2672,9 +2832,13 @@
 #endif
             }
         }
-        if(i < L4)
+        if(i < PAGING_L4)
             shadow_update_min_max(entry_get_pfn(sle_up), table_offset_64(va, 
i));
         sle_up = sle;
+    }
+
+    if (d->arch.ops->guest_paging_levels == PAGING_L2) {
+        va = orig_va;
     }
 
     if ( shadow_mode_refcounts(d) )
@@ -2692,9 +2856,13 @@
     }
 
     __shadow_set_l1e(v, va, &sl1e);
-    shadow_update_min_max(entry_get_pfn(sle_up), table_offset_64(va, L1));
-}
-
+
+    shadow_update_min_max(entry_get_pfn(sle_up), guest_l1_table_offset(va));
+}
+
+/* As 32-bit guest don't support 4M page yet,
+ * we don't concern double compile for this function
+ */
 static inline int l2e_rw_fault(
     struct vcpu *v, l2_pgentry_t *gl2e_p, unsigned long va, int rw)
 {
@@ -2825,12 +2993,120 @@
 
 }
 
+/*
+ * Check P, R/W, U/S bits in the guest page table.
+ * If the fault belongs to guest return 1,
+ * else return 0.
+ */
+#if defined( GUEST_PGENTRY_32 )
+static inline int guest_page_fault(struct vcpu *v,
+  unsigned long va, unsigned int error_code, 
+  guest_l2_pgentry_t *gpl2e, guest_l1_pgentry_t *gpl1e)
+{
+    /* The following check for 32-bit guest on 64-bit host */
+
+    __guest_get_l2e(v, va, gpl2e);
+
+    /* Check the guest L2 page-table entry first*/
+    if (unlikely(!(guest_l2e_get_flags(*gpl2e) & _PAGE_PRESENT)))
+        return 1;
+
+    if (error_code & ERROR_W) {
+        if (unlikely(!(guest_l2e_get_flags(*gpl2e) & _PAGE_RW)))
+            return 1;
+    }
+    if (error_code & ERROR_U) {
+        if (unlikely(!(guest_l2e_get_flags(*gpl2e) & _PAGE_USER)))
+            return 1;
+    }
+
+    if (guest_l2e_get_flags(*gpl2e) & _PAGE_PSE)
+        return 0;
+
+    __guest_get_l1e(v, va, gpl1e);
+
+    /* Then check the guest L1 page-table entry */
+    if (unlikely(!(guest_l1e_get_flags(*gpl1e) & _PAGE_PRESENT)))
+        return 1;
+
+    if (error_code & ERROR_W) {
+        if (unlikely(!(guest_l1e_get_flags(*gpl1e) & _PAGE_RW)))
+            return 1;
+    }
+    if (error_code & ERROR_U) {
+        if (unlikely(!(guest_l1e_get_flags(*gpl1e) & _PAGE_USER)))
+            return 1;
+    }
+
+    return 0;
+}
+#else
+static inline int guest_page_fault(struct vcpu *v,
+  unsigned long va, unsigned int error_code, 
+  guest_l2_pgentry_t *gpl2e, guest_l1_pgentry_t *gpl1e)
+{
+    struct domain *d = v->domain;
+    pgentry_64_t gle, *lva;
+    unsigned long mfn;
+    int i;
+
+    __rw_entry(v, va, &gle, GUEST_ENTRY | GET_ENTRY | PAGING_L4);
+    if (unlikely(!(entry_get_flags(gle) & _PAGE_PRESENT)))
+        return 1;
+
+    if (error_code & ERROR_W) {
+        if (unlikely(!(entry_get_flags(gle) & _PAGE_RW)))
+            return 1;
+    }
+    if (error_code & ERROR_U) {
+        if (unlikely(!(entry_get_flags(gle) & _PAGE_USER)))
+            return 1;
+    }
+    for (i = PAGING_L3; i >= PAGING_L1; i--) {
+        /*
+         * If it's not external mode, then mfn should be machine physical.
+         */
+        mfn = __gpfn_to_mfn(d, (entry_get_value(gle) >> PAGE_SHIFT));
+
+        lva = (pgentry_64_t *) phys_to_virt(
+          mfn << PAGE_SHIFT);
+        gle = lva[table_offset_64(va, i)];
+
+        if (unlikely(!(entry_get_flags(gle) & _PAGE_PRESENT)))
+            return 1;
+
+        if (error_code & ERROR_W) {
+            if (unlikely(!(entry_get_flags(gle) & _PAGE_RW)))
+                return 1;
+        }
+        if (error_code & ERROR_U) {
+            if (unlikely(!(entry_get_flags(gle) & _PAGE_USER)))
+                return 1;
+        }
+
+        if (i == PAGING_L2) {
+            if (gpl2e)
+                gpl2e->l2 = gle.lo;
+
+            if (likely(entry_get_flags(gle) & _PAGE_PSE))
+                return 0;
+
+        }
+
+        if (i == PAGING_L1)
+            if (gpl1e)
+                gpl1e->l1 = gle.lo;
+    }
+    return 0;
+}
+#endif
 static int shadow_fault_64(unsigned long va, struct cpu_user_regs *regs)
 {
     struct vcpu *v = current;
     struct domain *d = v->domain;
-    l2_pgentry_t gl2e;
-    l1_pgentry_t sl1e, gl1e;
+    guest_l2_pgentry_t gl2e;
+    guest_l1_pgentry_t gl1e;
+    l1_pgentry_t sl1e;
 
     perfc_incrc(shadow_fault_calls);
 
@@ -2853,12 +3129,11 @@
      * STEP 2. Check if the fault belongs to guest
      */
     if ( guest_page_fault(
-            v, va, regs->error_code, 
-            (pgentry_64_t *)&gl2e, (pgentry_64_t *)&gl1e) ) {
+            v, va, regs->error_code, &gl2e, &gl1e) ) {
         goto fail;
     }
     
-    if ( unlikely(!(l2e_get_flags(gl2e) & _PAGE_PSE)) ) {
+    if ( unlikely(!(guest_l2e_get_flags(gl2e) & _PAGE_PSE)) ) {
         /*
          * Handle 4K pages here
          */
@@ -2892,11 +3167,11 @@
          */
         /* Write fault? */
         if ( regs->error_code & 2 ) {
-            if ( !l2e_rw_fault(v, &gl2e, va, WRITE_FAULT) ) {
+            if ( !l2e_rw_fault(v, (l2_pgentry_t *)&gl2e, va, WRITE_FAULT) ) {
                 goto fail;
             }
         } else {
-            l2e_rw_fault(v, &gl2e, va, READ_FAULT);
+            l2e_rw_fault(v, (l2_pgentry_t *)&gl2e, va, READ_FAULT);
         }
 
         /*
@@ -2944,7 +3219,27 @@
     shadow_unlock(d);
 }
 
-#ifndef PGENTRY_32
+static unsigned long gva_to_gpa_64(unsigned long gva)
+{
+    struct vcpu *v = current;
+    guest_l1_pgentry_t gl1e = {0};
+    guest_l2_pgentry_t gl2e = {0};
+    unsigned long gpa;
+
+    if (guest_page_fault(v, gva, 0, &gl2e, &gl1e))
+        return 0;
+    
+    if (guest_l2e_get_flags(gl2e) & _PAGE_PSE)
+        gpa = guest_l2e_get_paddr(gl2e) + (gva & ((1 << 
GUEST_L2_PAGETABLE_SHIFT) - 1));
+    else
+        gpa = guest_l1e_get_paddr(gl1e) + (gva & ~PAGE_MASK);
+
+    return gpa;
+
+}
+
+#ifndef GUEST_PGENTRY_32
+
 struct shadow_ops MODE_F_HANDLER = {
     .guest_paging_levels              = 4,
     .invlpg                     = shadow_invlpg_64,
@@ -2955,10 +3250,42 @@
     .do_update_va_mapping       = do_update_va_mapping,
     .mark_mfn_out_of_sync       = mark_mfn_out_of_sync,
     .is_out_of_sync             = is_out_of_sync,
+    .gva_to_gpa                 = gva_to_gpa_64,
 };
 #endif
 
 #endif
+
+#if CONFIG_PAGING_LEVELS == 2
+struct shadow_ops MODE_A_HANDLER = {
+    .guest_paging_levels        = 2,
+    .invlpg                     = shadow_invlpg_32,
+    .fault                      = shadow_fault_32,
+    .update_pagetables          = shadow_update_pagetables,
+    .sync_all                   = sync_all,
+    .remove_all_write_access    = remove_all_write_access,
+    .do_update_va_mapping       = do_update_va_mapping,
+    .mark_mfn_out_of_sync       = mark_mfn_out_of_sync,
+    .is_out_of_sync             = is_out_of_sync,
+    .gva_to_gpa                 = gva_to_gpa_64,
+};
+
+#elif CONFIG_PAGING_LEVELS == 3
+struct shadow_ops MODE_B_HANDLER = {
+    .guest_paging_levels              = 3,
+    .invlpg                     = shadow_invlpg_32,
+    .fault                      = shadow_fault_32,
+    .update_pagetables          = shadow_update_pagetables,
+    .sync_all                   = sync_all,
+    .remove_all_write_access    = remove_all_write_access,
+    .do_update_va_mapping       = do_update_va_mapping,
+    .mark_mfn_out_of_sync       = mark_mfn_out_of_sync,
+    .is_out_of_sync             = is_out_of_sync,
+    .gva_to_gpa                 = gva_to_gpa_pae,
+};
+
+#endif
+
 
 /*
  * Local variables:
diff -r 95cfc001ddd1 -r 8b87d43412bf xen/arch/x86/shadow_public.c
--- a/xen/arch/x86/shadow_public.c      Fri Sep  2 09:02:13 2005
+++ b/xen/arch/x86/shadow_public.c      Fri Sep  2 09:43:32 2005
@@ -33,11 +33,15 @@
 #if CONFIG_PAGING_LEVELS >= 3
 #include <asm/shadow_64.h>
 
+#endif
+#if CONFIG_PAGING_LEVELS == 4
 extern struct shadow_ops MODE_F_HANDLER;
+extern struct shadow_ops MODE_D_HANDLER;
 #endif
 
 extern struct shadow_ops MODE_A_HANDLER;
 
+#define SHADOW_MAX_GUEST32(_encoded) ((L1_PAGETABLE_ENTRIES_32 - 1) - 
((_encoded) >> 16))
 /****************************************************************************/
 /************* export interface functions ***********************************/
 /****************************************************************************/
@@ -48,7 +52,7 @@
     shadow_lock(d);
 
     switch(levels) {
-#if CONFIG_PAGING_LEVELS >= 4 
+#if CONFIG_PAGING_LEVELS >= 4
     case 4:
        if ( d->arch.ops != &MODE_F_HANDLER )
            d->arch.ops = &MODE_F_HANDLER;
@@ -56,9 +60,14 @@
         return 1;
 #endif
     case 3:
-    case 2:                     
+    case 2:
+#if CONFIG_PAGING_LEVELS == 2
        if ( d->arch.ops != &MODE_A_HANDLER )
            d->arch.ops = &MODE_A_HANDLER;
+#elif CONFIG_PAGING_LEVELS == 4
+       if ( d->arch.ops != &MODE_D_HANDLER )
+           d->arch.ops = &MODE_D_HANDLER;
+#endif
        shadow_unlock(d);
         return 1;
    default:
@@ -122,13 +131,17 @@
     return d->arch.ops->is_out_of_sync(v, va);
 }
 
+unsigned long gva_to_gpa(unsigned long gva)
+{
+    struct domain *d = current->domain;
+    return d->arch.ops->gva_to_gpa(gva);
+}
 /****************************************************************************/
 /****************************************************************************/
 #if CONFIG_PAGING_LEVELS >= 4
 /*
  * Convert PAE 3-level page-table to 4-level page-table
  */
-#define PDP_ENTRIES   4
 static pagetable_t page_table_convert(struct domain *d)
 {
     struct pfn_info *l4page, *l3page;
@@ -203,19 +216,41 @@
 /*
  * Free l2, l3, l4 shadow tables
  */
+
+void free_fake_shadow_l2(struct domain *d,unsigned long smfn);
+
 static void inline
 free_shadow_tables(struct domain *d, unsigned long smfn, u32 level)
 {
     pgentry_64_t *ple = map_domain_page(smfn);
     int i, external = shadow_mode_external(d);
-
-    for ( i = 0; i < PAGETABLE_ENTRIES; i++ )
-        if ( external || is_guest_l4_slot(i) )
-            if ( entry_get_flags(ple[i]) & _PAGE_PRESENT )
-                put_shadow_ref(entry_get_pfn(ple[i]));
-
-    unmap_domain_page(ple);
-}
+    struct pfn_info *page = &frame_table[smfn];
+
+    if (d->arch.ops->guest_paging_levels == PAGING_L2)
+    {
+#if CONFIG_PAGING_LEVELS >=4
+        for ( i = 0; i < PDP_ENTRIES; i++ )
+        {
+            if (entry_get_flags(ple[i]) & _PAGE_PRESENT )
+                free_fake_shadow_l2(d,entry_get_pfn(ple[i]));
+        }
+   
+        page = &frame_table[entry_get_pfn(ple[0])];
+        free_domheap_pages(page, SL2_ORDER);
+        unmap_domain_page(ple);
+#endif
+    }
+    else
+    {
+        for ( i = 0; i < PAGETABLE_ENTRIES; i++ )
+            if ( external || is_guest_l4_slot(i) )
+                if ( entry_get_flags(ple[i]) & _PAGE_PRESENT )
+                        put_shadow_ref(entry_get_pfn(ple[i]));
+
+        unmap_domain_page(ple);
+    }
+}
+
 
 void free_monitor_pagetable(struct vcpu *v)
 {
@@ -453,7 +488,12 @@
     struct pfn_info *spage = pfn_to_page(smfn);
     u32 min_max = spage->tlbflush_timestamp;
     int min = SHADOW_MIN(min_max);
-    int max = SHADOW_MAX(min_max);
+    int max;
+    
+    if (d->arch.ops->guest_paging_levels == PAGING_L2)
+        max = SHADOW_MAX_GUEST32(min_max);
+    else
+        max = SHADOW_MAX(min_max);
 
     for ( i = min; i <= max; i++ )
     {
@@ -512,9 +552,24 @@
     unmap_domain_page(pl2e);
 }
 
+void free_fake_shadow_l2(struct domain *d, unsigned long smfn)
+{
+    pgentry_64_t *ple = map_domain_page(smfn);
+    int i;
+
+    for ( i = 0; i < PAGETABLE_ENTRIES; i = i + 2 )
+    {
+        if ( entry_get_flags(ple[i]) & _PAGE_PRESENT )
+            put_shadow_ref(entry_get_pfn(ple[i]));
+    }
+
+    unmap_domain_page(ple);
+}
+
 void free_shadow_page(unsigned long smfn)
 {
     struct pfn_info *page = &frame_table[smfn];
+
     unsigned long gmfn = page->u.inuse.type_info & PGT_mfn_mask;
     struct domain *d = page_get_owner(pfn_to_page(gmfn));
     unsigned long gpfn = __mfn_to_gpfn(d, gmfn);
@@ -531,6 +586,7 @@
             gpfn |= (1UL << 63);
     }
 #endif
+
     delete_shadow_status(d, gpfn, gmfn, type);
 
     switch ( type )
@@ -687,7 +743,7 @@
     int                   i;
     struct shadow_status *x;
     struct vcpu          *v;
- 
+
     /*
      * WARNING! The shadow page table must not currently be in use!
      * e.g., You are expected to have paused the domain and synchronized CR3.
@@ -794,7 +850,16 @@
         perfc_decr(free_l1_pages);
 
         struct pfn_info *page = list_entry(list_ent, struct pfn_info, list);
-        free_domheap_page(page);
+       if (d->arch.ops->guest_paging_levels == PAGING_L2)
+       {
+#if CONFIG_PAGING_LEVELS >=4
+        free_domheap_pages(page, SL1_ORDER);
+#else
+       free_domheap_page(page);
+#endif
+       }
+       else
+       free_domheap_page(page);
     }
 
     shadow_audit(d, 0);
@@ -1191,7 +1256,7 @@
     {
         DPRINTK("Don't try to do a shadow op on yourself!\n");
         return -EINVAL;
-    }   
+    }
 
     domain_pause(d);
 
diff -r 95cfc001ddd1 -r 8b87d43412bf xen/arch/x86/vmx.c
--- a/xen/arch/x86/vmx.c        Fri Sep  2 09:02:13 2005
+++ b/xen/arch/x86/vmx.c        Fri Sep  2 09:43:32 2005
@@ -412,7 +412,7 @@
     if ( !result )
     {
         __vmread(GUEST_RIP, &eip);
-        printk("vmx pgfault to guest va=%p eip=%p\n", va, eip);
+        printk("vmx pgfault to guest va=%lx eip=%lx\n", va, eip);
     }
 #endif
 
@@ -456,7 +456,16 @@
         clear_bit(X86_FEATURE_PSE, &edx);
         clear_bit(X86_FEATURE_PAE, &edx);
         clear_bit(X86_FEATURE_PSE36, &edx);
+#else
+        struct vcpu *d = current;
+        if (d->domain->arch.ops->guest_paging_levels == PAGING_L2)
+        {
+            clear_bit(X86_FEATURE_PSE, &edx);
+            clear_bit(X86_FEATURE_PAE, &edx);
+            clear_bit(X86_FEATURE_PSE36, &edx);
+        }
 #endif
+
     }
 
     regs->eax = (unsigned long) eax;
@@ -650,7 +659,7 @@
         p->df = (eflags & X86_EFLAGS_DF) ? 1 : 0;
 
         if (test_bit(5, &exit_qualification)) /* "rep" prefix */
-           p->count = vm86 ? regs->ecx & 0xFFFF : regs->ecx;
+            p->count = vm86 ? regs->ecx & 0xFFFF : regs->ecx;
 
         /*
          * Split up string I/O operations that cross page boundaries. Don't
@@ -1006,6 +1015,15 @@
 
 #if CONFIG_PAGING_LEVELS >= 4 
             if(!shadow_set_guest_paging_levels(d->domain, 4)) {
+                printk("Unsupported guest paging levels\n");
+                domain_crash_synchronous(); /* need to take a clean path */
+            }
+#endif
+        }
+        else
+        {
+#if CONFIG_PAGING_LEVELS >= 4
+            if(!shadow_set_guest_paging_levels(d->domain, 2)) {
                 printk("Unsupported guest paging levels\n");
                 domain_crash_synchronous(); /* need to take a clean path */
             }
diff -r 95cfc001ddd1 -r 8b87d43412bf xen/include/asm-x86/page-guest32.h
--- a/xen/include/asm-x86/page-guest32.h        Fri Sep  2 09:02:13 2005
+++ b/xen/include/asm-x86/page-guest32.h        Fri Sep  2 09:43:32 2005
@@ -32,6 +32,11 @@
 /* Get pte access flags (unsigned int). */
 #define l1e_get_flags_32(x)           (get_pte_flags_32((x).l1))
 #define l2e_get_flags_32(x)           (get_pte_flags_32((x).l2))
+
+#define l1e_get_paddr_32(x)           \
+    ((physaddr_t)(((x).l1 & (PADDR_MASK&PAGE_MASK))))
+#define l2e_get_paddr_32(x)           \
+    ((physaddr_t)(((x).l2 & (PADDR_MASK&PAGE_MASK))))
 
 /* Construct an empty pte. */
 #define l1e_empty_32()                ((l1_pgentry_32_t) { 0 })
diff -r 95cfc001ddd1 -r 8b87d43412bf xen/include/asm-x86/shadow.h
--- a/xen/include/asm-x86/shadow.h      Fri Sep  2 09:02:13 2005
+++ b/xen/include/asm-x86/shadow.h      Fri Sep  2 09:43:32 2005
@@ -34,6 +34,8 @@
 #include <asm/vmx.h>
 #include <public/dom0_ops.h>
 #include <asm/shadow_public.h>
+#include <asm/page-guest32.h>
+#include <asm/shadow_ops.h>
 
 /* Shadow PT operation mode : shadow-mode variable in arch_domain. */
 
@@ -104,9 +106,9 @@
 } while (0)
 #endif
 
-#define SHADOW_ENCODE_MIN_MAX(_min, _max) ((((L1_PAGETABLE_ENTRIES - 1) - 
(_max)) << 16) | (_min))
+#define SHADOW_ENCODE_MIN_MAX(_min, _max) ((((GUEST_L1_PAGETABLE_ENTRIES - 1) 
- (_max)) << 16) | (_min))
 #define SHADOW_MIN(_encoded) ((_encoded) & ((1u<<16) - 1))
-#define SHADOW_MAX(_encoded) ((L1_PAGETABLE_ENTRIES - 1) - ((_encoded) >> 16))
+#define SHADOW_MAX(_encoded) ((GUEST_L1_PAGETABLE_ENTRIES - 1) - ((_encoded) 
>> 16))
 
 extern void shadow_mode_init(void);
 extern int shadow_mode_control(struct domain *p, dom0_shadow_control_t *sc);
@@ -132,6 +134,7 @@
                                        struct domain_mmap_cache *cache);
 #if CONFIG_PAGING_LEVELS >= 3
 #include <asm/page-guest32.h>
+extern unsigned long gva_to_gpa(unsigned long gva);
 extern void shadow_l3_normal_pt_update(struct domain *d,
                                        unsigned long pa, l3_pgentry_t l3e,
                                        struct domain_mmap_cache *cache);
@@ -794,22 +797,22 @@
 #endif
 
 static inline void l1pte_propagate_from_guest(
-    struct domain *d, l1_pgentry_t gpte, l1_pgentry_t *spte_p)
+    struct domain *d, guest_l1_pgentry_t gpte, l1_pgentry_t *spte_p)
 { 
     unsigned long mfn;
     l1_pgentry_t spte;
 
     spte = l1e_empty();
 
-    if ( ((l1e_get_flags(gpte) & (_PAGE_PRESENT|_PAGE_ACCESSED) ) ==
+    if ( ((guest_l1e_get_flags(gpte) & (_PAGE_PRESENT|_PAGE_ACCESSED) ) ==
           (_PAGE_PRESENT|_PAGE_ACCESSED)) &&
          VALID_MFN(mfn = __gpfn_to_mfn(d, l1e_get_pfn(gpte))) )
     {
         spte = l1e_from_pfn(
-            mfn, l1e_get_flags(gpte) & ~(_PAGE_GLOBAL | _PAGE_AVAIL));
+            mfn, guest_l1e_get_flags(gpte) & ~(_PAGE_GLOBAL | _PAGE_AVAIL));
 
         if ( shadow_mode_log_dirty(d) ||
-             !(l1e_get_flags(gpte) & _PAGE_DIRTY) ||
+             !(guest_l1e_get_flags(gpte) & _PAGE_DIRTY) ||
              mfn_is_page_table(mfn) )
         {
             l1e_remove_flags(spte, _PAGE_RW);
@@ -859,22 +862,22 @@
 
 static inline void l2pde_general(
     struct domain *d,
-    l2_pgentry_t *gpde_p,
+    guest_l2_pgentry_t *gpde_p,
     l2_pgentry_t *spde_p,
     unsigned long sl1mfn)
 {
-    l2_pgentry_t gpde = *gpde_p;
+    guest_l2_pgentry_t gpde = *gpde_p;
     l2_pgentry_t spde;
 
     spde = l2e_empty();
-    if ( (l2e_get_flags(gpde) & _PAGE_PRESENT) && (sl1mfn != 0) )
+    if ( (guest_l2e_get_flags(gpde) & _PAGE_PRESENT) && (sl1mfn != 0) )
     {
         spde = l2e_from_pfn(
-            sl1mfn, 
-            (l2e_get_flags(gpde) | _PAGE_RW | _PAGE_ACCESSED) & ~_PAGE_AVAIL);
+            sl1mfn,
+            (guest_l2e_get_flags(gpde) | _PAGE_RW | _PAGE_ACCESSED) & 
~_PAGE_AVAIL);
 
         /* N.B. PDEs do not have a dirty bit. */
-        l2e_add_flags(gpde, _PAGE_ACCESSED);
+        guest_l2e_add_flags(gpde, _PAGE_ACCESSED);
 
         *gpde_p = gpde;
     }
@@ -887,12 +890,12 @@
 }
 
 static inline void l2pde_propagate_from_guest(
-    struct domain *d, l2_pgentry_t *gpde_p, l2_pgentry_t *spde_p)
-{
-    l2_pgentry_t gpde = *gpde_p;
+    struct domain *d, guest_l2_pgentry_t *gpde_p, l2_pgentry_t *spde_p)
+{
+    guest_l2_pgentry_t gpde = *gpde_p;
     unsigned long sl1mfn = 0;
 
-    if ( l2e_get_flags(gpde) & _PAGE_PRESENT )
+    if ( guest_l2e_get_flags(gpde) & _PAGE_PRESENT )
         sl1mfn =  __shadow_status(d, l2e_get_pfn(gpde), PGT_l1_shadow);
     l2pde_general(d, gpde_p, spde_p, sl1mfn);
 }
@@ -904,7 +907,7 @@
 static int inline
 validate_pte_change(
     struct domain *d,
-    l1_pgentry_t new_pte,
+    guest_l1_pgentry_t new_pte,
     l1_pgentry_t *shadow_pte_p)
 {
     l1_pgentry_t old_spte, new_spte;
@@ -1004,7 +1007,7 @@
 static int inline
 validate_pde_change(
     struct domain *d,
-    l2_pgentry_t new_gpde,
+    guest_l2_pgentry_t new_gpde,
     l2_pgentry_t *shadow_pde_p)
 {
     l2_pgentry_t old_spde, new_spde;
diff -r 95cfc001ddd1 -r 8b87d43412bf xen/include/asm-x86/shadow_64.h
--- a/xen/include/asm-x86/shadow_64.h   Fri Sep  2 09:02:13 2005
+++ b/xen/include/asm-x86/shadow_64.h   Fri Sep  2 09:43:32 2005
@@ -27,6 +27,7 @@
 #ifndef _XEN_SHADOW_64_H
 #define _XEN_SHADOW_64_H
 #include <asm/shadow.h>
+#include <asm/shadow_ops.h>
 
 #define READ_FAULT  0
 #define WRITE_FAULT 1
@@ -42,14 +43,14 @@
 #define ESH_LOG(_f, _a...) ((void)0)
 #endif
 
-#define L4      4UL
-#define L3      3UL
-#define L2      2UL
-#define L1      1UL
+#define PAGING_L4      4UL
+#define PAGING_L3      3UL
+#define PAGING_L2      2UL
+#define PAGING_L1      1UL
 #define L_MASK  0xff
 
-#define ROOT_LEVEL_64   L4
-#define ROOT_LEVEL_32   L2
+#define ROOT_LEVEL_64   PAGING_L4
+#define ROOT_LEVEL_32   PAGING_L2
 
 #define SHADOW_ENTRY    (2UL << 16)
 #define GUEST_ENTRY     (1UL << 16)
@@ -58,6 +59,10 @@
 #define SET_ENTRY   (1UL << 8)
 
 #define PAGETABLE_ENTRIES    (1<<PAGETABLE_ORDER)
+
+/* For 32-bit VMX guest to allocate shadow L1 & L2*/
+#define SL1_ORDER   1
+#define SL2_ORDER   2
 
 typedef struct { intpte_t lo; } pgentry_64_t;
 #define shadow_level_to_type(l)    (l << 29)
@@ -76,6 +81,10 @@
 #define entry_remove_flags(x, flags) ((x).lo &= ~put_pte_flags(flags))
 #define entry_has_changed(x,y,flags) \
         ( !!(((x).lo ^ (y).lo) & 
((PADDR_MASK&PAGE_MASK)|put_pte_flags(flags))) )
+
+#define PAE_SHADOW_SELF_ENTRY   259
+#define PDP_ENTRIES   4
+
 static inline int  table_offset_64(unsigned long va, int level)
 {
     switch(level) {
@@ -86,8 +95,13 @@
         case 3:
             return  (((va) >> L3_PAGETABLE_SHIFT) & (L3_PAGETABLE_ENTRIES - 
1));
 #if CONFIG_PAGING_LEVELS >= 4
+#ifndef GUEST_PGENTRY_32
         case 4:
             return  (((va) >> L4_PAGETABLE_SHIFT) & (L4_PAGETABLE_ENTRIES - 
1));
+#else
+        case 4:
+            return PAE_SHADOW_SELF_ENTRY; 
+#endif
 #endif
         default:
             //printk("<table_offset_64> level %d is too big\n", level);
@@ -165,30 +179,30 @@
     return le_e;
 }
 #define __shadow_set_l4e(v, va, value) \
-  __rw_entry(v, va, value, SHADOW_ENTRY | SET_ENTRY | L4)
+  __rw_entry(v, va, value, SHADOW_ENTRY | SET_ENTRY | PAGING_L4)
 #define __shadow_get_l4e(v, va, sl4e) \
-  __rw_entry(v, va, sl4e, SHADOW_ENTRY | GET_ENTRY | L4)
+  __rw_entry(v, va, sl4e, SHADOW_ENTRY | GET_ENTRY | PAGING_L4)
 #define __shadow_set_l3e(v, va, value) \
-  __rw_entry(v, va, value, SHADOW_ENTRY | SET_ENTRY | L3)
+  __rw_entry(v, va, value, SHADOW_ENTRY | SET_ENTRY | PAGING_L3)
 #define __shadow_get_l3e(v, va, sl3e) \
-  __rw_entry(v, va, sl3e, SHADOW_ENTRY | GET_ENTRY | L3)
+  __rw_entry(v, va, sl3e, SHADOW_ENTRY | GET_ENTRY | PAGING_L3)
 #define __shadow_set_l2e(v, va, value) \
-  __rw_entry(v, va, value, SHADOW_ENTRY | SET_ENTRY | L2)
+  __rw_entry(v, va, value, SHADOW_ENTRY | SET_ENTRY | PAGING_L2)
 #define __shadow_get_l2e(v, va, sl2e) \
-  __rw_entry(v, va, sl2e, SHADOW_ENTRY | GET_ENTRY | L2)
+  __rw_entry(v, va, sl2e, SHADOW_ENTRY | GET_ENTRY | PAGING_L2)
 #define __shadow_set_l1e(v, va, value) \
-  __rw_entry(v, va, value, SHADOW_ENTRY | SET_ENTRY | L1)
+  __rw_entry(v, va, value, SHADOW_ENTRY | SET_ENTRY | PAGING_L1)
 #define __shadow_get_l1e(v, va, sl1e) \
-  __rw_entry(v, va, sl1e, SHADOW_ENTRY | GET_ENTRY | L1)
+  __rw_entry(v, va, sl1e, SHADOW_ENTRY | GET_ENTRY | PAGING_L1)
 
 #define __guest_set_l4e(v, va, value) \
-  __rw_entry(v, va, value, GUEST_ENTRY | SET_ENTRY | L4)
+  __rw_entry(v, va, value, GUEST_ENTRY | SET_ENTRY | PAGING_L4)
 #define __guest_get_l4e(v, va, gl4e) \
-  __rw_entry(v, va, gl4e, GUEST_ENTRY | GET_ENTRY | L4)
+  __rw_entry(v, va, gl4e, GUEST_ENTRY | GET_ENTRY | PAGING_L4)
 #define __guest_set_l3e(v, va, value) \
-  __rw_entry(v, va, value, GUEST_ENTRY | SET_ENTRY | L3)
+  __rw_entry(v, va, value, GUEST_ENTRY | SET_ENTRY | PAGING_L3)
 #define __guest_get_l3e(v, va, sl3e) \
-  __rw_entry(v, va, gl3e, GUEST_ENTRY | GET_ENTRY | L3)
+  __rw_entry(v, va, gl3e, GUEST_ENTRY | GET_ENTRY | PAGING_L3)
 
 static inline void *  __guest_set_l2e(
     struct vcpu *v, u64 va, void *value, int size)
@@ -205,7 +219,7 @@
                 return &l2va[l2_table_offset_32(va)];
             }
         case 8:
-            return __rw_entry(v, va, value, GUEST_ENTRY | SET_ENTRY | L2);
+            return __rw_entry(v, va, value, GUEST_ENTRY | SET_ENTRY | 
PAGING_L2);
         default:
             BUG();
             return NULL;
@@ -230,7 +244,7 @@
                 return &l2va[l2_table_offset_32(va)];
             }
         case 8:
-            return __rw_entry(v, va, gl2e, GUEST_ENTRY | GET_ENTRY | L2);
+            return __rw_entry(v, va, gl2e, GUEST_ENTRY | GET_ENTRY | 
PAGING_L2);
         default:
             BUG();
             return NULL;
@@ -269,7 +283,7 @@
             }
 
         case 8:
-            return __rw_entry(v, va, value, GUEST_ENTRY | SET_ENTRY | L1);
+            return __rw_entry(v, va, value, GUEST_ENTRY | SET_ENTRY | 
PAGING_L1);
         default:
             BUG();
             return NULL;
@@ -310,7 +324,7 @@
             }
         case 8:
             // 64-bit guest
-            return __rw_entry(v, va, gl1e, GUEST_ENTRY | GET_ENTRY | L1);
+            return __rw_entry(v, va, gl1e, GUEST_ENTRY | GET_ENTRY | 
PAGING_L1);
         default:
             BUG();
             return NULL;
@@ -334,7 +348,7 @@
     sle = entry_empty();
     if ( (entry_get_flags(gle) & _PAGE_PRESENT) && (smfn != 0) )
     {
-        if ((entry_get_flags(gle) & _PAGE_PSE) && level == L2) {
+        if ((entry_get_flags(gle) & _PAGE_PSE) && level == PAGING_L2) {
             sle = entry_from_pfn(smfn, entry_get_flags(gle));
             entry_remove_flags(sle, _PAGE_PSE);
 
@@ -376,7 +390,7 @@
     unsigned long smfn = 0;
 
     if ( entry_get_flags(gle) & _PAGE_PRESENT ) {
-        if ((entry_get_flags(gle) & _PAGE_PSE) && level == L2) {
+        if ((entry_get_flags(gle) & _PAGE_PSE) && level == PAGING_L2) {
             smfn =  __shadow_status(d, entry_get_value(gle) >> PAGE_SHIFT, 
PGT_fl1_shadow);
         } else {
             smfn =  __shadow_status(d, entry_get_pfn(gle), 
@@ -421,88 +435,6 @@
     return 1;
 }
 
-/*
- * Check P, R/W, U/S bits in the guest page table.
- * If the fault belongs to guest return 1,
- * else return 0.
- */
-static inline int guest_page_fault(struct vcpu *v,
-  unsigned long va, unsigned int error_code, pgentry_64_t *gpl2e, pgentry_64_t 
*gpl1e)
-{
-    struct domain *d = v->domain;
-    pgentry_64_t gle, *lva;
-    unsigned long mfn;
-    int i;
-
-    __rw_entry(v, va, &gle, GUEST_ENTRY | GET_ENTRY | L4);
-    if (unlikely(!(entry_get_flags(gle) & _PAGE_PRESENT)))
-        return 1;
-
-    if (error_code & ERROR_W) {
-        if (unlikely(!(entry_get_flags(gle) & _PAGE_RW)))
-            return 1;
-    }
-    if (error_code & ERROR_U) {
-        if (unlikely(!(entry_get_flags(gle) & _PAGE_USER)))
-            return 1;
-    }
-    for (i = L3; i >= L1; i--) {
-       /*
-        * If it's not external mode, then mfn should be machine physical.
-        */
-       mfn = __gpfn_to_mfn(d, (entry_get_paddr(gle) >> PAGE_SHIFT));
-        if (mfn == -1)
-            return 1;
-
-        lva = (pgentry_64_t *) phys_to_virt(
-           mfn << PAGE_SHIFT);
-        gle = lva[table_offset_64(va, i)];
-
-        if (unlikely(!(entry_get_flags(gle) & _PAGE_PRESENT)))
-            return 1;
-
-        if (error_code & ERROR_W) {
-            if (unlikely(!(entry_get_flags(gle) & _PAGE_RW)))
-                return 1;
-        }
-        if (error_code & ERROR_U) {
-            if (unlikely(!(entry_get_flags(gle) & _PAGE_USER)))
-                return 1;
-        }
-
-        if (i == L2) {
-            if (gpl2e)
-                *gpl2e = gle;
-
-            if (likely(entry_get_flags(gle) & _PAGE_PSE))
-                return 0;
-
-        }
-
-        if (i == L1)
-            if (gpl1e)
-                *gpl1e = gle;
-    }
-    return 0;
-}
-
-static inline unsigned long gva_to_gpa(unsigned long gva)
-{
-    struct vcpu *v = current;
-    pgentry_64_t gl1e = {0};
-    pgentry_64_t gl2e = {0};
-    unsigned long gpa;
-
-    if (guest_page_fault(v, gva, 0, &gl2e, &gl1e))
-        return 0;
-    if (entry_get_flags(gl2e) & _PAGE_PSE)
-        gpa = entry_get_paddr(gl2e) + (gva & ((1 << L2_PAGETABLE_SHIFT) - 1));
-    else
-        gpa = entry_get_paddr(gl1e) + (gva & ~PAGE_MASK);
-
-    return gpa;
-
-}
 #endif
 
 
diff -r 95cfc001ddd1 -r 8b87d43412bf xen/include/asm-x86/shadow_public.h
--- a/xen/include/asm-x86/shadow_public.h       Fri Sep  2 09:02:13 2005
+++ b/xen/include/asm-x86/shadow_public.h       Fri Sep  2 09:43:32 2005
@@ -49,6 +49,7 @@
          (*mark_mfn_out_of_sync)(struct vcpu *v, unsigned long gpfn,
                               unsigned long mfn);
     int  (*is_out_of_sync)(struct vcpu *v, unsigned long va);
+    unsigned long (*gva_to_gpa)(unsigned long gva);
 };
 #endif
 

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


 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.