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