direct-io.hg

view tools/libxc/xc_linux_restore.c @ 2821:724449a888fe

bitkeeper revision 1.1159.1.332 (41874e954CLIDA2J3phVFD2RnzVTpA)

Clean up public XenLinux header files. Now accessible from userspace as
#include <xen/linux...>
Got rid of the linux-xen-sparse symlink as it's no longer needed.
author kaf24@freefall.cl.cam.ac.uk
date Tue Nov 02 09:08:37 2004 +0000 (2004-11-02)
parents 1511d2acc1a4
children e8a2c91dfc4f 2451944220aa 0dc3b8b8c298
line source
1 /******************************************************************************
2 * xc_linux_restore.c
3 *
4 * Restore the state of a Linux session.
5 *
6 * Copyright (c) 2003, K A Fraser.
7 */
9 #include "xc_private.h"
10 #include <xen/linux/suspend.h>
12 #define MAX_BATCH_SIZE 1024
14 #define DEBUG 0
16 #if DEBUG
17 #define DPRINTF(_f, _a...) printf ( _f , ## _a )
18 #else
19 #define DPRINTF(_f, _a...) ((void)0)
20 #endif
22 static int get_pfn_list(int xc_handle,
23 u32 domain_id,
24 unsigned long *pfn_buf,
25 unsigned long max_pfns)
26 {
27 dom0_op_t op;
28 int ret;
29 op.cmd = DOM0_GETMEMLIST;
30 op.u.getmemlist.domain = (domid_t)domain_id;
31 op.u.getmemlist.max_pfns = max_pfns;
32 op.u.getmemlist.buffer = pfn_buf;
34 if ( mlock(pfn_buf, max_pfns * sizeof(unsigned long)) != 0 )
35 {
36 PERROR("Could not lock pfn list buffer");
37 return -1;
38 }
40 ret = do_dom0_op(xc_handle, &op);
42 (void)munlock(pfn_buf, max_pfns * sizeof(unsigned long));
44 return (ret < 0) ? -1 : op.u.getmemlist.num_pfns;
45 }
47 /** Read the vmconfig string from the state input.
48 * It is stored as a 4-byte count 'n' followed by n bytes.
49 * The config data is stored in a new string in 'ioctxt->vmconfig',
50 * and is null-terminated. The count is stored in 'ioctxt->vmconfig_n'.
51 *
52 * @param ioctxt i/o context
53 * @return 0 on success, non-zero on error.
54 */
55 static int read_vmconfig(XcIOContext *ioctxt)
56 {
57 int err = -1;
59 if ( xcio_read(ioctxt, &ioctxt->vmconfig_n, sizeof(ioctxt->vmconfig_n)) )
60 goto exit;
62 ioctxt->vmconfig = malloc(ioctxt->vmconfig_n + 1);
63 if ( ioctxt->vmconfig == NULL )
64 goto exit;
66 if ( xcio_read(ioctxt, ioctxt->vmconfig, ioctxt->vmconfig_n) )
67 goto exit;
69 ioctxt->vmconfig[ioctxt->vmconfig_n] = '\0';
70 err = 0;
72 exit:
73 if ( err )
74 {
75 if ( ioctxt->vmconfig != NULL )
76 free(ioctxt->vmconfig);
77 ioctxt->vmconfig = NULL;
78 ioctxt->vmconfig_n = 0;
79 }
80 return err;
81 }
83 int xc_linux_restore(int xc_handle, XcIOContext *ioctxt)
84 {
85 dom0_op_t op;
86 int rc = 1, i, n, k;
87 unsigned long mfn, pfn, xpfn;
88 unsigned int prev_pc, this_pc;
89 u32 dom = 0;
90 int verify = 0;
92 /* Number of page frames in use by this Linux session. */
93 unsigned long nr_pfns;
95 /* The new domain's shared-info frame number. */
96 unsigned long shared_info_frame;
97 unsigned char shared_info[PAGE_SIZE]; /* saved contents from file */
99 /* A copy of the CPU context of the guest. */
100 full_execution_context_t ctxt;
102 /* First 16 bytes of the state file must contain 'LinuxGuestRecord'. */
103 char signature[16];
105 /* A table containg the type of each PFN (/not/ MFN!). */
106 unsigned long *pfn_type = NULL;
108 /* A table of MFNs to map in the current region */
109 unsigned long *region_mfn = NULL;
111 /* A temporary mapping, and a copy, of one frame of guest memory. */
112 unsigned long *ppage = NULL;
114 /* A copy of the pfn-to-mfn table frame list. */
115 unsigned long pfn_to_mfn_frame_list[1024];
117 /* A table mapping each PFN to its new MFN. */
118 unsigned long *pfn_to_mfn_table = NULL;
120 /* used by mapper for updating the domain's copy of the table */
121 unsigned long *live_pfn_to_mfn_table = NULL;
123 /* A temporary mapping of the guest's suspend record. */
124 suspend_record_t *p_srec;
126 char *region_base;
128 mmu_t *mmu = NULL;
130 /* used by debug verify code */
131 unsigned long buf[PAGE_SIZE/sizeof(unsigned long)];
133 xcio_info(ioctxt, "xc_linux_restore start\n");
135 if ( mlock(&ctxt, sizeof(ctxt) ) )
136 {
137 /* needed for when we do the build dom0 op,
138 but might as well do early */
139 PERROR("Unable to mlock ctxt");
140 return 1;
141 }
143 /* Start reading the saved-domain record. */
144 if ( xcio_read(ioctxt, signature, 16) ||
145 (memcmp(signature, "LinuxGuestRecord", 16) != 0) )
146 {
147 xcio_error(ioctxt, "Unrecognised state format -- no signature found");
148 goto out;
149 }
151 if ( xcio_read(ioctxt, &nr_pfns, sizeof(unsigned long)) ||
152 xcio_read(ioctxt, pfn_to_mfn_frame_list, PAGE_SIZE) )
153 {
154 xcio_error(ioctxt, "Error reading header");
155 goto out;
156 }
158 if ( read_vmconfig(ioctxt) )
159 {
160 xcio_error(ioctxt, "Error writing vmconfig");
161 goto out;
162 }
164 if ( nr_pfns > 1024*1024 )
165 {
166 xcio_error(ioctxt, "Invalid state file -- pfn count out of range");
167 goto out;
168 }
170 /* We want zeroed memory so use calloc rather than malloc. */
171 pfn_to_mfn_table = calloc(1, 4 * nr_pfns);
172 pfn_type = calloc(1, 4 * nr_pfns);
173 region_mfn = calloc(1, 4 * MAX_BATCH_SIZE);
175 if ( (pfn_to_mfn_table == NULL) ||
176 (pfn_type == NULL) ||
177 (region_mfn == NULL) )
178 {
179 errno = ENOMEM;
180 goto out;
181 }
183 if ( mlock(region_mfn, 4 * MAX_BATCH_SIZE ) )
184 {
185 xcio_error(ioctxt, "Could not mlock region_mfn");
186 goto out;
187 }
189 /* Create domain on CPU -1 so that it may auto load-balance in future. */
190 if ( xc_domain_create(xc_handle, nr_pfns * (PAGE_SIZE / 1024),
191 -1, 1, &dom) )
192 {
193 xcio_error(ioctxt, "Could not create domain. pfns=%d, %dKB",
194 nr_pfns,nr_pfns * (PAGE_SIZE / 1024));
195 goto out;
196 }
198 ioctxt->domain = dom;
199 xcio_info(ioctxt, "Created domain %ld\n",dom);
201 /* Get the domain's shared-info frame. */
202 op.cmd = DOM0_GETDOMAININFO;
203 op.u.getdomaininfo.domain = (domid_t)dom;
204 op.u.getdomaininfo.ctxt = NULL;
205 if ( do_dom0_op(xc_handle, &op) < 0 )
206 {
207 xcio_error(ioctxt, "Could not get information on new domain");
208 goto out;
209 }
210 shared_info_frame = op.u.getdomaininfo.shared_info_frame;
212 if(ioctxt->flags & XCFLAGS_CONFIGURE)
213 {
214 if(xcio_configure_domain(ioctxt))
215 {
216 xcio_error(ioctxt, "Configuring domain failed");
217 goto out;
218 }
219 }
221 /* Build the pfn-to-mfn table. We choose MFN ordering returned by Xen. */
222 if ( get_pfn_list(xc_handle, dom, pfn_to_mfn_table, nr_pfns) != nr_pfns )
223 {
224 xcio_error(ioctxt, "Did not read correct number of frame "
225 "numbers for new dom");
226 goto out;
227 }
229 if ( (mmu = init_mmu_updates(xc_handle, dom)) == NULL )
230 {
231 xcio_error(ioctxt, "Could not initialise for MMU updates");
232 goto out;
233 }
235 xcio_info(ioctxt, "Reloading memory pages: 0%%");
237 /*
238 * Now simply read each saved frame into its new machine frame.
239 * We uncanonicalise page tables as we go.
240 */
241 prev_pc = 0;
243 n = 0;
244 while ( 1 )
245 {
246 int j;
247 unsigned long region_pfn_type[MAX_BATCH_SIZE];
249 this_pc = (n * 100) / nr_pfns;
250 if ( (this_pc - prev_pc) >= 5 )
251 {
252 xcio_info(ioctxt, "\b\b\b\b%3d%%", this_pc);
253 prev_pc = this_pc;
254 }
256 if ( xcio_read(ioctxt, &j, sizeof(int)) )
257 {
258 xcio_error(ioctxt, "Error when reading from state file");
259 goto out;
260 }
262 DPRINTF("batch %d\n",j);
264 if ( j == -1 )
265 {
266 verify = 1;
267 printf("Entering page verify mode\n");
268 continue;
269 }
271 if ( j == 0 )
272 break; /* our work here is done */
274 if ( j > MAX_BATCH_SIZE )
275 {
276 xcio_error(ioctxt, "Max batch size exceeded. Giving up.");
277 goto out;
278 }
280 if ( xcio_read(ioctxt, region_pfn_type, j*sizeof(unsigned long)) ) {
281 xcio_error(ioctxt, "Error when reading from state file");
282 goto out;
283 }
285 for ( i = 0; i < j; i++ )
286 {
287 if ( (region_pfn_type[i] & LTAB_MASK) == XTAB)
288 {
289 region_mfn[i] = 0; /* we know map will fail, but don't care */
290 }
291 else
292 {
293 pfn = region_pfn_type[i] & ~LTAB_MASK;
294 region_mfn[i] = pfn_to_mfn_table[pfn];
295 }
296 }
298 if ( (region_base = xc_map_foreign_batch( xc_handle, dom,
299 PROT_WRITE,
300 region_mfn,
301 j )) == 0 )
302 {
303 xcio_error(ioctxt, "map batch failed");
304 goto out;
305 }
307 for ( i = 0; i < j; i++ )
308 {
309 unsigned long *ppage;
311 pfn = region_pfn_type[i] & ~LTAB_MASK;
313 if ( (region_pfn_type[i] & LTAB_MASK) == XTAB) continue;
315 if (pfn>nr_pfns)
316 {
317 xcio_error(ioctxt, "pfn out of range");
318 goto out;
319 }
321 region_pfn_type[i] &= LTAB_MASK;
323 pfn_type[pfn] = region_pfn_type[i];
325 mfn = pfn_to_mfn_table[pfn];
327 if ( verify )
328 ppage = (unsigned long*) buf; /* debug case */
329 else
330 ppage = (unsigned long*) (region_base + i*PAGE_SIZE);
332 if ( xcio_read(ioctxt, ppage, PAGE_SIZE) )
333 {
334 xcio_error(ioctxt, "Error when reading from state file");
335 goto out;
336 }
338 switch( region_pfn_type[i] & LTABTYPE_MASK )
339 {
340 case 0:
341 break;
343 case L1TAB:
344 {
345 for ( k = 0; k < 1024; k++ )
346 {
347 if ( ppage[k] & _PAGE_PRESENT )
348 {
349 xpfn = ppage[k] >> PAGE_SHIFT;
350 if ( xpfn >= nr_pfns )
351 {
352 xcio_error(ioctxt, "Frame number in type %lu page "
353 "table is out of range. i=%d k=%d "
354 "pfn=0x%lx nr_pfns=%lu",
355 region_pfn_type[i]>>28, i,
356 k, xpfn, nr_pfns);
357 goto out;
358 }
360 ppage[k] &= (PAGE_SIZE - 1) &
361 ~(_PAGE_GLOBAL | _PAGE_PAT);
362 ppage[k] |= pfn_to_mfn_table[xpfn] << PAGE_SHIFT;
363 }
364 }
365 }
366 break;
368 case L2TAB:
369 {
370 for ( k = 0;
371 k < (HYPERVISOR_VIRT_START>>L2_PAGETABLE_SHIFT);
372 k++ )
373 {
374 if ( ppage[k] & _PAGE_PRESENT )
375 {
376 xpfn = ppage[k] >> PAGE_SHIFT;
378 if ( xpfn >= nr_pfns )
379 {
380 xcio_error(ioctxt, "Frame number in type %lu page"
381 " table is out of range. i=%d k=%d "
382 "pfn=%lu nr_pfns=%lu",
383 region_pfn_type[i]>>28, i, k,
384 xpfn, nr_pfns);
385 goto out;
386 }
388 ppage[k] &= (PAGE_SIZE - 1) &
389 ~(_PAGE_GLOBAL | _PAGE_PSE);
390 ppage[k] |= pfn_to_mfn_table[xpfn] << PAGE_SHIFT;
391 }
392 }
393 }
394 break;
396 default:
397 xcio_error(ioctxt, "Bogus page type %lx page table is "
398 "out of range. i=%d nr_pfns=%lu",
399 region_pfn_type[i], i, nr_pfns);
400 goto out;
402 } /* end of page type switch statement */
404 if ( verify )
405 {
406 int res = memcmp(buf, (region_base + i*PAGE_SIZE), PAGE_SIZE );
407 if ( res )
408 {
409 int v;
410 printf("************** pfn=%lx type=%lx gotcs=%08lx "
411 "actualcs=%08lx\n", pfn, pfn_type[pfn],
412 csum_page(region_base + i*PAGE_SIZE),
413 csum_page(buf));
414 for ( v = 0; v < 4; v++ )
415 {
416 unsigned long *p = (unsigned long *)
417 (region_base + i*PAGE_SIZE);
418 if ( buf[v] != p[v] )
419 printf(" %d: %08lx %08lx\n",
420 v, buf[v], p[v] );
421 }
422 }
423 }
425 if ( add_mmu_update(xc_handle, mmu,
426 (mfn<<PAGE_SHIFT) | MMU_MACHPHYS_UPDATE, pfn) )
427 {
428 printf("machpys mfn=%ld pfn=%ld\n",mfn,pfn);
429 goto out;
430 }
432 } /* end of 'batch' for loop */
434 munmap( region_base, j*PAGE_SIZE );
435 n+=j; /* crude stats */
436 }
438 xcio_info(ioctxt, "Received all pages\n");
440 /*
441 * Pin page tables. Do this after writing to them as otherwise Xen
442 * will barf when doing the type-checking.
443 */
444 for ( i = 0; i < nr_pfns; i++ )
445 {
446 if ( pfn_type[i] == (L1TAB|LPINTAB) )
447 {
448 if ( add_mmu_update(xc_handle, mmu,
449 (pfn_to_mfn_table[i]<<PAGE_SHIFT) |
450 MMU_EXTENDED_COMMAND,
451 MMUEXT_PIN_L1_TABLE) ) {
452 printf("ERR pin L1 pfn=%lx mfn=%lx\n",
453 (unsigned long)i, pfn_to_mfn_table[i]);
454 goto out;
455 }
456 }
457 }
459 /* must pin all L1's before L2's (need consistent va back ptr) */
460 for ( i = 0; i < nr_pfns; i++ )
461 {
462 if ( pfn_type[i] == (L2TAB|LPINTAB) )
463 {
464 if ( add_mmu_update(xc_handle, mmu,
465 (pfn_to_mfn_table[i]<<PAGE_SHIFT) |
466 MMU_EXTENDED_COMMAND,
467 MMUEXT_PIN_L2_TABLE) )
468 {
469 printf("ERR pin L2 pfn=%lx mfn=%lx\n",
470 (unsigned long)i, pfn_to_mfn_table[i]);
471 goto out;
472 }
473 }
474 }
476 if ( finish_mmu_updates(xc_handle, mmu) ) goto out;
478 xcio_info(ioctxt, "\b\b\b\b100%%\n");
479 xcio_info(ioctxt, "Memory reloaded.\n");
481 /* Get the list of PFNs that are not in the psuedo-phys map */
482 {
483 unsigned int count, *pfntab;
484 int rc;
486 if ( xcio_read(ioctxt, &count, sizeof(count)) )
487 {
488 xcio_error(ioctxt, "Error when reading from state file");
489 goto out;
490 }
492 pfntab = malloc( sizeof(unsigned int) * count );
493 if ( pfntab == NULL )
494 {
495 xcio_error(ioctxt, "Out of memory");
496 goto out;
497 }
499 if ( xcio_read(ioctxt, pfntab, sizeof(unsigned int)*count) )
500 {
501 xcio_error(ioctxt, "Error when reading pfntab from state file");
502 goto out;
503 }
505 for ( i = 0; i < count; i++ )
506 {
507 unsigned long pfn = pfntab[i];
508 pfntab[i]=pfn_to_mfn_table[pfn];
509 pfn_to_mfn_table[pfn] = 0x80000001; // not in pmap
510 }
512 if ( count > 0 )
513 {
514 if ( (rc = do_dom_mem_op( xc_handle,
515 MEMOP_decrease_reservation,
516 pfntab, count, 0, dom )) <0 )
517 {
518 xcio_error(ioctxt, "Could not decrease reservation : %d",rc);
519 goto out;
520 }
521 else
522 {
523 printf("Decreased reservation by %d pages\n", count);
524 }
525 }
526 }
528 if ( xcio_read(ioctxt, &ctxt, sizeof(ctxt)) ||
529 xcio_read(ioctxt, shared_info, PAGE_SIZE) )
530 {
531 xcio_error(ioctxt, "Error when reading from state file");
532 goto out;
533 }
535 /* Uncanonicalise the suspend-record frame number and poke resume rec. */
536 pfn = ctxt.cpu_ctxt.esi;
537 if ( (pfn >= nr_pfns) || (pfn_type[pfn] != NOTAB) )
538 {
539 xcio_error(ioctxt, "Suspend record frame number is bad");
540 goto out;
541 }
542 ctxt.cpu_ctxt.esi = mfn = pfn_to_mfn_table[pfn];
543 p_srec = xc_map_foreign_range(
544 xc_handle, dom, PAGE_SIZE, PROT_WRITE, mfn);
545 p_srec->resume_info.nr_pages = nr_pfns;
546 p_srec->resume_info.shared_info = shared_info_frame << PAGE_SHIFT;
547 p_srec->resume_info.flags = 0;
548 munmap(p_srec, PAGE_SIZE);
550 /* Uncanonicalise each GDT frame number. */
551 if ( ctxt.gdt_ents > 8192 )
552 {
553 xcio_error(ioctxt, "GDT entry count out of range");
554 goto out;
555 }
557 for ( i = 0; i < ctxt.gdt_ents; i += 512 )
558 {
559 pfn = ctxt.gdt_frames[i];
560 if ( (pfn >= nr_pfns) || (pfn_type[pfn] != NOTAB) )
561 {
562 xcio_error(ioctxt, "GDT frame number is bad");
563 goto out;
564 }
565 ctxt.gdt_frames[i] = pfn_to_mfn_table[pfn];
566 }
568 /* Uncanonicalise the page table base pointer. */
569 pfn = ctxt.pt_base >> PAGE_SHIFT;
570 if ( (pfn >= nr_pfns) || ((pfn_type[pfn]&LTABTYPE_MASK) != L2TAB) )
571 {
572 printf("PT base is bad. pfn=%lu nr=%lu type=%08lx %08lx\n",
573 pfn, nr_pfns, pfn_type[pfn], (unsigned long)L2TAB);
574 xcio_error(ioctxt, "PT base is bad.");
575 goto out;
576 }
577 ctxt.pt_base = pfn_to_mfn_table[pfn] << PAGE_SHIFT;
579 /* clear any pending events and the selector */
580 memset(&(((shared_info_t *)shared_info)->evtchn_pending[0]),
581 0, sizeof (((shared_info_t *)shared_info)->evtchn_pending)+
582 sizeof(((shared_info_t *)shared_info)->evtchn_pending_sel));
584 /* Copy saved contents of shared-info page. No checking needed. */
585 ppage = xc_map_foreign_range(
586 xc_handle, dom, PAGE_SIZE, PROT_WRITE, shared_info_frame);
587 memcpy(ppage, shared_info, sizeof(shared_info_t));
588 munmap(ppage, PAGE_SIZE);
590 /* Uncanonicalise the pfn-to-mfn table frame-number list. */
591 for ( i = 0; i < (nr_pfns+1023)/1024; i++ )
592 {
593 unsigned long pfn, mfn;
595 pfn = pfn_to_mfn_frame_list[i];
596 if ( (pfn >= nr_pfns) || (pfn_type[pfn] != NOTAB) )
597 {
598 xcio_error(ioctxt, "PFN-to-MFN frame number is bad");
599 goto out;
600 }
601 mfn = pfn_to_mfn_table[pfn];
602 pfn_to_mfn_frame_list[i] = mfn;
603 }
605 if ( (live_pfn_to_mfn_table =
606 xc_map_foreign_batch(xc_handle, dom,
607 PROT_WRITE,
608 pfn_to_mfn_frame_list,
609 (nr_pfns+1023)/1024 )) == 0 )
610 {
611 xcio_error(ioctxt, "Couldn't map pfn_to_mfn table");
612 goto out;
613 }
615 memcpy(live_pfn_to_mfn_table, pfn_to_mfn_table,
616 nr_pfns*sizeof(unsigned long) );
618 munmap(live_pfn_to_mfn_table, ((nr_pfns+1023)/1024)*PAGE_SIZE);
620 /*
621 * Safety checking of saved context:
622 * 1. cpu_ctxt is fine, as Xen checks that on context switch.
623 * 2. fpu_ctxt is fine, as it can't hurt Xen.
624 * 3. trap_ctxt needs the code selectors checked.
625 * 4. fast_trap_idx is checked by Xen.
626 * 5. ldt base must be page-aligned, no more than 8192 ents, ...
627 * 6. gdt already done, and further checking is done by Xen.
628 * 7. check that guestos_ss is safe.
629 * 8. pt_base is already done.
630 * 9. debugregs are checked by Xen.
631 * 10. callback code selectors need checking.
632 */
633 for ( i = 0; i < 256; i++ )
634 {
635 ctxt.trap_ctxt[i].vector = i;
636 if ( (ctxt.trap_ctxt[i].cs & 3) == 0 )
637 ctxt.trap_ctxt[i].cs = FLAT_GUESTOS_CS;
638 }
639 if ( (ctxt.guestos_ss & 3) == 0 )
640 ctxt.guestos_ss = FLAT_GUESTOS_DS;
641 if ( (ctxt.event_callback_cs & 3) == 0 )
642 ctxt.event_callback_cs = FLAT_GUESTOS_CS;
643 if ( (ctxt.failsafe_callback_cs & 3) == 0 )
644 ctxt.failsafe_callback_cs = FLAT_GUESTOS_CS;
645 if ( ((ctxt.ldt_base & (PAGE_SIZE - 1)) != 0) ||
646 (ctxt.ldt_ents > 8192) ||
647 (ctxt.ldt_base > HYPERVISOR_VIRT_START) ||
648 ((ctxt.ldt_base + ctxt.ldt_ents*8) > HYPERVISOR_VIRT_START) )
649 {
650 xcio_error(ioctxt, "Bad LDT base or size");
651 goto out;
652 }
654 xcio_info(ioctxt, "Domain ready to be built.\n");
656 op.cmd = DOM0_BUILDDOMAIN;
657 op.u.builddomain.domain = (domid_t)dom;
658 op.u.builddomain.ctxt = &ctxt;
659 rc = do_dom0_op(xc_handle, &op);
661 if ( rc != 0 )
662 {
663 xcio_error(ioctxt, "Couldn't build the domain");
664 goto out;
665 }
667 if ( ioctxt->flags & XCFLAGS_CONFIGURE )
668 {
669 xcio_info(ioctxt, "Domain ready to be unpaused\n");
670 op.cmd = DOM0_UNPAUSEDOMAIN;
671 op.u.unpausedomain.domain = (domid_t)dom;
672 rc = do_dom0_op(xc_handle, &op);
673 }
675 if ( rc == 0 )
676 {
677 /* Success: print the domain id. */
678 xcio_info(ioctxt, "DOM=%lu\n", dom);
679 return 0;
680 }
683 out:
684 if ( (rc != 0) && (dom != 0) )
685 xc_domain_destroy(xc_handle, dom);
686 if ( mmu != NULL )
687 free(mmu);
688 if ( pfn_to_mfn_table != NULL )
689 free(pfn_to_mfn_table);
690 if ( pfn_type != NULL )
691 free(pfn_type);
693 if ( rc == 0 )
694 ioctxt->domain = dom;
696 DPRINTF("Restore exit with rc=%d\n",rc);
697 return rc;
698 }