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

[Xen-changelog] [xen-unstable] Make xc_translate_foreign_address aware of compat-mode guests and



# HG changeset patch
# User Keir Fraser <keir.fraser@xxxxxxxxxx>
# Date 1231153705 0
# Node ID 34f52eafd4e32b297a24f58cef60770e00c5bb15
# Parent  5ce75a8eec7fa4274f210bd1dfad91493199972a
Make xc_translate_foreign_address aware of compat-mode guests and
(32-bit) HVM guests.  64-bit HVM guests are still not supported for
now, pending a sensible way of getting at the guest's EFER.LMA.

Signed-off-by: Tim Deegan <Tim.Deegan@xxxxxxxxxx>
---
 tools/libxc/xc_pagetab.c |  235 +++++++++++++++--------------------------------
 tools/libxc/xenctrl.h    |    4 
 2 files changed, 77 insertions(+), 162 deletions(-)

diff -r 5ce75a8eec7f -r 34f52eafd4e3 tools/libxc/xc_pagetab.c
--- a/tools/libxc/xc_pagetab.c  Mon Jan 05 10:47:51 2009 +0000
+++ b/tools/libxc/xc_pagetab.c  Mon Jan 05 11:08:25 2009 +0000
@@ -4,181 +4,96 @@
  * Function to translate virtual to physical addresses.
  */
 #include "xc_private.h"
+#include <strings.h>
 
