aboutsummaryrefslogtreecommitdiffstats
path: root/tools/libxc
diff options
context:
space:
mode:
Diffstat (limited to 'tools/libxc')
-rw-r--r--tools/libxc/xc_domain.c127
-rw-r--r--tools/libxc/xc_offline_page.c185
-rw-r--r--tools/libxc/xenguest.h17
-rw-r--r--tools/libxc/xg_private.h9
4 files changed, 183 insertions, 155 deletions
diff --git a/tools/libxc/xc_domain.c b/tools/libxc/xc_domain.c
index 3210e34a73..81316d3c7f 100644
--- a/tools/libxc/xc_domain.c
+++ b/tools/libxc/xc_domain.c
@@ -21,6 +21,8 @@
*/
#include "xc_private.h"
+#include "xc_core.h"
+#include "xg_private.h"
#include "xg_save_restore.h"
#include <xen/memory.h>
#include <xen/hvm/hvm_op.h>
@@ -1477,6 +1479,131 @@ int xc_domain_bind_pt_isa_irq(
PT_IRQ_TYPE_ISA, 0, 0, 0, machine_irq));
}
+int xc_unmap_domain_meminfo(xc_interface *xch, struct xc_domain_meminfo *minfo)
+{
+ struct domain_info_context _di = { .guest_width = minfo->guest_width };
+ struct domain_info_context *dinfo = &_di;
+
+ free(minfo->pfn_type);
+ if ( minfo->p2m_table )
+ munmap(minfo->p2m_table, P2M_FLL_ENTRIES * PAGE_SIZE);
+ minfo->p2m_table = NULL;
+
+ return 0;
+}
+
+int xc_map_domain_meminfo(xc_interface *xch, int domid,
+ struct xc_domain_meminfo *minfo)
+{
+ struct domain_info_context _di;
+ struct domain_info_context *dinfo = &_di;
+
+ xc_dominfo_t info;
+ shared_info_any_t *live_shinfo;
+ xen_capabilities_info_t xen_caps = "";
+ int i;
+
+ /* Only be initialized once */
+ if ( minfo->pfn_type || minfo->p2m_table )
+ {
+ errno = EINVAL;
+ return -1;
+ }
+
+ if ( xc_domain_getinfo(xch, domid, 1, &info) != 1 )
+ {
+ PERROR("Could not get domain info");
+ return -1;
+ }
+
+ if ( xc_domain_get_guest_width(xch, domid, &minfo->guest_width) )
+ {
+ PERROR("Could not get domain address size");
+ return -1;
+ }
+ _di.guest_width = minfo->guest_width;
+
+ /* Get page table levels (see get_platform_info() in xg_save_restore.h */
+ if ( xc_version(xch, XENVER_capabilities, &xen_caps) )
+ {
+ PERROR("Could not get Xen capabilities (for page table levels)");
+ return -1;
+ }
+ if ( strstr(xen_caps, "xen-3.0-x86_64") )
+ /* Depends on whether it's a compat 32-on-64 guest */
+ minfo->pt_levels = ( (minfo->guest_width == 8) ? 4 : 3 );
+ else if ( strstr(xen_caps, "xen-3.0-x86_32p") )
+ minfo->pt_levels = 3;
+ else if ( strstr(xen_caps, "xen-3.0-x86_32") )
+ minfo->pt_levels = 2;
+ else
+ {
+ errno = EFAULT;
+ return -1;
+ }
+
+ /* We need the shared info page for mapping the P2M */
+ live_shinfo = xc_map_foreign_range(xch, domid, PAGE_SIZE, PROT_READ,
+ info.shared_info_frame);
+ if ( !live_shinfo )
+ {
+ PERROR("Could not map the shared info frame (MFN 0x%lx)",
+ info.shared_info_frame);
+ return -1;
+ }
+
+ if ( xc_core_arch_map_p2m_writable(xch, minfo->guest_width, &info,
+ live_shinfo, &minfo->p2m_table,
+ &minfo->p2m_size) )
+ {
+ PERROR("Could not map the P2M table");
+ munmap(live_shinfo, PAGE_SIZE);
+ return -1;
+ }
+ munmap(live_shinfo, PAGE_SIZE);
+ _di.p2m_size = minfo->p2m_size;
+
+ /* Make space and prepare for getting the PFN types */
+ minfo->pfn_type = calloc(sizeof(*minfo->pfn_type), minfo->p2m_size);
+ if ( !minfo->pfn_type )
+ {
+ PERROR("Could not allocate memory for the PFN types");
+ goto failed;
+ }
+ for ( i = 0; i < minfo->p2m_size; i++ )
+ minfo->pfn_type[i] = pfn_to_mfn(i, minfo->p2m_table,
+ minfo->guest_width);
+
+ /* Retrieve PFN types in batches */
+ for ( i = 0; i < minfo->p2m_size ; i+=1024 )
+ {
+ int count = ((minfo->p2m_size - i ) > 1024 ) ?
+ 1024: (minfo->p2m_size - i);
+
+ if ( xc_get_pfn_type_batch(xch, domid, count, minfo->pfn_type + i) )
+ {
+ PERROR("Could not get %d-eth batch of PFN types", (i+1)/1024);
+ goto failed;
+ }
+ }
+
+ return 0;
+
+failed:
+ if ( minfo->pfn_type )
+ {
+ free(minfo->pfn_type);
+ minfo->pfn_type = NULL;
+ }
+ if ( minfo->p2m_table )
+ {
+ munmap(minfo->p2m_table, P2M_FLL_ENTRIES * PAGE_SIZE);
+ minfo->p2m_table = NULL;
+ }
+
+ return -1;
+}
+
int xc_domain_memory_mapping(
xc_interface *xch,
uint32_t domid,
diff --git a/tools/libxc/xc_offline_page.c b/tools/libxc/xc_offline_page.c
index 1f6dbc6d5e..fbb53f5f0f 100644
--- a/tools/libxc/xc_offline_page.c
+++ b/tools/libxc/xc_offline_page.c
@@ -33,17 +33,6 @@
#include "xg_private.h"
#include "xg_save_restore.h"
-struct domain_mem_info{
- int domid;
- unsigned int pt_level;
- unsigned int guest_width;
- xen_pfn_t *pfn_type;
- xen_pfn_t *p2m_table;
- unsigned long p2m_size;
- xen_pfn_t *m2p_table;
- int max_mfn;
-};
-
struct pte_backup_entry
{
xen_pfn_t table_mfn;
@@ -180,139 +169,6 @@ static int xc_is_page_granted_v2(xc_interface *xch, xen_pfn_t gpfn,
return (i != gnt_num);
}
-static xen_pfn_t pfn_to_mfn(xen_pfn_t pfn, xen_pfn_t *p2m, int gwidth)
-{
- return ((xen_pfn_t) ((gwidth==8)?
- (((uint64_t *)p2m)[(pfn)]):
- ((((uint32_t *)p2m)[(pfn)]) == 0xffffffffU ?
- (-1UL) :
- (((uint32_t *)p2m)[(pfn)]))));
-}
-
-static int get_pt_level(xc_interface *xch, uint32_t domid,
- unsigned int *pt_level,
- unsigned int *gwidth)
-{
- xen_capabilities_info_t xen_caps = "";
-
- if (xc_version(xch, XENVER_capabilities, &xen_caps) != 0)
- return -1;
-
- if (xc_domain_get_guest_width(xch, domid, gwidth) != 0)
- return -1;
-
- if (strstr(xen_caps, "xen-3.0-x86_64"))
- /* Depends on whether it's a compat 32-on-64 guest */
- *pt_level = ( (*gwidth == 8) ? 4 : 3 );
- else if (strstr(xen_caps, "xen-3.0-x86_32p"))
- *pt_level = 3;
- else if (strstr(xen_caps, "xen-3.0-x86_32"))
- *pt_level = 2;
- else
- return -1;
-
- return 0;
-}
-
-static int close_mem_info(xc_interface *xch, struct domain_mem_info *minfo)
-{
- if (minfo->pfn_type)
- free(minfo->pfn_type);
- munmap(minfo->m2p_table, M2P_SIZE(minfo->max_mfn));
- munmap(minfo->p2m_table, P2M_FLL_ENTRIES * PAGE_SIZE);
- minfo->p2m_table = minfo->m2p_table = NULL;
-
- return 0;
-}
-
-static int init_mem_info(xc_interface *xch, int domid,
- struct domain_mem_info *minfo,
- xc_dominfo_t *info)
-{
- uint64_aligned_t shared_info_frame;
- shared_info_any_t *live_shinfo = NULL;
- int i, rc;
-
- /* Only be initialized once */
- if (minfo->pfn_type || minfo->m2p_table || minfo->p2m_table)
- return -EINVAL;
-
- if ( get_pt_level(xch, domid, &minfo->pt_level,
- &minfo->guest_width) )
- {
- ERROR("Unable to get PT level info.");
- return -EFAULT;
- }
- dinfo->guest_width = minfo->guest_width;
-
- shared_info_frame = info->shared_info_frame;
-
- live_shinfo = xc_map_foreign_range(xch, domid,
- PAGE_SIZE, PROT_READ, shared_info_frame);
- if ( !live_shinfo )
- {
- ERROR("Couldn't map live_shinfo");
- return -EFAULT;
- }
-
- if ( (rc = xc_core_arch_map_p2m_writable(xch, minfo->guest_width,
- info, live_shinfo, &minfo->p2m_table, &minfo->p2m_size)) )
- {
- ERROR("Couldn't map p2m table %x\n", rc);
- goto failed;
- }
- munmap(live_shinfo, PAGE_SIZE);
- live_shinfo = NULL;
-
- dinfo->p2m_size = minfo->p2m_size;
-
- minfo->max_mfn = xc_maximum_ram_page(xch);
- if ( !(minfo->m2p_table =
- xc_map_m2p(xch, minfo->max_mfn, PROT_READ, NULL)) )
- {
- ERROR("Failed to map live M2P table");
- goto failed;
- }
-
- /* Get pfn type */
- minfo->pfn_type = calloc(sizeof(*minfo->pfn_type), minfo->p2m_size);
- if (!minfo->pfn_type)
- {
- ERROR("Failed to malloc pfn_type\n");
- goto failed;
- }
-
- for (i = 0; i < minfo->p2m_size; i++)
- minfo->pfn_type[i] = pfn_to_mfn(i, minfo->p2m_table,
- minfo->guest_width);
-
- for (i = 0; i < minfo->p2m_size ; i+=1024)
- {
- int count = ((dinfo->p2m_size - i ) > 1024 ) ? 1024: (dinfo->p2m_size - i);
- if ( ( rc = xc_get_pfn_type_batch(xch, domid, count,
- minfo->pfn_type + i)) )
- {
- ERROR("Failed to get pfn_type %x\n", rc);
- goto failed;
- }
- }
- return 0;
-
-failed:
- if (minfo->pfn_type)
- {
- free(minfo->pfn_type);
- minfo->pfn_type = NULL;
- }
- if (live_shinfo)
- munmap(live_shinfo, PAGE_SIZE);
- munmap(minfo->m2p_table, M2P_SIZE(minfo->max_mfn));
- munmap(minfo->p2m_table, P2M_FLL_ENTRIES * PAGE_SIZE);
- minfo->p2m_table = minfo->m2p_table = NULL;
-
- return -1;
-}
-
static int backup_ptes(xen_pfn_t table_mfn, int offset,
struct pte_backup *backup)
{
@@ -402,7 +258,7 @@ static int __update_pte(xc_interface *xch,
}
static int change_pte(xc_interface *xch, int domid,
- struct domain_mem_info *minfo,
+ struct xc_domain_meminfo *minfo,
struct pte_backup *backup,
struct xc_mmu *mmu,
pte_func func,
@@ -412,7 +268,7 @@ static int change_pte(xc_interface *xch, int domid,
uint64_t i;
void *content = NULL;
- pte_num = PAGE_SIZE / ((minfo->pt_level == 2) ? 4 : 8);
+ pte_num = PAGE_SIZE / ((minfo->pt_levels == 2) ? 4 : 8);
for (i = 0; i < minfo->p2m_size; i++)
{
@@ -435,7 +291,7 @@ static int change_pte(xc_interface *xch, int domid,
for (j = 0; j < pte_num; j++)
{
- if ( minfo->pt_level == 2 )
+ if ( minfo->pt_levels == 2 )
pte = ((const uint32_t*)content)[j];
else
pte = ((const uint64_t*)content)[j];
@@ -447,7 +303,7 @@ static int change_pte(xc_interface *xch, int domid,
case 1:
if ( xc_add_mmu_update(xch, mmu,
table_mfn << PAGE_SHIFT |
- j * ( (minfo->pt_level == 2) ?
+ j * ( (minfo->pt_levels == 2) ?
sizeof(uint32_t): sizeof(uint64_t)) |
MMU_PT_UPDATE_PRESERVE_AD,
new_pte) )
@@ -480,7 +336,7 @@ failed:
}
static int update_pte(xc_interface *xch, int domid,
- struct domain_mem_info *minfo,
+ struct xc_domain_meminfo *minfo,
struct pte_backup *backup,
struct xc_mmu *mmu,
unsigned long new_mfn)
@@ -490,7 +346,7 @@ static int update_pte(xc_interface *xch, int domid,
}
static int clear_pte(xc_interface *xch, int domid,
- struct domain_mem_info *minfo,
+ struct xc_domain_meminfo *minfo,
struct pte_backup *backup,
struct xc_mmu *mmu,
xen_pfn_t mfn)
@@ -538,7 +394,7 @@ static int is_page_exchangable(xc_interface *xch, int domid, xen_pfn_t mfn,
int xc_exchange_page(xc_interface *xch, int domid, xen_pfn_t mfn)
{
xc_dominfo_t info;
- struct domain_mem_info minfo;
+ struct xc_domain_meminfo minfo;
struct xc_mmu *mmu = NULL;
struct pte_backup old_ptes = {NULL, 0, 0};
grant_entry_v1_t *gnttab_v1 = NULL;
@@ -549,6 +405,8 @@ int xc_exchange_page(xc_interface *xch, int domid, xen_pfn_t mfn)
int rc, result = -1;
uint32_t status;
xen_pfn_t new_mfn, gpfn;
+ xen_pfn_t *m2p_table;
+ int max_mfn;
if ( xc_domain_getinfo(xch, domid, 1, &info) != 1 )
{
@@ -568,10 +426,26 @@ int xc_exchange_page(xc_interface *xch, int domid, xen_pfn_t mfn)
return -EINVAL;
}
- /* Get domain's memory information */
+ /* Map M2P and obtain gpfn */
+ max_mfn = xc_maximum_ram_page(xch);
+ if ( !(m2p_table = xc_map_m2p(xch, max_mfn, PROT_READ, NULL)) )
+ {
+ PERROR("Failed to map live M2P table");
+ return -EFAULT;
+ }
+ gpfn = m2p_table[mfn];
+
+ /* Map domain's memory information */
memset(&minfo, 0, sizeof(minfo));
- init_mem_info(xch, domid, &minfo, &info);
- gpfn = minfo.m2p_table[mfn];
+ if ( xc_map_domain_meminfo(xch, domid, &minfo) )
+ {
+ PERROR("Could not map domain's memory information\n");
+ return -EFAULT;
+ }
+
+ /* For translation macros */
+ dinfo->guest_width = minfo.guest_width;
+ dinfo->p2m_size = minfo.p2m_size;
/* Don't exchange CR3 for PAE guest in PAE host environment */
if (minfo.guest_width > sizeof(long))
@@ -766,7 +640,8 @@ failed:
if (gnttab_v2)
munmap(gnttab_v2, gnt_num / (PAGE_SIZE/sizeof(grant_entry_v2_t)));
- close_mem_info(xch, &minfo);
+ xc_unmap_domain_meminfo(xch, &minfo);
+ munmap(m2p_table, M2P_SIZE(max_mfn));
return result;
}
diff --git a/tools/libxc/xenguest.h b/tools/libxc/xenguest.h
index 4714bd2249..c12091f52b 100644
--- a/tools/libxc/xenguest.h
+++ b/tools/libxc/xenguest.h
@@ -276,6 +276,23 @@ int xc_exchange_page(xc_interface *xch, int domid, xen_pfn_t mfn);
/**
+ * Memory related information, such as PFN types, the P2M table,
+ * the guest word width and the guest page table levels.
+ */
+struct xc_domain_meminfo {
+ unsigned int pt_levels;
+ unsigned int guest_width;
+ xen_pfn_t *pfn_type;
+ xen_pfn_t *p2m_table;
+ unsigned long p2m_size;
+};
+
+int xc_map_domain_meminfo(xc_interface *xch, int domid,
+ struct xc_domain_meminfo *minfo);
+
+int xc_unmap_domain_meminfo(xc_interface *xch, struct xc_domain_meminfo *mem);
+
+/**
* This function map m2p table
* @parm xch a handle to an open hypervisor interface
* @parm max_mfn the max pfn
diff --git a/tools/libxc/xg_private.h b/tools/libxc/xg_private.h
index db02ccf470..5ff2124346 100644
--- a/tools/libxc/xg_private.h
+++ b/tools/libxc/xg_private.h
@@ -136,6 +136,15 @@ struct domain_info_context {
unsigned long p2m_size;
};
+static inline xen_pfn_t pfn_to_mfn(xen_pfn_t pfn, xen_pfn_t *p2m, int gwidth)
+{
+ return ((xen_pfn_t) ((gwidth==8)?
+ (((uint64_t *)p2m)[(pfn)]):
+ ((((uint32_t *)p2m)[(pfn)]) == 0xffffffffU ?
+ (-1UL) :
+ (((uint32_t *)p2m)[(pfn)]))));
+}
+
/* Number of xen_pfn_t in a page */
#define FPP (PAGE_SIZE/(dinfo->guest_width))