diff --git a/arch/arm64/core/xen/hypercall.S b/arch/arm64/core/xen/hypercall.S index 429b0a4228..063538bae9 100644 --- a/arch/arm64/core/xen/hypercall.S +++ b/arch/arm64/core/xen/hypercall.S @@ -1,7 +1,6 @@ +/* SPDX-License-Identifier: Apache-2.0 */ /* - * Copyright (c) 2021 EPAM Systems - * - * SPDX-License-Identifier: Apache-2.0 + * Copyright (c) 2021-2023 EPAM Systems */ #include @@ -24,3 +23,7 @@ HYPERCALL(sched_op); HYPERCALL(event_channel_op); HYPERCALL(hvm_op); HYPERCALL(memory_op); + +#ifdef CONFIG_XEN_DOM0 +HYPERCALL(domctl); +#endif diff --git a/drivers/xen/CMakeLists.txt b/drivers/xen/CMakeLists.txt index fe5a679fd9..350c6d577b 100644 --- a/drivers/xen/CMakeLists.txt +++ b/drivers/xen/CMakeLists.txt @@ -1,6 +1,8 @@ # SPDX-License-Identifier: Apache-2.0 -# Copyright (c) 2021-2022 EPAM Systems +# Copyright (c) 2021-2023 EPAM Systems zephyr_sources(hvm.c) zephyr_sources(events.c) zephyr_sources_ifdef(CONFIG_XEN_GRANT_TABLE gnttab.c) + +add_subdirectory_ifdef(CONFIG_XEN_DOM0 dom0) diff --git a/drivers/xen/dom0/CMakeLists.txt b/drivers/xen/dom0/CMakeLists.txt new file mode 100644 index 0000000000..c722beb611 --- /dev/null +++ b/drivers/xen/dom0/CMakeLists.txt @@ -0,0 +1,4 @@ +# SPDX-License-Identifier: Apache-2.0 +# Copyright (c) 2023 EPAM Systems + +zephyr_sources(domctl.c) diff --git a/drivers/xen/dom0/domctl.c b/drivers/xen/dom0/domctl.c new file mode 100644 index 0000000000..2b1e3a6ca5 --- /dev/null +++ b/drivers/xen/dom0/domctl.c @@ -0,0 +1,305 @@ +/* SPDX-License-Identifier: Apache-2.0 */ +/* + * Copyright (c) 2023 EPAM Systems + * + */ + +#include +#include +#include +#include +#include + +#include +#include +#include + +static int do_domctl(xen_domctl_t *domctl) +{ + domctl->interface_version = XEN_DOMCTL_INTERFACE_VERSION; + return HYPERVISOR_domctl(domctl); +} + +int xen_domctl_scheduler_op(int domid, struct xen_domctl_scheduler_op *sched_op) +{ + xen_domctl_t domctl = { + .cmd = XEN_DOMCTL_scheduler_op, + .domain = domid, + .u.scheduler_op = *sched_op, + }; + + return do_domctl(&domctl); +} + +int xen_domctl_pausedomain(int domid) +{ + xen_domctl_t domctl = { + .cmd = XEN_DOMCTL_pausedomain, + .domain = domid, + }; + + return do_domctl(&domctl); +} + +int xen_domctl_unpausedomain(int domid) +{ + xen_domctl_t domctl = { + .cmd = XEN_DOMCTL_unpausedomain, + .domain = domid, + }; + + return do_domctl(&domctl); +} + +int xen_domctl_resumedomain(int domid) +{ + xen_domctl_t domctl = { + .cmd = XEN_DOMCTL_resumedomain, + .domain = domid, + }; + + return do_domctl(&domctl); +} + +int xen_domctl_getvcpucontext(int domid, int vcpu, vcpu_guest_context_t *ctxt) +{ + xen_domctl_t domctl = { + .cmd = XEN_DOMCTL_getvcpucontext, + .domain = domid, + .u.vcpucontext.vcpu = 0, + }; + + set_xen_guest_handle(domctl.u.vcpucontext.ctxt, ctxt); + + return do_domctl(&domctl); +} + +int xen_domctl_setvcpucontext(int domid, int vcpu, vcpu_guest_context_t *ctxt) +{ + xen_domctl_t domctl = { + .cmd = XEN_DOMCTL_setvcpucontext, + .domain = domid, + .u.vcpucontext.vcpu = 0, + }; + + set_xen_guest_handle(domctl.u.vcpucontext.ctxt, ctxt); + + return do_domctl(&domctl); +} + +int xen_domctl_getdomaininfo(int domid, xen_domctl_getdomaininfo_t *dom_info) +{ + int rc; + xen_domctl_t domctl = { + .cmd = XEN_DOMCTL_getdomaininfo, + .domain = domid, + }; + + rc = do_domctl(&domctl); + if (rc) { + return rc; + } + + memcpy(dom_info, &domctl.u.getdomaininfo, sizeof(*dom_info)); + + return 0; +} + +int xen_domctl_get_paging_mempool_size(int domid, uint64_t *size_mb) +{ + int rc; + xen_domctl_t domctl = { + .cmd = XEN_DOMCTL_get_paging_mempool_size, + .domain = domid, + }; + + rc = do_domctl(&domctl); + if (rc) + return rc; + + *size_mb = domctl.u.paging_mempool.size; + + return 0; +} + +int xen_domctl_set_paging_mempool_size(int domid, uint64_t size_mb) +{ + xen_domctl_t domctl = { + .cmd = XEN_DOMCTL_set_paging_mempool_size, + .domain = domid, + .u.paging_mempool.size = size_mb, + }; + + return do_domctl(&domctl); +} + +int xen_domctl_max_mem(int domid, uint64_t max_memkb) +{ + xen_domctl_t domctl = { + .cmd = XEN_DOMCTL_max_mem, + .domain = domid, + .u.max_mem.max_memkb = max_memkb, + }; + + return do_domctl(&domctl); +} + +int xen_domctl_set_address_size(int domid, int addr_size) +{ + xen_domctl_t domctl = { + .domain = domid, + .cmd = XEN_DOMCTL_set_address_size, + .u.address_size.size = addr_size, + }; + + return do_domctl(&domctl); +} + +int xen_domctl_iomem_permission(int domid, uint64_t first_mfn, + uint64_t nr_mfns, uint8_t allow_access) +{ + xen_domctl_t domctl = { + .domain = domid, + .cmd = XEN_DOMCTL_iomem_permission, + .u.iomem_permission.first_mfn = first_mfn, + .u.iomem_permission.nr_mfns = nr_mfns, + .u.iomem_permission.allow_access = allow_access, + }; + + return do_domctl(&domctl); +} + +int xen_domctl_memory_mapping(int domid, uint64_t first_gfn, uint64_t first_mfn, + uint64_t nr_mfns, uint32_t add_mapping) +{ + int ret; + uint64_t curr, nr_max, done; + xen_domctl_t domctl = { + .domain = domid, + .cmd = XEN_DOMCTL_memory_mapping, + .u.memory_mapping.add_mapping = add_mapping, + }; + + if (!nr_mfns) { + return 0; + } + + /* nr_mfns can be big and we need to handle this here */ + done = 0; + nr_max = nr_mfns; + do { + domctl.u.memory_mapping.first_gfn = first_gfn + done; + domctl.u.memory_mapping.first_mfn = first_mfn + done; + + curr = MIN(nr_mfns - done, nr_max); + domctl.u.memory_mapping.nr_mfns = curr; + + ret = do_domctl(&domctl); + if (ret < 0) { + if (ret == -E2BIG) { + /* Check if we not reach min amount */ + if (nr_max <= 1) { + break; + } + + /* Decrease amount twice and try again */ + nr_max = nr_max >> 1; + continue; + } else { + break; + } + } + + done += curr; + } while (done < nr_mfns); + + /* We may come here when get E2BIG and reach 1 at nr_max */ + if (!done) { + ret = -1; + } + + return ret; +} + +int xen_domctl_assign_dt_device(int domid, char *dtdev_path) +{ + xen_domctl_t domctl = { + .domain = domid, + .cmd = XEN_DOMCTL_assign_device, + .u.assign_device.flags = 0, + .u.assign_device.dev = XEN_DOMCTL_DEV_DT, + .u.assign_device.u.dt.size = strlen(dtdev_path), + }; + + set_xen_guest_handle(domctl.u.assign_device.u.dt.path, dtdev_path); + + return do_domctl(&domctl); + +} + +int 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) +{ + xen_domctl_t domctl = { + .domain = domid, + .cmd = XEN_DOMCTL_bind_pt_irq, + }; + struct xen_domctl_bind_pt_irq *bind = &(domctl.u.bind_pt_irq); + + switch (irq_type) { + case PT_IRQ_TYPE_SPI: + bind->irq_type = irq_type; + bind->machine_irq = machine_irq; + bind->u.spi.spi = spi; + break; + default: + /* TODO: implement other types */ + return -ENOTSUP; + } + + return do_domctl(&domctl); +} + +int xen_domctl_max_vcpus(int domid, int max_vcpus) +{ + xen_domctl_t domctl = { + .cmd = XEN_DOMCTL_max_vcpus, + .domain = domid, + .u.max_vcpus.max = max_vcpus, + }; + + return do_domctl(&domctl); +} + +int xen_domctl_createdomain(int domid, struct xen_domctl_createdomain *config) +{ + xen_domctl_t domctl = { + .cmd = XEN_DOMCTL_createdomain, + .domain = domid, + .u.createdomain = *config, + }; + + return do_domctl(&domctl); +} + +int xen_domctl_destroydomain(int domid) +{ + xen_domctl_t domctl = { + .cmd = XEN_DOMCTL_destroydomain, + .domain = domid, + }; + + return do_domctl(&domctl); +} + +int xen_domctl_cacheflush(int domid, struct xen_domctl_cacheflush *cacheflush) +{ + xen_domctl_t domctl = { + .cmd = XEN_DOMCTL_cacheflush, + .domain = domid, + .u.cacheflush = *cacheflush, + }; + + return do_domctl(&domctl); +} diff --git a/include/zephyr/arch/arm64/hypercall.h b/include/zephyr/arch/arm64/hypercall.h index 7a0b7aecf2..023ea10803 100644 --- a/include/zephyr/arch/arm64/hypercall.h +++ b/include/zephyr/arch/arm64/hypercall.h @@ -1,7 +1,6 @@ +/* SPDX-License-Identifier: Apache-2.0 */ /* - * Copyright (c) 2021-2022 EPAM Systems - * - * SPDX-License-Identifier: Apache-2.0 + * Copyright (c) 2021-2023 EPAM Systems */ #ifndef ZEPHYR_INCLUDE_ARCH_ARM64_HYPERCALL_H_ @@ -15,4 +14,8 @@ int HYPERVISOR_hvm_op(int op, void *param); int HYPERVISOR_memory_op(int op, void *param); int HYPERVISOR_grant_table_op(int op, void *uop, unsigned int count); +#ifdef CONFIG_XEN_DOM0 +int HYPERVISOR_domctl(void *param); +#endif + #endif /* ZEPHYR_INCLUDE_ARCH_ARM64_HYPERCALL_H_ */ diff --git a/include/zephyr/xen/dom0/domctl.h b/include/zephyr/xen/dom0/domctl.h new file mode 100644 index 0000000000..6dfe905388 --- /dev/null +++ b/include/zephyr/xen/dom0/domctl.h @@ -0,0 +1,37 @@ +/* SPDX-License-Identifier: Apache-2.0 */ +/* + * Copyright (c) 2023 EPAM Systems + * + */ +#ifndef __XEN_DOM0_DOMCTL_H__ +#define __XEN_DOM0_DOMCTL_H__ + +#include +#include +#include + +#include + +int xen_domctl_scheduler_op(int domid, struct xen_domctl_scheduler_op *sched_op); +int xen_domctl_pausedomain(int domid); +int xen_domctl_unpausedomain(int domid); +int xen_domctl_resumedomain(int domid); +int xen_domctl_getvcpucontext(int domid, int vcpu, vcpu_guest_context_t *ctxt); +int xen_domctl_setvcpucontext(int domid, int vcpu, vcpu_guest_context_t *ctxt); +int xen_domctl_getdomaininfo(int domid, xen_domctl_getdomaininfo_t *dom_info); +int xen_domctl_set_paging_mempool_size(int domid, uint64_t size_mb); +int xen_domctl_max_mem(int domid, uint64_t max_memkb); +int xen_domctl_set_address_size(int domid, int addr_size); +int xen_domctl_iomem_permission(int domid, uint64_t first_mfn, + uint64_t nr_mfns, uint8_t allow_access); +int xen_domctl_memory_mapping(int domid, uint64_t first_gfn, uint64_t first_mfn, + uint64_t nr_mfns, uint32_t add_mapping); +int xen_domctl_assign_dt_device(int domid, char *dtdev_path); +int 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); +int xen_domctl_max_vcpus(int domid, int max_vcpus); +int xen_domctl_createdomain(int domid, struct xen_domctl_createdomain *config); +int xen_domctl_cacheflush(int domid, struct xen_domctl_cacheflush *cacheflush); +int xen_domctl_destroydomain(int domid); + +#endif /* __XEN_DOM0_DOMCTL_H__ */