VirtualBox

Changeset 24125 in vbox for trunk/src/VBox/Devices/PC


Ignore:
Timestamp:
Oct 28, 2009 9:58:41 AM (15 years ago)
Author:
vboxsync
Message:

DevAPIC/PDM: Properly route PIC interrupts through local APIC (fixes double time interrupt delivery in some Linux kernels).

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Devices/PC/DevAPIC.cpp

    r24082 r24125  
    390390                                           uint8_t u8DeliveryMode, uint8_t iVector, uint8_t u8Polarity,
    391391                                           uint8_t u8TriggerMode);
     392PDMBOTHCBDECL(int)  apicLocalInterrupt(PPDMDEVINS pDevIns, uint8_t u8Pin, uint8_t u8Level);
    392393PDMBOTHCBDECL(int)  apicWriteMSR(PPDMDEVINS pDevIns, VMCPUID iCpu, uint32_t u32Reg, uint64_t u64Value);
    393394PDMBOTHCBDECL(int)  apicReadMSR(PPDMDEVINS pDevIns, VMCPUID iCpu, uint32_t u32Reg, uint64_t *pu64Value);
     
    446447}
    447448
    448 DECLINLINE(void) cpuClearInterrupt(APICDeviceInfo* dev, APICState *s)
     449DECLINLINE(void) cpuClearInterrupt(APICDeviceInfo* dev, APICState *s, PDMAPICIRQ enmType = PDMAPICIRQ_HARDWARE)
    449450{
    450451    LogFlow(("apic: clear interrupt flag\n"));
    451     dev->CTX_SUFF(pApicHlp)->pfnClearInterruptFF(dev->CTX_SUFF(pDevIns),
     452    dev->CTX_SUFF(pApicHlp)->pfnClearInterruptFF(dev->CTX_SUFF(pDevIns), enmType,
    452453                                                 getCpuFromLapic(dev, s));
    453454}
     
    961962    return apic_bus_deliver(dev, apic_get_delivery_bitmask(dev, u8Dest, u8DestMode),
    962963                            u8DeliveryMode, iVector, u8Polarity, u8TriggerMode);
     964}
     965
     966/**
     967 * Local interrupt delivery, for devices attached to the CPU's LINT0/LINT1 pin.
     968 * Normally used for 8259A PIC and NMI.
     969 */
     970PDMBOTHCBDECL(int) apicLocalInterrupt(PPDMDEVINS pDevIns, uint8_t u8Pin, uint8_t u8Level)
     971{
     972    APICDeviceInfo  *dev = PDMINS_2_DATA(pDevIns, APICDeviceInfo *);
     973    APICState       *s = getLapicById(dev, 0);
     974
     975    Assert(PDMCritSectIsOwner(dev->CTX_SUFF(pCritSect)));
     976    LogFlow(("apicLocalInterrupt: pDevIns=%p u8Pin=%x\n", pDevIns, u8Pin));
     977
     978    /* If LAPIC is disabled, go straight to the CPU. */
     979    if (!(s->spurious_vec & APIC_SV_ENABLE))
     980    {
     981        LogFlow(("apicLocalInterrupt: LAPIC disabled, delivering directly to CPU core.\n"));
     982        if (u8Level)
     983            cpuSetInterrupt(dev, s, PDMAPICIRQ_EXTINT);
     984        else
     985            cpuClearInterrupt(dev, s, PDMAPICIRQ_EXTINT);
     986
     987        return VINF_SUCCESS;
     988    }
     989
     990    /* If LAPIC is enabled, interrupts are subject to LVT programming. */
     991    if (u8Pin > 1)
     992    {
     993        /* There are only two local interrupt pins. */
     994        AssertMsgFailed(("Invalid LAPIC pin %d\n", u8Pin));
     995        return VERR_INVALID_PARAMETER;
     996    }
     997
     998    /* NB: We currently only deliver local interrupts to the first CPU. In theory they
     999     * should be delivered to all CPUs and it is the guest's responsibility to ensure
     1000     * no more than one CPU has the interrupt unmasked.
     1001     */
     1002    uint32_t    u32Lvec;
     1003
     1004    u32Lvec = s->lvt[APIC_LVT_LINT0 + u8Pin];   /* Fetch corresponding LVT entry. */
     1005    /* Drop int if entry is masked. May not be correct for level-triggered interrupts. */
     1006    if (!(u32Lvec & APIC_LVT_MASKED))
     1007    {   uint8_t     u8Delivery;
     1008        PDMAPICIRQ  enmType;
     1009
     1010        u8Delivery = (u32Lvec >> 8) & 7;
     1011        switch (u8Delivery)
     1012        {
     1013        case APIC_DM_EXTINT:
     1014            Assert(u8Pin == 0); /* PIC should be wired to LINT0. */
     1015            enmType = PDMAPICIRQ_EXTINT;
     1016            break;
     1017        case APIC_DM_NMI:
     1018            Assert(u8Pin == 0); /* NMI should be wired to LINT1. */
     1019            enmType = PDMAPICIRQ_NMI;
     1020            break;
     1021        case APIC_DM_SMI:
     1022            enmType = PDMAPICIRQ_SMI;
     1023            break;
     1024
     1025        }
     1026        LogFlow(("apicLocalInterrupt: setting local interrupt type %d\n", enmType));
     1027        cpuSetInterrupt(dev, s, enmType);
     1028    }
     1029    return VINF_SUCCESS;
    9631030}
    9641031
     
    27442811    ApicReg.pfnReadMSRR3            = apicReadMSR;
    27452812    ApicReg.pfnBusDeliverR3         = apicBusDeliverCallback;
     2813    ApicReg.pfnLocalInterruptR3     = apicLocalInterrupt;
    27462814    if (fGCEnabled) {
    27472815        ApicReg.pszGetInterruptRC   = "apicGetInterrupt";
     
    27542822        ApicReg.pszReadMSRRC        = "apicReadMSR";
    27552823        ApicReg.pszBusDeliverRC     = "apicBusDeliverCallback";
     2824        ApicReg.pszLocalInterruptRC = "apicLocalInterrupt";
    27562825    } else {
    27572826        ApicReg.pszGetInterruptRC   = NULL;
     
    27642833        ApicReg.pszReadMSRRC        = NULL;
    27652834        ApicReg.pszBusDeliverRC     = NULL;
     2835        ApicReg.pszLocalInterruptRC = NULL;
    27662836    }
    27672837    if (fR0Enabled) {
     
    27752845        ApicReg.pszReadMSRR0        = "apicReadMSR";
    27762846        ApicReg.pszBusDeliverR0     = "apicBusDeliverCallback";
     2847        ApicReg.pszLocalInterruptR0 = "apicLocalInterrupt";
    27772848    } else {
    27782849        ApicReg.pszGetInterruptR0   = NULL;
     
    27852856        ApicReg.pszReadMSRR0        = NULL;
    27862857        ApicReg.pszBusDeliverR0     = NULL;
     2858        ApicReg.pszLocalInterruptR0 = NULL;
    27872859    }
    27882860
Note: See TracChangeset for help on using the changeset viewer.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette