# HG changeset patch
# User Keir Fraser <keir@xxxxxxx>
# Date 1303130170 -3600
# Node ID 60f5df2afcbbe1e8d8438c2b7b8223d9d2102e06
# Parent 381ab77db71a4739b8a4f4fdad4ef3504999f998
svm: implement instruction fetch part of DecodeAssist (on #PF/#NPF)
Newer SVM implementations (Bulldozer) copy up to 15 bytes from the
instruction stream into the VMCB when a #PF or #NPF exception is
intercepted. This patch makes use of this information if available.
This saves us from a) traversing the guest's page tables, b) mapping
the guest's memory and c) copy the instructions from there into the
hypervisor's address space.
This speeds up #NPF intercepts quite a lot and avoids cache and TLB
trashing.
Signed-off-by: Andre Przywara <andre.przywara@xxxxxxx>
Signed-off-by: Keir Fraser <keir@xxxxxxx>
---
diff -r 381ab77db71a -r 60f5df2afcbb xen/arch/x86/hvm/emulate.c
--- a/xen/arch/x86/hvm/emulate.c Mon Apr 18 10:10:02 2011 +0100
+++ b/xen/arch/x86/hvm/emulate.c Mon Apr 18 13:36:10 2011 +0100
@@ -996,6 +996,8 @@
hvmemul_ctxt->insn_buf_eip = regs->eip;
hvmemul_ctxt->insn_buf_bytes =
+ hvm_get_insn_bytes(curr, hvmemul_ctxt->insn_buf)
+ ? :
(hvm_virtual_to_linear_addr(
x86_seg_cs, &hvmemul_ctxt->seg_reg[x86_seg_cs],
regs->eip, sizeof(hvmemul_ctxt->insn_buf),
diff -r 381ab77db71a -r 60f5df2afcbb xen/arch/x86/hvm/svm/svm.c
--- a/xen/arch/x86/hvm/svm/svm.c Mon Apr 18 10:10:02 2011 +0100
+++ b/xen/arch/x86/hvm/svm/svm.c Mon Apr 18 13:36:10 2011 +0100
@@ -660,6 +660,21 @@
vmcb_set_general1_intercepts(vmcb, general1_intercepts);
}
+static unsigned int svm_get_insn_bytes(struct vcpu *v, uint8_t *buf)
+{
+ struct vmcb_struct *vmcb = v->arch.hvm_svm.vmcb;
+ unsigned int len = v->arch.hvm_svm.cached_insn_len;
+
+ if ( len != 0 )
+ {
+ /* Latch and clear the cached instruction. */
+ memcpy(buf, vmcb->guest_ins, 15);
+ v->arch.hvm_svm.cached_insn_len = 0;
+ }
+
+ return len;
+}
+
static void svm_init_hypercall_page(struct domain *d, void *hypercall_page)
{
char *p;
@@ -1650,6 +1665,7 @@
.msr_write_intercept = svm_msr_write_intercept,
.invlpg_intercept = svm_invlpg_intercept,
.set_rdtsc_exiting = svm_set_rdtsc_exiting,
+ .get_insn_bytes = svm_get_insn_bytes,
.nhvm_vcpu_initialise = nsvm_vcpu_initialise,
.nhvm_vcpu_destroy = nsvm_vcpu_destroy,
@@ -1836,7 +1852,12 @@
(unsigned long)regs->ecx, (unsigned long)regs->edx,
(unsigned long)regs->esi, (unsigned long)regs->edi);
- if ( paging_fault(va, regs) )
+ if ( cpu_has_svm_decode )
+ v->arch.hvm_svm.cached_insn_len = vmcb->guest_ins_len & 0xf;
+ rc = paging_fault(va, regs);
+ v->arch.hvm_svm.cached_insn_len = 0;
+
+ if ( rc )
{
if ( trace_will_trace_event(TRC_SHADOW) )
break;
@@ -2013,7 +2034,10 @@
case VMEXIT_NPF:
perfc_incra(svmexits, VMEXIT_NPF_PERFC);
regs->error_code = vmcb->exitinfo1;
+ if ( cpu_has_svm_decode )
+ v->arch.hvm_svm.cached_insn_len = vmcb->guest_ins_len & 0xf;
svm_do_nested_pgfault(v, regs, vmcb->exitinfo2);
+ v->arch.hvm_svm.cached_insn_len = 0;
break;
case VMEXIT_IRET: {
diff -r 381ab77db71a -r 60f5df2afcbb xen/include/asm-x86/hvm/hvm.h
--- a/xen/include/asm-x86/hvm/hvm.h Mon Apr 18 10:10:02 2011 +0100
+++ b/xen/include/asm-x86/hvm/hvm.h Mon Apr 18 13:36:10 2011 +0100
@@ -133,6 +133,9 @@
int (*cpu_up)(void);
void (*cpu_down)(void);
+ /* Copy up to 15 bytes from cached instruction bytes at current rIP. */
+ unsigned int (*get_insn_bytes)(struct vcpu *v, uint8_t *buf);
+
/* Instruction intercepts: non-void return values are X86EMUL codes. */
void (*cpuid_intercept)(
unsigned int *eax, unsigned int *ebx,
@@ -342,6 +345,11 @@
hvm_funcs.cpu_down();
}
+static inline unsigned int hvm_get_insn_bytes(struct vcpu *v, uint8_t *buf)
+{
+ return (hvm_funcs.get_insn_bytes ? hvm_funcs.get_insn_bytes(v, buf) : 0);
+}
+
enum hvm_task_switch_reason { TSW_jmp, TSW_iret, TSW_call_or_int };
void hvm_task_switch(
uint16_t tss_sel, enum hvm_task_switch_reason taskswitch_reason,
diff -r 381ab77db71a -r 60f5df2afcbb xen/include/asm-x86/hvm/svm/vmcb.h
--- a/xen/include/asm-x86/hvm/svm/vmcb.h Mon Apr 18 10:10:02 2011 +0100
+++ b/xen/include/asm-x86/hvm/svm/vmcb.h Mon Apr 18 13:36:10 2011 +0100
@@ -501,6 +501,9 @@
int launch_core;
bool_t vmcb_in_sync; /* VMCB sync'ed with VMSAVE? */
+ /* VMCB has a cached instruction from #PF/#NPF Decode Assist? */
+ uint8_t cached_insn_len; /* Zero if no cached instruction. */
+
/* Upper four bytes are undefined in the VMCB, therefore we can't
* use the fields in the VMCB. Write a 64bit value and then read a 64bit
* value is fine unless there's a VMRUN/VMEXIT in between which clears
_______________________________________________
Xen-changelog mailing list
Xen-changelog@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-changelog
|