mirror of
https://github.com/projectacrn/acrn-hypervisor.git
synced 2025-06-19 12:12:16 +00:00
hv: add new function to get gva for MOVS/STO instruction
Drop the get_gla function and add - get_gva_di_si_nocheck get gva from ES:DI and DS(other segment):SI without check faulure case - get_gva_di_si_check get gva from ES:DI and DS(other segment):SI with failure case checked TODO: - Save dst_gpa and src_gpa for instruction emulation phase use. Signed-off-by: Yin Fengwei <fengwei.yin@intel.com> Acked-by: Anthony Xu <anthony.xu@intel.com>
This commit is contained in:
parent
8480c98053
commit
b01a81279a
@ -454,7 +454,6 @@ static int vie_calculate_gla(enum vm_cpu_mode cpu_mode, enum cpu_reg_name seg,
|
|||||||
uint64_t firstoff, segbase;
|
uint64_t firstoff, segbase;
|
||||||
uint64_t offset = offset_arg;
|
uint64_t offset = offset_arg;
|
||||||
uint8_t glasize;
|
uint8_t glasize;
|
||||||
uint32_t type;
|
|
||||||
|
|
||||||
firstoff = offset;
|
firstoff = offset;
|
||||||
glasize = (cpu_mode == CPU_MODE_64BIT) ? 8U: 4U;
|
glasize = (cpu_mode == CPU_MODE_64BIT) ? 8U: 4U;
|
||||||
@ -860,52 +859,97 @@ static int emulate_movx(struct vcpu *vcpu, struct instr_emul_vie *vie)
|
|||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/**
|
||||||
* Helper function to calculate and validate a linear address.
|
* @pre only called by instruction emulation and check was done during
|
||||||
|
* instruction decode
|
||||||
|
*
|
||||||
|
* @remark This function can only be called in instruction emulation and
|
||||||
|
* suppose always success because the check was done during instruction
|
||||||
|
* decode.
|
||||||
|
*
|
||||||
|
* It's only used by MOVS/STO
|
||||||
*/
|
*/
|
||||||
static int get_gla(struct vcpu *vcpu, __unused struct instr_emul_vie *vie,
|
static void get_gva_di_si_nocheck(struct vcpu *vcpu, uint8_t addrsize,
|
||||||
struct vm_guest_paging *paging,
|
enum cpu_reg_name seg, enum cpu_reg_name gpr, uint64_t *gva)
|
||||||
uint8_t opsize, uint8_t addrsize, uint32_t prot, enum cpu_reg_name seg,
|
|
||||||
enum cpu_reg_name gpr, uint64_t *gla, int *fault)
|
|
||||||
{
|
{
|
||||||
int ret;
|
uint64_t val;
|
||||||
struct seg_desc desc;
|
struct seg_desc desc;
|
||||||
uint64_t cr0, val, rflags;
|
enum vm_cpu_mode cpu_mode;
|
||||||
|
|
||||||
cr0 = vm_get_register(vcpu, CPU_REG_CR0);
|
|
||||||
rflags = vm_get_register(vcpu, CPU_REG_RFLAGS);
|
|
||||||
val = vm_get_register(vcpu, gpr);
|
val = vm_get_register(vcpu, gpr);
|
||||||
vm_get_seg_desc(seg, &desc);
|
vm_get_seg_desc(seg, &desc);
|
||||||
|
cpu_mode = get_vcpu_mode(vcpu);
|
||||||
|
|
||||||
if (vie_calculate_gla(paging->cpu_mode, seg, &desc, val,
|
(void)vie_calculate_gla(cpu_mode, seg, &desc, val, addrsize, gva);
|
||||||
addrsize, gla) != 0) {
|
|
||||||
if (seg == CPU_REG_SS) {
|
return;
|
||||||
pr_err("TODO: inject ss exception");
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* @pre only called during instruction decode phase
|
||||||
|
*
|
||||||
|
* @remark This function get gva from ES:DI and DS(other segment):SI. And
|
||||||
|
* do check the failure condition and inject exception to guest accordingly.
|
||||||
|
*
|
||||||
|
* It's only used by MOVS/STO
|
||||||
|
*/
|
||||||
|
static int get_gva_di_si_check(struct vcpu *vcpu, uint8_t addrsize,
|
||||||
|
uint32_t prot, enum cpu_reg_name seg, enum cpu_reg_name gpr,
|
||||||
|
uint64_t *gva)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
uint32_t err_code;
|
||||||
|
struct seg_desc desc;
|
||||||
|
enum vm_cpu_mode cpu_mode;
|
||||||
|
uint64_t val, gpa;
|
||||||
|
|
||||||
|
val = vm_get_register(vcpu, gpr);
|
||||||
|
vm_get_seg_desc(seg, &desc);
|
||||||
|
cpu_mode = get_vcpu_mode(vcpu);
|
||||||
|
|
||||||
|
if (!is_desc_valid(&desc, prot)) {
|
||||||
|
goto exception_inject;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cpu_mode == CPU_MODE_64BIT) {
|
||||||
|
if ((addrsize != 4U) && (addrsize != 8U)) {
|
||||||
|
goto exception_inject;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
pr_err("TODO: inject gp exception");
|
if ((addrsize != 2U) && (addrsize != 4U)) {
|
||||||
|
goto exception_inject;
|
||||||
}
|
}
|
||||||
goto guest_fault;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (vie_canonical_check(paging->cpu_mode, *gla) != 0) {
|
if (vie_calculate_gla(cpu_mode, seg, &desc, val, addrsize, gva) != 0) {
|
||||||
if (seg == CPU_REG_SS) {
|
goto exception_inject;
|
||||||
pr_err("TODO: inject ss exception");
|
|
||||||
} else {
|
|
||||||
pr_err("TODO: inject gp exception");
|
|
||||||
}
|
|
||||||
goto guest_fault;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
*fault = 0;
|
if (vie_canonical_check(cpu_mode, *gva) != 0) {
|
||||||
return 0;
|
goto exception_inject;
|
||||||
|
}
|
||||||
|
|
||||||
guest_fault:
|
err_code = (prot == PROT_WRITE) ? PAGE_FAULT_WR_FLAG : 0U;
|
||||||
*fault = 1;
|
ret = gva2gpa(vcpu, (uint64_t)gva, &gpa, &err_code);
|
||||||
|
if (ret < 0) {
|
||||||
|
if (ret == -EFAULT) {
|
||||||
|
vcpu_inject_pf(vcpu, (uint64_t)gva, err_code);
|
||||||
|
}
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int emulate_movs(struct vcpu *vcpu, struct instr_emul_vie *vie,
|
return 0;
|
||||||
struct vm_guest_paging *paging)
|
|
||||||
|
exception_inject:
|
||||||
|
if (seg == CPU_REG_SS) {
|
||||||
|
vcpu_inject_ss(vcpu);
|
||||||
|
} else {
|
||||||
|
vcpu_inject_gp(vcpu, 0U);
|
||||||
|
}
|
||||||
|
return -EFAULT;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int emulate_movs(struct vcpu *vcpu, struct instr_emul_vie *vie)
|
||||||
{
|
{
|
||||||
uint64_t dstaddr, srcaddr;
|
uint64_t dstaddr, srcaddr;
|
||||||
uint64_t rcx, rdi, rsi, rflags;
|
uint64_t rcx, rdi, rsi, rflags;
|
||||||
@ -939,18 +983,10 @@ static int emulate_movs(struct vcpu *vcpu, struct instr_emul_vie *vie,
|
|||||||
}
|
}
|
||||||
|
|
||||||
seg = (vie->seg_override != 0U) ? (vie->segment_register) : CPU_REG_DS;
|
seg = (vie->seg_override != 0U) ? (vie->segment_register) : CPU_REG_DS;
|
||||||
error = get_gla(vcpu, vie, paging, opsize, vie->addrsize,
|
|
||||||
PROT_READ, seg, CPU_REG_RSI, &srcaddr, &fault);
|
|
||||||
if ((error != 0) || (fault != 0)) {
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
|
|
||||||
error = get_gla(vcpu, vie, paging, opsize, vie->addrsize,
|
get_gva_di_si_nocheck(vcpu, vie->addrsize, seg, CPU_REG_RSI, &srcaddr);
|
||||||
PROT_WRITE, CPU_REG_ES, CPU_REG_RDI, &dstaddr,
|
get_gva_di_si_nocheck(vcpu, vie->addrsize, CPU_REG_ES, CPU_REG_RDI,
|
||||||
&fault);
|
&dstaddr);
|
||||||
if ((error != 0) || (fault != 0)) {
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
|
|
||||||
(void)memcpy_s((void *)dstaddr, 16U, (void *)srcaddr, opsize);
|
(void)memcpy_s((void *)dstaddr, 16U, (void *)srcaddr, opsize);
|
||||||
|
|
||||||
@ -1520,7 +1556,7 @@ static int vmm_emulate_instruction(struct instr_emul_ctxt *ctxt)
|
|||||||
error = emulate_movx(vcpu, vie);
|
error = emulate_movx(vcpu, vie);
|
||||||
break;
|
break;
|
||||||
case VIE_OP_TYPE_MOVS:
|
case VIE_OP_TYPE_MOVS:
|
||||||
error = emulate_movs(vcpu, vie, paging);
|
error = emulate_movs(vcpu, vie);
|
||||||
break;
|
break;
|
||||||
case VIE_OP_TYPE_STOS:
|
case VIE_OP_TYPE_STOS:
|
||||||
error = emulate_stos(vcpu, vie);
|
error = emulate_stos(vcpu, vie);
|
||||||
|
Loading…
Reference in New Issue
Block a user