VirtualBox

Opened 17 months ago

Last modified 9 months ago

#21353 new defect

apic timer does not trigger in time

Reported by: liowmark Owned by:
Component: VMM Version: VirtualBox 6.1.40
Keywords: apic timer Cc:
Guest type: Linux Host type: Windows

Description

Rencently,I found a bug of APIC timer.Since the vbox set the last VCPU thread as the thread to wakeup all the timer and other VCPU threads will sleep 500ms until the Last VCPU thread wakeup them. If the last VCPU thread sleep a long time firstly,other VCPU thread's apic timer will not able to trigger in timer.This make other VCPU thread sleep at least 500ms.

here is may patch to the funtion apicSetTimerIcr in VMM/VMMALL/APICAll.cpp to fix the bug

#include "TMInternal.h"
static VBOXSTRICTRC apicSetTimerIcr(PPDMDEVINS pDevIns, PVMCPUCC pVCpu, int rcBusy, uint32_t uInitialCount)
{
    VMCPU_ASSERT_EMT(pVCpu);

    PAPIC      pApic      = VM_TO_APIC(pVCpu->CTX_SUFF(pVM));
    PAPICCPU   pApicCpu   = VMCPU_TO_APICCPU(pVCpu);
    PXAPICPAGE pXApicPage = VMCPU_TO_XAPICPAGE(pVCpu);

    Log2(("APIC%u: apicSetTimerIcr: uInitialCount=%#RX32\n", pVCpu->idCpu, uInitialCount));
    STAM_COUNTER_INC(&pApicCpu->StatTimerIcrWrite);

    /* In TSC-deadline mode, timer ICR writes are ignored, see Intel spec. 10.5.4.1 "TSC-Deadline Mode". */
    if (   pApic->fSupportsTscDeadline
        && pXApicPage->lvt_timer.u.u2TimerMode == XAPIC_TIMER_MODE_TSC_DEADLINE)
        return VINF_SUCCESS;

    /*
     * The timer CCR may be modified by apicR3TimerCallback() in parallel,
     * so obtain the lock -before- updating it here to be consistent with the
     * timer ICR. We rely on CCR being consistent in apicGetTimerCcr().
     */
    TMTIMERHANDLE hTimer = pApicCpu->hTimer;
    VBOXSTRICTRC rc = PDMDevHlpTimerLockClock(pDevIns, hTimer, rcBusy);
    if (rc == VINF_SUCCESS)
    {
        pXApicPage->timer_icr.u32InitialCount = uInitialCount;
        pXApicPage->timer_ccr.u32CurrentCount = uInitialCount;
        if (uInitialCount)
            apicStartTimer(pVCpu, uInitialCount);
        else
            apicStopTimer(pVCpu);


        PVMCC pVM   = pVCpu->CTX_SUFF(pVM);
        PVMCPUCC pVCpuDst = VMCC_GET_CPU(pVM, pVM->tm.s.idTimerCpu);

        #ifdef IN_RING3
            VMR3NotifyCpuFFU(pVCpuDst->pUVCpu, VMNOTIFYFF_FLAGS_DONE_REM | VMNOTIFYFF_FLAGS_POKE);
        #elif defined(IN_RING0)

           if (VMMGetCpu(pVM) != pVCpuDst)
            {
                switch (VMCPU_GET_STATE(pVCpuDst))
                {
                    case VMCPUSTATE_STARTED_EXEC:
                        GVMMR0SchedPokeNoGVMNoLock(pVM, pVM->tm.s.idTimerCpu);
                        break;

                    case VMCPUSTATE_STARTED_HALTED:
                        GVMMR0SchedWakeUpNoGVMNoLock(pVM, pVM->tm.s.idTimerCpu);
                        break;

                    default:
                        break; /* nothing to do in other states. */
                }
            }
        #endif

        PDMDevHlpTimerUnlockClock(pDevIns, hTimer);
    }
    return rc;
}

Change History (1)

comment:1 by riverskyfang, 9 months ago

Is there a testcase that can reproduce this issue?

Last edited 9 months ago by riverskyfang (previous) (diff)
Note: See TracTickets for help on using tickets.

© 2023 Oracle
ContactPrivacy policyTerms of Use