From: Andrew Cooper Date: Fri, 22 Apr 2016 08:44:53 +0000 (+0100) Subject: x86/hvm: Correct the emulated interaction of invlpg with segments X-Git-Tag: archive/raspbian/4.8.0-1+rpi1~1^2~1138 X-Git-Url: https://dgit.raspbian.org/?a=commitdiff_plain;h=a373db28eaa1e9011db00cc6359b8ee1112c80e0;p=xen.git x86/hvm: Correct the emulated interaction of invlpg with segments The `invlpg` instruction is documented to take a memory address, and is not documented to suffer faults from segmentation violations. It is also explicitly documented to be a NOP when issued on a non-canonical address. Experimentally, and subsequently confirmed by both Intel and AMD, the instruction does take into account segment bases, but will happily invalidate a TLB entry for a mapping beyond the segment limit. The emulation logic will currently raise #GP/#SS faults for segment limit violations, or non-canonical addresses, which doesn't match hardware's behaviour. Instead, squash exceptions generated by hvmemul_virtual_to_linear() and proceed with invalidation. Signed-off-by: Andrew Cooper Reviewed-by: Jan Beulich Reviewed-by: Paul Durrant Release-acked-by: Wei Liu --- diff --git a/xen/arch/x86/hvm/emulate.c b/xen/arch/x86/hvm/emulate.c index ee5cf1f867..e6316be741 100644 --- a/xen/arch/x86/hvm/emulate.c +++ b/xen/arch/x86/hvm/emulate.c @@ -1608,7 +1608,22 @@ static int hvmemul_invlpg( rc = hvmemul_virtual_to_linear( seg, offset, 1, &reps, hvm_access_none, hvmemul_ctxt, &addr); - if ( rc == X86EMUL_OKAY ) + if ( rc == X86EMUL_EXCEPTION ) + { + /* + * `invlpg` takes segment bases into account, but is not subject to + * faults from segment type/limit checks, and is specified as a NOP + * when issued on non-canonical addresses. + * + * hvmemul_virtual_to_linear() raises exceptions for type/limit + * violations, so squash them. + */ + hvmemul_ctxt->exn_pending = 0; + hvmemul_ctxt->trap = (struct hvm_trap){}; + rc = X86EMUL_OKAY; + } + + if ( rc == X86EMUL_OKAY && is_canonical_address(addr) ) hvm_funcs.invlpg_intercept(addr); return rc;