# HG changeset patch
# User kfraser@xxxxxxxxxxxxxxxxxxxxx
# Node ID e0dc5a544ea1e84e6d3f9de916e401e06529ad72
# Parent 5b97dafc7448f645313ef244ca77a4c47bf264e1
[HVM] vlapic: More cleanups, simplifications and fixes.
Signed-off-by: Keir Fraser <keir@xxxxxxxxxxxxx>
---
xen/arch/x86/hvm/svm/svm.c | 2
xen/arch/x86/hvm/vlapic.c | 166 +++++++++++++++++----------------------
xen/arch/x86/hvm/vmx/io.c | 19 ++--
xen/arch/x86/hvm/vmx/vmx.c | 2
xen/include/asm-x86/hvm/vlapic.h | 27 +++---
5 files changed, 100 insertions(+), 116 deletions(-)
diff -r 5b97dafc7448 -r e0dc5a544ea1 xen/arch/x86/hvm/svm/svm.c
--- a/xen/arch/x86/hvm/svm/svm.c Mon Nov 13 17:23:49 2006 -0700
+++ b/xen/arch/x86/hvm/svm/svm.c Tue Nov 14 10:44:16 2006 +0000
@@ -990,7 +990,7 @@ static void svm_vmexit_do_cpuid(struct v
cpuid(input, &eax, &ebx, &ecx, &edx);
if (input == 0x00000001 || input == 0x80000001 )
{
- if ( !vlapic_global_enabled(vcpu_vlapic(v)) )
+ if ( vlapic_hw_disabled(vcpu_vlapic(v)) )
{
/* Since the apic is disabled, avoid any confusion
about SMP cpus being available */
diff -r 5b97dafc7448 -r e0dc5a544ea1 xen/arch/x86/hvm/vlapic.c
--- a/xen/arch/x86/hvm/vlapic.c Mon Nov 13 17:23:49 2006 -0700
+++ b/xen/arch/x86/hvm/vlapic.c Tue Nov 14 10:44:16 2006 +0000
@@ -71,17 +71,22 @@ static unsigned int vlapic_lvt_mask[VLAP
#define APIC_DEST_NOSHORT 0x0
#define APIC_DEST_MASK 0x800
-#define vlapic_lvt_enabled(vlapic, lvt_type) \
+#define vlapic_lvt_enabled(vlapic, lvt_type) \
(!(vlapic_get_reg(vlapic, lvt_type) & APIC_LVT_MASKED))
-#define vlapic_lvt_vector(vlapic, lvt_type) \
+#define vlapic_lvt_vector(vlapic, lvt_type) \
(vlapic_get_reg(vlapic, lvt_type) & APIC_VECTOR_MASK)
-#define vlapic_lvt_dm(vlapic, lvt_type) \
+#define vlapic_lvt_dm(vlapic, lvt_type) \
(vlapic_get_reg(vlapic, lvt_type) & APIC_MODE_MASK)
-#define vlapic_lvtt_period(vlapic) \
+#define vlapic_lvtt_period(vlapic) \
(vlapic_get_reg(vlapic, APIC_LVTT) & APIC_LVT_TIMER_PERIODIC)
+
+#define vlapic_base_address(vlapic) \
+ (vlapic->apic_base_msr & MSR_IA32_APICBASE_BASE)
+
+static int vlapic_reset(struct vlapic *vlapic);
/*
* Generic APIC bitmap vector update & search routines.
@@ -238,8 +243,7 @@ static int vlapic_match_dest(struct vcpu
if ( dest_mode == 0 )
{
/* Physical mode. */
- if ( (dest == 0xFF) || /* broadcast? */
- (GET_APIC_ID(vlapic_get_reg(target, APIC_ID)) == dest) )
+ if ( (dest == 0xFF) || (dest == v->vcpu_id) )
result = 1;
}
else
@@ -283,7 +287,7 @@ static int vlapic_accept_irq(struct vcpu
case APIC_DM_FIXED:
case APIC_DM_LOWEST:
/* FIXME add logic for vcpu on reset */
- if ( unlikely(vlapic == NULL || !vlapic_enabled(vlapic)) )
+ if ( unlikely(!vlapic_enabled(vlapic)) )
break;
if ( vlapic_test_and_set_irr(vector, vlapic) && trig_mode )
@@ -319,7 +323,7 @@ static int vlapic_accept_irq(struct vcpu
if ( trig_mode && !(level & APIC_INT_ASSERT) )
break;
/* FIXME How to check the situation after vcpu reset? */
- if ( test_and_clear_bit(_VCPUF_initialised, &v->vcpu_flags) )
+ if ( test_bit(_VCPUF_initialised, &v->vcpu_flags) )
{
gdprintk(XENLOG_ERR, "Reset hvm vcpu not supported yet\n");
goto exit_and_crash;
@@ -371,21 +375,15 @@ struct vlapic *apic_round_robin(
old = next = d->arch.hvm_domain.round_info[vector];
- /* the vcpu array is arranged according to vcpu_id */
do {
if ( ++next == MAX_VIRT_CPUS )
next = 0;
- if ( (d->vcpu[next] == NULL) ||
- !test_bit(_VCPUF_initialised, &d->vcpu[next]->vcpu_flags) )
+ if ( (d->vcpu[next] == NULL) || !test_bit(next, &bitmap) )
continue;
-
- if ( test_bit(next, &bitmap) )
- {
- target = vcpu_vlapic(d->vcpu[next]);
- if ( vlapic_enabled(target) )
- break;
- target = NULL;
- }
+ target = vcpu_vlapic(d->vcpu[next]);
+ if ( vlapic_enabled(target) )
+ break;
+ target = NULL;
} while ( next != old );
d->arch.hvm_domain.round_info[vector] = next;
@@ -398,10 +396,9 @@ void vlapic_EOI_set(struct vlapic *vlapi
{
int vector = vlapic_find_highest_isr(vlapic);
- /* Not every write EOI will has correpsoning ISR,
- one example is when Kernel check timer on setup_IO_APIC */
+ /* Some EOI writes may not have a matching to an in-service interrupt. */
if ( vector == -1 )
- return ;
+ return;
vlapic_clear_vector(vector, vlapic->regs + APIC_ISR);
@@ -538,7 +535,7 @@ static unsigned long vlapic_read(struct
unsigned int tmp;
unsigned long result;
struct vlapic *vlapic = vcpu_vlapic(v);
- unsigned int offset = address - vlapic->base_address;
+ unsigned int offset = address - vlapic_base_address(vlapic);
if ( offset > APIC_TDCR )
return 0;
@@ -588,7 +585,7 @@ static void vlapic_write(struct vcpu *v,
unsigned long len, unsigned long val)
{
struct vlapic *vlapic = vcpu_vlapic(v);
- unsigned int offset = address - vlapic->base_address;
+ unsigned int offset = address - vlapic_base_address(vlapic);
if ( offset != 0xb0 )
HVM_DBG_LOG(DBG_LEVEL_VLAPIC,
@@ -641,10 +638,6 @@ static void vlapic_write(struct vcpu *v,
switch ( offset )
{
- case APIC_ID: /* Local APIC ID */
- vlapic_set_reg(vlapic, APIC_ID, val);
- break;
-
case APIC_TASKPRI:
vlapic_set_reg(vlapic, APIC_TASKPRI, val & 0xff);
vlapic->flush_tpr_threshold = 1;
@@ -670,7 +663,7 @@ static void vlapic_write(struct vcpu *v,
int i;
uint32_t lvt_val;
- vlapic->status |= VLAPIC_SOFTWARE_DISABLE_MASK;
+ vlapic->disabled |= VLAPIC_SW_DISABLED;
for ( i = 0; i < VLAPIC_LVT_NUM; i++ )
{
@@ -678,17 +671,11 @@ static void vlapic_write(struct vcpu *v,
vlapic_set_reg(vlapic, APIC_LVTT + 0x10 * i,
lvt_val | APIC_LVT_MASKED);
}
-
- if ( (vlapic_get_reg(vlapic, APIC_LVT0) & APIC_MODE_MASK)
- == APIC_DM_EXTINT )
- clear_bit(_VLAPIC_BSP_ACCEPT_PIC, &vlapic->status);
}
else
{
- vlapic->status &= ~VLAPIC_SOFTWARE_DISABLE_MASK;
- if ( (vlapic_get_reg(vlapic, APIC_LVT0) & APIC_MODE_MASK)
- == APIC_DM_EXTINT )
- set_bit(_VLAPIC_BSP_ACCEPT_PIC, &vlapic->status);
+ vlapic->disabled &= ~VLAPIC_SW_DISABLED;
+ vlapic->flush_tpr_threshold = 1;
}
break;
@@ -712,26 +699,11 @@ static void vlapic_write(struct vcpu *v,
case APIC_LVT0: /* LVT LINT0 Reg */
case APIC_LVT1: /* LVT Lint1 Reg */
case APIC_LVTERR: /* LVT Error Reg */
- {
- if ( vlapic->status & VLAPIC_SOFTWARE_DISABLE_MASK )
+ if ( vlapic_sw_disabled(vlapic) )
val |= APIC_LVT_MASKED;
-
val &= vlapic_lvt_mask[(offset - APIC_LVTT) >> 4];
-
vlapic_set_reg(vlapic, offset, val);
-
- if ( (vlapic_vcpu(vlapic)->vcpu_id == 0) && (offset == APIC_LVT0) )
- {
- if ( (val & APIC_MODE_MASK) == APIC_DM_EXTINT )
- if ( val & APIC_LVT_MASKED)
- clear_bit(_VLAPIC_BSP_ACCEPT_PIC, &vlapic->status);
- else
- set_bit(_VLAPIC_BSP_ACCEPT_PIC, &vlapic->status);
- else
- clear_bit(_VLAPIC_BSP_ACCEPT_PIC, &vlapic->status);
- }
- }
- break;
+ break;
case APIC_TMICT:
{
@@ -773,10 +745,8 @@ static int vlapic_range(struct vcpu *v,
static int vlapic_range(struct vcpu *v, unsigned long addr)
{
struct vlapic *vlapic = vcpu_vlapic(v);
-
- return (vlapic_global_enabled(vlapic) &&
- (addr >= vlapic->base_address) &&
- (addr < vlapic->base_address + PAGE_SIZE));
+ unsigned long offset = addr - vlapic_base_address(vlapic);
+ return (!vlapic_hw_disabled(vlapic) && (offset < PAGE_SIZE));
}
struct hvm_mmio_handler vlapic_mmio_handler = {
@@ -787,17 +757,23 @@ struct hvm_mmio_handler vlapic_mmio_hand
void vlapic_msr_set(struct vlapic *vlapic, uint64_t value)
{
+ if ( (vlapic->apic_base_msr ^ value) & MSR_IA32_APICBASE_ENABLE )
+ {
+ if ( value & MSR_IA32_APICBASE_ENABLE )
+ {
+ vlapic_reset(vlapic);
+ vlapic->disabled &= ~VLAPIC_HW_DISABLED;
+ }
+ else
+ {
+ vlapic->disabled |= VLAPIC_HW_DISABLED;
+ }
+ }
+
vlapic->apic_base_msr = value;
- vlapic->base_address = vlapic->apic_base_msr & MSR_IA32_APICBASE_BASE;
-
- if ( !(value & MSR_IA32_APICBASE_ENABLE) )
- set_bit(_VLAPIC_GLOB_DISABLE, &vlapic->status );
- else
- clear_bit(_VLAPIC_GLOB_DISABLE, &vlapic->status);
HVM_DBG_LOG(DBG_LEVEL_VLAPIC,
- "apic base msr is 0x%016"PRIx64", and base address is 0x%lx.",
- vlapic->apic_base_msr, vlapic->base_address);
+ "apic base msr is 0x%016"PRIx64".", vlapic->apic_base_msr);
}
void vlapic_timer_fn(void *data)
@@ -845,8 +821,15 @@ int vlapic_accept_pic_intr(struct vcpu *
int vlapic_accept_pic_intr(struct vcpu *v)
{
struct vlapic *vlapic = vcpu_vlapic(v);
-
- return vlapic ? test_bit(_VLAPIC_BSP_ACCEPT_PIC, &vlapic->status) : 1;
+ uint32_t lvt0 = vlapic_get_reg(vlapic, APIC_LVT0);
+
+ /*
+ * Only CPU0 is wired to the 8259A. INTA cycles occur if LINT0 is set up
+ * accept ExtInts, or if the LAPIC is disabled (so LINT0 behaves as INTR).
+ */
+ return ((v->vcpu_id == 0) &&
+ (((lvt0 & (APIC_MODE_MASK|APIC_LVT_MASKED)) == APIC_DM_EXTINT) ||
+ vlapic_hw_disabled(vlapic)));
}
int cpu_get_apic_interrupt(struct vcpu *v, int *mode)
@@ -854,7 +837,7 @@ int cpu_get_apic_interrupt(struct vcpu *
struct vlapic *vlapic = vcpu_vlapic(v);
int highest_irr;
- if ( !vlapic || !vlapic_enabled(vlapic) )
+ if ( !vlapic_enabled(vlapic) )
return -1;
highest_irr = vlapic_find_highest_irr(vlapic);
@@ -886,9 +869,6 @@ void vlapic_post_injection(struct vcpu *
void vlapic_post_injection(struct vcpu *v, int vector, int deliver_mode)
{
struct vlapic *vlapic = vcpu_vlapic(v);
-
- if ( unlikely(vlapic == NULL) )
- return;
switch ( deliver_mode )
{
@@ -920,36 +900,38 @@ void vlapic_post_injection(struct vcpu *
}
}
+/* Reset the VLPAIC back to its power-on/reset state. */
static int vlapic_reset(struct vlapic *vlapic)
{
struct vcpu *v = vlapic_vcpu(vlapic);
int i;
- vlapic_set_reg(vlapic, APIC_ID, v->vcpu_id << 24);
-
+ vlapic_set_reg(vlapic, APIC_ID, v->vcpu_id << 24);
vlapic_set_reg(vlapic, APIC_LVR, VLAPIC_VERSION);
+
+ for ( i = 0; i < 8; i++ )
+ {
+ vlapic_set_reg(vlapic, APIC_IRR + 0x10 * i, 0);
+ vlapic_set_reg(vlapic, APIC_ISR + 0x10 * i, 0);
+ vlapic_set_reg(vlapic, APIC_TMR + 0x10 * i, 0);
+ }
+ vlapic_set_reg(vlapic, APIC_ICR, 0);
+ vlapic_set_reg(vlapic, APIC_ICR2, 0);
+ vlapic_set_reg(vlapic, APIC_LDR, 0);
+ vlapic_set_reg(vlapic, APIC_TASKPRI, 0);
+ vlapic_set_reg(vlapic, APIC_TMICT, 0);
+ vlapic_set_reg(vlapic, APIC_TMCCT, 0);
+ vlapic_set_tdcr(vlapic, 0);
+
+ vlapic_set_reg(vlapic, APIC_DFR, 0xffffffffU);
for ( i = 0; i < VLAPIC_LVT_NUM; i++ )
vlapic_set_reg(vlapic, APIC_LVTT + 0x10 * i, APIC_LVT_MASKED);
- vlapic_set_reg(vlapic, APIC_DFR, 0xffffffffU);
-
vlapic_set_reg(vlapic, APIC_SPIV, 0xff);
-
- vlapic->apic_base_msr = MSR_IA32_APICBASE_ENABLE | APIC_DEFAULT_PHYS_BASE;
-
- vlapic->flush_tpr_threshold = 0;
-
- vlapic_set_tdcr(vlapic, 0);
-
- vlapic->base_address = vlapic->apic_base_msr &
- MSR_IA32_APICBASE_BASE;
-
- HVM_DBG_LOG(DBG_LEVEL_VLAPIC,
- "vcpu=%p, id=%d, vlapic_apic_base_msr=0x%016"PRIx64", "
- "base_address=0x%0lx.",
- v, GET_APIC_ID(vlapic_get_reg(vlapic, APIC_ID)),
- vlapic->apic_base_msr, vlapic->base_address);
+ vlapic->disabled |= VLAPIC_SW_DISABLED;
+
+ vlapic->flush_tpr_threshold = 1;
return 1;
}
@@ -974,6 +956,7 @@ int vlapic_init(struct vcpu *v)
vlapic_reset(vlapic);
+ vlapic->apic_base_msr = MSR_IA32_APICBASE_ENABLE | APIC_DEFAULT_PHYS_BASE;
if ( v->vcpu_id == 0 )
vlapic->apic_base_msr |= MSR_IA32_APICBASE_BSP;
@@ -986,7 +969,6 @@ int vlapic_init(struct vcpu *v)
{
vlapic_set_reg(vlapic, APIC_LVT0, APIC_MODE_EXTINT << 8);
vlapic_set_reg(vlapic, APIC_LVT1, APIC_MODE_NMI << 8);
- set_bit(_VLAPIC_BSP_ACCEPT_PIC, &vlapic->status);
}
#endif
diff -r 5b97dafc7448 -r e0dc5a544ea1 xen/arch/x86/hvm/vmx/io.c
--- a/xen/arch/x86/hvm/vmx/io.c Mon Nov 13 17:23:49 2006 -0700
+++ b/xen/arch/x86/hvm/vmx/io.c Tue Nov 14 10:44:16 2006 +0000
@@ -69,20 +69,21 @@ static inline int is_interruptibility_st
#ifdef __x86_64__
static void update_tpr_threshold(struct vlapic *vlapic)
{
- int highest_irr, tpr;
+ int max_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);
+ if ( !vlapic_enabled(vlapic) ||
+ ((max_irr = vlapic_find_highest_irr(vlapic)) == -1) )
+ {
+ __vmwrite(TPR_THRESHOLD, 0);
+ return;
+ }
+
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));
+ __vmwrite(TPR_THRESHOLD, (max_irr > tpr) ? (tpr >> 4) : (max_irr >> 4));
}
#else
#define update_tpr_threshold(v) ((void)0)
@@ -115,7 +116,7 @@ asmlinkage void vmx_intr_assist(void)
pic_set_xen_irq(pic, callback_irq, local_events_need_delivery());
}
- if ( vlapic_enabled(vlapic) && vlapic->flush_tpr_threshold )
+ if ( vlapic->flush_tpr_threshold )
update_tpr_threshold(vlapic);
has_ext_irq = cpu_has_pending_irq(v);
diff -r 5b97dafc7448 -r e0dc5a544ea1 xen/arch/x86/hvm/vmx/vmx.c
--- a/xen/arch/x86/hvm/vmx/vmx.c Mon Nov 13 17:23:49 2006 -0700
+++ b/xen/arch/x86/hvm/vmx/vmx.c Tue Nov 14 10:44:16 2006 +0000
@@ -853,7 +853,7 @@ static void vmx_do_cpuid(struct cpu_user
/* Mask off reserved bits. */
ecx &= ~VMX_VCPU_CPUID_L1_ECX_RESERVED;
- if ( !vlapic_global_enabled(vcpu_vlapic(v)) )
+ if ( vlapic_hw_disabled(vcpu_vlapic(v)) )
clear_bit(X86_FEATURE_APIC, &edx);
#if CONFIG_PAGING_LEVELS >= 3
diff -r 5b97dafc7448 -r e0dc5a544ea1 xen/include/asm-x86/hvm/vlapic.h
--- a/xen/include/asm-x86/hvm/vlapic.h Mon Nov 13 17:23:49 2006 -0700
+++ b/xen/include/asm-x86/hvm/vlapic.h Tue Nov 14 10:44:16 2006 +0000
@@ -33,22 +33,23 @@
#define VLAPIC_ID(vlapic) \
(GET_APIC_ID(vlapic_get_reg(vlapic, APIC_ID)))
-#define _VLAPIC_GLOB_DISABLE 0x0
-#define VLAPIC_GLOB_DISABLE_MASK 0x1
-#define VLAPIC_SOFTWARE_DISABLE_MASK 0x2
-#define _VLAPIC_BSP_ACCEPT_PIC 0x3
-
-#define vlapic_enabled(vlapic) \
- (!((vlapic)->status & \
- (VLAPIC_GLOB_DISABLE_MASK | VLAPIC_SOFTWARE_DISABLE_MASK)))
-
-#define vlapic_global_enabled(vlapic) \
- (!(test_bit(_VLAPIC_GLOB_DISABLE, &(vlapic)->status)))
+/*
+ * APIC can be disabled in two ways:
+ * 1. 'Hardware disable': via IA32_APIC_BASE_MSR[11]
+ * CPU should behave as if it does not have an APIC.
+ * 2. 'Software disable': via APIC_SPIV[8].
+ * APIC is visible but does not respond to interrupt messages.
+ */
+#define VLAPIC_HW_DISABLED 0x1
+#define VLAPIC_SW_DISABLED 0x2
+#define vlapic_sw_disabled(vlapic) ((vlapic)->disabled & VLAPIC_SW_DISABLED)
+#define vlapic_hw_disabled(vlapic) ((vlapic)->disabled & VLAPIC_HW_DISABLED)
+#define vlapic_disabled(vlapic) ((vlapic)->disabled)
+#define vlapic_enabled(vlapic) (!vlapic_disabled(vlapic))
struct vlapic {
- uint32_t status;
uint64_t apic_base_msr;
- unsigned long base_address;
+ uint32_t disabled; /* VLAPIC_xx_DISABLED */
uint32_t timer_divisor;
struct timer vlapic_timer;
int timer_pending_count;
_______________________________________________
Xen-changelog mailing list
Xen-changelog@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-changelog
|