# 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
|