From: kfraser@localhost.localdomain Date: Thu, 9 Nov 2006 17:53:05 +0000 (+0000) Subject: [HVM] Clean up two small APIC TDCR issues. X-Git-Tag: archive/raspbian/4.8.0-1+rpi1~1^2~15567^2~24 X-Git-Url: https://dgit.raspbian.org/?a=commitdiff_plain;h=efeebd10a1e79133a295809618d31d69ea2284be;p=xen.git [HVM] Clean up two small APIC TDCR issues. First, only save the bits that can be set, so that on a subsequent read can't see MBZ bits as set. Next, be sure to initialize the timer_divide_count, which is derived from the TDCR. This avoids a potential divide-by-zero elsewhere in the code. The original patch was provided by Ben Thomas . This modified version refactors the code slightly and renames timer_divide_count to timer_divisor. Signed-off-by: Keir Fraser --- diff --git a/xen/arch/x86/hvm/vlapic.c b/xen/arch/x86/hvm/vlapic.c index 22888a76c7..9776c9dfff 100644 --- a/xen/arch/x86/hvm/vlapic.c +++ b/xen/arch/x86/hvm/vlapic.c @@ -495,8 +495,7 @@ static uint32_t vlapic_get_tmcct(struct vlapic *vlapic) else passed = now - vlapic->timer_last_update; - counter_passed = passed / - (APIC_BUS_CYCLE_NS * vlapic->timer_divide_count); + counter_passed = passed / (APIC_BUS_CYCLE_NS * vlapic->timer_divisor); tmcct -= counter_passed; @@ -528,10 +527,21 @@ static uint32_t vlapic_get_tmcct(struct vlapic *vlapic) return tmcct; } +static void vlapic_set_tdcr(struct vlapic *vlapic, unsigned int val) +{ + /* Only bits 0, 1 and 3 are settable; others are MBZ. */ + val &= 0xb; + vlapic_set_reg(vlapic, APIC_TDCR, val); + + /* Update the demangled timer_divisor. */ + val = ((val & 3) | ((val & 8) >> 1)) + 1; + vlapic->timer_divisor = 1 << (val & 7); +} + static void vlapic_read_aligned(struct vlapic *vlapic, unsigned int offset, unsigned int len, unsigned int *result) { - ASSERT(len == 4 && offset > 0 && offset <= APIC_TDCR); + ASSERT((len == 4) && (offset > 0) && (offset <= APIC_TDCR)); *result = 0; @@ -563,7 +573,7 @@ static unsigned long vlapic_read(struct vcpu *v, unsigned long address, struct vlapic *vlapic = vcpu_vlapic(v); unsigned int offset = address - vlapic->base_address; - if ( offset > APIC_TDCR) + if ( offset > APIC_TDCR ) return 0; /* some bugs on kernel cause read this with byte*/ @@ -760,8 +770,7 @@ static void vlapic_write(struct vcpu *v, unsigned long address, vlapic_set_reg(vlapic, APIC_TMCCT, val); vlapic->timer_last_update = now; - offset = APIC_BUS_CYCLE_NS * - vlapic->timer_divide_count * val; + offset = APIC_BUS_CYCLE_NS * vlapic->timer_divisor * val; set_timer(&vlapic->vlapic_timer, now + offset); @@ -776,19 +785,10 @@ static void vlapic_write(struct vcpu *v, unsigned long address, break; case APIC_TDCR: - { - unsigned int tmp1, tmp2; - - tmp1 = val & 0xf; - tmp2 = ((tmp1 & 0x3) | ((tmp1 & 0x8) >> 1)) + 1; - vlapic->timer_divide_count = 0x1 << (tmp2 & 0x7); - - vlapic_set_reg(vlapic, APIC_TDCR, val); - - HVM_DBG_LOG(DBG_LEVEL_VLAPIC_TIMER, "timer divide count is 0x%x", - vlapic->timer_divide_count); - } - break; + vlapic_set_tdcr(vlapic, val & 0xb); + HVM_DBG_LOG(DBG_LEVEL_VLAPIC_TIMER, "timer divisor is 0x%x", + vlapic->timer_divisor); + break; default: gdprintk(XENLOG_WARNING, @@ -852,8 +852,7 @@ void vlapic_timer_fn(void *data) vlapic_set_reg(vlapic, APIC_TMCCT, tmict); - offset = APIC_BUS_CYCLE_NS * - vlapic->timer_divide_count * tmict; + offset = APIC_BUS_CYCLE_NS * vlapic->timer_divisor * tmict; set_timer(&vlapic->vlapic_timer, now + offset); } @@ -967,6 +966,8 @@ static int vlapic_reset(struct vlapic *vlapic) vlapic->flush_tpr_threshold = 0; + vlapic_set_tdcr(vlapic, 0); + vlapic->base_address = vlapic->apic_base_msr & MSR_IA32_APICBASE_BASE; diff --git a/xen/include/asm-x86/hvm/vlapic.h b/xen/include/asm-x86/hvm/vlapic.h index ed23916649..3720127d6d 100644 --- a/xen/include/asm-x86/hvm/vlapic.h +++ b/xen/include/asm-x86/hvm/vlapic.h @@ -49,7 +49,7 @@ struct vlapic { uint32_t status; uint64_t apic_base_msr; unsigned long base_address; - uint32_t timer_divide_count; + uint32_t timer_divisor; struct timer vlapic_timer; int timer_pending_count; int flush_tpr_threshold;