diff --git a/doc/developer-guides/hld/hv-io-emulation.rst b/doc/developer-guides/hld/hv-io-emulation.rst index 9b674a9e9..d0b947a32 100644 --- a/doc/developer-guides/hld/hv-io-emulation.rst +++ b/doc/developer-guides/hld/hv-io-emulation.rst @@ -341,3 +341,6 @@ The following APIs are provided for I/O emulation at runtime: .. doxygenfunction:: pio_instr_vmexit_handler :project: Project ACRN + +.. doxygenfunction:: ept_violation_vmexit_handler + :project: Project ACRN diff --git a/doc/developer-guides/hld/hv-memmgt.rst b/doc/developer-guides/hld/hv-memmgt.rst index 1a4fd98fa..4b3bdb81a 100644 --- a/doc/developer-guides/hld/hv-memmgt.rst +++ b/doc/developer-guides/hld/hv-memmgt.rst @@ -460,9 +460,6 @@ EPT .. doxygenfunction:: invept :project: Project ACRN -.. doxygenfunction:: ept_violation_vmexit_handler - :project: Project ACRN - .. doxygenfunction:: ept_misconfig_vmexit_handler :project: Project ACRN diff --git a/hypervisor/arch/x86/ept.c b/hypervisor/arch/x86/ept.c index a87219ee6..de280d0a9 100644 --- a/hypervisor/arch/x86/ept.c +++ b/hypervisor/arch/x86/ept.c @@ -72,88 +72,6 @@ uint64_t vm0_hpa2gpa(uint64_t hpa) return hpa; } -int32_t ept_violation_vmexit_handler(struct acrn_vcpu *vcpu) -{ - int32_t status = -EINVAL, ret; - uint64_t exit_qual; - uint64_t gpa; - struct io_request *io_req = &vcpu->req; - struct mmio_request *mmio_req = &io_req->reqs.mmio; - - /* Handle page fault from guest */ - exit_qual = vcpu->arch.exit_qualification; - - io_req->type = REQ_MMIO; - - /* Specify if read or write operation */ - if ((exit_qual & 0x2UL) != 0UL) { - /* Write operation */ - mmio_req->direction = REQUEST_WRITE; - mmio_req->value = 0UL; - - /* XXX: write access while EPT perm RX -> WP */ - if ((exit_qual & 0x38UL) == 0x28UL) { - io_req->type = REQ_WP; - } - } else { - /* Read operation */ - mmio_req->direction = REQUEST_READ; - - /* TODO: Need to determine how sign extension is determined for - * reads - */ - } - - /* Get the guest physical address */ - gpa = exec_vmread64(VMX_GUEST_PHYSICAL_ADDR_FULL); - - TRACE_2L(TRACE_VMEXIT_EPT_VIOLATION, exit_qual, gpa); - - /* Adjust IPA appropriately and OR page offset to get full IPA of abort - */ - mmio_req->address = gpa; - - ret = decode_instruction(vcpu); - if (ret > 0) { - mmio_req->size = (uint64_t)ret; - /* - * For MMIO write, ask DM to run MMIO emulation after - * instruction emulation. For MMIO read, ask DM to run MMIO - * emulation at first. - */ - - /* Determine value being written. */ - if (mmio_req->direction == REQUEST_WRITE) { - status = emulate_instruction(vcpu); - if (status != 0) { - ret = -EFAULT; - } - } - - if (ret > 0) { - status = emulate_io(vcpu, io_req); - if (status == 0) { - emulate_mmio_post(vcpu, io_req); - } else { - if (status == IOREQ_PENDING) { - status = 0; - } - } - } - } else { - if (ret == -EFAULT) { - pr_info("page fault happen during decode_instruction"); - status = 0; - } - } - - if (ret <= 0) { - pr_acrnlog("Guest Linear Address: 0x%016llx", exec_vmread(VMX_GUEST_LINEAR_ADDR)); - pr_acrnlog("Guest Physical Address address: 0x%016llx", gpa); - } - return status; -} - int32_t ept_misconfig_vmexit_handler(__unused struct acrn_vcpu *vcpu) { int32_t status; diff --git a/hypervisor/arch/x86/io_emul.c b/hypervisor/arch/x86/io_emul.c index 2d4ac857c..7d1b28be3 100644 --- a/hypervisor/arch/x86/io_emul.c +++ b/hypervisor/arch/x86/io_emul.c @@ -403,6 +403,87 @@ int32_t pio_instr_vmexit_handler(struct acrn_vcpu *vcpu) return status; } +int32_t ept_violation_vmexit_handler(struct acrn_vcpu *vcpu) +{ + int32_t status = -EINVAL, ret; + uint64_t exit_qual; + uint64_t gpa; + struct io_request *io_req = &vcpu->req; + struct mmio_request *mmio_req = &io_req->reqs.mmio; + + /* Handle page fault from guest */ + exit_qual = vcpu->arch.exit_qualification; + + io_req->type = REQ_MMIO; + + /* Specify if read or write operation */ + if ((exit_qual & 0x2UL) != 0UL) { + /* Write operation */ + mmio_req->direction = REQUEST_WRITE; + mmio_req->value = 0UL; + + /* XXX: write access while EPT perm RX -> WP */ + if ((exit_qual & 0x38UL) == 0x28UL) { + io_req->type = REQ_WP; + } + } else { + /* Read operation */ + mmio_req->direction = REQUEST_READ; + + /* TODO: Need to determine how sign extension is determined for + * reads + */ + } + + /* Get the guest physical address */ + gpa = exec_vmread64(VMX_GUEST_PHYSICAL_ADDR_FULL); + + TRACE_2L(TRACE_VMEXIT_EPT_VIOLATION, exit_qual, gpa); + + /* Adjust IPA appropriately and OR page offset to get full IPA of abort + */ + mmio_req->address = gpa; + + ret = decode_instruction(vcpu); + if (ret > 0) { + mmio_req->size = (uint64_t)ret; + /* + * For MMIO write, ask DM to run MMIO emulation after + * instruction emulation. For MMIO read, ask DM to run MMIO + * emulation at first. + */ + + /* Determine value being written. */ + if (mmio_req->direction == REQUEST_WRITE) { + status = emulate_instruction(vcpu); + if (status != 0) { + ret = -EFAULT; + } + } + + if (ret > 0) { + status = emulate_io(vcpu, io_req); + if (status == 0) { + emulate_mmio_post(vcpu, io_req); + } else { + if (status == IOREQ_PENDING) { + status = 0; + } + } + } + } else { + if (ret == -EFAULT) { + pr_info("page fault happen during decode_instruction"); + status = 0; + } + } + + if (ret <= 0) { + pr_acrnlog("Guest Linear Address: 0x%016llx", exec_vmread(VMX_GUEST_LINEAR_ADDR)); + pr_acrnlog("Guest Physical Address address: 0x%016llx", gpa); + } + return status; +} /** * @brief Allow a VM to access a port I/O range diff --git a/hypervisor/include/arch/x86/io_emul.h b/hypervisor/include/arch/x86/io_emul.h index 86086d47a..2743e7640 100644 --- a/hypervisor/include/arch/x86/io_emul.h +++ b/hypervisor/include/arch/x86/io_emul.h @@ -79,6 +79,16 @@ int32_t emulate_io(struct acrn_vcpu *vcpu, struct io_request *io_req); */ int32_t pio_instr_vmexit_handler(struct acrn_vcpu *vcpu); +/** + * @brief EPT violation handling + * + * @param[in] vcpu the pointer that points to vcpu data structure + * + * @retval -EINVAL fail to handle the EPT violation + * @retval 0 Success to handle the EPT violation + */ +int32_t ept_violation_vmexit_handler(struct acrn_vcpu *vcpu); + /** * @brief Allow a VM to access a port I/O range * diff --git a/hypervisor/include/arch/x86/mmu.h b/hypervisor/include/arch/x86/mmu.h index ad6320955..c967c98b8 100644 --- a/hypervisor/include/arch/x86/mmu.h +++ b/hypervisor/include/arch/x86/mmu.h @@ -294,15 +294,7 @@ void ept_mr_modify(struct acrn_vm *vm, uint64_t *pml4_page, uint64_t gpa, */ void ept_mr_del(struct acrn_vm *vm, uint64_t *pml4_page, uint64_t gpa, uint64_t size); -/** - * @brief EPT violation handling - * - * @param[in] vcpu the pointer that points to vcpu data structure - * - * @retval -EINVAL fail to handle the EPT violation - * @retval 0 Success to handle the EPT violation - */ -int32_t ept_violation_vmexit_handler(struct acrn_vcpu *vcpu); + /** * @brief EPT misconfiguration handling *