debuggers.hg

view tools/libxc/ia64/xc_ia64_linux_restore.c @ 0:7d21f7218375

Exact replica of unstable on 051908 + README-this
author Mukesh Rathor
date Mon May 19 15:34:57 2008 -0700 (2008-05-19)
parents
children 5c0bf00e371d
line source
1 /******************************************************************************
2 * xc_ia64_linux_restore.c
3 *
4 * Restore the state of a Linux session.
5 *
6 * Copyright (c) 2003, K A Fraser.
7 * Rewritten for ia64 by Tristan Gingold <tristan.gingold@bull.net>
8 *
9 * Copyright (c) 2007 Isaku Yamahata <yamahata@valinux.co.jp>
10 * Use foreign p2m exposure.
11 * VTi domain support
12 */
14 #include <stdlib.h>
15 #include <unistd.h>
17 #include "xg_private.h"
18 #include "xc_ia64_save_restore.h"
19 #include "xc_ia64.h"
20 #include "xc_efi.h"
21 #include "xen/hvm/params.h"
23 #define PFN_TO_KB(_pfn) ((_pfn) << (PAGE_SHIFT - 10))
25 /* number of pfns this guest has (i.e. number of entries in the P2M) */
26 static unsigned long p2m_size;
28 /* number of 'in use' pfns in the guest (i.e. #P2M entries with a valid mfn) */
29 static unsigned long nr_pfns;
31 static int
32 populate_page_if_necessary(int xc_handle, uint32_t dom, unsigned long gmfn,
33 struct xen_ia64_p2m_table *p2m_table)
34 {
35 if (xc_ia64_p2m_present(p2m_table, gmfn))
36 return 0;
38 return xc_domain_memory_populate_physmap(xc_handle, dom, 1, 0, 0, &gmfn);
39 }
41 static int
42 read_page(int xc_handle, int io_fd, uint32_t dom, unsigned long pfn)
43 {
44 void *mem;
46 mem = xc_map_foreign_range(xc_handle, dom, PAGE_SIZE,
47 PROT_READ|PROT_WRITE, pfn);
48 if (mem == NULL) {
49 ERROR("cannot map page");
50 return -1;
51 }
52 if (read_exact(io_fd, mem, PAGE_SIZE)) {
53 ERROR("Error when reading from state file (5)");
54 munmap(mem, PAGE_SIZE);
55 return -1;
56 }
57 munmap(mem, PAGE_SIZE);
58 return 0;
59 }
61 /*
62 * Get the list of PFNs that are not in the psuedo-phys map.
63 * Although we allocate pages on demand, balloon driver may
64 * decreased simaltenously. So we have to free the freed
65 * pages here.
66 */
67 static int
68 xc_ia64_recv_unallocated_list(int xc_handle, int io_fd, uint32_t dom,
69 struct xen_ia64_p2m_table *p2m_table)
70 {
71 int rc = -1;
72 unsigned int i;
73 unsigned int count;
74 unsigned long *pfntab = NULL;
75 unsigned int nr_frees;
77 if (read_exact(io_fd, &count, sizeof(count))) {
78 ERROR("Error when reading pfn count");
79 goto out;
80 }
82 pfntab = malloc(sizeof(unsigned long) * count);
83 if (pfntab == NULL) {
84 ERROR("Out of memory");
85 goto out;
86 }
88 if (read_exact(io_fd, pfntab, sizeof(unsigned long)*count)) {
89 ERROR("Error when reading pfntab");
90 goto out;
91 }
93 nr_frees = 0;
94 for (i = 0; i < count; i++) {
95 if (xc_ia64_p2m_allocated(p2m_table, pfntab[i])) {
96 pfntab[nr_frees] = pfntab[i];
97 nr_frees++;
98 }
99 }
100 if (nr_frees > 0) {
101 if (xc_domain_memory_decrease_reservation(xc_handle, dom, nr_frees,
102 0, pfntab) < 0) {
103 PERROR("Could not decrease reservation");
104 goto out;
105 } else
106 DPRINTF("Decreased reservation by %d / %d pages\n",
107 nr_frees, count);
108 }
110 rc = 0;
112 out:
113 if (pfntab != NULL)
114 free(pfntab);
115 return rc;
116 }
118 static int
119 xc_ia64_recv_vcpu_context(int xc_handle, int io_fd, uint32_t dom,
120 uint32_t vcpu, vcpu_guest_context_t *ctxt)
121 {
122 if (read_exact(io_fd, ctxt, sizeof(*ctxt))) {
123 ERROR("Error when reading ctxt");
124 return -1;
125 }
127 fprintf(stderr, "ip=%016lx, b0=%016lx\n", ctxt->regs.ip, ctxt->regs.b[0]);
129 /* Initialize and set registers. */
130 ctxt->flags = VGCF_EXTRA_REGS | VGCF_SET_CR_IRR;
131 if (xc_vcpu_setcontext(xc_handle, dom, vcpu, ctxt) != 0) {
132 ERROR("Couldn't set vcpu context");
133 return -1;
134 }
136 /* Just a check. */
137 ctxt->flags = 0;
138 if (xc_vcpu_getcontext(xc_handle, dom, vcpu, ctxt)) {
139 ERROR("Could not get vcpu context");
140 return -1;
141 }
143 return 0;
144 }
146 /* Read shared info. */
147 static int
148 xc_ia64_recv_shared_info(int xc_handle, int io_fd, uint32_t dom,
149 unsigned long shared_info_frame,
150 unsigned long *start_info_pfn)
151 {
152 unsigned int i;
154 /* The new domain's shared-info frame. */
155 shared_info_t *shared_info;
157 /* Read shared info. */
158 shared_info = xc_map_foreign_range(xc_handle, dom, PAGE_SIZE,
159 PROT_READ|PROT_WRITE,
160 shared_info_frame);
161 if (shared_info == NULL) {
162 ERROR("cannot map page");
163 return -1;
164 }
166 if (read_exact(io_fd, shared_info, PAGE_SIZE)) {
167 ERROR("Error when reading shared_info page");
168 munmap(shared_info, PAGE_SIZE);
169 return -1;
170 }
172 /* clear any pending events and the selector */
173 memset(&(shared_info->evtchn_pending[0]), 0,
174 sizeof (shared_info->evtchn_pending));
175 for (i = 0; i < MAX_VIRT_CPUS; i++)
176 shared_info->vcpu_info[i].evtchn_pending_sel = 0;
178 if (start_info_pfn != NULL)
179 *start_info_pfn = shared_info->arch.start_info_pfn;
181 munmap (shared_info, PAGE_SIZE);
183 return 0;
184 }
186 static int
187 xc_ia64_pv_recv_context(int xc_handle, int io_fd, uint32_t dom,
188 unsigned long shared_info_frame,
189 struct xen_ia64_p2m_table *p2m_table,
190 unsigned int store_evtchn, unsigned long *store_mfn,
191 unsigned int console_evtchn,
192 unsigned long *console_mfn)
193 {
194 int rc = -1;
195 unsigned long gmfn;
197 /* A copy of the CPU context of the guest. */
198 vcpu_guest_context_t ctxt;
200 /* A temporary mapping of the guest's start_info page. */
201 start_info_t *start_info;
203 if (lock_pages(&ctxt, sizeof(ctxt))) {
204 /* needed for build domctl, but might as well do early */
205 ERROR("Unable to lock_pages ctxt");
206 return -1;
207 }
209 if (xc_ia64_recv_vcpu_context(xc_handle, io_fd, dom, 0, &ctxt))
210 goto out;
212 /* Then get privreg page. */
213 if (read_page(xc_handle, io_fd, dom, ctxt.privregs_pfn) < 0) {
214 ERROR("Could not read vcpu privregs");
215 goto out;
216 }
218 /* Read shared info. */
219 if (xc_ia64_recv_shared_info(xc_handle, io_fd, dom,
220 shared_info_frame, &gmfn))
221 goto out;
223 /* Uncanonicalise the suspend-record frame number and poke resume rec. */
224 if (populate_page_if_necessary(xc_handle, dom, gmfn, p2m_table)) {
225 ERROR("cannot populate page 0x%lx", gmfn);
226 goto out;
227 }
228 start_info = xc_map_foreign_range(xc_handle, dom, PAGE_SIZE,
229 PROT_READ | PROT_WRITE, gmfn);
230 if (start_info == NULL) {
231 ERROR("cannot map start_info page");
232 goto out;
233 }
234 start_info->nr_pages = p2m_size;
235 start_info->shared_info = shared_info_frame << PAGE_SHIFT;
236 start_info->flags = 0;
237 *store_mfn = start_info->store_mfn;
238 start_info->store_evtchn = store_evtchn;
239 *console_mfn = start_info->console.domU.mfn;
240 start_info->console.domU.evtchn = console_evtchn;
241 munmap(start_info, PAGE_SIZE);
243 rc = 0;
245 out:
246 unlock_pages(&ctxt, sizeof(ctxt));
247 return rc;
248 }
250 static int
251 xc_ia64_hvm_recv_context(int xc_handle, int io_fd, uint32_t dom,
252 unsigned long shared_info_frame,
253 struct xen_ia64_p2m_table *p2m_table,
254 unsigned int store_evtchn, unsigned long *store_mfn,
255 unsigned int console_evtchn,
256 unsigned long *console_mfn)
257 {
258 int rc = -1;
259 xc_dominfo_t info;
260 unsigned int i;
262 /* cpu */
263 uint64_t max_virt_cpus;
264 unsigned long vcpumap_size;
265 uint64_t *vcpumap = NULL;
267 /* HVM: magic frames for ioreqs and xenstore comms */
268 const int hvm_params[] = {
269 HVM_PARAM_STORE_PFN,
270 HVM_PARAM_IOREQ_PFN,
271 HVM_PARAM_BUFIOREQ_PFN,
272 HVM_PARAM_BUFPIOREQ_PFN,
273 };
274 const int NR_PARAMS = sizeof(hvm_params) / sizeof(hvm_params[0]);
275 /* ioreq_pfn, bufioreq_pfn, store_pfn */
276 uint64_t magic_pfns[NR_PARAMS];
278 /* HVM: a buffer for holding HVM contxt */
279 uint64_t rec_size = 0;
280 uint8_t *hvm_buf = NULL;
282 /* Read shared info. */
283 if (xc_ia64_recv_shared_info(xc_handle, io_fd, dom, shared_info_frame,
284 NULL))
285 goto out;
287 /* vcpu map */
288 if (xc_domain_getinfo(xc_handle, dom, 1, &info) != 1) {
289 ERROR("Could not get domain info");
290 goto out;
291 }
292 if (read_exact(io_fd, &max_virt_cpus, sizeof(max_virt_cpus))) {
293 ERROR("error reading max_virt_cpus");
294 goto out;
295 }
296 if (max_virt_cpus < info.max_vcpu_id) {
297 ERROR("too large max_virt_cpus %i < %i\n",
298 max_virt_cpus, info.max_vcpu_id);
299 goto out;
300 }
301 vcpumap_size = (max_virt_cpus + 1 + sizeof(vcpumap[0]) - 1) /
302 sizeof(vcpumap[0]);
303 vcpumap = malloc(vcpumap_size);
304 if (vcpumap == NULL) {
305 ERROR("memory alloc for vcpumap");
306 goto out;
307 }
308 memset(vcpumap, 0, vcpumap_size);
309 if (read_exact(io_fd, vcpumap, vcpumap_size)) {
310 ERROR("read vcpumap");
311 goto out;
312 }
314 /* vcpu context */
315 for (i = 0; i <= info.max_vcpu_id; i++) {
316 /* A copy of the CPU context of the guest. */
317 vcpu_guest_context_t ctxt;
319 if (!__test_bit(i, vcpumap))
320 continue;
322 if (xc_ia64_recv_vcpu_context(xc_handle, io_fd, dom, i, &ctxt))
323 goto out;
325 // system context of vcpu is recieved as hvm context.
326 }
328 /* Set HVM-specific parameters */
329 if (read_exact(io_fd, magic_pfns, sizeof(magic_pfns))) {
330 ERROR("error reading magic page addresses");
331 goto out;
332 }
334 /* These comms pages need to be zeroed at the start of day */
335 for (i = 0; i < NR_PARAMS; i++) {
336 rc = xc_clear_domain_page(xc_handle, dom, magic_pfns[i]);
337 if (rc != 0) {
338 ERROR("error zeroing magic pages: %i", rc);
339 goto out;
340 }
341 rc = xc_set_hvm_param(xc_handle, dom, hvm_params[i], magic_pfns[i]);
342 if (rc != 0) {
343 ERROR("error setting HVM params: %i", rc);
344 goto out;
345 }
346 }
347 rc = xc_set_hvm_param(xc_handle, dom,
348 HVM_PARAM_STORE_EVTCHN, store_evtchn);
349 if (rc != 0) {
350 ERROR("error setting HVM params: %i", rc);
351 goto out;
352 }
353 *store_mfn = magic_pfns[0];
355 /* Read HVM context */
356 if (read_exact(io_fd, &rec_size, sizeof(rec_size))) {
357 ERROR("error read hvm context size!\n");
358 goto out;
359 }
361 hvm_buf = malloc(rec_size);
362 if (hvm_buf == NULL) {
363 ERROR("memory alloc for hvm context buffer failed");
364 errno = ENOMEM;
365 goto out;
366 }
368 if (read_exact(io_fd, hvm_buf, rec_size)) {
369 ERROR("error loading the HVM context");
370 goto out;
371 }
373 rc = xc_domain_hvm_setcontext(xc_handle, dom, hvm_buf, rec_size);
374 if (rc != 0) {
375 ERROR("error setting the HVM context");
376 goto out;
377 }
379 rc = 0;
381 out:
382 if (vcpumap != NULL)
383 free(vcpumap);
384 if (hvm_buf != NULL)
385 free(hvm_buf);
386 return rc;
387 }
389 /*
390 * hvm domain requires IO pages allocated when XEN_DOMCTL_arch_setup
391 */
392 static int
393 xc_ia64_hvm_domain_setup(int xc_handle, uint32_t dom)
394 {
395 int rc;
396 xen_pfn_t pfn_list[] = {
397 IO_PAGE_START >> PAGE_SHIFT,
398 BUFFER_IO_PAGE_START >> PAGE_SHIFT,
399 BUFFER_PIO_PAGE_START >> PAGE_SHIFT,
400 };
401 unsigned long nr_pages = sizeof(pfn_list) / sizeof(pfn_list[0]);
403 rc = xc_domain_memory_populate_physmap(xc_handle, dom, nr_pages,
404 0, 0, &pfn_list[0]);
405 if (rc != 0)
406 PERROR("Could not allocate IO page or buffer io page.\n");
407 return rc;
408 }
410 int
411 xc_domain_restore(int xc_handle, int io_fd, uint32_t dom,
412 unsigned int store_evtchn, unsigned long *store_mfn,
413 unsigned int console_evtchn, unsigned long *console_mfn,
414 unsigned int hvm, unsigned int pae)
415 {
416 DECLARE_DOMCTL;
417 int rc = 1;
418 unsigned long ver;
420 /* The new domain's shared-info frame number. */
421 unsigned long shared_info_frame;
423 struct xen_ia64_p2m_table p2m_table;
424 xc_ia64_p2m_init(&p2m_table);
426 /* For info only */
427 nr_pfns = 0;
429 if ( read_exact(io_fd, &p2m_size, sizeof(unsigned long)) )
430 {
431 ERROR("read: p2m_size");
432 goto out;
433 }
434 DPRINTF("xc_linux_restore start: p2m_size = %lx\n", p2m_size);
436 if (read_exact(io_fd, &ver, sizeof(unsigned long))) {
437 ERROR("Error when reading version");
438 goto out;
439 }
440 if (ver != XC_IA64_SR_FORMAT_VER_ONE && ver != XC_IA64_SR_FORMAT_VER_TWO) {
441 ERROR("version of save doesn't match");
442 goto out;
443 }
445 if (read_exact(io_fd, &domctl.u.arch_setup, sizeof(domctl.u.arch_setup))) {
446 ERROR("read: domain setup");
447 goto out;
448 }
450 if (hvm && xc_ia64_hvm_domain_setup(xc_handle, dom) != 0)
451 goto out;
453 /* Build firmware (will be overwritten). */
454 domctl.domain = (domid_t)dom;
455 domctl.u.arch_setup.flags &= ~XEN_DOMAINSETUP_query;
456 domctl.u.arch_setup.bp = 0; /* indicate domain restore */
458 domctl.cmd = XEN_DOMCTL_arch_setup;
459 if (xc_domctl(xc_handle, &domctl))
460 goto out;
462 /* Get the domain's shared-info frame. */
463 domctl.cmd = XEN_DOMCTL_getdomaininfo;
464 domctl.domain = (domid_t)dom;
465 if (xc_domctl(xc_handle, &domctl) < 0) {
466 ERROR("Could not get information on new domain");
467 goto out;
468 }
469 shared_info_frame = domctl.u.getdomaininfo.shared_info_frame;
471 if (ver == XC_IA64_SR_FORMAT_VER_TWO) {
472 unsigned int memmap_info_num_pages;
473 unsigned long memmap_size;
474 xen_ia64_memmap_info_t *memmap_info;
476 if (read_exact(io_fd, &memmap_info_num_pages,
477 sizeof(memmap_info_num_pages))) {
478 ERROR("read: memmap_info_num_pages");
479 goto out;
480 }
481 memmap_size = memmap_info_num_pages * PAGE_SIZE;
482 memmap_info = malloc(memmap_size);
483 if (memmap_info == NULL) {
484 ERROR("Could not allocate memory for memmap_info");
485 goto out;
486 }
487 if (read_exact(io_fd, memmap_info, memmap_size)) {
488 ERROR("read: memmap_info");
489 goto out;
490 }
491 if (xc_ia64_p2m_map(&p2m_table, xc_handle,
492 dom, memmap_info, IA64_DOM0VP_EFP_ALLOC_PTE)) {
493 ERROR("p2m mapping");
494 goto out;
495 }
496 free(memmap_info);
497 } else if (ver == XC_IA64_SR_FORMAT_VER_ONE) {
498 xen_ia64_memmap_info_t *memmap_info;
499 efi_memory_desc_t *memdesc;
500 uint64_t buffer[(sizeof(*memmap_info) + sizeof(*memdesc) +
501 sizeof(uint64_t) - 1) / sizeof(uint64_t)];
503 memset(buffer, 0, sizeof(buffer));
504 memmap_info = (xen_ia64_memmap_info_t *)buffer;
505 memdesc = (efi_memory_desc_t*)&memmap_info->memdesc[0];
506 memmap_info->efi_memmap_size = sizeof(*memmap_info) + sizeof(*memdesc);
507 memmap_info->efi_memdesc_size = sizeof(*memdesc);
508 memmap_info->efi_memdesc_version = EFI_MEMORY_DESCRIPTOR_VERSION;
510 memdesc->type = EFI_MEMORY_DESCRIPTOR_VERSION;
511 memdesc->phys_addr = 0;
512 memdesc->virt_addr = 0;
513 memdesc->num_pages = nr_pfns << (PAGE_SHIFT - EFI_PAGE_SHIFT);
514 memdesc->attribute = EFI_MEMORY_WB;
516 if (xc_ia64_p2m_map(&p2m_table, xc_handle,
517 dom, memmap_info, IA64_DOM0VP_EFP_ALLOC_PTE)) {
518 ERROR("p2m mapping");
519 goto out;
520 }
521 } else {
522 ERROR("unknown version");
523 goto out;
524 }
526 DPRINTF("Reloading memory pages: 0%%\n");
528 while (1) {
529 unsigned long gmfn;
530 if (read_exact(io_fd, &gmfn, sizeof(unsigned long))) {
531 ERROR("Error when reading batch size");
532 goto out;
533 }
534 if (gmfn == INVALID_MFN)
535 break;
537 if (populate_page_if_necessary(xc_handle, dom, gmfn, &p2m_table) < 0) {
538 ERROR("can not populate page 0x%lx", gmfn);
539 goto out;
540 }
541 if (read_page(xc_handle, io_fd, dom, gmfn) < 0)
542 goto out;
543 }
545 DPRINTF("Received all pages\n");
547 if (xc_ia64_recv_unallocated_list(xc_handle, io_fd, dom, &p2m_table))
548 goto out;
550 if (!hvm)
551 rc = xc_ia64_pv_recv_context(xc_handle, io_fd, dom, shared_info_frame,
552 &p2m_table, store_evtchn, store_mfn,
553 console_evtchn, console_mfn);
554 else
555 rc = xc_ia64_hvm_recv_context(xc_handle, io_fd, dom, shared_info_frame,
556 &p2m_table, store_evtchn, store_mfn,
557 console_evtchn, console_mfn);
558 if (rc)
559 goto out;
561 /*
562 * Safety checking of saved context:
563 * 1. user_regs is fine, as Xen checks that on context switch.
564 * 2. fpu_ctxt is fine, as it can't hurt Xen.
565 * 3. trap_ctxt needs the code selectors checked.
566 * 4. ldt base must be page-aligned, no more than 8192 ents, ...
567 * 5. gdt already done, and further checking is done by Xen.
568 * 6. check that kernel_ss is safe.
569 * 7. pt_base is already done.
570 * 8. debugregs are checked by Xen.
571 * 9. callback code selectors need checking.
572 */
573 DPRINTF("Domain ready to be built.\n");
575 rc = 0;
577 out:
578 xc_ia64_p2m_unmap(&p2m_table);
580 if ((rc != 0) && (dom != 0))
581 xc_domain_destroy(xc_handle, dom);
583 DPRINTF("Restore exit with rc=%d\n", rc);
585 return rc;
586 }
588 /*
589 * Local variables:
590 * mode: C
591 * c-set-style: "BSD"
592 * c-basic-offset: 4
593 * tab-width: 4
594 * indent-tabs-mode: nil
595 * End:
596 */