diff options
author | Ian.Campbell@xensource.com <Ian.Campbell@xensource.com> | 2005-12-22 14:33:19 +0000 |
---|---|---|
committer | Ian.Campbell@xensource.com <Ian.Campbell@xensource.com> | 2005-12-22 14:33:19 +0000 |
commit | 40924689a9e86c301ebad2e6394ea359ec47b59f (patch) | |
tree | d2e6a25ae5d5c8948d474f5d2e6bd51b5d438515 /tools/libxc/xc_pagetab.c | |
parent | 4f27f31a471d94f55a39bc9a3eb02ca777112f59 (diff) | |
download | xen-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.c | 192 |
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: + */ |