source: trunk/packages/xen-common/xen-common/tools/libxc/xc_resume.c @ 34

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

Add xen and xen-common

File size: 6.1 KB
Line 
1#include "xc_private.h"
2#include "xg_private.h"
3#include "xg_save_restore.h"
4
5#if defined(__i386__) || defined(__x86_64__)
6
7#include <xen/foreign/x86_32.h>
8#include <xen/foreign/x86_64.h>
9#include <xen/hvm/params.h>
10
11/* Need to provide the right flavour of vcpu context for Xen */
12typedef union
13{
14    vcpu_guest_context_x86_64_t c64;
15    vcpu_guest_context_x86_32_t c32;   
16    vcpu_guest_context_t c;
17} vcpu_guest_context_either_t;
18
19static int modify_returncode(int xc_handle, uint32_t domid)
20{
21    vcpu_guest_context_either_t ctxt;
22    xc_dominfo_t info;
23    xen_capabilities_info_t caps;
24    int rc;
25
26    if ( xc_domain_getinfo(xc_handle, domid, 1, &info) != 1 )
27    {
28        PERROR("Could not get domain info");
29        return -1;
30    }
31
32    /* HVM guests without PV drivers do not have a return code to modify. */
33    if ( info.hvm )
34    {
35        unsigned long irq = 0;
36        xc_get_hvm_param(xc_handle, domid, HVM_PARAM_CALLBACK_IRQ, &irq);
37        if ( !irq )
38            return 0;
39    }
40
41    if ( xc_version(xc_handle, XENVER_capabilities, &caps) != 0 )
42    {
43        PERROR("Could not get Xen capabilities\n");
44        return -1;
45    }
46
47    if ( (rc = xc_vcpu_getcontext(xc_handle, domid, 0, &ctxt.c)) != 0 )
48        return rc;
49
50    if ( !info.hvm )
51        ctxt.c.user_regs.eax = 1;
52    else if ( strstr(caps, "x86_64") )
53        ctxt.c64.user_regs.eax = 1;
54    else
55        ctxt.c32.user_regs.eax = 1;
56
57    if ( (rc = xc_vcpu_setcontext(xc_handle, domid, 0, &ctxt.c)) != 0 )
58        return rc;
59
60    return 0;
61}
62
63#else
64
65static int modify_returncode(int xc_handle, uint32_t domid)
66{
67    return 0;
68
69}
70
71#endif
72
73static int xc_domain_resume_cooperative(int xc_handle, uint32_t domid)
74{
75    DECLARE_DOMCTL;
76    int rc;
77
78    /*
79     * Set hypercall return code to indicate that suspend is cancelled
80     * (rather than resuming in a new domain context).
81     */
82    if ( (rc = modify_returncode(xc_handle, domid)) != 0 )
83        return rc;
84
85    domctl.cmd = XEN_DOMCTL_resumedomain;
86    domctl.domain = domid;
87    return do_domctl(xc_handle, &domctl);
88}
89
90static int xc_domain_resume_any(int xc_handle, uint32_t domid)
91{
92    DECLARE_DOMCTL;
93    xc_dominfo_t info;
94    int i, rc = -1;
95#if defined(__i386__) || defined(__x86_64__)
96    unsigned long mfn, p2m_size = 0;
97    vcpu_guest_context_t ctxt;
98    start_info_t *start_info;
99    shared_info_t *shinfo = NULL;
100    xen_pfn_t *p2m_frame_list_list = NULL;
101    xen_pfn_t *p2m_frame_list = NULL;
102    xen_pfn_t *p2m = NULL;
103#endif
104
105    if ( xc_domain_getinfo(xc_handle, domid, 1, &info) != 1 )
106    {
107        PERROR("Could not get domain info");
108        return rc;
109    }
110
111    /*
112     * (x86 only) Rewrite store_mfn and console_mfn back to MFN (from PFN).
113     */
114#if defined(__i386__) || defined(__x86_64__)
115    if ( info.hvm )
116    {
117        ERROR("Cannot resume uncooperative HVM guests");
118        return rc;
119    }
120
121    /* Map the shared info frame */
122    shinfo = xc_map_foreign_range(xc_handle, domid, PAGE_SIZE,
123                                  PROT_READ, info.shared_info_frame);
124    if ( shinfo == NULL )
125    {
126        ERROR("Couldn't map shared info");
127        goto out;
128    }
129
130    p2m_size = shinfo->arch.max_pfn;
131
132    p2m_frame_list_list =
133        xc_map_foreign_range(xc_handle, domid, PAGE_SIZE, PROT_READ,
134                             shinfo->arch.pfn_to_mfn_frame_list_list);
135    if ( p2m_frame_list_list == NULL )
136    {
137        ERROR("Couldn't map p2m_frame_list_list");
138        goto out;
139    }
140
141    p2m_frame_list = xc_map_foreign_batch(xc_handle, domid, PROT_READ,
142                                          p2m_frame_list_list,
143                                          P2M_FLL_ENTRIES);
144    if ( p2m_frame_list == NULL )
145    {
146        ERROR("Couldn't map p2m_frame_list");
147        goto out;
148    }
149
150    /* Map all the frames of the pfn->mfn table. For migrate to succeed,
151       the guest must not change which frames are used for this purpose.
152       (its not clear why it would want to change them, and we'll be OK
153       from a safety POV anyhow. */
154    p2m = xc_map_foreign_batch(xc_handle, domid, PROT_READ,
155                               p2m_frame_list,
156                               P2M_FL_ENTRIES);
157    if ( p2m == NULL )
158    {
159        ERROR("Couldn't map p2m table");
160        goto out;
161    }
162
163    if ( lock_pages(&ctxt, sizeof(ctxt)) )
164    {
165        ERROR("Unable to lock ctxt");
166        goto out;
167    }
168
169    if ( xc_vcpu_getcontext(xc_handle, domid, 0, &ctxt) )
170    {
171        ERROR("Could not get vcpu context");
172        goto out;
173    }
174
175    mfn = ctxt.user_regs.edx;
176
177    start_info = xc_map_foreign_range(xc_handle, domid, PAGE_SIZE,
178                                      PROT_READ | PROT_WRITE, mfn);
179    if ( start_info == NULL )
180    {
181        ERROR("Couldn't map start_info");
182        goto out;
183    }
184
185    start_info->store_mfn        = p2m[start_info->store_mfn];
186    start_info->console.domU.mfn = p2m[start_info->console.domU.mfn];
187
188    munmap(start_info, PAGE_SIZE);
189#endif /* defined(__i386__) || defined(__x86_64__) */
190
191    /* Reset all secondary CPU states. */
192    for ( i = 1; i <= info.max_vcpu_id; i++ )
193        xc_vcpu_setcontext(xc_handle, domid, i, NULL);
194
195    /* Ready to resume domain execution now. */
196    domctl.cmd = XEN_DOMCTL_resumedomain;
197    domctl.domain = domid;
198    rc = do_domctl(xc_handle, &domctl);
199
200#if defined(__i386__) || defined(__x86_64__)
201 out:
202    unlock_pages((void *)&ctxt, sizeof ctxt);
203    if (p2m)
204        munmap(p2m, P2M_FL_ENTRIES*PAGE_SIZE);
205    if (p2m_frame_list)
206        munmap(p2m_frame_list, P2M_FLL_ENTRIES*PAGE_SIZE);
207    if (p2m_frame_list_list)
208        munmap(p2m_frame_list_list, PAGE_SIZE);
209    if (shinfo)
210        munmap(shinfo, PAGE_SIZE);
211#endif
212
213    return rc;
214}
215
216/*
217 * Resume execution of a domain after suspend shutdown.
218 * This can happen in one of two ways:
219 *  1. Resume with special return code.
220 *  2. Reset guest environment so it believes it is resumed in a new
221 *     domain context.
222 * (2) should be used only for guests which cannot handle the special
223 * new return code. (1) is always safe (but slower).
224 */
225int xc_domain_resume(int xc_handle, uint32_t domid, int fast)
226{
227    return (fast
228            ? xc_domain_resume_cooperative(xc_handle, domid)
229            : xc_domain_resume_any(xc_handle, domid));
230}
Note: See TracBrowser for help on using the repository browser.