diff --git a/hypervisor/Makefile b/hypervisor/Makefile index 9298579fc..58a068edc 100644 --- a/hypervisor/Makefile +++ b/hypervisor/Makefile @@ -306,6 +306,7 @@ VP_DM_C_SRCS += dm/vpci/vmsi.c VP_DM_C_SRCS += dm/vpci/vmsix.c VP_DM_C_SRCS += dm/vpci/vmsix_on_msi.c VP_DM_C_SRCS += dm/vpci/vsriov.c +VP_DM_C_SRCS += dm/mmio_dev.c VP_DM_C_SRCS += arch/x86/guest/vlapic.c VP_DM_C_SRCS += arch/x86/guest/pm.c VP_DM_C_SRCS += arch/x86/guest/assign.c diff --git a/hypervisor/arch/x86/guest/vmcall.c b/hypervisor/arch/x86/guest/vmcall.c index 58c3dfb89..70d89d715 100644 --- a/hypervisor/arch/x86/guest/vmcall.c +++ b/hypervisor/arch/x86/guest/vmcall.c @@ -160,6 +160,20 @@ static int32_t dispatch_sos_hypercall(const struct acrn_vcpu *vcpu) } break; + case HC_ASSIGN_MMIODEV: + /* param1: relative vmid to sos, vm_id: absolute vmid */ + if (vmid_is_valid) { + ret = hcall_assign_mmiodev(sos_vm, vm_id, param2); + } + break; + + case HC_DEASSIGN_MMIODEV: + /* param1: relative vmid to sos, vm_id: absolute vmid */ + if (vmid_is_valid) { + ret = hcall_deassign_mmiodev(sos_vm, vm_id, param2); + } + break; + case HC_SET_PTDEV_INTR_INFO: /* param1: relative vmid to sos, vm_id: absolute vmid */ if (vmid_is_valid) { diff --git a/hypervisor/common/hypercall.c b/hypervisor/common/hypercall.c index 224c21916..13b19827e 100644 --- a/hypervisor/common/hypercall.c +++ b/hypervisor/common/hypercall.c @@ -19,6 +19,7 @@ #include #include #include +#include #define DBG_LEVEL_HYCALL 6U @@ -893,6 +894,70 @@ int32_t hcall_deassign_pcidev(struct acrn_vm *vm, uint16_t vmid, uint64_t param) return ret; } +/** + * @brief Assign one MMIO dev to a VM. + * + * @param vm Pointer to VM data structure + * @param vmid ID of the VM + * @param param guest physical address. This gpa points to data structure of + * acrn_mmiodev including assign MMIO device info + * + * @pre Pointer vm shall point to SOS_VM + * @return 0 on success, non-zero on error. + */ +int32_t hcall_assign_mmiodev(struct acrn_vm *vm, uint16_t vmid, uint64_t param) +{ + int32_t ret = -EINVAL; + struct acrn_mmiodev mmiodev; + struct acrn_vm *target_vm = get_vm_from_vmid(vmid); + + /* We should only assign a device to a post-launched VM at creating time for safety, not runtime or other cases*/ + if (is_created_vm(target_vm) && is_postlaunched_vm(target_vm)) { + if (copy_from_gpa(vm, &mmiodev, param, sizeof(mmiodev)) == 0) { + ret = deassign_mmio_dev(vm, &mmiodev); + if (ret == 0) { + ret = assign_mmio_dev(target_vm, &mmiodev); + } + } + } else { + pr_err("vm[%d] %s failed!\n",target_vm->vm_id, __func__); + } + + return ret; +} + +/** + * @brief Deassign one MMIO dev from a VM. + * + * @param vm Pointer to VM data structure + * @param vmid ID of the VM + * @param param guest physical address. This gpa points to data structure of + * acrn_mmiodev including deassign MMIO device info + * + * @pre Pointer vm shall point to SOS_VM + * @return 0 on success, non-zero on error. + */ +int32_t hcall_deassign_mmiodev(struct acrn_vm *vm, uint16_t vmid, uint64_t param) +{ + int32_t ret = -EINVAL; + struct acrn_mmiodev mmiodev; + struct acrn_vm *target_vm = get_vm_from_vmid(vmid); + + /* We should only de-assign a device from a post-launched VM at creating/shutdown/reset time */ + if ((is_paused_vm(target_vm) || is_created_vm(target_vm)) && is_postlaunched_vm(target_vm)) { + if (copy_from_gpa(vm, &mmiodev, param, sizeof(mmiodev)) == 0) { + ret = deassign_mmio_dev(target_vm, &mmiodev); + if (ret == 0) { + ret = assign_mmio_dev(vm, &mmiodev); + } + } + } else { + pr_err("vm[%d] %s failed!\n",target_vm->vm_id, __func__); + } + + return ret; +} + /** * @brief Set interrupt mapping info of ptdev. * diff --git a/hypervisor/dm/mmio_dev.c b/hypervisor/dm/mmio_dev.c new file mode 100644 index 000000000..7fd69306b --- /dev/null +++ b/hypervisor/dm/mmio_dev.c @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2020 Intel Corporation. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include +#include +#include +#include +#include +#include + +int32_t assign_mmio_dev(struct acrn_vm *vm, const struct acrn_mmiodev *mmiodev) +{ + int32_t ret = -EINVAL; + + if (mem_aligned_check(mmiodev->base_gpa, PAGE_SIZE) && + mem_aligned_check(mmiodev->base_hpa, PAGE_SIZE) && + mem_aligned_check(mmiodev->size, PAGE_SIZE)) { + ept_add_mr(vm, (uint64_t *)vm->arch_vm.nworld_eptp, mmiodev->base_hpa, + is_sos_vm(vm) ? mmiodev->base_hpa : mmiodev->base_gpa, + mmiodev->size, EPT_RWX | EPT_UNCACHED); + ret = 0; + } + + return ret; +} + +int32_t deassign_mmio_dev(struct acrn_vm *vm, const struct acrn_mmiodev *mmiodev) +{ + int32_t ret = -EINVAL; + + if (mem_aligned_check(mmiodev->base_gpa, PAGE_SIZE) && + mem_aligned_check(mmiodev->base_hpa, PAGE_SIZE) && + mem_aligned_check(mmiodev->size, PAGE_SIZE)) { + ept_del_mr(vm, (uint64_t *)vm->arch_vm.nworld_eptp, + is_sos_vm(vm) ? mmiodev->base_hpa : mmiodev->base_gpa, mmiodev->size); + ret = 0; + } + + return ret; +} diff --git a/hypervisor/include/common/hypercall.h b/hypervisor/include/common/hypercall.h index fa4650f9d..ec30d36cb 100644 --- a/hypervisor/include/common/hypercall.h +++ b/hypervisor/include/common/hypercall.h @@ -274,6 +274,32 @@ int32_t hcall_assign_pcidev(struct acrn_vm *vm, uint16_t vmid, uint64_t param); */ int32_t hcall_deassign_pcidev(struct acrn_vm *vm, uint16_t vmid, uint64_t param); +/** + * @brief Assign one MMIO dev to VM. + * + * @param vm Pointer to VM data structure + * @param vmid ID of the VM + * @param param guest physical address. This gpa points to data structure of + * acrn_mmiodev including assign MMIO device info + * + * @pre Pointer vm shall point to SOS_VM + * @return 0 on success, non-zero on error. + */ +int32_t hcall_assign_mmiodev(struct acrn_vm *vm, uint16_t vmid, uint64_t param); + +/** + * @brief Deassign one MMIO dev to VM. + * + * @param vm Pointer to VM data structure + * @param vmid ID of the VM + * @param param guest physical address. This gpa points to data structure of + * acrn_mmiodev including deassign MMIO device info + * + * @pre Pointer vm shall point to SOS_VM + * @return 0 on success, non-zero on error. + */ +int32_t hcall_deassign_mmiodev(struct acrn_vm *vm, uint16_t vmid, uint64_t param); + /** * @brief Set interrupt mapping info of ptdev. * diff --git a/hypervisor/include/dm/mmio_dev.h b/hypervisor/include/dm/mmio_dev.h new file mode 100644 index 000000000..9f970a007 --- /dev/null +++ b/hypervisor/include/dm/mmio_dev.h @@ -0,0 +1,13 @@ +/* + * Copyright (C) 2020 Intel Corporation. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef MMIO_DEV_H +#define MMIO_DEV_H + +int32_t assign_mmio_dev(struct acrn_vm *vm, const struct acrn_mmiodev *mmiodev); +int32_t deassign_mmio_dev(struct acrn_vm *vm, const struct acrn_mmiodev *mmiodev); + +#endif /* MMIO_DEV_H */ diff --git a/hypervisor/include/public/acrn_hv_defs.h b/hypervisor/include/public/acrn_hv_defs.h index f69d2786c..f48285fe5 100644 --- a/hypervisor/include/public/acrn_hv_defs.h +++ b/hypervisor/include/public/acrn_hv_defs.h @@ -66,6 +66,8 @@ #define HC_RESET_PTDEV_INTR_INFO BASE_HC_ID(HC_ID, HC_ID_PCI_BASE + 0x04UL) #define HC_ASSIGN_PCIDEV BASE_HC_ID(HC_ID, HC_ID_PCI_BASE + 0x05UL) #define HC_DEASSIGN_PCIDEV BASE_HC_ID(HC_ID, HC_ID_PCI_BASE + 0x06UL) +#define HC_ASSIGN_MMIODEV BASE_HC_ID(HC_ID, HC_ID_PCI_BASE + 0x07UL) +#define HC_DEASSIGN_MMIODEV BASE_HC_ID(HC_ID, HC_ID_PCI_BASE + 0x08UL) /* DEBUG */ #define HC_ID_DBG_BASE 0x60UL @@ -300,6 +302,26 @@ struct acrn_assign_pcidev { } __attribute__((aligned(8))); +/** + * @brief Info to assign or deassign a MMIO device for a VM + * + * the parameter for HC_ASSIGN_MMIODEV or HC_DEASSIGN_MMIODEV hypercall + */ +struct acrn_mmiodev { + /** the gpa of the MMIO region for the MMIO device */ + uint64_t base_gpa; + + /** the hpa of the MMIO region for the MMIO device */ + uint64_t base_hpa; + + /** the size of the MMIO region for the MMIO device */ + uint64_t size; + + /** reserved for extension */ + uint64_t reserved[13]; + +} __attribute__((aligned(8))); + /** * Hypervisor api version info, return it for HC_GET_API_VERSION hypercall */