# HG changeset patch
# User kaf24@xxxxxxxxxxxxxxxxxxxx
# Node ID 3e31c5e160cfd01493e3e89256c733dda7efc922
# Parent 885c1513c6743cc6d8373f973a4fa696ce5215cb
[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@xxxxxxxxx>
* Signed-off-by: Yunhong Jiang <yunhong.jiang@xxxxxxxxx>
* Signed-off-by: Eddie Dong <eddie.dong@xxxxxxxxx>
Signed-off-by: Keir Fraser <keir@xxxxxxxxxxxxx>
---
xen/arch/x86/hvm/vlapic.c | 35 ++++++++++++++++-------------------
xen/include/asm-x86/hvm/vlapic.h | 30 ++++++++++++++++++++++--------
2 files changed, 38 insertions(+), 27 deletions(-)
diff -r 885c1513c674 -r 3e31c5e160cf xen/arch/x86/hvm/vlapic.c
--- a/xen/arch/x86/hvm/vlapic.c Wed Sep 13 15:15:27 2006 +0100
+++ b/xen/arch/x86/hvm/vlapic.c Wed Sep 13 15:59:14 2006 +0100
@@ -66,12 +66,10 @@ int vlapic_find_highest_irr(struct vlapi
{
int result;
- result = find_highest_bit((unsigned long *)(vlapic->regs + APIC_IRR),
- MAX_VECTOR);
-
- ASSERT( result == -1 || result >= 16);
-
- return result;
+ result = vlapic_find_highest_vector(vlapic->regs + APIC_IRR);
+ ASSERT((result == -1) || (result >= 16));
+
+ return result;
}
s_time_t get_apictime_scheduled(struct vcpu *v)
@@ -89,10 +87,8 @@ int vlapic_find_highest_isr(struct vlapi
{
int result;
- result = find_highest_bit((unsigned long *)(vlapic->regs + APIC_ISR),
- MAX_VECTOR);
-
- ASSERT( result == -1 || result >= 16);
+ result = vlapic_find_highest_vector(vlapic->regs + APIC_ISR);
+ ASSERT((result == -1) || (result >= 16));
return result;
}
@@ -221,7 +217,8 @@ static int vlapic_accept_irq(struct vcpu
if ( unlikely(vlapic == NULL || !vlapic_enabled(vlapic)) )
break;
- if ( test_and_set_bit(vector, vlapic->regs + APIC_IRR) && trig_mode)
+ if ( vlapic_test_and_set_vector(vector, vlapic->regs + APIC_IRR) &&
+ trig_mode)
{
HVM_DBG_LOG(DBG_LEVEL_VLAPIC,
"level trig mode repeatedly for vector %d\n", vector);
@@ -232,7 +229,7 @@ static int vlapic_accept_irq(struct vcpu
{
HVM_DBG_LOG(DBG_LEVEL_VLAPIC,
"level trig mode for vector %d\n", vector);
- set_bit(vector, vlapic->regs + APIC_TMR);
+ vlapic_set_vector(vector, vlapic->regs + APIC_TMR);
}
hvm_prod_vcpu(v);
@@ -358,10 +355,10 @@ void vlapic_EOI_set(struct vlapic *vlapi
if ( vector == -1 )
return ;
- clear_bit(vector, vlapic->regs + APIC_ISR);
+ vlapic_clear_vector(vector, vlapic->regs + APIC_ISR);
vlapic_update_ppr(vlapic);
- if ( test_and_clear_bit(vector, vlapic->regs + APIC_TMR) )
+ if ( vlapic_test_and_clear_vector(vector, vlapic->regs + APIC_TMR) )
ioapic_update_EOI(vlapic->domain, vector);
}
@@ -816,7 +813,7 @@ void vlapic_timer_fn(void *data)
vlapic->timer_last_update = now;
- if ( test_and_set_bit(timer_vector, vlapic->regs + APIC_IRR ))
+ if ( vlapic_test_and_set_vector(timer_vector, vlapic->regs + APIC_IRR) )
vlapic->intr_pending_count[timer_vector]++;
if ( vlapic_lvtt_period(vlapic) )
@@ -893,7 +890,7 @@ int cpu_get_apic_interrupt(struct vcpu *
HVM_DBG_LOG(DBG_LEVEL_VLAPIC,
"Sending an illegal vector 0x%x.", highest_irr);
- set_bit(err_vector, vlapic->regs + APIC_IRR);
+ vlapic_set_vector(err_vector, vlapic->regs + APIC_IRR);
highest_irr = err_vector;
}
@@ -943,15 +940,15 @@ void vlapic_post_injection(struct vcpu *
switch ( deliver_mode ) {
case APIC_DM_FIXED:
case APIC_DM_LOWEST:
- set_bit(vector, vlapic->regs + APIC_ISR);
- clear_bit(vector, vlapic->regs + APIC_IRR);
+ vlapic_set_vector(vector, vlapic->regs + APIC_ISR);
+ vlapic_clear_vector(vector, vlapic->regs + APIC_IRR);
vlapic_update_ppr(vlapic);
if ( vector == vlapic_lvt_vector(vlapic, APIC_LVTT) )
{
vlapic->intr_pending_count[vector]--;
if ( vlapic->intr_pending_count[vector] > 0 )
- test_and_set_bit(vector, vlapic->regs + APIC_IRR);
+ vlapic_test_and_set_vector(vector, vlapic->regs + APIC_IRR);
}
break;
diff -r 885c1513c674 -r 3e31c5e160cf xen/include/asm-x86/hvm/vlapic.h
--- a/xen/include/asm-x86/hvm/vlapic.h Wed Sep 13 15:15:27 2006 +0100
+++ b/xen/include/asm-x86/hvm/vlapic.h Wed Sep 13 15:59:14 2006 +0100
@@ -23,12 +23,28 @@
#include <asm/msr.h>
#include <public/hvm/ioreq.h>
-static __inline__ int find_highest_bit(unsigned long *data, int nr_bits)
+#define MAX_VECTOR 256
+
+#define VEC_POS(v) ((v)%32)
+#define REG_POS(v) (((v)/32)* 0x10)
+#define vlapic_test_and_set_vector(vec, bitmap) \
+ test_and_set_bit(VEC_POS(vec), (bitmap) + REG_POS(vec))
+#define vlapic_test_and_clear_vector(vec, bitmap) \
+ test_and_clear_bit(VEC_POS(vec), (bitmap) + REG_POS(vec))
+#define vlapic_set_vector(vec, bitmap) \
+ set_bit(VEC_POS(vec), (bitmap) + REG_POS(vec))
+#define vlapic_clear_vector(vec, bitmap) \
+ clear_bit(VEC_POS(vec), (bitmap) + REG_POS(vec))
+
+static inline int vlapic_find_highest_vector(u32 *bitmap)
{
- int length = BITS_TO_LONGS(nr_bits);
- while ( length && !data[--length] )
+ int word_offset = MAX_VECTOR / 32;
+
+ /* Work backwards through the bitmap (first 32-bit word in every four). */
+ while ( (word_offset != 0) && (bitmap[(--word_offset)*4] == 0) )
continue;
- return (fls(data[length]) - 1) + (length * BITS_PER_LONG);
+
+ return (fls(bitmap[word_offset*4]) - 1) + (word_offset * 32);
}
#define VLAPIC(v) (v->arch.hvm_vcpu.vlapic)
@@ -83,8 +99,6 @@ typedef struct direct_intr_info {
int source[6];
} direct_intr_info_t;
-#define MAX_VECTOR 256
-
struct vlapic {
uint32_t status;
uint32_t vcpu_id;
@@ -108,9 +122,9 @@ static inline int vlapic_set_irq(struct
{
int ret;
- ret = test_and_set_bit(vec, vlapic->regs + APIC_IRR);
+ ret = vlapic_test_and_set_vector(vec, vlapic->regs + APIC_IRR);
if ( trig )
- set_bit(vec, vlapic->regs + APIC_TMR);
+ vlapic_set_vector(vec, vlapic->regs + APIC_TMR);
/* We may need to wake up target vcpu, besides set pending bit here */
return ret;
_______________________________________________
Xen-changelog mailing list
Xen-changelog@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-changelog
|