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 *size_mb = domctl.u.paging_mempool.size;
121
122 return 0;
123 }
124
xen_domctl_set_paging_mempool_size(int domid,uint64_t size_mb)125 int xen_domctl_set_paging_mempool_size(int domid, uint64_t size_mb)
126 {
127 xen_domctl_t domctl = {
128 .cmd = XEN_DOMCTL_set_paging_mempool_size,
129 .domain = domid,
130 .u.paging_mempool.size = size_mb,
131 };
132
133 return do_domctl(&domctl);
134 }
135
xen_domctl_max_mem(int domid,uint64_t max_memkb)136 int xen_domctl_max_mem(int domid, uint64_t max_memkb)
137 {
138 xen_domctl_t domctl = {
139 .cmd = XEN_DOMCTL_max_mem,
140 .domain = domid,
141 .u.max_mem.max_memkb = max_memkb,
142 };
143
144 return do_domctl(&domctl);
145 }
146
xen_domctl_set_address_size(int domid,int addr_size)147 int xen_domctl_set_address_size(int domid, int addr_size)
148 {
149 xen_domctl_t domctl = {
150 .domain = domid,
151 .cmd = XEN_DOMCTL_set_address_size,
152 .u.address_size.size = addr_size,
153 };
154
155 return do_domctl(&domctl);
156 }
157
xen_domctl_iomem_permission(int domid,uint64_t first_mfn,uint64_t nr_mfns,uint8_t allow_access)158 int xen_domctl_iomem_permission(int domid, uint64_t first_mfn,
159 uint64_t nr_mfns, uint8_t allow_access)
160 {
161 xen_domctl_t domctl = {
162 .domain = domid,
163 .cmd = XEN_DOMCTL_iomem_permission,
164 .u.iomem_permission.first_mfn = first_mfn,
165 .u.iomem_permission.nr_mfns = nr_mfns,
166 .u.iomem_permission.allow_access = allow_access,
167 };
168
169 return do_domctl(&domctl);
170 }
171
xen_domctl_memory_mapping(int domid,uint64_t first_gfn,uint64_t first_mfn,uint64_t nr_mfns,uint32_t add_mapping)172 int xen_domctl_memory_mapping(int domid, uint64_t first_gfn, uint64_t first_mfn,
173 uint64_t nr_mfns, uint32_t add_mapping)
174 {
175 int ret;
176 uint64_t curr, nr_max, done;
177 xen_domctl_t domctl = {
178 .domain = domid,
179 .cmd = XEN_DOMCTL_memory_mapping,
180 .u.memory_mapping.add_mapping = add_mapping,
181 };
182
183 if (!nr_mfns) {
184 return 0;
185 }
186
187 /* nr_mfns can be big and we need to handle this here */
188 done = 0;
189 nr_max = nr_mfns;
190 do {
191 domctl.u.memory_mapping.first_gfn = first_gfn + done;
192 domctl.u.memory_mapping.first_mfn = first_mfn + done;
193
194 curr = MIN(nr_mfns - done, nr_max);
195 domctl.u.memory_mapping.nr_mfns = curr;
196
197 ret = do_domctl(&domctl);
198 if (ret < 0) {
199 if (ret == -E2BIG) {
200 /* Check if we not reach min amount */
201 if (nr_max <= 1) {
202 break;
203 }
204
205 /* Decrease amount twice and try again */
206 nr_max = nr_max >> 1;
207 continue;
208 } else {
209 break;
210 }
211 }
212
213 done += curr;
214 } while (done < nr_mfns);
215
216 /* We may come here when get E2BIG and reach 1 at nr_max */
217 if (!done) {
218 ret = -1;
219 }
220
221 return ret;
222 }
223
xen_domctl_assign_dt_device(int domid,char * dtdev_path)224 int xen_domctl_assign_dt_device(int domid, char *dtdev_path)
225 {
226 xen_domctl_t domctl = {
227 .domain = domid,
228 .cmd = XEN_DOMCTL_assign_device,
229 .u.assign_device.flags = 0,
230 .u.assign_device.dev = XEN_DOMCTL_DEV_DT,
231 .u.assign_device.u.dt.size = strlen(dtdev_path),
232 };
233
234 set_xen_guest_handle(domctl.u.assign_device.u.dt.path, dtdev_path);
235
236 return do_domctl(&domctl);
237
238 }
239
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)240 int xen_domctl_bind_pt_irq(int domid, uint32_t machine_irq, uint8_t irq_type,
241 uint8_t bus, uint8_t device, uint8_t intx, uint8_t isa_irq,
242 uint16_t spi)
243 {
244 xen_domctl_t domctl = {
245 .domain = domid,
246 .cmd = XEN_DOMCTL_bind_pt_irq,
247 };
248 struct xen_domctl_bind_pt_irq *bind = &(domctl.u.bind_pt_irq);
249
250 switch (irq_type) {
251 case PT_IRQ_TYPE_SPI:
252 bind->irq_type = irq_type;
253 bind->machine_irq = machine_irq;
254 bind->u.spi.spi = spi;
255 break;
256 default:
257 /* TODO: implement other types */
258 return -ENOTSUP;
259 }
260
261 return do_domctl(&domctl);
262 }
263
xen_domctl_max_vcpus(int domid,int max_vcpus)264 int xen_domctl_max_vcpus(int domid, int max_vcpus)
265 {
266 xen_domctl_t domctl = {
267 .cmd = XEN_DOMCTL_max_vcpus,
268 .domain = domid,
269 .u.max_vcpus.max = max_vcpus,
270 };
271
272 return do_domctl(&domctl);
273 }
274
xen_domctl_createdomain(int domid,struct xen_domctl_createdomain * config)275 int xen_domctl_createdomain(int domid, struct xen_domctl_createdomain *config)
276 {
277 xen_domctl_t domctl = {
278 .cmd = XEN_DOMCTL_createdomain,
279 .domain = domid,
280 .u.createdomain = *config,
281 };
282
283 return do_domctl(&domctl);
284 }
285
xen_domctl_destroydomain(int domid)286 int xen_domctl_destroydomain(int domid)
287 {
288 xen_domctl_t domctl = {
289 .cmd = XEN_DOMCTL_destroydomain,
290 .domain = domid,
291 };
292
293 return do_domctl(&domctl);
294 }
295
xen_domctl_cacheflush(int domid,struct xen_domctl_cacheflush * cacheflush)296 int xen_domctl_cacheflush(int domid, struct xen_domctl_cacheflush *cacheflush)
297 {
298 xen_domctl_t domctl = {
299 .cmd = XEN_DOMCTL_cacheflush,
300 .domain = domid,
301 .u.cacheflush = *cacheflush,
302 };
303
304 return do_domctl(&domctl);
305 }
306