12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268 |
- /** @file
- Local APIC Library.
- This local APIC library instance supports xAPIC mode only.
- Copyright (c) 2010 - 2019, Intel Corporation. All rights reserved.<BR>
- Copyright (c) 2017 - 2020, AMD Inc. All rights reserved.<BR>
- SPDX-License-Identifier: BSD-2-Clause-Patent
- **/
- #include <Register/Intel/Cpuid.h>
- #include <Register/Amd/Cpuid.h>
- #include <Register/Intel/Msr.h>
- #include <Register/Intel/LocalApic.h>
- #include <Library/BaseLib.h>
- #include <Library/DebugLib.h>
- #include <Library/LocalApicLib.h>
- #include <Library/IoLib.h>
- #include <Library/TimerLib.h>
- #include <Library/PcdLib.h>
- #include <Library/UefiCpuLib.h>
- //
- // Library internal functions
- //
- /**
- Determine if the CPU supports the Local APIC Base Address MSR.
- @retval TRUE The CPU supports the Local APIC Base Address MSR.
- @retval FALSE The CPU does not support the Local APIC Base Address MSR.
- **/
- BOOLEAN
- LocalApicBaseAddressMsrSupported (
- VOID
- )
- {
- UINT32 RegEax;
- UINTN FamilyId;
- AsmCpuid (1, &RegEax, NULL, NULL, NULL);
- FamilyId = BitFieldRead32 (RegEax, 8, 11);
- if ((FamilyId == 0x04) || (FamilyId == 0x05)) {
- //
- // CPUs with a FamilyId of 0x04 or 0x05 do not support the
- // Local APIC Base Address MSR
- //
- return FALSE;
- }
- return TRUE;
- }
- /**
- Retrieve the base address of local APIC.
- @return The base address of local APIC.
- **/
- UINTN
- EFIAPI
- GetLocalApicBaseAddress (
- VOID
- )
- {
- MSR_IA32_APIC_BASE_REGISTER ApicBaseMsr;
- if (!LocalApicBaseAddressMsrSupported ()) {
- //
- // If CPU does not support Local APIC Base Address MSR, then retrieve
- // Local APIC Base Address from PCD
- //
- return PcdGet32 (PcdCpuLocalApicBaseAddress);
- }
- ApicBaseMsr.Uint64 = AsmReadMsr64 (MSR_IA32_APIC_BASE);
- return (UINTN)(LShiftU64 ((UINT64)ApicBaseMsr.Bits.ApicBaseHi, 32)) +
- (((UINTN)ApicBaseMsr.Bits.ApicBase) << 12);
- }
- /**
- Set the base address of local APIC.
- If BaseAddress is not aligned on a 4KB boundary, then ASSERT().
- @param[in] BaseAddress Local APIC base address to be set.
- **/
- VOID
- EFIAPI
- SetLocalApicBaseAddress (
- IN UINTN BaseAddress
- )
- {
- MSR_IA32_APIC_BASE_REGISTER ApicBaseMsr;
- ASSERT ((BaseAddress & (SIZE_4KB - 1)) == 0);
- if (!LocalApicBaseAddressMsrSupported ()) {
- //
- // Ignore set request if the CPU does not support APIC Base Address MSR
- //
- return;
- }
- ApicBaseMsr.Uint64 = AsmReadMsr64 (MSR_IA32_APIC_BASE);
- ApicBaseMsr.Bits.ApicBase = (UINT32)(BaseAddress >> 12);
- ApicBaseMsr.Bits.ApicBaseHi = (UINT32)(RShiftU64 ((UINT64)BaseAddress, 32));
- AsmWriteMsr64 (MSR_IA32_APIC_BASE, ApicBaseMsr.Uint64);
- }
- /**
- Read from a local APIC register.
- This function reads from a local APIC register either in xAPIC or x2APIC mode.
- It is required that in xAPIC mode wider registers (64-bit or 256-bit) must be
- accessed using multiple 32-bit loads or stores, so this function only performs
- 32-bit read.
- @param MmioOffset The MMIO offset of the local APIC register in xAPIC mode.
- It must be 16-byte aligned.
- @return 32-bit Value read from the register.
- **/
- UINT32
- EFIAPI
- ReadLocalApicReg (
- IN UINTN MmioOffset
- )
- {
- ASSERT ((MmioOffset & 0xf) == 0);
- ASSERT (GetApicMode () == LOCAL_APIC_MODE_XAPIC);
- return MmioRead32 (GetLocalApicBaseAddress () + MmioOffset);
- }
- /**
- Write to a local APIC register.
- This function writes to a local APIC register either in xAPIC or x2APIC mode.
- It is required that in xAPIC mode wider registers (64-bit or 256-bit) must be
- accessed using multiple 32-bit loads or stores, so this function only performs
- 32-bit write.
- if the register index is invalid or unsupported in current APIC mode, then ASSERT.
- @param MmioOffset The MMIO offset of the local APIC register in xAPIC mode.
- It must be 16-byte aligned.
- @param Value Value to be written to the register.
- **/
- VOID
- EFIAPI
- WriteLocalApicReg (
- IN UINTN MmioOffset,
- IN UINT32 Value
- )
- {
- ASSERT ((MmioOffset & 0xf) == 0);
- ASSERT (GetApicMode () == LOCAL_APIC_MODE_XAPIC);
- MmioWrite32 (GetLocalApicBaseAddress () + MmioOffset, Value);
- }
- /**
- Send an IPI by writing to ICR.
- This function returns after the IPI has been accepted by the target processor.
- @param IcrLow 32-bit value to be written to the low half of ICR.
- @param ApicId APIC ID of the target processor if this IPI is targeted for a specific processor.
- **/
- VOID
- SendIpi (
- IN UINT32 IcrLow,
- IN UINT32 ApicId
- )
- {
- LOCAL_APIC_ICR_LOW IcrLowReg;
- UINT32 IcrHigh;
- BOOLEAN InterruptState;
- ASSERT (GetApicMode () == LOCAL_APIC_MODE_XAPIC);
- ASSERT (ApicId <= 0xff);
- InterruptState = SaveAndDisableInterrupts ();
- //
- // Save existing contents of ICR high 32 bits
- //
- IcrHigh = ReadLocalApicReg (XAPIC_ICR_HIGH_OFFSET);
- //
- // Wait for DeliveryStatus clear in case a previous IPI
- // is still being sent
- //
- do {
- IcrLowReg.Uint32 = ReadLocalApicReg (XAPIC_ICR_LOW_OFFSET);
- } while (IcrLowReg.Bits.DeliveryStatus != 0);
- //
- // For xAPIC, the act of writing to the low doubleword of the ICR causes the IPI to be sent.
- //
- WriteLocalApicReg (XAPIC_ICR_HIGH_OFFSET, ApicId << 24);
- WriteLocalApicReg (XAPIC_ICR_LOW_OFFSET, IcrLow);
- //
- // Wait for DeliveryStatus clear again
- //
- do {
- IcrLowReg.Uint32 = ReadLocalApicReg (XAPIC_ICR_LOW_OFFSET);
- } while (IcrLowReg.Bits.DeliveryStatus != 0);
- //
- // And restore old contents of ICR high
- //
- WriteLocalApicReg (XAPIC_ICR_HIGH_OFFSET, IcrHigh);
- SetInterruptState (InterruptState);
- }
- //
- // Library API implementation functions
- //
- /**
- Get the current local APIC mode.
- If local APIC is disabled, then ASSERT.
- @retval LOCAL_APIC_MODE_XAPIC current APIC mode is xAPIC.
- @retval LOCAL_APIC_MODE_X2APIC current APIC mode is x2APIC.
- **/
- UINTN
- EFIAPI
- GetApicMode (
- VOID
- )
- {
- DEBUG_CODE_BEGIN ();
- {
- MSR_IA32_APIC_BASE_REGISTER ApicBaseMsr;
- //
- // Check to see if the CPU supports the APIC Base Address MSR
- //
- if (LocalApicBaseAddressMsrSupported ()) {
- ApicBaseMsr.Uint64 = AsmReadMsr64 (MSR_IA32_APIC_BASE);
- //
- // Local APIC should have been enabled
- //
- ASSERT (ApicBaseMsr.Bits.EN != 0);
- ASSERT (ApicBaseMsr.Bits.EXTD == 0);
- }
- }
- DEBUG_CODE_END ();
- return LOCAL_APIC_MODE_XAPIC;
- }
- /**
- Set the current local APIC mode.
- If the specified local APIC mode is not valid, then ASSERT.
- If the specified local APIC mode can't be set as current, then ASSERT.
- @param ApicMode APIC mode to be set.
- @note This API must not be called from an interrupt handler or SMI handler.
- It may result in unpredictable behavior.
- **/
- VOID
- EFIAPI
- SetApicMode (
- IN UINTN ApicMode
- )
- {
- ASSERT (ApicMode == LOCAL_APIC_MODE_XAPIC);
- ASSERT (GetApicMode () == LOCAL_APIC_MODE_XAPIC);
- }
- /**
- Get the initial local APIC ID of the executing processor assigned by hardware upon power on or reset.
- In xAPIC mode, the initial local APIC ID may be different from current APIC ID.
- In x2APIC mode, the local APIC ID can't be changed and there is no concept of initial APIC ID. In this case,
- the 32-bit local APIC ID is returned as initial APIC ID.
- @return 32-bit initial local APIC ID of the executing processor.
- **/
- UINT32
- EFIAPI
- GetInitialApicId (
- VOID
- )
- {
- UINT32 ApicId;
- UINT32 MaxCpuIdIndex;
- UINT32 RegEbx;
- ASSERT (GetApicMode () == LOCAL_APIC_MODE_XAPIC);
- //
- // Get the max index of basic CPUID
- //
- AsmCpuid (CPUID_SIGNATURE, &MaxCpuIdIndex, NULL, NULL, NULL);
- //
- // If CPUID Leaf B is supported,
- // And CPUID.0BH:EBX[15:0] reports a non-zero value,
- // Then the initial 32-bit APIC ID = CPUID.0BH:EDX
- // Else the initial 8-bit APIC ID = CPUID.1:EBX[31:24]
- //
- if (MaxCpuIdIndex >= CPUID_EXTENDED_TOPOLOGY) {
- AsmCpuidEx (CPUID_EXTENDED_TOPOLOGY, 0, NULL, &RegEbx, NULL, &ApicId);
- if ((RegEbx & (BIT16 - 1)) != 0) {
- return ApicId;
- }
- }
- AsmCpuid (CPUID_VERSION_INFO, NULL, &RegEbx, NULL, NULL);
- return RegEbx >> 24;
- }
- /**
- Get the local APIC ID of the executing processor.
- @return 32-bit local APIC ID of the executing processor.
- **/
- UINT32
- EFIAPI
- GetApicId (
- VOID
- )
- {
- UINT32 ApicId;
- ASSERT (GetApicMode () == LOCAL_APIC_MODE_XAPIC);
- if ((ApicId = GetInitialApicId ()) < 0x100) {
- //
- // If the initial local APIC ID is less 0x100, read APIC ID from
- // XAPIC_ID_OFFSET, otherwise return the initial local APIC ID.
- //
- ApicId = ReadLocalApicReg (XAPIC_ID_OFFSET);
- ApicId >>= 24;
- }
- return ApicId;
- }
- /**
- Get the value of the local APIC version register.
- @return the value of the local APIC version register.
- **/
- UINT32
- EFIAPI
- GetApicVersion (
- VOID
- )
- {
- return ReadLocalApicReg (XAPIC_VERSION_OFFSET);
- }
- /**
- Send a Fixed IPI to a specified target processor.
- This function returns after the IPI has been accepted by the target processor.
- @param ApicId The local APIC ID of the target processor.
- @param Vector The vector number of the interrupt being sent.
- **/
- VOID
- EFIAPI
- SendFixedIpi (
- IN UINT32 ApicId,
- IN UINT8 Vector
- )
- {
- LOCAL_APIC_ICR_LOW IcrLow;
- IcrLow.Uint32 = 0;
- IcrLow.Bits.DeliveryMode = LOCAL_APIC_DELIVERY_MODE_FIXED;
- IcrLow.Bits.Level = 1;
- IcrLow.Bits.Vector = Vector;
- SendIpi (IcrLow.Uint32, ApicId);
- }
- /**
- Send a Fixed IPI to all processors excluding self.
- This function returns after the IPI has been accepted by the target processors.
- @param Vector The vector number of the interrupt being sent.
- **/
- VOID
- EFIAPI
- SendFixedIpiAllExcludingSelf (
- IN UINT8 Vector
- )
- {
- LOCAL_APIC_ICR_LOW IcrLow;
- IcrLow.Uint32 = 0;
- IcrLow.Bits.DeliveryMode = LOCAL_APIC_DELIVERY_MODE_FIXED;
- IcrLow.Bits.Level = 1;
- IcrLow.Bits.DestinationShorthand = LOCAL_APIC_DESTINATION_SHORTHAND_ALL_EXCLUDING_SELF;
- IcrLow.Bits.Vector = Vector;
- SendIpi (IcrLow.Uint32, 0);
- }
- /**
- Send a SMI IPI to a specified target processor.
- This function returns after the IPI has been accepted by the target processor.
- @param ApicId Specify the local APIC ID of the target processor.
- **/
- VOID
- EFIAPI
- SendSmiIpi (
- IN UINT32 ApicId
- )
- {
- LOCAL_APIC_ICR_LOW IcrLow;
- IcrLow.Uint32 = 0;
- IcrLow.Bits.DeliveryMode = LOCAL_APIC_DELIVERY_MODE_SMI;
- IcrLow.Bits.Level = 1;
- SendIpi (IcrLow.Uint32, ApicId);
- }
- /**
- Send a SMI IPI to all processors excluding self.
- This function returns after the IPI has been accepted by the target processors.
- **/
- VOID
- EFIAPI
- SendSmiIpiAllExcludingSelf (
- VOID
- )
- {
- LOCAL_APIC_ICR_LOW IcrLow;
- IcrLow.Uint32 = 0;
- IcrLow.Bits.DeliveryMode = LOCAL_APIC_DELIVERY_MODE_SMI;
- IcrLow.Bits.Level = 1;
- IcrLow.Bits.DestinationShorthand = LOCAL_APIC_DESTINATION_SHORTHAND_ALL_EXCLUDING_SELF;
- SendIpi (IcrLow.Uint32, 0);
- }
- /**
- Send an INIT IPI to a specified target processor.
- This function returns after the IPI has been accepted by the target processor.
- @param ApicId Specify the local APIC ID of the target processor.
- **/
- VOID
- EFIAPI
- SendInitIpi (
- IN UINT32 ApicId
- )
- {
- LOCAL_APIC_ICR_LOW IcrLow;
- IcrLow.Uint32 = 0;
- IcrLow.Bits.DeliveryMode = LOCAL_APIC_DELIVERY_MODE_INIT;
- IcrLow.Bits.Level = 1;
- SendIpi (IcrLow.Uint32, ApicId);
- }
- /**
- Send an INIT IPI to all processors excluding self.
- This function returns after the IPI has been accepted by the target processors.
- **/
- VOID
- EFIAPI
- SendInitIpiAllExcludingSelf (
- VOID
- )
- {
- LOCAL_APIC_ICR_LOW IcrLow;
- IcrLow.Uint32 = 0;
- IcrLow.Bits.DeliveryMode = LOCAL_APIC_DELIVERY_MODE_INIT;
- IcrLow.Bits.Level = 1;
- IcrLow.Bits.DestinationShorthand = LOCAL_APIC_DESTINATION_SHORTHAND_ALL_EXCLUDING_SELF;
- SendIpi (IcrLow.Uint32, 0);
- }
- /**
- Send an INIT-Start-up-Start-up IPI sequence to a specified target processor.
- This function returns after the IPI has been accepted by the target processor.
- if StartupRoutine >= 1M, then ASSERT.
- if StartupRoutine is not multiple of 4K, then ASSERT.
- @param ApicId Specify the local APIC ID of the target processor.
- @param StartupRoutine Points to a start-up routine which is below 1M physical
- address and 4K aligned.
- **/
- VOID
- EFIAPI
- SendInitSipiSipi (
- IN UINT32 ApicId,
- IN UINT32 StartupRoutine
- )
- {
- LOCAL_APIC_ICR_LOW IcrLow;
- ASSERT (StartupRoutine < 0x100000);
- ASSERT ((StartupRoutine & 0xfff) == 0);
- SendInitIpi (ApicId);
- MicroSecondDelay (PcdGet32 (PcdCpuInitIpiDelayInMicroSeconds));
- IcrLow.Uint32 = 0;
- IcrLow.Bits.Vector = (StartupRoutine >> 12);
- IcrLow.Bits.DeliveryMode = LOCAL_APIC_DELIVERY_MODE_STARTUP;
- IcrLow.Bits.Level = 1;
- SendIpi (IcrLow.Uint32, ApicId);
- if (!StandardSignatureIsAuthenticAMD ()) {
- MicroSecondDelay (200);
- SendIpi (IcrLow.Uint32, ApicId);
- }
- }
- /**
- Send an INIT-Start-up-Start-up IPI sequence to all processors excluding self.
- This function returns after the IPI has been accepted by the target processors.
- if StartupRoutine >= 1M, then ASSERT.
- if StartupRoutine is not multiple of 4K, then ASSERT.
- @param StartupRoutine Points to a start-up routine which is below 1M physical
- address and 4K aligned.
- **/
- VOID
- EFIAPI
- SendInitSipiSipiAllExcludingSelf (
- IN UINT32 StartupRoutine
- )
- {
- LOCAL_APIC_ICR_LOW IcrLow;
- ASSERT (StartupRoutine < 0x100000);
- ASSERT ((StartupRoutine & 0xfff) == 0);
- SendInitIpiAllExcludingSelf ();
- MicroSecondDelay (PcdGet32 (PcdCpuInitIpiDelayInMicroSeconds));
- IcrLow.Uint32 = 0;
- IcrLow.Bits.Vector = (StartupRoutine >> 12);
- IcrLow.Bits.DeliveryMode = LOCAL_APIC_DELIVERY_MODE_STARTUP;
- IcrLow.Bits.Level = 1;
- IcrLow.Bits.DestinationShorthand = LOCAL_APIC_DESTINATION_SHORTHAND_ALL_EXCLUDING_SELF;
- SendIpi (IcrLow.Uint32, 0);
- if (!StandardSignatureIsAuthenticAMD ()) {
- MicroSecondDelay (200);
- SendIpi (IcrLow.Uint32, 0);
- }
- }
- /**
- Initialize the state of the SoftwareEnable bit in the Local APIC
- Spurious Interrupt Vector register.
- @param Enable If TRUE, then set SoftwareEnable to 1
- If FALSE, then set SoftwareEnable to 0.
- **/
- VOID
- EFIAPI
- InitializeLocalApicSoftwareEnable (
- IN BOOLEAN Enable
- )
- {
- LOCAL_APIC_SVR Svr;
- //
- // Set local APIC software-enabled bit.
- //
- Svr.Uint32 = ReadLocalApicReg (XAPIC_SPURIOUS_VECTOR_OFFSET);
- if (Enable) {
- if (Svr.Bits.SoftwareEnable == 0) {
- Svr.Bits.SoftwareEnable = 1;
- WriteLocalApicReg (XAPIC_SPURIOUS_VECTOR_OFFSET, Svr.Uint32);
- }
- } else {
- if (Svr.Bits.SoftwareEnable == 1) {
- Svr.Bits.SoftwareEnable = 0;
- WriteLocalApicReg (XAPIC_SPURIOUS_VECTOR_OFFSET, Svr.Uint32);
- }
- }
- }
- /**
- Programming Virtual Wire Mode.
- This function programs the local APIC for virtual wire mode following
- the example described in chapter A.3 of the MP 1.4 spec.
- IOxAPIC is not involved in this type of virtual wire mode.
- **/
- VOID
- EFIAPI
- ProgramVirtualWireMode (
- VOID
- )
- {
- LOCAL_APIC_SVR Svr;
- LOCAL_APIC_LVT_LINT Lint;
- //
- // Enable the APIC via SVR and set the spurious interrupt to use Int 00F.
- //
- Svr.Uint32 = ReadLocalApicReg (XAPIC_SPURIOUS_VECTOR_OFFSET);
- Svr.Bits.SpuriousVector = 0xf;
- Svr.Bits.SoftwareEnable = 1;
- WriteLocalApicReg (XAPIC_SPURIOUS_VECTOR_OFFSET, Svr.Uint32);
- //
- // Program the LINT0 vector entry as ExtInt. Not masked, edge, active high.
- //
- Lint.Uint32 = ReadLocalApicReg (XAPIC_LVT_LINT0_OFFSET);
- Lint.Bits.DeliveryMode = LOCAL_APIC_DELIVERY_MODE_EXTINT;
- Lint.Bits.InputPinPolarity = 0;
- Lint.Bits.TriggerMode = 0;
- Lint.Bits.Mask = 0;
- WriteLocalApicReg (XAPIC_LVT_LINT0_OFFSET, Lint.Uint32);
- //
- // Program the LINT0 vector entry as NMI. Not masked, edge, active high.
- //
- Lint.Uint32 = ReadLocalApicReg (XAPIC_LVT_LINT1_OFFSET);
- Lint.Bits.DeliveryMode = LOCAL_APIC_DELIVERY_MODE_NMI;
- Lint.Bits.InputPinPolarity = 0;
- Lint.Bits.TriggerMode = 0;
- Lint.Bits.Mask = 0;
- WriteLocalApicReg (XAPIC_LVT_LINT1_OFFSET, Lint.Uint32);
- }
- /**
- Disable LINT0 & LINT1 interrupts.
- This function sets the mask flag in the LVT LINT0 & LINT1 registers.
- **/
- VOID
- EFIAPI
- DisableLvtInterrupts (
- VOID
- )
- {
- LOCAL_APIC_LVT_LINT LvtLint;
- LvtLint.Uint32 = ReadLocalApicReg (XAPIC_LVT_LINT0_OFFSET);
- LvtLint.Bits.Mask = 1;
- WriteLocalApicReg (XAPIC_LVT_LINT0_OFFSET, LvtLint.Uint32);
- LvtLint.Uint32 = ReadLocalApicReg (XAPIC_LVT_LINT1_OFFSET);
- LvtLint.Bits.Mask = 1;
- WriteLocalApicReg (XAPIC_LVT_LINT1_OFFSET, LvtLint.Uint32);
- }
- /**
- Read the initial count value from the init-count register.
- @return The initial count value read from the init-count register.
- **/
- UINT32
- EFIAPI
- GetApicTimerInitCount (
- VOID
- )
- {
- return ReadLocalApicReg (XAPIC_TIMER_INIT_COUNT_OFFSET);
- }
- /**
- Read the current count value from the current-count register.
- @return The current count value read from the current-count register.
- **/
- UINT32
- EFIAPI
- GetApicTimerCurrentCount (
- VOID
- )
- {
- return ReadLocalApicReg (XAPIC_TIMER_CURRENT_COUNT_OFFSET);
- }
- /**
- Initialize the local APIC timer.
- The local APIC timer is initialized and enabled.
- @param DivideValue The divide value for the DCR. It is one of 1,2,4,8,16,32,64,128.
- If it is 0, then use the current divide value in the DCR.
- @param InitCount The initial count value.
- @param PeriodicMode If TRUE, timer mode is peridoic. Othewise, timer mode is one-shot.
- @param Vector The timer interrupt vector number.
- **/
- VOID
- EFIAPI
- InitializeApicTimer (
- IN UINTN DivideValue,
- IN UINT32 InitCount,
- IN BOOLEAN PeriodicMode,
- IN UINT8 Vector
- )
- {
- LOCAL_APIC_DCR Dcr;
- LOCAL_APIC_LVT_TIMER LvtTimer;
- UINT32 Divisor;
- //
- // Ensure local APIC is in software-enabled state.
- //
- InitializeLocalApicSoftwareEnable (TRUE);
- //
- // Program init-count register.
- //
- WriteLocalApicReg (XAPIC_TIMER_INIT_COUNT_OFFSET, InitCount);
- if (DivideValue != 0) {
- ASSERT (DivideValue <= 128);
- ASSERT (DivideValue == GetPowerOfTwo32 ((UINT32)DivideValue));
- Divisor = (UINT32)((HighBitSet32 ((UINT32)DivideValue) - 1) & 0x7);
- Dcr.Uint32 = ReadLocalApicReg (XAPIC_TIMER_DIVIDE_CONFIGURATION_OFFSET);
- Dcr.Bits.DivideValue1 = (Divisor & 0x3);
- Dcr.Bits.DivideValue2 = (Divisor >> 2);
- WriteLocalApicReg (XAPIC_TIMER_DIVIDE_CONFIGURATION_OFFSET, Dcr.Uint32);
- }
- //
- // Enable APIC timer interrupt with specified timer mode.
- //
- LvtTimer.Uint32 = ReadLocalApicReg (XAPIC_LVT_TIMER_OFFSET);
- if (PeriodicMode) {
- LvtTimer.Bits.TimerMode = 1;
- } else {
- LvtTimer.Bits.TimerMode = 0;
- }
- LvtTimer.Bits.Mask = 0;
- LvtTimer.Bits.Vector = Vector;
- WriteLocalApicReg (XAPIC_LVT_TIMER_OFFSET, LvtTimer.Uint32);
- }
- /**
- Get the state of the local APIC timer.
- This function will ASSERT if the local APIC is not software enabled.
- @param DivideValue Return the divide value for the DCR. It is one of 1,2,4,8,16,32,64,128.
- @param PeriodicMode Return the timer mode. If TRUE, timer mode is peridoic. Othewise, timer mode is one-shot.
- @param Vector Return the timer interrupt vector number.
- **/
- VOID
- EFIAPI
- GetApicTimerState (
- OUT UINTN *DivideValue OPTIONAL,
- OUT BOOLEAN *PeriodicMode OPTIONAL,
- OUT UINT8 *Vector OPTIONAL
- )
- {
- UINT32 Divisor;
- LOCAL_APIC_DCR Dcr;
- LOCAL_APIC_LVT_TIMER LvtTimer;
- //
- // Check the APIC Software Enable/Disable bit (bit 8) in Spurious-Interrupt
- // Vector Register.
- // This bit will be 1, if local APIC is software enabled.
- //
- ASSERT ((ReadLocalApicReg (XAPIC_SPURIOUS_VECTOR_OFFSET) & BIT8) != 0);
- if (DivideValue != NULL) {
- Dcr.Uint32 = ReadLocalApicReg (XAPIC_TIMER_DIVIDE_CONFIGURATION_OFFSET);
- Divisor = Dcr.Bits.DivideValue1 | (Dcr.Bits.DivideValue2 << 2);
- Divisor = (Divisor + 1) & 0x7;
- *DivideValue = ((UINTN)1) << Divisor;
- }
- if ((PeriodicMode != NULL) || (Vector != NULL)) {
- LvtTimer.Uint32 = ReadLocalApicReg (XAPIC_LVT_TIMER_OFFSET);
- if (PeriodicMode != NULL) {
- if (LvtTimer.Bits.TimerMode == 1) {
- *PeriodicMode = TRUE;
- } else {
- *PeriodicMode = FALSE;
- }
- }
- if (Vector != NULL) {
- *Vector = (UINT8)LvtTimer.Bits.Vector;
- }
- }
- }
- /**
- Enable the local APIC timer interrupt.
- **/
- VOID
- EFIAPI
- EnableApicTimerInterrupt (
- VOID
- )
- {
- LOCAL_APIC_LVT_TIMER LvtTimer;
- LvtTimer.Uint32 = ReadLocalApicReg (XAPIC_LVT_TIMER_OFFSET);
- LvtTimer.Bits.Mask = 0;
- WriteLocalApicReg (XAPIC_LVT_TIMER_OFFSET, LvtTimer.Uint32);
- }
- /**
- Disable the local APIC timer interrupt.
- **/
- VOID
- EFIAPI
- DisableApicTimerInterrupt (
- VOID
- )
- {
- LOCAL_APIC_LVT_TIMER LvtTimer;
- LvtTimer.Uint32 = ReadLocalApicReg (XAPIC_LVT_TIMER_OFFSET);
- LvtTimer.Bits.Mask = 1;
- WriteLocalApicReg (XAPIC_LVT_TIMER_OFFSET, LvtTimer.Uint32);
- }
- /**
- Get the local APIC timer interrupt state.
- @retval TRUE The local APIC timer interrupt is enabled.
- @retval FALSE The local APIC timer interrupt is disabled.
- **/
- BOOLEAN
- EFIAPI
- GetApicTimerInterruptState (
- VOID
- )
- {
- LOCAL_APIC_LVT_TIMER LvtTimer;
- LvtTimer.Uint32 = ReadLocalApicReg (XAPIC_LVT_TIMER_OFFSET);
- return (BOOLEAN)(LvtTimer.Bits.Mask == 0);
- }
- /**
- Send EOI to the local APIC.
- **/
- VOID
- EFIAPI
- SendApicEoi (
- VOID
- )
- {
- WriteLocalApicReg (XAPIC_EOI_OFFSET, 0);
- }
- /**
- Get the 32-bit address that a device should use to send a Message Signaled
- Interrupt (MSI) to the Local APIC of the currently executing processor.
- @return 32-bit address used to send an MSI to the Local APIC.
- **/
- UINT32
- EFIAPI
- GetApicMsiAddress (
- VOID
- )
- {
- LOCAL_APIC_MSI_ADDRESS MsiAddress;
- //
- // Return address for an MSI interrupt to be delivered only to the APIC ID
- // of the currently executing processor.
- //
- MsiAddress.Uint32 = 0;
- MsiAddress.Bits.BaseAddress = 0xFEE;
- MsiAddress.Bits.DestinationId = GetApicId ();
- return MsiAddress.Uint32;
- }
- /**
- Get the 64-bit data value that a device should use to send a Message Signaled
- Interrupt (MSI) to the Local APIC of the currently executing processor.
- If Vector is not in range 0x10..0xFE, then ASSERT().
- If DeliveryMode is not supported, then ASSERT().
- @param Vector The 8-bit interrupt vector associated with the MSI.
- Must be in the range 0x10..0xFE
- @param DeliveryMode A 3-bit value that specifies how the recept of the MSI
- is handled. The only supported values are:
- 0: LOCAL_APIC_DELIVERY_MODE_FIXED
- 1: LOCAL_APIC_DELIVERY_MODE_LOWEST_PRIORITY
- 2: LOCAL_APIC_DELIVERY_MODE_SMI
- 4: LOCAL_APIC_DELIVERY_MODE_NMI
- 5: LOCAL_APIC_DELIVERY_MODE_INIT
- 7: LOCAL_APIC_DELIVERY_MODE_EXTINT
- @param LevelTriggered TRUE specifies a level triggered interrupt.
- FALSE specifies an edge triggered interrupt.
- @param AssertionLevel Ignored if LevelTriggered is FALSE.
- TRUE specifies a level triggered interrupt that active
- when the interrupt line is asserted.
- FALSE specifies a level triggered interrupt that active
- when the interrupt line is deasserted.
- @return 64-bit data value used to send an MSI to the Local APIC.
- **/
- UINT64
- EFIAPI
- GetApicMsiValue (
- IN UINT8 Vector,
- IN UINTN DeliveryMode,
- IN BOOLEAN LevelTriggered,
- IN BOOLEAN AssertionLevel
- )
- {
- LOCAL_APIC_MSI_DATA MsiData;
- ASSERT (Vector >= 0x10 && Vector <= 0xFE);
- ASSERT (DeliveryMode < 8 && DeliveryMode != 6 && DeliveryMode != 3);
- MsiData.Uint64 = 0;
- MsiData.Bits.Vector = Vector;
- MsiData.Bits.DeliveryMode = (UINT32)DeliveryMode;
- if (LevelTriggered) {
- MsiData.Bits.TriggerMode = 1;
- if (AssertionLevel) {
- MsiData.Bits.Level = 1;
- }
- }
- return MsiData.Uint64;
- }
- /**
- Get Package ID/Core ID/Thread ID of a processor.
- The algorithm assumes the target system has symmetry across physical
- package boundaries with respect to the number of logical processors
- per package, number of cores per package.
- @param[in] InitialApicId Initial APIC ID of the target logical processor.
- @param[out] Package Returns the processor package ID.
- @param[out] Core Returns the processor core ID.
- @param[out] Thread Returns the processor thread ID.
- **/
- VOID
- EFIAPI
- GetProcessorLocationByApicId (
- IN UINT32 InitialApicId,
- OUT UINT32 *Package OPTIONAL,
- OUT UINT32 *Core OPTIONAL,
- OUT UINT32 *Thread OPTIONAL
- )
- {
- BOOLEAN TopologyLeafSupported;
- CPUID_VERSION_INFO_EBX VersionInfoEbx;
- CPUID_VERSION_INFO_EDX VersionInfoEdx;
- CPUID_CACHE_PARAMS_EAX CacheParamsEax;
- CPUID_EXTENDED_TOPOLOGY_EAX ExtendedTopologyEax;
- CPUID_EXTENDED_TOPOLOGY_EBX ExtendedTopologyEbx;
- CPUID_EXTENDED_TOPOLOGY_ECX ExtendedTopologyEcx;
- CPUID_AMD_EXTENDED_CPU_SIG_ECX AmdExtendedCpuSigEcx;
- CPUID_AMD_PROCESSOR_TOPOLOGY_EBX AmdProcessorTopologyEbx;
- CPUID_AMD_VIR_PHY_ADDRESS_SIZE_ECX AmdVirPhyAddressSizeEcx;
- UINT32 MaxStandardCpuIdIndex;
- UINT32 MaxExtendedCpuIdIndex;
- UINT32 SubIndex;
- UINTN LevelType;
- UINT32 MaxLogicProcessorsPerPackage;
- UINT32 MaxCoresPerPackage;
- UINTN ThreadBits;
- UINTN CoreBits;
- //
- // Check if the processor is capable of supporting more than one logical processor.
- //
- AsmCpuid (CPUID_VERSION_INFO, NULL, NULL, NULL, &VersionInfoEdx.Uint32);
- if (VersionInfoEdx.Bits.HTT == 0) {
- if (Thread != NULL) {
- *Thread = 0;
- }
- if (Core != NULL) {
- *Core = 0;
- }
- if (Package != NULL) {
- *Package = 0;
- }
- return;
- }
- //
- // Assume three-level mapping of APIC ID: Package|Core|Thread.
- //
- ThreadBits = 0;
- CoreBits = 0;
- //
- // Get max index of CPUID
- //
- AsmCpuid (CPUID_SIGNATURE, &MaxStandardCpuIdIndex, NULL, NULL, NULL);
- AsmCpuid (CPUID_EXTENDED_FUNCTION, &MaxExtendedCpuIdIndex, NULL, NULL, NULL);
- //
- // If the extended topology enumeration leaf is available, it
- // is the preferred mechanism for enumerating topology.
- //
- TopologyLeafSupported = FALSE;
- if (MaxStandardCpuIdIndex >= CPUID_EXTENDED_TOPOLOGY) {
- AsmCpuidEx (
- CPUID_EXTENDED_TOPOLOGY,
- 0,
- &ExtendedTopologyEax.Uint32,
- &ExtendedTopologyEbx.Uint32,
- &ExtendedTopologyEcx.Uint32,
- NULL
- );
- //
- // If CPUID.(EAX=0BH, ECX=0H):EBX returns zero and maximum input value for
- // basic CPUID information is greater than 0BH, then CPUID.0BH leaf is not
- // supported on that processor.
- //
- if (ExtendedTopologyEbx.Uint32 != 0) {
- TopologyLeafSupported = TRUE;
- //
- // Sub-leaf index 0 (ECX= 0 as input) provides enumeration parameters to extract
- // the SMT sub-field of x2APIC ID.
- //
- LevelType = ExtendedTopologyEcx.Bits.LevelType;
- ASSERT (LevelType == CPUID_EXTENDED_TOPOLOGY_LEVEL_TYPE_SMT);
- ThreadBits = ExtendedTopologyEax.Bits.ApicIdShift;
- //
- // Software must not assume any "level type" encoding
- // value to be related to any sub-leaf index, except sub-leaf 0.
- //
- SubIndex = 1;
- do {
- AsmCpuidEx (
- CPUID_EXTENDED_TOPOLOGY,
- SubIndex,
- &ExtendedTopologyEax.Uint32,
- NULL,
- &ExtendedTopologyEcx.Uint32,
- NULL
- );
- LevelType = ExtendedTopologyEcx.Bits.LevelType;
- if (LevelType == CPUID_EXTENDED_TOPOLOGY_LEVEL_TYPE_CORE) {
- CoreBits = ExtendedTopologyEax.Bits.ApicIdShift - ThreadBits;
- break;
- }
- SubIndex++;
- } while (LevelType != CPUID_EXTENDED_TOPOLOGY_LEVEL_TYPE_INVALID);
- }
- }
- if (!TopologyLeafSupported) {
- //
- // Get logical processor count
- //
- AsmCpuid (CPUID_VERSION_INFO, NULL, &VersionInfoEbx.Uint32, NULL, NULL);
- MaxLogicProcessorsPerPackage = VersionInfoEbx.Bits.MaximumAddressableIdsForLogicalProcessors;
- //
- // Assume single-core processor
- //
- MaxCoresPerPackage = 1;
- //
- // Check for topology extensions on AMD processor
- //
- if (StandardSignatureIsAuthenticAMD ()) {
- if (MaxExtendedCpuIdIndex >= CPUID_AMD_PROCESSOR_TOPOLOGY) {
- AsmCpuid (CPUID_EXTENDED_CPU_SIG, NULL, NULL, &AmdExtendedCpuSigEcx.Uint32, NULL);
- if (AmdExtendedCpuSigEcx.Bits.TopologyExtensions != 0) {
- //
- // Account for max possible thread count to decode ApicId
- //
- AsmCpuid (CPUID_VIR_PHY_ADDRESS_SIZE, NULL, NULL, &AmdVirPhyAddressSizeEcx.Uint32, NULL);
- MaxLogicProcessorsPerPackage = 1 << AmdVirPhyAddressSizeEcx.Bits.ApicIdCoreIdSize;
- //
- // Get cores per processor package
- //
- AsmCpuid (CPUID_AMD_PROCESSOR_TOPOLOGY, NULL, &AmdProcessorTopologyEbx.Uint32, NULL, NULL);
- MaxCoresPerPackage = MaxLogicProcessorsPerPackage / (AmdProcessorTopologyEbx.Bits.ThreadsPerCore + 1);
- }
- }
- } else {
- //
- // Extract core count based on CACHE information
- //
- if (MaxStandardCpuIdIndex >= CPUID_CACHE_PARAMS) {
- AsmCpuidEx (CPUID_CACHE_PARAMS, 0, &CacheParamsEax.Uint32, NULL, NULL, NULL);
- if (CacheParamsEax.Uint32 != 0) {
- MaxCoresPerPackage = CacheParamsEax.Bits.MaximumAddressableIdsForLogicalProcessors + 1;
- }
- }
- }
- ThreadBits = (UINTN)(HighBitSet32 (MaxLogicProcessorsPerPackage / MaxCoresPerPackage - 1) + 1);
- CoreBits = (UINTN)(HighBitSet32 (MaxCoresPerPackage - 1) + 1);
- }
- if (Thread != NULL) {
- *Thread = InitialApicId & ((1 << ThreadBits) - 1);
- }
- if (Core != NULL) {
- *Core = (InitialApicId >> ThreadBits) & ((1 << CoreBits) - 1);
- }
- if (Package != NULL) {
- *Package = (InitialApicId >> (ThreadBits + CoreBits));
- }
- }
- /**
- Get Package ID/Die ID/Tile ID/Module ID/Core ID/Thread ID of a processor.
- The algorithm assumes the target system has symmetry across physical
- package boundaries with respect to the number of threads per core, number of
- cores per module, number of modules per tile, number of tiles per die, number
- of dies per package.
- @param[in] InitialApicId Initial APIC ID of the target logical processor.
- @param[out] Package Returns the processor package ID.
- @param[out] Die Returns the processor die ID.
- @param[out] Tile Returns the processor tile ID.
- @param[out] Module Returns the processor module ID.
- @param[out] Core Returns the processor core ID.
- @param[out] Thread Returns the processor thread ID.
- **/
- VOID
- EFIAPI
- GetProcessorLocation2ByApicId (
- IN UINT32 InitialApicId,
- OUT UINT32 *Package OPTIONAL,
- OUT UINT32 *Die OPTIONAL,
- OUT UINT32 *Tile OPTIONAL,
- OUT UINT32 *Module OPTIONAL,
- OUT UINT32 *Core OPTIONAL,
- OUT UINT32 *Thread OPTIONAL
- )
- {
- CPUID_EXTENDED_TOPOLOGY_EAX ExtendedTopologyEax;
- CPUID_EXTENDED_TOPOLOGY_ECX ExtendedTopologyEcx;
- UINT32 MaxStandardCpuIdIndex;
- UINT32 Index;
- UINTN LevelType;
- UINT32 Bits[CPUID_V2_EXTENDED_TOPOLOGY_LEVEL_TYPE_DIE + 2];
- UINT32 *Location[CPUID_V2_EXTENDED_TOPOLOGY_LEVEL_TYPE_DIE + 2];
- for (LevelType = 0; LevelType < ARRAY_SIZE (Bits); LevelType++) {
- Bits[LevelType] = 0;
- }
- //
- // Get max index of CPUID
- //
- AsmCpuid (CPUID_SIGNATURE, &MaxStandardCpuIdIndex, NULL, NULL, NULL);
- if (MaxStandardCpuIdIndex < CPUID_V2_EXTENDED_TOPOLOGY) {
- if (Die != NULL) {
- *Die = 0;
- }
- if (Tile != NULL) {
- *Tile = 0;
- }
- if (Module != NULL) {
- *Module = 0;
- }
- GetProcessorLocationByApicId (InitialApicId, Package, Core, Thread);
- return;
- }
- //
- // If the V2 extended topology enumeration leaf is available, it
- // is the preferred mechanism for enumerating topology.
- //
- for (Index = 0; ; Index++) {
- AsmCpuidEx (
- CPUID_V2_EXTENDED_TOPOLOGY,
- Index,
- &ExtendedTopologyEax.Uint32,
- NULL,
- &ExtendedTopologyEcx.Uint32,
- NULL
- );
- LevelType = ExtendedTopologyEcx.Bits.LevelType;
- //
- // first level reported should be SMT.
- //
- ASSERT ((Index != 0) || (LevelType == CPUID_EXTENDED_TOPOLOGY_LEVEL_TYPE_SMT));
- if (LevelType == CPUID_EXTENDED_TOPOLOGY_LEVEL_TYPE_INVALID) {
- break;
- }
- ASSERT (LevelType < ARRAY_SIZE (Bits));
- Bits[LevelType] = ExtendedTopologyEax.Bits.ApicIdShift;
- }
- for (LevelType = CPUID_EXTENDED_TOPOLOGY_LEVEL_TYPE_CORE; LevelType < ARRAY_SIZE (Bits); LevelType++) {
- //
- // If there are more levels between level-1 (low-level) and level-2 (high-level), the unknown levels will be ignored
- // and treated as an extension of the last known level (i.e., level-1 in this case).
- //
- if (Bits[LevelType] == 0) {
- Bits[LevelType] = Bits[LevelType - 1];
- }
- }
- Location[CPUID_V2_EXTENDED_TOPOLOGY_LEVEL_TYPE_DIE + 1] = Package;
- Location[CPUID_V2_EXTENDED_TOPOLOGY_LEVEL_TYPE_DIE] = Die;
- Location[CPUID_V2_EXTENDED_TOPOLOGY_LEVEL_TYPE_TILE] = Tile;
- Location[CPUID_V2_EXTENDED_TOPOLOGY_LEVEL_TYPE_MODULE] = Module;
- Location[CPUID_EXTENDED_TOPOLOGY_LEVEL_TYPE_CORE] = Core;
- Location[CPUID_EXTENDED_TOPOLOGY_LEVEL_TYPE_SMT] = Thread;
- Bits[CPUID_V2_EXTENDED_TOPOLOGY_LEVEL_TYPE_DIE + 1] = 32;
- for ( LevelType = CPUID_EXTENDED_TOPOLOGY_LEVEL_TYPE_SMT
- ; LevelType <= CPUID_V2_EXTENDED_TOPOLOGY_LEVEL_TYPE_DIE + 1
- ; LevelType++
- )
- {
- if (Location[LevelType] != NULL) {
- //
- // Bits[i] holds the number of bits to shift right on x2APIC ID to get a unique
- // topology ID of the next level type.
- //
- *Location[LevelType] = InitialApicId >> Bits[LevelType - 1];
- //
- // Bits[i] - Bits[i-1] holds the number of bits for the next ONE level type.
- //
- *Location[LevelType] &= (1 << (Bits[LevelType] - Bits[LevelType - 1])) - 1;
- }
- }
- }
|