# HG changeset patch
# User kfraser@xxxxxxxxxxxxxxxxxxxxx
# Node ID 2b99c99f96e67572d33dc1117a6f402ab90d2d3d
# Parent c33272c2571c7bab7056d8228490700d1df405f9
[HVM][VMX] Enable VMX TPR shadow feature.
x64 Windows uses CR8 to access TPR very frequently. This patch enables
TPR shadow and allows mov-from/to-CR8 to access it directly; tests
indicates it can boost greatly the performance of x64 Windows 2003.
Signed-off-by: Eddie Dong <eddie.dong@xxxxxxxxx>
Signed-off-by: Yunhong Jiang <yunhong.jiang@xxxxxxxxx>
Signed-off-by: Dexuan Cui <dexuan.cui@xxxxxxxxx>
---
xen/arch/x86/hvm/vlapic.c | 19 +++++++++++++------
xen/arch/x86/hvm/vmx/io.c | 25 +++++++++++++++++++++++++
xen/arch/x86/hvm/vmx/vmcs.c | 23 +++++++++++++++--------
xen/arch/x86/hvm/vmx/vmx.c | 5 +++++
xen/include/asm-x86/hvm/vlapic.h | 25 ++++++++++++++++++++++++-
5 files changed, 82 insertions(+), 15 deletions(-)
diff -r c33272c2571c -r 2b99c99f96e6 xen/arch/x86/hvm/vlapic.c
--- a/xen/arch/x86/hvm/vlapic.c Mon Oct 30 09:45:17 2006 +0000
+++ b/xen/arch/x86/hvm/vlapic.c Mon Oct 30 10:42:27 2006 +0000
@@ -217,8 +217,7 @@ static int vlapic_accept_irq(struct vcpu
if ( unlikely(vlapic == NULL || !vlapic_enabled(vlapic)) )
break;
- if ( vlapic_test_and_set_vector(vector, vlapic->regs + APIC_IRR) &&
- trig_mode)
+ if ( vlapic_test_and_set_irr(vector, vlapic) && trig_mode )
{
HVM_DBG_LOG(DBG_LEVEL_VLAPIC,
"level trig mode repeatedly for vector %d\n", vector);
@@ -482,6 +481,11 @@ static void vlapic_read_aligned(struct v
*result = 0;
switch ( offset ) {
+ case APIC_PROCPRI:
+ vlapic_update_ppr(vlapic);
+ *result = vlapic_get_reg(vlapic, offset);
+ break;
+
case APIC_ARBPRI:
printk("access local APIC ARBPRI register which is for P6\n");
break;
@@ -616,6 +620,7 @@ static void vlapic_write(struct vcpu *v,
case APIC_TASKPRI:
vlapic_set_reg(vlapic, APIC_TASKPRI, val & 0xff);
vlapic_update_ppr(vlapic);
+ vlapic->flush_tpr_threshold = 1;
break;
case APIC_EOI:
@@ -814,7 +819,7 @@ void vlapic_timer_fn(void *data)
vlapic->timer_last_update = now;
- if ( vlapic_test_and_set_vector(timer_vector, vlapic->regs + APIC_IRR) )
+ if ( vlapic_test_and_set_irr(timer_vector, vlapic) )
vlapic->intr_pending_count[timer_vector]++;
if ( vlapic_lvtt_period(vlapic) )
@@ -891,7 +896,7 @@ int cpu_get_apic_interrupt(struct vcpu *
HVM_DBG_LOG(DBG_LEVEL_VLAPIC,
"Sending an illegal vector 0x%x.", highest_irr);
- vlapic_set_vector(err_vector, vlapic->regs + APIC_IRR);
+ vlapic_set_irr(err_vector, vlapic);
highest_irr = err_vector;
}
@@ -942,7 +947,7 @@ void vlapic_post_injection(struct vcpu *
case APIC_DM_FIXED:
case APIC_DM_LOWEST:
vlapic_set_vector(vector, vlapic->regs + APIC_ISR);
- vlapic_clear_vector(vector, vlapic->regs + APIC_IRR);
+ vlapic_clear_irr(vector, vlapic);
vlapic_update_ppr(vlapic);
if ( vector == vlapic_lvt_vector(vlapic, APIC_LVTT) )
@@ -950,7 +955,7 @@ void vlapic_post_injection(struct vcpu *
if ( vlapic->intr_pending_count[vector] > 0 )
{
vlapic->intr_pending_count[vector]--;
- vlapic_test_and_set_vector(vector, vlapic->regs + APIC_IRR);
+ vlapic_set_irr(vector, vlapic);
}
}
break;
@@ -1000,6 +1005,8 @@ static int vlapic_reset(struct vlapic *v
vlapic_set_reg(vlapic, APIC_SPIV, 0xff);
vlapic->apic_base_msr = MSR_IA32_APICBASE_ENABLE | APIC_DEFAULT_PHYS_BASE;
+
+ vlapic->flush_tpr_threshold = 0;
if ( v->vcpu_id == 0 )
vlapic->apic_base_msr |= MSR_IA32_APICBASE_BSP;
diff -r c33272c2571c -r 2b99c99f96e6 xen/arch/x86/hvm/vmx/io.c
--- a/xen/arch/x86/hvm/vmx/io.c Mon Oct 30 09:45:17 2006 +0000
+++ b/xen/arch/x86/hvm/vmx/io.c Mon Oct 30 10:42:27 2006 +0000
@@ -68,6 +68,27 @@ static inline int is_interruptibility_st
return interruptibility;
}
+#ifdef __x86_64__
+static void update_tpr_threshold(struct vlapic *vlapic)
+{
+ int highest_irr, tpr;
+
+ /* Clear the work-to-do flag /then/ do the work. */
+ vlapic->flush_tpr_threshold = 0;
+ mb();
+
+ highest_irr = vlapic_find_highest_irr(vlapic);
+ tpr = vlapic_get_reg(vlapic, APIC_TASKPRI) & 0xF0;
+
+ if ( highest_irr == -1 )
+ __vmwrite(TPR_THRESHOLD, 0);
+ else
+ __vmwrite(TPR_THRESHOLD,
+ (highest_irr > tpr) ? (tpr >> 4) : (highest_irr >> 4));
+}
+#else
+#define update_tpr_threshold(v) ((void)0)
+#endif
asmlinkage void vmx_intr_assist(void)
{
@@ -75,6 +96,7 @@ asmlinkage void vmx_intr_assist(void)
int highest_vector;
unsigned long eflags;
struct vcpu *v = current;
+ struct vlapic *vlapic = VLAPIC(v);
struct hvm_domain *plat=&v->domain->arch.hvm_domain;
struct periodic_time *pt = &plat->pl_time.periodic_tm;
struct hvm_virpic *pic= &plat->vpic;
@@ -97,6 +119,9 @@ asmlinkage void vmx_intr_assist(void)
if ( callback_irq != 0 )
pic_set_xen_irq(pic, callback_irq, local_events_need_delivery());
}
+
+ if ( vlapic && vlapic_enabled(vlapic) && vlapic->flush_tpr_threshold )
+ update_tpr_threshold(vlapic);
has_ext_irq = cpu_has_pending_irq(v);
diff -r c33272c2571c -r 2b99c99f96e6 xen/arch/x86/hvm/vmx/vmcs.c
--- a/xen/arch/x86/hvm/vmx/vmcs.c Mon Oct 30 09:45:17 2006 +0000
+++ b/xen/arch/x86/hvm/vmx/vmcs.c Mon Oct 30 10:42:27 2006 +0000
@@ -346,8 +346,21 @@ static void vmx_do_launch(struct vcpu *v
hvm_stts(v);
- if(hvm_apic_support(v->domain))
- vlapic_init(v);
+ if( hvm_apic_support(v->domain) && (vlapic_init(v) == 0) )
+ {
+#ifdef __x86_64__
+ u32 *cpu_exec_control = &v->arch.hvm_vcpu.u.vmx.exec_control;
+ u64 vapic_page_addr =
+ page_to_maddr(v->arch.hvm_vcpu.vlapic->regs_page);
+
+ *cpu_exec_control |= CPU_BASED_TPR_SHADOW;
+ *cpu_exec_control &= ~CPU_BASED_CR8_STORE_EXITING;
+ *cpu_exec_control &= ~CPU_BASED_CR8_LOAD_EXITING;
+ error |= __vmwrite(CPU_BASED_VM_EXEC_CONTROL, *cpu_exec_control);
+ error |= __vmwrite(VIRTUAL_APIC_PAGE_ADDR, vapic_page_addr);
+ error |= __vmwrite(TPR_THRESHOLD, 0);
+#endif
+ }
vmx_set_host_env(v);
init_timer(&v->arch.hvm_vcpu.hlt_timer, hlt_timer_fn, v, v->processor);
@@ -514,12 +527,6 @@ static inline int construct_vmcs_host(vo
error |= __vmwrite(HOST_CR4, crn);
error |= __vmwrite(HOST_RIP, (unsigned long) vmx_asm_vmexit_handler);
-#ifdef __x86_64__
- /* TBD: support cr8 for 64-bit guest */
- __vmwrite(VIRTUAL_APIC_PAGE_ADDR, 0);
- __vmwrite(TPR_THRESHOLD, 0);
- __vmwrite(SECONDARY_VM_EXEC_CONTROL, 0);
-#endif
return error;
}
diff -r c33272c2571c -r 2b99c99f96e6 xen/arch/x86/hvm/vmx/vmx.c
--- a/xen/arch/x86/hvm/vmx/vmx.c Mon Oct 30 09:45:17 2006 +0000
+++ b/xen/arch/x86/hvm/vmx/vmx.c Mon Oct 30 10:42:27 2006 +0000
@@ -2409,6 +2409,11 @@ asmlinkage void vmx_vmexit_handler(struc
vmx_inject_hw_exception(v, TRAP_invalid_op, VMX_DELIVER_NO_ERROR_CODE);
break;
+ case EXIT_REASON_TPR_BELOW_THRESHOLD:
+ vlapic_update_ppr(VLAPIC(v));
+ VLAPIC(v)->flush_tpr_threshold = 1;
+ break;
+
default:
domain_crash_synchronous(); /* should not happen */
}
diff -r c33272c2571c -r 2b99c99f96e6 xen/include/asm-x86/hvm/vlapic.h
--- a/xen/include/asm-x86/hvm/vlapic.h Mon Oct 30 09:45:17 2006 +0000
+++ b/xen/include/asm-x86/hvm/vlapic.h Mon Oct 30 10:42:27 2006 +0000
@@ -107,6 +107,7 @@ struct vlapic {
uint32_t timer_divide_count;
struct timer vlapic_timer;
int intr_pending_count[MAX_VECTOR];
+ int flush_tpr_threshold;
s_time_t timer_last_update;
direct_intr_info_t direct_intr;
uint32_t err_status;
@@ -117,12 +118,30 @@ struct vlapic {
void *regs;
};
+static inline int vlapic_test_and_set_irr(int vector, struct vlapic *vlapic)
+{
+ vlapic->flush_tpr_threshold = 1;
+ return vlapic_test_and_set_vector(vector, vlapic->regs + APIC_IRR);
+}
+
+static inline void vlapic_set_irr(int vector, struct vlapic *vlapic)
+{
+ vlapic->flush_tpr_threshold = 1;
+ vlapic_set_vector(vector, vlapic->regs + APIC_IRR);
+}
+
+static inline void vlapic_clear_irr(int vector, struct vlapic *vlapic)
+{
+ vlapic->flush_tpr_threshold = 1;
+ vlapic_clear_vector(vector, vlapic->regs + APIC_IRR);
+}
+
static inline int vlapic_set_irq(struct vlapic *vlapic,
uint8_t vec, uint8_t trig)
{
int ret;
- ret = vlapic_test_and_set_vector(vec, vlapic->regs + APIC_IRR);
+ ret = vlapic_test_and_set_irr(vec, vlapic);
if ( trig )
vlapic_set_vector(vec, vlapic->regs + APIC_TMR);
@@ -144,12 +163,16 @@ static inline void vlapic_set_reg(struct
void vlapic_post_injection(struct vcpu* v, int vector, int deliver_mode);
+extern int vlapic_find_highest_irr(struct vlapic *vlapic);
+
int cpu_has_apic_interrupt(struct vcpu* v);
int cpu_get_apic_interrupt(struct vcpu* v, int *mode);
extern int vlapic_init(struct vcpu *vc);
extern void vlapic_msr_set(struct vlapic *vlapic, uint64_t value);
+
+extern uint32_t vlapic_update_ppr(struct vlapic *vlapic);
int vlapic_accept_pic_intr(struct vcpu *v);
_______________________________________________
Xen-changelog mailing list
Xen-changelog@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-changelog
|