# HG changeset patch
# User kaf24@xxxxxxxxxxxxxxxxxxxxx
# Node ID b61b7478b3245daac1d76a2eadb6f33123aec85c
# Parent fab84f9c0ce6d5d1fb89b31ef071148f781ae5a6
[HVM][SVM] Allow SVM to take advantage of flag_dr_dirty.
Signed-off-by: Travis Betak <travis.betak@xxxxxxx>
---
xen/arch/x86/hvm/svm/svm.c | 155 ++++++++++++++-----------------------
xen/arch/x86/hvm/svm/vmcb.c | 2
xen/include/asm-x86/hvm/svm/vmcb.h | 45 ++++++++++
3 files changed, 105 insertions(+), 97 deletions(-)
diff -r fab84f9c0ce6 -r b61b7478b324 xen/arch/x86/hvm/svm/svm.c
--- a/xen/arch/x86/hvm/svm/svm.c Mon Aug 28 12:09:36 2006 +0100
+++ b/xen/arch/x86/hvm/svm/svm.c Mon Aug 28 12:35:43 2006 +0100
@@ -403,6 +403,50 @@ static inline int long_mode_do_msr_write
return 1;
}
+
+#define loaddebug(_v,_reg) \
+ __asm__ __volatile__ ("mov %0,%%db" #_reg : : "r" ((_v)->debugreg[_reg]))
+#define savedebug(_v,_reg) \
+ __asm__ __volatile__ ("mov %%db" #_reg ",%0" : : "r"
((_v)->debugreg[_reg]))
+
+
+static inline void svm_save_dr(struct vcpu *v)
+{
+ if (v->arch.hvm_vcpu.flag_dr_dirty)
+ {
+ /* clear the DR dirty flag and re-enable intercepts for DR accesses */
+ v->arch.hvm_vcpu.flag_dr_dirty = 0;
+ v->arch.hvm_svm.vmcb->dr_intercepts = DR_INTERCEPT_ALL_WRITES;
+
+ savedebug(&v->arch.guest_context, 0);
+ savedebug(&v->arch.guest_context, 1);
+ savedebug(&v->arch.guest_context, 2);
+ savedebug(&v->arch.guest_context, 3);
+ }
+}
+
+
+static inline void __restore_debug_registers(struct vcpu *v)
+{
+ loaddebug(&v->arch.guest_context, 0);
+ loaddebug(&v->arch.guest_context, 1);
+ loaddebug(&v->arch.guest_context, 2);
+ loaddebug(&v->arch.guest_context, 3);
+}
+
+
+static inline void svm_restore_dr(struct vcpu *v)
+{
+ struct vmcb_struct *vmcb = v->arch.hvm_svm.vmcb;
+
+ if (!vmcb)
+ return;
+
+ if (unlikely(vmcb->dr7 & 0xFF))
+ __restore_debug_registers(v);
+}
+
+
static int svm_realmode(struct vcpu *v)
{
unsigned long cr0 = v->arch.hvm_svm.cpu_shadow_cr0;
@@ -717,6 +761,7 @@ static void svm_ctxt_switch_from(struct
static void svm_ctxt_switch_from(struct vcpu *v)
{
svm_freeze_time(v);
+ svm_save_dr(v);
}
static void svm_ctxt_switch_to(struct vcpu *v)
@@ -732,6 +777,7 @@ static void svm_ctxt_switch_to(struct vc
set_segment_register(es, 0);
set_segment_register(ss, 0);
#endif
+ svm_restore_dr(v);
}
@@ -1183,55 +1229,16 @@ static inline void set_reg(unsigned int
}
-static void svm_dr_access (struct vcpu *v, unsigned int reg, unsigned int type,
- struct cpu_user_regs *regs)
-{
- unsigned long *reg_p = 0;
- unsigned int gpreg = 0;
- unsigned long eip;
- int inst_len;
- int index;
- struct vmcb_struct *vmcb;
- u8 buffer[MAX_INST_LEN];
- u8 prefix = 0;
-
- vmcb = v->arch.hvm_svm.vmcb;
-
- ASSERT(vmcb);
-
- eip = vmcb->rip;
- inst_copy_from_guest(buffer, svm_rip2pointer(vmcb), sizeof(buffer));
- index = skip_prefix_bytes(buffer, sizeof(buffer));
-
- ASSERT(buffer[index+0] == 0x0f && (buffer[index+1] & 0xFD) == 0x21);
-
- if (index > 0 && (buffer[index-1] & 0xF0) == 0x40)
- prefix = buffer[index-1];
-
- gpreg = decode_src_reg(prefix, buffer[index + 2]);
- ASSERT(reg == decode_dest_reg(prefix, buffer[index + 2]));
-
- HVM_DBG_LOG(DBG_LEVEL_1, "svm_dr_access : eip=%lx, reg=%d, gpreg = %x",
- eip, reg, gpreg);
-
- reg_p = get_reg_p(gpreg, regs, vmcb);
-
- switch (type)
- {
- case TYPE_MOV_TO_DR:
- inst_len = __get_instruction_length(vmcb, INSTR_MOV2DR, buffer);
- v->arch.guest_context.debugreg[reg] = *reg_p;
- break;
- case TYPE_MOV_FROM_DR:
- inst_len = __get_instruction_length(vmcb, INSTR_MOVDR2, buffer);
- *reg_p = v->arch.guest_context.debugreg[reg];
- break;
- default:
- __hvm_bug(regs);
- break;
- }
- ASSERT(inst_len > 0);
- __update_guest_eip(vmcb, inst_len);
+static void svm_dr_access(struct vcpu *v, struct cpu_user_regs *regs)
+{
+ struct vmcb_struct *vmcb = v->arch.hvm_svm.vmcb;
+
+ v->arch.hvm_vcpu.flag_dr_dirty = 1;
+
+ __restore_debug_registers(v);
+
+ /* allow the guest full access to the debug registers */
+ vmcb->dr_intercepts = 0;
}
@@ -2862,53 +2869,9 @@ asmlinkage void svm_vmexit_handler(struc
case VMEXIT_CR8_WRITE:
svm_cr_access(v, 8, TYPE_MOV_TO_CR, ®s);
break;
-
- case VMEXIT_DR0_READ:
- svm_dr_access(v, 0, TYPE_MOV_FROM_DR, ®s);
- break;
-
- case VMEXIT_DR1_READ:
- svm_dr_access(v, 1, TYPE_MOV_FROM_DR, ®s);
- break;
-
- case VMEXIT_DR2_READ:
- svm_dr_access(v, 2, TYPE_MOV_FROM_DR, ®s);
- break;
-
- case VMEXIT_DR3_READ:
- svm_dr_access(v, 3, TYPE_MOV_FROM_DR, ®s);
- break;
-
- case VMEXIT_DR6_READ:
- svm_dr_access(v, 6, TYPE_MOV_FROM_DR, ®s);
- break;
-
- case VMEXIT_DR7_READ:
- svm_dr_access(v, 7, TYPE_MOV_FROM_DR, ®s);
- break;
-
- case VMEXIT_DR0_WRITE:
- svm_dr_access(v, 0, TYPE_MOV_TO_DR, ®s);
- break;
-
- case VMEXIT_DR1_WRITE:
- svm_dr_access(v, 1, TYPE_MOV_TO_DR, ®s);
- break;
-
- case VMEXIT_DR2_WRITE:
- svm_dr_access(v, 2, TYPE_MOV_TO_DR, ®s);
- break;
-
- case VMEXIT_DR3_WRITE:
- svm_dr_access(v, 3, TYPE_MOV_TO_DR, ®s);
- break;
-
- case VMEXIT_DR6_WRITE:
- svm_dr_access(v, 6, TYPE_MOV_TO_DR, ®s);
- break;
-
- case VMEXIT_DR7_WRITE:
- svm_dr_access(v, 7, TYPE_MOV_TO_DR, ®s);
+
+ case VMEXIT_DR0_WRITE ... VMEXIT_DR7_WRITE:
+ svm_dr_access(v, ®s);
break;
case VMEXIT_IOIO:
diff -r fab84f9c0ce6 -r b61b7478b324 xen/arch/x86/hvm/svm/vmcb.c
--- a/xen/arch/x86/hvm/svm/vmcb.c Mon Aug 28 12:09:36 2006 +0100
+++ b/xen/arch/x86/hvm/svm/vmcb.c Mon Aug 28 12:35:43 2006 +0100
@@ -121,7 +121,7 @@ static int construct_vmcb_controls(struc
GENERAL2_INTERCEPT_SKINIT | GENERAL2_INTERCEPT_RDTSCP;
/* read or write all debug registers 0 - 15 */
- vmcb->dr_intercepts = 0;
+ vmcb->dr_intercepts = DR_INTERCEPT_ALL_WRITES;
/* RD/WR all control registers 0 - 15, but not read CR2 */
vmcb->cr_intercepts = ~(CR_INTERCEPT_CR2_READ | CR_INTERCEPT_CR2_WRITE);
diff -r fab84f9c0ce6 -r b61b7478b324 xen/include/asm-x86/hvm/svm/vmcb.h
--- a/xen/include/asm-x86/hvm/svm/vmcb.h Mon Aug 28 12:09:36 2006 +0100
+++ b/xen/include/asm-x86/hvm/svm/vmcb.h Mon Aug 28 12:35:43 2006 +0100
@@ -113,6 +113,51 @@ enum CRInterceptBits
CR_INTERCEPT_CR14_WRITE = 1 << 30,
CR_INTERCEPT_CR15_WRITE = 1 << 31,
};
+
+
+/* debug register intercepts */
+enum DRInterceptBits
+{
+ DR_INTERCEPT_DR0_READ = 1 << 0,
+ DR_INTERCEPT_DR1_READ = 1 << 1,
+ DR_INTERCEPT_DR2_READ = 1 << 2,
+ DR_INTERCEPT_DR3_READ = 1 << 3,
+ DR_INTERCEPT_DR4_READ = 1 << 4,
+ DR_INTERCEPT_DR5_READ = 1 << 5,
+ DR_INTERCEPT_DR6_READ = 1 << 6,
+ DR_INTERCEPT_DR7_READ = 1 << 7,
+ DR_INTERCEPT_DR8_READ = 1 << 8,
+ DR_INTERCEPT_DR9_READ = 1 << 9,
+ DR_INTERCEPT_DR10_READ = 1 << 10,
+ DR_INTERCEPT_DR11_READ = 1 << 11,
+ DR_INTERCEPT_DR12_READ = 1 << 12,
+ DR_INTERCEPT_DR13_READ = 1 << 13,
+ DR_INTERCEPT_DR14_READ = 1 << 14,
+ DR_INTERCEPT_DR15_READ = 1 << 15,
+ DR_INTERCEPT_DR0_WRITE = 1 << 16,
+ DR_INTERCEPT_DR1_WRITE = 1 << 17,
+ DR_INTERCEPT_DR2_WRITE = 1 << 18,
+ DR_INTERCEPT_DR3_WRITE = 1 << 19,
+ DR_INTERCEPT_DR4_WRITE = 1 << 20,
+ DR_INTERCEPT_DR5_WRITE = 1 << 21,
+ DR_INTERCEPT_DR6_WRITE = 1 << 22,
+ DR_INTERCEPT_DR7_WRITE = 1 << 23,
+ DR_INTERCEPT_DR8_WRITE = 1 << 24,
+ DR_INTERCEPT_DR9_WRITE = 1 << 25,
+ DR_INTERCEPT_DR10_WRITE = 1 << 26,
+ DR_INTERCEPT_DR11_WRITE = 1 << 27,
+ DR_INTERCEPT_DR12_WRITE = 1 << 28,
+ DR_INTERCEPT_DR13_WRITE = 1 << 29,
+ DR_INTERCEPT_DR14_WRITE = 1 << 30,
+ DR_INTERCEPT_DR15_WRITE = 1 << 31,
+};
+
+/* for lazy save/restore we'd like to intercept all DR writes */
+#define DR_INTERCEPT_ALL_WRITES \
+ (DR_INTERCEPT_DR0_WRITE|DR_INTERCEPT_DR1_WRITE|DR_INTERCEPT_DR2_WRITE \
+ |DR_INTERCEPT_DR3_WRITE|DR_INTERCEPT_DR4_WRITE|DR_INTERCEPT_DR5_WRITE \
+ |DR_INTERCEPT_DR6_WRITE|DR_INTERCEPT_DR7_WRITE)
+
enum VMEXIT_EXITCODE
{
_______________________________________________
Xen-changelog mailing list
Xen-changelog@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-changelog
|