debuggers.hg

view tools/libxc/xc_linux_restore.c @ 2628:98bdf2c88015

bitkeeper revision 1.1159.1.201 (41600e1fkVMoQU0dVgk1h6vT502hEg)

Merge
author iap10@labyrinth.cl.cam.ac.uk
date Sun Oct 03 14:35:11 2004 +0000 (2004-10-03)
parents 1e99cd1cb3a3 a15ab016f0c6
children e442cedb12d8
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 <asm-xen/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 copy of the domain's name. */
106 char name[MAX_DOMAIN_NAME];
108 /* A table containg the type of each PFN (/not/ MFN!). */
109 unsigned long *pfn_type = NULL;
111 /* A table of MFNs to map in the current region */
112 unsigned long *region_mfn = NULL;
114 /* A temporary mapping, and a copy, of one frame of guest memory. */
115 unsigned long *ppage = NULL;
117 /* A copy of the pfn-to-mfn table frame list. */
118 unsigned long pfn_to_mfn_frame_list[1024];
120 /* A table mapping each PFN to its new MFN. */
121 unsigned long *pfn_to_mfn_table = NULL;
123 /* used by mapper for updating the domain's copy of the table */
124 unsigned long *live_pfn_to_mfn_table = NULL;
126 /* A temporary mapping of the guest's suspend record. */
127 suspend_record_t *p_srec;
129 char *region_base;
131 mmu_t *mmu = NULL;
133 /* used by debug verify code */
134 unsigned long buf[PAGE_SIZE/sizeof(unsigned long)];
136 if ( mlock(&ctxt, sizeof(ctxt) ) )
137 {
138 /* needed for when we do the build dom0 op,
139 but might as well do early */
140 PERROR("Unable to mlock ctxt");
141 return 1;
142 }
144 /* Start reading the saved-domain record. */
145 if ( xcio_read(ioctxt, signature, 16) ||
146 (memcmp(signature, "LinuxGuestRecord", 16) != 0) )
147 {
148 xcio_error(ioctxt, "Unrecognised state format -- no signature found");
149 goto out;
150 }
152 if ( xcio_read(ioctxt, name, sizeof(name)) ||
153 xcio_read(ioctxt, &nr_pfns, sizeof(unsigned long)) ||
154 xcio_read(ioctxt, pfn_to_mfn_frame_list, PAGE_SIZE) )
155 {
156 xcio_error(ioctxt, "Error reading header");
157 goto out;
158 }
160 if ( read_vmconfig(ioctxt) )
161 {
162 xcio_error(ioctxt, "Error writing vmconfig");
163 goto out;
164 }
166 for ( i = 0; i < MAX_DOMAIN_NAME; i++ )
167 {
168 if ( name[i] == '\0' ) break;
169 if ( name[i] & 0x80 )
170 {
171 xcio_error(ioctxt, "Random characters in domain name");
172 goto out;
173 }
174 }
175 name[MAX_DOMAIN_NAME-1] = '\0';
177 if ( nr_pfns > 1024*1024 )
178 {
179 xcio_error(ioctxt, "Invalid state file -- pfn count out of range");
180 goto out;
181 }
183 /* We want zeroed memory so use calloc rather than malloc. */
184 pfn_to_mfn_table = calloc(1, 4 * nr_pfns);
185 pfn_type = calloc(1, 4 * nr_pfns);
186 region_mfn = calloc(1, 4 * MAX_BATCH_SIZE);
188 if ( (pfn_to_mfn_table == NULL) ||
189 (pfn_type == NULL) ||
190 (region_mfn == NULL) )
191 {
192 errno = ENOMEM;
193 goto out;
194 }
196 if ( mlock(region_mfn, 4 * MAX_BATCH_SIZE ) )
197 {
198 xcio_error(ioctxt, "Could not mlock region_mfn");
199 goto out;
200 }
202 #if 0
203 /* Set the domain's name to that from the restore file */
204 if ( xc_domain_setname( xc_handle, dom, name ) )
205 {
206 xcio_error(ioctxt, "Could not set domain name");
207 goto out;
208 }
210 /* Set the domain's initial memory allocation
211 to that from the restore file */
213 if ( xc_domain_setinitialmem(xc_handle, dom,
214 nr_pfns * (PAGE_SIZE / 1024)) )
215 {
216 xcio_error(ioctxt, "Could not set domain %d initial memory. pfns=%d, %dKB",
217 dom, nr_pfns,nr_pfns * (PAGE_SIZE / 1024));
218 goto out;
219 }
220 #endif
223 /* XXX create domain on CPU=-1 so that in future it auto load ballances by default */
224 if ( xc_domain_create( xc_handle, nr_pfns * (PAGE_SIZE / 1024),
225 "", -1, 1, &dom ) )
226 {
227 xcio_error(ioctxt, "Could not create domain. pfns=%d, %dKB",
228 nr_pfns,nr_pfns * (PAGE_SIZE / 1024));
229 goto out;
230 }
232 ioctxt->domain = dom;
233 printf("Created domain %ld\n",dom);
235 /* Get the domain's shared-info frame. */
236 op.cmd = DOM0_GETDOMAININFO;
237 op.u.getdomaininfo.domain = (domid_t)dom;
238 op.u.getdomaininfo.ctxt = NULL;
239 if ( do_dom0_op(xc_handle, &op) < 0 )
240 {
241 xcio_error(ioctxt, "Could not get information on new domain");
242 goto out;
243 }
244 shared_info_frame = op.u.getdomaininfo.shared_info_frame;
246 if(ioctxt->flags & XCFLAGS_CONFIGURE)
247 {
248 if(xcio_configure_domain(ioctxt))
249 {
250 xcio_error(ioctxt, "Configuring domain failed");
251 goto out;
252 }
253 }
255 /* Build the pfn-to-mfn table. We choose MFN ordering returned by Xen. */
256 if ( get_pfn_list(xc_handle, dom, pfn_to_mfn_table, nr_pfns) != nr_pfns )
257 {
258 xcio_error(ioctxt, "Did not read correct number of frame "
259 "numbers for new dom");
260 goto out;
261 }
263 if ( (mmu = init_mmu_updates(xc_handle, dom)) == NULL )
264 {
265 xcio_error(ioctxt, "Could not initialise for MMU updates");
266 goto out;
267 }
269 xcio_info(ioctxt, "Reloading memory pages: 0%%");
271 /*
272 * Now simply read each saved frame into its new machine frame.
273 * We uncanonicalise page tables as we go.
274 */
275 prev_pc = 0;
277 n = 0;
278 while ( 1 )
279 {
280 int j;
281 unsigned long region_pfn_type[MAX_BATCH_SIZE];
283 this_pc = (n * 100) / nr_pfns;
284 if ( (this_pc - prev_pc) >= 5 )
285 {
286 xcio_info(ioctxt, "\b\b\b\b%3d%%", this_pc);
287 prev_pc = this_pc;
288 }
290 if ( xcio_read(ioctxt, &j, sizeof(int)) )
291 {
292 xcio_error(ioctxt, "Error when reading from state file");
293 goto out;
294 }
296 DPRINTF("batch %d\n",j);
298 if ( j == -1 )
299 {
300 verify = 1;
301 printf("Entering page verify mode\n");
302 continue;
303 }
305 if ( j == 0 )
306 break; /* our work here is done */
308 if ( j > MAX_BATCH_SIZE )
309 {
310 xcio_error(ioctxt, "Max batch size exceeded. Giving up.");
311 goto out;
312 }
314 if ( xcio_read(ioctxt, region_pfn_type, j*sizeof(unsigned long)) ) {
315 xcio_error(ioctxt, "Error when reading from state file");
316 goto out;
317 }
319 for ( i = 0; i < j; i++ )
320 {
321 if ( (region_pfn_type[i] & LTAB_MASK) == XTAB)
322 {
323 region_mfn[i] = 0; /* we know map will fail, but don't care */
324 }
325 else
326 {
327 pfn = region_pfn_type[i] & ~LTAB_MASK;
328 region_mfn[i] = pfn_to_mfn_table[pfn];
329 }
330 }
332 if ( (region_base = xc_map_foreign_batch( xc_handle, dom,
333 PROT_WRITE,
334 region_mfn,
335 j )) == 0 )
336 {
337 xcio_error(ioctxt, "map batch failed");
338 goto out;
339 }
341 for ( i = 0; i < j; i++ )
342 {
343 unsigned long *ppage;
345 pfn = region_pfn_type[i] & ~LTAB_MASK;
347 if ( (region_pfn_type[i] & LTAB_MASK) == XTAB) continue;
349 if (pfn>nr_pfns)
350 {
351 xcio_error(ioctxt, "pfn out of range");
352 goto out;
353 }
355 region_pfn_type[i] &= LTAB_MASK;
357 pfn_type[pfn] = region_pfn_type[i];
359 mfn = pfn_to_mfn_table[pfn];
361 if ( verify )
362 ppage = (unsigned long*) buf; /* debug case */
363 else
364 ppage = (unsigned long*) (region_base + i*PAGE_SIZE);
366 if ( xcio_read(ioctxt, ppage, PAGE_SIZE) )
367 {
368 xcio_error(ioctxt, "Error when reading from state file");
369 goto out;
370 }
372 switch( region_pfn_type[i] & LTABTYPE_MASK )
373 {
374 case 0:
375 break;
377 case L1TAB:
378 {
379 for ( k = 0; k < 1024; k++ )
380 {
381 if ( ppage[k] & _PAGE_PRESENT )
382 {
383 xpfn = ppage[k] >> PAGE_SHIFT;
384 if ( xpfn >= nr_pfns )
385 {
386 xcio_error(ioctxt, "Frame number in type %lu page "
387 "table is out of range. i=%d k=%d "
388 "pfn=0x%lx nr_pfns=%lu",
389 region_pfn_type[i]>>28, i,
390 k, xpfn, nr_pfns);
391 goto out;
392 }
394 ppage[k] &= (PAGE_SIZE - 1) &
395 ~(_PAGE_GLOBAL | _PAGE_PAT);
396 ppage[k] |= pfn_to_mfn_table[xpfn] << PAGE_SHIFT;
397 }
398 }
399 }
400 break;
402 case L2TAB:
403 {
404 for ( k = 0;
405 k < (HYPERVISOR_VIRT_START>>L2_PAGETABLE_SHIFT);
406 k++ )
407 {
408 if ( ppage[k] & _PAGE_PRESENT )
409 {
410 xpfn = ppage[k] >> PAGE_SHIFT;
412 if ( xpfn >= nr_pfns )
413 {
414 xcio_error(ioctxt, "Frame number in type %lu page"
415 " table is out of range. i=%d k=%d "
416 "pfn=%lu nr_pfns=%lu",
417 region_pfn_type[i]>>28, i, k,
418 xpfn, nr_pfns);
419 goto out;
420 }
422 ppage[k] &= (PAGE_SIZE - 1) &
423 ~(_PAGE_GLOBAL | _PAGE_PSE);
424 ppage[k] |= pfn_to_mfn_table[xpfn] << PAGE_SHIFT;
425 }
426 }
427 }
428 break;
430 default:
431 xcio_error(ioctxt, "Bogus page type %lx page table is "
432 "out of range. i=%d nr_pfns=%lu",
433 region_pfn_type[i], i, nr_pfns);
434 goto out;
436 } /* end of page type switch statement */
438 if ( verify )
439 {
440 int res = memcmp(buf, (region_base + i*PAGE_SIZE), PAGE_SIZE );
441 if ( res )
442 {
443 int v;
444 printf("************** pfn=%lx type=%lx gotcs=%08lx "
445 "actualcs=%08lx\n", pfn, pfn_type[pfn],
446 csum_page(region_base + i*PAGE_SIZE),
447 csum_page(buf));
448 for ( v = 0; v < 4; v++ )
449 {
450 unsigned long *p = (unsigned long *)
451 (region_base + i*PAGE_SIZE);
452 if ( buf[v] != p[v] )
453 printf(" %d: %08lx %08lx\n",
454 v, buf[v], p[v] );
455 }
456 }
457 }
459 if ( add_mmu_update(xc_handle, mmu,
460 (mfn<<PAGE_SHIFT) | MMU_MACHPHYS_UPDATE, pfn) )
461 {
462 printf("machpys mfn=%ld pfn=%ld\n",mfn,pfn);
463 goto out;
464 }
466 } /* end of 'batch' for loop */
468 munmap( region_base, j*PAGE_SIZE );
469 n+=j; /* crude stats */
470 }
472 DPRINTF("Received all pages\n");
474 /*
475 * Pin page tables. Do this after writing to them as otherwise Xen
476 * will barf when doing the type-checking.
477 */
478 for ( i = 0; i < nr_pfns; i++ )
479 {
480 if ( pfn_type[i] == (L1TAB|LPINTAB) )
481 {
482 if ( add_mmu_update(xc_handle, mmu,
483 (pfn_to_mfn_table[i]<<PAGE_SHIFT) |
484 MMU_EXTENDED_COMMAND,
485 MMUEXT_PIN_L1_TABLE) ) {
486 printf("ERR pin L1 pfn=%lx mfn=%lx\n",
487 (unsigned long)i, pfn_to_mfn_table[i]);
488 goto out;
489 }
490 }
491 }
493 /* must pin all L1's before L2's (need consistent va back ptr) */
494 for ( i = 0; i < nr_pfns; i++ )
495 {
496 if ( pfn_type[i] == (L2TAB|LPINTAB) )
497 {
498 if ( add_mmu_update(xc_handle, mmu,
499 (pfn_to_mfn_table[i]<<PAGE_SHIFT) |
500 MMU_EXTENDED_COMMAND,
501 MMUEXT_PIN_L2_TABLE) )
502 {
503 printf("ERR pin L2 pfn=%lx mfn=%lx\n",
504 (unsigned long)i, pfn_to_mfn_table[i]);
505 goto out;
506 }
507 }
508 }
510 if ( finish_mmu_updates(xc_handle, mmu) ) goto out;
512 xcio_info(ioctxt, "\b\b\b\b100%%\nMemory reloaded.\n");
514 /* Get the list of PFNs that are not in the psuedo-phys map */
515 {
516 unsigned int count, *pfntab;
517 int rc;
519 if ( xcio_read(ioctxt, &count, sizeof(count)) )
520 {
521 xcio_error(ioctxt, "Error when reading from state file");
522 goto out;
523 }
525 pfntab = malloc( sizeof(unsigned int) * count );
526 if ( pfntab == NULL )
527 {
528 xcio_error(ioctxt, "Out of memory");
529 goto out;
530 }
532 if ( xcio_read(ioctxt, pfntab, sizeof(unsigned int)*count) )
533 {
534 xcio_error(ioctxt, "Error when reading pfntab from state file");
535 goto out;
536 }
538 for ( i = 0; i < count; i++ )
539 {
540 unsigned long pfn = pfntab[i];
541 pfntab[i]=pfn_to_mfn_table[pfn];
542 pfn_to_mfn_table[pfn] = 0x80000001; // not in pmap
543 }
545 if ( count > 0 )
546 {
547 if ( (rc = do_dom_mem_op( xc_handle,
548 MEMOP_decrease_reservation,
549 pfntab, count, 0, dom )) <0 )
550 {
551 xcio_error(ioctxt, "Could not decrease reservation : %d",rc);
552 goto out;
553 }
554 else
555 {
556 printf("Decreased reservation by %d pages\n", count);
557 }
558 }
559 }
561 if ( xcio_read(ioctxt, &ctxt, sizeof(ctxt)) ||
562 xcio_read(ioctxt, shared_info, PAGE_SIZE) )
563 {
564 xcio_error(ioctxt, "Error when reading from state file");
565 goto out;
566 }
568 /* Uncanonicalise the suspend-record frame number and poke resume rec. */
569 pfn = ctxt.cpu_ctxt.esi;
570 if ( (pfn >= nr_pfns) || (pfn_type[pfn] != NOTAB) )
571 {
572 xcio_error(ioctxt, "Suspend record frame number is bad");
573 goto out;
574 }
575 ctxt.cpu_ctxt.esi = mfn = pfn_to_mfn_table[pfn];
576 p_srec = xc_map_foreign_range(
577 xc_handle, dom, PAGE_SIZE, PROT_WRITE, mfn);
578 p_srec->resume_info.nr_pages = nr_pfns;
579 p_srec->resume_info.shared_info = shared_info_frame << PAGE_SHIFT;
580 p_srec->resume_info.flags = 0;
581 munmap(p_srec, PAGE_SIZE);
583 /* Uncanonicalise each GDT frame number. */
584 if ( ctxt.gdt_ents > 8192 )
585 {
586 xcio_error(ioctxt, "GDT entry count out of range");
587 goto out;
588 }
590 for ( i = 0; i < ctxt.gdt_ents; i += 512 )
591 {
592 pfn = ctxt.gdt_frames[i];
593 if ( (pfn >= nr_pfns) || (pfn_type[pfn] != NOTAB) )
594 {
595 xcio_error(ioctxt, "GDT frame number is bad");
596 goto out;
597 }
598 ctxt.gdt_frames[i] = pfn_to_mfn_table[pfn];
599 }
601 /* Uncanonicalise the page table base pointer. */
602 pfn = ctxt.pt_base >> PAGE_SHIFT;
603 if ( (pfn >= nr_pfns) || ((pfn_type[pfn]&LTABTYPE_MASK) != L2TAB) )
604 {
605 printf("PT base is bad. pfn=%lu nr=%lu type=%08lx %08lx\n",
606 pfn, nr_pfns, pfn_type[pfn], (unsigned long)L2TAB);
607 xcio_error(ioctxt, "PT base is bad.");
608 goto out;
609 }
610 ctxt.pt_base = pfn_to_mfn_table[pfn] << PAGE_SHIFT;
612 /* clear any pending events and the selector */
613 memset(&(((shared_info_t *)shared_info)->evtchn_pending[0]),
614 0, sizeof (((shared_info_t *)shared_info)->evtchn_pending)+
615 sizeof(((shared_info_t *)shared_info)->evtchn_pending_sel));
617 /* Copy saved contents of shared-info page. No checking needed. */
618 ppage = xc_map_foreign_range(
619 xc_handle, dom, PAGE_SIZE, PROT_WRITE, shared_info_frame);
620 memcpy(ppage, shared_info, sizeof(shared_info_t));
621 munmap(ppage, PAGE_SIZE);
623 /* Uncanonicalise the pfn-to-mfn table frame-number list. */
624 for ( i = 0; i < (nr_pfns+1023)/1024; i++ )
625 {
626 unsigned long pfn, mfn;
628 pfn = pfn_to_mfn_frame_list[i];
629 if ( (pfn >= nr_pfns) || (pfn_type[pfn] != NOTAB) )
630 {
631 xcio_error(ioctxt, "PFN-to-MFN frame number is bad");
632 goto out;
633 }
634 mfn = pfn_to_mfn_table[pfn];
635 pfn_to_mfn_frame_list[i] = mfn;
636 }
638 if ( (live_pfn_to_mfn_table =
639 xc_map_foreign_batch(xc_handle, dom,
640 PROT_WRITE,
641 pfn_to_mfn_frame_list,
642 (nr_pfns+1023)/1024 )) == 0 )
643 {
644 xcio_error(ioctxt, "Couldn't map pfn_to_mfn table");
645 goto out;
646 }
648 memcpy(live_pfn_to_mfn_table, pfn_to_mfn_table,
649 nr_pfns*sizeof(unsigned long) );
651 munmap(live_pfn_to_mfn_table, ((nr_pfns+1023)/1024)*PAGE_SIZE);
653 /*
654 * Safety checking of saved context:
655 * 1. cpu_ctxt is fine, as Xen checks that on context switch.
656 * 2. fpu_ctxt is fine, as it can't hurt Xen.
657 * 3. trap_ctxt needs the code selectors checked.
658 * 4. fast_trap_idx is checked by Xen.
659 * 5. ldt base must be page-aligned, no more than 8192 ents, ...
660 * 6. gdt already done, and further checking is done by Xen.
661 * 7. check that guestos_ss is safe.
662 * 8. pt_base is already done.
663 * 9. debugregs are checked by Xen.
664 * 10. callback code selectors need checking.
665 */
666 for ( i = 0; i < 256; i++ )
667 {
668 ctxt.trap_ctxt[i].vector = i;
669 if ( (ctxt.trap_ctxt[i].cs & 3) == 0 )
670 ctxt.trap_ctxt[i].cs = FLAT_GUESTOS_CS;
671 }
672 if ( (ctxt.guestos_ss & 3) == 0 )
673 ctxt.guestos_ss = FLAT_GUESTOS_DS;
674 if ( (ctxt.event_callback_cs & 3) == 0 )
675 ctxt.event_callback_cs = FLAT_GUESTOS_CS;
676 if ( (ctxt.failsafe_callback_cs & 3) == 0 )
677 ctxt.failsafe_callback_cs = FLAT_GUESTOS_CS;
678 if ( ((ctxt.ldt_base & (PAGE_SIZE - 1)) != 0) ||
679 (ctxt.ldt_ents > 8192) ||
680 (ctxt.ldt_base > HYPERVISOR_VIRT_START) ||
681 ((ctxt.ldt_base + ctxt.ldt_ents*8) > HYPERVISOR_VIRT_START) )
682 {
683 xcio_error(ioctxt, "Bad LDT base or size");
684 goto out;
685 }
687 op.cmd = DOM0_BUILDDOMAIN;
688 op.u.builddomain.domain = (domid_t)dom;
689 op.u.builddomain.ctxt = &ctxt;
690 rc = do_dom0_op(xc_handle, &op);
692 /* don't start the domain as we have console etc to set up */
694 if ( rc == 0 )
695 {
696 /* Success: print the domain id. */
697 xcio_info(ioctxt, "DOM=%lu\n", dom);
698 return 0;
699 }
702 out:
703 if ( (rc != 0) && (dom != 0) )
704 xc_domain_destroy(xc_handle, dom);
705 if ( mmu != NULL )
706 free(mmu);
707 if ( pfn_to_mfn_table != NULL )
708 free(pfn_to_mfn_table);
709 if ( pfn_type != NULL )
710 free(pfn_type);
712 if ( rc == 0 )
713 ioctxt->domain = dom;
715 DPRINTF("Restore exit with rc=%d\n",rc);
716 return rc;
717 }