ia64/xen-unstable

changeset 12041:2b99c99f96e6

[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@intel.com>
Signed-off-by: Yunhong Jiang <yunhong.jiang@intel.com>
Signed-off-by: Dexuan Cui <dexuan.cui@intel.com>
author kfraser@localhost.localdomain
date Mon Oct 30 10:42:27 2006 +0000 (2006-10-30)
parents c33272c2571c
children 7e52933a46b1
files xen/arch/x86/hvm/vlapic.c xen/arch/x86/hvm/vmx/io.c xen/arch/x86/hvm/vmx/vmcs.c xen/arch/x86/hvm/vmx/vmx.c xen/include/asm-x86/hvm/vlapic.h
line diff
     1.1 --- a/xen/arch/x86/hvm/vlapic.c	Mon Oct 30 09:45:17 2006 +0000
     1.2 +++ b/xen/arch/x86/hvm/vlapic.c	Mon Oct 30 10:42:27 2006 +0000
     1.3 @@ -217,8 +217,7 @@ static int vlapic_accept_irq(struct vcpu
     1.4          if ( unlikely(vlapic == NULL || !vlapic_enabled(vlapic)) )
     1.5              break;
     1.6  
     1.7 -        if ( vlapic_test_and_set_vector(vector, vlapic->regs + APIC_IRR) &&
     1.8 -             trig_mode)
     1.9 +        if ( vlapic_test_and_set_irr(vector, vlapic) && trig_mode )
    1.10          {
    1.11              HVM_DBG_LOG(DBG_LEVEL_VLAPIC,
    1.12                    "level trig mode repeatedly for vector %d\n", vector);
    1.13 @@ -482,6 +481,11 @@ static void vlapic_read_aligned(struct v
    1.14      *result = 0;
    1.15  
    1.16      switch ( offset ) {
    1.17 +    case APIC_PROCPRI:
    1.18 +        vlapic_update_ppr(vlapic);
    1.19 +        *result = vlapic_get_reg(vlapic, offset);
    1.20 +        break;
    1.21 +
    1.22      case APIC_ARBPRI:
    1.23          printk("access local APIC ARBPRI register which is for P6\n");
    1.24          break;
    1.25 @@ -616,6 +620,7 @@ static void vlapic_write(struct vcpu *v,
    1.26      case APIC_TASKPRI:
    1.27          vlapic_set_reg(vlapic, APIC_TASKPRI, val & 0xff);
    1.28          vlapic_update_ppr(vlapic);
    1.29 +        vlapic->flush_tpr_threshold = 1;
    1.30          break;
    1.31  
    1.32      case APIC_EOI:
    1.33 @@ -814,7 +819,7 @@ void vlapic_timer_fn(void *data)
    1.34  
    1.35      vlapic->timer_last_update = now;
    1.36  
    1.37 -    if ( vlapic_test_and_set_vector(timer_vector, vlapic->regs + APIC_IRR) )
    1.38 +    if ( vlapic_test_and_set_irr(timer_vector, vlapic) )
    1.39          vlapic->intr_pending_count[timer_vector]++;
    1.40  
    1.41      if ( vlapic_lvtt_period(vlapic) )
    1.42 @@ -891,7 +896,7 @@ int cpu_get_apic_interrupt(struct vcpu *
    1.43                  HVM_DBG_LOG(DBG_LEVEL_VLAPIC,
    1.44                              "Sending an illegal vector 0x%x.", highest_irr);
    1.45  
    1.46 -                vlapic_set_vector(err_vector, vlapic->regs + APIC_IRR);
    1.47 +                vlapic_set_irr(err_vector, vlapic);
    1.48                  highest_irr = err_vector;
    1.49              }
    1.50  
    1.51 @@ -942,7 +947,7 @@ void vlapic_post_injection(struct vcpu *
    1.52      case APIC_DM_FIXED:
    1.53      case APIC_DM_LOWEST:
    1.54          vlapic_set_vector(vector, vlapic->regs + APIC_ISR);
    1.55 -        vlapic_clear_vector(vector, vlapic->regs + APIC_IRR);
    1.56 +        vlapic_clear_irr(vector, vlapic);
    1.57          vlapic_update_ppr(vlapic);
    1.58  
    1.59          if ( vector == vlapic_lvt_vector(vlapic, APIC_LVTT) )
    1.60 @@ -950,7 +955,7 @@ void vlapic_post_injection(struct vcpu *
    1.61              if ( vlapic->intr_pending_count[vector] > 0 )
    1.62              {
    1.63                  vlapic->intr_pending_count[vector]--;
    1.64 -                vlapic_test_and_set_vector(vector, vlapic->regs + APIC_IRR);
    1.65 +                vlapic_set_irr(vector, vlapic);
    1.66              }
    1.67          }
    1.68          break;
    1.69 @@ -1001,6 +1006,8 @@ static int vlapic_reset(struct vlapic *v
    1.70  
    1.71      vlapic->apic_base_msr = MSR_IA32_APICBASE_ENABLE | APIC_DEFAULT_PHYS_BASE;
    1.72  
    1.73 +    vlapic->flush_tpr_threshold = 0;
    1.74 +
    1.75      if ( v->vcpu_id == 0 )
    1.76          vlapic->apic_base_msr |= MSR_IA32_APICBASE_BSP;
    1.77  
     2.1 --- a/xen/arch/x86/hvm/vmx/io.c	Mon Oct 30 09:45:17 2006 +0000
     2.2 +++ b/xen/arch/x86/hvm/vmx/io.c	Mon Oct 30 10:42:27 2006 +0000
     2.3 @@ -68,6 +68,27 @@ static inline int is_interruptibility_st
     2.4      return interruptibility;
     2.5  }
     2.6  
     2.7 +#ifdef __x86_64__
     2.8 +static void update_tpr_threshold(struct vlapic *vlapic)
     2.9 +{
    2.10 +    int highest_irr, tpr;
    2.11 +
    2.12 +    /* Clear the work-to-do flag /then/ do the work. */
    2.13 +    vlapic->flush_tpr_threshold = 0;
    2.14 +    mb();
    2.15 +
    2.16 +    highest_irr = vlapic_find_highest_irr(vlapic);
    2.17 +    tpr = vlapic_get_reg(vlapic, APIC_TASKPRI) & 0xF0;
    2.18 +
    2.19 +    if ( highest_irr == -1 )
    2.20 +        __vmwrite(TPR_THRESHOLD, 0);
    2.21 +    else
    2.22 +        __vmwrite(TPR_THRESHOLD,
    2.23 +                  (highest_irr > tpr) ? (tpr >> 4) : (highest_irr >> 4));
    2.24 +}
    2.25 +#else
    2.26 +#define update_tpr_threshold(v) ((void)0)
    2.27 +#endif
    2.28  
    2.29  asmlinkage void vmx_intr_assist(void)
    2.30  {
    2.31 @@ -75,6 +96,7 @@ asmlinkage void vmx_intr_assist(void)
    2.32      int highest_vector;
    2.33      unsigned long eflags;
    2.34      struct vcpu *v = current;
    2.35 +    struct vlapic *vlapic = VLAPIC(v);
    2.36      struct hvm_domain *plat=&v->domain->arch.hvm_domain;
    2.37      struct periodic_time *pt = &plat->pl_time.periodic_tm;
    2.38      struct hvm_virpic *pic= &plat->vpic;
    2.39 @@ -98,6 +120,9 @@ asmlinkage void vmx_intr_assist(void)
    2.40              pic_set_xen_irq(pic, callback_irq, local_events_need_delivery());
    2.41      }
    2.42  
    2.43 +    if ( vlapic && vlapic_enabled(vlapic) && vlapic->flush_tpr_threshold )
    2.44 +        update_tpr_threshold(vlapic);
    2.45 +
    2.46      has_ext_irq = cpu_has_pending_irq(v);
    2.47  
    2.48      if (unlikely(v->arch.hvm_vmx.vector_injected)) {
     3.1 --- a/xen/arch/x86/hvm/vmx/vmcs.c	Mon Oct 30 09:45:17 2006 +0000
     3.2 +++ b/xen/arch/x86/hvm/vmx/vmcs.c	Mon Oct 30 10:42:27 2006 +0000
     3.3 @@ -346,8 +346,21 @@ static void vmx_do_launch(struct vcpu *v
     3.4  
     3.5      hvm_stts(v);
     3.6  
     3.7 -    if(hvm_apic_support(v->domain))
     3.8 -        vlapic_init(v);
     3.9 +    if( hvm_apic_support(v->domain) && (vlapic_init(v) == 0) )
    3.10 +    {
    3.11 +#ifdef __x86_64__ 
    3.12 +        u32 *cpu_exec_control = &v->arch.hvm_vcpu.u.vmx.exec_control;
    3.13 +        u64  vapic_page_addr = 
    3.14 +                        page_to_maddr(v->arch.hvm_vcpu.vlapic->regs_page);
    3.15 +
    3.16 +        *cpu_exec_control   |= CPU_BASED_TPR_SHADOW;
    3.17 +        *cpu_exec_control   &= ~CPU_BASED_CR8_STORE_EXITING;
    3.18 +        *cpu_exec_control   &= ~CPU_BASED_CR8_LOAD_EXITING;
    3.19 +        error |= __vmwrite(CPU_BASED_VM_EXEC_CONTROL, *cpu_exec_control);
    3.20 +        error |= __vmwrite(VIRTUAL_APIC_PAGE_ADDR, vapic_page_addr);
    3.21 +        error |= __vmwrite(TPR_THRESHOLD, 0);
    3.22 +#endif
    3.23 +    }
    3.24  
    3.25      vmx_set_host_env(v);
    3.26      init_timer(&v->arch.hvm_vcpu.hlt_timer, hlt_timer_fn, v, v->processor);
    3.27 @@ -514,12 +527,6 @@ static inline int construct_vmcs_host(vo
    3.28      error |= __vmwrite(HOST_CR4, crn);
    3.29  
    3.30      error |= __vmwrite(HOST_RIP, (unsigned long) vmx_asm_vmexit_handler);
    3.31 -#ifdef __x86_64__
    3.32 -    /* TBD: support cr8 for 64-bit guest */
    3.33 -    __vmwrite(VIRTUAL_APIC_PAGE_ADDR, 0);
    3.34 -    __vmwrite(TPR_THRESHOLD, 0);
    3.35 -    __vmwrite(SECONDARY_VM_EXEC_CONTROL, 0);
    3.36 -#endif
    3.37  
    3.38      return error;
    3.39  }
     4.1 --- a/xen/arch/x86/hvm/vmx/vmx.c	Mon Oct 30 09:45:17 2006 +0000
     4.2 +++ b/xen/arch/x86/hvm/vmx/vmx.c	Mon Oct 30 10:42:27 2006 +0000
     4.3 @@ -2409,6 +2409,11 @@ asmlinkage void vmx_vmexit_handler(struc
     4.4          vmx_inject_hw_exception(v, TRAP_invalid_op, VMX_DELIVER_NO_ERROR_CODE);
     4.5          break;
     4.6  
     4.7 +    case EXIT_REASON_TPR_BELOW_THRESHOLD:
     4.8 +        vlapic_update_ppr(VLAPIC(v));
     4.9 +        VLAPIC(v)->flush_tpr_threshold = 1;
    4.10 +        break;
    4.11 +
    4.12      default:
    4.13          domain_crash_synchronous();     /* should not happen */
    4.14      }
     5.1 --- a/xen/include/asm-x86/hvm/vlapic.h	Mon Oct 30 09:45:17 2006 +0000
     5.2 +++ b/xen/include/asm-x86/hvm/vlapic.h	Mon Oct 30 10:42:27 2006 +0000
     5.3 @@ -107,6 +107,7 @@ struct vlapic {
     5.4      uint32_t           timer_divide_count;
     5.5      struct timer       vlapic_timer;
     5.6      int                intr_pending_count[MAX_VECTOR];
     5.7 +    int                flush_tpr_threshold;
     5.8      s_time_t           timer_last_update;
     5.9      direct_intr_info_t direct_intr;
    5.10      uint32_t           err_status;
    5.11 @@ -117,12 +118,30 @@ struct vlapic {
    5.12      void               *regs;
    5.13  };
    5.14  
    5.15 +static inline int vlapic_test_and_set_irr(int vector, struct vlapic *vlapic)
    5.16 +{
    5.17 +    vlapic->flush_tpr_threshold = 1;
    5.18 +    return vlapic_test_and_set_vector(vector, vlapic->regs + APIC_IRR);
    5.19 +}
    5.20 +
    5.21 +static inline void vlapic_set_irr(int vector, struct vlapic *vlapic)
    5.22 +{
    5.23 +    vlapic->flush_tpr_threshold = 1;
    5.24 +    vlapic_set_vector(vector, vlapic->regs + APIC_IRR);
    5.25 +}
    5.26 +
    5.27 +static inline void vlapic_clear_irr(int vector, struct vlapic *vlapic)
    5.28 +{
    5.29 +    vlapic->flush_tpr_threshold = 1;
    5.30 +    vlapic_clear_vector(vector, vlapic->regs + APIC_IRR);
    5.31 +}
    5.32 +
    5.33  static inline int vlapic_set_irq(struct vlapic *vlapic,
    5.34                                   uint8_t vec, uint8_t trig)
    5.35  {
    5.36      int ret;
    5.37  
    5.38 -    ret = vlapic_test_and_set_vector(vec, vlapic->regs + APIC_IRR);
    5.39 +    ret = vlapic_test_and_set_irr(vec, vlapic);
    5.40      if ( trig )
    5.41          vlapic_set_vector(vec, vlapic->regs + APIC_TMR);
    5.42  
    5.43 @@ -144,6 +163,8 @@ static inline void vlapic_set_reg(struct
    5.44  
    5.45  void vlapic_post_injection(struct vcpu* v, int vector, int deliver_mode);
    5.46  
    5.47 +extern int vlapic_find_highest_irr(struct vlapic *vlapic);
    5.48 +
    5.49  int cpu_has_apic_interrupt(struct vcpu* v);
    5.50  int cpu_get_apic_interrupt(struct vcpu* v, int *mode);
    5.51  
    5.52 @@ -151,6 +172,8 @@ extern int vlapic_init(struct vcpu *vc);
    5.53  
    5.54  extern void vlapic_msr_set(struct vlapic *vlapic, uint64_t value);
    5.55  
    5.56 +extern uint32_t vlapic_update_ppr(struct vlapic *vlapic);
    5.57 +
    5.58  int vlapic_accept_pic_intr(struct vcpu *v);
    5.59  
    5.60  struct vlapic* apic_round_robin(struct domain *d,