ia64/xen-unstable
changeset 11472: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>
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;