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