aboutsummaryrefslogtreecommitdiffstats
path: root/tools
diff options
context:
space:
mode:
Diffstat (limited to 'tools')
-rw-r--r--tools/Makefile4
-rwxr-xr-xtools/examples/xc_dom_control.py4
-rw-r--r--tools/xc/lib/Makefile2
-rw-r--r--tools/xc/lib/xc_domain.c1
-rw-r--r--tools/xc/lib/xc_linux_build.c25
-rw-r--r--tools/xc/lib/xc_linux_restore.c242
-rw-r--r--tools/xc/lib/xc_linux_save.c392
-rw-r--r--tools/xc/lib/xc_netbsd_build.c26
-rw-r--r--tools/xc/lib/xc_private.c228
-rw-r--r--tools/xc/lib/xc_private.h100
10 files changed, 787 insertions, 237 deletions
diff --git a/tools/Makefile b/tools/Makefile
index 0d4c43fb24..9ddf5f25a2 100644
--- a/tools/Makefile
+++ b/tools/Makefile
@@ -17,6 +17,10 @@ install: all
$(MAKE) -C xenctl install
$(MAKE) -C xend install
+dist: $(TARGET)
+ $(MAKE) prefix=`pwd`/../../install dist=yes install
+
+
clean:
$(MAKE) -C balloon clean
$(MAKE) -C xc clean
diff --git a/tools/examples/xc_dom_control.py b/tools/examples/xc_dom_control.py
index ea97a45f0e..4f0bd5de52 100755
--- a/tools/examples/xc_dom_control.py
+++ b/tools/examples/xc_dom_control.py
@@ -137,6 +137,10 @@ elif cmd == 'suspend':
os.kill(pid, signal.SIGTERM)
xc.domain_stop( dom=dom )
+
+ while not xc.domain_getinfo( first_dom=dom, max_doms=1 )[0]['stopped']:
+ time.sleep(0.1);
+
rc = xc.linux_save( dom=dom, state_file=file, progress=1)
if rc == 0 : xc.domain_destroy( dom=dom, force=1 )
diff --git a/tools/xc/lib/Makefile b/tools/xc/lib/Makefile
index 79dce046df..f542935167 100644
--- a/tools/xc/lib/Makefile
+++ b/tools/xc/lib/Makefile
@@ -4,7 +4,7 @@ MINOR = 0
SONAME = libxc.so.$(MAJOR)
CC = gcc
-CFLAGS = -c -Wall -O3 -fno-strict-aliasing
+CFLAGS = -c -Werror -O3 -fno-strict-aliasing
CFLAGS += -I../../../xen/include/hypervisor-ifs
CFLAGS += -I../../xend/lib
CFLAGS += -I../../../xenolinux-sparse/include
diff --git a/tools/xc/lib/xc_domain.c b/tools/xc/lib/xc_domain.c
index ec28f2686b..1d77bfc016 100644
--- a/tools/xc/lib/xc_domain.c
+++ b/tools/xc/lib/xc_domain.c
@@ -84,6 +84,7 @@ int xc_domain_getinfo(int xc_handle,
{
op.cmd = DOM0_GETDOMAININFO;
op.u.getdomaininfo.domain = (domid_t)next_domid;
+ op.u.getdomaininfo.ctxt = NULL; // no exec context info, thanks.
if ( do_dom0_op(xc_handle, &op) < 0 )
break;
info->domid = (u64)op.u.getdomaininfo.domain;
diff --git a/tools/xc/lib/xc_linux_build.c b/tools/xc/lib/xc_linux_build.c
index 27bc6c6668..67351210fc 100644
--- a/tools/xc/lib/xc_linux_build.c
+++ b/tools/xc/lib/xc_linux_build.c
@@ -26,6 +26,7 @@ static long get_tot_pages(int xc_handle, u64 domid)
dom0_op_t op;
op.cmd = DOM0_GETDOMAININFO;
op.u.getdomaininfo.domain = (domid_t)domid;
+ op.u.getdomaininfo.ctxt = NULL;
return (do_dom0_op(xc_handle, &op) < 0) ?
-1 : op.u.getdomaininfo.tot_pages;
}
@@ -70,7 +71,7 @@ static int setup_guestos(int xc_handle,
gzFile initrd_gfd, unsigned long initrd_len,
unsigned long nr_pages,
unsigned long *pvsi, unsigned long *pvke,
- dom0_builddomain_t *builddomain,
+ full_execution_context_t *ctxt,
const char *cmdline,
unsigned long shared_info_frame,
unsigned int control_evtchn,
@@ -164,8 +165,6 @@ static int setup_guestos(int xc_handle,
v_start, v_end);
printf(" ENTRY ADDRESS: %08lx\n", vkern_entry);
- memset(builddomain, 0, sizeof(*builddomain));
-
if ( (pm_handle = init_pfn_mapper((domid_t)dom)) < 0 )
goto error_out;
@@ -206,7 +205,7 @@ static int setup_guestos(int xc_handle,
/* First allocate page for page dir. */
ppt_alloc = (vpt_start - v_start) >> PAGE_SHIFT;
l2tab = page_array[ppt_alloc++] << PAGE_SHIFT;
- builddomain->ctxt.pt_base = l2tab;
+ ctxt->pt_base = l2tab;
/* Initialise the page tables. */
if ( (vl2tab = map_pfn_writeable(pm_handle, l2tab >> PAGE_SHIFT)) == NULL )
@@ -390,7 +389,7 @@ int xc_linux_build(int xc_handle,
int initrd_fd = -1;
gzFile initrd_gfd = NULL;
int rc, i;
- full_execution_context_t *ctxt;
+ full_execution_context_t st_ctxt, *ctxt = &st_ctxt;
unsigned long nr_pages;
char *image = NULL;
unsigned long image_size, initrd_size=0;
@@ -422,8 +421,15 @@ int xc_linux_build(int xc_handle,
}
}
+ if ( mlock(&st_ctxt, sizeof(st_ctxt) ) )
+ {
+ PERROR("Unable to mlock ctxt");
+ return 1;
+ }
+
op.cmd = DOM0_GETDOMAININFO;
op.u.getdomaininfo.domain = (domid_t)domid;
+ op.u.getdomaininfo.ctxt = ctxt;
if ( (do_dom0_op(xc_handle, &op) < 0) ||
((u64)op.u.getdomaininfo.domain != domid) )
{
@@ -431,7 +437,7 @@ int xc_linux_build(int xc_handle,
goto error_out;
}
if ( (op.u.getdomaininfo.state != DOMSTATE_STOPPED) ||
- (op.u.getdomaininfo.ctxt.pt_base != 0) )
+ (ctxt->pt_base != 0) )
{
ERROR("Domain is already constructed");
goto error_out;
@@ -440,7 +446,7 @@ int xc_linux_build(int xc_handle,
if ( setup_guestos(xc_handle, domid, image, image_size,
initrd_gfd, initrd_size, nr_pages,
&vstartinfo_start, &vkern_entry,
- &launch_op.u.builddomain, cmdline,
+ ctxt, cmdline,
op.u.getdomaininfo.shared_info_frame,
control_evtchn, io_priv) < 0 )
{
@@ -455,8 +461,6 @@ int xc_linux_build(int xc_handle,
if ( image != NULL )
free(image);
- ctxt = &launch_op.u.builddomain.ctxt;
-
ctxt->flags = 0;
/*
@@ -509,8 +513,11 @@ int xc_linux_build(int xc_handle,
ctxt->failsafe_callback_cs = FLAT_GUESTOS_CS;
ctxt->failsafe_callback_eip = 0;
+ memset( &launch_op, 0, sizeof(launch_op) );
+
launch_op.u.builddomain.domain = (domid_t)domid;
launch_op.u.builddomain.num_vifs = 1;
+ launch_op.u.builddomain.ctxt = ctxt;
launch_op.cmd = DOM0_BUILDDOMAIN;
rc = do_dom0_op(xc_handle, &launch_op);
diff --git a/tools/xc/lib/xc_linux_restore.c b/tools/xc/lib/xc_linux_restore.c
index 239df65984..e27221281a 100644
--- a/tools/xc/lib/xc_linux_restore.c
+++ b/tools/xc/lib/xc_linux_restore.c
@@ -10,6 +10,8 @@
#include <asm-xen/suspend.h>
#include <zlib.h>
+#define MAX_BATCH_SIZE 1024
+
/* This may allow us to create a 'quiet' command-line option, if necessary. */
#define verbose_printf(_f, _a...) \
do { \
@@ -58,8 +60,8 @@ int xc_linux_restore(int xc_handle,
u64 *pdomid)
{
dom0_op_t op;
- int rc = 1, i, j;
- unsigned long mfn, pfn;
+ int rc = 1, i, j, n, k;
+ unsigned long mfn, pfn, xpfn;
unsigned int prev_pc, this_pc;
/* Number of page frames in use by this Linux session. */
@@ -93,6 +95,9 @@ int xc_linux_restore(int xc_handle,
/* A temporary mapping of the guest's suspend record. */
suspend_record_t *p_srec;
+ mfn_mapper_t *region_mapper, *mapper_handle1;
+ char *region_base;
+
/* The name and descriptor of the file that we are reading from. */
int fd;
gzFile gfd;
@@ -114,6 +119,14 @@ int xc_linux_restore(int xc_handle,
return 1;
}
+ if ( mlock(&ctxt, sizeof(ctxt) ) )
+ {
+ /* needed for when we do the build dom0 op,
+ but might as well do early */
+ PERROR("Unable to mlock ctxt");
+ return 1;
+ }
+
/* Start writing out the saved-domain record. */
if ( !checked_read(gfd, signature, 16) ||
(memcmp(signature, "LinuxGuestRecord", 16) != 0) )
@@ -159,12 +172,6 @@ int xc_linux_restore(int xc_handle,
goto out;
}
- if ( !checked_read(gfd, pfn_type, 4 * nr_pfns) )
- {
- ERROR("Error when reading from state file");
- goto out;
- }
-
/* Set the domain's name to that from the restore file */
if ( xc_domain_setname( xc_handle, dom, name ) )
{
@@ -184,6 +191,7 @@ int xc_linux_restore(int xc_handle,
/* Get the domain's shared-info frame. */
op.cmd = DOM0_GETDOMAININFO;
op.u.getdomaininfo.domain = (domid_t)dom;
+ op.u.getdomaininfo.ctxt = NULL;
if ( do_dom0_op(xc_handle, &op) < 0 )
{
ERROR("Could not get information on new domain");
@@ -212,6 +220,15 @@ int xc_linux_restore(int xc_handle,
goto out;
}
+
+ if ( (region_mapper = mfn_mapper_init(xc_handle, dom,
+ MAX_BATCH_SIZE*PAGE_SIZE,
+ PROT_WRITE ))
+ == NULL )
+ goto out;
+
+ region_base = mfn_mapper_base( region_mapper );
+
verbose_printf("Reloading memory pages: 0%%");
/*
@@ -219,75 +236,141 @@ int xc_linux_restore(int xc_handle,
* We uncanonicalise page tables as we go.
*/
prev_pc = 0;
- for ( i = 0; i < nr_pfns; i++ )
+
+ n=0;
+ while(1)
{
- this_pc = (i * 100) / nr_pfns;
+ int j;
+ unsigned long region_pfn_type[1024];
+
+ this_pc = (n * 100) / nr_pfns;
if ( (this_pc - prev_pc) >= 5 )
{
verbose_printf("\b\b\b\b%3d%%", this_pc);
prev_pc = this_pc;
}
- mfn = pfn_to_mfn_table[i];
-
- ppage = map_pfn_writeable(pm_handle, mfn);
-
- if ( !checked_read(gfd, ppage, PAGE_SIZE) )
+ if ( !checked_read(gfd, &j, sizeof(int)) )
{
ERROR("Error when reading from state file");
goto out;
}
- if ( pfn_type[i] == L1TAB )
+ //printf("batch=%d\n",j);
+
+ if(j==0) break; // our work here is done
+
+ if ( !checked_read(gfd, region_pfn_type, j*sizeof(unsigned long)) )
{
- for ( j = 0; j < 1024; j++ )
- {
- if ( ppage[j] & _PAGE_PRESENT )
- {
- if ( (pfn = ppage[j] >> PAGE_SHIFT) >= nr_pfns )
- {
- ERROR("Frame number in page table is out of range");
- goto out;
- }
- if ( (pfn_type[pfn] != NONE) && (ppage[j] & _PAGE_RW) )
- {
- ERROR("Write access requested for a restricted frame");
- goto out;
- }
- ppage[j] &= (PAGE_SIZE - 1) & ~(_PAGE_GLOBAL | _PAGE_PAT);
- ppage[j] |= pfn_to_mfn_table[pfn] << PAGE_SHIFT;
- }
- }
- }
- else if ( pfn_type[i] == L2TAB )
- {
- for ( j = 0; j < (HYPERVISOR_VIRT_START>>L2_PAGETABLE_SHIFT); j++ )
- {
- if ( ppage[j] & _PAGE_PRESENT )
- {
- if ( (pfn = ppage[j] >> PAGE_SHIFT) >= nr_pfns )
- {
- ERROR("Frame number in page table is out of range");
- goto out;
- }
- if ( pfn_type[pfn] != L1TAB )
- {
- ERROR("Page table mistyping");
- goto out;
- }
- ppage[j] &= (PAGE_SIZE - 1) & ~(_PAGE_GLOBAL | _PAGE_PSE);
- ppage[j] |= pfn_to_mfn_table[pfn] << PAGE_SHIFT;
- }
- }
+ ERROR("Error when reading from state file");
+ goto out;
}
- unmap_pfn(pm_handle, ppage);
+ for(i=0;i<j;i++)
+ {
+ pfn = region_pfn_type[i] & ~PGT_type_mask;
+ mfn = pfn_to_mfn_table[pfn];
+
+ mfn_mapper_queue_entry( region_mapper, i<<PAGE_SHIFT,
+ mfn, PAGE_SIZE );
+ }
+
+ if( mfn_mapper_flush_queue(region_mapper) )
+ {
+ ERROR("Couldn't map page region");
+ goto out;
+ }
+
+
+ for(i=0;i<j;i++)
+ {
+ unsigned long *ppage;
+
+ pfn = region_pfn_type[i] & ~PGT_type_mask;
+
+//if(pfn_type[i])printf("^pfn=%d %08lx\n",pfn,pfn_type[i]);
+
+ if (pfn>nr_pfns)
+ {
+ ERROR("pfn out of range");
+ goto out;
+ }
+
+ region_pfn_type[i] &= PGT_type_mask;
+
+ pfn_type[pfn] = region_pfn_type[i];
+
+ mfn = pfn_to_mfn_table[pfn];
+
+//if(region_pfn_type[i])printf("i=%d pfn=%d mfn=%d type=%lx\n",i,pfn,mfn,region_pfn_type[i]);
+
+ ppage = (unsigned long*) (region_base + i*PAGE_SIZE);
+
+ if ( !checked_read(gfd, ppage, PAGE_SIZE) )
+ {
+ ERROR("Error when reading from state file");
+ goto out;
+ }
+
+ if ( region_pfn_type[i] == L1TAB )
+ {
+ for ( k = 0; k < 1024; k++ )
+ {
+ if ( ppage[k] & _PAGE_PRESENT )
+ {
+ if ( (xpfn = ppage[k] >> PAGE_SHIFT) >= nr_pfns )
+ {
+ ERROR("Frame number in type %d page table is out of range. i=%d k=%d pfn=%d nr_pfns=%d",region_pfn_type[i],i,k,xpfn,nr_pfns);
+ goto out;
+ }
+#if 0
+ if ( (region_pfn_type[xpfn] != NONE) && (ppage[k] & _PAGE_RW) )
+ {
+ ERROR("Write access requested for a restricted frame");
+ goto out;
+ }
+#endif
+ ppage[k] &= (PAGE_SIZE - 1) & ~(_PAGE_GLOBAL | _PAGE_PAT);
+ ppage[k] |= pfn_to_mfn_table[xpfn] << PAGE_SHIFT;
+ }
+ }
+ }
+ else if ( region_pfn_type[i] == L2TAB )
+ {
+ for ( k = 0; k < (HYPERVISOR_VIRT_START>>L2_PAGETABLE_SHIFT); k++ )
+ {
+ if ( ppage[k] & _PAGE_PRESENT )
+ {
+ if ( (xpfn = ppage[k] >> PAGE_SHIFT) >= nr_pfns )
+ {
+ ERROR("Frame number in page table is out of range");
+ goto out;
+ }
+#if 0
+ if ( region_pfn_type[pfn] != L1TAB )
+ {
+ ERROR("Page table mistyping");
+ goto out;
+ }
+#endif
+ ppage[k] &= (PAGE_SIZE - 1) & ~(_PAGE_GLOBAL | _PAGE_PSE);
+ ppage[k] |= pfn_to_mfn_table[xpfn] << PAGE_SHIFT;
+ }
+ }
+ }
+
+ if ( add_mmu_update(xc_handle, mmu,
+ (mfn<<PAGE_SHIFT) | MMU_MACHPHYS_UPDATE, pfn) )
+ goto out;
+
+ }
+
+ n+=j; // crude stats
- if ( add_mmu_update(xc_handle, mmu,
- (mfn<<PAGE_SHIFT) | MMU_MACHPHYS_UPDATE, i) )
- goto out;
}
+ mfn_mapper_close( region_mapper );
+
/*
* Pin page tables. Do this after writing to them as otherwise Xen
* will barf when doing the type-checking.
@@ -352,26 +435,47 @@ int xc_linux_restore(int xc_handle,
pfn = ctxt.pt_base >> PAGE_SHIFT;
if ( (pfn >= nr_pfns) || (pfn_type[pfn] != L2TAB) )
{
- ERROR("PT base is bad");
+ printf("PT base is bad. pfn=%d nr=%d type=%08lx %08lx\n",
+ pfn, nr_pfns, pfn_type[pfn], L2TAB);
+ ERROR("PT base is bad.");
goto out;
}
ctxt.pt_base = pfn_to_mfn_table[pfn] << PAGE_SHIFT;
/* Uncanonicalise the pfn-to-mfn table frame-number list. */
- for ( i = 0; i < nr_pfns; i += 1024 )
+
+
+ if ( (mapper_handle1 = mfn_mapper_init(xc_handle, dom,
+ 1024*1024, PROT_WRITE ))
+ == NULL )
+ goto out;
+
+ for ( i = 0; i < (nr_pfns+1023)/1024; i++ )
{
- unsigned long copy_size = (nr_pfns - i) * sizeof(unsigned long);
- if ( copy_size > PAGE_SIZE ) copy_size = PAGE_SIZE;
- pfn = pfn_to_mfn_frame_list[i/1024];
+ unsigned long pfn, mfn;
+
+ pfn = pfn_to_mfn_frame_list[i];
if ( (pfn >= nr_pfns) || (pfn_type[pfn] != NONE) )
{
ERROR("PFN-to-MFN frame number is bad");
goto out;
}
- ppage = map_pfn_writeable(pm_handle, pfn_to_mfn_table[pfn]);
- memcpy(ppage, &pfn_to_mfn_table[i], copy_size);
- unmap_pfn(pm_handle, ppage);
+ mfn = pfn_to_mfn_table[pfn];
+
+ mfn_mapper_queue_entry( mapper_handle1, i<<PAGE_SHIFT,
+ mfn, PAGE_SIZE );
}
+
+ if ( mfn_mapper_flush_queue(mapper_handle1) )
+ {
+ ERROR("Couldn't map pfn_to_mfn table");
+ goto out;
+ }
+
+ memcpy( mfn_mapper_base( mapper_handle1 ), pfn_to_mfn_table,
+ nr_pfns*sizeof(unsigned long) );
+
+ mfn_mapper_close( mapper_handle1 );
/*
* Safety checking of saved context:
@@ -406,11 +510,11 @@ int xc_linux_restore(int xc_handle,
ERROR("Bad LDT base or size");
goto out;
}
-
+
op.cmd = DOM0_BUILDDOMAIN;
op.u.builddomain.domain = (domid_t)dom;
op.u.builddomain.num_vifs = 1;
- memcpy(&op.u.builddomain.ctxt, &ctxt, sizeof(ctxt));
+ op.u.builddomain.ctxt = &ctxt;
rc = do_dom0_op(xc_handle, &op);
out:
diff --git a/tools/xc/lib/xc_linux_save.c b/tools/xc/lib/xc_linux_save.c
index dc759f546c..88ed9e15d7 100644
--- a/tools/xc/lib/xc_linux_save.c
+++ b/tools/xc/lib/xc_linux_save.c
@@ -10,6 +10,8 @@
#include <asm-xen/suspend.h>
#include <zlib.h>
+#define BATCH_SIZE 1024 /* 1024 pages (4MB) at a time */
+
/* This may allow us to create a 'quiet' command-line option, if necessary. */
#define verbose_printf(_f, _a...) \
do { \
@@ -24,7 +26,7 @@
*/
#define MFN_IS_IN_PSEUDOPHYS_MAP(_mfn) \
(((_mfn) < (1024*1024)) && \
- (pfn_to_mfn_table[mfn_to_pfn_table[_mfn]] == (_mfn)))
+ (live_pfn_to_mfn_table[live_mfn_to_pfn_table[_mfn]] == (_mfn)))
/* Returns TRUE if MFN is successfully converted to a PFN. */
#define translate_mfn_to_pfn(_pmfn) \
@@ -34,37 +36,11 @@
if ( !MFN_IS_IN_PSEUDOPHYS_MAP(mfn) ) \
_res = 0; \
else \
- *(_pmfn) = mfn_to_pfn_table[mfn]; \
+ *(_pmfn) = live_mfn_to_pfn_table[mfn]; \
_res; \
})
-static int check_pfn_ownership(int xc_handle,
- unsigned long mfn,
- u64 dom)
-{
- dom0_op_t op;
- op.cmd = DOM0_GETPAGEFRAMEINFO;
- op.u.getpageframeinfo.pfn = mfn;
- op.u.getpageframeinfo.domain = (domid_t)dom;
- return (do_dom0_op(xc_handle, &op) >= 0);
-}
-#define GETPFN_ERR (~0U)
-static unsigned int get_pfn_type(int xc_handle,
- unsigned long mfn,
- u64 dom)
-{
- dom0_op_t op;
- op.cmd = DOM0_GETPAGEFRAMEINFO;
- op.u.getpageframeinfo.pfn = mfn;
- op.u.getpageframeinfo.domain = (domid_t)dom;
- if ( do_dom0_op(xc_handle, &op) < 0 )
- {
- PERROR("Unexpected failure when getting page frame info!");
- return GETPFN_ERR;
- }
- return op.u.getpageframeinfo.type;
-}
static int checked_write(gzFile fd, void *buf, size_t count)
{
@@ -80,10 +56,13 @@ int xc_linux_save(int xc_handle,
int verbose)
{
dom0_op_t op;
- int rc = 1, i, j;
+ int rc = 1, i, j, k, n;
unsigned long mfn;
unsigned int prev_pc, this_pc;
+ /* state of the new MFN mapper */
+ mfn_mapper_t *mapper_handle1, *mapper_handle2;
+
/* Remember if we stopped the guest, so we can restart it on exit. */
int we_stopped_it = 0;
@@ -100,18 +79,23 @@ int xc_linux_save(int xc_handle,
unsigned long *pfn_type = NULL;
/* A temporary mapping, and a copy, of one frame of guest memory. */
- unsigned long *ppage, page[1024];
+ unsigned long page[1024];
- /* A temporary mapping, and a copy, of the pfn-to-mfn table frame list. */
- unsigned long *p_pfn_to_mfn_frame_list, pfn_to_mfn_frame_list[1024];
- /* A temporary mapping of one frame in the above list. */
- unsigned long *pfn_to_mfn_frame;
+ /* A copy of the pfn-to-mfn table frame list. */
+ unsigned long *live_pfn_to_mfn_frame_list;
+ unsigned long pfn_to_mfn_frame_list[1024];
- /* A table mapping each PFN to its current MFN. */
- unsigned long *pfn_to_mfn_table = NULL;
- /* A table mapping each current MFN to its canonical PFN. */
- unsigned long *mfn_to_pfn_table = NULL;
+ /* Live mapping of the table mapping each PFN to its current MFN. */
+ unsigned long *live_pfn_to_mfn_table = NULL;
+ /* Live mapping of system MFN to PFN table. */
+ unsigned long *live_mfn_to_pfn_table = NULL;
+ /* Live mapping of shared info structure */
+ unsigned long *live_shinfo;
+
+ /* base of the region in which domain memory is mapped */
+ unsigned char *region_base;
+
/* A temporary mapping, and a copy, of the guest's suspend record. */
suspend_record_t *p_srec, srec;
@@ -138,11 +122,18 @@ int xc_linux_save(int xc_handle,
return 1;
}
+ if ( mlock(&ctxt, sizeof(ctxt) ) )
+ {
+ PERROR("Unable to mlock ctxt");
+ return 1;
+ }
+
/* Ensure that the domain exists, and that it is stopped. */
for ( ; ; )
{
op.cmd = DOM0_GETDOMAININFO;
op.u.getdomaininfo.domain = (domid_t)domid;
+ op.u.getdomaininfo.ctxt = &ctxt;
if ( (do_dom0_op(xc_handle, &op) < 0) ||
((u64)op.u.getdomaininfo.domain != domid) )
{
@@ -150,7 +141,6 @@ int xc_linux_save(int xc_handle,
goto out;
}
- memcpy(&ctxt, &op.u.getdomaininfo.ctxt, sizeof(ctxt));
memcpy(name, op.u.getdomaininfo.name, sizeof(name));
shared_info_frame = op.u.getdomaininfo.shared_info_frame;
@@ -178,99 +168,115 @@ int xc_linux_save(int xc_handle,
goto out;
}
- if ( (pm_handle = init_pfn_mapper((domid_t)domid)) < 0 )
- goto out;
- /* Is the suspend-record MFN actually valid for this domain? */
- if ( !check_pfn_ownership(xc_handle, ctxt.cpu_ctxt.esi, domid) )
+ /* Map the suspend-record MFN to pin it. The page must be owned by
+ domid for this to succeed. */
+ p_srec = mfn_mapper_map_single(xc_handle, domid,
+ sizeof(srec), PROT_READ,
+ ctxt.cpu_ctxt.esi );
+
+ if (!p_srec)
{
- ERROR("Invalid state record pointer");
+ ERROR("Couldn't map state record");
goto out;
}
- /* If the suspend-record MFN is okay then grab a copy of it to @srec. */
- p_srec = map_pfn_readonly(pm_handle, ctxt.cpu_ctxt.esi);
- memcpy(&srec, p_srec, sizeof(srec));
- unmap_pfn(pm_handle, p_srec);
+ memcpy( &srec, p_srec, sizeof(srec) );
+ /* cheesy sanity check */
if ( srec.nr_pfns > 1024*1024 )
{
ERROR("Invalid state record -- pfn count out of range");
goto out;
}
- if ( !check_pfn_ownership(xc_handle, srec.pfn_to_mfn_frame_list, domid) )
+ /* the pfn_to_mfn_frame_list fits in a single page */
+ live_pfn_to_mfn_frame_list =
+ mfn_mapper_map_single(xc_handle, domid,
+ PAGE_SIZE, PROT_READ,
+ srec.pfn_to_mfn_frame_list );
+
+ if (!live_pfn_to_mfn_frame_list)
{
- ERROR("Invalid pfn-to-mfn frame list pointer");
+ ERROR("Couldn't map pfn_to_mfn_frame_list");
goto out;
}
+
+
+ if ( (mapper_handle1 = mfn_mapper_init(xc_handle, domid,
+ 1024*1024, PROT_READ ))
+ == NULL )
+ goto out;
+
+ for ( i = 0; i < (srec.nr_pfns+1023)/1024; i++ )
+ {
+ /* Grab a copy of the pfn-to-mfn table frame list.
+ This has the effect of preventing the page from being freed and
+ given to another domain. (though the domain is stopped anyway...) */
+ mfn_mapper_queue_entry( mapper_handle1, i<<PAGE_SHIFT,
+ live_pfn_to_mfn_frame_list[i],
+ PAGE_SIZE );
+ }
+
+ if ( mfn_mapper_flush_queue(mapper_handle1) )
+ {
+ ERROR("Couldn't map pfn_to_mfn table");
+ goto out;
+ }
+
+ live_pfn_to_mfn_table = mfn_mapper_base( mapper_handle1 );
+
- /* Grab a copy of the pfn-to-mfn table frame list. */
- p_pfn_to_mfn_frame_list = map_pfn_readonly(
- pm_handle, srec.pfn_to_mfn_frame_list);
- memcpy(pfn_to_mfn_frame_list, p_pfn_to_mfn_frame_list, PAGE_SIZE);
- unmap_pfn(pm_handle, p_pfn_to_mfn_frame_list);
/* We want zeroed memory so use calloc rather than malloc. */
- mfn_to_pfn_table = calloc(1, 4 * 1024 * 1024);
- pfn_to_mfn_table = calloc(1, 4 * srec.nr_pfns);
- pfn_type = calloc(1, 4 * srec.nr_pfns);
+ pfn_type = calloc(BATCH_SIZE, sizeof(unsigned long));
- if ( (mfn_to_pfn_table == NULL) ||
- (pfn_to_mfn_table == NULL) ||
- (pfn_type == NULL) )
+ if ( (pfn_type == NULL) )
{
errno = ENOMEM;
goto out;
}
+ if ( mlock( pfn_type, BATCH_SIZE * sizeof(unsigned long) ) )
+ {
+ ERROR("Unable to mlock");
+ goto out;
+ }
- /*
- * Construct the local pfn-to-mfn and mfn-to-pfn tables. On exit from this
- * loop we have each MFN mapped at most once. Note that there may be MFNs
- * that aren't mapped at all: we detect these by MFN_IS_IN_PSEUDOPHYS_MAP.
- */
- pfn_to_mfn_frame = NULL;
- for ( i = 0; i < srec.nr_pfns; i++ )
+
+ /* Track the mfn_to_pfn table down from the domains PT */
{
- /* Each frameful of table frames must be checked & mapped on demand. */
- if ( (i & 1023) == 0 )
- {
- mfn = pfn_to_mfn_frame_list[i/1024];
- if ( !check_pfn_ownership(xc_handle, mfn, domid) )
- {
- ERROR("Invalid frame number if pfn-to-mfn frame list");
- goto out;
- }
- if ( pfn_to_mfn_frame != NULL )
- unmap_pfn(pm_handle, pfn_to_mfn_frame);
- pfn_to_mfn_frame = map_pfn_readonly(pm_handle, mfn);
- }
-
- mfn = pfn_to_mfn_frame[i & 1023];
+ unsigned long *pgd;
+ unsigned long mfn_to_pfn_table_start_mfn;
- if ( !check_pfn_ownership(xc_handle, mfn, domid) )
- {
- ERROR("Invalid frame specified with pfn-to-mfn table");
- goto out;
- }
+ pgd = mfn_mapper_map_single(xc_handle, domid,
+ PAGE_SIZE, PROT_READ,
+ ctxt.pt_base>>PAGE_SHIFT);
- /* Did we map this MFN already? That would be invalid! */
- if ( MFN_IS_IN_PSEUDOPHYS_MAP(mfn) )
- {
- ERROR("A machine frame appears twice in pseudophys space");
- goto out;
- }
+ mfn_to_pfn_table_start_mfn =
+ pgd[HYPERVISOR_VIRT_START>>L2_PAGETABLE_SHIFT]>>PAGE_SHIFT;
+
+ live_mfn_to_pfn_table =
+ mfn_mapper_map_single(xc_handle, ~0ULL,
+ PAGE_SIZE*1024, PROT_READ,
+ mfn_to_pfn_table_start_mfn );
+ }
- pfn_to_mfn_table[i] = mfn;
- mfn_to_pfn_table[mfn] = i;
- /* Query page type by MFN, but store it by PFN. */
- if ( (pfn_type[i] = get_pfn_type(xc_handle, mfn, domid)) ==
- GETPFN_ERR )
- goto out;
+ /*
+ * Quick belt and braces sanity check.
+ */
+
+ for ( i = 0; i < srec.nr_pfns; i++ )
+ {
+ mfn = live_pfn_to_mfn_table[i];
+
+ if( live_mfn_to_pfn_table[mfn] != i )
+ printf("i=%d mfn=%d live_mfn_to_pfn_table=%d\n",
+ i,mfn,live_mfn_to_pfn_table[mfn]);
}
+
/* Canonicalise the suspend-record frame number. */
if ( !translate_mfn_to_pfn(&ctxt.cpu_ctxt.esi) )
{
@@ -294,9 +300,10 @@ int xc_linux_save(int xc_handle,
ERROR("PT base is not in range of pseudophys map");
goto out;
}
- ctxt.pt_base = mfn_to_pfn_table[ctxt.pt_base >> PAGE_SHIFT] << PAGE_SHIFT;
+ ctxt.pt_base = live_mfn_to_pfn_table[ctxt.pt_base >> PAGE_SHIFT] << PAGE_SHIFT;
/* Canonicalise the pfn-to-mfn table frame-number list. */
+ memcpy( pfn_to_mfn_frame_list, live_pfn_to_mfn_frame_list, PAGE_SIZE );
for ( i = 0; i < srec.nr_pfns; i += 1024 )
{
if ( !translate_mfn_to_pfn(&pfn_to_mfn_frame_list[i/1024]) )
@@ -307,63 +314,152 @@ int xc_linux_save(int xc_handle,
}
/* Start writing out the saved-domain record. */
- ppage = map_pfn_readonly(pm_handle, shared_info_frame);
+ live_shinfo = mfn_mapper_map_single(xc_handle, domid,
+ PAGE_SIZE, PROT_READ,
+ shared_info_frame);
+
+ if (!live_shinfo)
+ {
+ ERROR("Couldn't map live_shinfo");
+ goto out;
+ }
+
if ( !checked_write(gfd, "LinuxGuestRecord", 16) ||
!checked_write(gfd, name, sizeof(name)) ||
!checked_write(gfd, &srec.nr_pfns, sizeof(unsigned long)) ||
!checked_write(gfd, &ctxt, sizeof(ctxt)) ||
- !checked_write(gfd, ppage, PAGE_SIZE) ||
- !checked_write(gfd, pfn_to_mfn_frame_list, PAGE_SIZE) ||
- !checked_write(gfd, pfn_type, 4 * srec.nr_pfns) )
+ !checked_write(gfd, live_shinfo, PAGE_SIZE) ||
+ !checked_write(gfd, pfn_to_mfn_frame_list, PAGE_SIZE) )
{
ERROR("Error when writing to state file");
goto out;
}
- unmap_pfn(pm_handle, ppage);
+ munmap(live_shinfo, PAGE_SIZE);
verbose_printf("Saving memory pages: 0%%");
+ if ( (mapper_handle2 = mfn_mapper_init(xc_handle, domid,
+ BATCH_SIZE*4096, PROT_READ ))
+ == NULL )
+ goto out;
+
+ region_base = mfn_mapper_base( mapper_handle2 );
+
/* Now write out each data page, canonicalising page tables as we go... */
prev_pc = 0;
- for ( i = 0; i < srec.nr_pfns; i++ )
+ for ( n = 0; n < srec.nr_pfns; )
{
- this_pc = (i * 100) / srec.nr_pfns;
+ this_pc = (n * 100) / srec.nr_pfns;
if ( (this_pc - prev_pc) >= 5 )
{
verbose_printf("\b\b\b\b%3d%%", this_pc);
prev_pc = this_pc;
}
- mfn = pfn_to_mfn_table[i];
-
- ppage = map_pfn_readonly(pm_handle, mfn);
- memcpy(page, ppage, PAGE_SIZE);
- unmap_pfn(pm_handle, ppage);
-
- if ( (pfn_type[i] == L1TAB) || (pfn_type[i] == L2TAB) )
- {
- for ( j = 0;
- j < ((pfn_type[i] == L2TAB) ?
- (HYPERVISOR_VIRT_START >> L2_PAGETABLE_SHIFT) : 1024);
- j++ )
- {
- if ( !(page[j] & _PAGE_PRESENT) ) continue;
- mfn = page[j] >> PAGE_SHIFT;
- if ( !MFN_IS_IN_PSEUDOPHYS_MAP(mfn) )
- {
- ERROR("Frame number in pagetable page is invalid");
- goto out;
- }
- page[j] &= PAGE_SIZE - 1;
- page[j] |= mfn_to_pfn_table[mfn] << PAGE_SHIFT;
- }
- }
-
- if ( !checked_write(gfd, page, PAGE_SIZE) )
- {
- ERROR("Error when writing to state file");
- goto out;
- }
+ for( j = 0, i = n; j < BATCH_SIZE && i < srec.nr_pfns ; j++, i++ )
+ {
+ pfn_type[j] = live_pfn_to_mfn_table[i];
+ }
+
+
+ for( j = 0, i = n; j < BATCH_SIZE && i < srec.nr_pfns ; j++, i++ )
+ {
+ /* queue up mappings for all of the pages in this batch */
+
+//printf("region n=%d j=%d i=%d mfn=%d\n",n,j,i,live_pfn_to_mfn_table[i]);
+ mfn_mapper_queue_entry( mapper_handle2, j<<PAGE_SHIFT,
+ live_pfn_to_mfn_table[i],
+ PAGE_SIZE );
+ }
+
+ if( mfn_mapper_flush_queue(mapper_handle2) )
+ {
+ ERROR("Couldn't map page region");
+ goto out;
+ }
+
+ if ( get_pfn_type_batch(xc_handle, domid, j, pfn_type) )
+ {
+ ERROR("get_pfn_type_batch failed");
+ goto out;
+ }
+
+ for( j = 0, i = n; j < BATCH_SIZE && i < srec.nr_pfns ; j++, i++ )
+ {
+ if((pfn_type[j]>>29) == 7)
+ {
+ ERROR("bogus page");
+ goto out;
+ }
+
+ /* canonicalise mfn->pfn */
+ pfn_type[j] = (pfn_type[j] & PGT_type_mask) |
+ live_mfn_to_pfn_table[pfn_type[j]&~PGT_type_mask];
+
+/* if(pfn_type[j]>>29)
+ printf("i=%d type=%d\n",i,pfn_type[i]); */
+ }
+
+
+ if ( !checked_write(gfd, &j, sizeof(int) ) )
+ {
+ ERROR("Error when writing to state file");
+ goto out;
+ }
+
+ if ( !checked_write(gfd, pfn_type, sizeof(unsigned long)*j ) )
+ {
+ ERROR("Error when writing to state file");
+ goto out;
+ }
+
+
+ for( j = 0, i = n; j < BATCH_SIZE && i < srec.nr_pfns ; j++, i++ )
+ {
+ /* write out pages in batch */
+
+ if ( ((pfn_type[j] & PGT_type_mask) == L1TAB) ||
+ ((pfn_type[j] & PGT_type_mask) == L2TAB) )
+ {
+
+ memcpy(page, region_base + (PAGE_SIZE*j), PAGE_SIZE);
+
+ for ( k = 0;
+ k < (((pfn_type[j] & PGT_type_mask) == L2TAB) ?
+ (HYPERVISOR_VIRT_START >> L2_PAGETABLE_SHIFT) : 1024);
+ k++ )
+ {
+ if ( !(page[k] & _PAGE_PRESENT) ) continue;
+ mfn = page[k] >> PAGE_SHIFT;
+ if ( !MFN_IS_IN_PSEUDOPHYS_MAP(mfn) )
+ {
+ ERROR("Frame number in pagetable page is invalid");
+ goto out;
+ }
+ page[k] &= PAGE_SIZE - 1;
+ page[k] |= live_mfn_to_pfn_table[mfn] << PAGE_SHIFT;
+
+ }
+
+ if ( !checked_write(gfd, page, PAGE_SIZE) )
+ {
+ ERROR("Error when writing to state file");
+ goto out;
+ }
+
+
+ }
+ else
+ {
+ if ( !checked_write(gfd, region_base + (PAGE_SIZE*j), PAGE_SIZE) )
+ {
+ ERROR("Error when writing to state file");
+ goto out;
+ }
+ }
+ }
+
+ n+=j; /* i is the master loop counter */
}
verbose_printf("\b\b\b\b100%%\nMemory saved.\n");
@@ -371,10 +467,19 @@ int xc_linux_save(int xc_handle,
/* Success! */
rc = 0;
- out:
+ /* Zero terminate */
+ if ( !checked_write(gfd, &rc, sizeof(int)) )
+ {
+ ERROR("Error when writing to state file");
+ goto out;
+ }
+
+
+out:
/* Restart the domain if we had to stop it to save its state. */
if ( we_stopped_it )
{
+ printf("Restart domain\n");
op.cmd = DOM0_STARTDOMAIN;
op.u.startdomain.domain = (domid_t)domid;
(void)do_dom0_op(xc_handle, &op);
@@ -382,13 +487,6 @@ int xc_linux_save(int xc_handle,
gzclose(gfd);
- if ( pm_handle >= 0 )
- (void)close_pfn_mapper(pm_handle);
-
- if ( pfn_to_mfn_table != NULL )
- free(pfn_to_mfn_table);
- if ( mfn_to_pfn_table != NULL )
- free(mfn_to_pfn_table);
if ( pfn_type != NULL )
free(pfn_type);
@@ -397,4 +495,6 @@ int xc_linux_save(int xc_handle,
unlink(state_file);
return !!rc;
+
+
}
diff --git a/tools/xc/lib/xc_netbsd_build.c b/tools/xc/lib/xc_netbsd_build.c
index cac444bd80..8260c75ea4 100644
--- a/tools/xc/lib/xc_netbsd_build.c
+++ b/tools/xc/lib/xc_netbsd_build.c
@@ -27,6 +27,7 @@ static long get_tot_pages(int xc_handle, u64 domid)
dom0_op_t op;
op.cmd = DOM0_GETDOMAININFO;
op.u.getdomaininfo.domain = (domid_t)domid;
+ op.u.getdomaininfo.ctxt = NULL;
return (do_dom0_op(xc_handle, &op) < 0) ?
-1 : op.u.getdomaininfo.tot_pages;
}
@@ -59,7 +60,7 @@ static int setup_guestos(int xc_handle,
unsigned long tot_pages,
unsigned long *virt_startinfo_addr,
unsigned long *virt_load_addr,
- dom0_builddomain_t *builddomain,
+ full_execution_context_t *ctxt,
const char *cmdline,
unsigned long shared_info_frame,
unsigned int control_evtchn,
@@ -79,8 +80,6 @@ static int setup_guestos(int xc_handle,
mmu_t *mmu = NULL;
int pm_handle, i;
- memset(builddomain, 0, sizeof(*builddomain));
-
if ( (pm_handle = init_pfn_mapper((domid_t)dom)) < 0 )
goto error_out;
@@ -120,7 +119,7 @@ static int setup_guestos(int xc_handle,
*/
l2tab = page_array[alloc_index] << PAGE_SHIFT;
alloc_index--;
- builddomain->ctxt.pt_base = l2tab;
+ ctxt->pt_base = l2tab;
if ( (mmu = init_mmu_updates(xc_handle, dom)) == NULL )
goto error_out;
@@ -223,7 +222,7 @@ int xc_netbsd_build(int xc_handle,
int kernel_fd = -1;
gzFile kernel_gfd = NULL;
int rc, i;
- full_execution_context_t *ctxt;
+ full_execution_context_t st_ctxt, *ctxt = &st_ctxt;
unsigned long virt_startinfo_addr;
if ( (tot_pages = get_tot_pages(xc_handle, domid)) < 0 )
@@ -246,8 +245,15 @@ int xc_netbsd_build(int xc_handle,
return 1;
}
+ if ( mlock(&st_ctxt, sizeof(st_ctxt) ) )
+ {
+ PERROR("Unable to mlock ctxt");
+ return 1;
+ }
+
op.cmd = DOM0_GETDOMAININFO;
op.u.getdomaininfo.domain = (domid_t)domid;
+ op.u.getdomaininfo.ctxt = ctxt;
if ( (do_dom0_op(xc_handle, &op) < 0) ||
((u64)op.u.getdomaininfo.domain != domid) )
{
@@ -255,7 +261,7 @@ int xc_netbsd_build(int xc_handle,
goto error_out;
}
if ( (op.u.getdomaininfo.state != DOMSTATE_STOPPED) ||
- (op.u.getdomaininfo.ctxt.pt_base != 0) )
+ (op.u.getdomaininfo.ctxt->pt_base != 0) )
{
ERROR("Domain is already constructed");
goto error_out;
@@ -263,7 +269,7 @@ int xc_netbsd_build(int xc_handle,
if ( setup_guestos(xc_handle, domid, kernel_gfd, tot_pages,
&virt_startinfo_addr,
- &load_addr, &launch_op.u.builddomain, cmdline,
+ &load_addr, &st_ctxt, cmdline,
op.u.getdomaininfo.shared_info_frame,
control_evtchn, io_priv) < 0 )
{
@@ -276,8 +282,6 @@ int xc_netbsd_build(int xc_handle,
if( kernel_gfd )
gzclose(kernel_gfd);
- ctxt = &launch_op.u.builddomain.ctxt;
-
ctxt->flags = 0;
/*
@@ -330,9 +334,11 @@ int xc_netbsd_build(int xc_handle,
ctxt->failsafe_callback_cs = FLAT_GUESTOS_CS;
ctxt->failsafe_callback_eip = 0;
+ memset( &launch_op, 0, sizeof(launch_op) );
+
launch_op.u.builddomain.domain = (domid_t)domid;
launch_op.u.builddomain.num_vifs = 1;
-
+ launch_op.u.builddomain.ctxt = ctxt;
launch_op.cmd = DOM0_BUILDDOMAIN;
rc = do_dom0_op(xc_handle, &launch_op);
diff --git a/tools/xc/lib/xc_private.c b/tools/xc/lib/xc_private.c
index 485aa58754..d137176ca8 100644
--- a/tools/xc/lib/xc_private.c
+++ b/tools/xc/lib/xc_private.c
@@ -45,6 +45,234 @@ void unmap_pfn(int pm_handle, void *vaddr)
(void)munmap(vaddr, PAGE_SIZE);
}
+/*******************/
+
+void * mfn_mapper_map_single(int xc_handle, domid_t dom,
+ int size, int prot,
+ unsigned long mfn )
+{
+ privcmd_mmap_t ioctlx;
+ privcmd_mmap_entry_t entry;
+ void *addr;
+ addr = mmap( NULL, size, prot, MAP_SHARED, xc_handle, 0 );
+ if (addr)
+ {
+ ioctlx.num=1;
+ ioctlx.dom=dom;
+ ioctlx.entry=&entry;
+ entry.va=(unsigned long) addr;
+ entry.mfn=mfn;
+ entry.npages=(size+PAGE_SIZE-1)>>PAGE_SHIFT;
+ if ( ioctl( xc_handle, IOCTL_PRIVCMD_MMAP, &ioctlx ) <0 )
+ return 0;
+ }
+ return addr;
+}
+
+mfn_mapper_t * mfn_mapper_init(int xc_handle, domid_t dom, int size, int prot)
+{
+ mfn_mapper_t * t;
+ t = calloc( 1, sizeof(mfn_mapper_t)+
+ mfn_mapper_queue_size*sizeof(privcmd_mmap_entry_t) );
+ if (!t) return NULL;
+ t->xc_handle = xc_handle;
+ t->size = size;
+ t->prot = prot;
+ t->error = 0;
+ t->max_queue_size = mfn_mapper_queue_size;
+ t->addr = mmap( NULL, size, prot, MAP_SHARED, xc_handle, 0 );
+ if (!t->addr)
+ {
+ free(t);
+ return NULL;
+ }
+ t->ioctl.num = 0;
+ t->ioctl.dom = dom;
+ t->ioctl.entry = (privcmd_mmap_entry_t *) &t[1];
+ return t;
+}
+
+void * mfn_mapper_base(mfn_mapper_t *t)
+{
+ return t->addr;
+}
+
+void mfn_mapper_close(mfn_mapper_t *t)
+{
+ if(t->addr) munmap( t->addr, t->size );
+ free(t);
+}
+
+static int __mfn_mapper_flush_queue(mfn_mapper_t *t)
+{
+ int rc;
+ rc = ioctl( t->xc_handle, IOCTL_PRIVCMD_MMAP, &t->ioctl );
+ t->ioctl.num = 0;
+ if(rc && !t->error)
+ t->error = rc;
+ return rc;
+}
+
+int mfn_mapper_flush_queue(mfn_mapper_t *t)
+{
+ int rc;
+
+ rc = __mfn_mapper_flush_queue(t);
+
+ if ( t->error )
+ {
+ rc = t->error;
+ }
+
+ t->error = 0;
+ return rc;
+}
+
+void * mfn_mapper_queue_entry(mfn_mapper_t *t, int offset,
+ unsigned long mfn, int size)
+{
+ privcmd_mmap_entry_t *entry, *prev;
+ int pages;
+
+ offset &= PAGE_MASK;
+ pages =(size+PAGE_SIZE-1)>>PAGE_SHIFT;
+ entry = &t->ioctl.entry[t->ioctl.num];
+
+ if ( t->ioctl.num > 0 )
+ {
+ prev = &t->ioctl.entry[t->ioctl.num-1];
+
+ if ( (prev->va+(prev->npages*PAGE_SIZE)) ==
+ ((unsigned long)t->addr+offset) &&
+ (prev->mfn+prev->npages) == mfn )
+ {
+ prev->npages += pages;
+ return t->addr+offset;
+ }
+ }
+
+ entry->va = (unsigned long)t->addr+offset;
+ entry->mfn = mfn;
+ entry->npages = pages;
+ t->ioctl.num++;
+
+ if(t->ioctl.num == t->max_queue_size)
+ {
+ if ( __mfn_mapper_flush_queue(t) )
+ return 0;
+ }
+
+ return t->addr+offset;
+}
+
+
+/*******************/
+
+#if 0
+
+mfn_typer_t *mfn_typer_init(int xc_handle, domid_t dom, int num )
+{
+ mfn_typer_t *t;
+ multicall_entry_t *m;
+ dom0_op_compact_getpageframeinfo_t *d;
+
+ t = calloc(1, sizeof(mfn_typer_t) );
+ m = calloc(num, sizeof(multicall_entry_t));
+ d = calloc(num, sizeof(dom0_op_compact_getpageframeinfo_t));
+
+ if (!t || !m || !d)
+ {
+ if(t) free(t);
+ if(m) free(m);
+ if(d) free(d);
+ return NULL;
+ }
+
+printf("sizeof(m)=%d sizeof(d)=%d m=%p d=%p\n",sizeof(multicall_entry_t), sizeof(dom0_op_compact_getpageframeinfo_t),m,d);
+
+ if ( (mlock(m, sizeof(multicall_entry_t)*num ) != 0) ||
+ (mlock(d, sizeof(dom0_op_compact_getpageframeinfo_t)*num ) != 0) )
+ {
+ PERROR("Could not lock memory for Xen hypercall");
+ return NULL;
+ }
+
+ t->xc_handle = xc_handle;
+ t->max = num;
+ t->nr_multicall_ents=0;
+ t->multicall_list=m;
+ t->gpf_list=d;
+ t->dom = dom;
+
+ return t;
+}
+
+void mfn_typer_queue_entry(mfn_typer_t *t, unsigned long mfn )
+{
+ int i = t->nr_multicall_ents;
+ multicall_entry_t *m = &t->multicall_list[i];
+ dom0_op_compact_getpageframeinfo_t *d = &t->gpf_list[i];
+
+ d->cmd = DOM0_GETPAGEFRAMEINFO;
+ d->interface_version = DOM0_INTERFACE_VERSION;
+ d->getpageframeinfo.pfn = mfn;
+ d->getpageframeinfo.domain = t->dom;
+ d->getpageframeinfo.type = 1000; //~0UL;
+
+ m->op = __HYPERVISOR_dom0_op;
+ m->args[0] = (unsigned long)d;
+
+ t->nr_multicall_ents++;
+}
+
+int mfn_typer_flush_queue(mfn_typer_t *t)
+{
+ if (t->nr_multicall_ents == 0) return 0;
+ do_multicall_op(t->xc_handle, t->multicall_list, t->nr_multicall_ents);
+ t->nr_multicall_ents = 0;
+}
+
+unsigned int mfn_typer_get_result(mfn_typer_t *t, int idx)
+{
+ return t->gpf_list[idx].getpageframeinfo.type;
+}
+
+#endif
+
+/* NB: arr must be mlock'ed */
+
+int get_pfn_type_batch(int xc_handle,
+ u64 dom, int num, unsigned long *arr)
+{
+ dom0_op_t op;
+ op.cmd = DOM0_GETPAGEFRAMEINFO2;
+ op.u.getpageframeinfo2.domain = (domid_t)dom;
+ op.u.getpageframeinfo2.num = num;
+ op.u.getpageframeinfo2.array = arr;
+ return do_dom0_op(xc_handle, &op);
+}
+
+#define GETPFN_ERR (~0U)
+unsigned int get_pfn_type(int xc_handle,
+ unsigned long mfn,
+ u64 dom)
+{
+ dom0_op_t op;
+ op.cmd = DOM0_GETPAGEFRAMEINFO;
+ op.u.getpageframeinfo.pfn = mfn;
+ op.u.getpageframeinfo.domain = (domid_t)dom;
+ if ( do_dom0_op(xc_handle, &op) < 0 )
+ {
+ PERROR("Unexpected failure when getting page frame info!");
+ return GETPFN_ERR;
+ }
+ return op.u.getpageframeinfo.type;
+}
+
+
+
+/*******************/
+
#define FIRST_MMU_UPDATE 2
static int flush_mmu_updates(int xc_handle, mmu_t *mmu)
diff --git a/tools/xc/lib/xc_private.h b/tools/xc/lib/xc_private.h
index d4299109e5..eaa301772d 100644
--- a/tools/xc/lib/xc_private.h
+++ b/tools/xc/lib/xc_private.h
@@ -16,8 +16,6 @@
#include "xc.h"
-#include <asm-xen/proc_cmd.h>
-
/* from xen/include/hypervisor-ifs */
#include <hypervisor-if.h>
#include <dom0_ops.h>
@@ -25,6 +23,10 @@
#include <event_channel.h>
#include <sched_ctl.h>
+#include <asm-xen/proc_cmd.h>
+
+
+
/* from xend/lib */
#include <domain_controller.h>
@@ -108,6 +110,27 @@ static inline int do_dom0_op(int xc_handle, dom0_op_t *op)
out1: return ret;
}
+static inline int do_multicall_op(int xc_handle,
+ void *call_list, int nr_calls)
+{
+ int ret = -1;
+ privcmd_hypercall_t hypercall;
+
+ hypercall.op = __HYPERVISOR_multicall;
+ hypercall.arg[0] = (unsigned long)call_list;
+ hypercall.arg[1] = (unsigned long)nr_calls;
+
+ if ( (ret = do_xen_hypercall(xc_handle, &hypercall)) < 0 )
+ {
+ if ( errno == EACCES )
+ fprintf(stderr, "Dom0 operation failed -- need to"
+ " rebuild the user-space tool set?\n");
+ goto out1;
+ }
+
+ out1: return ret;
+}
+
static inline int do_network_op(int xc_handle, network_op_t *op)
{
int ret = -1;
@@ -174,4 +197,77 @@ int add_mmu_update(int xc_handle, mmu_t *mmu,
unsigned long ptr, unsigned long val);
int finish_mmu_updates(int xc_handle, mmu_t *mmu);
+
+/*
+ * ioctl-based mfn mapping interface
+ */
+
+/*
+typedef struct privcmd_mmap_entry {
+ unsigned long va;
+ unsigned long mfn;
+ unsigned long npages;
+} privcmd_mmap_entry_t;
+
+typedef struct privcmd_mmap {
+ int num;
+ domid_t dom;
+ privcmd_mmap_entry_t *entry;
+} privcmd_mmap_t;
+*/
+
+#define mfn_mapper_queue_size 128
+
+typedef struct mfn_mapper {
+ int xc_handle;
+ int size;
+ int prot;
+ int error;
+ int max_queue_size;
+ void * addr;
+ privcmd_mmap_t ioctl;
+
+} mfn_mapper_t;
+
+void * mfn_mapper_map_single(int xc_handle, domid_t dom, int size, int prot,
+ unsigned long mfn );
+
+mfn_mapper_t * mfn_mapper_init(int xc_handle, domid_t dom, int size, int prot);
+
+void * mfn_mapper_base(mfn_mapper_t *t);
+
+void mfn_mapper_close(mfn_mapper_t *t);
+
+int mfn_mapper_flush_queue(mfn_mapper_t *t);
+
+void * mfn_mapper_queue_entry(mfn_mapper_t *t, int offset,
+ unsigned long mfn, int size );
+
+/*********************/
+
+
+#if 0
+typedef struct mfn_typer {
+ domid_t dom;
+ int xc_handle;
+ int max;
+ dom0_op_t op;
+} mfn_typer_t;
+
+
+mfn_typer_t *mfn_typer_init(int xc_handle, domid_t dom, int num );
+
+void mfn_typer_queue_entry(mfn_typer_t *t, unsigned long mfn );
+
+int mfn_typer_flush_queue(mfn_typer_t *t);
+#endif
+
+int get_pfn_type_batch(int xc_handle,
+ u64 dom, int num, unsigned long *arr);
+
+unsigned int get_pfn_type(int xc_handle,
+ unsigned long mfn,
+ u64 dom);
+
+
#endif /* __XC_PRIVATE_H__ */