📄 loapicintr.c
字号:
/* loApicIntr.c - Intel Pentium[234] Local APIC/xAPIC driver *//* Copyright 1984-2002 Wind River Systems, Inc. */#include "copyright_wrs.h"/*modification history--------------------01f,15may02,hdn changed apicId 8 bit to 16 bit, added DBG_MSG. added Error Status Register checking01e,08mar02,hdn updated loApicInit() and loApicIpi() added loApicEnable() for HTT (spr 73738)01d,29nov01,hdn doc update for 5.501c,21jun01,hdn added support for Pentium4 Local xAPIC moved show routines to loApicIntrShow.c01b,25mar98,hdn re-written.01a,20jun97,sub written.*//*DESCRIPTIONThis module is a driver for the local APIC/xAPIC (Advanced Programmable Interrupt Controller) in P6 (PentiumPro, II, III) family processorsand P7 (Pentium4) family processors. The local APIC/xAPIC is included in selected P6 (PentiumPro, II, III) and P7 (Pentium4) family processors.Beginning with the P6 family processors, the presence or absence of an on-chip local APIC can be detected using the CPUID instruction. When the CPUID instruction is executed, bit 9 of the feature flags returned in the EDX register indicates the presence (set) or absence (clear) of an on-chip local APIC.The local APIC performs two main functions for the processor: - It processes local external interrupts that the processor receives at its interrupt pins and local internal interrupts that software generates. - In multiple-processor systems, it communicates with an external IO APIC chip. The external IO APIC receives external interrupt events from the system and interprocessor interrupts from the processors on the system bus and distributes them to the processors on the system bus. The IO APIC is part of Intel's system chip set.The local APIC controls the dispatching of interrupts (to its associated processor) that it receives either locally or from the IO APIC. It providesfacilities for queuing, nesting and masking of interrupts. It handles the interrupt delivery protocol with its local processor and accesses to APIC registers, and also manages interprocessor interrupts and remote APIC registerreads. A timer on the local APIC allows local generation of interrupts, and local interrupt pins permit local reception of processor-specific interrupts.The local APIC can be disabled and used in conjunction with a standard 8259Astyle interrupt controller. Disabling the local APIC can be done in hardware for the Pentium processors or in software for the P6 and P7 (Pentium4) familyprocessors.The local APIC in the Pentium4 processors (called the xAPIC) is an extensionof the local APIC found in the P6 family processors. The primary differencebetween the APIC architecture and xAPIC architecture is that with Pentium4processors, the local xAPICs and IO xAPIC communicate with one another throughthe processors system bus; whereas, with the P6 family processors, communication between the local APICs and the IO APIC is handled through a dedicated 3-wire APIC bus. Also, some of the architectural features of the local APIC have been extended and/or modified in the local xAPIC.The base address of the local APIC and IO APIC is taken from the MP configurationtable (see Intel MP Specification Version 1.4) or the IA32_APIC_BASE MSR. It uses LOAPIC_BASE and IOAPIC_INDEX_BASE defined in the BSP, if it is not able to find the addresses. This driver contains three routines for use. They are:loApicInit() initializes the Local APIC for the interrupt mode chosen.loApicEnable() enables or disables the Local APIC. loApicIpi() delivers the inter processor interrupt to the specified local APIC.Local APIC is used in the Virtual Wire Mode (define VIRTUAL_WIRE_MODE in the BSP) and the Symmetric IO Mode (define SYMMETRIC_IO_MODE in the BSP), but notin the PIC Mode which is the default interrupt mode and uses 8259A PIC.Virtual Wire Mode is one of three interrupt modes defined by the MP specification. In this mode, interrupts are generated by the 8259A equivalentPICs, but delivered to the Boot Strap Processor by the local APIC that isprogrammed to act as a "virtual Wire"; that is, the local APIC is logicallyindistinguishable from a hardware connection. This is a uniprocessorcompatibility mode.Symmetric IO Mode is one of three interrupt modes defined by the MPspecification. In this mode, the local and IO APICs are fully functional, and interrupts are generated and delivered to the processors by the APICs.Any interrupt can be delivered to any processor. This is the only multiprocessor interrupt mode. The local and IO APICs support interrupts in the range of 32 to 255.Interrupt priority is implied by its vector, according to the following relationship: "priority = vector / 16".Here the quotient is rounded down to the nearest integer value to determinethe priority, with 1 being the lowest and 15 is the highest. Because vectors 0 through 31 are reserved for exclusive use by the processor, the priority ofuser defined interrupts range from 2 to 15. A value of 15 in the Interrupt Class field of the Task Priority Register (TPR) will mask off all interrupts,which require interrupt service.The P6 family processor's local APIC includes an in-service entry and a holdingentry for each priority level. To avoid losing interrupts, software should allocate no more than 2 interrupt vectors per priority. The Pentium4 processorexpands this support of all acceptance of two interrupts per vector rather thanper priority level.INCLUDE FILES: loApic.h*//* includes */#include "drv/intrCtl/loApic.h"/* defines */#define LOAPIC_DBG#ifdef LOAPIC_DBG# define LOAPIC_DBG_MSG(STR,VALUE) logMsg(STR,VALUE,0,0,0,0,0);#else# define LOAPIC_DBG_MSG(STR,VALUE)#endif /* IPI_DEBUG *//* externs */IMPORT CPUID sysCpuId; /* CPUID structure */IMPORT UINT sysProcessor; /* CPU family */IMPORT BOOL sysBp; /* TRUE(default) for BP, FALSE for AP *//* globals */UINT32 loApicBase = LOAPIC_BASE; /* def Local APIC addr */UINT32 ioApicBase = IOAPIC_INDEX_BASE; /* def IO APIC select (index) addr */UINT32 ioApicData = IOAPIC_DATA_BASE; /* def IO APIC window (data) addr */UINT32 loApicId; /* local APIC Id */UINT32 loApicVersion; /* local APIC Version */UINT32 loApicMaxLvt; /* local APIC Max LVT */UINT32 loApicBusy = 0; /* counter for not sending IPI */UINT32 loApicNcpu = 0; /* number of CPUs (MP Table) */UINT32 loApicNioApic = 0; /* number of IO APICs (MP Table) */BOOL loApicImcr = FALSE; /* TRUE if IMCR exist (MP Table) *//* locals */LOCAL UINT32 sysIntMaskLocalApic = 0;LOCAL UINT32 loApicOldSvr = 0; /* original SVR */LOCAL UINT32 loApicOldLint0 = 0; /* original LINT0 */LOCAL UINT32 loApicOldLint1 = 0; /* original LINT1 *//* forward declarations */LOCAL void loApicIntEoi (INT32 irq);LOCAL STATUS loApicMpConfigTableInit (void);LOCAL INT8 * loApicMpScan (INT8 * start, INT8 * end);/********************************************************************************* loApicInit - initialize the Local APIC or xAPIC** This routine initializes Local APIC or xAPIC.** RETURNS: N/A**/void loApicInit (void) { UINT32 apicBase[2]; /* override loApicBase from the MP Config Table */ (void) loApicMpConfigTableInit (); /* override loApicBase, sysBp from MSR if available */ if (sysCpuId.featuresEdx & CPUID_APIC) { pentiumMsrGet (IA32_APIC_BASE, (long long int *)&apicBase); loApicBase = apicBase[0] & LOAPIC_BASE_MASK; /* override */ sysBp = apicBase[0] & LOAPIC_BSP ? TRUE : FALSE; /* override */ /* enable the Local APIC explicitly */ apicBase[0] |= LOAPIC_GLOBAL_ENABLE; /* set E(nable) bit */ pentiumMsrSet (IA32_APIC_BASE, (long long int *)&apicBase); } /* remember the original state : SVR, LINT0, LINT1 for now */ loApicOldSvr = *(int *)(loApicBase + LOAPIC_SVR); loApicOldLint0 = *(int *)(loApicBase + LOAPIC_LINT0); loApicOldLint1 = *(int *)(loApicBase + LOAPIC_LINT1); /* enable the Local APIC */ loApicEnable (TRUE); *(int *)(loApicBase + LOAPIC_SVR) |= LOAPIC_FOCUS_DISABLE | INT_NUM_LOAPIC_SPURIOUS; /* get the Local APIC ID from Local APIC ID register */ loApicId = (*(int *)(loApicBase + LOAPIC_ID) & LOAPIC_ID_MASK) >> 24; /* get the Local APIC Version from Local APIC Version register */ loApicVersion = *(int *)(loApicBase + LOAPIC_VER) & LOAPIC_VERSION_MASK; loApicMaxLvt = (*(int *)(loApicBase + LOAPIC_VER) & LOAPIC_MAXLVT_MASK) >> 16; /* reset the DFR, TPR, TIMER_CONFIG, and TIMER_ICR */ *(int *)(loApicBase + LOAPIC_DFR) = 0xffffffff; *(int *)(loApicBase + LOAPIC_TPR) = 0x0; *(int *)(loApicBase + LOAPIC_TIMER_CONFIG) = 0x0; *(int *)(loApicBase + LOAPIC_TIMER_ICR) = 0x0;#if defined(VIRTUAL_WIRE_MODE) /* program Local Vector Table for the Virtual Wire Mode */ if (sysBp) { /* set LINT0: extInt, high-polarity, edge-trigger, not-masked */ *(int *)(loApicBase + LOAPIC_LINT0) = (*(int *)(loApicBase + LOAPIC_LINT0) & ~(LOAPIC_MODE | LOAPIC_LOW | LOAPIC_LEVEL | LOAPIC_MASK)) | (LOAPIC_EXT | LOAPIC_HIGH | LOAPIC_EDGE); /* set LINT1: NMI, high-polarity, edge-trigger, not-masked */ *(int *)(loApicBase + LOAPIC_LINT1) = (*(int *)(loApicBase + LOAPIC_LINT1) & ~(LOAPIC_MODE | LOAPIC_LOW | LOAPIC_LEVEL | LOAPIC_MASK)) | (LOAPIC_NMI | LOAPIC_HIGH | LOAPIC_EDGE); } else { *(int *)(loApicBase + LOAPIC_LINT0) = LOAPIC_MASK; *(int *)(loApicBase + LOAPIC_LINT1) = LOAPIC_MASK; }#elif defined(SYMMETRIC_IO_MODE) /* program Local Vector Table for the Symmetric IO Mode */ *(int *)(loApicBase + LOAPIC_LINT0) = LOAPIC_MASK; *(int *)(loApicBase + LOAPIC_LINT1) = LOAPIC_MASK; #endif /* defined(VIRTUAL_WIRE_MODE) */ /* lock the Local APIC interrupts */ *(int *)(loApicBase + LOAPIC_TIMER) = LOAPIC_MASK; *(int *)(loApicBase + LOAPIC_ERROR) = LOAPIC_MASK; if (loApicMaxLvt >= LOAPIC_LVT_P6) *(int *)(loApicBase + LOAPIC_PMC) = LOAPIC_MASK; if (loApicMaxLvt >= LOAPIC_LVT_PENTIUM4) *(int *)(loApicBase + LOAPIC_THERMAL) = LOAPIC_MASK; /* discard a pending interrupt if any */ *(int *)(loApicBase + LOAPIC_EOI) = 0; }/********************************************************************************* loApicEnable - enable or disable the Local xAPIC** This routine enables or disables the Local xAPIC. If the parameter is TRUE, * the Local xAPIC is enabled. If the parameter is FALSE, the Local xAPIC* is disabled.** RETURNS: N/A*/void loApicEnable ( BOOL enable /* enable the Local xAPIC */ ) { INT32 oldLevel; oldLevel = intLock (); /* LOCK INTERRUPTS */ /* enable or disable the Local APIC */ if (enable) { /* if the original mode is PIC mode, enable the Local APIC */ if ((loApicOldSvr & LOAPIC_ENABLE) == 0) { *(int *)(loApicBase + LOAPIC_SVR) |= LOAPIC_ENABLE; }#if defined (SYMMETRIC_IO_MODE) /* switch to SYMMETRIC_IO mode from PIC/VIRTUAL_WIRE mode */ if (loApicImcr) { sysOutByte (IMCR_ADRS, IMCR_REG_SEL); sysOutByte (IMCR_DATA, IMCR_IOAPIC_ON); }#endif /* defined (SYMMETRIC_IO_MODE) */ } else {#if defined (SYMMETRIC_IO_MODE) /* switch from SYMMETRIC_IO mode to PIC/VIRTUAL_WIRE mode */ if (loApicImcr) { sysOutByte (IMCR_ADRS, IMCR_REG_SEL); sysOutByte (IMCR_DATA, IMCR_IOAPIC_OFF); }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -