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