mirror of
https://github.com/xen-project/xen.git
synced 2026-10-28 10:11:27 +01:00
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>
193 lines
5.4 KiB
C
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:
|
|
*/
|