From owner-svn-src-all@FreeBSD.ORG Fri Dec 27 20:18:20 2013 Return-Path: Delivered-To: svn-src-all@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:1900:2254:206a::19:1]) (using TLSv1 with cipher ADH-AES256-SHA (256/256 bits)) (No client certificate requested) by hub.freebsd.org (Postfix) with ESMTPS id C06FE4E4; Fri, 27 Dec 2013 20:18:20 +0000 (UTC) Received: from svn.freebsd.org (svn.freebsd.org [IPv6:2001:1900:2254:2068::e6a:0]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mx1.freebsd.org (Postfix) with ESMTPS id AC8B51D1C; Fri, 27 Dec 2013 20:18:20 +0000 (UTC) Received: from svn.freebsd.org ([127.0.1.70]) by svn.freebsd.org (8.14.7/8.14.7) with ESMTP id rBRKIKXf002125; Fri, 27 Dec 2013 20:18:20 GMT (envelope-from neel@svn.freebsd.org) Received: (from neel@localhost) by svn.freebsd.org (8.14.7/8.14.7/Submit) id rBRKIKEN002123; Fri, 27 Dec 2013 20:18:20 GMT (envelope-from neel@svn.freebsd.org) Message-Id: <201312272018.rBRKIKEN002123@svn.freebsd.org> From: Neel Natu Date: Fri, 27 Dec 2013 20:18:20 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r259961 - head/sys/amd64/vmm/io X-SVN-Group: head MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: svn-src-all@freebsd.org X-Mailman-Version: 2.1.17 Precedence: list List-Id: "SVN commit messages for the entire src tree \(except for " user" and " projects" \)" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Fri, 27 Dec 2013 20:18:20 -0000 Author: neel Date: Fri Dec 27 20:18:19 2013 New Revision: 259961 URL: http://svnweb.freebsd.org/changeset/base/259961 Log: Modify handling of writes to the vlapic ICR_TIMER, DCR_TIMER, ICRLO and ESR registers. The handler is now called after the register value is updated in the virtual APIC page. This will make it easier to handle APIC-write VM-exits with APIC register virtualization turned on. We can no longer rely on the value of 'icr_timer' on the APIC page in the callout handler. With APIC register virtualization the value of 'icr_timer' will be updated by the processor in guest-context before an APIC-write VM-exit. Clear the 'delivery status' bit in the ICRLO register in the write handler. With APIC register virtualization the write happens in guest-context and we cannot prevent a (buggy) guest from setting this bit. Modified: head/sys/amd64/vmm/io/vlapic.c head/sys/amd64/vmm/io/vlapic.h Modified: head/sys/amd64/vmm/io/vlapic.c ============================================================================== --- head/sys/amd64/vmm/io/vlapic.c Fri Dec 27 19:53:42 2013 (r259960) +++ head/sys/amd64/vmm/io/vlapic.c Fri Dec 27 20:18:19 2013 (r259961) @@ -100,14 +100,9 @@ do { \ /* * The 'vlapic->timer_mtx' is used to provide mutual exclusion between the - * vlapic_callout_handler() and vcpu accesses to the following registers: - * - initial count register aka icr_timer - * - current count register aka ccr_timer - * - divide config register aka dcr_timer + * vlapic_callout_handler() and vcpu accesses to: + * - timer_freq_bt, timer_period_bt, timer_fire_bt * - timer LVT register - * - * Note that the vlapic_callout_handler() does not write to any of these - * registers so they can be safely read from the vcpu context without locking. */ #define VLAPIC_TIMER_LOCK(vlapic) mtx_lock_spin(&((vlapic)->timer_mtx)) #define VLAPIC_TIMER_UNLOCK(vlapic) mtx_unlock_spin(&((vlapic)->timer_mtx)) @@ -273,8 +268,8 @@ vlapic_get_ccr(struct vlapic *vlapic) return (ccr); } -static void -vlapic_set_dcr(struct vlapic *vlapic, uint32_t dcr) +void +vlapic_dcr_write_handler(struct vlapic *vlapic) { struct LAPIC *lapic; int divisor; @@ -282,9 +277,9 @@ vlapic_set_dcr(struct vlapic *vlapic, ui lapic = vlapic->apic_page; VLAPIC_TIMER_LOCK(vlapic); - lapic->dcr_timer = dcr; - divisor = vlapic_timer_divisor(dcr); - VLAPIC_CTR2(vlapic, "vlapic dcr_timer=%#x, divisor=%d", dcr, divisor); + divisor = vlapic_timer_divisor(lapic->dcr_timer); + VLAPIC_CTR2(vlapic, "vlapic dcr_timer=%#x, divisor=%d", + lapic->dcr_timer, divisor); /* * Update the timer frequency and the timer period. @@ -299,8 +294,8 @@ vlapic_set_dcr(struct vlapic *vlapic, ui VLAPIC_TIMER_UNLOCK(vlapic); } -static void -vlapic_update_errors(struct vlapic *vlapic) +void +vlapic_esr_write_handler(struct vlapic *vlapic) { struct LAPIC *lapic; @@ -323,7 +318,9 @@ vlapic_reset(struct vlapic *vlapic) lapic->dfr = 0xffffffff; lapic->svr = APIC_SVR_VECTOR; vlapic_mask_lvts(vlapic); - vlapic_set_dcr(vlapic, 0); + + lapic->dcr_timer = 0; + vlapic_dcr_write_handler(vlapic); if (vlapic->vcpuid == 0) vlapic->boot_state = BS_RUNNING; /* BSP */ @@ -711,8 +708,6 @@ vlapic_callout_handler(void *arg) callout_deactivate(&vlapic->callout); - KASSERT(vlapic->apic_page->icr_timer != 0, ("timer is disabled")); - vlapic_fire_timer(vlapic); if (vlapic_periodic_timer(vlapic)) { @@ -757,16 +752,17 @@ done: VLAPIC_TIMER_UNLOCK(vlapic); } -static void -vlapic_set_icr_timer(struct vlapic *vlapic, uint32_t icr_timer) +void +vlapic_icrtmr_write_handler(struct vlapic *vlapic) { struct LAPIC *lapic; sbintime_t sbt; + uint32_t icr_timer; VLAPIC_TIMER_LOCK(vlapic); lapic = vlapic->apic_page; - lapic->icr_timer = icr_timer; + icr_timer = lapic->icr_timer; vlapic->timer_period_bt = vlapic->timer_freq_bt; bintime_mul(&vlapic->timer_period_bt, icr_timer); @@ -888,16 +884,22 @@ vlapic_calcdest(struct vm *vm, cpuset_t static VMM_STAT_ARRAY(IPIS_SENT, VM_MAXCPU, "ipis sent to vcpu"); -static int -lapic_process_icr(struct vlapic *vlapic, uint64_t icrval, bool *retu) +int +vlapic_icrlo_write_handler(struct vlapic *vlapic, bool *retu) { int i; bool phys; cpuset_t dmask; + uint64_t icrval; uint32_t dest, vec, mode; struct vlapic *vlapic2; struct vm_exit *vmexit; - + struct LAPIC *lapic; + + lapic = vlapic->apic_page; + lapic->icr_lo &= ~APIC_DELSTAT_PEND; + icrval = ((uint64_t)lapic->icr_hi << 32) | lapic->icr_lo; + if (x2apic(vlapic)) dest = icrval >> 32; else @@ -1088,7 +1090,7 @@ vlapic_svr_write_handler(struct vlapic * */ VLAPIC_CTR0(vlapic, "vlapic is software-enabled"); if (vlapic_periodic_timer(vlapic)) - vlapic_set_icr_timer(vlapic, lapic->icr_timer); + vlapic_icrtmr_write_handler(vlapic); } } } @@ -1155,6 +1157,8 @@ vlapic_read(struct vlapic *vlapic, uint6 break; case APIC_OFFSET_ICR_LOW: *data = lapic->icr_lo; + if (x2apic(vlapic)) + *data |= (uint64_t)lapic->icr_hi << 32; break; case APIC_OFFSET_ICR_HI: *data = lapic->icr_hi; @@ -1224,32 +1228,30 @@ vlapic_write(struct vlapic *vlapic, uint vlapic_svr_write_handler(vlapic); break; case APIC_OFFSET_ICR_LOW: - if (!x2apic(vlapic)) { - data &= 0xffffffff; - data |= (uint64_t)lapic->icr_hi << 32; - } - retval = lapic_process_icr(vlapic, data, retu); + lapic->icr_lo = data; + if (x2apic(vlapic)) + lapic->icr_hi = data >> 32; + retval = vlapic_icrlo_write_handler(vlapic, retu); break; case APIC_OFFSET_ICR_HI: - if (!x2apic(vlapic)) { - retval = 0; - lapic->icr_hi = data; - } + lapic->icr_hi = data; break; case APIC_OFFSET_CMCI_LVT: case APIC_OFFSET_TIMER_LVT ... APIC_OFFSET_ERROR_LVT: vlapic_set_lvt(vlapic, offset, data); break; case APIC_OFFSET_TIMER_ICR: - vlapic_set_icr_timer(vlapic, data); + lapic->icr_timer = data; + vlapic_icrtmr_write_handler(vlapic); break; case APIC_OFFSET_TIMER_DCR: - vlapic_set_dcr(vlapic, data); + lapic->dcr_timer = data; + vlapic_dcr_write_handler(vlapic); break; case APIC_OFFSET_ESR: - vlapic_update_errors(vlapic); + vlapic_esr_write_handler(vlapic); break; case APIC_OFFSET_VER: case APIC_OFFSET_APR: Modified: head/sys/amd64/vmm/io/vlapic.h ============================================================================== --- head/sys/amd64/vmm/io/vlapic.h Fri Dec 27 19:53:42 2013 (r259960) +++ head/sys/amd64/vmm/io/vlapic.h Fri Dec 27 20:18:19 2013 (r259961) @@ -76,4 +76,8 @@ void vlapic_id_write_handler(struct vlap void vlapic_ldr_write_handler(struct vlapic *vlapic); void vlapic_dfr_write_handler(struct vlapic *vlapic); void vlapic_svr_write_handler(struct vlapic *vlapic); +void vlapic_esr_write_handler(struct vlapic *vlapic); +int vlapic_icrlo_write_handler(struct vlapic *vlapic, bool *retu); +void vlapic_icrtmr_write_handler(struct vlapic *vlapic); +void vlapic_dcr_write_handler(struct vlapic *vlapic); #endif /* _VLAPIC_H_ */