Files
xen/tools/libxc/xc_pagetab.c
T
kaf24@firebug.cl.cam.ac.uk 2928514138 [LIBXC] Convert all printf/fprintf uses to use a macro instead.
Thus all can be disabled at compile time. It would be easy to
make enabling/disabling a run-time option too.
Signed-off-by: Keir Fraser <keir@xensource.com>
2006-06-07 14:07:36 +01:00

193 lines
5.4 KiB
C

/******************************************************************************
* 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_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.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;
}
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 */
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;
}
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) {
DPRINTF("page entry not present in PD\n");
goto out_unmap_pd;
}
/* Page Table */
if (pde & 0x00000008) { /* 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 long *)(pt + 4 * ((virt >> L1_PAGETABLE_SHIFT) & L1_PAGETABLE_MASK));
if ((pte & 0x00000001) == 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;
}
/*
* Local variables:
* mode: C
* c-set-style: "BSD"
* c-basic-offset: 4
* tab-width: 4
* indent-tabs-mode: nil
* End:
*/