1 #include <assert.h>
2
3 #include "xc_sr_common_x86.h"
4
5 #include <xen/hvm/params.h>
6
7 /*
8 * Query for the HVM context and write an HVM_CONTEXT record into the stream.
9 */
write_hvm_context(struct xc_sr_context * ctx)10 static int write_hvm_context(struct xc_sr_context *ctx)
11 {
12 xc_interface *xch = ctx->xch;
13 int rc, hvm_buf_size;
14 struct xc_sr_record hvm_rec = {
15 .type = REC_TYPE_HVM_CONTEXT,
16 };
17
18 hvm_buf_size = xc_domain_hvm_getcontext(xch, ctx->domid, 0, 0);
19 if ( hvm_buf_size < 0 )
20 {
21 PERROR("Couldn't get HVM context size from Xen");
22 rc = -1;
23 goto out;
24 }
25
26 hvm_rec.data = malloc(hvm_buf_size);
27 if ( !hvm_rec.data )
28 {
29 PERROR("Couldn't allocate memory");
30 rc = -1;
31 goto out;
32 }
33
34 hvm_buf_size = xc_domain_hvm_getcontext(xch, ctx->domid,
35 hvm_rec.data, hvm_buf_size);
36 if ( hvm_buf_size < 0 )
37 {
38 PERROR("Couldn't get HVM context from Xen");
39 rc = -1;
40 goto out;
41 }
42
43 hvm_rec.length = hvm_buf_size;
44 rc = write_record(ctx, &hvm_rec);
45 if ( rc < 0 )
46 {
47 PERROR("error write HVM_CONTEXT record");
48 goto out;
49 }
50
51 out:
52 free(hvm_rec.data);
53 return rc;
54 }
55
56 /*
57 * Query for a range of HVM parameters and write an HVM_PARAMS record into the
58 * stream.
59 */
write_hvm_params(struct xc_sr_context * ctx)60 static int write_hvm_params(struct xc_sr_context *ctx)
61 {
62 static const unsigned int params[] = {
63 HVM_PARAM_STORE_PFN,
64 HVM_PARAM_IOREQ_PFN,
65 HVM_PARAM_BUFIOREQ_PFN,
66 HVM_PARAM_PAGING_RING_PFN,
67 HVM_PARAM_MONITOR_RING_PFN,
68 HVM_PARAM_SHARING_RING_PFN,
69 HVM_PARAM_VM86_TSS_SIZED,
70 HVM_PARAM_CONSOLE_PFN,
71 HVM_PARAM_ACPI_IOPORTS_LOCATION,
72 HVM_PARAM_VIRIDIAN,
73 HVM_PARAM_IDENT_PT,
74 HVM_PARAM_VM_GENERATION_ID_ADDR,
75 HVM_PARAM_IOREQ_SERVER_PFN,
76 HVM_PARAM_NR_IOREQ_SERVER_PAGES,
77 HVM_PARAM_X87_FIP_WIDTH,
78 HVM_PARAM_MCA_CAP,
79 };
80
81 xc_interface *xch = ctx->xch;
82 struct xc_sr_rec_hvm_params_entry entries[ARRAY_SIZE(params)];
83 struct xc_sr_rec_hvm_params hdr = {
84 .count = 0,
85 };
86 struct xc_sr_record rec = {
87 .type = REC_TYPE_HVM_PARAMS,
88 .length = sizeof(hdr),
89 .data = &hdr,
90 };
91 unsigned int i;
92 int rc;
93
94 for ( i = 0; i < ARRAY_SIZE(params); i++ )
95 {
96 uint32_t index = params[i];
97 uint64_t value;
98
99 rc = xc_hvm_param_get(xch, ctx->domid, index, &value);
100 if ( rc )
101 {
102 PERROR("Failed to get HVMPARAM at index %u", index);
103 return rc;
104 }
105
106 if ( value != 0 )
107 {
108 entries[hdr.count].index = index;
109 entries[hdr.count].value = value;
110 hdr.count++;
111 }
112 }
113
114 /* No params? Skip this record. */
115 if ( hdr.count == 0 )
116 return 0;
117
118 rc = write_split_record(ctx, &rec, entries, hdr.count * sizeof(*entries));
119 if ( rc )
120 PERROR("Failed to write HVM_PARAMS record");
121
122 return rc;
123 }
124
x86_hvm_pfn_to_gfn(const struct xc_sr_context * ctx,xen_pfn_t pfn)125 static xen_pfn_t x86_hvm_pfn_to_gfn(const struct xc_sr_context *ctx,
126 xen_pfn_t pfn)
127 {
128 /* identity map */
129 return pfn;
130 }
131
x86_hvm_normalise_page(struct xc_sr_context * ctx,xen_pfn_t type,void ** page)132 static int x86_hvm_normalise_page(struct xc_sr_context *ctx,
133 xen_pfn_t type, void **page)
134 {
135 return 0;
136 }
137
x86_hvm_setup(struct xc_sr_context * ctx)138 static int x86_hvm_setup(struct xc_sr_context *ctx)
139 {
140 xc_interface *xch = ctx->xch;
141 xen_pfn_t nr_pfns;
142
143 if ( xc_domain_nr_gpfns(xch, ctx->domid, &nr_pfns) < 0 )
144 {
145 PERROR("Unable to obtain the guest p2m size");
146 return -1;
147 }
148 #ifdef __i386__
149 /* Very large domains (> 1TB) will exhaust virtual address space. */
150 if ( nr_pfns > 0x0fffffff )
151 {
152 errno = E2BIG;
153 PERROR("Cannot save this big a guest");
154 return -1;
155 }
156 #endif
157
158 ctx->save.p2m_size = nr_pfns;
159
160 if ( ctx->save.callbacks->switch_qemu_logdirty(
161 ctx->domid, 1, ctx->save.callbacks->data) )
162 {
163 PERROR("Couldn't enable qemu log-dirty mode");
164 return -1;
165 }
166
167 ctx->x86.hvm.save.qemu_enabled_logdirty = true;
168
169 return 0;
170 }
171
x86_hvm_static_data(struct xc_sr_context * ctx)172 static int x86_hvm_static_data(struct xc_sr_context *ctx)
173 {
174 return write_x86_cpu_policy_records(ctx);
175 }
176
x86_hvm_start_of_stream(struct xc_sr_context * ctx)177 static int x86_hvm_start_of_stream(struct xc_sr_context *ctx)
178 {
179 return 0;
180 }
181
x86_hvm_start_of_checkpoint(struct xc_sr_context * ctx)182 static int x86_hvm_start_of_checkpoint(struct xc_sr_context *ctx)
183 {
184 return 0;
185 }
186
x86_hvm_check_vm_state(struct xc_sr_context * ctx)187 static int x86_hvm_check_vm_state(struct xc_sr_context *ctx)
188 {
189 return 0;
190 }
191
x86_hvm_end_of_checkpoint(struct xc_sr_context * ctx)192 static int x86_hvm_end_of_checkpoint(struct xc_sr_context *ctx)
193 {
194 int rc;
195
196 /* Write the TSC record. */
197 rc = write_x86_tsc_info(ctx);
198 if ( rc )
199 return rc;
200
201 /* Write the HVM_CONTEXT record. */
202 rc = write_hvm_context(ctx);
203 if ( rc )
204 return rc;
205
206 /* Write HVM_PARAMS record contains applicable HVM params. */
207 rc = write_hvm_params(ctx);
208 if ( rc )
209 return rc;
210
211 return 0;
212 }
213
x86_hvm_cleanup(struct xc_sr_context * ctx)214 static int x86_hvm_cleanup(struct xc_sr_context *ctx)
215 {
216 xc_interface *xch = ctx->xch;
217
218 /* If qemu successfully enabled logdirty mode, attempt to disable. */
219 if ( ctx->x86.hvm.save.qemu_enabled_logdirty &&
220 ctx->save.callbacks->switch_qemu_logdirty(
221 ctx->domid, 0, ctx->save.callbacks->data) )
222 {
223 PERROR("Couldn't disable qemu log-dirty mode");
224 return -1;
225 }
226
227 return 0;
228 }
229
230 struct xc_sr_save_ops save_ops_x86_hvm =
231 {
232 .pfn_to_gfn = x86_hvm_pfn_to_gfn,
233 .normalise_page = x86_hvm_normalise_page,
234 .setup = x86_hvm_setup,
235 .static_data = x86_hvm_static_data,
236 .start_of_stream = x86_hvm_start_of_stream,
237 .start_of_checkpoint = x86_hvm_start_of_checkpoint,
238 .end_of_checkpoint = x86_hvm_end_of_checkpoint,
239 .check_vm_state = x86_hvm_check_vm_state,
240 .cleanup = x86_hvm_cleanup,
241 };
242
243 /*
244 * Local variables:
245 * mode: C
246 * c-file-style: "BSD"
247 * c-basic-offset: 4
248 * tab-width: 4
249 * indent-tabs-mode: nil
250 * End:
251 */
252