mirror of
https://github.com/projectacrn/acrn-hypervisor.git
synced 2025-06-19 04:02:05 +00:00
instr_emul: refine decode_instruction with copy_from_gva
use copy_from_gva in vie_init, if copy_from_gva meet -EFAULT, inject #PF. And for decode_instruction, if return -EFAULT, the caller should keep return path with successful status. v2: - remove vm_restart_instruction when inject #PF Signed-off-by: Jason Chen CJ <jason.cj.chen@intel.com>
This commit is contained in:
parent
88758dfe57
commit
570aef648a
@ -321,7 +321,7 @@ static int dm_emulate_mmio_pre(struct vcpu *vcpu, uint64_t exit_qual)
|
||||
|
||||
int ept_violation_vmexit_handler(struct vcpu *vcpu)
|
||||
{
|
||||
int status = -EINVAL;
|
||||
int status = -EINVAL, ret;
|
||||
uint64_t exit_qual;
|
||||
uint64_t gpa;
|
||||
struct list_head *pos;
|
||||
@ -361,8 +361,14 @@ int ept_violation_vmexit_handler(struct vcpu *vcpu)
|
||||
*/
|
||||
mmio->paddr = gpa;
|
||||
|
||||
mmio->access_size = decode_instruction(vcpu);
|
||||
if (mmio->access_size == 0)
|
||||
ret = decode_instruction(vcpu);
|
||||
if (ret > 0)
|
||||
mmio->access_size = ret;
|
||||
else if (ret == -EFAULT) {
|
||||
pr_info("page fault happen during decode_instruction");
|
||||
status = 0;
|
||||
goto out;
|
||||
} else
|
||||
goto out;
|
||||
|
||||
list_for_each(pos, &vcpu->vm->mmio_list) {
|
||||
|
@ -1674,11 +1674,16 @@ vie_calculate_gla(enum vm_cpu_mode cpu_mode, enum vm_reg_name seg,
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
vie_init(struct vie *vie, const char *inst_bytes, uint32_t inst_length)
|
||||
int
|
||||
vie_init(struct vie *vie, struct vcpu *vcpu)
|
||||
{
|
||||
ASSERT(inst_length <= VIE_INST_SIZE,
|
||||
"%s: invalid instruction length (%d)", __func__, inst_length);
|
||||
uint32_t inst_len = vcpu->arch_vcpu.inst_len;
|
||||
|
||||
if (inst_len > VIE_INST_SIZE) {
|
||||
pr_err("%s: invalid instruction length (%d)",
|
||||
__func__, inst_len);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
memset(vie, 0, sizeof(struct vie));
|
||||
|
||||
@ -1686,11 +1691,24 @@ vie_init(struct vie *vie, const char *inst_bytes, uint32_t inst_length)
|
||||
vie->index_register = VM_REG_LAST;
|
||||
vie->segment_register = VM_REG_LAST;
|
||||
|
||||
if (inst_length) {
|
||||
memcpy_s((char *)vie->inst, VIE_INST_SIZE,
|
||||
(char *)inst_bytes, inst_length);
|
||||
vie->num_valid = inst_length;
|
||||
if (inst_len) {
|
||||
int ret;
|
||||
uint64_t guest_rip_gva =
|
||||
vcpu->arch_vcpu.contexts[vcpu->arch_vcpu.cur_context].rip;
|
||||
uint32_t err_code;
|
||||
|
||||
err_code = PAGE_FAULT_ID_FLAG;
|
||||
ret = copy_from_gva(vcpu, vie->inst, guest_rip_gva,
|
||||
inst_len, &err_code);
|
||||
if (ret == -EFAULT) {
|
||||
vcpu_inject_pf(vcpu, guest_rip_gva, err_code);
|
||||
return ret;
|
||||
} else if (ret < 0)
|
||||
return ret;
|
||||
vie->num_valid = inst_len;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
|
@ -72,7 +72,7 @@ int vie_calculate_gla(enum vm_cpu_mode cpu_mode, enum vm_reg_name seg,
|
||||
struct seg_desc *desc, uint64_t off, int length, int addrsize, int prot,
|
||||
uint64_t *gla);
|
||||
|
||||
void vie_init(struct vie *vie, const char *inst_bytes, uint32_t inst_length);
|
||||
int vie_init(struct vie *vie, struct vcpu *vcpu);
|
||||
|
||||
/*
|
||||
* Decode the instruction fetched into 'vie' so it can be emulated.
|
||||
@ -90,6 +90,6 @@ int __decode_instruction(struct vcpu *vcpu, uint64_t gla,
|
||||
enum vm_cpu_mode cpu_mode, int csd, struct vie *vie);
|
||||
|
||||
int emulate_instruction(struct vcpu *vcpu);
|
||||
uint8_t decode_instruction(struct vcpu *vcpu);
|
||||
int decode_instruction(struct vcpu *vcpu);
|
||||
|
||||
#endif /* _VMM_INSTRUCTION_EMUL_H_ */
|
||||
|
@ -307,35 +307,25 @@ int vm_gva2gpa(struct vcpu *vcpu, uint64_t gva, uint64_t *gpa,
|
||||
return gva2gpa(vcpu, gva, gpa, err_code);
|
||||
}
|
||||
|
||||
uint8_t decode_instruction(struct vcpu *vcpu)
|
||||
int decode_instruction(struct vcpu *vcpu)
|
||||
{
|
||||
uint64_t guest_rip_gva, guest_rip_gpa;
|
||||
char *guest_rip_hva;
|
||||
struct emul_cnx *emul_cnx;
|
||||
uint32_t csar;
|
||||
int retval = 0;
|
||||
enum vm_cpu_mode cpu_mode;
|
||||
int error;
|
||||
uint32_t err_code;
|
||||
|
||||
guest_rip_gva =
|
||||
vcpu->arch_vcpu.contexts[vcpu->arch_vcpu.cur_context].rip;
|
||||
|
||||
err_code = PAGE_FAULT_ID_FLAG;
|
||||
error = gva2gpa(vcpu, guest_rip_gva, &guest_rip_gpa, &err_code);
|
||||
if (error) {
|
||||
pr_err("gva2gpa failed for guest_rip_gva 0x%016llx:",
|
||||
guest_rip_gva);
|
||||
return 0;
|
||||
}
|
||||
|
||||
guest_rip_hva = GPA2HVA(vcpu->vm, guest_rip_gpa);
|
||||
emul_cnx = &per_cpu(g_inst_ctxt, vcpu->pcpu_id);
|
||||
emul_cnx->vcpu = vcpu;
|
||||
|
||||
/* by now, HVA <-> HPA is 1:1 mapping, so use hpa is OK*/
|
||||
vie_init(&emul_cnx->vie, guest_rip_hva,
|
||||
vcpu->arch_vcpu.inst_len);
|
||||
retval = vie_init(&emul_cnx->vie, vcpu);
|
||||
if (retval < 0) {
|
||||
if (retval != -EFAULT) {
|
||||
pr_err("decode instruction failed @ 0x%016llx:",
|
||||
vcpu->arch_vcpu.
|
||||
contexts[vcpu->arch_vcpu.cur_context].rip);
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
get_guest_paging_info(vcpu, emul_cnx);
|
||||
csar = exec_vmread(VMX_GUEST_CS_ATTR);
|
||||
@ -346,8 +336,8 @@ uint8_t decode_instruction(struct vcpu *vcpu)
|
||||
|
||||
if (retval != 0) {
|
||||
pr_err("decode instruction failed @ 0x%016llx:",
|
||||
exec_vmread(VMX_GUEST_RIP));
|
||||
return 0;
|
||||
vcpu->arch_vcpu.contexts[vcpu->arch_vcpu.cur_context].rip);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return emul_cnx->vie.opsize;
|
||||
|
@ -2198,7 +2198,7 @@ apicv_inject_pir(struct vlapic *vlapic)
|
||||
|
||||
int apic_access_vmexit_handler(struct vcpu *vcpu)
|
||||
{
|
||||
int access_type, offset;
|
||||
int access_type, offset = 0, ret;
|
||||
uint64_t qual;
|
||||
struct vlapic *vlapic;
|
||||
|
||||
@ -2211,7 +2211,13 @@ int apic_access_vmexit_handler(struct vcpu *vcpu)
|
||||
|
||||
vlapic = vcpu->arch_vcpu.vlapic;
|
||||
|
||||
decode_instruction(vcpu);
|
||||
ret = decode_instruction(vcpu);
|
||||
/* apic access should already fetched instruction, decode_instruction
|
||||
* will not trigger #PF, so if it failed, just return error_no
|
||||
*/
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
if (access_type == 1) {
|
||||
if (!emulate_instruction(vcpu))
|
||||
vlapic_write(vlapic, 1, offset, vcpu->mmio.value);
|
||||
|
Loading…
Reference in New Issue
Block a user