1 /* SPDX-License-Identifier: Apache-2.0 */
2 /*
3 * Copyright (c) 2023 EPAM Systems
4 *
5 */
6
7 #include <zephyr/arch/arm64/hypercall.h>
8 #include <zephyr/xen/dom0/domctl.h>
9 #include <zephyr/xen/generic.h>
10 #include <zephyr/xen/public/domctl.h>
11 #include <zephyr/xen/public/xen.h>
12
13 #include <zephyr/init.h>
14 #include <zephyr/kernel.h>
15 #include <string.h>
16
do_domctl(xen_domctl_t * domctl)17 static int do_domctl(xen_domctl_t *domctl)
18 {
19 domctl->interface_version = XEN_DOMCTL_INTERFACE_VERSION;
20 return HYPERVISOR_domctl(domctl);
21 }
22
xen_domctl_scheduler_op(int domid,struct xen_domctl_scheduler_op * sched_op)23 int xen_domctl_scheduler_op(int domid, struct xen_domctl_scheduler_op *sched_op)
24 {
25 xen_domctl_t domctl = {
26 .cmd = XEN_DOMCTL_scheduler_op,
27 .domain = domid,
28 .u.scheduler_op = *sched_op,
29 };
30
31 return do_domctl(&domctl);
32 }
33
xen_domctl_pausedomain(int domid)34 int xen_domctl_pausedomain(int domid)
35 {
36 xen_domctl_t domctl = {
37 .cmd = XEN_DOMCTL_pausedomain,
38 .domain = domid,
39 };
40
41 return do_domctl(&domctl);
42 }
43
xen_domctl_unpausedomain(int domid)44 int xen_domctl_unpausedomain(int domid)
45 {
46 xen_domctl_t domctl = {
47 .cmd = XEN_DOMCTL_unpausedomain,
48 .domain = domid,
49 };
50
51 return do_domctl(&domctl);
52 }
53
xen_domctl_resumedomain(int domid)54 int xen_domctl_resumedomain(int domid)
55 {
56 xen_domctl_t domctl = {
57 .cmd = XEN_DOMCTL_resumedomain,
58 .domain = domid,
59 };
60
61 return do_domctl(&domctl);
62 }
63
xen_domctl_getvcpucontext(int domid,int vcpu,vcpu_guest_context_t * ctxt)64 int xen_domctl_getvcpucontext(int domid, int vcpu, vcpu_guest_context_t *ctxt)
65 {
66 xen_domctl_t domctl = {
67 .cmd = XEN_DOMCTL_getvcpucontext,
68 .domain = domid,
69 .u.vcpucontext.vcpu = 0,
70 };
71
72 set_xen_guest_handle(domctl.u.vcpucontext.ctxt, ctxt);
73
74 return do_domctl(&domctl);
75 }
76
xen_domctl_setvcpucontext(int domid,int vcpu,vcpu_guest_context_t * ctxt)77 int xen_domctl_setvcpucontext(int domid, int vcpu, vcpu_guest_context_t *ctxt)
78 {
79 xen_domctl_t domctl = {
80 .cmd = XEN_DOMCTL_setvcpucontext,
81 .domain = domid,
82 .u.vcpucontext.vcpu = 0,
83 };
84
85 set_xen_guest_handle(domctl.u.vcpucontext.ctxt, ctxt);
86
87 return do_domctl(&domctl);
88 }
89
xen_domctl_getdomaininfo(int domid,xen_domctl_getdomaininfo_t * dom_info)90 int xen_domctl_getdomaininfo(int domid, xen_domctl_getdomaininfo_t *dom_info)
91 {
92 int rc;
93 xen_domctl_t domctl = {
94 .cmd = XEN_DOMCTL_getdomaininfo,
95 .domain = domid,
96 };
97
98 rc = do_domctl(&domctl);
99 if (rc) {
100 return rc;
101 }
102
103 memcpy(dom_info, &domctl.u.getdomaininfo, sizeof(*dom_info));
104
105 return 0;
106 }
107
xen_domctl_get_paging_mempool_size(int domid,uint64_t * size_mb)108 int xen_domctl_get_paging_mempool_size(int domid, uint64_t *size_mb)
109 {
110 int rc;
111 xen_domctl_t domctl = {
112 .cmd = XEN_DOMCTL_get_paging_mempool_size,
113 .domain = domid,
114 };
115
116 rc = do_domctl(&domctl);
117 if (rc) {
118 return rc;
119 }
120
121 *size_mb = domctl.u.paging_mempool.size;
122
123 return 0;
124 }
125
xen_domctl_set_paging_mempool_size(int domid,uint64_t size_mb)126 int xen_domctl_set_paging_mempool_size(int domid, uint64_t size_mb)
127 {
128 xen_domctl_t domctl = {
129 .cmd = XEN_DOMCTL_set_paging_mempool_size,
130 .domain = domid,
131 .u.paging_mempool.size = size_mb,
132 };
133
134 return do_domctl(&domctl);
135 }
136
xen_domctl_max_mem(int domid,uint64_t max_memkb)137 int xen_domctl_max_mem(int domid, uint64_t max_memkb)
138 {
139 xen_domctl_t domctl = {
140 .cmd = XEN_DOMCTL_max_mem,
141 .domain = domid,
142 .u.max_mem.max_memkb = max_memkb,
143 };
144
145 return do_domctl(&domctl);
146 }
147
xen_domctl_set_address_size(int domid,int addr_size)148 int xen_domctl_set_address_size(int domid, int addr_size)
149 {
150 xen_domctl_t domctl = {
151 .domain = domid,
152 .cmd = XEN_DOMCTL_set_address_size,
153 .u.address_size.size = addr_size,
154 };
155
156 return do_domctl(&domctl);
157 }
158
xen_domctl_iomem_permission(int domid,uint64_t first_mfn,uint64_t nr_mfns,uint8_t allow_access)159 int xen_domctl_iomem_permission(int domid, uint64_t first_mfn,
160 uint64_t nr_mfns, uint8_t allow_access)
161 {
162 xen_domctl_t domctl = {
163 .domain = domid,
164 .cmd = XEN_DOMCTL_iomem_permission,
165 .u.iomem_permission.first_mfn = first_mfn,
166 .u.iomem_permission.nr_mfns = nr_mfns,
167 .u.iomem_permission.allow_access = allow_access,
168 };
169
170 return do_domctl(&domctl);
171 }
172
xen_domctl_memory_mapping(int domid,uint64_t first_gfn,uint64_t first_mfn,uint64_t nr_mfns,uint32_t add_mapping)173 int xen_domctl_memory_mapping(int domid, uint64_t first_gfn, uint64_t first_mfn,
174 uint64_t nr_mfns, uint32_t add_mapping)
175 {
176 int ret;
177 uint64_t curr, nr_max, done;
178 xen_domctl_t domctl = {
179 .domain = domid,
180 .cmd = XEN_DOMCTL_memory_mapping,
181 .u.memory_mapping.add_mapping = add_mapping,
182 };
183
184 if (!nr_mfns) {
185 return 0;
186 }
187
188 /* nr_mfns can be big and we need to handle this here */
189 done = 0;
190 nr_max = nr_mfns;
191 do {
192 domctl.u.memory_mapping.first_gfn = first_gfn + done;
193 domctl.u.memory_mapping.first_mfn = first_mfn + done;
194
195 curr = MIN(nr_mfns - done, nr_max);
196 domctl.u.memory_mapping.nr_mfns = curr;
197
198 ret = do_domctl(&domctl);
199 if (ret < 0) {
200 if (ret == -E2BIG) {
201 /* Check if we not reach min amount */
202 if (nr_max <= 1) {
203 break;
204 }
205
206 /* Decrease amount twice and try again */
207 nr_max = nr_max >> 1;
208 continue;
209 } else {
210 break;
211 }
212 }
213
214 done += curr;
215 } while (done < nr_mfns);
216
217 /* We may come here when get E2BIG and reach 1 at nr_max */
218 if (!done) {
219 ret = -1;
220 }
221
222 return ret;
223 }
224
xen_domctl_assign_dt_device(int domid,char * dtdev_path)225 int xen_domctl_assign_dt_device(int domid, char *dtdev_path)
226 {
227 xen_domctl_t domctl = {
228 .domain = domid,
229 .cmd = XEN_DOMCTL_assign_device,
230 .u.assign_device.flags = 0,
231 .u.assign_device.dev = XEN_DOMCTL_DEV_DT,
232 .u.assign_device.u.dt.size = strlen(dtdev_path),
233 };
234
235 set_xen_guest_handle(domctl.u.assign_device.u.dt.path, dtdev_path);
236
237 return do_domctl(&domctl);
238
239 }
240
xen_domctl_bind_pt_irq(int domid,uint32_t machine_irq,uint8_t irq_type,uint8_t bus,uint8_t device,uint8_t intx,uint8_t isa_irq,uint16_t spi)241 int xen_domctl_bind_pt_irq(int domid, uint32_t machine_irq, uint8_t irq_type,
242 uint8_t bus, uint8_t device, uint8_t intx, uint8_t isa_irq,
243 uint16_t spi)
244 {
245 xen_domctl_t domctl = {
246 .domain = domid,
247 .cmd = XEN_DOMCTL_bind_pt_irq,
248 };
249 struct xen_domctl_bind_pt_irq *bind = &(domctl.u.bind_pt_irq);
250
251 switch (irq_type) {
252 case PT_IRQ_TYPE_SPI:
253 bind->irq_type = irq_type;
254 bind->machine_irq = machine_irq;
255 bind->u.spi.spi = spi;
256 break;
257 default:
258 /* TODO: implement other types */
259 return -ENOTSUP;
260 }
261
262 return do_domctl(&domctl);
263 }
264
xen_domctl_max_vcpus(int domid,int max_vcpus)265 int xen_domctl_max_vcpus(int domid, int max_vcpus)
266 {
267 xen_domctl_t domctl = {
268 .cmd = XEN_DOMCTL_max_vcpus,
269 .domain = domid,
270 .u.max_vcpus.max = max_vcpus,
271 };
272
273 return do_domctl(&domctl);
274 }
275
xen_domctl_createdomain(int domid,struct xen_domctl_createdomain * config)276 int xen_domctl_createdomain(int domid, struct xen_domctl_createdomain *config)
277 {
278 xen_domctl_t domctl = {
279 .cmd = XEN_DOMCTL_createdomain,
280 .domain = domid,
281 .u.createdomain = *config,
282 };
283
284 return do_domctl(&domctl);
285 }
286
xen_domctl_destroydomain(int domid)287 int xen_domctl_destroydomain(int domid)
288 {
289 xen_domctl_t domctl = {
290 .cmd = XEN_DOMCTL_destroydomain,
291 .domain = domid,
292 };
293
294 return do_domctl(&domctl);
295 }
296
xen_domctl_cacheflush(int domid,struct xen_domctl_cacheflush * cacheflush)297 int xen_domctl_cacheflush(int domid, struct xen_domctl_cacheflush *cacheflush)
298 {
299 xen_domctl_t domctl = {
300 .cmd = XEN_DOMCTL_cacheflush,
301 .domain = domid,
302 .u.cacheflush = *cacheflush,
303 };
304
305 return do_domctl(&domctl);
306 }
307