x86/mm: adjust paging interface to return superpage sizes
authorTim Deegan <tim@xen.org>
Thu, 8 Sep 2011 14:13:06 +0000 (15:13 +0100)
committerTim Deegan <tim@xen.org>
Thu, 8 Sep 2011 14:13:06 +0000 (15:13 +0100)
to the caller of paging_ga_to_gfn_cr3()

Signed-off-by: Christoph Egger <Christoph.Egger@amd.com>
Signed-off-by: Tim Deegan <tim@xen.org>
Committed-by: Tim Deegan <tim@xen.org>
xen/arch/x86/mm/hap/guest_walk.c
xen/arch/x86/mm/hap/hap.c
xen/arch/x86/mm/hap/nested_hap.c
xen/arch/x86/mm/hap/private.h
xen/arch/x86/mm/p2m.c
xen/include/asm-x86/guest_pt.h
xen/include/asm-x86/paging.h

index 24ff59c196d0f7bfec20d6a8ae75b50e969a9ae5..78ae03219503789984cb25801f4377127b78caaf 100644 (file)
@@ -43,12 +43,12 @@ unsigned long hap_gva_to_gfn(GUEST_PAGING_LEVELS)(
     struct vcpu *v, struct p2m_domain *p2m, unsigned long gva, uint32_t *pfec)
 {
     unsigned long cr3 = v->arch.hvm_vcpu.guest_cr[3];
-    return hap_p2m_ga_to_gfn(GUEST_PAGING_LEVELS)(v, p2m, cr3, gva, pfec);
+    return hap_p2m_ga_to_gfn(GUEST_PAGING_LEVELS)(v, p2m, cr3, gva, pfec, NULL);
 }
 
 unsigned long hap_p2m_ga_to_gfn(GUEST_PAGING_LEVELS)(
     struct vcpu *v, struct p2m_domain *p2m, unsigned long cr3,
-    paddr_t ga, uint32_t *pfec)
+    paddr_t ga, uint32_t *pfec, unsigned int *page_order)
 {
     uint32_t missing;
     mfn_t top_mfn;
@@ -107,6 +107,9 @@ unsigned long hap_p2m_ga_to_gfn(GUEST_PAGING_LEVELS)(
             return INVALID_GFN;
         }
 
+        if ( page_order )
+            *page_order = guest_walk_to_page_order(&gw);
+
         return gfn_x(gfn);
     }
 
index f90511ef04d22d263f698e15f1a3aab9f9bc79fd..9f6b990c2a5160c053c4e8bff7f33870f3af1272 100644 (file)
@@ -897,8 +897,10 @@ static unsigned long hap_gva_to_gfn_real_mode(
 
 static unsigned long hap_p2m_ga_to_gfn_real_mode(
     struct vcpu *v, struct p2m_domain *p2m, unsigned long cr3,
-    paddr_t ga, uint32_t *pfec)
+    paddr_t ga, uint32_t *pfec, unsigned int *page_order)
 {
+    if ( page_order )
+        *page_order = PAGE_ORDER_4K;
     return (ga >> PAGE_SHIFT);
 }
 
index 2bab9e71f26c4afbd1ba96edee747415e8de5dc8..d2c833f0f92d21eb38b94b31d78dae4afe92bd1a 100644 (file)
@@ -162,7 +162,7 @@ nestedhap_walk_L1_p2m(struct vcpu *v, paddr_t L2_gpa, paddr_t *L1_gpa)
     nested_cr3 = nhvm_vcpu_hostcr3(v);
 
     /* Walk the guest-supplied NPT table, just as if it were a pagetable */
-    gfn = paging_ga_to_gfn_cr3(v, nested_cr3, L2_gpa, &pfec);
+    gfn = paging_ga_to_gfn_cr3(v, nested_cr3, L2_gpa, &pfec, NULL);
 
     if ( gfn == INVALID_GFN ) 
         return NESTEDHVM_PAGEFAULT_INJECT;
index 6dcd12883816c7ea92c0a7e2258c8f569c997f66..b5c0b6aafd8015591d3411938571d32a7e45d43d 100644 (file)
@@ -40,12 +40,12 @@ unsigned long hap_gva_to_gfn_4_levels(struct vcpu *v,
 
 unsigned long hap_p2m_ga_to_gfn_2_levels(struct vcpu *v,
     struct p2m_domain *p2m, unsigned long cr3,
-    paddr_t ga, uint32_t *pfec);
+    paddr_t ga, uint32_t *pfec, unsigned int *page_order);
 unsigned long hap_p2m_ga_to_gfn_3_levels(struct vcpu *v,
     struct p2m_domain *p2m, unsigned long cr3,
-    paddr_t ga, uint32_t *pfec);
+    paddr_t ga, uint32_t *pfec, unsigned int *page_order);
 unsigned long hap_p2m_ga_to_gfn_4_levels(struct vcpu *v,
     struct p2m_domain *p2m, unsigned long cr3,
-    paddr_t ga, uint32_t *pfec);
+    paddr_t ga, uint32_t *pfec, unsigned int *page_order);
 
 #endif /* __HAP_PRIVATE_H__ */
