aboutsummaryrefslogtreecommitdiffstats
path: root/tools/libxc/xc_pagetab.c
diff options
context:
space:
mode:
authorIan.Campbell@xensource.com <Ian.Campbell@xensource.com>2005-12-22 14:33:19 +0000
committerIan.Campbell@xensource.com <Ian.Campbell@xensource.com>2005-12-22 14:33:19 +0000
commit40924689a9e86c301ebad2e6394ea359ec47b59f (patch)
treed2e6a25ae5d5c8948d474f5d2e6bd51b5d438515 /tools/libxc/xc_pagetab.c
parent4f27f31a471d94f55a39bc9a3eb02ca777112f59 (diff)
downloadxen-40924689a9e86c301ebad2e6394ea359ec47b59f.tar.gz
xen-40924689a9e86c301ebad2e6394ea359ec47b59f.tar.bz2
xen-40924689a9e86c301ebad2e6394ea359ec47b59f.zip
Add support to xenctx for printing stack traces on x86_32 and x86_64.
To support this add xc_translate_foreign_address to libxc. This function walks page tables and translates virtual addresses using a given domain and vcpu page table. Signed-off-by: Ian Campbell <Ian.Campbell@XenSource.com>
Diffstat (limited to 'tools/libxc/xc_pagetab.c')
-rw-r--r--tools/libxc/xc_pagetab.c192
1 files changed, 192 insertions, 0 deletions
diff --git a/tools/libxc/xc_pagetab.c b/tools/libxc/xc_pagetab.c
new file mode 100644
index 0000000000..b63ea89ade
--- /dev/null
+++ b/tools/libxc/xc_pagetab.c
@@ -0,0 +1,192 @@
+/******************************************************************************
+ * xc_pagetab.c
+ *
+ * Function to translate virtual to physical addresses.
+ */
+#include "xc_private.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 0x0000000ffffff000ULL
+#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 0x000000fffffff000ULL
+#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
+
+unsigned long xc_translate_foreign_address(int xc_handle, uint32_t dom,
+ int vcpu, unsigned long long virt )
+{
+ vcpu_guest_context_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;
+
+ if (pt_levels == 0) {
+ 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"))
+ pt_levels = 4;
+ else if (strstr(xen_caps, "xen-3.0-x86_32p"))
+ 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_domain_get_vcpu_context(xc_handle, dom, vcpu, &ctx) != 0) {
+ fprintf(stderr, "failed to retreive vcpu context\n");
+ goto out;
+ }
+ cr3 = ctx.ctrlreg[3];
+
+ /* 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) {
+ fprintf(stderr, "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) {
+ fprintf(stderr, "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) {
+ fprintf(stderr, "failed to map PDP\n");
+ goto out_unmap_pml;
+ }
+ 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) {
+ fprintf(stderr, "page entry not present in PDP\n");
+ goto out_unmap_pdp;
+ }
+ } else {
+ pdpe = pmle;
+ }
+
+ /* Page Directory */
+
+ pd = xc_map_foreign_range(xc_handle, dom, PAGE_SIZE, PROT_READ, pdpe >> PAGE_SHIFT);
+ if (pd == NULL) {
+ fprintf(stderr, "failed to map PD\n");
+ goto out_unmap_pdp;
+ }
+
+ if (pt_levels >= 3)
+ pde = *(unsigned long long *)(pd + 8 * ((virt >> L2_PAGETABLE_SHIFT_PAE) & L2_PAGETABLE_MASK_PAE));
+ else
+ pde = *(unsigned long long *)(pd + 4 * ((virt >> L2_PAGETABLE_SHIFT) & L2_PAGETABLE_MASK));
+
+ if ((pde & 1) == 0) {
+ fprintf(stderr, "page entry not present in PD\n");
+ goto out_unmap_pd;
+ }
+
+ /* Page Table */
+
+ if (pde & 0x00000008) { /* 4M page (or 2M in PAE mode) */
+ fprintf(stderr, "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) {
+ fprintf(stderr, "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 long *)(pt + 4 * ((virt >> L1_PAGETABLE_SHIFT) & L1_PAGETABLE_MASK));
+
+ if ((pte & 0x00000001) == 0) {
+ fprintf(stderr, "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;
+}
+
+/*
+ * Local variables:
+ * mode: C
+ * c-set-style: "BSD"
+ * c-basic-offset: 4
+ * tab-width: 4
+ * indent-tabs-mode: nil
+ * End:
+ */