aboutsummaryrefslogtreecommitdiffstats
path: root/tools/xc/lib/xc_linux_save.c
diff options
context:
space:
mode:
Diffstat (limited to 'tools/xc/lib/xc_linux_save.c')
-rw-r--r--tools/xc/lib/xc_linux_save.c220
1 files changed, 124 insertions, 96 deletions
diff --git a/tools/xc/lib/xc_linux_save.c b/tools/xc/lib/xc_linux_save.c
index e6e8f8864d..0a367234de 100644
--- a/tools/xc/lib/xc_linux_save.c
+++ b/tools/xc/lib/xc_linux_save.c
@@ -24,7 +24,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,7 +34,7 @@
if ( !MFN_IS_IN_PSEUDOPHYS_MAP(mfn) ) \
_res = 0; \
else \
- *(_pmfn) = mfn_to_pfn_table[mfn]; \
+ *(_pmfn) = live_mfn_to_pfn_table[mfn]; \
_res; \
})
@@ -80,7 +80,7 @@ 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;
@@ -103,25 +103,25 @@ 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 copy of the pfn-to-mfn table frame list. */
- unsigned long *pfn_to_mfn_frame_list;
- /* A live mapping 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 translating each PFN to its current MFN. */
- unsigned long *pfn_to_mfn_table = NULL;
/* Live mapping of the table mapping each PFN to its current MFN. */
unsigned long *live_pfn_to_mfn_table = NULL;
- /* A table translating each current MFN to its canonical PFN. */
- unsigned long *mfn_to_pfn_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 *srec;
+ suspend_record_t *p_srec, srec;
/* The name and descriptor of the file that we are writing to. */
int fd;
@@ -187,118 +187,126 @@ int xc_linux_save(int xc_handle,
}
- /* Map the suspend-record MFN to pin it */
- srec = mfn_mapper_map_single(xc_handle, PROT_READ,
- ctxt.cpu_ctxt.esi, sizeof(*srec));
+ /* 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 );
- /* Is the suspend-record MFN actually valid for this domain? */
- if ( !check_pfn_ownership(xc_handle, ctxt.cpu_ctxt.esi, domid) )
+ if (!p_srec)
{
- ERROR("Invalid state record pointer");
+ ERROR("Couldn't map state record");
goto out;
}
+ memcpy( &srec, p_srec, sizeof(srec) );
+
/* cheesy sanity check */
- if ( srec->nr_pfns > 1024*1024 )
+ if ( srec.nr_pfns > 1024*1024 )
{
ERROR("Invalid state record -- pfn count out of range");
goto out;
}
-
/* the pfn_to_mfn_frame_list fits in a single page */
live_pfn_to_mfn_frame_list =
- mfn_mapper_map_single(xc_handle, PROT_WRITE,
- srec->pfn_to_mfn_frame_list,
- PAGE_SIZE);
+ mfn_mapper_map_single(xc_handle, domid,
+ PAGE_SIZE, PROT_READ,
+ srec.pfn_to_mfn_frame_list );
- if ( !check_pfn_ownership(xc_handle,
- srec->pfn_to_mfn_frame_list, domid) )
+ if (!live_pfn_to_mfn_frame_list)
{
- ERROR("Invalid pfn-to-mfn frame list pointer");
- goto out;
+ ERROR("Couldn't map pfn_to_mfn_frame_list");
+ goto out;
}
+
- memcpy( pfn_to_mfn_frame_list, live_pfn_to_mfn_frame_list, PAGE_SIZE );
-
- if ( (mapper_handle1 = mfn_mapper_init(xc_handle, 1024*1024, PROT_READ ))
+ 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++ )
+ 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,
- pfn_to_mfn_frame_list[i],
+ live_pfn_to_mfn_frame_list[i],
PAGE_SIZE );
}
- mfn_mapper_flush_queue(mapper_handle1);
-
- /* Now they're pined, check they're the right dom. We assume
- they're not going to change, otherwise the suspend is going to fail,
- with only itself to blame. */
-
- for ( i = 0; i < (srec->nr_pfns+1023)/1024; i++ )
+ if ( mfn_mapper_flush_queue(mapper_handle1) )
{
- if ( !check_pfn_ownership(xc_handle,
- pfn_to_mfn_frame_list[i], domid) )
- {
- ERROR("Invalid pfn-to-mfn frame list pointer");
- goto out;
- }
+ ERROR("Couldn't map pfn_to_mfn table");
+ goto out;
}
live_pfn_to_mfn_table = mfn_mapper_base( mapper_handle1 );
+
+
/* 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(1, 4 * srec.nr_pfns);
- if ( (mfn_to_pfn_table == NULL) ||
- (pfn_to_mfn_table == NULL) ||
- (pfn_type == NULL) )
+ if ( (pfn_type == NULL) )
{
errno = ENOMEM;
goto out;
}
+
+ /* Track the mfn_to_pfn table down from the domains PT */
+ {
+ unsigned long *pgd;
+ unsigned long mfn_to_pfn_table_start_mfn;
+
+ pgd = mfn_mapper_map_single(xc_handle, domid,
+ PAGE_SIZE, PROT_READ,
+ ctxt.pt_base>>PAGE_SHIFT);
+/*
+ printf("pt mfn=%d pfn=%d type=%08x pte=%08x\n",ctxt.pt_base>>PAGE_SHIFT,
+ mfn_to_pfn_table[ctxt.pt_base>>PAGE_SHIFT],
+ pfn_type[mfn_to_pfn_table[ctxt.pt_base>>PAGE_SHIFT]],
+ pgd[HYPERVISOR_VIRT_START>>L2_PAGETABLE_SHIFT] );
+*/
+ 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 );
+ }
+
+
/*
* 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.
*/
- for ( i = 0; i < srec->nr_pfns; i++ )
+ for ( i = 0; i < srec.nr_pfns; i++ )
{
mfn = live_pfn_to_mfn_table[i];
- if ( !check_pfn_ownership(xc_handle, mfn, domid) )
- {
- ERROR("Invalid frame specified with pfn-to-mfn table");
- goto out;
- }
+#if 1 /* XXX use the master mfn_to_pfn table???? */
- /* Did we map this MFN already? That would be invalid! */
- if ( mfn_to_pfn_table[mfn] )
- {
- ERROR("A machine frame appears twice in pseudophys space");
- goto out;
- }
- mfn_to_pfn_table[mfn] = i;
- pfn_to_mfn_table[i] = 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]);
/* 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;
+#endif
+
}
+
+
/* Canonicalise the suspend-record frame number. */
if ( !translate_mfn_to_pfn(&ctxt.cpu_ctxt.esi) )
{
@@ -322,9 +330,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]) )
@@ -335,8 +344,15 @@ int xc_linux_save(int xc_handle,
}
/* Start writing out the saved-domain record. */
- live_shinfo = mfn_mapper_map_single(xc_handle, PROT_READ,
- shared_info_frame, PAGE_SIZE);
+ 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;
+ }
/* Belts and braces safety check on the shared info record */
if ( !check_pfn_ownership(xc_handle, shared_info_frame, domid) )
@@ -360,7 +376,9 @@ int xc_linux_save(int xc_handle,
verbose_printf("Saving memory pages: 0%%");
- if ( (mapper_handle2 = mfn_mapper_init(xc_handle,
+#define BATCH_SIZE 1024 /* 1024 pages (4MB) at a time */
+
+ if ( (mapper_handle2 = mfn_mapper_init(xc_handle, domid,
BATCH_SIZE*4096, PROT_READ ))
== NULL )
goto out;
@@ -383,12 +401,19 @@ int xc_linux_save(int xc_handle,
{
/* 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,
- pfn_to_mfn_frame_list[i],
+ live_pfn_to_mfn_table[i],
PAGE_SIZE );
}
- mfn_mapper_flush_queue(mapper_handle2);
-
+
+ if( mfn_mapper_flush_queue(mapper_handle2) )
+ {
+ ERROR("Couldn't map page region");
+ goto out;
+ }
+
+#if 0
typer_handle = get_type_init( xc_handle, BATCH_SIZE )
for( j = 0, i = n; j < BATCH_SIZE && i < srec.nr_pfns ; j++, i++ )
@@ -399,42 +424,51 @@ int xc_linux_save(int xc_handle,
pfn_to_mfn_frame_list[i] );
}
-
region_type = get_type;
+#endif
+
for( j = 0, i = n; j < BATCH_SIZE && i < srec.nr_pfns ; j++, i++ )
{
/* write out pages in batch */
- 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) ?
+
+ memcpy(page, region_base + (PAGE_SIZE*j), PAGE_SIZE);
+
+ for ( k = 0;
+ k < ((pfn_type[i] == L2TAB) ?
(HYPERVISOR_VIRT_START >> L2_PAGETABLE_SHIFT) : 1024);
- j++ )
+ k++ )
{
- if ( !(page[j] & _PAGE_PRESENT) ) continue;
- mfn = page[j] >> PAGE_SHIFT;
+ 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[j] &= PAGE_SIZE - 1;
- page[j] |= mfn_to_pfn_table[mfn] << PAGE_SHIFT;
+ 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;
}
- }
- if ( !checked_write(gfd, page, PAGE_SIZE) )
+
+ }
+ else
{
- ERROR("Error when writing to state file");
- goto out;
+ if ( !checked_write(gfd, region_base + (PAGE_SIZE*j), PAGE_SIZE) )
+ {
+ ERROR("Error when writing to state file");
+ goto out;
+ }
}
}
@@ -450,6 +484,7 @@ 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);
@@ -457,13 +492,6 @@ out:
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);