Skip to content

Commit 4579e57

Browse files
fyin1lijinxia
authored andcommitted
hv: add gva check for the case gva is from instruction decode
For the instructions other than MOVS, one operand is register and another one is memory which trigger EPT voilation. In this case, there is one possibility that EPT voilation happens before guest fault: the fault is triggered by related guest PTE access bit voilation (like write to a gva with R/W bit cleared in PTE). So we do this kind of check and inject exception to guest accordingly during instruction decoding phase. Signed-off-by: Yin Fengwei <fengwei.yin@intel.com> Acked-by: Anthony Xu <anthony.xu@intel.com>
1 parent 7dde0df commit 4579e57

File tree

1 file changed

+87
-0
lines changed

1 file changed

+87
-0
lines changed

hypervisor/arch/x86/guest/instr_emul.c

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2138,6 +2138,91 @@ static int instr_check_di(struct vcpu *vcpu, struct instr_emul_ctxt *emul_ctxt)
21382138
}
21392139
}
21402140

2141+
static int instr_check_gva(struct vcpu *vcpu, struct instr_emul_ctxt *emul_ctxt,
2142+
enum vm_cpu_mode cpu_mode)
2143+
{
2144+
int ret = 0;
2145+
uint64_t base, segbase, idx, gva, gpa;
2146+
uint32_t err_code;
2147+
enum cpu_reg_name seg;
2148+
struct instr_emul_vie *vie = &emul_ctxt->vie;
2149+
2150+
base = 0UL;
2151+
if (vie->base_register != CPU_REG_LAST) {
2152+
base = vm_get_register(vcpu, vie->base_register);
2153+
2154+
/* RIP relative addressing starts from the
2155+
* following instruction
2156+
*/
2157+
if (vie->base_register == CPU_REG_RIP)
2158+
base += vie->num_processed;
2159+
2160+
}
2161+
2162+
idx = 0UL;
2163+
if (vie->index_register != CPU_REG_LAST) {
2164+
idx = vm_get_register(vcpu, vie->index_register);
2165+
}
2166+
2167+
/* "Specifying a Segment Selector" of SDM Vol1 3.7.4
2168+
*
2169+
* In legacy IA-32 mode, when ESP or EBP register is used as
2170+
* base, the SS segment is default segment.
2171+
*
2172+
* All data references, except when relative to stack or
2173+
* string destination, DS is default segment.
2174+
*
2175+
* segment override could overwrite the default segment
2176+
*
2177+
* 64bit mode, segmentation is generally disabled. The
2178+
* exception are FS and GS.
2179+
*/
2180+
if (vie->seg_override != 0U) {
2181+
seg = vie->segment_register;
2182+
} else if ((vie->base_register == CPU_REG_RSP) ||
2183+
(vie->base_register == CPU_REG_RBP)) {
2184+
seg = CPU_REG_SS;
2185+
} else {
2186+
seg = CPU_REG_DS;
2187+
}
2188+
2189+
if ((cpu_mode == CPU_MODE_64BIT) && (seg != CPU_REG_FS) &&
2190+
(seg != CPU_REG_GS)) {
2191+
segbase = 0UL;
2192+
} else {
2193+
struct seg_desc desc;
2194+
2195+
vm_get_seg_desc(seg, &desc);
2196+
2197+
segbase = desc.base;
2198+
}
2199+
2200+
gva = segbase + base + vie->scale * idx + vie->displacement;
2201+
2202+
if (vie_canonical_check(cpu_mode, gva) != 0) {
2203+
if (seg == CPU_REG_SS) {
2204+
vcpu_inject_ss(vcpu);
2205+
} else {
2206+
vcpu_inject_gp(vcpu, 0U);
2207+
}
2208+
return -EFAULT;
2209+
}
2210+
2211+
err_code = (vcpu->req.reqs.mmio.direction == REQUEST_WRITE) ?
2212+
PAGE_FAULT_WR_FLAG : 0U;
2213+
2214+
ret = gva2gpa(vcpu, gva, &gpa, &err_code);
2215+
if (ret < 0) {
2216+
if (ret == -EFAULT) {
2217+
vcpu_inject_pf(vcpu, gva,
2218+
err_code);
2219+
}
2220+
return ret;
2221+
}
2222+
2223+
return 0;
2224+
}
2225+
21412226
int decode_instruction(struct vcpu *vcpu)
21422227
{
21432228
struct instr_emul_ctxt *emul_ctxt;
@@ -2190,6 +2275,8 @@ int decode_instruction(struct vcpu *vcpu)
21902275
retval = instr_check_di(vcpu, emul_ctxt);
21912276
if (retval < 0)
21922277
return retval;
2278+
} else {
2279+
instr_check_gva(vcpu, emul_ctxt, cpu_mode);
21932280
}
21942281

21952282
return emul_ctxt->vie.opsize;

0 commit comments

Comments
 (0)