aboutsummaryrefslogtreecommitdiffstats
path: root/tools
diff options
context:
space:
mode:
Diffstat (limited to 'tools')
-rw-r--r--tools/xc/lib/xc.h1
-rw-r--r--tools/xc/lib/xc_linux_restore.c67
-rw-r--r--tools/xc/lib/xc_linux_save.c104
-rw-r--r--tools/xc/lib/xc_private.c20
-rw-r--r--tools/xc/py/Xc.c10
5 files changed, 172 insertions, 30 deletions
diff --git a/tools/xc/lib/xc.h b/tools/xc/lib/xc.h
index 2132d6e7c1..223710fad1 100644
--- a/tools/xc/lib/xc.h
+++ b/tools/xc/lib/xc.h
@@ -64,6 +64,7 @@ int xc_shadow_control(int xc_handle,
#define XCFLAGS_VERBOSE 1
#define XCFLAGS_LIVE 2
+#define XCFLAGS_DEBUG 4
int xc_linux_save(int xc_handle,
u64 domid,
diff --git a/tools/xc/lib/xc_linux_restore.c b/tools/xc/lib/xc_linux_restore.c
index 1bbc575889..d66e22fd0a 100644
--- a/tools/xc/lib/xc_linux_restore.c
+++ b/tools/xc/lib/xc_linux_restore.c
@@ -67,6 +67,7 @@ int xc_linux_restore(int xc_handle,
unsigned long mfn, pfn, xpfn;
unsigned int prev_pc, this_pc;
int verbose = flags & XCFLAGS_VERBOSE;
+ int verify = 0;
/* Number of page frames in use by this Linux session. */
unsigned long nr_pfns;
@@ -106,6 +107,8 @@ int xc_linux_restore(int xc_handle,
int pm_handle = -1;
+ /* used by debug verify code */
+ unsigned long buf[PAGE_SIZE/sizeof(unsigned long)];
if ( mlock(&ctxt, sizeof(ctxt) ) )
{
@@ -241,8 +244,17 @@ int xc_linux_restore(int xc_handle,
DPRINTF("batch %d\n",j);
+ if (j == -1)
+ {
+ verify = 1;
+ printf("Entering page verify mode\n");
+ continue;
+ }
+
if (j == 0)
+ {
break; // our work here is done
+ }
if( j > MAX_BATCH_SIZE )
{
@@ -296,7 +308,10 @@ int xc_linux_restore(int xc_handle,
mfn = pfn_to_mfn_table[pfn];
- ppage = (unsigned long*) (region_base + i*PAGE_SIZE);
+ if ( verify )
+ ppage = (unsigned long*) buf; // debug case
+ else
+ ppage = (unsigned long*) (region_base + i*PAGE_SIZE);
if ( (*readerfn)(readerst, ppage, PAGE_SIZE) )
{
@@ -364,6 +379,24 @@ int xc_linux_restore(int xc_handle,
} // end of page type switch statement
+ if ( verify )
+ {
+ int res = memcmp(buf, (region_base + i*PAGE_SIZE), PAGE_SIZE );
+ if (res)
+ {
+ int v;
+ printf("************** pfn=%x type=%x gotcs=%08lx actualcs=%08lx\n",pfn,pfn_type[pfn],csum_page(region_base + i*PAGE_SIZE),csum_page(buf));
+ for(v=0;v<4;v++)
+ {
+ unsigned long * p = (unsigned long *) (region_base + i*PAGE_SIZE);
+ if ( buf[v] != p[v] )
+ printf(" %d: %08lx %08lx\n",
+ v, buf[v], p[v] );
+ }
+
+ }
+ }
+
if ( add_mmu_update(xc_handle, mmu,
(mfn<<PAGE_SHIFT) | MMU_MACHPHYS_UPDATE, pfn) )
goto out;
@@ -421,7 +454,6 @@ int xc_linux_restore(int xc_handle,
goto out;
}
-
/* Uncanonicalise the suspend-record frame number and poke resume rec. */
pfn = ctxt.cpu_ctxt.esi;
if ( (pfn >= nr_pfns) || (pfn_type[pfn] != NONE) )
@@ -464,6 +496,12 @@ int xc_linux_restore(int xc_handle,
}
ctxt.pt_base = pfn_to_mfn_table[pfn] << PAGE_SHIFT;
+
+ /* clear any pending events and the selector */
+ memset( &(((shared_info_t *)shared_info)->evtchn_pending[0]),
+ 0, sizeof (((shared_info_t *)shared_info)->evtchn_pending)+
+ sizeof(((shared_info_t *)shared_info)->evtchn_pending_sel) );
+
/* Copy saved contents of shared-info page. No checking needed. */
ppage = map_pfn_writeable(pm_handle, shared_info_frame);
memcpy(ppage, shared_info, sizeof(shared_info_t));
@@ -543,13 +581,18 @@ int xc_linux_restore(int xc_handle,
op.u.builddomain.ctxt = &ctxt;
rc = do_dom0_op(xc_handle, &op);
- DPRINTF("Everything OK!\n");
+ /* don't start the domain as we have console etc to set up */
+
+ if( rc == 0 )
+ {
+ /* Success: print the domain id. */
+ verbose_printf("DOM=%llu\n", dom);
+ return 0;
+ }
- out:
- if ( mmu != NULL )
- free(mmu);
- if ( rc != 0 )
+ out:
+ if ( rc != 0 ) // destroy is something went wrong
{
if ( dom != 0 )
{
@@ -559,11 +602,9 @@ int xc_linux_restore(int xc_handle,
(void)do_dom0_op(xc_handle, &op);
}
}
- else
- {
- /* Success: print the domain id. */
- verbose_printf("DOM=%llu\n", dom);
- }
+
+ if ( mmu != NULL )
+ free(mmu);
if ( pm_handle >= 0 )
(void)close_pfn_mapper(pm_handle);
@@ -577,5 +618,7 @@ int xc_linux_restore(int xc_handle,
if ( rc == 0 )
*pdomid = dom;
+ DPRINTF("Restore exit with rc=%d\n",rc);
+
return rc;
}
diff --git a/tools/xc/lib/xc_linux_save.c b/tools/xc/lib/xc_linux_save.c
index 37dd7c6fce..ceb5f02e15 100644
--- a/tools/xc/lib/xc_linux_save.c
+++ b/tools/xc/lib/xc_linux_save.c
@@ -12,6 +12,7 @@
#define BATCH_SIZE 1024 /* 1024 pages (4MB) at a time */
#define DEBUG 0
+#define DDEBUG 0
#if DEBUG
#define DPRINTF(_f, _a...) printf ( _f , ## _a )
@@ -19,6 +20,14 @@
#define DPRINTF(_f, _a...) ((void)0)
#endif
+#if DDEBUG
+#define DDPRINTF(_f, _a...) printf ( _f , ## _a )
+#else
+#define DDPRINTF(_f, _a...) ((void)0)
+#endif
+
+
+
/* This may allow us to create a 'quiet' command-line option, if necessary. */
#define verbose_printf(_f, _a...) \
do { \
@@ -61,6 +70,18 @@ inline int test_bit ( int nr, volatile void * addr)
(nr % (sizeof(unsigned long)*8) ) ) & 1;
}
+inline void clear_bit ( int nr, volatile void * addr)
+{
+ ((unsigned long*)addr)[nr/(sizeof(unsigned long)*8)] &=
+ ~(1 << (nr % (sizeof(unsigned long)*8) ) );
+}
+
+inline void set_bit ( int nr, volatile void * addr)
+{
+ ((unsigned long*)addr)[nr/(sizeof(unsigned long)*8)] |=
+ (1 << (nr % (sizeof(unsigned long)*8) ) );
+}
+
int xc_linux_save(int xc_handle,
u64 domid,
@@ -73,6 +94,7 @@ int xc_linux_save(int xc_handle,
unsigned long mfn;
int verbose = flags & XCFLAGS_VERBOSE;
int live = flags & XCFLAGS_LIVE;
+ int debug = flags & XCFLAGS_DEBUG;
int sent_last_iter, sent_this_iter, max_iters;
/* Remember if we stopped the guest, so we can restart it on exit. */
@@ -89,6 +111,7 @@ int xc_linux_save(int xc_handle,
/* A table containg the type of each PFN (/not/ MFN!). */
unsigned long *pfn_type = NULL;
+ unsigned long *pfn_batch = NULL;
/* A temporary mapping, and a copy, of one frame of guest memory. */
unsigned long page[1024];
@@ -115,7 +138,9 @@ int xc_linux_save(int xc_handle,
unsigned long nr_pfns;
/* bitmap of pages left to send */
- unsigned long *to_send;
+ unsigned long *to_send, *to_fix;
+
+//live=0;
if ( mlock(&ctxt, sizeof(ctxt) ) )
{
@@ -274,8 +299,9 @@ int xc_linux_save(int xc_handle,
int sz = (nr_pfns/8) + 8; // includes slop at end of array
to_send = malloc( sz );
+ to_fix = calloc( 1, sz );
- if (!to_send)
+ if (!to_send || !to_fix)
{
ERROR("Couldn't allocate to_send array");
goto out;
@@ -292,8 +318,9 @@ int xc_linux_save(int xc_handle,
/* We want zeroed memory so use calloc rather than malloc. */
pfn_type = calloc(BATCH_SIZE, sizeof(unsigned long));
+ pfn_batch = calloc(BATCH_SIZE, sizeof(unsigned long));
- if ( (pfn_type == NULL) )
+ if ( (pfn_type == NULL) || (pfn_batch == NULL) )
{
errno = ENOMEM;
goto out;
@@ -370,22 +397,41 @@ int xc_linux_save(int xc_handle,
for( batch = 0; batch < BATCH_SIZE && n < nr_pfns ; n++ )
{
- if ( !test_bit(n, to_send ) ) continue;
+ if(0 && debug)
+ fprintf(stderr,"%d pfn= %08lx mfn= %08lx %d [mfn]= %08lx\n",
+ iter, n, live_pfn_to_mfn_table[n],
+ test_bit(n,to_send),
+ live_mfn_to_pfn_table[live_pfn_to_mfn_table[n]&0xFFFFF]);
+
+
+ if ( !test_bit(n, to_send ) &&
+ !( last_iter && test_bit(n, to_fix ) ) ) continue;
+
+ pfn_batch[batch] = n;
pfn_type[batch] = live_pfn_to_mfn_table[n];
if( pfn_type[batch] == 0x80000004 )
{
- DPRINTF("Skip netbuf pfn %lx. mfn %lx\n",n,pfn_type[batch]);
+ set_bit( n, to_fix );
+ if( iter>1 )
+ DDPRINTF("Urk! netbuf race: iter %d, pfn %lx. mfn %lx\n",
+ iter,n,pfn_type[batch]);
continue;
}
- if(iter>1) { DPRINTF("pfn=%x mfn=%x\n",n,pfn_type[batch]); }
-
+ if ( last_iter && test_bit(n, to_fix ) && !test_bit(n, to_send ))
+ {
+ DPRINTF("Fix! iter %d, pfn %lx. mfn %lx\n",
+ iter,n,pfn_type[batch]);
+ }
+
+ clear_bit( n, to_fix );
+
batch++;
}
- DPRINTF("batch %d:%d (n=%d)\n",iter,batch,n);
+ DDPRINTF("batch %d:%d (n=%d)\n",iter,batch,n);
if(batch == 0) goto skip; // vanishingly unlikely...
@@ -408,15 +454,26 @@ int xc_linux_save(int xc_handle,
{
if((pfn_type[j]>>29) == 7)
{
- DPRINTF("type fail: page %i mfn %08lx\n",j,pfn_type[j]);
+ DDPRINTF("type fail: page %i mfn %08lx\n",j,pfn_type[j]);
continue;
}
+ if(0 && debug)
+ fprintf(stderr,"%d pfn= %08lx mfn= %08lx [mfn]= %08lx sum= %08lx\n",
+ iter,
+ (pfn_type[j] & PGT_type_mask) | pfn_batch[j],
+ pfn_type[j],
+ live_mfn_to_pfn_table[pfn_type[j]&(~PGT_type_mask)],
+ csum_page(region_base + (PAGE_SIZE*j))
+ );
+
/* canonicalise mfn->pfn */
pfn_type[j] = (pfn_type[j] & PGT_type_mask) |
- live_mfn_to_pfn_table[pfn_type[j]&~PGT_type_mask];
+ pfn_batch[j];
+ //live_mfn_to_pfn_table[pfn_type[j]&~PGT_type_mask];
+
}
-
+
if ( (*writerfn)(writerst, &batch, sizeof(int) ) )
{
@@ -437,7 +494,7 @@ int xc_linux_save(int xc_handle,
if((pfn_type[j]>>29) == 7)
{
- DPRINTF("SKIP BOGUS page %i mfn %08lx\n",j,pfn_type[j]);
+ DDPRINTF("SKIP BOGUS page %i mfn %08lx\n",j,pfn_type[j]);
continue;
}
@@ -494,6 +551,7 @@ int xc_linux_save(int xc_handle,
} /* end of it's a PT page */
else
{ /* normal page */
+
if ( (*writerfn)(writerst, region_base + (PAGE_SIZE*j), PAGE_SIZE) )
{
ERROR("Error when writing to state file (5)");
@@ -512,6 +570,23 @@ int xc_linux_save(int xc_handle,
verbose_printf("\b\b\b\b100%% (%d pages)\n", sent_this_iter );
+ if ( debug && last_iter )
+ {
+ int minusone = -1;
+ memset( to_send, 0xff, nr_pfns/8 );
+ debug = 0;
+ printf("Entering debug resend-all mode\n");
+
+ /* send "-1" to put receiver into debug mode */
+ if ( (*writerfn)(writerst, &minusone, sizeof(int)) )
+ {
+ ERROR("Error when writing to state file (6)");
+ goto out;
+ }
+
+ continue;
+ }
+
if ( last_iter )
break;
@@ -520,7 +595,7 @@ int xc_linux_save(int xc_handle,
if ( ( sent_this_iter > (sent_last_iter * 0.95) ) ||
(iter >= max_iters) || (sent_this_iter < 10) )
{
- printf("Start last iteration\n");
+ DPRINTF("Start last iteration\n");
last_iter = 1;
xc_domain_stop_sync( xc_handle, domid );
@@ -536,6 +611,7 @@ int xc_linux_save(int xc_handle,
}
sent_last_iter = sent_this_iter;
+
}
@@ -609,6 +685,8 @@ out:
if ( pfn_type != NULL )
free(pfn_type);
+
+ DPRINTF("Save exit rc=%d\n",rc);
return !!rc;
diff --git a/tools/xc/lib/xc_private.c b/tools/xc/lib/xc_private.c
index 41eb2e744a..430dc6ec11 100644
--- a/tools/xc/lib/xc_private.c
+++ b/tools/xc/lib/xc_private.c
@@ -410,7 +410,7 @@ int xc_domain_stop_sync( int xc_handle, domid_t domid )
if ( op.u.getdomaininfo.state == DOMSTATE_STOPPED )
{
- printf("\nDomain %lld stopped\n",domid);
+ printf("Domain %lld stopped\n",domid);
return 0;
}
@@ -420,3 +420,21 @@ int xc_domain_stop_sync( int xc_handle, domid_t domid )
out:
return -1;
}
+
+/**********************************************************************/
+
+// this is shared between save and restore, and may be useful.
+
+unsigned long csum_page ( void * page )
+{
+ int i;
+ unsigned long *p = page;
+ unsigned long long sum=0;
+
+ for (i=0;i<PAGE_SIZE/sizeof(unsigned long);i++)
+ {
+ sum += p[i];
+ }
+
+ return sum ^ (sum>>32);
+}
diff --git a/tools/xc/py/Xc.c b/tools/xc/py/Xc.c
index b2ae143eda..7bb1d877bd 100644
--- a/tools/xc/py/Xc.c
+++ b/tools/xc/py/Xc.c
@@ -191,17 +191,18 @@ static PyObject *pyxc_linux_save(PyObject *self,
u64 dom;
char *state_file;
- int progress = 1, live = -1;
+ int progress = 1, live = -1, debug = 0;
unsigned int flags = 0;
- static char *kwd_list[] = { "dom", "state_file", "progress", "live", NULL };
+ static char *kwd_list[] = { "dom", "state_file", "progress", "live", "debug", NULL };
- if ( !PyArg_ParseTupleAndKeywords(args, kwds, "Ls|ii", kwd_list,
- &dom, &state_file, &progress, &live) )
+ if ( !PyArg_ParseTupleAndKeywords(args, kwds, "Ls|iii", kwd_list,
+ &dom, &state_file, &progress, &live, &debug) )
return NULL;
if (progress) flags |= XCFLAGS_VERBOSE;
if (live == 1) flags |= XCFLAGS_LIVE;
+ if (debug) flags |= XCFLAGS_DEBUG;
if ( strncmp(state_file,"tcp:", strlen("tcp:")) == 0 )
{
@@ -362,6 +363,7 @@ static PyObject *pyxc_linux_restore(PyObject *self,
do {
rc = read( (int) fd, ((char*)buf)+tot, count-tot );
if ( rc < 0 ) { perror("READ"); return rc; }
+ if ( rc == 0 ) { printf("read: need %d, tot=%d got zero\n"); return -1; }
tot += rc;
}
while ( tot < count );