source: trunk/packages/xen-3.1/xen-3.1/tools/libxc/ia64/xc_ia64_linux_restore.c @ 34

Last change on this file since 34 was 34, checked in by hartmans, 18 years ago

Add xen and xen-common

File size: 9.1 KB
Line 
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
10#include <stdlib.h>
11#include <unistd.h>
12
13#include "xg_private.h"
14
15#define PFN_TO_KB(_pfn) ((_pfn) << (PAGE_SHIFT - 10))
16
17/* number of pfns this guest has (i.e. number of entries in the P2M) */
18static unsigned long p2m_size;
19
20/* number of 'in use' pfns in the guest (i.e. #P2M entries with a valid mfn) */
21static unsigned long nr_pfns;
22
23static ssize_t
24read_exact(int fd, void *buf, size_t count)
25{
26    int r = 0, s;
27    unsigned char *b = buf;
28
29    while (r < count) {
30        s = read(fd, &b[r], count - r);
31        if ((s == -1) && (errno == EINTR))
32            continue;
33        if (s <= 0) {
34            break;
35        }
36        r += s;
37    }
38
39    return (r == count) ? 1 : 0;
40}
41
42static int
43read_page(int xc_handle, int io_fd, uint32_t dom, unsigned long pfn)
44{
45    void *mem;
46
47    mem = xc_map_foreign_range(xc_handle, dom, PAGE_SIZE,
48                               PROT_READ|PROT_WRITE, pfn);
49    if (mem == NULL) {
50            ERROR("cannot map page");
51            return -1;
52    }
53    if (!read_exact(io_fd, mem, PAGE_SIZE)) {
54            ERROR("Error when reading from state file (5)");
55            return -1;
56    }
57    munmap(mem, PAGE_SIZE);
58    return 0;
59}
60
61int
62xc_domain_restore(int xc_handle, int io_fd, uint32_t dom,
63                 unsigned int store_evtchn, unsigned long *store_mfn,
64                 unsigned int console_evtchn, unsigned long *console_mfn,
65                 unsigned int hvm, unsigned int pae)
66{
67    DECLARE_DOMCTL;
68    int rc = 1, i;
69    unsigned long gmfn;
70    unsigned long ver;
71
72    /* The new domain's shared-info frame number. */
73    unsigned long shared_info_frame;
74    unsigned char shared_info_page[PAGE_SIZE]; /* saved contents from file */
75    shared_info_t *shared_info = (shared_info_t *)shared_info_page;
76
77    /* A copy of the CPU context of the guest. */
78    vcpu_guest_context_t ctxt;
79
80    unsigned long *page_array = NULL;
81
82    /* A temporary mapping of the guest's start_info page. */
83    start_info_t *start_info;
84
85    if (hvm) {
86        ERROR("HVM Restore is unsupported");
87        goto out;
88    }
89
90    /* For info only */
91    nr_pfns = 0;
92
93    if ( !read_exact(io_fd, &p2m_size, sizeof(unsigned long)) )
94    {
95        ERROR("read: p2m_size");
96        goto out;
97    }
98    DPRINTF("xc_linux_restore start: p2m_size = %lx\n", p2m_size);
99
100    if (!read_exact(io_fd, &ver, sizeof(unsigned long))) {
101        ERROR("Error when reading version");
102        goto out;
103    }
104    if (ver != 1) {
105        ERROR("version of save doesn't match");
106        goto out;
107    }
108
109    if (mlock(&ctxt, sizeof(ctxt))) {
110        /* needed for build domctl, but might as well do early */
111        ERROR("Unable to mlock ctxt");
112        return 1;
113    }
114
115    /* Get pages.  */
116    page_array = malloc(p2m_size * sizeof(unsigned long));
117    if (page_array == NULL) {
118        ERROR("Could not allocate memory");
119        goto out;
120    }
121
122    for ( i = 0; i < p2m_size; i++ )
123        page_array[i] = i;
124
125    if ( xc_domain_memory_populate_physmap(xc_handle, dom, p2m_size,
126                                           0, 0, page_array) )
127    {
128        ERROR("Failed to allocate memory for %ld KB to dom %d.\n",
129              PFN_TO_KB(p2m_size), dom);
130        goto out;
131    }
132    DPRINTF("Allocated memory by %ld KB\n", PFN_TO_KB(p2m_size));
133
134    if (!read_exact(io_fd, &domctl.u.arch_setup, sizeof(domctl.u.arch_setup))) {
135        ERROR("read: domain setup");
136        goto out;
137    }
138
139    /* Build firmware (will be overwritten).  */
140    domctl.domain = (domid_t)dom;
141    domctl.u.arch_setup.flags &= ~XEN_DOMAINSETUP_query;
142    domctl.u.arch_setup.bp = ((p2m_size - 3) << PAGE_SHIFT)
143                           + sizeof (start_info_t);
144    domctl.u.arch_setup.maxmem = (p2m_size - 3) << PAGE_SHIFT;
145   
146    domctl.cmd = XEN_DOMCTL_arch_setup;
147    if (xc_domctl(xc_handle, &domctl))
148        goto out;
149
150    /* Get the domain's shared-info frame. */
151    domctl.cmd = XEN_DOMCTL_getdomaininfo;
152    domctl.domain = (domid_t)dom;
153    if (xc_domctl(xc_handle, &domctl) < 0) {
154        ERROR("Could not get information on new domain");
155        goto out;
156    }
157    shared_info_frame = domctl.u.getdomaininfo.shared_info_frame;
158
159    DPRINTF("Reloading memory pages:   0%%\n");
160
161    while (1) {
162        if (!read_exact(io_fd, &gmfn, sizeof(unsigned long))) {
163            ERROR("Error when reading batch size");
164            goto out;
165        }
166        if (gmfn == INVALID_MFN)
167                break;
168
169        if (read_page(xc_handle, io_fd, dom, gmfn) < 0)
170                goto out;
171    }
172
173    DPRINTF("Received all pages\n");
174
175    /* Get the list of PFNs that are not in the psuedo-phys map */
176    {
177        unsigned int count;
178        unsigned long *pfntab;
179        int rc;
180
181        if (!read_exact(io_fd, &count, sizeof(count))) {
182            ERROR("Error when reading pfn count");
183            goto out;
184        }
185
186        pfntab = malloc(sizeof(unsigned long) * count);
187        if (!pfntab) {
188            ERROR("Out of memory");
189            goto out;
190        }
191
192        if (!read_exact(io_fd, pfntab, sizeof(unsigned long)*count)) {
193            ERROR("Error when reading pfntab");
194            goto out;
195        }
196
197        DPRINTF ("Try to free %u pages\n", count);
198
199        for (i = 0; i < count; i++) {
200
201            volatile unsigned long pfn;
202
203            struct xen_memory_reservation reservation = {
204                .nr_extents   = 1,
205                .extent_order = 0,
206                .domid        = dom
207            };
208            set_xen_guest_handle(reservation.extent_start,
209                                 (unsigned long *)&pfn);
210
211            pfn = pfntab[i];
212            rc = xc_memory_op(xc_handle, XENMEM_decrease_reservation,
213                              &reservation);
214            if (rc != 1) {
215                ERROR("Could not decrease reservation : %d", rc);
216                goto out;
217            }
218        }
219
220        DPRINTF("Decreased reservation by %d pages\n", count);
221    }
222
223
224    if (!read_exact(io_fd, &ctxt, sizeof(ctxt))) {
225        ERROR("Error when reading ctxt");
226        goto out;
227    }
228
229    fprintf(stderr, "ip=%016lx, b0=%016lx\n", ctxt.user_regs.cr_iip,
230            ctxt.user_regs.b0);
231
232    /* First to initialize.  */
233    domctl.cmd = XEN_DOMCTL_setvcpucontext;
234    domctl.domain = (domid_t)dom;
235    domctl.u.vcpucontext.vcpu   = 0;
236    set_xen_guest_handle(domctl.u.vcpucontext.ctxt, &ctxt);
237    if (xc_domctl(xc_handle, &domctl) != 0) {
238            ERROR("Couldn't set vcpu context");
239            goto out;
240    }
241
242    /* Second to set registers...  */
243    ctxt.flags = VGCF_EXTRA_REGS;
244    domctl.cmd = XEN_DOMCTL_setvcpucontext;
245    domctl.domain = (domid_t)dom;
246    domctl.u.vcpucontext.vcpu   = 0;
247    set_xen_guest_handle(domctl.u.vcpucontext.ctxt, &ctxt);
248    if (xc_domctl(xc_handle, &domctl) != 0) {
249            ERROR("Couldn't set vcpu context");
250            goto out;
251    }
252
253    /* Just a check.  */
254    if (xc_vcpu_getcontext(xc_handle, dom, 0 /* XXX */, &ctxt)) {
255        ERROR("Could not get vcpu context");
256        goto out;
257    }
258
259    /* Then get privreg page.  */
260    if (read_page(xc_handle, io_fd, dom, ctxt.privregs_pfn) < 0) {
261            ERROR("Could not read vcpu privregs");
262            goto out;
263    }
264
265    /* Read shared info.  */
266    shared_info = xc_map_foreign_range(xc_handle, dom, PAGE_SIZE,
267                                       PROT_READ|PROT_WRITE, shared_info_frame);
268    if (shared_info == NULL) {
269            ERROR("cannot map page");
270            goto out;
271    }
272    if (!read_exact(io_fd, shared_info, PAGE_SIZE)) {
273            ERROR("Error when reading shared_info page");
274            goto out;
275    }
276
277    /* clear any pending events and the selector */
278    memset(&(shared_info->evtchn_pending[0]), 0,
279           sizeof (shared_info->evtchn_pending));
280    for (i = 0; i < MAX_VIRT_CPUS; i++)
281        shared_info->vcpu_info[i].evtchn_pending_sel = 0;
282
283    gmfn = shared_info->arch.start_info_pfn;
284
285    munmap (shared_info, PAGE_SIZE);
286
287    /* Uncanonicalise the suspend-record frame number and poke resume rec. */
288    start_info = xc_map_foreign_range(xc_handle, dom, PAGE_SIZE,
289                                      PROT_READ | PROT_WRITE, gmfn);
290    start_info->nr_pages = p2m_size;
291    start_info->shared_info = shared_info_frame << PAGE_SHIFT;
292    start_info->flags = 0;
293    *store_mfn = start_info->store_mfn;
294    start_info->store_evtchn = store_evtchn;
295    *console_mfn = start_info->console.domU.mfn;
296    start_info->console.domU.evtchn = console_evtchn;
297    munmap(start_info, PAGE_SIZE);
298
299    /*
300     * Safety checking of saved context:
301     *  1. user_regs is fine, as Xen checks that on context switch.
302     *  2. fpu_ctxt is fine, as it can't hurt Xen.
303     *  3. trap_ctxt needs the code selectors checked.
304     *  4. ldt base must be page-aligned, no more than 8192 ents, ...
305     *  5. gdt already done, and further checking is done by Xen.
306     *  6. check that kernel_ss is safe.
307     *  7. pt_base is already done.
308     *  8. debugregs are checked by Xen.
309     *  9. callback code selectors need checking.
310     */
311    DPRINTF("Domain ready to be built.\n");
312
313    rc = 0;
314
315 out:
316    if ((rc != 0) && (dom != 0))
317        xc_domain_destroy(xc_handle, dom);
318
319    if (page_array != NULL)
320            free(page_array);
321
322    DPRINTF("Restore exit with rc=%d\n", rc);
323
324    return rc;
325}
Note: See TracBrowser for help on using the repository browser.