1bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun/** @file
2bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun  Local APIC Library.
3bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun
4bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun  This local APIC library instance supports x2APIC capable processors
5bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun  which have xAPIC and x2APIC modes.
6bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun
7a742e1865de889d73372b984e5e53d5d3afa29c4Jeff Fan  Copyright (c) 2010 - 2016, Intel Corporation. All rights reserved.<BR>
8bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun  This program and the accompanying materials
9bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun  are licensed and made available under the terms and conditions of the BSD License
10bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun  which accompanies this distribution.  The full text of the license may be found at
11bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun  http://opensource.org/licenses/bsd-license.php
12bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun
13bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
14bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
15bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun
16bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun**/
17bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun
1828a7ddf0311f8557360b4f8d042e558b938f6e8cMichael Kinney#include <Register/Cpuid.h>
19a742e1865de889d73372b984e5e53d5d3afa29c4Jeff Fan#include <Register/Msr.h>
20bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun#include <Register/LocalApic.h>
21bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun
22bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun#include <Library/BaseLib.h>
23bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun#include <Library/DebugLib.h>
24bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun#include <Library/LocalApicLib.h>
25bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun#include <Library/IoLib.h>
26bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun#include <Library/TimerLib.h>
27e9cd66d0859f63ec6aab2b1ac863fe72b65fe474Michael Kinney#include <Library/PcdLib.h>
28bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun
29bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun//
30bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun// Library internal functions
31bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun//
32bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun
33bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun/**
34e9cd66d0859f63ec6aab2b1ac863fe72b65fe474Michael Kinney  Determine if the CPU supports the Local APIC Base Address MSR.
35e9cd66d0859f63ec6aab2b1ac863fe72b65fe474Michael Kinney
36e9cd66d0859f63ec6aab2b1ac863fe72b65fe474Michael Kinney  @retval TRUE  The CPU supports the Local APIC Base Address MSR.
37e9cd66d0859f63ec6aab2b1ac863fe72b65fe474Michael Kinney  @retval FALSE The CPU does not support the Local APIC Base Address MSR.
38e9cd66d0859f63ec6aab2b1ac863fe72b65fe474Michael Kinney
39e9cd66d0859f63ec6aab2b1ac863fe72b65fe474Michael Kinney**/
40e9cd66d0859f63ec6aab2b1ac863fe72b65fe474Michael KinneyBOOLEAN
41e9cd66d0859f63ec6aab2b1ac863fe72b65fe474Michael KinneyLocalApicBaseAddressMsrSupported (
42e9cd66d0859f63ec6aab2b1ac863fe72b65fe474Michael Kinney  VOID
43e9cd66d0859f63ec6aab2b1ac863fe72b65fe474Michael Kinney  )
44e9cd66d0859f63ec6aab2b1ac863fe72b65fe474Michael Kinney{
45e9cd66d0859f63ec6aab2b1ac863fe72b65fe474Michael Kinney  UINT32  RegEax;
46e9cd66d0859f63ec6aab2b1ac863fe72b65fe474Michael Kinney  UINTN   FamilyId;
47e9cd66d0859f63ec6aab2b1ac863fe72b65fe474Michael Kinney
48e9cd66d0859f63ec6aab2b1ac863fe72b65fe474Michael Kinney  AsmCpuid (1, &RegEax, NULL, NULL, NULL);
49e9cd66d0859f63ec6aab2b1ac863fe72b65fe474Michael Kinney  FamilyId = BitFieldRead32 (RegEax, 8, 11);
50e9cd66d0859f63ec6aab2b1ac863fe72b65fe474Michael Kinney  if (FamilyId == 0x04 || FamilyId == 0x05) {
51e9cd66d0859f63ec6aab2b1ac863fe72b65fe474Michael Kinney    //
52e9cd66d0859f63ec6aab2b1ac863fe72b65fe474Michael Kinney    // CPUs with a FamilyId of 0x04 or 0x05 do not support the
53e9cd66d0859f63ec6aab2b1ac863fe72b65fe474Michael Kinney    // Local APIC Base Address MSR
54e9cd66d0859f63ec6aab2b1ac863fe72b65fe474Michael Kinney    //
55e9cd66d0859f63ec6aab2b1ac863fe72b65fe474Michael Kinney    return FALSE;
56e9cd66d0859f63ec6aab2b1ac863fe72b65fe474Michael Kinney  }
57e9cd66d0859f63ec6aab2b1ac863fe72b65fe474Michael Kinney  return TRUE;
58e9cd66d0859f63ec6aab2b1ac863fe72b65fe474Michael Kinney}
59e9cd66d0859f63ec6aab2b1ac863fe72b65fe474Michael Kinney
60e9cd66d0859f63ec6aab2b1ac863fe72b65fe474Michael Kinney/**
61a66e0c7da759ce41b2615529f9d69627e23e5b08vanjeff  Retrieve the base address of local APIC.
62a66e0c7da759ce41b2615529f9d69627e23e5b08vanjeff
63a66e0c7da759ce41b2615529f9d69627e23e5b08vanjeff  @return The base address of local APIC.
64a66e0c7da759ce41b2615529f9d69627e23e5b08vanjeff
65a66e0c7da759ce41b2615529f9d69627e23e5b08vanjeff**/
66a66e0c7da759ce41b2615529f9d69627e23e5b08vanjeffUINTN
67a66e0c7da759ce41b2615529f9d69627e23e5b08vanjeffEFIAPI
68a66e0c7da759ce41b2615529f9d69627e23e5b08vanjeffGetLocalApicBaseAddress (
69a66e0c7da759ce41b2615529f9d69627e23e5b08vanjeff  VOID
70a66e0c7da759ce41b2615529f9d69627e23e5b08vanjeff  )
71a66e0c7da759ce41b2615529f9d69627e23e5b08vanjeff{
72a742e1865de889d73372b984e5e53d5d3afa29c4Jeff Fan  MSR_IA32_APIC_BASE_REGISTER  ApicBaseMsr;
73e9cd66d0859f63ec6aab2b1ac863fe72b65fe474Michael Kinney
74e9cd66d0859f63ec6aab2b1ac863fe72b65fe474Michael Kinney  if (!LocalApicBaseAddressMsrSupported ()) {
75e9cd66d0859f63ec6aab2b1ac863fe72b65fe474Michael Kinney    //
76e9cd66d0859f63ec6aab2b1ac863fe72b65fe474Michael Kinney    // If CPU does not support Local APIC Base Address MSR, then retrieve
77e9cd66d0859f63ec6aab2b1ac863fe72b65fe474Michael Kinney    // Local APIC Base Address from PCD
78e9cd66d0859f63ec6aab2b1ac863fe72b65fe474Michael Kinney    //
79e9cd66d0859f63ec6aab2b1ac863fe72b65fe474Michael Kinney    return PcdGet32 (PcdCpuLocalApicBaseAddress);
80e9cd66d0859f63ec6aab2b1ac863fe72b65fe474Michael Kinney  }
81e9cd66d0859f63ec6aab2b1ac863fe72b65fe474Michael Kinney
82a742e1865de889d73372b984e5e53d5d3afa29c4Jeff Fan  ApicBaseMsr.Uint64 = AsmReadMsr64 (MSR_IA32_APIC_BASE);
83a66e0c7da759ce41b2615529f9d69627e23e5b08vanjeff
84a742e1865de889d73372b984e5e53d5d3afa29c4Jeff Fan  return (UINTN)(LShiftU64 ((UINT64) ApicBaseMsr.Bits.ApicBaseHi, 32)) +
85a742e1865de889d73372b984e5e53d5d3afa29c4Jeff Fan           (((UINTN)ApicBaseMsr.Bits.ApicBase) << 12);
86a66e0c7da759ce41b2615529f9d69627e23e5b08vanjeff}
87a66e0c7da759ce41b2615529f9d69627e23e5b08vanjeff
88a66e0c7da759ce41b2615529f9d69627e23e5b08vanjeff/**
89a66e0c7da759ce41b2615529f9d69627e23e5b08vanjeff  Set the base address of local APIC.
90a66e0c7da759ce41b2615529f9d69627e23e5b08vanjeff
91a66e0c7da759ce41b2615529f9d69627e23e5b08vanjeff  If BaseAddress is not aligned on a 4KB boundary, then ASSERT().
92a66e0c7da759ce41b2615529f9d69627e23e5b08vanjeff
93a66e0c7da759ce41b2615529f9d69627e23e5b08vanjeff  @param[in] BaseAddress   Local APIC base address to be set.
94a66e0c7da759ce41b2615529f9d69627e23e5b08vanjeff
95a66e0c7da759ce41b2615529f9d69627e23e5b08vanjeff**/
96a66e0c7da759ce41b2615529f9d69627e23e5b08vanjeffVOID
97a66e0c7da759ce41b2615529f9d69627e23e5b08vanjeffEFIAPI
98a66e0c7da759ce41b2615529f9d69627e23e5b08vanjeffSetLocalApicBaseAddress (
99a66e0c7da759ce41b2615529f9d69627e23e5b08vanjeff  IN UINTN                BaseAddress
100a66e0c7da759ce41b2615529f9d69627e23e5b08vanjeff  )
101a66e0c7da759ce41b2615529f9d69627e23e5b08vanjeff{
102a742e1865de889d73372b984e5e53d5d3afa29c4Jeff Fan  MSR_IA32_APIC_BASE_REGISTER  ApicBaseMsr;
103a66e0c7da759ce41b2615529f9d69627e23e5b08vanjeff
104a66e0c7da759ce41b2615529f9d69627e23e5b08vanjeff  ASSERT ((BaseAddress & (SIZE_4KB - 1)) == 0);
105a66e0c7da759ce41b2615529f9d69627e23e5b08vanjeff
106e9cd66d0859f63ec6aab2b1ac863fe72b65fe474Michael Kinney  if (!LocalApicBaseAddressMsrSupported ()) {
107e9cd66d0859f63ec6aab2b1ac863fe72b65fe474Michael Kinney    //
108e9cd66d0859f63ec6aab2b1ac863fe72b65fe474Michael Kinney    // Ignore set request of the CPU does not support APIC Base Address MSR
109e9cd66d0859f63ec6aab2b1ac863fe72b65fe474Michael Kinney    //
110e9cd66d0859f63ec6aab2b1ac863fe72b65fe474Michael Kinney    return;
111e9cd66d0859f63ec6aab2b1ac863fe72b65fe474Michael Kinney  }
112e9cd66d0859f63ec6aab2b1ac863fe72b65fe474Michael Kinney
113a742e1865de889d73372b984e5e53d5d3afa29c4Jeff Fan  ApicBaseMsr.Uint64 = AsmReadMsr64 (MSR_IA32_APIC_BASE);
114a66e0c7da759ce41b2615529f9d69627e23e5b08vanjeff
115a742e1865de889d73372b984e5e53d5d3afa29c4Jeff Fan  ApicBaseMsr.Bits.ApicBase   = (UINT32) (BaseAddress >> 12);
116a742e1865de889d73372b984e5e53d5d3afa29c4Jeff Fan  ApicBaseMsr.Bits.ApicBaseHi = (UINT32) (RShiftU64((UINT64) BaseAddress, 32));
117a66e0c7da759ce41b2615529f9d69627e23e5b08vanjeff
118a742e1865de889d73372b984e5e53d5d3afa29c4Jeff Fan  AsmWriteMsr64 (MSR_IA32_APIC_BASE, ApicBaseMsr.Uint64);
119a66e0c7da759ce41b2615529f9d69627e23e5b08vanjeff}
120a66e0c7da759ce41b2615529f9d69627e23e5b08vanjeff
121a66e0c7da759ce41b2615529f9d69627e23e5b08vanjeff/**
122bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun  Read from a local APIC register.
123bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun
124bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun  This function reads from a local APIC register either in xAPIC or x2APIC mode.
125bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun  It is required that in xAPIC mode wider registers (64-bit or 256-bit) must be
126bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun  accessed using multiple 32-bit loads or stores, so this function only performs
127bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun  32-bit read.
128bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun
129bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun  @param  MmioOffset  The MMIO offset of the local APIC register in xAPIC mode.
130bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun                      It must be 16-byte aligned.
131bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun
132bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun  @return 32-bit      Value read from the register.
133bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun**/
134bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsunUINT32
135bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsunEFIAPI
136bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsunReadLocalApicReg (
137bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun  IN UINTN  MmioOffset
138bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun  )
139bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun{
140bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun  UINT32 MsrIndex;
141bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun
142bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun  ASSERT ((MmioOffset & 0xf) == 0);
143bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun
144bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun  if (GetApicMode () == LOCAL_APIC_MODE_XAPIC) {
145a66e0c7da759ce41b2615529f9d69627e23e5b08vanjeff    return MmioRead32 (GetLocalApicBaseAddress() + MmioOffset);
146bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun  } else {
147bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun    //
148bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun    // DFR is not supported in x2APIC mode.
149bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun    //
150bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun    ASSERT (MmioOffset != XAPIC_ICR_DFR_OFFSET);
151bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun    //
152bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun    // Note that in x2APIC mode, ICR is a 64-bit MSR that needs special treatment. It
153bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun    // is not supported in this function for simplicity.
154bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun    //
155bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun    ASSERT (MmioOffset != XAPIC_ICR_HIGH_OFFSET);
156bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun
157bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun    MsrIndex = (UINT32)(MmioOffset >> 4) + X2APIC_MSR_BASE_ADDRESS;
158bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun    return AsmReadMsr32 (MsrIndex);
159bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun  }
160bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun}
161bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun
162bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun/**
163bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun  Write to a local APIC register.
164bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun
165bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun  This function writes to a local APIC register either in xAPIC or x2APIC mode.
166bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun  It is required that in xAPIC mode wider registers (64-bit or 256-bit) must be
167bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun  accessed using multiple 32-bit loads or stores, so this function only performs
168bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun  32-bit write.
169bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun
170bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun  if the register index is invalid or unsupported in current APIC mode, then ASSERT.
171bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun
172bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun  @param  MmioOffset  The MMIO offset of the local APIC register in xAPIC mode.
173bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun                      It must be 16-byte aligned.
174bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun  @param  Value       Value to be written to the register.
175bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun**/
176bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsunVOID
177bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsunEFIAPI
178bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsunWriteLocalApicReg (
179bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun  IN UINTN  MmioOffset,
180bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun  IN UINT32 Value
181bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun  )
182bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun{
183bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun  UINT32 MsrIndex;
184bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun
185bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun  ASSERT ((MmioOffset & 0xf) == 0);
186bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun
187bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun  if (GetApicMode () == LOCAL_APIC_MODE_XAPIC) {
188a66e0c7da759ce41b2615529f9d69627e23e5b08vanjeff    MmioWrite32 (GetLocalApicBaseAddress() + MmioOffset, Value);
189bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun  } else {
190bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun    //
191bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun    // DFR is not supported in x2APIC mode.
192bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun    //
193bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun    ASSERT (MmioOffset != XAPIC_ICR_DFR_OFFSET);
194bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun    //
195bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun    // Note that in x2APIC mode, ICR is a 64-bit MSR that needs special treatment. It
196bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun    // is not supported in this function for simplicity.
197bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun    //
198bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun    ASSERT (MmioOffset != XAPIC_ICR_HIGH_OFFSET);
199bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun    ASSERT (MmioOffset != XAPIC_ICR_LOW_OFFSET);
200bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun
201bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun    MsrIndex =  (UINT32)(MmioOffset >> 4) + X2APIC_MSR_BASE_ADDRESS;
202bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun    //
203bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun    // The serializing semantics of WRMSR are relaxed when writing to the APIC registers.
204bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun    // Use memory fence here to force the serializing semantics to be consisent with xAPIC mode.
205bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun    //
206bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun    MemoryFence ();
207bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun    AsmWriteMsr32 (MsrIndex, Value);
208bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun  }
209bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun}
210bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun
211bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun/**
212bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun  Send an IPI by writing to ICR.
213bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun
214bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun  This function returns after the IPI has been accepted by the target processor.
215bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun
216bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun  @param  IcrLow 32-bit value to be written to the low half of ICR.
217bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun  @param  ApicId APIC ID of the target processor if this IPI is targeted for a specific processor.
218bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun**/
219bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsunVOID
220bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsunSendIpi (
221bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun  IN UINT32          IcrLow,
222bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun  IN UINT32          ApicId
223bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun  )
224bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun{
225bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun  UINT64             MsrValue;
226bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun  LOCAL_APIC_ICR_LOW IcrLowReg;
227a66e0c7da759ce41b2615529f9d69627e23e5b08vanjeff  UINTN              LocalApciBaseAddress;
2289c71e1e05666d274a760e45866f65fafc2ccfbc6Jeff Fan  UINT32             IcrHigh;
2299c71e1e05666d274a760e45866f65fafc2ccfbc6Jeff Fan  BOOLEAN            InterruptState;
230bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun
2319c71e1e05666d274a760e45866f65fafc2ccfbc6Jeff Fan  //
2329c71e1e05666d274a760e45866f65fafc2ccfbc6Jeff Fan  // Legacy APIC or X2APIC?
2339c71e1e05666d274a760e45866f65fafc2ccfbc6Jeff Fan  //
234bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun  if (GetApicMode () == LOCAL_APIC_MODE_XAPIC) {
235bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun    ASSERT (ApicId <= 0xff);
236bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun
2379c71e1e05666d274a760e45866f65fafc2ccfbc6Jeff Fan    InterruptState = SaveAndDisableInterrupts ();
2389c71e1e05666d274a760e45866f65fafc2ccfbc6Jeff Fan
239bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun    //
2409c71e1e05666d274a760e45866f65fafc2ccfbc6Jeff Fan    // Get base address of this LAPIC
241bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun    //
242a66e0c7da759ce41b2615529f9d69627e23e5b08vanjeff    LocalApciBaseAddress = GetLocalApicBaseAddress();
2439c71e1e05666d274a760e45866f65fafc2ccfbc6Jeff Fan
2449c71e1e05666d274a760e45866f65fafc2ccfbc6Jeff Fan    //
2459c71e1e05666d274a760e45866f65fafc2ccfbc6Jeff Fan    // Save existing contents of ICR high 32 bits
2469c71e1e05666d274a760e45866f65fafc2ccfbc6Jeff Fan    //
2479c71e1e05666d274a760e45866f65fafc2ccfbc6Jeff Fan    IcrHigh = MmioRead32 (LocalApciBaseAddress + XAPIC_ICR_HIGH_OFFSET);
2489c71e1e05666d274a760e45866f65fafc2ccfbc6Jeff Fan
2499c71e1e05666d274a760e45866f65fafc2ccfbc6Jeff Fan    //
2509c71e1e05666d274a760e45866f65fafc2ccfbc6Jeff Fan    // Wait for DeliveryStatus clear in case a previous IPI
2519c71e1e05666d274a760e45866f65fafc2ccfbc6Jeff Fan    //  is still being sent
2529c71e1e05666d274a760e45866f65fafc2ccfbc6Jeff Fan    //
2539c71e1e05666d274a760e45866f65fafc2ccfbc6Jeff Fan    do {
2549c71e1e05666d274a760e45866f65fafc2ccfbc6Jeff Fan      IcrLowReg.Uint32 = MmioRead32 (LocalApciBaseAddress + XAPIC_ICR_LOW_OFFSET);
2559c71e1e05666d274a760e45866f65fafc2ccfbc6Jeff Fan    } while (IcrLowReg.Bits.DeliveryStatus != 0);
2569c71e1e05666d274a760e45866f65fafc2ccfbc6Jeff Fan
2579c71e1e05666d274a760e45866f65fafc2ccfbc6Jeff Fan    //
2589c71e1e05666d274a760e45866f65fafc2ccfbc6Jeff Fan    // For xAPIC, the act of writing to the low doubleword of the ICR causes the IPI to be sent.
2599c71e1e05666d274a760e45866f65fafc2ccfbc6Jeff Fan    //
260a66e0c7da759ce41b2615529f9d69627e23e5b08vanjeff    MmioWrite32 (LocalApciBaseAddress + XAPIC_ICR_HIGH_OFFSET, ApicId << 24);
261a66e0c7da759ce41b2615529f9d69627e23e5b08vanjeff    MmioWrite32 (LocalApciBaseAddress + XAPIC_ICR_LOW_OFFSET, IcrLow);
2629c71e1e05666d274a760e45866f65fafc2ccfbc6Jeff Fan
2639c71e1e05666d274a760e45866f65fafc2ccfbc6Jeff Fan    //
2649c71e1e05666d274a760e45866f65fafc2ccfbc6Jeff Fan    // Wait for DeliveryStatus clear again
2659c71e1e05666d274a760e45866f65fafc2ccfbc6Jeff Fan    //
266bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun    do {
267a66e0c7da759ce41b2615529f9d69627e23e5b08vanjeff      IcrLowReg.Uint32 = MmioRead32 (LocalApciBaseAddress + XAPIC_ICR_LOW_OFFSET);
268bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun    } while (IcrLowReg.Bits.DeliveryStatus != 0);
2699c71e1e05666d274a760e45866f65fafc2ccfbc6Jeff Fan
2709c71e1e05666d274a760e45866f65fafc2ccfbc6Jeff Fan    //
2719c71e1e05666d274a760e45866f65fafc2ccfbc6Jeff Fan    // And restore old contents of ICR high
2729c71e1e05666d274a760e45866f65fafc2ccfbc6Jeff Fan    //
2739c71e1e05666d274a760e45866f65fafc2ccfbc6Jeff Fan    MmioWrite32 (LocalApciBaseAddress + XAPIC_ICR_HIGH_OFFSET, IcrHigh);
2749c71e1e05666d274a760e45866f65fafc2ccfbc6Jeff Fan
2759c71e1e05666d274a760e45866f65fafc2ccfbc6Jeff Fan    SetInterruptState (InterruptState);
2769c71e1e05666d274a760e45866f65fafc2ccfbc6Jeff Fan
277bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun  } else {
278bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun    //
279bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun    // For x2APIC, A single MSR write to the Interrupt Command Register is required for dispatching an
280bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun    // interrupt in x2APIC mode.
281bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun    //
28223394428fdfe351ae9382576cdeee2834a2c637drsun    MsrValue = LShiftU64 ((UINT64) ApicId, 32) | IcrLow;
283bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun    AsmWriteMsr64 (X2APIC_MSR_ICR_ADDRESS, MsrValue);
284bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun  }
285bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun}
286bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun
287bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun//
288bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun// Library API implementation functions
289bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun//
290bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun
291bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun/**
292bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun  Get the current local APIC mode.
293bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun
294bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun  If local APIC is disabled, then ASSERT.
295bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun
296bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun  @retval LOCAL_APIC_MODE_XAPIC  current APIC mode is xAPIC.
297bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun  @retval LOCAL_APIC_MODE_X2APIC current APIC mode is x2APIC.
298bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun**/
299bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsunUINTN
300bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsunEFIAPI
301bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsunGetApicMode (
302bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun  VOID
303bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun  )
304bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun{
305a742e1865de889d73372b984e5e53d5d3afa29c4Jeff Fan  MSR_IA32_APIC_BASE_REGISTER  ApicBaseMsr;
306e9cd66d0859f63ec6aab2b1ac863fe72b65fe474Michael Kinney
307e9cd66d0859f63ec6aab2b1ac863fe72b65fe474Michael Kinney  if (!LocalApicBaseAddressMsrSupported ()) {
308e9cd66d0859f63ec6aab2b1ac863fe72b65fe474Michael Kinney    //
309e9cd66d0859f63ec6aab2b1ac863fe72b65fe474Michael Kinney    // If CPU does not support APIC Base Address MSR, then return XAPIC mode
310e9cd66d0859f63ec6aab2b1ac863fe72b65fe474Michael Kinney    //
311e9cd66d0859f63ec6aab2b1ac863fe72b65fe474Michael Kinney    return LOCAL_APIC_MODE_XAPIC;
312e9cd66d0859f63ec6aab2b1ac863fe72b65fe474Michael Kinney  }
313bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun
314a742e1865de889d73372b984e5e53d5d3afa29c4Jeff Fan  ApicBaseMsr.Uint64 = AsmReadMsr64 (MSR_IA32_APIC_BASE);
315bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun  //
316bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun  // Local APIC should have been enabled
317bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun  //
318a742e1865de889d73372b984e5e53d5d3afa29c4Jeff Fan  ASSERT (ApicBaseMsr.Bits.EN != 0);
319a742e1865de889d73372b984e5e53d5d3afa29c4Jeff Fan  if (ApicBaseMsr.Bits.EXTD != 0) {
320bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun    return LOCAL_APIC_MODE_X2APIC;
321bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun  } else {
322bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun    return LOCAL_APIC_MODE_XAPIC;
323bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun  }
324bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun}
325bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun
326bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun/**
327bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun  Set the current local APIC mode.
328bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun
329bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun  If the specified local APIC mode is not valid, then ASSERT.
330bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun  If the specified local APIC mode can't be set as current, then ASSERT.
331bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun
332bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun  @param ApicMode APIC mode to be set.
3339c71e1e05666d274a760e45866f65fafc2ccfbc6Jeff Fan
3349c71e1e05666d274a760e45866f65fafc2ccfbc6Jeff Fan  @note  This API must not be called from an interrupt handler or SMI handler.
3359c71e1e05666d274a760e45866f65fafc2ccfbc6Jeff Fan         It may result in unpredictable behavior.
336bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun**/
337bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsunVOID
338bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsunEFIAPI
339bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsunSetApicMode (
340bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun  IN UINTN  ApicMode
341bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun  )
342bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun{
343a742e1865de889d73372b984e5e53d5d3afa29c4Jeff Fan  UINTN                        CurrentMode;
344a742e1865de889d73372b984e5e53d5d3afa29c4Jeff Fan  MSR_IA32_APIC_BASE_REGISTER  ApicBaseMsr;
345e9cd66d0859f63ec6aab2b1ac863fe72b65fe474Michael Kinney
346e9cd66d0859f63ec6aab2b1ac863fe72b65fe474Michael Kinney  if (!LocalApicBaseAddressMsrSupported ()) {
347e9cd66d0859f63ec6aab2b1ac863fe72b65fe474Michael Kinney    //
348e9cd66d0859f63ec6aab2b1ac863fe72b65fe474Michael Kinney    // Ignore set request if the CPU does not support APIC Base Address MSR
349e9cd66d0859f63ec6aab2b1ac863fe72b65fe474Michael Kinney    //
350e9cd66d0859f63ec6aab2b1ac863fe72b65fe474Michael Kinney    return;
351e9cd66d0859f63ec6aab2b1ac863fe72b65fe474Michael Kinney  }
352bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun
353bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun  CurrentMode = GetApicMode ();
354bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun  if (CurrentMode == LOCAL_APIC_MODE_XAPIC) {
355bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun    switch (ApicMode) {
356bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun      case LOCAL_APIC_MODE_XAPIC:
357bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun        break;
358bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun      case LOCAL_APIC_MODE_X2APIC:
359a742e1865de889d73372b984e5e53d5d3afa29c4Jeff Fan        ApicBaseMsr.Uint64 = AsmReadMsr64 (MSR_IA32_APIC_BASE);
360a742e1865de889d73372b984e5e53d5d3afa29c4Jeff Fan        ApicBaseMsr.Bits.EXTD = 1;
361a742e1865de889d73372b984e5e53d5d3afa29c4Jeff Fan        AsmWriteMsr64 (MSR_IA32_APIC_BASE, ApicBaseMsr.Uint64);
362bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun        break;
363bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun      default:
364bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun        ASSERT (FALSE);
365bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun    }
366bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun  } else {
367bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun    switch (ApicMode) {
368bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun      case LOCAL_APIC_MODE_XAPIC:
369bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun        //
370bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun        //  Transition from x2APIC mode to xAPIC mode is a two-step process:
371bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun        //    x2APIC -> Local APIC disabled -> xAPIC
372bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun        //
373a742e1865de889d73372b984e5e53d5d3afa29c4Jeff Fan        ApicBaseMsr.Uint64 = AsmReadMsr64 (MSR_IA32_APIC_BASE);
374a742e1865de889d73372b984e5e53d5d3afa29c4Jeff Fan        ApicBaseMsr.Bits.EXTD = 0;
375a742e1865de889d73372b984e5e53d5d3afa29c4Jeff Fan        ApicBaseMsr.Bits.EN = 0;
376a742e1865de889d73372b984e5e53d5d3afa29c4Jeff Fan        AsmWriteMsr64 (MSR_IA32_APIC_BASE, ApicBaseMsr.Uint64);
377a742e1865de889d73372b984e5e53d5d3afa29c4Jeff Fan        ApicBaseMsr.Bits.EN = 1;
378a742e1865de889d73372b984e5e53d5d3afa29c4Jeff Fan        AsmWriteMsr64 (MSR_IA32_APIC_BASE, ApicBaseMsr.Uint64);
379bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun        break;
380bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun      case LOCAL_APIC_MODE_X2APIC:
381bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun        break;
382bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun      default:
383bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun        ASSERT (FALSE);
384bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun    }
385bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun  }
386bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun}
387bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun
388bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun/**
389bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun  Get the initial local APIC ID of the executing processor assigned by hardware upon power on or reset.
390bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun
3916e3e4d70d47a8beb7d7e1ac10be69cc2924b9e8dJeff Fan  In xAPIC mode, the initial local APIC ID may be different from current APIC ID.
392bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun  In x2APIC mode, the local APIC ID can't be changed and there is no concept of initial APIC ID. In this case,
393bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun  the 32-bit local APIC ID is returned as initial APIC ID.
394bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun
395bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun  @return  32-bit initial local APIC ID of the executing processor.
396bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun**/
397bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsunUINT32
398bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsunEFIAPI
399bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsunGetInitialApicId (
400bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun  VOID
401bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun  )
402bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun{
4036e3e4d70d47a8beb7d7e1ac10be69cc2924b9e8dJeff Fan  UINT32 ApicId;
4046e3e4d70d47a8beb7d7e1ac10be69cc2924b9e8dJeff Fan  UINT32 MaxCpuIdIndex;
405bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun  UINT32 RegEbx;
406bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun
407bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun  if (GetApicMode () == LOCAL_APIC_MODE_XAPIC) {
4086e3e4d70d47a8beb7d7e1ac10be69cc2924b9e8dJeff Fan    //
4096e3e4d70d47a8beb7d7e1ac10be69cc2924b9e8dJeff Fan    // Get the max index of basic CPUID
4106e3e4d70d47a8beb7d7e1ac10be69cc2924b9e8dJeff Fan    //
4116e3e4d70d47a8beb7d7e1ac10be69cc2924b9e8dJeff Fan    AsmCpuid (CPUID_SIGNATURE, &MaxCpuIdIndex, NULL, NULL, NULL);
4126e3e4d70d47a8beb7d7e1ac10be69cc2924b9e8dJeff Fan    //
4136e3e4d70d47a8beb7d7e1ac10be69cc2924b9e8dJeff Fan    // If CPUID Leaf B is supported,
4144af3ae1463796ef7b2ecf2bfe8b390e72817212cLaszlo Ersek    // And CPUID.0BH:EBX[15:0] reports a non-zero value,
4156e3e4d70d47a8beb7d7e1ac10be69cc2924b9e8dJeff Fan    // Then the initial 32-bit APIC ID = CPUID.0BH:EDX
4166e3e4d70d47a8beb7d7e1ac10be69cc2924b9e8dJeff Fan    // Else the initial 8-bit APIC ID = CPUID.1:EBX[31:24]
4176e3e4d70d47a8beb7d7e1ac10be69cc2924b9e8dJeff Fan    //
4186e3e4d70d47a8beb7d7e1ac10be69cc2924b9e8dJeff Fan    if (MaxCpuIdIndex >= CPUID_EXTENDED_TOPOLOGY) {
4194af3ae1463796ef7b2ecf2bfe8b390e72817212cLaszlo Ersek      AsmCpuidEx (CPUID_EXTENDED_TOPOLOGY, 0, NULL, &RegEbx, NULL, &ApicId);
4204af3ae1463796ef7b2ecf2bfe8b390e72817212cLaszlo Ersek      if ((RegEbx & (BIT16 - 1)) != 0) {
4214af3ae1463796ef7b2ecf2bfe8b390e72817212cLaszlo Ersek        return ApicId;
4224af3ae1463796ef7b2ecf2bfe8b390e72817212cLaszlo Ersek      }
4236e3e4d70d47a8beb7d7e1ac10be69cc2924b9e8dJeff Fan    }
424bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun    AsmCpuid (CPUID_VERSION_INFO, NULL, &RegEbx, NULL, NULL);
425bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun    return RegEbx >> 24;
426bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun  } else {
427bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun    return GetApicId ();
428bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun  }
429bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun}
430bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun
431bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun/**
432bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun  Get the local APIC ID of the executing processor.
433bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun
434bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun  @return  32-bit local APIC ID of the executing processor.
435bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun**/
436bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsunUINT32
437bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsunEFIAPI
438bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsunGetApicId (
439bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun  VOID
440bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun  )
441bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun{
442bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun  UINT32 ApicId;
4436e3e4d70d47a8beb7d7e1ac10be69cc2924b9e8dJeff Fan  UINT32 InitApicId;
444bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun
445bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun  ApicId = ReadLocalApicReg (XAPIC_ID_OFFSET);
446bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun  if (GetApicMode () == LOCAL_APIC_MODE_XAPIC) {
4476e3e4d70d47a8beb7d7e1ac10be69cc2924b9e8dJeff Fan    ApicId = ((InitApicId = GetInitialApicId ()) < 0x100) ? (ApicId >> 24) : InitApicId;
448bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun  }
4496e3e4d70d47a8beb7d7e1ac10be69cc2924b9e8dJeff Fan
450bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun  return ApicId;
451bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun}
452bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun
453bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun/**
454ae40aef1fb4f5f34e5273b6fd5d4103bf6c7dd2drsun  Get the value of the local APIC version register.
455ae40aef1fb4f5f34e5273b6fd5d4103bf6c7dd2drsun
456ae40aef1fb4f5f34e5273b6fd5d4103bf6c7dd2drsun  @return  the value of the local APIC version register.
457ae40aef1fb4f5f34e5273b6fd5d4103bf6c7dd2drsun**/
458ae40aef1fb4f5f34e5273b6fd5d4103bf6c7dd2drsunUINT32
459ae40aef1fb4f5f34e5273b6fd5d4103bf6c7dd2drsunEFIAPI
460ae40aef1fb4f5f34e5273b6fd5d4103bf6c7dd2drsunGetApicVersion (
461ae40aef1fb4f5f34e5273b6fd5d4103bf6c7dd2drsun  VOID
462ae40aef1fb4f5f34e5273b6fd5d4103bf6c7dd2drsun  )
463ae40aef1fb4f5f34e5273b6fd5d4103bf6c7dd2drsun{
464ae40aef1fb4f5f34e5273b6fd5d4103bf6c7dd2drsun  return ReadLocalApicReg (XAPIC_VERSION_OFFSET);
465ae40aef1fb4f5f34e5273b6fd5d4103bf6c7dd2drsun}
466ae40aef1fb4f5f34e5273b6fd5d4103bf6c7dd2drsun
467ae40aef1fb4f5f34e5273b6fd5d4103bf6c7dd2drsun/**
468ae40aef1fb4f5f34e5273b6fd5d4103bf6c7dd2drsun  Send a Fixed IPI to a specified target processor.
469ae40aef1fb4f5f34e5273b6fd5d4103bf6c7dd2drsun
470ae40aef1fb4f5f34e5273b6fd5d4103bf6c7dd2drsun  This function returns after the IPI has been accepted by the target processor.
471ae40aef1fb4f5f34e5273b6fd5d4103bf6c7dd2drsun
472ae40aef1fb4f5f34e5273b6fd5d4103bf6c7dd2drsun  @param  ApicId   The local APIC ID of the target processor.
473ae40aef1fb4f5f34e5273b6fd5d4103bf6c7dd2drsun  @param  Vector   The vector number of the interrupt being sent.
474ae40aef1fb4f5f34e5273b6fd5d4103bf6c7dd2drsun**/
475ae40aef1fb4f5f34e5273b6fd5d4103bf6c7dd2drsunVOID
476ae40aef1fb4f5f34e5273b6fd5d4103bf6c7dd2drsunEFIAPI
477ae40aef1fb4f5f34e5273b6fd5d4103bf6c7dd2drsunSendFixedIpi (
478ae40aef1fb4f5f34e5273b6fd5d4103bf6c7dd2drsun  IN UINT32          ApicId,
479ae40aef1fb4f5f34e5273b6fd5d4103bf6c7dd2drsun  IN UINT8           Vector
480ae40aef1fb4f5f34e5273b6fd5d4103bf6c7dd2drsun  )
481ae40aef1fb4f5f34e5273b6fd5d4103bf6c7dd2drsun{
482ae40aef1fb4f5f34e5273b6fd5d4103bf6c7dd2drsun  LOCAL_APIC_ICR_LOW IcrLow;
483ae40aef1fb4f5f34e5273b6fd5d4103bf6c7dd2drsun
484ae40aef1fb4f5f34e5273b6fd5d4103bf6c7dd2drsun  IcrLow.Uint32 = 0;
485ae40aef1fb4f5f34e5273b6fd5d4103bf6c7dd2drsun  IcrLow.Bits.DeliveryMode = LOCAL_APIC_DELIVERY_MODE_FIXED;
486ae40aef1fb4f5f34e5273b6fd5d4103bf6c7dd2drsun  IcrLow.Bits.Level = 1;
487ae40aef1fb4f5f34e5273b6fd5d4103bf6c7dd2drsun  IcrLow.Bits.Vector = Vector;
488ae40aef1fb4f5f34e5273b6fd5d4103bf6c7dd2drsun  SendIpi (IcrLow.Uint32, ApicId);
489ae40aef1fb4f5f34e5273b6fd5d4103bf6c7dd2drsun}
490ae40aef1fb4f5f34e5273b6fd5d4103bf6c7dd2drsun
491ae40aef1fb4f5f34e5273b6fd5d4103bf6c7dd2drsun/**
492ae40aef1fb4f5f34e5273b6fd5d4103bf6c7dd2drsun  Send a Fixed IPI to all processors excluding self.
493ae40aef1fb4f5f34e5273b6fd5d4103bf6c7dd2drsun
494ae40aef1fb4f5f34e5273b6fd5d4103bf6c7dd2drsun  This function returns after the IPI has been accepted by the target processors.
495ae40aef1fb4f5f34e5273b6fd5d4103bf6c7dd2drsun
496ae40aef1fb4f5f34e5273b6fd5d4103bf6c7dd2drsun  @param  Vector   The vector number of the interrupt being sent.
497ae40aef1fb4f5f34e5273b6fd5d4103bf6c7dd2drsun**/
498ae40aef1fb4f5f34e5273b6fd5d4103bf6c7dd2drsunVOID
499ae40aef1fb4f5f34e5273b6fd5d4103bf6c7dd2drsunEFIAPI
500ae40aef1fb4f5f34e5273b6fd5d4103bf6c7dd2drsunSendFixedIpiAllExcludingSelf (
501ae40aef1fb4f5f34e5273b6fd5d4103bf6c7dd2drsun  IN UINT8           Vector
502ae40aef1fb4f5f34e5273b6fd5d4103bf6c7dd2drsun  )
503ae40aef1fb4f5f34e5273b6fd5d4103bf6c7dd2drsun{
504ae40aef1fb4f5f34e5273b6fd5d4103bf6c7dd2drsun  LOCAL_APIC_ICR_LOW IcrLow;
505ae40aef1fb4f5f34e5273b6fd5d4103bf6c7dd2drsun
506ae40aef1fb4f5f34e5273b6fd5d4103bf6c7dd2drsun  IcrLow.Uint32 = 0;
507ae40aef1fb4f5f34e5273b6fd5d4103bf6c7dd2drsun  IcrLow.Bits.DeliveryMode = LOCAL_APIC_DELIVERY_MODE_FIXED;
508ae40aef1fb4f5f34e5273b6fd5d4103bf6c7dd2drsun  IcrLow.Bits.Level = 1;
509ae40aef1fb4f5f34e5273b6fd5d4103bf6c7dd2drsun  IcrLow.Bits.DestinationShorthand = LOCAL_APIC_DESTINATION_SHORTHAND_ALL_EXCLUDING_SELF;
510ae40aef1fb4f5f34e5273b6fd5d4103bf6c7dd2drsun  IcrLow.Bits.Vector = Vector;
511ae40aef1fb4f5f34e5273b6fd5d4103bf6c7dd2drsun  SendIpi (IcrLow.Uint32, 0);
512ae40aef1fb4f5f34e5273b6fd5d4103bf6c7dd2drsun}
513ae40aef1fb4f5f34e5273b6fd5d4103bf6c7dd2drsun
514ae40aef1fb4f5f34e5273b6fd5d4103bf6c7dd2drsun/**
515bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun  Send a SMI IPI to a specified target processor.
516bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun
517bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun  This function returns after the IPI has been accepted by the target processor.
518bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun
519bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun  @param  ApicId   Specify the local APIC ID of the target processor.
520bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun**/
521bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsunVOID
522bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsunEFIAPI
523bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsunSendSmiIpi (
524bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun  IN UINT32          ApicId
525bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun  )
526bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun{
527bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun  LOCAL_APIC_ICR_LOW IcrLow;
528bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun
529bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun  IcrLow.Uint32 = 0;
530bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun  IcrLow.Bits.DeliveryMode = LOCAL_APIC_DELIVERY_MODE_SMI;
531bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun  IcrLow.Bits.Level = 1;
532bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun  SendIpi (IcrLow.Uint32, ApicId);
533bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun}
534bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun
535bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun/**
536bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun  Send a SMI IPI to all processors excluding self.
537bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun
538bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun  This function returns after the IPI has been accepted by the target processors.
539bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun**/
540bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsunVOID
541bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsunEFIAPI
542bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsunSendSmiIpiAllExcludingSelf (
543bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun  VOID
544bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun  )
545bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun{
546bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun  LOCAL_APIC_ICR_LOW IcrLow;
547bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun
548bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun  IcrLow.Uint32 = 0;
549bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun  IcrLow.Bits.DeliveryMode = LOCAL_APIC_DELIVERY_MODE_SMI;
550bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun  IcrLow.Bits.Level = 1;
551bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun  IcrLow.Bits.DestinationShorthand = LOCAL_APIC_DESTINATION_SHORTHAND_ALL_EXCLUDING_SELF;
552bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun  SendIpi (IcrLow.Uint32, 0);
553bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun}
554bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun
555bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun/**
556bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun  Send an INIT IPI to a specified target processor.
557bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun
558bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun  This function returns after the IPI has been accepted by the target processor.
559bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun
560bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun  @param  ApicId   Specify the local APIC ID of the target processor.
561bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun**/
562bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsunVOID
563bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsunEFIAPI
564bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsunSendInitIpi (
565bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun  IN UINT32          ApicId
566bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun  )
567bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun{
568bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun  LOCAL_APIC_ICR_LOW IcrLow;
569bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun
570bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun  IcrLow.Uint32 = 0;
571bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun  IcrLow.Bits.DeliveryMode = LOCAL_APIC_DELIVERY_MODE_INIT;
572bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun  IcrLow.Bits.Level = 1;
573bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun  SendIpi (IcrLow.Uint32, ApicId);
574bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun}
575bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun
576bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun/**
577bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun  Send an INIT IPI to all processors excluding self.
578bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun
579bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun  This function returns after the IPI has been accepted by the target processors.
580bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun**/
581bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsunVOID
582bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsunEFIAPI
583bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsunSendInitIpiAllExcludingSelf (
584bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun  VOID
585bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun  )
586bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun{
587bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun  LOCAL_APIC_ICR_LOW IcrLow;
588bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun
589bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun  IcrLow.Uint32 = 0;
590bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun  IcrLow.Bits.DeliveryMode = LOCAL_APIC_DELIVERY_MODE_INIT;
591bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun  IcrLow.Bits.Level = 1;
592bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun  IcrLow.Bits.DestinationShorthand = LOCAL_APIC_DESTINATION_SHORTHAND_ALL_EXCLUDING_SELF;
593bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun  SendIpi (IcrLow.Uint32, 0);
594bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun}
595bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun
596bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun/**
597bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun  Send an INIT-Start-up-Start-up IPI sequence to a specified target processor.
598bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun
599bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun  This function returns after the IPI has been accepted by the target processor.
600bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun
601bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun  if StartupRoutine >= 1M, then ASSERT.
602bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun  if StartupRoutine is not multiple of 4K, then ASSERT.
603bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun
604bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun  @param  ApicId          Specify the local APIC ID of the target processor.
605bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun  @param  StartupRoutine  Points to a start-up routine which is below 1M physical
606bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun                          address and 4K aligned.
607bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun**/
608bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsunVOID
609bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsunEFIAPI
610bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsunSendInitSipiSipi (
611bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun  IN UINT32          ApicId,
612bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun  IN UINT32          StartupRoutine
613bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun  )
614bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun{
615bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun  LOCAL_APIC_ICR_LOW IcrLow;
616bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun
617bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun  ASSERT (StartupRoutine < 0x100000);
618bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun  ASSERT ((StartupRoutine & 0xfff) == 0);
619bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun
620bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun  SendInitIpi (ApicId);
621cf1eb6e6f85952b0fad82b937054f611cf148d57Jeff Fan  MicroSecondDelay (PcdGet32(PcdCpuInitIpiDelayInMicroSeconds));
622bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun  IcrLow.Uint32 = 0;
623bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun  IcrLow.Bits.Vector = (StartupRoutine >> 12);
624bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun  IcrLow.Bits.DeliveryMode = LOCAL_APIC_DELIVERY_MODE_STARTUP;
625bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun  IcrLow.Bits.Level = 1;
626bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun  SendIpi (IcrLow.Uint32, ApicId);
627bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun  MicroSecondDelay (200);
628bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun  SendIpi (IcrLow.Uint32, ApicId);
629bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun}
630bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun
631bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun/**
632bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun  Send an INIT-Start-up-Start-up IPI sequence to all processors excluding self.
633bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun
634bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun  This function returns after the IPI has been accepted by the target processors.
635bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun
636bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun  if StartupRoutine >= 1M, then ASSERT.
637bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun  if StartupRoutine is not multiple of 4K, then ASSERT.
638bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun
639bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun  @param  StartupRoutine    Points to a start-up routine which is below 1M physical
640bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun                            address and 4K aligned.
641bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun**/
642bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsunVOID
643bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsunEFIAPI
644bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsunSendInitSipiSipiAllExcludingSelf (
645bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun  IN UINT32          StartupRoutine
646bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun  )
647bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun{
648bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun  LOCAL_APIC_ICR_LOW IcrLow;
649bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun
650bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun  ASSERT (StartupRoutine < 0x100000);
651bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun  ASSERT ((StartupRoutine & 0xfff) == 0);
652bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun
653bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun  SendInitIpiAllExcludingSelf ();
654cf1eb6e6f85952b0fad82b937054f611cf148d57Jeff Fan  MicroSecondDelay (PcdGet32(PcdCpuInitIpiDelayInMicroSeconds));
655bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun  IcrLow.Uint32 = 0;
656bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun  IcrLow.Bits.Vector = (StartupRoutine >> 12);
657bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun  IcrLow.Bits.DeliveryMode = LOCAL_APIC_DELIVERY_MODE_STARTUP;
658bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun  IcrLow.Bits.Level = 1;
659bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun  IcrLow.Bits.DestinationShorthand = LOCAL_APIC_DESTINATION_SHORTHAND_ALL_EXCLUDING_SELF;
660bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun  SendIpi (IcrLow.Uint32, 0);
661bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun  MicroSecondDelay (200);
662bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun  SendIpi (IcrLow.Uint32, 0);
663bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun}
664bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun
665bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun/**
66614e4ca25c6199fa29bda7066f31d919197840664Michael Kinney  Initialize the state of the SoftwareEnable bit in the Local APIC
66714e4ca25c6199fa29bda7066f31d919197840664Michael Kinney  Spurious Interrupt Vector register.
66814e4ca25c6199fa29bda7066f31d919197840664Michael Kinney
66914e4ca25c6199fa29bda7066f31d919197840664Michael Kinney  @param  Enable  If TRUE, then set SoftwareEnable to 1
67014e4ca25c6199fa29bda7066f31d919197840664Michael Kinney                  If FALSE, then set SoftwareEnable to 0.
67114e4ca25c6199fa29bda7066f31d919197840664Michael Kinney
67214e4ca25c6199fa29bda7066f31d919197840664Michael Kinney**/
67314e4ca25c6199fa29bda7066f31d919197840664Michael KinneyVOID
67414e4ca25c6199fa29bda7066f31d919197840664Michael KinneyEFIAPI
67514e4ca25c6199fa29bda7066f31d919197840664Michael KinneyInitializeLocalApicSoftwareEnable (
67614e4ca25c6199fa29bda7066f31d919197840664Michael Kinney  IN BOOLEAN  Enable
67714e4ca25c6199fa29bda7066f31d919197840664Michael Kinney  )
67814e4ca25c6199fa29bda7066f31d919197840664Michael Kinney{
67914e4ca25c6199fa29bda7066f31d919197840664Michael Kinney  LOCAL_APIC_SVR  Svr;
68014e4ca25c6199fa29bda7066f31d919197840664Michael Kinney
68114e4ca25c6199fa29bda7066f31d919197840664Michael Kinney  //
68214e4ca25c6199fa29bda7066f31d919197840664Michael Kinney  // Set local APIC software-enabled bit.
68314e4ca25c6199fa29bda7066f31d919197840664Michael Kinney  //
68414e4ca25c6199fa29bda7066f31d919197840664Michael Kinney  Svr.Uint32 = ReadLocalApicReg (XAPIC_SPURIOUS_VECTOR_OFFSET);
68514e4ca25c6199fa29bda7066f31d919197840664Michael Kinney  if (Enable) {
68614e4ca25c6199fa29bda7066f31d919197840664Michael Kinney    if (Svr.Bits.SoftwareEnable == 0) {
68714e4ca25c6199fa29bda7066f31d919197840664Michael Kinney      Svr.Bits.SoftwareEnable = 1;
68814e4ca25c6199fa29bda7066f31d919197840664Michael Kinney      WriteLocalApicReg (XAPIC_SPURIOUS_VECTOR_OFFSET, Svr.Uint32);
68914e4ca25c6199fa29bda7066f31d919197840664Michael Kinney    }
69014e4ca25c6199fa29bda7066f31d919197840664Michael Kinney  } else {
69114e4ca25c6199fa29bda7066f31d919197840664Michael Kinney    if (Svr.Bits.SoftwareEnable == 1) {
69214e4ca25c6199fa29bda7066f31d919197840664Michael Kinney      Svr.Bits.SoftwareEnable = 0;
69314e4ca25c6199fa29bda7066f31d919197840664Michael Kinney      WriteLocalApicReg (XAPIC_SPURIOUS_VECTOR_OFFSET, Svr.Uint32);
69414e4ca25c6199fa29bda7066f31d919197840664Michael Kinney    }
69514e4ca25c6199fa29bda7066f31d919197840664Michael Kinney  }
69614e4ca25c6199fa29bda7066f31d919197840664Michael Kinney}
69714e4ca25c6199fa29bda7066f31d919197840664Michael Kinney
69814e4ca25c6199fa29bda7066f31d919197840664Michael Kinney/**
699bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun  Programming Virtual Wire Mode.
700bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun
701bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun  This function programs the local APIC for virtual wire mode following
702bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun  the example described in chapter A.3 of the MP 1.4 spec.
703bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun
704bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun  IOxAPIC is not involved in this type of virtual wire mode.
705bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun**/
706bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsunVOID
707bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsunEFIAPI
708bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsunProgramVirtualWireMode (
709bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun  VOID
710bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun  )
711bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun{
712bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun  LOCAL_APIC_SVR      Svr;
713bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun  LOCAL_APIC_LVT_LINT Lint;
714bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun
715bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun  //
716bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun  // Enable the APIC via SVR and set the spurious interrupt to use Int 00F.
717bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun  //
718bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun  Svr.Uint32 = ReadLocalApicReg (XAPIC_SPURIOUS_VECTOR_OFFSET);
719bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun  Svr.Bits.SpuriousVector = 0xf;
720bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun  Svr.Bits.SoftwareEnable = 1;
721bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun  WriteLocalApicReg (XAPIC_SPURIOUS_VECTOR_OFFSET, Svr.Uint32);
722bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun
723bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun  //
724bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun  // Program the LINT0 vector entry as ExtInt. Not masked, edge, active high.
725bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun  //
726ae40aef1fb4f5f34e5273b6fd5d4103bf6c7dd2drsun  Lint.Uint32 = ReadLocalApicReg (XAPIC_LVT_LINT0_OFFSET);
727bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun  Lint.Bits.DeliveryMode = LOCAL_APIC_DELIVERY_MODE_EXTINT;
728bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun  Lint.Bits.InputPinPolarity = 0;
729bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun  Lint.Bits.TriggerMode = 0;
730bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun  Lint.Bits.Mask = 0;
731ae40aef1fb4f5f34e5273b6fd5d4103bf6c7dd2drsun  WriteLocalApicReg (XAPIC_LVT_LINT0_OFFSET, Lint.Uint32);
732bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun
733bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun  //
734bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun  // Program the LINT0 vector entry as NMI. Not masked, edge, active high.
735bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun  //
736ae40aef1fb4f5f34e5273b6fd5d4103bf6c7dd2drsun  Lint.Uint32 = ReadLocalApicReg (XAPIC_LVT_LINT1_OFFSET);
737bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun  Lint.Bits.DeliveryMode = LOCAL_APIC_DELIVERY_MODE_NMI;
738bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun  Lint.Bits.InputPinPolarity = 0;
739bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun  Lint.Bits.TriggerMode = 0;
740bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun  Lint.Bits.Mask = 0;
741ae40aef1fb4f5f34e5273b6fd5d4103bf6c7dd2drsun  WriteLocalApicReg (XAPIC_LVT_LINT1_OFFSET, Lint.Uint32);
742bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun}
743bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun
744bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun/**
745b1b8c631f613084d43d64d0b9e1d27337d4d8b5arsun  Disable LINT0 & LINT1 interrupts.
746b1b8c631f613084d43d64d0b9e1d27337d4d8b5arsun
747b1b8c631f613084d43d64d0b9e1d27337d4d8b5arsun  This function sets the mask flag in the LVT LINT0 & LINT1 registers.
748b1b8c631f613084d43d64d0b9e1d27337d4d8b5arsun**/
749b1b8c631f613084d43d64d0b9e1d27337d4d8b5arsunVOID
750b1b8c631f613084d43d64d0b9e1d27337d4d8b5arsunEFIAPI
751b1b8c631f613084d43d64d0b9e1d27337d4d8b5arsunDisableLvtInterrupts (
752b1b8c631f613084d43d64d0b9e1d27337d4d8b5arsun  VOID
753b1b8c631f613084d43d64d0b9e1d27337d4d8b5arsun  )
754b1b8c631f613084d43d64d0b9e1d27337d4d8b5arsun{
755b1b8c631f613084d43d64d0b9e1d27337d4d8b5arsun  LOCAL_APIC_LVT_LINT LvtLint;
756b1b8c631f613084d43d64d0b9e1d27337d4d8b5arsun
757b1b8c631f613084d43d64d0b9e1d27337d4d8b5arsun  LvtLint.Uint32 = ReadLocalApicReg (XAPIC_LVT_LINT0_OFFSET);
758b1b8c631f613084d43d64d0b9e1d27337d4d8b5arsun  LvtLint.Bits.Mask = 1;
759b1b8c631f613084d43d64d0b9e1d27337d4d8b5arsun  WriteLocalApicReg (XAPIC_LVT_LINT0_OFFSET, LvtLint.Uint32);
760b1b8c631f613084d43d64d0b9e1d27337d4d8b5arsun
761b1b8c631f613084d43d64d0b9e1d27337d4d8b5arsun  LvtLint.Uint32 = ReadLocalApicReg (XAPIC_LVT_LINT1_OFFSET);
762b1b8c631f613084d43d64d0b9e1d27337d4d8b5arsun  LvtLint.Bits.Mask = 1;
763b1b8c631f613084d43d64d0b9e1d27337d4d8b5arsun  WriteLocalApicReg (XAPIC_LVT_LINT1_OFFSET, LvtLint.Uint32);
764b1b8c631f613084d43d64d0b9e1d27337d4d8b5arsun}
765b1b8c631f613084d43d64d0b9e1d27337d4d8b5arsun
766b1b8c631f613084d43d64d0b9e1d27337d4d8b5arsun/**
767bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun  Read the initial count value from the init-count register.
768bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun
769bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun  @return The initial count value read from the init-count register.
770bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun**/
771bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsunUINT32
772bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsunEFIAPI
773bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsunGetApicTimerInitCount (
774bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun  VOID
775bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun  )
776bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun{
777bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun  return ReadLocalApicReg (XAPIC_TIMER_INIT_COUNT_OFFSET);
778bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun}
779bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun
780bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun/**
781bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun  Read the current count value from the current-count register.
782bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun
783bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun  @return The current count value read from the current-count register.
784bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun**/
785bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsunUINT32
786bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsunEFIAPI
787bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsunGetApicTimerCurrentCount (
788bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun  VOID
789bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun  )
790bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun{
791bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun  return ReadLocalApicReg (XAPIC_TIMER_CURRENT_COUNT_OFFSET);
792bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun}
793bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun
794bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun/**
795bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun  Initialize the local APIC timer.
796bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun
797bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun  The local APIC timer is initialized and enabled.
798bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun
799bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun  @param DivideValue   The divide value for the DCR. It is one of 1,2,4,8,16,32,64,128.
800bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun                       If it is 0, then use the current divide value in the DCR.
801bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun  @param InitCount     The initial count value.
802bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun  @param PeriodicMode  If TRUE, timer mode is peridoic. Othewise, timer mode is one-shot.
803bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun  @param Vector        The timer interrupt vector number.
804bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun**/
805bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsunVOID
806bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsunEFIAPI
807bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsunInitializeApicTimer (
808bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun  IN UINTN   DivideValue,
809bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun  IN UINT32  InitCount,
810bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun  IN BOOLEAN PeriodicMode,
811bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun  IN UINT8   Vector
812bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun  )
813bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun{
814bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun  LOCAL_APIC_DCR       Dcr;
815bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun  LOCAL_APIC_LVT_TIMER LvtTimer;
816bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun  UINT32               Divisor;
817bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun
818bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun  //
819bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun  // Ensure local APIC is in software-enabled state.
820bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun  //
82114e4ca25c6199fa29bda7066f31d919197840664Michael Kinney  InitializeLocalApicSoftwareEnable (TRUE);
822bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun
823bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun  //
824bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun  // Program init-count register.
825bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun  //
826bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun  WriteLocalApicReg (XAPIC_TIMER_INIT_COUNT_OFFSET, InitCount);
827bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun
828bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun  if (DivideValue != 0) {
829bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun    ASSERT (DivideValue <= 128);
830bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun    ASSERT (DivideValue == GetPowerOfTwo32((UINT32)DivideValue));
831bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun    Divisor = (UINT32)((HighBitSet32 ((UINT32)DivideValue) - 1) & 0x7);
832bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun
833bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun    Dcr.Uint32 = ReadLocalApicReg (XAPIC_TIMER_DIVIDE_CONFIGURATION_OFFSET);
834bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun    Dcr.Bits.DivideValue1 = (Divisor & 0x3);
835bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun    Dcr.Bits.DivideValue2 = (Divisor >> 2);
836bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun    WriteLocalApicReg (XAPIC_TIMER_DIVIDE_CONFIGURATION_OFFSET, Dcr.Uint32);
837bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun  }
838bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun
839bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun  //
840bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun  // Enable APIC timer interrupt with specified timer mode.
841bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun  //
842bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun  LvtTimer.Uint32 = ReadLocalApicReg (XAPIC_LVT_TIMER_OFFSET);
843bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun  if (PeriodicMode) {
844bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun    LvtTimer.Bits.TimerMode = 1;
845bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun  } else {
846bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun    LvtTimer.Bits.TimerMode = 0;
847bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun  }
848bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun  LvtTimer.Bits.Mask = 0;
849bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun  LvtTimer.Bits.Vector = Vector;
850bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun  WriteLocalApicReg (XAPIC_LVT_TIMER_OFFSET, LvtTimer.Uint32);
851bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun}
852bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun
853bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun/**
854ae40aef1fb4f5f34e5273b6fd5d4103bf6c7dd2drsun  Get the state of the local APIC timer.
855ae40aef1fb4f5f34e5273b6fd5d4103bf6c7dd2drsun
8566d72ff7d9daf7efae5243e9c00a281b350fc0f95Hao Wu  This function will ASSERT if the local APIC is not software enabled.
8576d72ff7d9daf7efae5243e9c00a281b350fc0f95Hao Wu
858ae40aef1fb4f5f34e5273b6fd5d4103bf6c7dd2drsun  @param DivideValue   Return the divide value for the DCR. It is one of 1,2,4,8,16,32,64,128.
859ae40aef1fb4f5f34e5273b6fd5d4103bf6c7dd2drsun  @param PeriodicMode  Return the timer mode. If TRUE, timer mode is peridoic. Othewise, timer mode is one-shot.
860ae40aef1fb4f5f34e5273b6fd5d4103bf6c7dd2drsun  @param Vector        Return the timer interrupt vector number.
861ae40aef1fb4f5f34e5273b6fd5d4103bf6c7dd2drsun**/
862ae40aef1fb4f5f34e5273b6fd5d4103bf6c7dd2drsunVOID
863ae40aef1fb4f5f34e5273b6fd5d4103bf6c7dd2drsunEFIAPI
864ae40aef1fb4f5f34e5273b6fd5d4103bf6c7dd2drsunGetApicTimerState (
865ae40aef1fb4f5f34e5273b6fd5d4103bf6c7dd2drsun  OUT UINTN    *DivideValue  OPTIONAL,
866ae40aef1fb4f5f34e5273b6fd5d4103bf6c7dd2drsun  OUT BOOLEAN  *PeriodicMode  OPTIONAL,
867ae40aef1fb4f5f34e5273b6fd5d4103bf6c7dd2drsun  OUT UINT8    *Vector  OPTIONAL
868ae40aef1fb4f5f34e5273b6fd5d4103bf6c7dd2drsun  )
869ae40aef1fb4f5f34e5273b6fd5d4103bf6c7dd2drsun{
870ae40aef1fb4f5f34e5273b6fd5d4103bf6c7dd2drsun  UINT32 Divisor;
871ae40aef1fb4f5f34e5273b6fd5d4103bf6c7dd2drsun  LOCAL_APIC_DCR Dcr;
872ae40aef1fb4f5f34e5273b6fd5d4103bf6c7dd2drsun  LOCAL_APIC_LVT_TIMER LvtTimer;
873ae40aef1fb4f5f34e5273b6fd5d4103bf6c7dd2drsun
8746d72ff7d9daf7efae5243e9c00a281b350fc0f95Hao Wu  //
8756d72ff7d9daf7efae5243e9c00a281b350fc0f95Hao Wu  // Check the APIC Software Enable/Disable bit (bit 8) in Spurious-Interrupt
8766d72ff7d9daf7efae5243e9c00a281b350fc0f95Hao Wu  // Vector Register.
8776d72ff7d9daf7efae5243e9c00a281b350fc0f95Hao Wu  // This bit will be 1, if local APIC is software enabled.
8786d72ff7d9daf7efae5243e9c00a281b350fc0f95Hao Wu  //
8796d72ff7d9daf7efae5243e9c00a281b350fc0f95Hao Wu  ASSERT ((ReadLocalApicReg(XAPIC_SPURIOUS_VECTOR_OFFSET) & BIT8) != 0);
8806d72ff7d9daf7efae5243e9c00a281b350fc0f95Hao Wu
881ae40aef1fb4f5f34e5273b6fd5d4103bf6c7dd2drsun  if (DivideValue != NULL) {
882ae40aef1fb4f5f34e5273b6fd5d4103bf6c7dd2drsun    Dcr.Uint32 = ReadLocalApicReg (XAPIC_TIMER_DIVIDE_CONFIGURATION_OFFSET);
883ae40aef1fb4f5f34e5273b6fd5d4103bf6c7dd2drsun    Divisor = Dcr.Bits.DivideValue1 | (Dcr.Bits.DivideValue2 << 2);
884ae40aef1fb4f5f34e5273b6fd5d4103bf6c7dd2drsun    Divisor = (Divisor + 1) & 0x7;
885ae40aef1fb4f5f34e5273b6fd5d4103bf6c7dd2drsun    *DivideValue = ((UINTN)1) << Divisor;
886ae40aef1fb4f5f34e5273b6fd5d4103bf6c7dd2drsun  }
887ae40aef1fb4f5f34e5273b6fd5d4103bf6c7dd2drsun
888ae40aef1fb4f5f34e5273b6fd5d4103bf6c7dd2drsun  if (PeriodicMode != NULL || Vector != NULL) {
889ae40aef1fb4f5f34e5273b6fd5d4103bf6c7dd2drsun    LvtTimer.Uint32 = ReadLocalApicReg (XAPIC_LVT_TIMER_OFFSET);
890ae40aef1fb4f5f34e5273b6fd5d4103bf6c7dd2drsun    if (PeriodicMode != NULL) {
891ae40aef1fb4f5f34e5273b6fd5d4103bf6c7dd2drsun      if (LvtTimer.Bits.TimerMode == 1) {
892ae40aef1fb4f5f34e5273b6fd5d4103bf6c7dd2drsun        *PeriodicMode = TRUE;
893ae40aef1fb4f5f34e5273b6fd5d4103bf6c7dd2drsun      } else {
894ae40aef1fb4f5f34e5273b6fd5d4103bf6c7dd2drsun        *PeriodicMode = FALSE;
895ae40aef1fb4f5f34e5273b6fd5d4103bf6c7dd2drsun      }
896ae40aef1fb4f5f34e5273b6fd5d4103bf6c7dd2drsun    }
897ae40aef1fb4f5f34e5273b6fd5d4103bf6c7dd2drsun    if (Vector != NULL) {
898ae40aef1fb4f5f34e5273b6fd5d4103bf6c7dd2drsun      *Vector = (UINT8) LvtTimer.Bits.Vector;
899ae40aef1fb4f5f34e5273b6fd5d4103bf6c7dd2drsun    }
900ae40aef1fb4f5f34e5273b6fd5d4103bf6c7dd2drsun  }
901ae40aef1fb4f5f34e5273b6fd5d4103bf6c7dd2drsun}
902ae40aef1fb4f5f34e5273b6fd5d4103bf6c7dd2drsun
903ae40aef1fb4f5f34e5273b6fd5d4103bf6c7dd2drsun/**
904bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun  Enable the local APIC timer interrupt.
905bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun**/
906bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsunVOID
907bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsunEFIAPI
908bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsunEnableApicTimerInterrupt (
909bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun  VOID
910bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun  )
911bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun{
912bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun  LOCAL_APIC_LVT_TIMER LvtTimer;
913bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun
914bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun  LvtTimer.Uint32 = ReadLocalApicReg (XAPIC_LVT_TIMER_OFFSET);
915bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun  LvtTimer.Bits.Mask = 0;
916bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun  WriteLocalApicReg (XAPIC_LVT_TIMER_OFFSET, LvtTimer.Uint32);
917bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun}
918bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun
919bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun/**
920bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun  Disable the local APIC timer interrupt.
921bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun**/
922bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsunVOID
923bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsunEFIAPI
924bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsunDisableApicTimerInterrupt (
925bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun  VOID
926bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun  )
927bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun{
928bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun  LOCAL_APIC_LVT_TIMER LvtTimer;
929bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun
930bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun  LvtTimer.Uint32 = ReadLocalApicReg (XAPIC_LVT_TIMER_OFFSET);
931bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun  LvtTimer.Bits.Mask = 1;
932bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun  WriteLocalApicReg (XAPIC_LVT_TIMER_OFFSET, LvtTimer.Uint32);
933bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun}
934bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun
935bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun/**
936bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun  Get the local APIC timer interrupt state.
937bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun
938bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun  @retval TRUE  The local APIC timer interrupt is enabled.
939bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun  @retval FALSE The local APIC timer interrupt is disabled.
940bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun**/
941bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsunBOOLEAN
942bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsunEFIAPI
943bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsunGetApicTimerInterruptState (
944bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun  VOID
945bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun  )
946bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun{
947bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun  LOCAL_APIC_LVT_TIMER LvtTimer;
948bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun
949bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun  LvtTimer.Uint32 = ReadLocalApicReg (XAPIC_LVT_TIMER_OFFSET);
950bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun  return (BOOLEAN)(LvtTimer.Bits.Mask == 0);
951bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun}
952bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun
953bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun/**
954bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun  Send EOI to the local APIC.
955bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun**/
956bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsunVOID
957bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsunEFIAPI
958bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsunSendApicEoi (
959bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun  VOID
960bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun  )
961bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun{
962bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun  WriteLocalApicReg (XAPIC_EOI_OFFSET, 0);
963bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun}
964bf73cc4bbcdaa76bad31875bce6ff9dd0d91eb09rsun
9655f867ad00d499debbf22dee044b22e01b63e1ademdkinney/**
9665f867ad00d499debbf22dee044b22e01b63e1ademdkinney  Get the 32-bit address that a device should use to send a Message Signaled
9675f867ad00d499debbf22dee044b22e01b63e1ademdkinney  Interrupt (MSI) to the Local APIC of the currently executing processor.
9685f867ad00d499debbf22dee044b22e01b63e1ademdkinney
9695f867ad00d499debbf22dee044b22e01b63e1ademdkinney  @return 32-bit address used to send an MSI to the Local APIC.
9705f867ad00d499debbf22dee044b22e01b63e1ademdkinney**/
9715f867ad00d499debbf22dee044b22e01b63e1ademdkinneyUINT32
9725f867ad00d499debbf22dee044b22e01b63e1ademdkinneyEFIAPI
9735f867ad00d499debbf22dee044b22e01b63e1ademdkinneyGetApicMsiAddress (
9745f867ad00d499debbf22dee044b22e01b63e1ademdkinney  VOID
9755f867ad00d499debbf22dee044b22e01b63e1ademdkinney  )
9765f867ad00d499debbf22dee044b22e01b63e1ademdkinney{
9775f867ad00d499debbf22dee044b22e01b63e1ademdkinney  LOCAL_APIC_MSI_ADDRESS  MsiAddress;
9785f867ad00d499debbf22dee044b22e01b63e1ademdkinney
9795f867ad00d499debbf22dee044b22e01b63e1ademdkinney  //
9805f867ad00d499debbf22dee044b22e01b63e1ademdkinney  // Return address for an MSI interrupt to be delivered only to the APIC ID
9815f867ad00d499debbf22dee044b22e01b63e1ademdkinney  // of the currently executing processor.
9825f867ad00d499debbf22dee044b22e01b63e1ademdkinney  //
9835f867ad00d499debbf22dee044b22e01b63e1ademdkinney  MsiAddress.Uint32             = 0;
9845f867ad00d499debbf22dee044b22e01b63e1ademdkinney  MsiAddress.Bits.BaseAddress   = 0xFEE;
9855f867ad00d499debbf22dee044b22e01b63e1ademdkinney  MsiAddress.Bits.DestinationId = GetApicId ();
9865f867ad00d499debbf22dee044b22e01b63e1ademdkinney  return MsiAddress.Uint32;
9875f867ad00d499debbf22dee044b22e01b63e1ademdkinney}
9885f867ad00d499debbf22dee044b22e01b63e1ademdkinney
9895f867ad00d499debbf22dee044b22e01b63e1ademdkinney/**
9905f867ad00d499debbf22dee044b22e01b63e1ademdkinney  Get the 64-bit data value that a device should use to send a Message Signaled
9915f867ad00d499debbf22dee044b22e01b63e1ademdkinney  Interrupt (MSI) to the Local APIC of the currently executing processor.
9925f867ad00d499debbf22dee044b22e01b63e1ademdkinney
9935f867ad00d499debbf22dee044b22e01b63e1ademdkinney  If Vector is not in range 0x10..0xFE, then ASSERT().
9945f867ad00d499debbf22dee044b22e01b63e1ademdkinney  If DeliveryMode is not supported, then ASSERT().
9955f867ad00d499debbf22dee044b22e01b63e1ademdkinney
9965f867ad00d499debbf22dee044b22e01b63e1ademdkinney  @param  Vector          The 8-bit interrupt vector associated with the MSI.
9975f867ad00d499debbf22dee044b22e01b63e1ademdkinney                          Must be in the range 0x10..0xFE
9985f867ad00d499debbf22dee044b22e01b63e1ademdkinney  @param  DeliveryMode    A 3-bit value that specifies how the recept of the MSI
9995f867ad00d499debbf22dee044b22e01b63e1ademdkinney                          is handled.  The only supported values are:
10005f867ad00d499debbf22dee044b22e01b63e1ademdkinney                            0: LOCAL_APIC_DELIVERY_MODE_FIXED
10015f867ad00d499debbf22dee044b22e01b63e1ademdkinney                            1: LOCAL_APIC_DELIVERY_MODE_LOWEST_PRIORITY
10025f867ad00d499debbf22dee044b22e01b63e1ademdkinney                            2: LOCAL_APIC_DELIVERY_MODE_SMI
10035f867ad00d499debbf22dee044b22e01b63e1ademdkinney                            4: LOCAL_APIC_DELIVERY_MODE_NMI
10045f867ad00d499debbf22dee044b22e01b63e1ademdkinney                            5: LOCAL_APIC_DELIVERY_MODE_INIT
10055f867ad00d499debbf22dee044b22e01b63e1ademdkinney                            7: LOCAL_APIC_DELIVERY_MODE_EXTINT
10065f867ad00d499debbf22dee044b22e01b63e1ademdkinney
10075f867ad00d499debbf22dee044b22e01b63e1ademdkinney  @param  LevelTriggered  TRUE specifies a level triggered interrupt.
10085f867ad00d499debbf22dee044b22e01b63e1ademdkinney                          FALSE specifies an edge triggered interrupt.
10095f867ad00d499debbf22dee044b22e01b63e1ademdkinney  @param  AssertionLevel  Ignored if LevelTriggered is FALSE.
10105f867ad00d499debbf22dee044b22e01b63e1ademdkinney                          TRUE specifies a level triggered interrupt that active
10115f867ad00d499debbf22dee044b22e01b63e1ademdkinney                          when the interrupt line is asserted.
10125f867ad00d499debbf22dee044b22e01b63e1ademdkinney                          FALSE specifies a level triggered interrupt that active
10135f867ad00d499debbf22dee044b22e01b63e1ademdkinney                          when the interrupt line is deasserted.
10145f867ad00d499debbf22dee044b22e01b63e1ademdkinney
10155f867ad00d499debbf22dee044b22e01b63e1ademdkinney  @return 64-bit data value used to send an MSI to the Local APIC.
10165f867ad00d499debbf22dee044b22e01b63e1ademdkinney**/
10175f867ad00d499debbf22dee044b22e01b63e1ademdkinneyUINT64
10185f867ad00d499debbf22dee044b22e01b63e1ademdkinneyEFIAPI
10195f867ad00d499debbf22dee044b22e01b63e1ademdkinneyGetApicMsiValue (
10205f867ad00d499debbf22dee044b22e01b63e1ademdkinney  IN UINT8    Vector,
10215f867ad00d499debbf22dee044b22e01b63e1ademdkinney  IN UINTN    DeliveryMode,
10225f867ad00d499debbf22dee044b22e01b63e1ademdkinney  IN BOOLEAN  LevelTriggered,
10235f867ad00d499debbf22dee044b22e01b63e1ademdkinney  IN BOOLEAN  AssertionLevel
10245f867ad00d499debbf22dee044b22e01b63e1ademdkinney  )
10255f867ad00d499debbf22dee044b22e01b63e1ademdkinney{
10265f867ad00d499debbf22dee044b22e01b63e1ademdkinney  LOCAL_APIC_MSI_DATA  MsiData;
10275f867ad00d499debbf22dee044b22e01b63e1ademdkinney
10285f867ad00d499debbf22dee044b22e01b63e1ademdkinney  ASSERT (Vector >= 0x10 && Vector <= 0xFE);
10295f867ad00d499debbf22dee044b22e01b63e1ademdkinney  ASSERT (DeliveryMode < 8 && DeliveryMode != 6 && DeliveryMode != 3);
10305f867ad00d499debbf22dee044b22e01b63e1ademdkinney
10315f867ad00d499debbf22dee044b22e01b63e1ademdkinney  MsiData.Uint64            = 0;
10325f867ad00d499debbf22dee044b22e01b63e1ademdkinney  MsiData.Bits.Vector       = Vector;
10335f867ad00d499debbf22dee044b22e01b63e1ademdkinney  MsiData.Bits.DeliveryMode = (UINT32)DeliveryMode;
10345f867ad00d499debbf22dee044b22e01b63e1ademdkinney  if (LevelTriggered) {
10355f867ad00d499debbf22dee044b22e01b63e1ademdkinney    MsiData.Bits.TriggerMode = 1;
10365f867ad00d499debbf22dee044b22e01b63e1ademdkinney    if (AssertionLevel) {
10375f867ad00d499debbf22dee044b22e01b63e1ademdkinney      MsiData.Bits.Level = 1;
10385f867ad00d499debbf22dee044b22e01b63e1ademdkinney    }
10395f867ad00d499debbf22dee044b22e01b63e1ademdkinney  }
10405f867ad00d499debbf22dee044b22e01b63e1ademdkinney  return MsiData.Uint64;
10415f867ad00d499debbf22dee044b22e01b63e1ademdkinney}
104273152f19c0be7f31ee05f32878b515a296c487faLeo Duran
104373152f19c0be7f31ee05f32878b515a296c487faLeo Duran/**
104473152f19c0be7f31ee05f32878b515a296c487faLeo Duran  Get Package ID/Core ID/Thread ID of a processor.
104573152f19c0be7f31ee05f32878b515a296c487faLeo Duran
104673152f19c0be7f31ee05f32878b515a296c487faLeo Duran  The algorithm assumes the target system has symmetry across physical
104773152f19c0be7f31ee05f32878b515a296c487faLeo Duran  package  boundaries with respect to the number of logical processors
104873152f19c0be7f31ee05f32878b515a296c487faLeo Duran  per package,  number of cores per package.
104973152f19c0be7f31ee05f32878b515a296c487faLeo Duran
105073152f19c0be7f31ee05f32878b515a296c487faLeo Duran  @param[in]  InitialApicId  Initial APIC ID of the target logical processor.
105173152f19c0be7f31ee05f32878b515a296c487faLeo Duran  @param[out]  Package       Returns the processor package ID.
105273152f19c0be7f31ee05f32878b515a296c487faLeo Duran  @param[out]  Core          Returns the processor core ID.
105373152f19c0be7f31ee05f32878b515a296c487faLeo Duran  @param[out]  Thread        Returns the processor thread ID.
105473152f19c0be7f31ee05f32878b515a296c487faLeo Duran**/
105573152f19c0be7f31ee05f32878b515a296c487faLeo DuranVOID
10561c8ca9a012ce19a1096625ef9e810036e8346827Jeff FanEFIAPI
1057262128e5ab9edda666586c7dda3f2b0f53c0c557Jeff FanGetProcessorLocationByApicId (
105873152f19c0be7f31ee05f32878b515a296c487faLeo Duran  IN  UINT32  InitialApicId,
105973152f19c0be7f31ee05f32878b515a296c487faLeo Duran  OUT UINT32  *Package  OPTIONAL,
106073152f19c0be7f31ee05f32878b515a296c487faLeo Duran  OUT UINT32  *Core    OPTIONAL,
106173152f19c0be7f31ee05f32878b515a296c487faLeo Duran  OUT UINT32  *Thread  OPTIONAL
106273152f19c0be7f31ee05f32878b515a296c487faLeo Duran  )
106373152f19c0be7f31ee05f32878b515a296c487faLeo Duran{
106473152f19c0be7f31ee05f32878b515a296c487faLeo Duran  BOOLEAN                       TopologyLeafSupported;
106573152f19c0be7f31ee05f32878b515a296c487faLeo Duran  UINTN                         ThreadBits;
106673152f19c0be7f31ee05f32878b515a296c487faLeo Duran  UINTN                         CoreBits;
106773152f19c0be7f31ee05f32878b515a296c487faLeo Duran  CPUID_VERSION_INFO_EBX        VersionInfoEbx;
106873152f19c0be7f31ee05f32878b515a296c487faLeo Duran  CPUID_VERSION_INFO_EDX        VersionInfoEdx;
106973152f19c0be7f31ee05f32878b515a296c487faLeo Duran  CPUID_CACHE_PARAMS_EAX        CacheParamsEax;
107073152f19c0be7f31ee05f32878b515a296c487faLeo Duran  CPUID_EXTENDED_TOPOLOGY_EAX   ExtendedTopologyEax;
107173152f19c0be7f31ee05f32878b515a296c487faLeo Duran  CPUID_EXTENDED_TOPOLOGY_EBX   ExtendedTopologyEbx;
107273152f19c0be7f31ee05f32878b515a296c487faLeo Duran  CPUID_EXTENDED_TOPOLOGY_ECX   ExtendedTopologyEcx;
107373152f19c0be7f31ee05f32878b515a296c487faLeo Duran  UINT32                        MaxCpuIdIndex;
107473152f19c0be7f31ee05f32878b515a296c487faLeo Duran  UINT32                        SubIndex;
107573152f19c0be7f31ee05f32878b515a296c487faLeo Duran  UINTN                         LevelType;
107673152f19c0be7f31ee05f32878b515a296c487faLeo Duran  UINT32                        MaxLogicProcessorsPerPackage;
107773152f19c0be7f31ee05f32878b515a296c487faLeo Duran  UINT32                        MaxCoresPerPackage;
107873152f19c0be7f31ee05f32878b515a296c487faLeo Duran
107973152f19c0be7f31ee05f32878b515a296c487faLeo Duran  //
108073152f19c0be7f31ee05f32878b515a296c487faLeo Duran  // Check if the processor is capable of supporting more than one logical processor.
108173152f19c0be7f31ee05f32878b515a296c487faLeo Duran  //
108273152f19c0be7f31ee05f32878b515a296c487faLeo Duran  AsmCpuid(CPUID_VERSION_INFO, NULL, NULL, NULL, &VersionInfoEdx.Uint32);
108373152f19c0be7f31ee05f32878b515a296c487faLeo Duran  if (VersionInfoEdx.Bits.HTT == 0) {
108473152f19c0be7f31ee05f32878b515a296c487faLeo Duran    if (Thread != NULL) {
108573152f19c0be7f31ee05f32878b515a296c487faLeo Duran      *Thread  = 0;
108673152f19c0be7f31ee05f32878b515a296c487faLeo Duran    }
108773152f19c0be7f31ee05f32878b515a296c487faLeo Duran    if (Core != NULL) {
108873152f19c0be7f31ee05f32878b515a296c487faLeo Duran      *Core    = 0;
108973152f19c0be7f31ee05f32878b515a296c487faLeo Duran    }
109073152f19c0be7f31ee05f32878b515a296c487faLeo Duran    if (Package != NULL) {
109173152f19c0be7f31ee05f32878b515a296c487faLeo Duran      *Package = 0;
109273152f19c0be7f31ee05f32878b515a296c487faLeo Duran    }
109373152f19c0be7f31ee05f32878b515a296c487faLeo Duran    return;
109473152f19c0be7f31ee05f32878b515a296c487faLeo Duran  }
109573152f19c0be7f31ee05f32878b515a296c487faLeo Duran
109673152f19c0be7f31ee05f32878b515a296c487faLeo Duran  ThreadBits = 0;
109773152f19c0be7f31ee05f32878b515a296c487faLeo Duran  CoreBits = 0;
109873152f19c0be7f31ee05f32878b515a296c487faLeo Duran
109973152f19c0be7f31ee05f32878b515a296c487faLeo Duran  //
110073152f19c0be7f31ee05f32878b515a296c487faLeo Duran  // Assume three-level mapping of APIC ID: Package:Core:SMT.
110173152f19c0be7f31ee05f32878b515a296c487faLeo Duran  //
110273152f19c0be7f31ee05f32878b515a296c487faLeo Duran  TopologyLeafSupported = FALSE;
110373152f19c0be7f31ee05f32878b515a296c487faLeo Duran
110473152f19c0be7f31ee05f32878b515a296c487faLeo Duran  //
110573152f19c0be7f31ee05f32878b515a296c487faLeo Duran  // Get the max index of basic CPUID
110673152f19c0be7f31ee05f32878b515a296c487faLeo Duran  //
110773152f19c0be7f31ee05f32878b515a296c487faLeo Duran  AsmCpuid(CPUID_SIGNATURE, &MaxCpuIdIndex, NULL, NULL, NULL);
110873152f19c0be7f31ee05f32878b515a296c487faLeo Duran
110973152f19c0be7f31ee05f32878b515a296c487faLeo Duran  //
111073152f19c0be7f31ee05f32878b515a296c487faLeo Duran  // If the extended topology enumeration leaf is available, it
111173152f19c0be7f31ee05f32878b515a296c487faLeo Duran  // is the preferred mechanism for enumerating topology.
111273152f19c0be7f31ee05f32878b515a296c487faLeo Duran  //
111373152f19c0be7f31ee05f32878b515a296c487faLeo Duran  if (MaxCpuIdIndex >= CPUID_EXTENDED_TOPOLOGY) {
111473152f19c0be7f31ee05f32878b515a296c487faLeo Duran    AsmCpuidEx(
111573152f19c0be7f31ee05f32878b515a296c487faLeo Duran      CPUID_EXTENDED_TOPOLOGY,
111673152f19c0be7f31ee05f32878b515a296c487faLeo Duran      0,
111773152f19c0be7f31ee05f32878b515a296c487faLeo Duran      &ExtendedTopologyEax.Uint32,
111873152f19c0be7f31ee05f32878b515a296c487faLeo Duran      &ExtendedTopologyEbx.Uint32,
111973152f19c0be7f31ee05f32878b515a296c487faLeo Duran      &ExtendedTopologyEcx.Uint32,
112073152f19c0be7f31ee05f32878b515a296c487faLeo Duran      NULL
112173152f19c0be7f31ee05f32878b515a296c487faLeo Duran      );
112273152f19c0be7f31ee05f32878b515a296c487faLeo Duran    //
112373152f19c0be7f31ee05f32878b515a296c487faLeo Duran    // If CPUID.(EAX=0BH, ECX=0H):EBX returns zero and maximum input value for
112473152f19c0be7f31ee05f32878b515a296c487faLeo Duran    // basic CPUID information is greater than 0BH, then CPUID.0BH leaf is not
112573152f19c0be7f31ee05f32878b515a296c487faLeo Duran    // supported on that processor.
112673152f19c0be7f31ee05f32878b515a296c487faLeo Duran    //
112773152f19c0be7f31ee05f32878b515a296c487faLeo Duran    if (ExtendedTopologyEbx.Uint32 != 0) {
112873152f19c0be7f31ee05f32878b515a296c487faLeo Duran      TopologyLeafSupported = TRUE;
112973152f19c0be7f31ee05f32878b515a296c487faLeo Duran
113073152f19c0be7f31ee05f32878b515a296c487faLeo Duran      //
113173152f19c0be7f31ee05f32878b515a296c487faLeo Duran      // Sub-leaf index 0 (ECX= 0 as input) provides enumeration parameters to extract
113273152f19c0be7f31ee05f32878b515a296c487faLeo Duran      // the SMT sub-field of x2APIC ID.
113373152f19c0be7f31ee05f32878b515a296c487faLeo Duran      //
113473152f19c0be7f31ee05f32878b515a296c487faLeo Duran      LevelType = ExtendedTopologyEcx.Bits.LevelType;
113573152f19c0be7f31ee05f32878b515a296c487faLeo Duran      ASSERT(LevelType == CPUID_EXTENDED_TOPOLOGY_LEVEL_TYPE_SMT);
113673152f19c0be7f31ee05f32878b515a296c487faLeo Duran      ThreadBits = ExtendedTopologyEax.Bits.ApicIdShift;
113773152f19c0be7f31ee05f32878b515a296c487faLeo Duran
113873152f19c0be7f31ee05f32878b515a296c487faLeo Duran      //
113973152f19c0be7f31ee05f32878b515a296c487faLeo Duran      // Software must not assume any "level type" encoding
114073152f19c0be7f31ee05f32878b515a296c487faLeo Duran      // value to be related to any sub-leaf index, except sub-leaf 0.
114173152f19c0be7f31ee05f32878b515a296c487faLeo Duran      //
114273152f19c0be7f31ee05f32878b515a296c487faLeo Duran      SubIndex = 1;
114373152f19c0be7f31ee05f32878b515a296c487faLeo Duran      do {
114473152f19c0be7f31ee05f32878b515a296c487faLeo Duran        AsmCpuidEx(
114573152f19c0be7f31ee05f32878b515a296c487faLeo Duran          CPUID_EXTENDED_TOPOLOGY,
114673152f19c0be7f31ee05f32878b515a296c487faLeo Duran          SubIndex,
114773152f19c0be7f31ee05f32878b515a296c487faLeo Duran          &ExtendedTopologyEax.Uint32,
114873152f19c0be7f31ee05f32878b515a296c487faLeo Duran          NULL,
114973152f19c0be7f31ee05f32878b515a296c487faLeo Duran          &ExtendedTopologyEcx.Uint32,
115073152f19c0be7f31ee05f32878b515a296c487faLeo Duran          NULL
115173152f19c0be7f31ee05f32878b515a296c487faLeo Duran          );
115273152f19c0be7f31ee05f32878b515a296c487faLeo Duran        LevelType = ExtendedTopologyEcx.Bits.LevelType;
115373152f19c0be7f31ee05f32878b515a296c487faLeo Duran        if (LevelType == CPUID_EXTENDED_TOPOLOGY_LEVEL_TYPE_CORE) {
115473152f19c0be7f31ee05f32878b515a296c487faLeo Duran          CoreBits = ExtendedTopologyEax.Bits.ApicIdShift - ThreadBits;
115573152f19c0be7f31ee05f32878b515a296c487faLeo Duran          break;
115673152f19c0be7f31ee05f32878b515a296c487faLeo Duran        }
115773152f19c0be7f31ee05f32878b515a296c487faLeo Duran        SubIndex++;
115873152f19c0be7f31ee05f32878b515a296c487faLeo Duran      } while (LevelType != CPUID_EXTENDED_TOPOLOGY_LEVEL_TYPE_INVALID);
115973152f19c0be7f31ee05f32878b515a296c487faLeo Duran    }
116073152f19c0be7f31ee05f32878b515a296c487faLeo Duran  }
116173152f19c0be7f31ee05f32878b515a296c487faLeo Duran
116273152f19c0be7f31ee05f32878b515a296c487faLeo Duran  if (!TopologyLeafSupported) {
116373152f19c0be7f31ee05f32878b515a296c487faLeo Duran    AsmCpuid(CPUID_VERSION_INFO, NULL, &VersionInfoEbx.Uint32, NULL, NULL);
116473152f19c0be7f31ee05f32878b515a296c487faLeo Duran    MaxLogicProcessorsPerPackage = VersionInfoEbx.Bits.MaximumAddressableIdsForLogicalProcessors;
116573152f19c0be7f31ee05f32878b515a296c487faLeo Duran    if (MaxCpuIdIndex >= CPUID_CACHE_PARAMS) {
116673152f19c0be7f31ee05f32878b515a296c487faLeo Duran      AsmCpuidEx(CPUID_CACHE_PARAMS, 0, &CacheParamsEax.Uint32, NULL, NULL, NULL);
116773152f19c0be7f31ee05f32878b515a296c487faLeo Duran      MaxCoresPerPackage = CacheParamsEax.Bits.MaximumAddressableIdsForLogicalProcessors + 1;
116873152f19c0be7f31ee05f32878b515a296c487faLeo Duran    }
116973152f19c0be7f31ee05f32878b515a296c487faLeo Duran    else {
117073152f19c0be7f31ee05f32878b515a296c487faLeo Duran      //
117173152f19c0be7f31ee05f32878b515a296c487faLeo Duran      // Must be a single-core processor.
117273152f19c0be7f31ee05f32878b515a296c487faLeo Duran      //
117373152f19c0be7f31ee05f32878b515a296c487faLeo Duran      MaxCoresPerPackage = 1;
117473152f19c0be7f31ee05f32878b515a296c487faLeo Duran    }
117573152f19c0be7f31ee05f32878b515a296c487faLeo Duran
117673152f19c0be7f31ee05f32878b515a296c487faLeo Duran    ThreadBits = (UINTN)(HighBitSet32(MaxLogicProcessorsPerPackage / MaxCoresPerPackage - 1) + 1);
117773152f19c0be7f31ee05f32878b515a296c487faLeo Duran    CoreBits = (UINTN)(HighBitSet32(MaxCoresPerPackage - 1) + 1);  }
117873152f19c0be7f31ee05f32878b515a296c487faLeo Duran
117973152f19c0be7f31ee05f32878b515a296c487faLeo Duran  if (Thread != NULL) {
118073152f19c0be7f31ee05f32878b515a296c487faLeo Duran    *Thread  = InitialApicId & ((1 << ThreadBits) - 1);
118173152f19c0be7f31ee05f32878b515a296c487faLeo Duran  }
118273152f19c0be7f31ee05f32878b515a296c487faLeo Duran  if (Core != NULL) {
118373152f19c0be7f31ee05f32878b515a296c487faLeo Duran    *Core    = (InitialApicId >> ThreadBits) & ((1 << CoreBits) - 1);
118473152f19c0be7f31ee05f32878b515a296c487faLeo Duran  }
118573152f19c0be7f31ee05f32878b515a296c487faLeo Duran  if (Package != NULL) {
118673152f19c0be7f31ee05f32878b515a296c487faLeo Duran    *Package = (InitialApicId >> (ThreadBits + CoreBits));
118773152f19c0be7f31ee05f32878b515a296c487faLeo Duran  }
118873152f19c0be7f31ee05f32878b515a296c487faLeo Duran}
1189