1 /******************************************************************************
2 *
3 * xc_altp2m.c
4 *
5 * Interface to altp2m related HVMOPs
6 *
7 * Copyright (c) 2015 Tamas K Lengyel (tamas@tklengyel.com)
8 *
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License as published by the Free Software Foundation; either
12 * version 2.1 of the License, or (at your option) any later version.
13 *
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
18 *
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with this library; If not, see <http://www.gnu.org/licenses/>.
21 */
22
23 #include "xc_private.h"
24 #include <stdbool.h>
25 #include <xen/hvm/hvm_op.h>
26
xc_altp2m_get_domain_state(xc_interface * handle,uint32_t dom,bool * state)27 int xc_altp2m_get_domain_state(xc_interface *handle, uint32_t dom, bool *state)
28 {
29 int rc;
30 DECLARE_HYPERCALL_BUFFER(xen_hvm_altp2m_op_t, arg);
31
32 arg = xc_hypercall_buffer_alloc(handle, arg, sizeof(*arg));
33 if ( arg == NULL )
34 return -1;
35
36 arg->version = HVMOP_ALTP2M_INTERFACE_VERSION;
37 arg->cmd = HVMOP_altp2m_get_domain_state;
38 arg->domain = dom;
39
40 rc = xencall2(handle->xcall, __HYPERVISOR_hvm_op, HVMOP_altp2m,
41 HYPERCALL_BUFFER_AS_ARG(arg));
42
43 if ( !rc )
44 *state = arg->u.domain_state.state;
45
46 xc_hypercall_buffer_free(handle, arg);
47 return rc;
48 }
49
xc_altp2m_set_domain_state(xc_interface * handle,uint32_t dom,bool state)50 int xc_altp2m_set_domain_state(xc_interface *handle, uint32_t dom, bool state)
51 {
52 int rc;
53 DECLARE_HYPERCALL_BUFFER(xen_hvm_altp2m_op_t, arg);
54
55 arg = xc_hypercall_buffer_alloc(handle, arg, sizeof(*arg));
56 if ( arg == NULL )
57 return -1;
58
59 arg->version = HVMOP_ALTP2M_INTERFACE_VERSION;
60 arg->cmd = HVMOP_altp2m_set_domain_state;
61 arg->domain = dom;
62 arg->u.domain_state.state = state;
63
64 rc = xencall2(handle->xcall, __HYPERVISOR_hvm_op, HVMOP_altp2m,
65 HYPERCALL_BUFFER_AS_ARG(arg));
66
67 xc_hypercall_buffer_free(handle, arg);
68 return rc;
69 }
70
xc_altp2m_set_vcpu_enable_notify(xc_interface * handle,uint32_t domid,uint32_t vcpuid,xen_pfn_t gfn)71 int xc_altp2m_set_vcpu_enable_notify(xc_interface *handle, uint32_t domid,
72 uint32_t vcpuid, xen_pfn_t gfn)
73 {
74 int rc;
75 DECLARE_HYPERCALL_BUFFER(xen_hvm_altp2m_op_t, arg);
76
77 arg = xc_hypercall_buffer_alloc(handle, arg, sizeof(*arg));
78 if ( arg == NULL )
79 return -1;
80
81 arg->version = HVMOP_ALTP2M_INTERFACE_VERSION;
82 arg->cmd = HVMOP_altp2m_vcpu_enable_notify;
83 arg->domain = domid;
84 arg->u.enable_notify.vcpu_id = vcpuid;
85 arg->u.enable_notify.gfn = gfn;
86
87 rc = xencall2(handle->xcall, __HYPERVISOR_hvm_op, HVMOP_altp2m,
88 HYPERCALL_BUFFER_AS_ARG(arg));
89
90 xc_hypercall_buffer_free(handle, arg);
91 return rc;
92 }
93
xc_altp2m_set_vcpu_disable_notify(xc_interface * handle,uint32_t domid,uint32_t vcpuid)94 int xc_altp2m_set_vcpu_disable_notify(xc_interface *handle, uint32_t domid,
95 uint32_t vcpuid)
96 {
97 int rc;
98 DECLARE_HYPERCALL_BUFFER(xen_hvm_altp2m_op_t, arg);
99
100 arg = xc_hypercall_buffer_alloc(handle, arg, sizeof(*arg));
101 if ( arg == NULL )
102 return -1;
103
104 arg->version = HVMOP_ALTP2M_INTERFACE_VERSION;
105 arg->cmd = HVMOP_altp2m_vcpu_disable_notify;
106 arg->domain = domid;
107 arg->u.disable_notify.vcpu_id = vcpuid;
108
109 rc = xencall2(handle->xcall, __HYPERVISOR_hvm_op, HVMOP_altp2m,
110 HYPERCALL_BUFFER_AS_ARG(arg));
111
112 xc_hypercall_buffer_free(handle, arg);
113 return rc;
114 }
115
xc_altp2m_create_view(xc_interface * handle,uint32_t domid,xenmem_access_t default_access,uint16_t * view_id)116 int xc_altp2m_create_view(xc_interface *handle, uint32_t domid,
117 xenmem_access_t default_access, uint16_t *view_id)
118 {
119 int rc;
120 DECLARE_HYPERCALL_BUFFER(xen_hvm_altp2m_op_t, arg);
121
122 arg = xc_hypercall_buffer_alloc(handle, arg, sizeof(*arg));
123 if ( arg == NULL )
124 return -1;
125
126 arg->version = HVMOP_ALTP2M_INTERFACE_VERSION;
127 arg->cmd = HVMOP_altp2m_create_p2m;
128 arg->domain = domid;
129 arg->u.view.view = -1;
130 arg->u.view.hvmmem_default_access = default_access;
131
132 rc = xencall2(handle->xcall, __HYPERVISOR_hvm_op, HVMOP_altp2m,
133 HYPERCALL_BUFFER_AS_ARG(arg));
134
135 if ( !rc )
136 *view_id = arg->u.view.view;
137
138 xc_hypercall_buffer_free(handle, arg);
139 return rc;
140 }
141
xc_altp2m_destroy_view(xc_interface * handle,uint32_t domid,uint16_t view_id)142 int xc_altp2m_destroy_view(xc_interface *handle, uint32_t domid,
143 uint16_t view_id)
144 {
145 int rc;
146 DECLARE_HYPERCALL_BUFFER(xen_hvm_altp2m_op_t, arg);
147
148 arg = xc_hypercall_buffer_alloc(handle, arg, sizeof(*arg));
149 if ( arg == NULL )
150 return -1;
151
152 arg->version = HVMOP_ALTP2M_INTERFACE_VERSION;
153 arg->cmd = HVMOP_altp2m_destroy_p2m;
154 arg->domain = domid;
155 arg->u.view.view = view_id;
156
157 rc = xencall2(handle->xcall, __HYPERVISOR_hvm_op, HVMOP_altp2m,
158 HYPERCALL_BUFFER_AS_ARG(arg));
159
160 xc_hypercall_buffer_free(handle, arg);
161 return rc;
162 }
163
164 /* Switch all vCPUs of the domain to the specified altp2m view */
xc_altp2m_switch_to_view(xc_interface * handle,uint32_t domid,uint16_t view_id)165 int xc_altp2m_switch_to_view(xc_interface *handle, uint32_t domid,
166 uint16_t view_id)
167 {
168 int rc;
169 DECLARE_HYPERCALL_BUFFER(xen_hvm_altp2m_op_t, arg);
170
171 arg = xc_hypercall_buffer_alloc(handle, arg, sizeof(*arg));
172 if ( arg == NULL )
173 return -1;
174
175 arg->version = HVMOP_ALTP2M_INTERFACE_VERSION;
176 arg->cmd = HVMOP_altp2m_switch_p2m;
177 arg->domain = domid;
178 arg->u.view.view = view_id;
179
180 rc = xencall2(handle->xcall, __HYPERVISOR_hvm_op, HVMOP_altp2m,
181 HYPERCALL_BUFFER_AS_ARG(arg));
182
183 xc_hypercall_buffer_free(handle, arg);
184 return rc;
185 }
186
xc_altp2m_get_suppress_ve(xc_interface * handle,uint32_t domid,uint16_t view_id,xen_pfn_t gfn,bool * sve)187 int xc_altp2m_get_suppress_ve(xc_interface *handle, uint32_t domid,
188 uint16_t view_id, xen_pfn_t gfn, bool *sve)
189 {
190 int rc;
191 DECLARE_HYPERCALL_BUFFER(xen_hvm_altp2m_op_t, arg);
192
193 arg = xc_hypercall_buffer_alloc(handle, arg, sizeof(*arg));
194 if ( arg == NULL )
195 return -1;
196
197 arg->version = HVMOP_ALTP2M_INTERFACE_VERSION;
198 arg->cmd = HVMOP_altp2m_get_suppress_ve;
199 arg->domain = domid;
200 arg->u.suppress_ve.view = view_id;
201 arg->u.suppress_ve.gfn = gfn;
202
203 rc = xencall2(handle->xcall, __HYPERVISOR_hvm_op, HVMOP_altp2m,
204 HYPERCALL_BUFFER_AS_ARG(arg));
205
206 if ( !rc )
207 *sve = arg->u.suppress_ve.suppress_ve;
208
209 xc_hypercall_buffer_free(handle, arg);
210 return rc;
211 }
212
xc_altp2m_set_suppress_ve(xc_interface * handle,uint32_t domid,uint16_t view_id,xen_pfn_t gfn,bool sve)213 int xc_altp2m_set_suppress_ve(xc_interface *handle, uint32_t domid,
214 uint16_t view_id, xen_pfn_t gfn, bool sve)
215 {
216 int rc;
217 DECLARE_HYPERCALL_BUFFER(xen_hvm_altp2m_op_t, arg);
218
219 arg = xc_hypercall_buffer_alloc(handle, arg, sizeof(*arg));
220 if ( arg == NULL )
221 return -1;
222
223 arg->version = HVMOP_ALTP2M_INTERFACE_VERSION;
224 arg->cmd = HVMOP_altp2m_set_suppress_ve;
225 arg->domain = domid;
226 arg->u.suppress_ve.view = view_id;
227 arg->u.suppress_ve.gfn = gfn;
228 arg->u.suppress_ve.suppress_ve = sve;
229
230 rc = xencall2(handle->xcall, __HYPERVISOR_hvm_op, HVMOP_altp2m,
231 HYPERCALL_BUFFER_AS_ARG(arg));
232
233 xc_hypercall_buffer_free(handle, arg);
234 return rc;
235 }
236
xc_altp2m_set_supress_ve_multi(xc_interface * handle,uint32_t domid,uint16_t view_id,xen_pfn_t first_gfn,xen_pfn_t last_gfn,bool sve,xen_pfn_t * error_gfn,int32_t * error_code)237 int xc_altp2m_set_supress_ve_multi(xc_interface *handle, uint32_t domid,
238 uint16_t view_id, xen_pfn_t first_gfn,
239 xen_pfn_t last_gfn, bool sve,
240 xen_pfn_t *error_gfn, int32_t *error_code)
241 {
242 int rc;
243 DECLARE_HYPERCALL_BUFFER(xen_hvm_altp2m_op_t, arg);
244
245 arg = xc_hypercall_buffer_alloc(handle, arg, sizeof(*arg));
246 if ( arg == NULL )
247 return -1;
248
249 arg->version = HVMOP_ALTP2M_INTERFACE_VERSION;
250 arg->cmd = HVMOP_altp2m_set_suppress_ve_multi;
251 arg->domain = domid;
252 arg->u.suppress_ve_multi.view = view_id;
253 arg->u.suppress_ve_multi.first_gfn = first_gfn;
254 arg->u.suppress_ve_multi.last_gfn = last_gfn;
255 arg->u.suppress_ve_multi.suppress_ve = sve;
256
257 rc = xencall2(handle->xcall, __HYPERVISOR_hvm_op, HVMOP_altp2m,
258 HYPERCALL_BUFFER_AS_ARG(arg));
259
260 if ( arg->u.suppress_ve_multi.first_error )
261 {
262 *error_gfn = arg->u.suppress_ve_multi.first_error_gfn;
263 *error_code = arg->u.suppress_ve_multi.first_error;
264 }
265
266 xc_hypercall_buffer_free(handle, arg);
267 return rc;
268 }
269
xc_altp2m_set_mem_access(xc_interface * handle,uint32_t domid,uint16_t view_id,xen_pfn_t gfn,xenmem_access_t access)270 int xc_altp2m_set_mem_access(xc_interface *handle, uint32_t domid,
271 uint16_t view_id, xen_pfn_t gfn,
272 xenmem_access_t access)
273 {
274 int rc;
275 DECLARE_HYPERCALL_BUFFER(xen_hvm_altp2m_op_t, arg);
276
277 arg = xc_hypercall_buffer_alloc(handle, arg, sizeof(*arg));
278 if ( arg == NULL )
279 return -1;
280
281 arg->version = HVMOP_ALTP2M_INTERFACE_VERSION;
282 arg->cmd = HVMOP_altp2m_set_mem_access;
283 arg->domain = domid;
284 arg->u.mem_access.view = view_id;
285 arg->u.mem_access.access = access;
286 arg->u.mem_access.gfn = gfn;
287
288 rc = xencall2(handle->xcall, __HYPERVISOR_hvm_op, HVMOP_altp2m,
289 HYPERCALL_BUFFER_AS_ARG(arg));
290
291 xc_hypercall_buffer_free(handle, arg);
292 return rc;
293 }
294
xc_altp2m_change_gfn(xc_interface * handle,uint32_t domid,uint16_t view_id,xen_pfn_t old_gfn,xen_pfn_t new_gfn)295 int xc_altp2m_change_gfn(xc_interface *handle, uint32_t domid,
296 uint16_t view_id, xen_pfn_t old_gfn,
297 xen_pfn_t new_gfn)
298 {
299 int rc;
300 DECLARE_HYPERCALL_BUFFER(xen_hvm_altp2m_op_t, arg);
301
302 arg = xc_hypercall_buffer_alloc(handle, arg, sizeof(*arg));
303 if ( arg == NULL )
304 return -1;
305
306 arg->version = HVMOP_ALTP2M_INTERFACE_VERSION;
307 arg->cmd = HVMOP_altp2m_change_gfn;
308 arg->domain = domid;
309 arg->u.change_gfn.view = view_id;
310 arg->u.change_gfn.old_gfn = old_gfn;
311 arg->u.change_gfn.new_gfn = new_gfn;
312
313 rc = xencall2(handle->xcall, __HYPERVISOR_hvm_op, HVMOP_altp2m,
314 HYPERCALL_BUFFER_AS_ARG(arg));
315
316 xc_hypercall_buffer_free(handle, arg);
317 return rc;
318 }
319
xc_altp2m_set_mem_access_multi(xc_interface * xch,uint32_t domid,uint16_t view_id,uint8_t * access,uint64_t * gfns,uint32_t nr)320 int xc_altp2m_set_mem_access_multi(xc_interface *xch, uint32_t domid,
321 uint16_t view_id, uint8_t *access,
322 uint64_t *gfns, uint32_t nr)
323 {
324 int rc;
325
326 DECLARE_HYPERCALL_BUFFER(xen_hvm_altp2m_op_t, arg);
327 DECLARE_HYPERCALL_BOUNCE(access, nr * sizeof(*access),
328 XC_HYPERCALL_BUFFER_BOUNCE_IN);
329 DECLARE_HYPERCALL_BOUNCE(gfns, nr * sizeof(*gfns),
330 XC_HYPERCALL_BUFFER_BOUNCE_IN);
331
332 arg = xc_hypercall_buffer_alloc(xch, arg, sizeof(*arg));
333 if ( arg == NULL )
334 return -1;
335
336 arg->version = HVMOP_ALTP2M_INTERFACE_VERSION;
337 arg->cmd = HVMOP_altp2m_set_mem_access_multi;
338 arg->domain = domid;
339 arg->u.set_mem_access_multi.view = view_id;
340 arg->u.set_mem_access_multi.nr = nr;
341
342 if ( xc_hypercall_bounce_pre(xch, gfns) ||
343 xc_hypercall_bounce_pre(xch, access) )
344 {
345 PERROR("Could not bounce memory for HVMOP_altp2m_set_mem_access_multi");
346 return -1;
347 }
348
349 set_xen_guest_handle(arg->u.set_mem_access_multi.pfn_list, gfns);
350 set_xen_guest_handle(arg->u.set_mem_access_multi.access_list, access);
351
352 rc = xencall2(xch->xcall, __HYPERVISOR_hvm_op, HVMOP_altp2m,
353 HYPERCALL_BUFFER_AS_ARG(arg));
354
355 xc_hypercall_buffer_free(xch, arg);
356 xc_hypercall_bounce_post(xch, access);
357 xc_hypercall_bounce_post(xch, gfns);
358
359 return rc;
360 }
361
xc_altp2m_get_mem_access(xc_interface * handle,uint32_t domid,uint16_t view_id,xen_pfn_t gfn,xenmem_access_t * access)362 int xc_altp2m_get_mem_access(xc_interface *handle, uint32_t domid,
363 uint16_t view_id, xen_pfn_t gfn,
364 xenmem_access_t *access)
365 {
366 int rc;
367 DECLARE_HYPERCALL_BUFFER(xen_hvm_altp2m_op_t, arg);
368
369 arg = xc_hypercall_buffer_alloc(handle, arg, sizeof(*arg));
370 if ( arg == NULL )
371 return -1;
372
373 arg->version = HVMOP_ALTP2M_INTERFACE_VERSION;
374 arg->cmd = HVMOP_altp2m_get_mem_access;
375 arg->domain = domid;
376 arg->u.mem_access.view = view_id;
377 arg->u.mem_access.gfn = gfn;
378
379 rc = xencall2(handle->xcall, __HYPERVISOR_hvm_op, HVMOP_altp2m,
380 HYPERCALL_BUFFER_AS_ARG(arg));
381
382 if ( !rc )
383 *access = arg->u.mem_access.access;
384
385 xc_hypercall_buffer_free(handle, arg);
386 return rc;
387 }
388
xc_altp2m_get_vcpu_p2m_idx(xc_interface * handle,uint32_t domid,uint32_t vcpuid,uint16_t * altp2m_idx)389 int xc_altp2m_get_vcpu_p2m_idx(xc_interface *handle, uint32_t domid,
390 uint32_t vcpuid, uint16_t *altp2m_idx)
391 {
392 int rc;
393
394 DECLARE_HYPERCALL_BUFFER(xen_hvm_altp2m_op_t, arg);
395
396 arg = xc_hypercall_buffer_alloc(handle, arg, sizeof(*arg));
397 if ( arg == NULL )
398 return -1;
399
400 arg->version = HVMOP_ALTP2M_INTERFACE_VERSION;
401 arg->cmd = HVMOP_altp2m_get_p2m_idx;
402 arg->domain = domid;
403 arg->u.get_vcpu_p2m_idx.vcpu_id = vcpuid;
404
405 rc = xencall2(handle->xcall, __HYPERVISOR_hvm_op, HVMOP_altp2m,
406 HYPERCALL_BUFFER_AS_ARG(arg));
407 if ( !rc )
408 *altp2m_idx = arg->u.get_vcpu_p2m_idx.altp2m_idx;
409
410 xc_hypercall_buffer_free(handle, arg);
411 return rc;
412 }
413
xc_altp2m_set_visibility(xc_interface * handle,uint32_t domid,uint16_t view_id,bool visible)414 int xc_altp2m_set_visibility(xc_interface *handle, uint32_t domid,
415 uint16_t view_id, bool visible)
416 {
417 int rc;
418
419 DECLARE_HYPERCALL_BUFFER(xen_hvm_altp2m_op_t, arg);
420
421 arg = xc_hypercall_buffer_alloc(handle, arg, sizeof(*arg));
422 if ( arg == NULL )
423 return -1;
424
425 arg->version = HVMOP_ALTP2M_INTERFACE_VERSION;
426 arg->cmd = HVMOP_altp2m_set_visibility;
427 arg->domain = domid;
428 arg->u.set_visibility.altp2m_idx = view_id;
429 arg->u.set_visibility.visible = visible;
430
431 rc = xencall2(handle->xcall, __HYPERVISOR_hvm_op, HVMOP_altp2m,
432 HYPERCALL_BUFFER_AS_ARG(arg));
433
434 xc_hypercall_buffer_free(handle, arg);
435 return rc;
436 }
437