-#if defined(__i386__)
-
-#define L1_PAGETABLE_SHIFT_PAE 12
-#define L2_PAGETABLE_SHIFT_PAE 21
-#define L3_PAGETABLE_SHIFT_PAE 30
-
-#define L1_PAGETABLE_SHIFT             12
-#define L2_PAGETABLE_SHIFT             22
-
-#define L0_PAGETABLE_MASK_PAE  0x00000ffffffff000ULL
-#define L1_PAGETABLE_MASK_PAE  0x1ffULL
-#define L2_PAGETABLE_MASK_PAE  0x1ffULL
-#define L3_PAGETABLE_MASK_PAE  0x3ULL
-
-#define L0_PAGETABLE_MASK              0xfffff000ULL
-#define L1_PAGETABLE_MASK              0x3ffULL
-#define L2_PAGETABLE_MASK              0x3ffULL
-
-#elif defined(__x86_64__)
-
-#define L1_PAGETABLE_SHIFT_PAE 12
-#define L2_PAGETABLE_SHIFT_PAE 21
-#define L3_PAGETABLE_SHIFT_PAE 30
-#define L4_PAGETABLE_SHIFT_PAE 39
-
-#define L1_PAGETABLE_SHIFT             L1_PAGETABLE_SHIFT_PAE
-#define L2_PAGETABLE_SHIFT             L2_PAGETABLE_SHIFT_PAE
-
-#define L0_PAGETABLE_MASK_PAE  0x000ffffffffff000ULL
-#define L1_PAGETABLE_MASK_PAE  0x1ffULL
-#define L2_PAGETABLE_MASK_PAE  0x1ffULL
-#define L3_PAGETABLE_MASK_PAE  0x1ffULL
-#define L4_PAGETABLE_MASK_PAE  0x1ffULL
-
-#define L0_PAGETABLE_MASK              L0_PAGETABLE_MASK_PAE
-#define L1_PAGETABLE_MASK              L1_PAGETABLE_MASK_PAE
-#define L2_PAGETABLE_MASK              L2_PAGETABLE_MASK_PAE
-
-#endif
+#define CR0_PG  0x80000000
+#define CR4_PAE 0x20
+#define PTE_PSE 0x80
 
 unsigned long xc_translate_foreign_address(int xc_handle, uint32_t dom,
-                                           int vcpu, unsigned long long virt )
+                                           int vcpu, unsigned long long virt)
 {
+    xc_dominfo_t dominfo;
     vcpu_guest_context_any_t ctx;
-    unsigned long long cr3;
-    void *pd, *pt, *pdppage = NULL, *pdp, *pml = NULL;
-    unsigned long long pde, pte, pdpe, pmle;
-    unsigned long mfn = 0;
-#if defined (__i386__)
-    static int pt_levels = 0;
+    uint64_t paddr, mask, pte = 0;
+    int size, level, pt_levels = 2;
+    void *map;
 
-    if (pt_levels == 0) {
+    if (xc_domain_getinfo(xc_handle, dom, 1, &dominfo) != 1 
+        || dominfo.domid != dom
+        || xc_vcpu_getcontext(xc_handle, dom, vcpu, &ctx) != 0)
+        return 0;
+
+    /* What kind of paging are we dealing with? */
+    if (dominfo.hvm) {
+        unsigned long cr0, cr3, cr4;
         xen_capabilities_info_t xen_caps = "";
-
         if (xc_version(xc_handle, XENVER_capabilities, &xen_caps) != 0)
-            goto out;
-        if (strstr(xen_caps, "xen-3.0-x86_64"))
+            return 0;
+        /* HVM context records are always host-sized */
+        if (strstr(xen_caps, "xen-3.0-x86_64")) {
+            cr0 = ctx.x64.ctrlreg[0];
+            cr3 = ctx.x64.ctrlreg[3];
+            cr4 = ctx.x64.ctrlreg[4];
+        } else {
+            cr0 = ctx.x32.ctrlreg[0];
+            cr3 = ctx.x32.ctrlreg[3];
+            cr4 = ctx.x32.ctrlreg[4];
+        }
+        if (!(cr0 & CR0_PG))
+            return virt;
+        if (0 /* XXX how to get EFER.LMA? */) 
             pt_levels = 4;
-        else if (strstr(xen_caps, "xen-3.0-x86_32p"))
+        else
+            pt_levels = (cr4 & CR4_PAE) ? 3 : 2;
+        paddr = cr3 & ((pt_levels == 3) ? ~0x1full : ~0xfffull);
+    } else {
+        DECLARE_DOMCTL;
+        domctl.domain = dom;
+        domctl.cmd = XEN_DOMCTL_get_address_size;
+        if ( do_domctl(xc_handle, &domctl) != 0 )
+            return 0;
+        if (domctl.u.address_size.size == 64) {
+            pt_levels = 4;
+            paddr = ctx.x64.ctrlreg[3] & ~0xfffull;
+        } else {
             pt_levels = 3;
-        else if (strstr(xen_caps, "xen-3.0-x86_32"))
-            pt_levels = 2;
-        else
-            goto out;
-    }
-#elif defined (__x86_64__)
-#define pt_levels 4
-#endif
-
-    if (xc_vcpu_getcontext(xc_handle, dom, vcpu, &ctx) != 0) {
-        DPRINTF("failed to retreive vcpu context\n");
-        goto out;
-    }
-    cr3 = ((unsigned long long)xen_cr3_to_pfn(ctx.c.ctrlreg[3])) << PAGE_SHIFT;
-
-    /* Page Map Level 4 */
-
-#if defined(__i386__)
-    pmle = cr3;
-#elif defined(__x86_64__)
-    pml = xc_map_foreign_range(xc_handle, dom, PAGE_SIZE, PROT_READ, cr3 >> 
PAGE_SHIFT);
-    if (pml == NULL) {
-        DPRINTF("failed to map PML4\n");
-        goto out;
-    }
-    pmle = *(unsigned long long *)(pml + 8 * ((virt >> L4_PAGETABLE_SHIFT_PAE) 
& L4_PAGETABLE_MASK_PAE));
-    if((pmle & 1) == 0) {
-        DPRINTF("page entry not present in PML4\n");
-        goto out_unmap_pml;
-    }
-#endif
-
-    /* Page Directory Pointer Table */
-
-    if (pt_levels >= 3) {
-        pdppage = xc_map_foreign_range(xc_handle, dom, PAGE_SIZE, PROT_READ, 
pmle >> PAGE_SHIFT);
-        if (pdppage == NULL) {
-            DPRINTF("failed to map PDP\n");
-            goto out_unmap_pml;
+            paddr = (((uint64_t) xen_cr3_to_pfn(ctx.x32.ctrlreg[3])) 
+                     << PAGE_SHIFT);
         }
-        if (pt_levels >= 4)
-            pdp = pdppage;
-        else
-            /* PDP is only 32 bit aligned with 3 level pts */
-            pdp = pdppage + (pmle & ~(XC_PAGE_MASK | 0x1f));
-
-        pdpe = *(unsigned long long *)(pdp + 8 * ((virt >> 
L3_PAGETABLE_SHIFT_PAE) & L3_PAGETABLE_MASK_PAE));
-
-        if((pdpe & 1) == 0) {
-            DPRINTF("page entry not present in PDP\n");
-            goto out_unmap_pdp;
-        }
-    } else {
-        pdpe = pmle;
     }
 
-    /* Page Directory */
+    if (pt_levels == 4) {
+        virt &= 0x0000ffffffffffffull;
+        mask =  0x0000ff8000000000ull;
+    } else if (pt_levels == 3) {
+        virt &= 0x00000000ffffffffull;
+        mask =  0x0000007fc0000000ull;
+    } else {
+        virt &= 0x00000000ffffffffull;
+        mask =  0x00000000ffc00000ull;
+    }
+    size = (pt_levels == 2 ? 4 : 8);
 
-    pd = xc_map_foreign_range(xc_handle, dom, PAGE_SIZE, PROT_READ, pdpe >> 
PAGE_SHIFT);
-    if (pd == NULL) {
-        DPRINTF("failed to map PD\n");
-        goto out_unmap_pdp;
+    /* Walk the pagetables */
+    for (level = pt_levels; level > 0; level--) {
+        paddr += ((virt & mask) >> (ffsll(mask) - 1)) * size;
+        map = xc_map_foreign_range(xc_handle, dom, PAGE_SIZE, PROT_READ, 
+                                   paddr >>PAGE_SHIFT);
+        if (!map) 
+            return 0;
+        memcpy(&pte, map + (paddr & (PAGE_SIZE - 1)), size);
+        munmap(map, PAGE_SIZE);
+        if (!(pte & 1)) 
+            return 0;
+        paddr = pte & 0x000ffffffffff000ull;
+        if (level == 2 && (pte & PTE_PSE)) {
+            mask = ((mask ^ ~-mask) >> 1); /* All bits below first set bit */
+            return ((paddr & ~mask) | (virt & mask)) >> PAGE_SHIFT;
+        }
+        mask >>= (pt_levels == 2 ? 10 : 9);
     }
-
-    if (pt_levels >= 3)
-        pde = *(unsigned long long *)(pd + 8 * ((virt >> 
L2_PAGETABLE_SHIFT_PAE) & L2_PAGETABLE_MASK_PAE));
-    else
-        pde = *(unsigned long *)(pd + 4 * ((virt >> L2_PAGETABLE_SHIFT) & 
L2_PAGETABLE_MASK));
-
-    if ((pde & 1) == 0) {
-        DPRINTF("page entry not present in PD\n");
-        goto out_unmap_pd;
-    }
-
-    /* Page Table */
-
-    if (pde & 0x00000080) { /* 4M page (or 2M in PAE mode) */
-        DPRINTF("Cannot currently cope with 2/4M pages\n");
-        exit(-1);
-    } else { /* 4k page */
-        pt = xc_map_foreign_range(xc_handle, dom, PAGE_SIZE, PROT_READ,
-                                  pde >> PAGE_SHIFT);
-
-        if (pt == NULL) {
-            DPRINTF("failed to map PT\n");
-            goto out_unmap_pd;
-        }
-
-        if (pt_levels >= 3)
-            pte = *(unsigned long long *)(pt + 8 * ((virt >> 
L1_PAGETABLE_SHIFT_PAE) & L1_PAGETABLE_MASK_PAE));
-        else
-            pte = *(unsigned long *)(pt + 4 * ((virt >> L1_PAGETABLE_SHIFT) & 
L1_PAGETABLE_MASK));
-
-        if ((pte & 1) == 0) {
-            DPRINTF("page entry not present in PT\n");
-            goto out_unmap_pt;
-        }
-
-        if (pt_levels >= 3)
-            mfn = (pte & L0_PAGETABLE_MASK_PAE) >> PAGE_SHIFT;
-        else
-            mfn = (pte & L0_PAGETABLE_MASK) >> PAGE_SHIFT;
-    }
-
- out_unmap_pt:
-    munmap(pt, PAGE_SIZE);
- out_unmap_pd:
-    munmap(pd, PAGE_SIZE);
- out_unmap_pdp:
-    munmap(pdppage, PAGE_SIZE);
- out_unmap_pml:
-    munmap(pml, PAGE_SIZE);
- out:
-    return mfn;
+    return paddr >> PAGE_SHIFT;
 }
 
 /*
diff -r 5ce75a8eec7f -r 34f52eafd4e3 tools/libxc/xenctrl.h
--- a/tools/libxc/xenctrl.h     Mon Jan 05 10:47:51 2009 +0000
+++ b/tools/libxc/xenctrl.h     Mon Jan 05 11:08:25 2009 +0000
@@ -716,8 +716,8 @@ void *xc_map_foreign_batch(int xc_handle
 
 /**
  * Translates a virtual address in the context of a given domain and
- * vcpu returning the machine page frame number of the associated
- * page.
+ * vcpu returning the GFN containing the address (that is, an MFN for 
+ * PV guests, a PFN for HVM guests).  Returns 0 for failure.
  *
  * @parm xc_handle a handle on an open hypervisor interface
  * @parm dom the domain to perform the translation in

_______________________________________________
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®.