direct-io.hg

changeset 11468:3e31c5e160cf

[HVM] Fix an error when read from APIC registers like IRR, ISR and TMR.
From SDM3 spec, for APIC registers, all 32-bit registers should
be accessed using 128-bit aligned 32bit loads or stores.
And wider registers (64-bit or 256-bit) must be accessed using
multiple 32-bit loads or stores.

In old APIC virtualization code, we use IRR, ISR and TMR which are
256-bit registers as contiguous bit maps other than multiple 32-bit.

So guest always fetch error values.

Original patch was:
* Signed-off-by: Xiaohui Xin <xiaohui.xin@intel.com>
* Signed-off-by: Yunhong Jiang <yunhong.jiang@intel.com>
* Signed-off-by: Eddie Dong <eddie.dong@intel.com>

Signed-off-by: Keir Fraser <keir@xensource.com>
author kaf24@firebug.cl.cam.ac.uk
date Wed Sep 13 15:59:14 2006 +0100 (2006-09-13)
parents 885c1513c674
children 25ece14b6234
files xen/arch/x86/hvm/vlapic.c xen/include/asm-x86/hvm/vlapic.h
line diff
     1.1 --- a/xen/arch/x86/hvm/vlapic.c	Wed Sep 13 15:15:27 2006 +0100
     1.2 +++ b/xen/arch/x86/hvm/vlapic.c	Wed Sep 13 15:59:14 2006 +0100
     1.3 @@ -66,12 +66,10 @@ int vlapic_find_highest_irr(struct vlapi
     1.4  {
     1.5      int result;
     1.6  
     1.7 -     result = find_highest_bit((unsigned long *)(vlapic->regs + APIC_IRR),
     1.8 -                               MAX_VECTOR);
     1.9 +    result = vlapic_find_highest_vector(vlapic->regs + APIC_IRR);
    1.10 +    ASSERT((result == -1) || (result >= 16));
    1.11  
    1.12 -     ASSERT( result == -1 || result >= 16);
    1.13 -
    1.14 -     return result;
    1.15 +    return result;
    1.16  }
    1.17  
    1.18  s_time_t get_apictime_scheduled(struct vcpu *v)
    1.19 @@ -89,10 +87,8 @@ int vlapic_find_highest_isr(struct vlapi
    1.20  {
    1.21      int result;
    1.22  
    1.23 -    result = find_highest_bit((unsigned long *)(vlapic->regs + APIC_ISR),
    1.24 -                               MAX_VECTOR);
    1.25 -
    1.26 -    ASSERT( result == -1 || result >= 16);
    1.27 +    result = vlapic_find_highest_vector(vlapic->regs + APIC_ISR);
    1.28 +    ASSERT((result == -1) || (result >= 16));
    1.29  
    1.30      return result;
    1.31  }
    1.32 @@ -221,7 +217,8 @@ static int vlapic_accept_irq(struct vcpu
    1.33          if ( unlikely(vlapic == NULL || !vlapic_enabled(vlapic)) )
    1.34              break;
    1.35  
    1.36 -        if ( test_and_set_bit(vector, vlapic->regs + APIC_IRR) && trig_mode)
    1.37 +        if ( vlapic_test_and_set_vector(vector, vlapic->regs + APIC_IRR) &&
    1.38 +             trig_mode)
    1.39          {
    1.40              HVM_DBG_LOG(DBG_LEVEL_VLAPIC,
    1.41                    "level trig mode repeatedly for vector %d\n", vector);
    1.42 @@ -232,7 +229,7 @@ static int vlapic_accept_irq(struct vcpu
    1.43          {
    1.44              HVM_DBG_LOG(DBG_LEVEL_VLAPIC,
    1.45                "level trig mode for vector %d\n", vector);
    1.46 -            set_bit(vector, vlapic->regs + APIC_TMR);
    1.47 +            vlapic_set_vector(vector, vlapic->regs + APIC_TMR);
    1.48          }
    1.49          hvm_prod_vcpu(v);
    1.50  
    1.51 @@ -358,10 +355,10 @@ void vlapic_EOI_set(struct vlapic *vlapi
    1.52      if ( vector == -1 )
    1.53          return ;
    1.54  
    1.55 -    clear_bit(vector, vlapic->regs + APIC_ISR);
    1.56 +    vlapic_clear_vector(vector, vlapic->regs + APIC_ISR);
    1.57      vlapic_update_ppr(vlapic);
    1.58  
    1.59 -    if ( test_and_clear_bit(vector, vlapic->regs + APIC_TMR) )
    1.60 +    if ( vlapic_test_and_clear_vector(vector, vlapic->regs + APIC_TMR) )
    1.61          ioapic_update_EOI(vlapic->domain, vector);
    1.62  }
    1.63  
    1.64 @@ -816,7 +813,7 @@ void vlapic_timer_fn(void *data)
    1.65  
    1.66      vlapic->timer_last_update = now;
    1.67  
    1.68 -    if ( test_and_set_bit(timer_vector, vlapic->regs + APIC_IRR ))
    1.69 +    if ( vlapic_test_and_set_vector(timer_vector, vlapic->regs + APIC_IRR) )
    1.70          vlapic->intr_pending_count[timer_vector]++;
    1.71  
    1.72      if ( vlapic_lvtt_period(vlapic) )
    1.73 @@ -893,7 +890,7 @@ int cpu_get_apic_interrupt(struct vcpu *
    1.74                  HVM_DBG_LOG(DBG_LEVEL_VLAPIC,
    1.75                              "Sending an illegal vector 0x%x.", highest_irr);
    1.76  
    1.77 -                set_bit(err_vector, vlapic->regs + APIC_IRR);
    1.78 +                vlapic_set_vector(err_vector, vlapic->regs + APIC_IRR);
    1.79                  highest_irr = err_vector;
    1.80              }
    1.81  
    1.82 @@ -943,15 +940,15 @@ void vlapic_post_injection(struct vcpu *
    1.83      switch ( deliver_mode ) {
    1.84      case APIC_DM_FIXED:
    1.85      case APIC_DM_LOWEST:
    1.86 -        set_bit(vector, vlapic->regs + APIC_ISR);
    1.87 -        clear_bit(vector, vlapic->regs + APIC_IRR);
    1.88 +        vlapic_set_vector(vector, vlapic->regs + APIC_ISR);
    1.89 +        vlapic_clear_vector(vector, vlapic->regs + APIC_IRR);
    1.90          vlapic_update_ppr(vlapic);
    1.91  
    1.92          if ( vector == vlapic_lvt_vector(vlapic, APIC_LVTT) )
    1.93          {
    1.94              vlapic->intr_pending_count[vector]--;
    1.95              if ( vlapic->intr_pending_count[vector] > 0 )
    1.96 -                test_and_set_bit(vector, vlapic->regs + APIC_IRR);
    1.97 +                vlapic_test_and_set_vector(vector, vlapic->regs + APIC_IRR);
    1.98          }
    1.99          break;
   1.100  
     2.1 --- a/xen/include/asm-x86/hvm/vlapic.h	Wed Sep 13 15:15:27 2006 +0100
     2.2 +++ b/xen/include/asm-x86/hvm/vlapic.h	Wed Sep 13 15:59:14 2006 +0100
     2.3 @@ -23,12 +23,28 @@
     2.4  #include <asm/msr.h>
     2.5  #include <public/hvm/ioreq.h>
     2.6  
     2.7 -static __inline__ int find_highest_bit(unsigned long *data, int nr_bits)
     2.8 +#define MAX_VECTOR      256
     2.9 +
    2.10 +#define VEC_POS(v) ((v)%32)
    2.11 +#define REG_POS(v) (((v)/32)* 0x10)
    2.12 +#define vlapic_test_and_set_vector(vec, bitmap)                 \
    2.13 +    test_and_set_bit(VEC_POS(vec), (bitmap) + REG_POS(vec))
    2.14 +#define vlapic_test_and_clear_vector(vec, bitmap)               \
    2.15 +    test_and_clear_bit(VEC_POS(vec), (bitmap) + REG_POS(vec))
    2.16 +#define vlapic_set_vector(vec, bitmap)                          \
    2.17 +    set_bit(VEC_POS(vec), (bitmap) + REG_POS(vec))
    2.18 +#define vlapic_clear_vector(vec, bitmap)                        \
    2.19 +    clear_bit(VEC_POS(vec), (bitmap) + REG_POS(vec))
    2.20 +
    2.21 +static inline int vlapic_find_highest_vector(u32 *bitmap)
    2.22  {
    2.23 -    int length = BITS_TO_LONGS(nr_bits);
    2.24 -    while ( length && !data[--length] )
    2.25 +    int word_offset = MAX_VECTOR / 32;
    2.26 +
    2.27 +    /* Work backwards through the bitmap (first 32-bit word in every four). */
    2.28 +    while ( (word_offset != 0) && (bitmap[(--word_offset)*4] == 0) )
    2.29          continue;
    2.30 -    return (fls(data[length]) - 1) + (length * BITS_PER_LONG);
    2.31 +
    2.32 +    return (fls(bitmap[word_offset*4]) - 1) + (word_offset * 32);
    2.33  }
    2.34  
    2.35  #define VLAPIC(v)                       (v->arch.hvm_vcpu.vlapic)
    2.36 @@ -83,8 +99,6 @@ typedef struct direct_intr_info {
    2.37      int source[6];
    2.38  } direct_intr_info_t;
    2.39  
    2.40 -#define MAX_VECTOR      256
    2.41 -
    2.42  struct vlapic {
    2.43      uint32_t           status;
    2.44      uint32_t           vcpu_id;
    2.45 @@ -108,9 +122,9 @@ static inline int vlapic_set_irq(struct 
    2.46  {
    2.47      int ret;
    2.48  
    2.49 -    ret = test_and_set_bit(vec, vlapic->regs + APIC_IRR);
    2.50 +    ret = vlapic_test_and_set_vector(vec, vlapic->regs + APIC_IRR);
    2.51      if ( trig )
    2.52 -        set_bit(vec, vlapic->regs + APIC_TMR);
    2.53 +        vlapic_set_vector(vec, vlapic->regs + APIC_TMR);
    2.54  
    2.55      /* We may need to wake up target vcpu, besides set pending bit here */
    2.56      return ret;