debuggers.hg

view tools/libxc/xc_resume.c @ 16715:c5deb251b9dc

Update version to 3.2.0-rc4
author Keir Fraser <keir.fraser@citrix.com>
date Sat Dec 29 17:57:37 2007 +0000 (2007-12-29)
parents 4c8394e3b011
children d3a87899985d
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 /* Don't yet support cross-address-size uncooperative resume */
12 #define guest_width (sizeof (unsigned long))
14 static int modify_returncode(int xc_handle, uint32_t domid)
15 {
16 vcpu_guest_context_either_t ctxt;
17 xc_dominfo_t info;
18 xen_capabilities_info_t caps;
19 int rc;
21 if ( xc_domain_getinfo(xc_handle, domid, 1, &info) != 1 )
22 {
23 PERROR("Could not get domain info");
24 return -1;
25 }
27 /* HVM guests without PV drivers do not have a return code to modify. */
28 if ( info.hvm )
29 {
30 unsigned long irq = 0;
31 xc_get_hvm_param(xc_handle, domid, HVM_PARAM_CALLBACK_IRQ, &irq);
32 if ( !irq )
33 return 0;
34 }
36 if ( xc_version(xc_handle, XENVER_capabilities, &caps) != 0 )
37 {
38 PERROR("Could not get Xen capabilities\n");
39 return -1;
40 }
42 if ( (rc = xc_vcpu_getcontext(xc_handle, domid, 0, &ctxt.c)) != 0 )
43 return rc;
45 if ( !info.hvm )
46 ctxt.c.user_regs.eax = 1;
47 else if ( strstr(caps, "x86_64") )
48 ctxt.x64.user_regs.eax = 1;
49 else
50 ctxt.x32.user_regs.eax = 1;
52 if ( (rc = xc_vcpu_setcontext(xc_handle, domid, 0, &ctxt.c)) != 0 )
53 return rc;
55 return 0;
56 }
58 #else
60 static int modify_returncode(int xc_handle, uint32_t domid)
61 {
62 return 0;
64 }
66 #endif
68 static int xc_domain_resume_cooperative(int xc_handle, uint32_t domid)
69 {
70 DECLARE_DOMCTL;
71 int rc;
73 /*
74 * Set hypercall return code to indicate that suspend is cancelled
75 * (rather than resuming in a new domain context).
76 */
77 if ( (rc = modify_returncode(xc_handle, domid)) != 0 )
78 return rc;
80 domctl.cmd = XEN_DOMCTL_resumedomain;
81 domctl.domain = domid;
82 return do_domctl(xc_handle, &domctl);
83 }
85 static int xc_domain_resume_any(int xc_handle, uint32_t domid)
86 {
87 DECLARE_DOMCTL;
88 xc_dominfo_t info;
89 int i, rc = -1;
90 #if defined(__i386__) || defined(__x86_64__)
91 unsigned long mfn, p2m_size = 0;
92 vcpu_guest_context_t ctxt;
93 start_info_t *start_info;
94 shared_info_t *shinfo = NULL;
95 xen_pfn_t *p2m_frame_list_list = NULL;
96 xen_pfn_t *p2m_frame_list = NULL;
97 xen_pfn_t *p2m = NULL;
98 #endif
100 if ( xc_domain_getinfo(xc_handle, domid, 1, &info) != 1 )
101 {
102 PERROR("Could not get domain info");
103 return rc;
104 }
106 /*
107 * (x86 only) Rewrite store_mfn and console_mfn back to MFN (from PFN).
108 */
109 #if defined(__i386__) || defined(__x86_64__)
110 if ( info.hvm )
111 {
112 ERROR("Cannot resume uncooperative HVM guests");
113 return rc;
114 }
116 /* Map the shared info frame */
117 shinfo = xc_map_foreign_range(xc_handle, domid, PAGE_SIZE,
118 PROT_READ, info.shared_info_frame);
119 if ( shinfo == NULL )
120 {
121 ERROR("Couldn't map shared info");
122 goto out;
123 }
125 p2m_size = shinfo->arch.max_pfn;
127 p2m_frame_list_list =
128 xc_map_foreign_range(xc_handle, domid, PAGE_SIZE, PROT_READ,
129 shinfo->arch.pfn_to_mfn_frame_list_list);
130 if ( p2m_frame_list_list == NULL )
131 {
132 ERROR("Couldn't map p2m_frame_list_list");
133 goto out;
134 }
136 p2m_frame_list = xc_map_foreign_batch(xc_handle, domid, PROT_READ,
137 p2m_frame_list_list,
138 P2M_FLL_ENTRIES);
139 if ( p2m_frame_list == NULL )
140 {
141 ERROR("Couldn't map p2m_frame_list");
142 goto out;
143 }
145 /* Map all the frames of the pfn->mfn table. For migrate to succeed,
146 the guest must not change which frames are used for this purpose.
147 (its not clear why it would want to change them, and we'll be OK
148 from a safety POV anyhow. */
149 p2m = xc_map_foreign_batch(xc_handle, domid, PROT_READ,
150 p2m_frame_list,
151 P2M_FL_ENTRIES);
152 if ( p2m == NULL )
153 {
154 ERROR("Couldn't map p2m table");
155 goto out;
156 }
158 if ( lock_pages(&ctxt, sizeof(ctxt)) )
159 {
160 ERROR("Unable to lock ctxt");
161 goto out;
162 }
164 if ( xc_vcpu_getcontext(xc_handle, domid, 0, &ctxt) )
165 {
166 ERROR("Could not get vcpu context");
167 goto out;
168 }
170 mfn = ctxt.user_regs.edx;
172 start_info = xc_map_foreign_range(xc_handle, domid, PAGE_SIZE,
173 PROT_READ | PROT_WRITE, mfn);
174 if ( start_info == NULL )
175 {
176 ERROR("Couldn't map start_info");
177 goto out;
178 }
180 start_info->store_mfn = p2m[start_info->store_mfn];
181 start_info->console.domU.mfn = p2m[start_info->console.domU.mfn];
183 munmap(start_info, PAGE_SIZE);
184 #endif /* defined(__i386__) || defined(__x86_64__) */
186 /* Reset all secondary CPU states. */
187 for ( i = 1; i <= info.max_vcpu_id; i++ )
188 xc_vcpu_setcontext(xc_handle, domid, i, NULL);
190 /* Ready to resume domain execution now. */
191 domctl.cmd = XEN_DOMCTL_resumedomain;
192 domctl.domain = domid;
193 rc = do_domctl(xc_handle, &domctl);
195 #if defined(__i386__) || defined(__x86_64__)
196 out:
197 unlock_pages((void *)&ctxt, sizeof ctxt);
198 if (p2m)
199 munmap(p2m, P2M_FL_ENTRIES*PAGE_SIZE);
200 if (p2m_frame_list)
201 munmap(p2m_frame_list, P2M_FLL_ENTRIES*PAGE_SIZE);
202 if (p2m_frame_list_list)
203 munmap(p2m_frame_list_list, PAGE_SIZE);
204 if (shinfo)
205 munmap(shinfo, PAGE_SIZE);
206 #endif
208 return rc;
209 }
211 /*
212 * Resume execution of a domain after suspend shutdown.
213 * This can happen in one of two ways:
214 * 1. Resume with special return code.
215 * 2. Reset guest environment so it believes it is resumed in a new
216 * domain context.
217 * (2) should be used only for guests which cannot handle the special
218 * new return code. (1) is always safe (but slower).
219 */
220 int xc_domain_resume(int xc_handle, uint32_t domid, int fast)
221 {
222 return (fast
223 ? xc_domain_resume_cooperative(xc_handle, domid)
224 : xc_domain_resume_any(xc_handle, domid));
225 }