index c3c8c87c37c865d506356627291d9e237141e517..c6cb98b2e50e76edb9cbe820ebda38e8a680569e 100644 (file)
@@ -1206,7 +1206,7 @@ unsigned long paging_gva_to_gfn(struct vcpu *v,
 
         /* translate l2 guest gfn into l1 guest gfn */
         return hostmode->p2m_ga_to_gfn(v, hostp2m, ncr3,
-            gfn << PAGE_SHIFT, pfec);
+                                       gfn << PAGE_SHIFT, pfec, NULL);
     }
 
     return hostmode->gva_to_gfn(v, hostp2m, va, pfec);
index e3dd07a8d7ad748caeb2727f42aa00cd78fc46a8..9a3b949bf1c60c5d14f640c30992d2a9377b8199 100644 (file)
@@ -272,6 +272,24 @@ guest_walk_to_gpa(walk_t *gw)
     return guest_l1e_get_paddr(gw->l1e) + (gw->va & ~PAGE_MASK);
 }
 
+/* Given a walk_t from a successful walk, return the page-order of the 
+ * page or superpage that the virtual address is in. */
+static inline unsigned int 
+guest_walk_to_page_order(walk_t *gw)
+{
+    /* This is only valid for successful walks - otherwise the 
+     * PSE bits might be invalid. */
+    ASSERT(guest_l1e_get_flags(gw->l1e) & _PAGE_PRESENT);
+#if GUEST_PAGING_LEVELS >= 3
+    if ( guest_l3e_get_flags(gw->l3e) & _PAGE_PSE )
+        return GUEST_L3_PAGETABLE_SHIFT - PAGE_SHIFT;
+#endif
+    if ( guest_l2e_get_flags(gw->l2e) & _PAGE_PSE )
+        return GUEST_L2_PAGETABLE_SHIFT - PAGE_SHIFT;
+    return GUEST_L1_PAGETABLE_SHIFT - PAGE_SHIFT;
+}
+
+
 /* Walk the guest pagetables, after the manner of a hardware walker. 
  *
  * Inputs: a vcpu, a virtual address, a walk_t to fill, a 
index 0a32fe2b4e83aa33f80965b7607daa40a2c356ec..c432a973ed12451312f6fcce5493edea30c1d4c9 100644 (file)
@@ -115,7 +115,8 @@ struct paging_mode {
     unsigned long (*p2m_ga_to_gfn         )(struct vcpu *v,
                                             struct p2m_domain *p2m,
                                             unsigned long cr3,
-                                            paddr_t ga, uint32_t *pfec);
+                                            paddr_t ga, uint32_t *pfec,
+                                            unsigned int *page_order);
     void          (*update_cr3            )(struct vcpu *v, int do_locking);
     void          (*update_paging_modes   )(struct vcpu *v);
     void          (*write_p2m_entry       )(struct vcpu *v, unsigned long gfn,
@@ -270,15 +271,18 @@ unsigned long paging_gva_to_gfn(struct vcpu *v,
  * to by nested HAP code, to walk the guest-supplied NPT tables as if
  * they were pagetables.
  * Use 'paddr_t' for the guest address so it won't overflow when
- * guest or nested guest is in 32bit PAE mode.
- */
+ * l1 or l2 guest is in 32bit PAE mode.
+ * If the GFN returned is not INVALID_GFN, *page_order gives
+ * the size of the superpage (if any) it was found in. */
 static inline unsigned long paging_ga_to_gfn_cr3(struct vcpu *v,
                                                  unsigned long cr3,
                                                  paddr_t ga,
-                                                 uint32_t *pfec)
+                                                 uint32_t *pfec,
+                                                 unsigned int *page_order)
 {
     struct p2m_domain *p2m = v->domain->arch.p2m;
-    return paging_get_hostmode(v)->p2m_ga_to_gfn(v, p2m, cr3, ga, pfec);
+    return paging_get_hostmode(v)->p2m_ga_to_gfn(v, p2m, cr3, ga, pfec,
+        page_order);
 }
 
 /* Update all the things that are derived from the guest's CR3.