ia64/xen-unstable

view tools/libxc/ia64/xc_ia64_linux_restore.c @ 10692:306d7857928c

[IA64] Save & restore.

xc_ia64_linux_save.c and xc_ia64_linux_restore.c added.
vcpu context has more registers and states (eg: tr registers).
Per cpu irqs are deallocated when cpu is switched off.
#if/#endif added in reboot.c for ia64.

Signed-off-by: Tristan Gingold <tristan.gingold@bull.net>
author awilliam@xenbuild.aw
date Tue Jul 11 12:51:18 2006 -0600 (2006-07-11)
parents
children 86e5d8458c08
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 */
10 #include <stdlib.h>
11 #include <unistd.h>
13 #include "xg_private.h"
15 #define PFN_TO_KB(_pfn) ((_pfn) << (PAGE_SHIFT - 10))
17 /* total number of pages used by the current guest */
18 static unsigned long max_pfn;
20 static ssize_t
21 read_exact(int fd, void *buf, size_t count)
22 {
23 int r = 0, s;
24 unsigned char *b = buf;
26 while (r < count) {
27 s = read(fd, &b[r], count - r);
28 if ((s == -1) && (errno == EINTR))
29 continue;
30 if (s <= 0) {
31 break;
32 }
33 r += s;
34 }
36 return (r == count) ? 1 : 0;
37 }
39 static int
40 read_page(int xc_handle, int io_fd, uint32_t dom, unsigned long pfn)
41 {
42 void *mem;
44 mem = xc_map_foreign_range(xc_handle, dom, PAGE_SIZE,
45 PROT_READ|PROT_WRITE, pfn);
46 if (mem == NULL) {
47 ERR("cannot map page");
48 return -1;
49 }
50 if (!read_exact(io_fd, mem, PAGE_SIZE)) {
51 ERR("Error when reading from state file (5)");
52 return -1;
53 }
54 munmap(mem, PAGE_SIZE);
55 return 0;
56 }
58 int
59 xc_linux_restore(int xc_handle, int io_fd, uint32_t dom,
60 unsigned long nr_pfns, unsigned int store_evtchn,
61 unsigned long *store_mfn, unsigned int console_evtchn,
62 unsigned long *console_mfn)
63 {
64 DECLARE_DOM0_OP;
65 int rc = 1, i;
66 unsigned long mfn, pfn;
67 unsigned long ver;
69 /* The new domain's shared-info frame number. */
70 unsigned long shared_info_frame;
71 unsigned char shared_info_page[PAGE_SIZE]; /* saved contents from file */
72 shared_info_t *shared_info = (shared_info_t *)shared_info_page;
74 /* A copy of the CPU context of the guest. */
75 vcpu_guest_context_t ctxt;
77 unsigned long *page_array = NULL;
79 /* A temporary mapping of the guest's start_info page. */
80 start_info_t *start_info;
82 max_pfn = nr_pfns;
84 DPRINTF("xc_linux_restore start: max_pfn = %ld\n", max_pfn);
87 if (!read_exact(io_fd, &ver, sizeof(unsigned long))) {
88 ERR("Error when reading version");
89 goto out;
90 }
91 if (ver != 1) {
92 ERR("version of save doesn't match");
93 goto out;
94 }
96 if (mlock(&ctxt, sizeof(ctxt))) {
97 /* needed for build dom0 op, but might as well do early */
98 ERR("Unable to mlock ctxt");
99 return 1;
100 }
102 /* Get the domain's shared-info frame. */
103 op.cmd = DOM0_GETDOMAININFO;
104 op.u.getdomaininfo.domain = (domid_t)dom;
105 if (xc_dom0_op(xc_handle, &op) < 0) {
106 ERR("Could not get information on new domain");
107 goto out;
108 }
109 shared_info_frame = op.u.getdomaininfo.shared_info_frame;
111 if (xc_domain_setmaxmem(xc_handle, dom, PFN_TO_KB(max_pfn)) != 0) {
112 errno = ENOMEM;
113 goto out;
114 }
116 if (xc_domain_memory_increase_reservation(xc_handle, dom, max_pfn,
117 0, 0, NULL) != 0) {
118 ERR("Failed to increase reservation by %ld KB", PFN_TO_KB(max_pfn));
119 errno = ENOMEM;
120 goto out;
121 }
123 DPRINTF("Increased domain reservation by %ld KB\n", PFN_TO_KB(max_pfn));
125 if (!read_exact(io_fd, &op.u.domain_setup, sizeof(op.u.domain_setup))) {
126 ERR("read: domain setup");
127 goto out;
128 }
130 /* Build firmware (will be overwritten). */
131 op.u.domain_setup.domain = (domid_t)dom;
132 op.u.domain_setup.flags &= ~XEN_DOMAINSETUP_query;
133 op.u.domain_setup.bp = ((nr_pfns - 3) << PAGE_SHIFT)
134 + sizeof (start_info_t);
135 op.u.domain_setup.maxmem = (nr_pfns - 3) << PAGE_SHIFT;
137 op.cmd = DOM0_DOMAIN_SETUP;
138 if (xc_dom0_op(xc_handle, &op))
139 goto out;
141 /* Get pages. */
142 page_array = malloc(max_pfn * sizeof(unsigned long));
143 if (page_array == NULL ) {
144 ERR("Could not allocate memory");
145 goto out;
146 }
148 if (xc_ia64_get_pfn_list(xc_handle, dom, page_array,
149 0, max_pfn) != max_pfn) {
150 ERR("Could not get the page frame list");
151 goto out;
152 }
154 DPRINTF("Reloading memory pages: 0%%\n");
156 while (1) {
157 if (!read_exact(io_fd, &mfn, sizeof(unsigned long))) {
158 ERR("Error when reading batch size");
159 goto out;
160 }
161 if (mfn == INVALID_MFN)
162 break;
164 pfn = page_array[mfn];
166 DPRINTF ("xc_linux_restore: page %lu/%lu at %lx\n", mfn, max_pfn, pfn);
168 if (read_page(xc_handle, io_fd, dom, page_array[mfn]) < 0)
169 goto out;
170 }
172 DPRINTF("Received all pages\n");
174 /* Get the list of PFNs that are not in the psuedo-phys map */
175 {
176 unsigned int count;
177 unsigned long *pfntab;
178 int rc;
180 if (!read_exact(io_fd, &count, sizeof(count))) {
181 ERR("Error when reading pfn count");
182 goto out;
183 }
185 pfntab = malloc(sizeof(unsigned long) * count);
186 if (!pfntab) {
187 ERR("Out of memory");
188 goto out;
189 }
191 if (!read_exact(io_fd, pfntab, sizeof(unsigned long)*count)) {
192 ERR("Error when reading pfntab");
193 goto out;
194 }
196 DPRINTF ("Try to free %u pages\n", count);
198 for (i = 0; i < count; i++) {
200 volatile unsigned long pfn;
202 struct xen_memory_reservation reservation = {
203 .nr_extents = 1,
204 .extent_order = 0,
205 .domid = dom
206 };
207 set_xen_guest_handle(reservation.extent_start,
208 (unsigned long *)&pfn);
210 pfn = pfntab[i];
211 rc = xc_memory_op(xc_handle, XENMEM_decrease_reservation,
212 &reservation);
213 if (rc != 1) {
214 ERR("Could not decrease reservation : %d", rc);
215 goto out;
216 }
217 }
219 DPRINTF("Decreased reservation by %d pages\n", count);
220 }
223 if (!read_exact(io_fd, &ctxt, sizeof(ctxt))) {
224 ERR("Error when reading ctxt");
225 goto out;
226 }
228 /* First to initialize. */
229 op.cmd = DOM0_SETVCPUCONTEXT;
230 op.u.setvcpucontext.domain = (domid_t)dom;
231 op.u.setvcpucontext.vcpu = 0;
232 set_xen_guest_handle(op.u.setvcpucontext.ctxt, &ctxt);
233 if (xc_dom0_op(xc_handle, &op) != 0) {
234 ERR("Couldn't set vcpu context");
235 goto out;
236 }
238 /* Second to set registers... */
239 ctxt.flags = VGCF_EXTRA_REGS;
240 op.cmd = DOM0_SETVCPUCONTEXT;
241 op.u.setvcpucontext.domain = (domid_t)dom;
242 op.u.setvcpucontext.vcpu = 0;
243 set_xen_guest_handle(op.u.setvcpucontext.ctxt, &ctxt);
244 if (xc_dom0_op(xc_handle, &op) != 0) {
245 ERR("Couldn't set vcpu context");
246 goto out;
247 }
249 /* Just a check. */
250 if (xc_vcpu_getcontext(xc_handle, dom, 0 /* XXX */, &ctxt)) {
251 ERR("Could not get vcpu context");
252 goto out;
253 }
255 /* Then get privreg page. */
256 if (read_page(xc_handle, io_fd, dom, ctxt.privregs_pfn) < 0) {
257 ERR("Could not read vcpu privregs");
258 goto out;
259 }
261 /* Read shared info. */
262 shared_info = xc_map_foreign_range(xc_handle, dom, PAGE_SIZE,
263 PROT_READ|PROT_WRITE, shared_info_frame);
264 if (shared_info == NULL) {
265 ERR("cannot map page");
266 goto out;
267 }
268 if (!read_exact(io_fd, shared_info, PAGE_SIZE)) {
269 ERR("Error when reading shared_info page");
270 goto out;
271 }
273 /* clear any pending events and the selector */
274 memset(&(shared_info->evtchn_pending[0]), 0,
275 sizeof (shared_info->evtchn_pending));
276 for (i = 0; i < MAX_VIRT_CPUS; i++)
277 shared_info->vcpu_info[i].evtchn_pending_sel = 0;
279 mfn = page_array[shared_info->arch.start_info_pfn];
281 munmap (shared_info, PAGE_SIZE);
283 /* Uncanonicalise the suspend-record frame number and poke resume rec. */
284 start_info = xc_map_foreign_range(xc_handle, dom, PAGE_SIZE,
285 PROT_READ | PROT_WRITE, mfn);
286 start_info->nr_pages = max_pfn;
287 start_info->shared_info = shared_info_frame << PAGE_SHIFT;
288 start_info->flags = 0;
289 *store_mfn = page_array[start_info->store_mfn];
290 start_info->store_evtchn = store_evtchn;
291 *console_mfn = page_array[start_info->console_mfn];
292 start_info->console_evtchn = console_evtchn;
293 munmap(start_info, PAGE_SIZE);
295 /*
296 * Safety checking of saved context:
297 * 1. user_regs is fine, as Xen checks that on context switch.
298 * 2. fpu_ctxt is fine, as it can't hurt Xen.
299 * 3. trap_ctxt needs the code selectors checked.
300 * 4. ldt base must be page-aligned, no more than 8192 ents, ...
301 * 5. gdt already done, and further checking is done by Xen.
302 * 6. check that kernel_ss is safe.
303 * 7. pt_base is already done.
304 * 8. debugregs are checked by Xen.
305 * 9. callback code selectors need checking.
306 */
307 DPRINTF("Domain ready to be built.\n");
309 rc = 0;
311 out:
312 if ((rc != 0) && (dom != 0))
313 xc_domain_destroy(xc_handle, dom);
315 free (page_array);
317 DPRINTF("Restore exit with rc=%d\n", rc);
319 return rc;
320 }