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