mirror of
https://github.com/projectacrn/acrn-hypervisor.git
synced 2025-06-23 14:07:42 +00:00
HV: refine EPT violation VM-exit handler
- refine EPT violation vmexit handler - add check for mmio access that spans devices Signed-off-by: Yonghua Huang <yonghua.huang@intel.com>
This commit is contained in:
parent
a6780652f3
commit
25219e29a5
@ -229,62 +229,17 @@ int is_ept_supported(void)
|
|||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int check_hv_mmio_range(struct vm *vm, struct mem_io *mmio)
|
static int hv_emulate_mmio(struct vcpu *vcpu, struct mem_io *mmio,
|
||||||
|
struct mem_io_node *mmio_handler)
|
||||||
{
|
{
|
||||||
int status = false;
|
if ((mmio->paddr % mmio->access_size) != 0) {
|
||||||
struct list_head *pos;
|
pr_err("access size not align with paddr");
|
||||||
struct mem_io_node *mmio_node;
|
return -EINVAL;
|
||||||
|
|
||||||
|
|
||||||
list_for_each(pos, &vm->mmio_list) {
|
|
||||||
mmio_node = list_entry(pos, struct mem_io_node, list);
|
|
||||||
/* Check if this handler's range covers this memory access */
|
|
||||||
if ((mmio->paddr >= mmio_node->range_start) &&
|
|
||||||
(mmio->paddr + mmio->access_size <=
|
|
||||||
mmio_node->range_end)) {
|
|
||||||
status = true;
|
|
||||||
|
|
||||||
/* Break from loop - only 1 handler allowed to support
|
|
||||||
* a given memory range
|
|
||||||
*/
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/* Return success for now */
|
|
||||||
return status;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int hv_emulate_mmio(struct vcpu *vcpu, struct mem_io *mmio)
|
|
||||||
{
|
|
||||||
int status = -EINVAL;
|
|
||||||
struct list_head *pos;
|
|
||||||
struct mem_io_node *mmio_node;
|
|
||||||
struct vm *vm = vcpu->vm;
|
|
||||||
|
|
||||||
list_for_each(pos, &vm->mmio_list) {
|
|
||||||
mmio_node = list_entry(pos, struct mem_io_node, list);
|
|
||||||
/* Check if this handler's range covers this memory access */
|
|
||||||
if ((mmio->paddr >= mmio_node->range_start) &&
|
|
||||||
(mmio->paddr + mmio->access_size
|
|
||||||
<= mmio_node->range_end)) {
|
|
||||||
|
|
||||||
ASSERT((mmio->paddr % mmio->access_size) == 0,
|
|
||||||
"access size not align with paddr");
|
|
||||||
|
|
||||||
/* Handle this MMIO operation */
|
/* Handle this MMIO operation */
|
||||||
status = mmio_node->read_write(vcpu, mmio,
|
return mmio_handler->read_write(vcpu, mmio,
|
||||||
mmio_node->handler_private_data);
|
mmio_handler->handler_private_data);
|
||||||
|
|
||||||
/* Break from loop - only 1 handler allowed to support
|
|
||||||
* given memory range
|
|
||||||
*/
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Return success for now */
|
|
||||||
return status;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int register_mmio_emulation_handler(struct vm *vm,
|
int register_mmio_emulation_handler(struct vm *vm,
|
||||||
@ -409,9 +364,12 @@ static int dm_emulate_mmio_pre(struct vcpu *vcpu, uint64_t exit_qual)
|
|||||||
|
|
||||||
int ept_violation_vmexit_handler(struct vcpu *vcpu)
|
int ept_violation_vmexit_handler(struct vcpu *vcpu)
|
||||||
{
|
{
|
||||||
int status;
|
int status = -EINVAL;
|
||||||
uint64_t exit_qual;
|
uint64_t exit_qual;
|
||||||
uint64_t gpa;
|
uint64_t gpa;
|
||||||
|
struct list_head *pos;
|
||||||
|
struct mem_io *mmio = &vcpu->mmio;
|
||||||
|
struct mem_io_node *mmio_handler = NULL;
|
||||||
|
|
||||||
/* Handle page fault from guest */
|
/* Handle page fault from guest */
|
||||||
exit_qual = vcpu->arch_vcpu.exit_qualification;
|
exit_qual = vcpu->arch_vcpu.exit_qualification;
|
||||||
@ -419,22 +377,22 @@ int ept_violation_vmexit_handler(struct vcpu *vcpu)
|
|||||||
/* Specify if read or write operation */
|
/* Specify if read or write operation */
|
||||||
if (exit_qual & 0x2) {
|
if (exit_qual & 0x2) {
|
||||||
/* Write operation */
|
/* Write operation */
|
||||||
vcpu->mmio.read_write = HV_MEM_IO_WRITE;
|
mmio->read_write = HV_MEM_IO_WRITE;
|
||||||
|
|
||||||
/* Get write value from appropriate register in context */
|
/* Get write value from appropriate register in context */
|
||||||
/* TODO: Need to figure out how to determine value being
|
/* TODO: Need to figure out how to determine value being
|
||||||
* written
|
* written
|
||||||
*/
|
*/
|
||||||
vcpu->mmio.value = 0;
|
mmio->value = 0;
|
||||||
} else {
|
} else {
|
||||||
/* Read operation */
|
/* Read operation */
|
||||||
vcpu->mmio.read_write = HV_MEM_IO_READ;
|
mmio->read_write = HV_MEM_IO_READ;
|
||||||
|
|
||||||
/* Get sign extension requirements for read */
|
/* Get sign extension requirements for read */
|
||||||
/* TODO: Need to determine how sign extension is determined for
|
/* TODO: Need to determine how sign extension is determined for
|
||||||
* reads
|
* reads
|
||||||
*/
|
*/
|
||||||
vcpu->mmio.sign_extend_read = 0;
|
mmio->sign_extend_read = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Get the guest physical address */
|
/* Get the guest physical address */
|
||||||
@ -444,21 +402,28 @@ int ept_violation_vmexit_handler(struct vcpu *vcpu)
|
|||||||
|
|
||||||
/* Adjust IPA appropriately and OR page offset to get full IPA of abort
|
/* Adjust IPA appropriately and OR page offset to get full IPA of abort
|
||||||
*/
|
*/
|
||||||
vcpu->mmio.paddr = gpa;
|
mmio->paddr = gpa;
|
||||||
|
|
||||||
/* Check if the MMIO access has a HV registered handler */
|
list_for_each(pos, &vcpu->vm->mmio_list) {
|
||||||
status = check_hv_mmio_range((struct vm *) vcpu->vm, &vcpu->mmio);
|
mmio_handler = list_entry(pos, struct mem_io_node, list);
|
||||||
|
if ((mmio->paddr + mmio->access_size <=
|
||||||
|
mmio_handler->range_start) ||
|
||||||
|
(mmio->paddr >= mmio_handler->range_end))
|
||||||
|
continue;
|
||||||
|
|
||||||
if (status == true) {
|
else if (!((mmio->paddr >= mmio_handler->range_start) &&
|
||||||
/* Fetch and decode current vcpu instruction */
|
(mmio->paddr + mmio->access_size <=
|
||||||
status = analyze_instruction(vcpu, &vcpu->mmio);
|
mmio_handler->range_end))) {
|
||||||
|
pr_fatal("Err MMIO, addr:0x%llx, size:%x",
|
||||||
|
mmio->paddr, mmio->access_size);
|
||||||
|
return -EIO;
|
||||||
|
}
|
||||||
|
|
||||||
if (status != 0)
|
if (analyze_instruction(vcpu, mmio) != 0)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
if (vcpu->mmio.read_write == HV_MEM_IO_WRITE) {
|
if (mmio->read_write == HV_MEM_IO_WRITE) {
|
||||||
status = emulate_instruction(vcpu, &vcpu->mmio);
|
if (emulate_instruction(vcpu, mmio) != 0)
|
||||||
if (status != 0)
|
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -467,15 +432,18 @@ int ept_violation_vmexit_handler(struct vcpu *vcpu)
|
|||||||
* instruction emulation. For MMIO read,
|
* instruction emulation. For MMIO read,
|
||||||
* call hv_emulate_mmio at first.
|
* call hv_emulate_mmio at first.
|
||||||
*/
|
*/
|
||||||
status = hv_emulate_mmio(vcpu, &vcpu->mmio);
|
hv_emulate_mmio(vcpu, mmio, mmio_handler);
|
||||||
|
if (mmio->read_write == HV_MEM_IO_READ) {
|
||||||
if (vcpu->mmio.read_write == HV_MEM_IO_READ) {
|
|
||||||
/* Emulate instruction and update vcpu register set */
|
/* Emulate instruction and update vcpu register set */
|
||||||
status = emulate_instruction(vcpu, &vcpu->mmio);
|
if (emulate_instruction(vcpu, mmio) != 0)
|
||||||
if (status != 0)
|
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
|
status = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (status != 0) {
|
||||||
/*
|
/*
|
||||||
* No mmio handler from HV side, search from VHM in Dom0
|
* No mmio handler from HV side, search from VHM in Dom0
|
||||||
*
|
*
|
||||||
@ -486,9 +454,9 @@ int ept_violation_vmexit_handler(struct vcpu *vcpu)
|
|||||||
*/
|
*/
|
||||||
memset(&vcpu->req, 0, sizeof(struct vhm_request));
|
memset(&vcpu->req, 0, sizeof(struct vhm_request));
|
||||||
|
|
||||||
status = dm_emulate_mmio_pre(vcpu, exit_qual);
|
if (dm_emulate_mmio_pre(vcpu, exit_qual) != 0)
|
||||||
if (status != 0)
|
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
status = acrn_insert_request_wait(vcpu, &vcpu->req);
|
status = acrn_insert_request_wait(vcpu, &vcpu->req);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -501,8 +469,6 @@ out:
|
|||||||
pr_fatal("Guest Physical Address address: 0x%016llx",
|
pr_fatal("Guest Physical Address address: 0x%016llx",
|
||||||
gpa);
|
gpa);
|
||||||
|
|
||||||
ASSERT(status == true, "EPT violation");
|
|
||||||
|
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user