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