]> git.proxmox.com Git - mirror_edk2.git/blame - UefiCpuPkg/Library/BaseXApicX2ApicLib/BaseXApicX2ApicLib.c
UefiCpuPkg: Support TDX in BaseXApicX2ApicLib
[mirror_edk2.git] / UefiCpuPkg / Library / BaseXApicX2ApicLib / BaseXApicX2ApicLib.c
CommitLineData
bf73cc4b 1/** @file\r
2 Local APIC Library.\r
3\r
4 This local APIC library instance supports x2APIC capable processors\r
5 which have xAPIC and x2APIC modes.\r
6\r
7f33d4f2 7 Copyright (c) 2010 - 2019, Intel Corporation. All rights reserved.<BR>\r
df667535 8 Copyright (c) 2017 - 2020, AMD Inc. All rights reserved.<BR>\r
061ead7a 9\r
0acd8697 10 SPDX-License-Identifier: BSD-2-Clause-Patent\r
bf73cc4b 11\r
12**/\r
13\r
01acb06c 14#include <Register/Intel/Cpuid.h>\r
061ead7a 15#include <Register/Amd/Cpuid.h>\r
01acb06c
RN
16#include <Register/Intel/Msr.h>\r
17#include <Register/Intel/LocalApic.h>\r
bf73cc4b 18\r
19#include <Library/BaseLib.h>\r
20#include <Library/DebugLib.h>\r
21#include <Library/LocalApicLib.h>\r
22#include <Library/IoLib.h>\r
23#include <Library/TimerLib.h>\r
e9cd66d0 24#include <Library/PcdLib.h>\r
df667535 25#include <Library/UefiCpuLib.h>\r
7bed7ae6 26#include <IndustryStandard/Tdx.h>\r
bf73cc4b 27\r
28//\r
29// Library internal functions\r
30//\r
31\r
7bed7ae6
MX
32/**\r
33 Some MSRs in TDX are accessed via TdCall.\r
34 Some are directly read/write from/to CPU.\r
35\r
36 @param MsrIndex Index of the MSR\r
37 @retval TRUE MSR accessed via TdCall.\r
38 @retval FALSE MSR accessed not via TdCall.\r
39\r
40**/\r
41BOOLEAN\r
42AccessMsrTdxCall (\r
43 IN UINT32 MsrIndex\r
44 )\r
45{\r
46 if (!TdIsEnabled ()) {\r
47 return FALSE;\r
48 }\r
49\r
50 switch (MsrIndex) {\r
51 case MSR_IA32_X2APIC_TPR:\r
52 case MSR_IA32_X2APIC_PPR:\r
53 case MSR_IA32_X2APIC_EOI:\r
54 case MSR_IA32_X2APIC_ISR0:\r
55 case MSR_IA32_X2APIC_ISR1:\r
56 case MSR_IA32_X2APIC_ISR2:\r
57 case MSR_IA32_X2APIC_ISR3:\r
58 case MSR_IA32_X2APIC_ISR4:\r
59 case MSR_IA32_X2APIC_ISR5:\r
60 case MSR_IA32_X2APIC_ISR6:\r
61 case MSR_IA32_X2APIC_ISR7:\r
62 case MSR_IA32_X2APIC_TMR0:\r
63 case MSR_IA32_X2APIC_TMR1:\r
64 case MSR_IA32_X2APIC_TMR2:\r
65 case MSR_IA32_X2APIC_TMR3:\r
66 case MSR_IA32_X2APIC_TMR4:\r
67 case MSR_IA32_X2APIC_TMR5:\r
68 case MSR_IA32_X2APIC_TMR6:\r
69 case MSR_IA32_X2APIC_TMR7:\r
70 case MSR_IA32_X2APIC_IRR0:\r
71 case MSR_IA32_X2APIC_IRR1:\r
72 case MSR_IA32_X2APIC_IRR2:\r
73 case MSR_IA32_X2APIC_IRR3:\r
74 case MSR_IA32_X2APIC_IRR4:\r
75 case MSR_IA32_X2APIC_IRR5:\r
76 case MSR_IA32_X2APIC_IRR6:\r
77 case MSR_IA32_X2APIC_IRR7:\r
78 return FALSE;\r
79 default:\r
80 break;\r
81 }\r
82\r
83 return TRUE;\r
84}\r
85\r
86/**\r
87 Read MSR value.\r
88\r
89 @param MsrIndex Index of the MSR to read\r
90 @retval 64-bit Value of MSR.\r
91\r
92**/\r
93UINT64\r
94LocalApicReadMsrReg64 (\r
95 IN UINT32 MsrIndex\r
96 )\r
97{\r
98 UINT64 Val;\r
99 UINT64 Status;\r
100\r
101 if (AccessMsrTdxCall (MsrIndex)) {\r
102 Status = TdVmCall (TDVMCALL_RDMSR, (UINT64)MsrIndex, 0, 0, 0, &Val);\r
103 if (Status != 0) {\r
104 TdVmCall (TDVMCALL_HALT, 0, 0, 0, 0, 0);\r
105 }\r
106 } else {\r
107 Val = AsmReadMsr64 (MsrIndex);\r
108 }\r
109\r
110 return Val;\r
111}\r
112\r
113/**\r
114 Write to MSR.\r
115\r
116 @param MsrIndex Index of the MSR to write to\r
117 @param Value Value to be written to the MSR\r
118\r
119 @return Value\r
120\r
121**/\r
122UINT64\r
123LocalApicWriteMsrReg64 (\r
124 IN UINT32 MsrIndex,\r
125 IN UINT64 Value\r
126 )\r
127{\r
128 UINT64 Status;\r
129\r
130 if (AccessMsrTdxCall (MsrIndex)) {\r
131 Status = TdVmCall (TDVMCALL_WRMSR, (UINT64)MsrIndex, Value, 0, 0, 0);\r
132 if (Status != 0) {\r
133 TdVmCall (TDVMCALL_HALT, 0, 0, 0, 0, 0);\r
134 }\r
135 } else {\r
136 AsmWriteMsr64 (MsrIndex, Value);\r
137 }\r
138\r
139 return Value;\r
140}\r
141\r
142/**\r
143 Read MSR value.\r
144\r
145 @param MsrIndex Index of the MSR to read\r
146 @retval 32-bit Value of MSR.\r
147\r
148**/\r
149UINT32\r
150LocalApicReadMsrReg32 (\r
151 IN UINT32 MsrIndex\r
152 )\r
153{\r
154 return (UINT32)LocalApicReadMsrReg64 (MsrIndex);\r
155}\r
156\r
157/**\r
158 Write to MSR.\r
159\r
160 @param MsrIndex Index of the MSR to write to\r
161 @param Value Value to be written to the MSR\r
162\r
163 @return Value\r
164\r
165**/\r
166UINT32\r
167LocalApicWriteMsrReg32 (\r
168 IN UINT32 MsrIndex,\r
169 IN UINT32 Value\r
170 )\r
171{\r
172 return (UINT32)LocalApicWriteMsrReg64 (MsrIndex, Value);\r
173}\r
174\r
e9cd66d0
MK
175/**\r
176 Determine if the CPU supports the Local APIC Base Address MSR.\r
177\r
178 @retval TRUE The CPU supports the Local APIC Base Address MSR.\r
179 @retval FALSE The CPU does not support the Local APIC Base Address MSR.\r
180\r
181**/\r
182BOOLEAN\r
183LocalApicBaseAddressMsrSupported (\r
184 VOID\r
185 )\r
186{\r
187 UINT32 RegEax;\r
188 UINTN FamilyId;\r
7367cc6c 189\r
e9cd66d0
MK
190 AsmCpuid (1, &RegEax, NULL, NULL, NULL);\r
191 FamilyId = BitFieldRead32 (RegEax, 8, 11);\r
053e878b 192 if ((FamilyId == 0x04) || (FamilyId == 0x05)) {\r
e9cd66d0 193 //\r
7367cc6c 194 // CPUs with a FamilyId of 0x04 or 0x05 do not support the\r
e9cd66d0
MK
195 // Local APIC Base Address MSR\r
196 //\r
197 return FALSE;\r
198 }\r
053e878b 199\r
e9cd66d0
MK
200 return TRUE;\r
201}\r
202\r
a66e0c7d 203/**\r
204 Retrieve the base address of local APIC.\r
205\r
206 @return The base address of local APIC.\r
207\r
208**/\r
209UINTN\r
210EFIAPI\r
211GetLocalApicBaseAddress (\r
212 VOID\r
213 )\r
214{\r
a742e186 215 MSR_IA32_APIC_BASE_REGISTER ApicBaseMsr;\r
e9cd66d0
MK
216\r
217 if (!LocalApicBaseAddressMsrSupported ()) {\r
218 //\r
219 // If CPU does not support Local APIC Base Address MSR, then retrieve\r
220 // Local APIC Base Address from PCD\r
221 //\r
222 return PcdGet32 (PcdCpuLocalApicBaseAddress);\r
223 }\r
224\r
7bed7ae6 225 ApicBaseMsr.Uint64 = LocalApicReadMsrReg64 (MSR_IA32_APIC_BASE);\r
7367cc6c 226\r
053e878b
MK
227 return (UINTN)(LShiftU64 ((UINT64)ApicBaseMsr.Bits.ApicBaseHi, 32)) +\r
228 (((UINTN)ApicBaseMsr.Bits.ApicBase) << 12);\r
a66e0c7d 229}\r
230\r
231/**\r
232 Set the base address of local APIC.\r
233\r
234 If BaseAddress is not aligned on a 4KB boundary, then ASSERT().\r
235\r
236 @param[in] BaseAddress Local APIC base address to be set.\r
237\r
238**/\r
239VOID\r
240EFIAPI\r
241SetLocalApicBaseAddress (\r
053e878b 242 IN UINTN BaseAddress\r
a66e0c7d 243 )\r
244{\r
a742e186 245 MSR_IA32_APIC_BASE_REGISTER ApicBaseMsr;\r
a66e0c7d 246\r
247 ASSERT ((BaseAddress & (SIZE_4KB - 1)) == 0);\r
248\r
e9cd66d0
MK
249 if (!LocalApicBaseAddressMsrSupported ()) {\r
250 //\r
251 // Ignore set request of the CPU does not support APIC Base Address MSR\r
252 //\r
253 return;\r
254 }\r
255\r
7bed7ae6 256 ApicBaseMsr.Uint64 = LocalApicReadMsrReg64 (MSR_IA32_APIC_BASE);\r
a66e0c7d 257\r
053e878b
MK
258 ApicBaseMsr.Bits.ApicBase = (UINT32)(BaseAddress >> 12);\r
259 ApicBaseMsr.Bits.ApicBaseHi = (UINT32)(RShiftU64 ((UINT64)BaseAddress, 32));\r
a66e0c7d 260\r
7bed7ae6 261 LocalApicWriteMsrReg64 (MSR_IA32_APIC_BASE, ApicBaseMsr.Uint64);\r
a66e0c7d 262}\r
263\r
bf73cc4b 264/**\r
265 Read from a local APIC register.\r
266\r
267 This function reads from a local APIC register either in xAPIC or x2APIC mode.\r
268 It is required that in xAPIC mode wider registers (64-bit or 256-bit) must be\r
269 accessed using multiple 32-bit loads or stores, so this function only performs\r
270 32-bit read.\r
271\r
272 @param MmioOffset The MMIO offset of the local APIC register in xAPIC mode.\r
273 It must be 16-byte aligned.\r
274\r
275 @return 32-bit Value read from the register.\r
276**/\r
277UINT32\r
278EFIAPI\r
279ReadLocalApicReg (\r
280 IN UINTN MmioOffset\r
281 )\r
282{\r
053e878b 283 UINT32 MsrIndex;\r
bf73cc4b 284\r
285 ASSERT ((MmioOffset & 0xf) == 0);\r
286\r
287 if (GetApicMode () == LOCAL_APIC_MODE_XAPIC) {\r
053e878b 288 return MmioRead32 (GetLocalApicBaseAddress () + MmioOffset);\r
bf73cc4b 289 } else {\r
290 //\r
291 // DFR is not supported in x2APIC mode.\r
292 //\r
293 ASSERT (MmioOffset != XAPIC_ICR_DFR_OFFSET);\r
294 //\r
295 // Note that in x2APIC mode, ICR is a 64-bit MSR that needs special treatment. It\r
296 // is not supported in this function for simplicity.\r
297 //\r
298 ASSERT (MmioOffset != XAPIC_ICR_HIGH_OFFSET);\r
299\r
300 MsrIndex = (UINT32)(MmioOffset >> 4) + X2APIC_MSR_BASE_ADDRESS;\r
7bed7ae6 301 return LocalApicReadMsrReg32 (MsrIndex);\r
bf73cc4b 302 }\r
303}\r
304\r
305/**\r
306 Write to a local APIC register.\r
307\r
308 This function writes to a local APIC register either in xAPIC or x2APIC mode.\r
309 It is required that in xAPIC mode wider registers (64-bit or 256-bit) must be\r
310 accessed using multiple 32-bit loads or stores, so this function only performs\r
311 32-bit write.\r
312\r
313 if the register index is invalid or unsupported in current APIC mode, then ASSERT.\r
314\r
315 @param MmioOffset The MMIO offset of the local APIC register in xAPIC mode.\r
316 It must be 16-byte aligned.\r
317 @param Value Value to be written to the register.\r
318**/\r
319VOID\r
320EFIAPI\r
321WriteLocalApicReg (\r
053e878b
MK
322 IN UINTN MmioOffset,\r
323 IN UINT32 Value\r
bf73cc4b 324 )\r
325{\r
053e878b 326 UINT32 MsrIndex;\r
bf73cc4b 327\r
328 ASSERT ((MmioOffset & 0xf) == 0);\r
329\r
330 if (GetApicMode () == LOCAL_APIC_MODE_XAPIC) {\r
053e878b 331 MmioWrite32 (GetLocalApicBaseAddress () + MmioOffset, Value);\r
bf73cc4b 332 } else {\r
333 //\r
334 // DFR is not supported in x2APIC mode.\r
335 //\r
336 ASSERT (MmioOffset != XAPIC_ICR_DFR_OFFSET);\r
337 //\r
338 // Note that in x2APIC mode, ICR is a 64-bit MSR that needs special treatment. It\r
339 // is not supported in this function for simplicity.\r
340 //\r
341 ASSERT (MmioOffset != XAPIC_ICR_HIGH_OFFSET);\r
342 ASSERT (MmioOffset != XAPIC_ICR_LOW_OFFSET);\r
343\r
344 MsrIndex = (UINT32)(MmioOffset >> 4) + X2APIC_MSR_BASE_ADDRESS;\r
345 //\r
346 // The serializing semantics of WRMSR are relaxed when writing to the APIC registers.\r
347 // Use memory fence here to force the serializing semantics to be consisent with xAPIC mode.\r
348 //\r
349 MemoryFence ();\r
7bed7ae6 350 LocalApicWriteMsrReg32 (MsrIndex, Value);\r
bf73cc4b 351 }\r
352}\r
353\r
354/**\r
355 Send an IPI by writing to ICR.\r
356\r
7367cc6c 357 This function returns after the IPI has been accepted by the target processor.\r
bf73cc4b 358\r
359 @param IcrLow 32-bit value to be written to the low half of ICR.\r
360 @param ApicId APIC ID of the target processor if this IPI is targeted for a specific processor.\r
361**/\r
362VOID\r
363SendIpi (\r
053e878b
MK
364 IN UINT32 IcrLow,\r
365 IN UINT32 ApicId\r
bf73cc4b 366 )\r
367{\r
053e878b
MK
368 UINT64 MsrValue;\r
369 LOCAL_APIC_ICR_LOW IcrLowReg;\r
370 UINTN LocalApciBaseAddress;\r
371 UINT32 IcrHigh;\r
372 BOOLEAN InterruptState;\r
bf73cc4b 373\r
9c71e1e0
JF
374 //\r
375 // Legacy APIC or X2APIC?\r
376 //\r
bf73cc4b 377 if (GetApicMode () == LOCAL_APIC_MODE_XAPIC) {\r
378 ASSERT (ApicId <= 0xff);\r
379\r
9c71e1e0
JF
380 InterruptState = SaveAndDisableInterrupts ();\r
381\r
bf73cc4b 382 //\r
9c71e1e0 383 // Get base address of this LAPIC\r
bf73cc4b 384 //\r
053e878b 385 LocalApciBaseAddress = GetLocalApicBaseAddress ();\r
9c71e1e0
JF
386\r
387 //\r
388 // Save existing contents of ICR high 32 bits\r
389 //\r
390 IcrHigh = MmioRead32 (LocalApciBaseAddress + XAPIC_ICR_HIGH_OFFSET);\r
391\r
392 //\r
393 // Wait for DeliveryStatus clear in case a previous IPI\r
394 // is still being sent\r
395 //\r
396 do {\r
397 IcrLowReg.Uint32 = MmioRead32 (LocalApciBaseAddress + XAPIC_ICR_LOW_OFFSET);\r
398 } while (IcrLowReg.Bits.DeliveryStatus != 0);\r
399\r
400 //\r
401 // For xAPIC, the act of writing to the low doubleword of the ICR causes the IPI to be sent.\r
402 //\r
a66e0c7d 403 MmioWrite32 (LocalApciBaseAddress + XAPIC_ICR_HIGH_OFFSET, ApicId << 24);\r
404 MmioWrite32 (LocalApciBaseAddress + XAPIC_ICR_LOW_OFFSET, IcrLow);\r
9c71e1e0
JF
405\r
406 //\r
407 // Wait for DeliveryStatus clear again\r
408 //\r
bf73cc4b 409 do {\r
a66e0c7d 410 IcrLowReg.Uint32 = MmioRead32 (LocalApciBaseAddress + XAPIC_ICR_LOW_OFFSET);\r
bf73cc4b 411 } while (IcrLowReg.Bits.DeliveryStatus != 0);\r
9c71e1e0
JF
412\r
413 //\r
414 // And restore old contents of ICR high\r
415 //\r
416 MmioWrite32 (LocalApciBaseAddress + XAPIC_ICR_HIGH_OFFSET, IcrHigh);\r
417\r
418 SetInterruptState (InterruptState);\r
bf73cc4b 419 } else {\r
420 //\r
7367cc6c 421 // For x2APIC, A single MSR write to the Interrupt Command Register is required for dispatching an\r
bf73cc4b 422 // interrupt in x2APIC mode.\r
423 //\r
053e878b 424 MsrValue = LShiftU64 ((UINT64)ApicId, 32) | IcrLow;\r
bf73cc4b 425 AsmWriteMsr64 (X2APIC_MSR_ICR_ADDRESS, MsrValue);\r
426 }\r
427}\r
428\r
429//\r
430// Library API implementation functions\r
431//\r
432\r
433/**\r
434 Get the current local APIC mode.\r
435\r
436 If local APIC is disabled, then ASSERT.\r
437\r
438 @retval LOCAL_APIC_MODE_XAPIC current APIC mode is xAPIC.\r
439 @retval LOCAL_APIC_MODE_X2APIC current APIC mode is x2APIC.\r
440**/\r
441UINTN\r
442EFIAPI\r
443GetApicMode (\r
444 VOID\r
445 )\r
446{\r
a742e186 447 MSR_IA32_APIC_BASE_REGISTER ApicBaseMsr;\r
e9cd66d0
MK
448\r
449 if (!LocalApicBaseAddressMsrSupported ()) {\r
450 //\r
451 // If CPU does not support APIC Base Address MSR, then return XAPIC mode\r
452 //\r
453 return LOCAL_APIC_MODE_XAPIC;\r
454 }\r
bf73cc4b 455\r
7bed7ae6 456 ApicBaseMsr.Uint64 = LocalApicReadMsrReg64 (MSR_IA32_APIC_BASE);\r
bf73cc4b 457 //\r
458 // Local APIC should have been enabled\r
459 //\r
a742e186
JF
460 ASSERT (ApicBaseMsr.Bits.EN != 0);\r
461 if (ApicBaseMsr.Bits.EXTD != 0) {\r
bf73cc4b 462 return LOCAL_APIC_MODE_X2APIC;\r
463 } else {\r
464 return LOCAL_APIC_MODE_XAPIC;\r
465 }\r
466}\r
467\r
468/**\r
469 Set the current local APIC mode.\r
470\r
471 If the specified local APIC mode is not valid, then ASSERT.\r
472 If the specified local APIC mode can't be set as current, then ASSERT.\r
473\r
474 @param ApicMode APIC mode to be set.\r
9c71e1e0
JF
475\r
476 @note This API must not be called from an interrupt handler or SMI handler.\r
477 It may result in unpredictable behavior.\r
bf73cc4b 478**/\r
479VOID\r
480EFIAPI\r
481SetApicMode (\r
482 IN UINTN ApicMode\r
483 )\r
484{\r
a742e186
JF
485 UINTN CurrentMode;\r
486 MSR_IA32_APIC_BASE_REGISTER ApicBaseMsr;\r
e9cd66d0
MK
487\r
488 if (!LocalApicBaseAddressMsrSupported ()) {\r
489 //\r
490 // Ignore set request if the CPU does not support APIC Base Address MSR\r
491 //\r
492 return;\r
493 }\r
bf73cc4b 494\r
495 CurrentMode = GetApicMode ();\r
496 if (CurrentMode == LOCAL_APIC_MODE_XAPIC) {\r
497 switch (ApicMode) {\r
498 case LOCAL_APIC_MODE_XAPIC:\r
499 break;\r
500 case LOCAL_APIC_MODE_X2APIC:\r
7bed7ae6 501 ApicBaseMsr.Uint64 = LocalApicReadMsrReg64 (MSR_IA32_APIC_BASE);\r
a742e186 502 ApicBaseMsr.Bits.EXTD = 1;\r
7bed7ae6 503 LocalApicWriteMsrReg64 (MSR_IA32_APIC_BASE, ApicBaseMsr.Uint64);\r
bf73cc4b 504 break;\r
505 default:\r
506 ASSERT (FALSE);\r
507 }\r
508 } else {\r
509 switch (ApicMode) {\r
510 case LOCAL_APIC_MODE_XAPIC:\r
511 //\r
512 // Transition from x2APIC mode to xAPIC mode is a two-step process:\r
513 // x2APIC -> Local APIC disabled -> xAPIC\r
514 //\r
053e878b 515 ApicBaseMsr.Uint64 = AsmReadMsr64 (MSR_IA32_APIC_BASE);\r
a742e186 516 ApicBaseMsr.Bits.EXTD = 0;\r
053e878b 517 ApicBaseMsr.Bits.EN = 0;\r
a742e186
JF
518 AsmWriteMsr64 (MSR_IA32_APIC_BASE, ApicBaseMsr.Uint64);\r
519 ApicBaseMsr.Bits.EN = 1;\r
520 AsmWriteMsr64 (MSR_IA32_APIC_BASE, ApicBaseMsr.Uint64);\r
bf73cc4b 521 break;\r
522 case LOCAL_APIC_MODE_X2APIC:\r
523 break;\r
524 default:\r
525 ASSERT (FALSE);\r
526 }\r
527 }\r
528}\r
529\r
530/**\r
531 Get the initial local APIC ID of the executing processor assigned by hardware upon power on or reset.\r
532\r
6e3e4d70 533 In xAPIC mode, the initial local APIC ID may be different from current APIC ID.\r
7367cc6c 534 In x2APIC mode, the local APIC ID can't be changed and there is no concept of initial APIC ID. In this case,\r
bf73cc4b 535 the 32-bit local APIC ID is returned as initial APIC ID.\r
536\r
537 @return 32-bit initial local APIC ID of the executing processor.\r
538**/\r
539UINT32\r
540EFIAPI\r
541GetInitialApicId (\r
542 VOID\r
543 )\r
544{\r
053e878b
MK
545 UINT32 ApicId;\r
546 UINT32 MaxCpuIdIndex;\r
547 UINT32 RegEbx;\r
bf73cc4b 548\r
549 if (GetApicMode () == LOCAL_APIC_MODE_XAPIC) {\r
6e3e4d70
JF
550 //\r
551 // Get the max index of basic CPUID\r
552 //\r
553 AsmCpuid (CPUID_SIGNATURE, &MaxCpuIdIndex, NULL, NULL, NULL);\r
554 //\r
7367cc6c 555 // If CPUID Leaf B is supported,\r
4af3ae14 556 // And CPUID.0BH:EBX[15:0] reports a non-zero value,\r
6e3e4d70
JF
557 // Then the initial 32-bit APIC ID = CPUID.0BH:EDX\r
558 // Else the initial 8-bit APIC ID = CPUID.1:EBX[31:24]\r
559 //\r
560 if (MaxCpuIdIndex >= CPUID_EXTENDED_TOPOLOGY) {\r
4af3ae14
LE
561 AsmCpuidEx (CPUID_EXTENDED_TOPOLOGY, 0, NULL, &RegEbx, NULL, &ApicId);\r
562 if ((RegEbx & (BIT16 - 1)) != 0) {\r
563 return ApicId;\r
564 }\r
6e3e4d70 565 }\r
053e878b 566\r
bf73cc4b 567 AsmCpuid (CPUID_VERSION_INFO, NULL, &RegEbx, NULL, NULL);\r
568 return RegEbx >> 24;\r
569 } else {\r
570 return GetApicId ();\r
571 }\r
572}\r
573\r
574/**\r
575 Get the local APIC ID of the executing processor.\r
576\r
577 @return 32-bit local APIC ID of the executing processor.\r
578**/\r
579UINT32\r
580EFIAPI\r
581GetApicId (\r
582 VOID\r
583 )\r
584{\r
053e878b
MK
585 UINT32 ApicId;\r
586 UINT32 InitApicId;\r
bf73cc4b 587\r
588 ApicId = ReadLocalApicReg (XAPIC_ID_OFFSET);\r
589 if (GetApicMode () == LOCAL_APIC_MODE_XAPIC) {\r
6e3e4d70 590 ApicId = ((InitApicId = GetInitialApicId ()) < 0x100) ? (ApicId >> 24) : InitApicId;\r
bf73cc4b 591 }\r
6e3e4d70 592\r
bf73cc4b 593 return ApicId;\r
594}\r
595\r
ae40aef1 596/**\r
597 Get the value of the local APIC version register.\r
598\r
599 @return the value of the local APIC version register.\r
600**/\r
601UINT32\r
602EFIAPI\r
603GetApicVersion (\r
604 VOID\r
605 )\r
606{\r
607 return ReadLocalApicReg (XAPIC_VERSION_OFFSET);\r
608}\r
609\r
610/**\r
611 Send a Fixed IPI to a specified target processor.\r
612\r
7367cc6c 613 This function returns after the IPI has been accepted by the target processor.\r
ae40aef1 614\r
615 @param ApicId The local APIC ID of the target processor.\r
616 @param Vector The vector number of the interrupt being sent.\r
617**/\r
618VOID\r
619EFIAPI\r
620SendFixedIpi (\r
053e878b
MK
621 IN UINT32 ApicId,\r
622 IN UINT8 Vector\r
ae40aef1 623 )\r
624{\r
053e878b 625 LOCAL_APIC_ICR_LOW IcrLow;\r
ae40aef1 626\r
053e878b 627 IcrLow.Uint32 = 0;\r
ae40aef1 628 IcrLow.Bits.DeliveryMode = LOCAL_APIC_DELIVERY_MODE_FIXED;\r
053e878b
MK
629 IcrLow.Bits.Level = 1;\r
630 IcrLow.Bits.Vector = Vector;\r
ae40aef1 631 SendIpi (IcrLow.Uint32, ApicId);\r
632}\r
633\r
634/**\r
635 Send a Fixed IPI to all processors excluding self.\r
636\r
7367cc6c 637 This function returns after the IPI has been accepted by the target processors.\r
ae40aef1 638\r
639 @param Vector The vector number of the interrupt being sent.\r
640**/\r
641VOID\r
642EFIAPI\r
643SendFixedIpiAllExcludingSelf (\r
053e878b 644 IN UINT8 Vector\r
ae40aef1 645 )\r
646{\r
053e878b 647 LOCAL_APIC_ICR_LOW IcrLow;\r
ae40aef1 648\r
053e878b
MK
649 IcrLow.Uint32 = 0;\r
650 IcrLow.Bits.DeliveryMode = LOCAL_APIC_DELIVERY_MODE_FIXED;\r
651 IcrLow.Bits.Level = 1;\r
ae40aef1 652 IcrLow.Bits.DestinationShorthand = LOCAL_APIC_DESTINATION_SHORTHAND_ALL_EXCLUDING_SELF;\r
053e878b 653 IcrLow.Bits.Vector = Vector;\r
ae40aef1 654 SendIpi (IcrLow.Uint32, 0);\r
655}\r
656\r
bf73cc4b 657/**\r
658 Send a SMI IPI to a specified target processor.\r
659\r
7367cc6c 660 This function returns after the IPI has been accepted by the target processor.\r
bf73cc4b 661\r
662 @param ApicId Specify the local APIC ID of the target processor.\r
663**/\r
664VOID\r
665EFIAPI\r
666SendSmiIpi (\r
053e878b 667 IN UINT32 ApicId\r
bf73cc4b 668 )\r
669{\r
053e878b 670 LOCAL_APIC_ICR_LOW IcrLow;\r
bf73cc4b 671\r
053e878b 672 IcrLow.Uint32 = 0;\r
bf73cc4b 673 IcrLow.Bits.DeliveryMode = LOCAL_APIC_DELIVERY_MODE_SMI;\r
053e878b 674 IcrLow.Bits.Level = 1;\r
bf73cc4b 675 SendIpi (IcrLow.Uint32, ApicId);\r
676}\r
677\r
678/**\r
679 Send a SMI IPI to all processors excluding self.\r
680\r
7367cc6c 681 This function returns after the IPI has been accepted by the target processors.\r
bf73cc4b 682**/\r
683VOID\r
684EFIAPI\r
685SendSmiIpiAllExcludingSelf (\r
686 VOID\r
687 )\r
688{\r
053e878b 689 LOCAL_APIC_ICR_LOW IcrLow;\r
bf73cc4b 690\r
053e878b
MK
691 IcrLow.Uint32 = 0;\r
692 IcrLow.Bits.DeliveryMode = LOCAL_APIC_DELIVERY_MODE_SMI;\r
693 IcrLow.Bits.Level = 1;\r
bf73cc4b 694 IcrLow.Bits.DestinationShorthand = LOCAL_APIC_DESTINATION_SHORTHAND_ALL_EXCLUDING_SELF;\r
695 SendIpi (IcrLow.Uint32, 0);\r
696}\r
697\r
698/**\r
699 Send an INIT IPI to a specified target processor.\r
700\r
7367cc6c 701 This function returns after the IPI has been accepted by the target processor.\r
bf73cc4b 702\r
703 @param ApicId Specify the local APIC ID of the target processor.\r
704**/\r
705VOID\r
706EFIAPI\r
707SendInitIpi (\r
053e878b 708 IN UINT32 ApicId\r
bf73cc4b 709 )\r
710{\r
053e878b 711 LOCAL_APIC_ICR_LOW IcrLow;\r
bf73cc4b 712\r
053e878b 713 IcrLow.Uint32 = 0;\r
bf73cc4b 714 IcrLow.Bits.DeliveryMode = LOCAL_APIC_DELIVERY_MODE_INIT;\r
053e878b 715 IcrLow.Bits.Level = 1;\r
bf73cc4b 716 SendIpi (IcrLow.Uint32, ApicId);\r
717}\r
718\r
719/**\r
720 Send an INIT IPI to all processors excluding self.\r
721\r
7367cc6c 722 This function returns after the IPI has been accepted by the target processors.\r
bf73cc4b 723**/\r
724VOID\r
725EFIAPI\r
726SendInitIpiAllExcludingSelf (\r
727 VOID\r
728 )\r
729{\r
053e878b 730 LOCAL_APIC_ICR_LOW IcrLow;\r
bf73cc4b 731\r
053e878b
MK
732 IcrLow.Uint32 = 0;\r
733 IcrLow.Bits.DeliveryMode = LOCAL_APIC_DELIVERY_MODE_INIT;\r
734 IcrLow.Bits.Level = 1;\r
bf73cc4b 735 IcrLow.Bits.DestinationShorthand = LOCAL_APIC_DESTINATION_SHORTHAND_ALL_EXCLUDING_SELF;\r
736 SendIpi (IcrLow.Uint32, 0);\r
737}\r
738\r
739/**\r
740 Send an INIT-Start-up-Start-up IPI sequence to a specified target processor.\r
741\r
7367cc6c 742 This function returns after the IPI has been accepted by the target processor.\r
bf73cc4b 743\r
744 if StartupRoutine >= 1M, then ASSERT.\r
745 if StartupRoutine is not multiple of 4K, then ASSERT.\r
746\r
747 @param ApicId Specify the local APIC ID of the target processor.\r
748 @param StartupRoutine Points to a start-up routine which is below 1M physical\r
749 address and 4K aligned.\r
750**/\r
751VOID\r
752EFIAPI\r
753SendInitSipiSipi (\r
053e878b
MK
754 IN UINT32 ApicId,\r
755 IN UINT32 StartupRoutine\r
bf73cc4b 756 )\r
757{\r
053e878b 758 LOCAL_APIC_ICR_LOW IcrLow;\r
bf73cc4b 759\r
760 ASSERT (StartupRoutine < 0x100000);\r
761 ASSERT ((StartupRoutine & 0xfff) == 0);\r
762\r
763 SendInitIpi (ApicId);\r
053e878b
MK
764 MicroSecondDelay (PcdGet32 (PcdCpuInitIpiDelayInMicroSeconds));\r
765 IcrLow.Uint32 = 0;\r
766 IcrLow.Bits.Vector = (StartupRoutine >> 12);\r
bf73cc4b 767 IcrLow.Bits.DeliveryMode = LOCAL_APIC_DELIVERY_MODE_STARTUP;\r
053e878b 768 IcrLow.Bits.Level = 1;\r
bf73cc4b 769 SendIpi (IcrLow.Uint32, ApicId);\r
bf252e29
ED
770 if (!StandardSignatureIsAuthenticAMD ()) {\r
771 MicroSecondDelay (200);\r
772 SendIpi (IcrLow.Uint32, ApicId);\r
773 }\r
bf73cc4b 774}\r
775\r
776/**\r
777 Send an INIT-Start-up-Start-up IPI sequence to all processors excluding self.\r
778\r
7367cc6c 779 This function returns after the IPI has been accepted by the target processors.\r
bf73cc4b 780\r
781 if StartupRoutine >= 1M, then ASSERT.\r
782 if StartupRoutine is not multiple of 4K, then ASSERT.\r
783\r
784 @param StartupRoutine Points to a start-up routine which is below 1M physical\r
785 address and 4K aligned.\r
786**/\r
787VOID\r
788EFIAPI\r
789SendInitSipiSipiAllExcludingSelf (\r
053e878b 790 IN UINT32 StartupRoutine\r
bf73cc4b 791 )\r
792{\r
053e878b 793 LOCAL_APIC_ICR_LOW IcrLow;\r
bf73cc4b 794\r
795 ASSERT (StartupRoutine < 0x100000);\r
796 ASSERT ((StartupRoutine & 0xfff) == 0);\r
797\r
798 SendInitIpiAllExcludingSelf ();\r
053e878b
MK
799 MicroSecondDelay (PcdGet32 (PcdCpuInitIpiDelayInMicroSeconds));\r
800 IcrLow.Uint32 = 0;\r
801 IcrLow.Bits.Vector = (StartupRoutine >> 12);\r
802 IcrLow.Bits.DeliveryMode = LOCAL_APIC_DELIVERY_MODE_STARTUP;\r
803 IcrLow.Bits.Level = 1;\r
bf73cc4b 804 IcrLow.Bits.DestinationShorthand = LOCAL_APIC_DESTINATION_SHORTHAND_ALL_EXCLUDING_SELF;\r
805 SendIpi (IcrLow.Uint32, 0);\r
bf252e29
ED
806 if (!StandardSignatureIsAuthenticAMD ()) {\r
807 MicroSecondDelay (200);\r
808 SendIpi (IcrLow.Uint32, 0);\r
809 }\r
bf73cc4b 810}\r
811\r
14e4ca25
MK
812/**\r
813 Initialize the state of the SoftwareEnable bit in the Local APIC\r
814 Spurious Interrupt Vector register.\r
815\r
816 @param Enable If TRUE, then set SoftwareEnable to 1\r
817 If FALSE, then set SoftwareEnable to 0.\r
818\r
819**/\r
820VOID\r
821EFIAPI\r
822InitializeLocalApicSoftwareEnable (\r
823 IN BOOLEAN Enable\r
824 )\r
825{\r
826 LOCAL_APIC_SVR Svr;\r
827\r
828 //\r
829 // Set local APIC software-enabled bit.\r
830 //\r
831 Svr.Uint32 = ReadLocalApicReg (XAPIC_SPURIOUS_VECTOR_OFFSET);\r
832 if (Enable) {\r
833 if (Svr.Bits.SoftwareEnable == 0) {\r
834 Svr.Bits.SoftwareEnable = 1;\r
835 WriteLocalApicReg (XAPIC_SPURIOUS_VECTOR_OFFSET, Svr.Uint32);\r
836 }\r
837 } else {\r
838 if (Svr.Bits.SoftwareEnable == 1) {\r
839 Svr.Bits.SoftwareEnable = 0;\r
840 WriteLocalApicReg (XAPIC_SPURIOUS_VECTOR_OFFSET, Svr.Uint32);\r
841 }\r
842 }\r
843}\r
844\r
bf73cc4b 845/**\r
846 Programming Virtual Wire Mode.\r
847\r
848 This function programs the local APIC for virtual wire mode following\r
849 the example described in chapter A.3 of the MP 1.4 spec.\r
850\r
851 IOxAPIC is not involved in this type of virtual wire mode.\r
852**/\r
853VOID\r
854EFIAPI\r
855ProgramVirtualWireMode (\r
856 VOID\r
857 )\r
858{\r
053e878b
MK
859 LOCAL_APIC_SVR Svr;\r
860 LOCAL_APIC_LVT_LINT Lint;\r
bf73cc4b 861\r
862 //\r
863 // Enable the APIC via SVR and set the spurious interrupt to use Int 00F.\r
864 //\r
053e878b 865 Svr.Uint32 = ReadLocalApicReg (XAPIC_SPURIOUS_VECTOR_OFFSET);\r
bf73cc4b 866 Svr.Bits.SpuriousVector = 0xf;\r
867 Svr.Bits.SoftwareEnable = 1;\r
868 WriteLocalApicReg (XAPIC_SPURIOUS_VECTOR_OFFSET, Svr.Uint32);\r
869\r
870 //\r
871 // Program the LINT0 vector entry as ExtInt. Not masked, edge, active high.\r
872 //\r
053e878b
MK
873 Lint.Uint32 = ReadLocalApicReg (XAPIC_LVT_LINT0_OFFSET);\r
874 Lint.Bits.DeliveryMode = LOCAL_APIC_DELIVERY_MODE_EXTINT;\r
bf73cc4b 875 Lint.Bits.InputPinPolarity = 0;\r
053e878b
MK
876 Lint.Bits.TriggerMode = 0;\r
877 Lint.Bits.Mask = 0;\r
ae40aef1 878 WriteLocalApicReg (XAPIC_LVT_LINT0_OFFSET, Lint.Uint32);\r
bf73cc4b 879\r
880 //\r
881 // Program the LINT0 vector entry as NMI. Not masked, edge, active high.\r
882 //\r
053e878b
MK
883 Lint.Uint32 = ReadLocalApicReg (XAPIC_LVT_LINT1_OFFSET);\r
884 Lint.Bits.DeliveryMode = LOCAL_APIC_DELIVERY_MODE_NMI;\r
bf73cc4b 885 Lint.Bits.InputPinPolarity = 0;\r
053e878b
MK
886 Lint.Bits.TriggerMode = 0;\r
887 Lint.Bits.Mask = 0;\r
ae40aef1 888 WriteLocalApicReg (XAPIC_LVT_LINT1_OFFSET, Lint.Uint32);\r
bf73cc4b 889}\r
890\r
b1b8c631 891/**\r
892 Disable LINT0 & LINT1 interrupts.\r
893\r
894 This function sets the mask flag in the LVT LINT0 & LINT1 registers.\r
895**/\r
896VOID\r
897EFIAPI\r
898DisableLvtInterrupts (\r
899 VOID\r
900 )\r
901{\r
053e878b 902 LOCAL_APIC_LVT_LINT LvtLint;\r
b1b8c631 903\r
053e878b 904 LvtLint.Uint32 = ReadLocalApicReg (XAPIC_LVT_LINT0_OFFSET);\r
b1b8c631 905 LvtLint.Bits.Mask = 1;\r
906 WriteLocalApicReg (XAPIC_LVT_LINT0_OFFSET, LvtLint.Uint32);\r
907\r
053e878b 908 LvtLint.Uint32 = ReadLocalApicReg (XAPIC_LVT_LINT1_OFFSET);\r
b1b8c631 909 LvtLint.Bits.Mask = 1;\r
910 WriteLocalApicReg (XAPIC_LVT_LINT1_OFFSET, LvtLint.Uint32);\r
911}\r
912\r
bf73cc4b 913/**\r
914 Read the initial count value from the init-count register.\r
915\r
916 @return The initial count value read from the init-count register.\r
917**/\r
918UINT32\r
919EFIAPI\r
920GetApicTimerInitCount (\r
921 VOID\r
922 )\r
923{\r
924 return ReadLocalApicReg (XAPIC_TIMER_INIT_COUNT_OFFSET);\r
925}\r
926\r
927/**\r
928 Read the current count value from the current-count register.\r
929\r
930 @return The current count value read from the current-count register.\r
931**/\r
932UINT32\r
933EFIAPI\r
934GetApicTimerCurrentCount (\r
935 VOID\r
936 )\r
937{\r
938 return ReadLocalApicReg (XAPIC_TIMER_CURRENT_COUNT_OFFSET);\r
939}\r
940\r
941/**\r
942 Initialize the local APIC timer.\r
943\r
944 The local APIC timer is initialized and enabled.\r
945\r
946 @param DivideValue The divide value for the DCR. It is one of 1,2,4,8,16,32,64,128.\r
947 If it is 0, then use the current divide value in the DCR.\r
948 @param InitCount The initial count value.\r
949 @param PeriodicMode If TRUE, timer mode is peridoic. Othewise, timer mode is one-shot.\r
950 @param Vector The timer interrupt vector number.\r
951**/\r
952VOID\r
953EFIAPI\r
954InitializeApicTimer (\r
053e878b
MK
955 IN UINTN DivideValue,\r
956 IN UINT32 InitCount,\r
957 IN BOOLEAN PeriodicMode,\r
958 IN UINT8 Vector\r
bf73cc4b 959 )\r
960{\r
053e878b
MK
961 LOCAL_APIC_DCR Dcr;\r
962 LOCAL_APIC_LVT_TIMER LvtTimer;\r
963 UINT32 Divisor;\r
bf73cc4b 964\r
965 //\r
966 // Ensure local APIC is in software-enabled state.\r
967 //\r
14e4ca25 968 InitializeLocalApicSoftwareEnable (TRUE);\r
bf73cc4b 969\r
970 //\r
971 // Program init-count register.\r
972 //\r
973 WriteLocalApicReg (XAPIC_TIMER_INIT_COUNT_OFFSET, InitCount);\r
974\r
975 if (DivideValue != 0) {\r
976 ASSERT (DivideValue <= 128);\r
053e878b 977 ASSERT (DivideValue == GetPowerOfTwo32 ((UINT32)DivideValue));\r
bf73cc4b 978 Divisor = (UINT32)((HighBitSet32 ((UINT32)DivideValue) - 1) & 0x7);\r
979\r
053e878b 980 Dcr.Uint32 = ReadLocalApicReg (XAPIC_TIMER_DIVIDE_CONFIGURATION_OFFSET);\r
bf73cc4b 981 Dcr.Bits.DivideValue1 = (Divisor & 0x3);\r
982 Dcr.Bits.DivideValue2 = (Divisor >> 2);\r
7367cc6c 983 WriteLocalApicReg (XAPIC_TIMER_DIVIDE_CONFIGURATION_OFFSET, Dcr.Uint32);\r
bf73cc4b 984 }\r
985\r
986 //\r
987 // Enable APIC timer interrupt with specified timer mode.\r
988 //\r
989 LvtTimer.Uint32 = ReadLocalApicReg (XAPIC_LVT_TIMER_OFFSET);\r
990 if (PeriodicMode) {\r
991 LvtTimer.Bits.TimerMode = 1;\r
992 } else {\r
993 LvtTimer.Bits.TimerMode = 0;\r
994 }\r
053e878b
MK
995\r
996 LvtTimer.Bits.Mask = 0;\r
bf73cc4b 997 LvtTimer.Bits.Vector = Vector;\r
998 WriteLocalApicReg (XAPIC_LVT_TIMER_OFFSET, LvtTimer.Uint32);\r
999}\r
1000\r
ae40aef1 1001/**\r
1002 Get the state of the local APIC timer.\r
1003\r
6d72ff7d
HW
1004 This function will ASSERT if the local APIC is not software enabled.\r
1005\r
ae40aef1 1006 @param DivideValue Return the divide value for the DCR. It is one of 1,2,4,8,16,32,64,128.\r
1007 @param PeriodicMode Return the timer mode. If TRUE, timer mode is peridoic. Othewise, timer mode is one-shot.\r
1008 @param Vector Return the timer interrupt vector number.\r
1009**/\r
1010VOID\r
1011EFIAPI\r
1012GetApicTimerState (\r
1013 OUT UINTN *DivideValue OPTIONAL,\r
1014 OUT BOOLEAN *PeriodicMode OPTIONAL,\r
1015 OUT UINT8 *Vector OPTIONAL\r
1016 )\r
1017{\r
053e878b
MK
1018 UINT32 Divisor;\r
1019 LOCAL_APIC_DCR Dcr;\r
1020 LOCAL_APIC_LVT_TIMER LvtTimer;\r
ae40aef1 1021\r
6d72ff7d
HW
1022 //\r
1023 // Check the APIC Software Enable/Disable bit (bit 8) in Spurious-Interrupt\r
1024 // Vector Register.\r
1025 // This bit will be 1, if local APIC is software enabled.\r
1026 //\r
053e878b 1027 ASSERT ((ReadLocalApicReg (XAPIC_SPURIOUS_VECTOR_OFFSET) & BIT8) != 0);\r
6d72ff7d 1028\r
ae40aef1 1029 if (DivideValue != NULL) {\r
053e878b
MK
1030 Dcr.Uint32 = ReadLocalApicReg (XAPIC_TIMER_DIVIDE_CONFIGURATION_OFFSET);\r
1031 Divisor = Dcr.Bits.DivideValue1 | (Dcr.Bits.DivideValue2 << 2);\r
1032 Divisor = (Divisor + 1) & 0x7;\r
ae40aef1 1033 *DivideValue = ((UINTN)1) << Divisor;\r
1034 }\r
1035\r
053e878b 1036 if ((PeriodicMode != NULL) || (Vector != NULL)) {\r
ae40aef1 1037 LvtTimer.Uint32 = ReadLocalApicReg (XAPIC_LVT_TIMER_OFFSET);\r
1038 if (PeriodicMode != NULL) {\r
1039 if (LvtTimer.Bits.TimerMode == 1) {\r
1040 *PeriodicMode = TRUE;\r
1041 } else {\r
1042 *PeriodicMode = FALSE;\r
1043 }\r
1044 }\r
053e878b 1045\r
ae40aef1 1046 if (Vector != NULL) {\r
053e878b 1047 *Vector = (UINT8)LvtTimer.Bits.Vector;\r
ae40aef1 1048 }\r
1049 }\r
1050}\r
1051\r
bf73cc4b 1052/**\r
1053 Enable the local APIC timer interrupt.\r
1054**/\r
1055VOID\r
1056EFIAPI\r
1057EnableApicTimerInterrupt (\r
1058 VOID\r
1059 )\r
1060{\r
053e878b 1061 LOCAL_APIC_LVT_TIMER LvtTimer;\r
bf73cc4b 1062\r
053e878b 1063 LvtTimer.Uint32 = ReadLocalApicReg (XAPIC_LVT_TIMER_OFFSET);\r
bf73cc4b 1064 LvtTimer.Bits.Mask = 0;\r
1065 WriteLocalApicReg (XAPIC_LVT_TIMER_OFFSET, LvtTimer.Uint32);\r
1066}\r
1067\r
1068/**\r
1069 Disable the local APIC timer interrupt.\r
1070**/\r
1071VOID\r
1072EFIAPI\r
1073DisableApicTimerInterrupt (\r
1074 VOID\r
1075 )\r
1076{\r
053e878b 1077 LOCAL_APIC_LVT_TIMER LvtTimer;\r
bf73cc4b 1078\r
053e878b 1079 LvtTimer.Uint32 = ReadLocalApicReg (XAPIC_LVT_TIMER_OFFSET);\r
bf73cc4b 1080 LvtTimer.Bits.Mask = 1;\r
1081 WriteLocalApicReg (XAPIC_LVT_TIMER_OFFSET, LvtTimer.Uint32);\r
1082}\r
1083\r
1084/**\r
1085 Get the local APIC timer interrupt state.\r
1086\r
1087 @retval TRUE The local APIC timer interrupt is enabled.\r
1088 @retval FALSE The local APIC timer interrupt is disabled.\r
1089**/\r
1090BOOLEAN\r
1091EFIAPI\r
1092GetApicTimerInterruptState (\r
1093 VOID\r
1094 )\r
1095{\r
053e878b 1096 LOCAL_APIC_LVT_TIMER LvtTimer;\r
bf73cc4b 1097\r
1098 LvtTimer.Uint32 = ReadLocalApicReg (XAPIC_LVT_TIMER_OFFSET);\r
1099 return (BOOLEAN)(LvtTimer.Bits.Mask == 0);\r
1100}\r
1101\r
1102/**\r
1103 Send EOI to the local APIC.\r
1104**/\r
1105VOID\r
1106EFIAPI\r
1107SendApicEoi (\r
1108 VOID\r
1109 )\r
1110{\r
1111 WriteLocalApicReg (XAPIC_EOI_OFFSET, 0);\r
1112}\r
1113\r
5f867ad0 1114/**\r
7367cc6c 1115 Get the 32-bit address that a device should use to send a Message Signaled\r
5f867ad0 1116 Interrupt (MSI) to the Local APIC of the currently executing processor.\r
1117\r
1118 @return 32-bit address used to send an MSI to the Local APIC.\r
1119**/\r
1120UINT32\r
7367cc6c 1121EFIAPI\r
5f867ad0 1122GetApicMsiAddress (\r
1123 VOID\r
1124 )\r
1125{\r
1126 LOCAL_APIC_MSI_ADDRESS MsiAddress;\r
1127\r
1128 //\r
7367cc6c 1129 // Return address for an MSI interrupt to be delivered only to the APIC ID\r
5f867ad0 1130 // of the currently executing processor.\r
1131 //\r
1132 MsiAddress.Uint32 = 0;\r
1133 MsiAddress.Bits.BaseAddress = 0xFEE;\r
1134 MsiAddress.Bits.DestinationId = GetApicId ();\r
1135 return MsiAddress.Uint32;\r
1136}\r
7367cc6c 1137\r
5f867ad0 1138/**\r
7367cc6c 1139 Get the 64-bit data value that a device should use to send a Message Signaled\r
5f867ad0 1140 Interrupt (MSI) to the Local APIC of the currently executing processor.\r
1141\r
1142 If Vector is not in range 0x10..0xFE, then ASSERT().\r
1143 If DeliveryMode is not supported, then ASSERT().\r
7367cc6c
LG
1144\r
1145 @param Vector The 8-bit interrupt vector associated with the MSI.\r
5f867ad0 1146 Must be in the range 0x10..0xFE\r
7367cc6c 1147 @param DeliveryMode A 3-bit value that specifies how the recept of the MSI\r
5f867ad0 1148 is handled. The only supported values are:\r
1149 0: LOCAL_APIC_DELIVERY_MODE_FIXED\r
1150 1: LOCAL_APIC_DELIVERY_MODE_LOWEST_PRIORITY\r
1151 2: LOCAL_APIC_DELIVERY_MODE_SMI\r
1152 4: LOCAL_APIC_DELIVERY_MODE_NMI\r
1153 5: LOCAL_APIC_DELIVERY_MODE_INIT\r
1154 7: LOCAL_APIC_DELIVERY_MODE_EXTINT\r
7367cc6c
LG
1155\r
1156 @param LevelTriggered TRUE specifies a level triggered interrupt.\r
5f867ad0 1157 FALSE specifies an edge triggered interrupt.\r
1158 @param AssertionLevel Ignored if LevelTriggered is FALSE.\r
7367cc6c 1159 TRUE specifies a level triggered interrupt that active\r
5f867ad0 1160 when the interrupt line is asserted.\r
7367cc6c 1161 FALSE specifies a level triggered interrupt that active\r
5f867ad0 1162 when the interrupt line is deasserted.\r
1163\r
1164 @return 64-bit data value used to send an MSI to the Local APIC.\r
1165**/\r
1166UINT64\r
7367cc6c 1167EFIAPI\r
5f867ad0 1168GetApicMsiValue (\r
1169 IN UINT8 Vector,\r
1170 IN UINTN DeliveryMode,\r
1171 IN BOOLEAN LevelTriggered,\r
1172 IN BOOLEAN AssertionLevel\r
1173 )\r
1174{\r
1175 LOCAL_APIC_MSI_DATA MsiData;\r
1176\r
1177 ASSERT (Vector >= 0x10 && Vector <= 0xFE);\r
1178 ASSERT (DeliveryMode < 8 && DeliveryMode != 6 && DeliveryMode != 3);\r
7367cc6c 1179\r
5f867ad0 1180 MsiData.Uint64 = 0;\r
1181 MsiData.Bits.Vector = Vector;\r
1182 MsiData.Bits.DeliveryMode = (UINT32)DeliveryMode;\r
1183 if (LevelTriggered) {\r
1184 MsiData.Bits.TriggerMode = 1;\r
1185 if (AssertionLevel) {\r
1186 MsiData.Bits.Level = 1;\r
1187 }\r
1188 }\r
053e878b 1189\r
5f867ad0 1190 return MsiData.Uint64;\r
1191}\r
73152f19
LD
1192\r
1193/**\r
1194 Get Package ID/Core ID/Thread ID of a processor.\r
1195\r
1196 The algorithm assumes the target system has symmetry across physical\r
1197 package boundaries with respect to the number of logical processors\r
1198 per package, number of cores per package.\r
1199\r
1200 @param[in] InitialApicId Initial APIC ID of the target logical processor.\r
1201 @param[out] Package Returns the processor package ID.\r
1202 @param[out] Core Returns the processor core ID.\r
1203 @param[out] Thread Returns the processor thread ID.\r
1204**/\r
1205VOID\r
1c8ca9a0 1206EFIAPI\r
262128e5 1207GetProcessorLocationByApicId (\r
73152f19
LD
1208 IN UINT32 InitialApicId,\r
1209 OUT UINT32 *Package OPTIONAL,\r
1210 OUT UINT32 *Core OPTIONAL,\r
1211 OUT UINT32 *Thread OPTIONAL\r
1212 )\r
1213{\r
061ead7a
LD
1214 BOOLEAN TopologyLeafSupported;\r
1215 CPUID_VERSION_INFO_EBX VersionInfoEbx;\r
1216 CPUID_VERSION_INFO_EDX VersionInfoEdx;\r
1217 CPUID_CACHE_PARAMS_EAX CacheParamsEax;\r
1218 CPUID_EXTENDED_TOPOLOGY_EAX ExtendedTopologyEax;\r
1219 CPUID_EXTENDED_TOPOLOGY_EBX ExtendedTopologyEbx;\r
1220 CPUID_EXTENDED_TOPOLOGY_ECX ExtendedTopologyEcx;\r
1221 CPUID_AMD_EXTENDED_CPU_SIG_ECX AmdExtendedCpuSigEcx;\r
1222 CPUID_AMD_PROCESSOR_TOPOLOGY_EBX AmdProcessorTopologyEbx;\r
061ead7a
LD
1223 CPUID_AMD_VIR_PHY_ADDRESS_SIZE_ECX AmdVirPhyAddressSizeEcx;\r
1224 UINT32 MaxStandardCpuIdIndex;\r
1225 UINT32 MaxExtendedCpuIdIndex;\r
1226 UINT32 SubIndex;\r
1227 UINTN LevelType;\r
1228 UINT32 MaxLogicProcessorsPerPackage;\r
1229 UINT32 MaxCoresPerPackage;\r
061ead7a
LD
1230 UINTN ThreadBits;\r
1231 UINTN CoreBits;\r
73152f19
LD
1232\r
1233 //\r
1234 // Check if the processor is capable of supporting more than one logical processor.\r
1235 //\r
ae66c6f1 1236 AsmCpuid (CPUID_VERSION_INFO, NULL, NULL, NULL, &VersionInfoEdx.Uint32);\r
73152f19
LD
1237 if (VersionInfoEdx.Bits.HTT == 0) {\r
1238 if (Thread != NULL) {\r
061ead7a 1239 *Thread = 0;\r
73152f19 1240 }\r
053e878b 1241\r
73152f19 1242 if (Core != NULL) {\r
061ead7a 1243 *Core = 0;\r
73152f19 1244 }\r
053e878b 1245\r
73152f19
LD
1246 if (Package != NULL) {\r
1247 *Package = 0;\r
1248 }\r
053e878b 1249\r
73152f19
LD
1250 return;\r
1251 }\r
1252\r
73152f19 1253 //\r
061ead7a 1254 // Assume three-level mapping of APIC ID: Package|Core|Thread.\r
73152f19 1255 //\r
061ead7a 1256 ThreadBits = 0;\r
053e878b 1257 CoreBits = 0;\r
73152f19
LD
1258\r
1259 //\r
061ead7a 1260 // Get max index of CPUID\r
73152f19 1261 //\r
ae66c6f1
LD
1262 AsmCpuid (CPUID_SIGNATURE, &MaxStandardCpuIdIndex, NULL, NULL, NULL);\r
1263 AsmCpuid (CPUID_EXTENDED_FUNCTION, &MaxExtendedCpuIdIndex, NULL, NULL, NULL);\r
73152f19
LD
1264\r
1265 //\r
1266 // If the extended topology enumeration leaf is available, it\r
1267 // is the preferred mechanism for enumerating topology.\r
1268 //\r
061ead7a
LD
1269 TopologyLeafSupported = FALSE;\r
1270 if (MaxStandardCpuIdIndex >= CPUID_EXTENDED_TOPOLOGY) {\r
053e878b 1271 AsmCpuidEx (\r
73152f19
LD
1272 CPUID_EXTENDED_TOPOLOGY,\r
1273 0,\r
1274 &ExtendedTopologyEax.Uint32,\r
1275 &ExtendedTopologyEbx.Uint32,\r
1276 &ExtendedTopologyEcx.Uint32,\r
1277 NULL\r
1278 );\r
1279 //\r
1280 // If CPUID.(EAX=0BH, ECX=0H):EBX returns zero and maximum input value for\r
1281 // basic CPUID information is greater than 0BH, then CPUID.0BH leaf is not\r
1282 // supported on that processor.\r
1283 //\r
1284 if (ExtendedTopologyEbx.Uint32 != 0) {\r
1285 TopologyLeafSupported = TRUE;\r
1286\r
1287 //\r
1288 // Sub-leaf index 0 (ECX= 0 as input) provides enumeration parameters to extract\r
1289 // the SMT sub-field of x2APIC ID.\r
1290 //\r
1291 LevelType = ExtendedTopologyEcx.Bits.LevelType;\r
ae66c6f1 1292 ASSERT (LevelType == CPUID_EXTENDED_TOPOLOGY_LEVEL_TYPE_SMT);\r
73152f19
LD
1293 ThreadBits = ExtendedTopologyEax.Bits.ApicIdShift;\r
1294\r
1295 //\r
1296 // Software must not assume any "level type" encoding\r
1297 // value to be related to any sub-leaf index, except sub-leaf 0.\r
1298 //\r
1299 SubIndex = 1;\r
1300 do {\r
ae66c6f1 1301 AsmCpuidEx (\r
73152f19
LD
1302 CPUID_EXTENDED_TOPOLOGY,\r
1303 SubIndex,\r
1304 &ExtendedTopologyEax.Uint32,\r
1305 NULL,\r
1306 &ExtendedTopologyEcx.Uint32,\r
1307 NULL\r
1308 );\r
1309 LevelType = ExtendedTopologyEcx.Bits.LevelType;\r
1310 if (LevelType == CPUID_EXTENDED_TOPOLOGY_LEVEL_TYPE_CORE) {\r
1311 CoreBits = ExtendedTopologyEax.Bits.ApicIdShift - ThreadBits;\r
1312 break;\r
1313 }\r
053e878b 1314\r
73152f19
LD
1315 SubIndex++;\r
1316 } while (LevelType != CPUID_EXTENDED_TOPOLOGY_LEVEL_TYPE_INVALID);\r
1317 }\r
1318 }\r
1319\r
1320 if (!TopologyLeafSupported) {\r
061ead7a
LD
1321 //\r
1322 // Get logical processor count\r
1323 //\r
ae66c6f1 1324 AsmCpuid (CPUID_VERSION_INFO, NULL, &VersionInfoEbx.Uint32, NULL, NULL);\r
73152f19 1325 MaxLogicProcessorsPerPackage = VersionInfoEbx.Bits.MaximumAddressableIdsForLogicalProcessors;\r
061ead7a
LD
1326\r
1327 //\r
1328 // Assume single-core processor\r
1329 //\r
1330 MaxCoresPerPackage = 1;\r
1331\r
1332 //\r
1333 // Check for topology extensions on AMD processor\r
1334 //\r
053e878b 1335 if (StandardSignatureIsAuthenticAMD ()) {\r
061ead7a 1336 if (MaxExtendedCpuIdIndex >= CPUID_AMD_PROCESSOR_TOPOLOGY) {\r
ae66c6f1 1337 AsmCpuid (CPUID_EXTENDED_CPU_SIG, NULL, NULL, &AmdExtendedCpuSigEcx.Uint32, NULL);\r
061ead7a 1338 if (AmdExtendedCpuSigEcx.Bits.TopologyExtensions != 0) {\r
061ead7a 1339 //\r
ae66c6f1 1340 // Account for max possible thread count to decode ApicId\r
061ead7a 1341 //\r
ae66c6f1
LD
1342 AsmCpuid (CPUID_VIR_PHY_ADDRESS_SIZE, NULL, NULL, &AmdVirPhyAddressSizeEcx.Uint32, NULL);\r
1343 MaxLogicProcessorsPerPackage = 1 << AmdVirPhyAddressSizeEcx.Bits.ApicIdCoreIdSize;\r
061ead7a
LD
1344\r
1345 //\r
ae66c6f1 1346 // Get cores per processor package\r
061ead7a 1347 //\r
ae66c6f1
LD
1348 AsmCpuid (CPUID_AMD_PROCESSOR_TOPOLOGY, NULL, &AmdProcessorTopologyEbx.Uint32, NULL, NULL);\r
1349 MaxCoresPerPackage = MaxLogicProcessorsPerPackage / (AmdProcessorTopologyEbx.Bits.ThreadsPerCore + 1);\r
061ead7a
LD
1350 }\r
1351 }\r
053e878b 1352 } else {\r
73152f19 1353 //\r
061ead7a 1354 // Extract core count based on CACHE information\r
73152f19 1355 //\r
061ead7a 1356 if (MaxStandardCpuIdIndex >= CPUID_CACHE_PARAMS) {\r
ae66c6f1 1357 AsmCpuidEx (CPUID_CACHE_PARAMS, 0, &CacheParamsEax.Uint32, NULL, NULL, NULL);\r
061ead7a
LD
1358 if (CacheParamsEax.Uint32 != 0) {\r
1359 MaxCoresPerPackage = CacheParamsEax.Bits.MaximumAddressableIdsForLogicalProcessors + 1;\r
1360 }\r
1361 }\r
73152f19
LD
1362 }\r
1363\r
053e878b
MK
1364 ThreadBits = (UINTN)(HighBitSet32 (MaxLogicProcessorsPerPackage / MaxCoresPerPackage - 1) + 1);\r
1365 CoreBits = (UINTN)(HighBitSet32 (MaxCoresPerPackage - 1) + 1);\r
061ead7a 1366 }\r
73152f19
LD
1367\r
1368 if (Thread != NULL) {\r
061ead7a 1369 *Thread = InitialApicId & ((1 << ThreadBits) - 1);\r
73152f19 1370 }\r
053e878b 1371\r
73152f19 1372 if (Core != NULL) {\r
061ead7a 1373 *Core = (InitialApicId >> ThreadBits) & ((1 << CoreBits) - 1);\r
73152f19 1374 }\r
053e878b 1375\r
73152f19
LD
1376 if (Package != NULL) {\r
1377 *Package = (InitialApicId >> (ThreadBits + CoreBits));\r
1378 }\r
1379}\r
7f33d4f2
RN
1380\r
1381/**\r
1382 Get Package ID/Die ID/Tile ID/Module ID/Core ID/Thread ID of a processor.\r
1383\r
1384 The algorithm assumes the target system has symmetry across physical\r
1385 package boundaries with respect to the number of threads per core, number of\r
1386 cores per module, number of modules per tile, number of tiles per die, number\r
1387 of dies per package.\r
1388\r
1389 @param[in] InitialApicId Initial APIC ID of the target logical processor.\r
1390 @param[out] Package Returns the processor package ID.\r
1391 @param[out] Die Returns the processor die ID.\r
1392 @param[out] Tile Returns the processor tile ID.\r
1393 @param[out] Module Returns the processor module ID.\r
1394 @param[out] Core Returns the processor core ID.\r
1395 @param[out] Thread Returns the processor thread ID.\r
1396**/\r
1397VOID\r
1398EFIAPI\r
1399GetProcessorLocation2ByApicId (\r
1400 IN UINT32 InitialApicId,\r
1401 OUT UINT32 *Package OPTIONAL,\r
1402 OUT UINT32 *Die OPTIONAL,\r
1403 OUT UINT32 *Tile OPTIONAL,\r
1404 OUT UINT32 *Module OPTIONAL,\r
1405 OUT UINT32 *Core OPTIONAL,\r
1406 OUT UINT32 *Thread OPTIONAL\r
1407 )\r
1408{\r
053e878b
MK
1409 CPUID_EXTENDED_TOPOLOGY_EAX ExtendedTopologyEax;\r
1410 CPUID_EXTENDED_TOPOLOGY_ECX ExtendedTopologyEcx;\r
1411 UINT32 MaxStandardCpuIdIndex;\r
1412 UINT32 Index;\r
1413 UINTN LevelType;\r
1414 UINT32 Bits[CPUID_V2_EXTENDED_TOPOLOGY_LEVEL_TYPE_DIE + 2];\r
1415 UINT32 *Location[CPUID_V2_EXTENDED_TOPOLOGY_LEVEL_TYPE_DIE + 2];\r
7f33d4f2
RN
1416\r
1417 for (LevelType = 0; LevelType < ARRAY_SIZE (Bits); LevelType++) {\r
1418 Bits[LevelType] = 0;\r
1419 }\r
1420\r
1421 //\r
1422 // Get max index of CPUID\r
1423 //\r
1424 AsmCpuid (CPUID_SIGNATURE, &MaxStandardCpuIdIndex, NULL, NULL, NULL);\r
1425 if (MaxStandardCpuIdIndex < CPUID_V2_EXTENDED_TOPOLOGY) {\r
1426 if (Die != NULL) {\r
1427 *Die = 0;\r
1428 }\r
053e878b 1429\r
7f33d4f2
RN
1430 if (Tile != NULL) {\r
1431 *Tile = 0;\r
1432 }\r
053e878b 1433\r
7f33d4f2
RN
1434 if (Module != NULL) {\r
1435 *Module = 0;\r
1436 }\r
053e878b 1437\r
7f33d4f2
RN
1438 GetProcessorLocationByApicId (InitialApicId, Package, Core, Thread);\r
1439 return;\r
1440 }\r
1441\r
1442 //\r
1443 // If the V2 extended topology enumeration leaf is available, it\r
1444 // is the preferred mechanism for enumerating topology.\r
1445 //\r
1446 for (Index = 0; ; Index++) {\r
053e878b 1447 AsmCpuidEx (\r
7f33d4f2
RN
1448 CPUID_V2_EXTENDED_TOPOLOGY,\r
1449 Index,\r
1450 &ExtendedTopologyEax.Uint32,\r
1451 NULL,\r
1452 &ExtendedTopologyEcx.Uint32,\r
1453 NULL\r
1454 );\r
1455\r
1456 LevelType = ExtendedTopologyEcx.Bits.LevelType;\r
1457\r
1458 //\r
1459 // first level reported should be SMT.\r
1460 //\r
1461 ASSERT ((Index != 0) || (LevelType == CPUID_EXTENDED_TOPOLOGY_LEVEL_TYPE_SMT));\r
1462 if (LevelType == CPUID_EXTENDED_TOPOLOGY_LEVEL_TYPE_INVALID) {\r
1463 break;\r
1464 }\r
053e878b 1465\r
7f33d4f2
RN
1466 ASSERT (LevelType < ARRAY_SIZE (Bits));\r
1467 Bits[LevelType] = ExtendedTopologyEax.Bits.ApicIdShift;\r
1468 }\r
1469\r
1470 for (LevelType = CPUID_EXTENDED_TOPOLOGY_LEVEL_TYPE_CORE; LevelType < ARRAY_SIZE (Bits); LevelType++) {\r
1471 //\r
1472 // If there are more levels between level-1 (low-level) and level-2 (high-level), the unknown levels will be ignored\r
1473 // and treated as an extension of the last known level (i.e., level-1 in this case).\r
1474 //\r
1475 if (Bits[LevelType] == 0) {\r
1476 Bits[LevelType] = Bits[LevelType - 1];\r
1477 }\r
1478 }\r
1479\r
1480 Location[CPUID_V2_EXTENDED_TOPOLOGY_LEVEL_TYPE_DIE + 1] = Package;\r
053e878b
MK
1481 Location[CPUID_V2_EXTENDED_TOPOLOGY_LEVEL_TYPE_DIE] = Die;\r
1482 Location[CPUID_V2_EXTENDED_TOPOLOGY_LEVEL_TYPE_TILE] = Tile;\r
1483 Location[CPUID_V2_EXTENDED_TOPOLOGY_LEVEL_TYPE_MODULE] = Module;\r
1484 Location[CPUID_EXTENDED_TOPOLOGY_LEVEL_TYPE_CORE] = Core;\r
1485 Location[CPUID_EXTENDED_TOPOLOGY_LEVEL_TYPE_SMT] = Thread;\r
7f33d4f2
RN
1486\r
1487 Bits[CPUID_V2_EXTENDED_TOPOLOGY_LEVEL_TYPE_DIE + 1] = 32;\r
1488\r
1489 for ( LevelType = CPUID_EXTENDED_TOPOLOGY_LEVEL_TYPE_SMT\r
053e878b
MK
1490 ; LevelType <= CPUID_V2_EXTENDED_TOPOLOGY_LEVEL_TYPE_DIE + 1\r
1491 ; LevelType++\r
1492 )\r
1493 {\r
7f33d4f2
RN
1494 if (Location[LevelType] != NULL) {\r
1495 //\r
1496 // Bits[i] holds the number of bits to shift right on x2APIC ID to get a unique\r
1497 // topology ID of the next level type.\r
1498 //\r
1499 *Location[LevelType] = InitialApicId >> Bits[LevelType - 1];\r
1500\r
1501 //\r
1502 // Bits[i] - Bits[i-1] holds the number of bits for the next ONE level type.\r
1503 //\r
1504 *Location[LevelType] &= (1 << (Bits[LevelType] - Bits[LevelType - 1])) - 1;\r
1505 }\r
1506 }\r
1507}\r