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