diff --git a/hypervisor/arch/x86/guest/vmcall.c b/hypervisor/arch/x86/guest/vmcall.c index 66aac127c..e7ad68940 100644 --- a/hypervisor/arch/x86/guest/vmcall.c +++ b/hypervisor/arch/x86/guest/vmcall.c @@ -58,6 +58,10 @@ static const struct hc_dispatch hc_dispatch_table[] = { .handler = hcall_inject_msi}, [HC_IDX(HC_SET_IOREQ_BUFFER)] = { .handler = hcall_set_ioreq_buffer}, + [HC_IDX(HC_ASYNCIO_ASSIGN)] = { + .handler = hcall_asyncio_assign}, + [HC_IDX(HC_ASYNCIO_DEASSIGN)] = { + .handler = hcall_asyncio_deassign}, [HC_IDX(HC_NOTIFY_REQUEST_FINISH)] = { .handler = hcall_notify_ioreq_finish}, [HC_IDX(HC_VM_SET_MEMORY_REGIONS)] = { diff --git a/hypervisor/common/hypercall.c b/hypervisor/common/hypercall.c index f86e3d9d7..5269380c1 100644 --- a/hypervisor/common/hypercall.c +++ b/hypervisor/common/hypercall.c @@ -545,6 +545,34 @@ int32_t hcall_setup_sbuf(struct acrn_vcpu *vcpu, struct acrn_vm *target_vm, return ret; } +int32_t hcall_asyncio_assign(__unused struct acrn_vcpu *vcpu, struct acrn_vm *target_vm, + __unused uint64_t param1, uint64_t param2) +{ + struct acrn_asyncio_info asyncio_info; + struct acrn_vm *vm = vcpu->vm; + int ret = -1; + + if (copy_from_gpa(vm, &asyncio_info, param2, sizeof(asyncio_info)) == 0) { + add_asyncio(target_vm, asyncio_info.type, asyncio_info.addr, asyncio_info.fd); + ret = 0; + } + return ret; +} + +int32_t hcall_asyncio_deassign(__unused struct acrn_vcpu *vcpu, struct acrn_vm *target_vm, + __unused uint64_t param1, uint64_t param2) +{ + struct acrn_asyncio_info asyncio_info; + struct acrn_vm *vm = vcpu->vm; + int ret = -1; + + if (copy_from_gpa(vm, &asyncio_info, param2, sizeof(asyncio_info)) == 0) { + remove_asyncio(target_vm, asyncio_info.type, asyncio_info.addr, asyncio_info.fd); + ret = 0; + } + return ret; +} + /** * @brief notify request done * diff --git a/hypervisor/dm/io_req.c b/hypervisor/dm/io_req.c index 2ddecfe37..7bc14ba41 100644 --- a/hypervisor/dm/io_req.c +++ b/hypervisor/dm/io_req.c @@ -64,6 +64,63 @@ void reset_vm_ioreqs(struct acrn_vm *vm) } } +int add_asyncio(struct acrn_vm *vm, uint32_t type, uint64_t addr, uint64_t fd) +{ + uint32_t i; + int ret = -1; + + if (addr != 0UL) { + spinlock_obtain(&vm->asyncio_lock); + for (i = 0U; i < ACRN_ASYNCIO_MAX; i++) { + if ((vm->aio_desc[i].addr == 0UL) && (vm->aio_desc[i].fd == 0UL)) { + vm->aio_desc[i].type = type; + vm->aio_desc[i].addr = addr; + vm->aio_desc[i].fd = fd; + INIT_LIST_HEAD(&vm->aio_desc[i].list); + list_add(&vm->aio_desc[i].list, &vm->aiodesc_queue); + ret = 0; + break; + } + } + spinlock_release(&vm->asyncio_lock); + if (i == ACRN_ASYNCIO_MAX) { + pr_fatal("too much fastio, would not support!"); + } + } else { + pr_err("%s: base = 0 is not supported!", __func__); + } + return ret; +} + +int remove_asyncio(struct acrn_vm *vm, uint32_t type, uint64_t addr, uint64_t fd) +{ + uint32_t i; + int ret = -1; + + if (addr != 0UL) { + spinlock_obtain(&vm->asyncio_lock); + for (i = 0U; i < ACRN_ASYNCIO_MAX; i++) { + if ((vm->aio_desc[i].type == type) + && (vm->aio_desc[i].addr == addr) + && (vm->aio_desc[i].fd == fd)) { + vm->aio_desc[i].type = 0U; + vm->aio_desc[i].addr = 0UL; + vm->aio_desc[i].fd = 0UL; + list_del_init(&vm->aio_desc[i].list); + ret = 0; + break; + } + } + spinlock_release(&vm->asyncio_lock); + if (i == ACRN_ASYNCIO_MAX) { + pr_fatal("Failed to find asyncio req on addr: %lx!", addr); + } + } else { + pr_err("%s: base = 0 is not supported!", __func__); + } + return ret; +} + static inline bool has_complete_ioreq(const struct acrn_vcpu *vcpu) { return (get_io_req_state(vcpu->vm, vcpu->vcpu_id) == ACRN_IOREQ_STATE_COMPLETE); @@ -186,6 +243,8 @@ int init_asyncio(struct acrn_vm *vm, uint64_t *hva) if (sbuf != NULL) { if (sbuf->magic == SBUF_MAGIC) { vm->sw.asyncio_sbuf = sbuf; + INIT_LIST_HEAD(&vm->aiodesc_queue); + spinlock_init(&vm->asyncio_lock); ret = 0; } } diff --git a/hypervisor/include/arch/x86/asm/guest/vm.h b/hypervisor/include/arch/x86/asm/guest/vm.h index 8ce702137..62b606be1 100644 --- a/hypervisor/include/arch/x86/asm/guest/vm.h +++ b/hypervisor/include/arch/x86/asm/guest/vm.h @@ -28,6 +28,7 @@ #include #include #include +#include #ifdef CONFIG_HYPERV_ENABLED #include #endif @@ -144,6 +145,10 @@ struct acrn_vm { uint16_t vm_id; /* Virtual machine identifier */ enum vm_state state; /* VM state */ struct acrn_vuart vuart[MAX_VUART_NUM_PER_VM]; /* Virtual UART */ + struct asyncio_desc aio_desc[ACRN_ASYNCIO_MAX]; + struct list_head aiodesc_queue; + spinlock_t asyncio_lock; /* Spin-lock used to protect asyncio add/remove for a VM */ + enum vpic_wire_mode wire_mode; struct iommu_domain *iommu; /* iommu domain of this VM */ /* vm_state_lock used to protect vm/vcpu state transition, diff --git a/hypervisor/include/common/hypercall.h b/hypervisor/include/common/hypercall.h index 3810f3b6d..c8f8a9831 100644 --- a/hypervisor/include/common/hypercall.h +++ b/hypervisor/include/common/hypercall.h @@ -524,6 +524,33 @@ int32_t hcall_set_callback_vector(struct acrn_vcpu *vcpu, struct acrn_vm *target */ int32_t hcall_setup_sbuf(struct acrn_vcpu *vcpu, struct acrn_vm *target_vm, uint64_t param1, uint64_t param2); +/** + * @brief Assign an asyncio to a VM. + * + * @param vcpu not used + * @param target_vm which VM the asyncio belongs. + * @param param1 guest physical address. This gpa points to + * struct acrn_asyncio_info + * @param param2 not used + * + * @return 0 on success, non-zero on error. + */ +int32_t hcall_asyncio_assign(__unused struct acrn_vcpu *vcpu, struct acrn_vm *target_vm, + __unused uint64_t param1, uint64_t param2); +/** + * @brief Deassign an asyncio from a VM. + * + * @param vcpu not used + * @param target_vm which VM the asyncio belongs. + * @param param1 guest physical address. This gpa points to + * struct acrn_asyncio_info + * @param param2 not used + * + * @return 0 on success, non-zero on error. + */ +int32_t hcall_asyncio_deassign(__unused struct acrn_vcpu *vcpu, struct acrn_vm *target_vm, + __unused uint64_t param1, uint64_t param2); + /** * @brief Setup the hypervisor NPK log. * diff --git a/hypervisor/include/dm/io_req.h b/hypervisor/include/dm/io_req.h index d5ebd2268..775389b0b 100644 --- a/hypervisor/include/dm/io_req.h +++ b/hypervisor/include/dm/io_req.h @@ -40,6 +40,13 @@ struct io_request { } reqs; }; +struct asyncio_desc { + uint32_t type; + uint64_t addr; + uint64_t fd; + struct list_head list; +}; + /** * @brief Definition of a IO port range */ @@ -293,6 +300,10 @@ void unregister_mmio_emulation_handler(struct acrn_vm *vm, void deinit_emul_io(struct acrn_vm *vm); int init_asyncio(struct acrn_vm *vm, uint64_t *hva); + +int add_asyncio(struct acrn_vm *vm, uint32_t type, uint64_t addr, uint64_t fd); + +int remove_asyncio(struct acrn_vm *vm, uint32_t type, uint64_t addr, uint64_t fd); /** * @} */ diff --git a/hypervisor/include/public/acrn_common.h b/hypervisor/include/public/acrn_common.h index a2293c1fa..86299ce05 100644 --- a/hypervisor/include/public/acrn_common.h +++ b/hypervisor/include/public/acrn_common.h @@ -26,6 +26,7 @@ */ #define ACRN_IO_REQUEST_MAX 16U +#define ACRN_ASYNCIO_MAX 64U #define ACRN_IOREQ_STATE_PENDING 0U #define ACRN_IOREQ_STATE_COMPLETE 1U @@ -342,6 +343,12 @@ struct acrn_io_request_buffer { }; }; +struct acrn_asyncio_info { + uint32_t type; + uint64_t addr; + uint64_t fd; +}; + /** * @brief Info to create a VM, the parameter for HC_CREATE_VM hypercall */ @@ -472,6 +479,7 @@ struct acrn_irqline_ops { uint32_t op; }; + /** * @brief Info to inject a MSI interrupt to VM * diff --git a/hypervisor/include/public/acrn_hv_defs.h b/hypervisor/include/public/acrn_hv_defs.h index c36955f4b..9d9bc2fb7 100644 --- a/hypervisor/include/public/acrn_hv_defs.h +++ b/hypervisor/include/public/acrn_hv_defs.h @@ -50,6 +50,9 @@ #define HC_ID_IOREQ_BASE 0x30UL #define HC_SET_IOREQ_BUFFER BASE_HC_ID(HC_ID, HC_ID_IOREQ_BASE + 0x00UL) #define HC_NOTIFY_REQUEST_FINISH BASE_HC_ID(HC_ID, HC_ID_IOREQ_BASE + 0x01UL) +#define HC_ASYNCIO_ASSIGN BASE_HC_ID(HC_ID, HC_ID_IOREQ_BASE + 0x02UL) +#define HC_ASYNCIO_DEASSIGN BASE_HC_ID(HC_ID, HC_ID_IOREQ_BASE + 0x03UL) + /* Guest memory management */ #define HC_ID_MEM_BASE 0x40UL