From: Tim Deegan <Tim.Deegan@citrix.com>
To: xen-devel@lists.xensource.com
Subject: Re: [PATCH] Rework xc_pagetab.c
Date: Mon, 5 Jan 2009 10:58:47 +0000 [thread overview]
Message-ID: <20090105105847.GH12729@york.uk.xensource.com> (raw)
In-Reply-To: <20090105105645.GF12729@york.uk.xensource.com>
[-- Attachment #1: Type: text/plain, Size: 353 bytes --]
Attaching the patch this time...
At 10:56 +0000 on 05 Jan (1231153005), Tim Deegan wrote:
> 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@citrix.com>
>
[-- Attachment #2: xenctx-01-pagewalker --]
[-- Type: text/plain, Size: 9111 bytes --]
diff -r de38a475ab9e tools/libxc/xc_pagetab.c
--- a/tools/libxc/xc_pagetab.c Mon Dec 29 14:13:07 2008 +0000
+++ b/tools/libxc/xc_pagetab.c Mon Jan 05 10:44:00 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 de38a475ab9e tools/libxc/xenctrl.h
--- a/tools/libxc/xenctrl.h Mon Dec 29 14:13:07 2008 +0000
+++ b/tools/libxc/xenctrl.h Mon Jan 05 10:44:00 2009 +0000
@@ -703,8 +703,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
[-- Attachment #3: Type: text/plain, Size: 138 bytes --]
_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xensource.com
http://lists.xensource.com/xen-devel
prev parent reply other threads:[~2009-01-05 10:58 UTC|newest]
Thread overview: 2+ messages / expand[flat|nested] mbox.gz Atom feed top
2009-01-05 10:56 [PATCH] Rework xc_pagetab.c Tim Deegan
2009-01-05 10:58 ` Tim Deegan [this message]
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20090105105847.GH12729@york.uk.xensource.com \
--to=tim.deegan@citrix.com \
--cc=xen-devel@lists.xensource.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
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.