debuggers.hg

view tools/libxc/xc_resume.c @ 21067:b4a1832a916f

Update Xen version to 4.0.0-rc6
author Keir Fraser <keir.fraser@citrix.com>
date Tue Mar 09 18:18:05 2010 +0000 (2010-03-09)
parents 0b138a019292
children 779c0ef9682c
line source
1 #include "xc_private.h"
2 #include "xg_private.h"
3 #include "xg_save_restore.h"
5 #if defined(__i386__) || defined(__x86_64__)
7 #include <xen/foreign/x86_32.h>
8 #include <xen/foreign/x86_64.h>
9 #include <xen/hvm/params.h>
11 static int pv_guest_width(int xc_handle, uint32_t domid)
12 {
13 DECLARE_DOMCTL;
14 domctl.domain = domid;
15 domctl.cmd = XEN_DOMCTL_get_address_size;
16 if ( xc_domctl(xc_handle, &domctl) != 0 )
17 {
18 PERROR("Could not get guest address size");
19 return -1;
20 }
21 return domctl.u.address_size.size / 8;
22 }
24 static int modify_returncode(int xc_handle, uint32_t domid)
25 {
26 vcpu_guest_context_any_t ctxt;
27 xc_dominfo_t info;
28 xen_capabilities_info_t caps;
29 struct domain_info_context _dinfo = {};
30 struct domain_info_context *dinfo = &_dinfo;
31 int rc;
33 if ( xc_domain_getinfo(xc_handle, domid, 1, &info) != 1 )
34 {
35 PERROR("Could not get domain info");
36 return -1;
37 }
39 if ( info.hvm )
40 {
41 /* HVM guests without PV drivers have no return code to modify. */
42 unsigned long irq = 0;
43 xc_get_hvm_param(xc_handle, domid, HVM_PARAM_CALLBACK_IRQ, &irq);
44 if ( !irq )
45 return 0;
47 /* HVM guests have host address width. */
48 if ( xc_version(xc_handle, XENVER_capabilities, &caps) != 0 )
49 {
50 PERROR("Could not get Xen capabilities\n");
51 return -1;
52 }
53 dinfo->guest_width = strstr(caps, "x86_64") ? 8 : 4;
54 }
55 else
56 {
57 /* Probe PV guest address width. */
58 dinfo->guest_width = pv_guest_width(xc_handle, domid);
59 if ( dinfo->guest_width < 0 )
60 return -1;
61 }
63 if ( (rc = xc_vcpu_getcontext(xc_handle, domid, 0, &ctxt)) != 0 )
64 return rc;
66 SET_FIELD(&ctxt, user_regs.eax, 1);
68 if ( (rc = xc_vcpu_setcontext(xc_handle, domid, 0, &ctxt)) != 0 )
69 return rc;
71 return 0;
72 }
74 #else
76 static int modify_returncode(int xc_handle, uint32_t domid)
77 {
78 return 0;
80 }
82 #endif
84 static int xc_domain_resume_cooperative(int xc_handle, uint32_t domid)
85 {
86 DECLARE_DOMCTL;
87 int rc;
89 /*
90 * Set hypercall return code to indicate that suspend is cancelled
91 * (rather than resuming in a new domain context).
92 */
93 if ( (rc = modify_returncode(xc_handle, domid)) != 0 )
94 return rc;
96 domctl.cmd = XEN_DOMCTL_resumedomain;
97 domctl.domain = domid;
98 return do_domctl(xc_handle, &domctl);
99 }
101 static int xc_domain_resume_any(int xc_handle, uint32_t domid)
102 {
103 DECLARE_DOMCTL;
104 xc_dominfo_t info;
105 int i, rc = -1;
106 #if defined(__i386__) || defined(__x86_64__)
107 struct domain_info_context _dinfo = { .p2m_size = 0 };
108 struct domain_info_context *dinfo = &_dinfo;
109 unsigned long mfn;
110 vcpu_guest_context_any_t ctxt;
111 start_info_t *start_info;
112 shared_info_t *shinfo = NULL;
113 xen_pfn_t *p2m_frame_list_list = NULL;
114 xen_pfn_t *p2m_frame_list = NULL;
115 xen_pfn_t *p2m = NULL;
116 #endif
118 if ( xc_domain_getinfo(xc_handle, domid, 1, &info) != 1 )
119 {
120 PERROR("Could not get domain info");
121 return rc;
122 }
124 /*
125 * (x86 only) Rewrite store_mfn and console_mfn back to MFN (from PFN).
126 */
127 #if defined(__i386__) || defined(__x86_64__)
128 if ( info.hvm )
129 {
130 ERROR("Cannot resume uncooperative HVM guests");
131 return rc;
132 }
134 dinfo->guest_width = pv_guest_width(xc_handle, domid);
135 if ( dinfo->guest_width != sizeof(long) )
136 {
137 ERROR("Cannot resume uncooperative cross-address-size guests");
138 return rc;
139 }
141 /* Map the shared info frame */
142 shinfo = xc_map_foreign_range(xc_handle, domid, PAGE_SIZE,
143 PROT_READ, info.shared_info_frame);
144 if ( shinfo == NULL )
145 {
146 ERROR("Couldn't map shared info");
147 goto out;
148 }
150 dinfo->p2m_size = shinfo->arch.max_pfn;
152 p2m_frame_list_list =
153 xc_map_foreign_range(xc_handle, domid, PAGE_SIZE, PROT_READ,
154 shinfo->arch.pfn_to_mfn_frame_list_list);
155 if ( p2m_frame_list_list == NULL )
156 {
157 ERROR("Couldn't map p2m_frame_list_list");
158 goto out;
159 }
161 p2m_frame_list = xc_map_foreign_pages(xc_handle, domid, PROT_READ,
162 p2m_frame_list_list,
163 P2M_FLL_ENTRIES);
164 if ( p2m_frame_list == NULL )
165 {
166 ERROR("Couldn't map p2m_frame_list");
167 goto out;
168 }
170 /* Map all the frames of the pfn->mfn table. For migrate to succeed,
171 the guest must not change which frames are used for this purpose.
172 (its not clear why it would want to change them, and we'll be OK
173 from a safety POV anyhow. */
174 p2m = xc_map_foreign_pages(xc_handle, domid, PROT_READ,
175 p2m_frame_list,
176 P2M_FL_ENTRIES);
177 if ( p2m == NULL )
178 {
179 ERROR("Couldn't map p2m table");
180 goto out;
181 }
183 if ( lock_pages(&ctxt, sizeof(ctxt)) )
184 {
185 ERROR("Unable to lock ctxt");
186 goto out;
187 }
189 if ( xc_vcpu_getcontext(xc_handle, domid, 0, &ctxt) )
190 {
191 ERROR("Could not get vcpu context");
192 goto out;
193 }
195 mfn = GET_FIELD(&ctxt, user_regs.edx);
197 start_info = xc_map_foreign_range(xc_handle, domid, PAGE_SIZE,
198 PROT_READ | PROT_WRITE, mfn);
199 if ( start_info == NULL )
200 {
201 ERROR("Couldn't map start_info");
202 goto out;
203 }
205 start_info->store_mfn = p2m[start_info->store_mfn];
206 start_info->console.domU.mfn = p2m[start_info->console.domU.mfn];
208 munmap(start_info, PAGE_SIZE);
209 #endif /* defined(__i386__) || defined(__x86_64__) */
211 /* Reset all secondary CPU states. */
212 for ( i = 1; i <= info.max_vcpu_id; i++ )
213 xc_vcpu_setcontext(xc_handle, domid, i, NULL);
215 /* Ready to resume domain execution now. */
216 domctl.cmd = XEN_DOMCTL_resumedomain;
217 domctl.domain = domid;
218 rc = do_domctl(xc_handle, &domctl);
220 #if defined(__i386__) || defined(__x86_64__)
221 out:
222 unlock_pages((void *)&ctxt, sizeof ctxt);
223 if (p2m)
224 munmap(p2m, P2M_FL_ENTRIES*PAGE_SIZE);
225 if (p2m_frame_list)
226 munmap(p2m_frame_list, P2M_FLL_ENTRIES*PAGE_SIZE);
227 if (p2m_frame_list_list)
228 munmap(p2m_frame_list_list, PAGE_SIZE);
229 if (shinfo)
230 munmap(shinfo, PAGE_SIZE);
231 #endif
233 return rc;
234 }
236 /*
237 * Resume execution of a domain after suspend shutdown.
238 * This can happen in one of two ways:
239 * 1. Resume with special return code.
240 * 2. Reset guest environment so it believes it is resumed in a new
241 * domain context.
242 * (2) should be used only for guests which cannot handle the special
243 * new return code. (1) is always safe (but slower).
244 */
245 int xc_domain_resume(int xc_handle, uint32_t domid, int fast)
246 {
247 return (fast
248 ? xc_domain_resume_cooperative(xc_handle, domid)
249 : xc_domain_resume_any(xc_handle, domid));
250 }