]> git.proxmox.com Git - mirror_edk2.git/blame_incremental - UefiCpuPkg/Library/BaseXApicX2ApicLib/BaseXApicX2ApicLib.c
UefiCpuPkg: Support TDX in BaseXApicX2ApicLib
[mirror_edk2.git] / UefiCpuPkg / Library / BaseXApicX2ApicLib / BaseXApicX2ApicLib.c
... / ...
CommitLineData
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
7 Copyright (c) 2010 - 2019, Intel Corporation. All rights reserved.<BR>\r
8 Copyright (c) 2017 - 2020, AMD Inc. All rights reserved.<BR>\r
9\r
10 SPDX-License-Identifier: BSD-2-Clause-Patent\r
11\r
12**/\r
13\r
14#include <Register/Intel/Cpuid.h>\r
15#include <Register/Amd/Cpuid.h>\r
16#include <Register/Intel/Msr.h>\r
17#include <Register/Intel/LocalApic.h>\r
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
24#include <Library/PcdLib.h>\r
25#include <Library/UefiCpuLib.h>\r
26#include <IndustryStandard/Tdx.h>\r
27\r
28//\r
29// Library internal functions\r
30//\r
31\r
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
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
189\r
190 AsmCpuid (1, &RegEax, NULL, NULL, NULL);\r
191 FamilyId = BitFieldRead32 (RegEax, 8, 11);\r
192 if ((FamilyId == 0x04) || (FamilyId == 0x05)) {\r
193 //\r
194 // CPUs with a FamilyId of 0x04 or 0x05 do not support the\r
195 // Local APIC Base Address MSR\r
196 //\r
197 return FALSE;\r
198 }\r
199\r
200 return TRUE;\r
201}\r
202\r
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
215 MSR_IA32_APIC_BASE_REGISTER ApicBaseMsr;\r
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
225 ApicBaseMsr.Uint64 = LocalApicReadMsrReg64 (MSR_IA32_APIC_BASE);\r
226\r
227 return (UINTN)(LShiftU64 ((UINT64)ApicBaseMsr.Bits.ApicBaseHi, 32)) +\r
228 (((UINTN)ApicBaseMsr.Bits.ApicBase) << 12);\r
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
242 IN UINTN BaseAddress\r
243 )\r
244{\r
245 MSR_IA32_APIC_BASE_REGISTER ApicBaseMsr;\r
246\r
247 ASSERT ((BaseAddress & (SIZE_4KB - 1)) == 0);\r
248\r
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
256 ApicBaseMsr.Uint64 = LocalApicReadMsrReg64 (MSR_IA32_APIC_BASE);\r
257\r
258 ApicBaseMsr.Bits.ApicBase = (UINT32)(BaseAddress >> 12);\r
259 ApicBaseMsr.Bits.ApicBaseHi = (UINT32)(RShiftU64 ((UINT64)BaseAddress, 32));\r
260\r
261 LocalApicWriteMsrReg64 (MSR_IA32_APIC_BASE, ApicBaseMsr.Uint64);\r
262}\r
263\r
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
283 UINT32 MsrIndex;\r
284\r
285 ASSERT ((MmioOffset & 0xf) == 0);\r
286\r
287 if (GetApicMode () == LOCAL_APIC_MODE_XAPIC) {\r
288 return MmioRead32 (GetLocalApicBaseAddress () + MmioOffset);\r
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
301 return LocalApicReadMsrReg32 (MsrIndex);\r
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
322 IN UINTN MmioOffset,\r
323 IN UINT32 Value\r
324 )\r
325{\r
326 UINT32 MsrIndex;\r
327\r
328 ASSERT ((MmioOffset & 0xf) == 0);\r
329\r
330 if (GetApicMode () == LOCAL_APIC_MODE_XAPIC) {\r
331 MmioWrite32 (GetLocalApicBaseAddress () + MmioOffset, Value);\r
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
350 LocalApicWriteMsrReg32 (MsrIndex, Value);\r
351 }\r
352}\r
353\r
354/**\r
355 Send an IPI by writing to ICR.\r
356\r
357 This function returns after the IPI has been accepted by the target processor.\r
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
364 IN UINT32 IcrLow,\r
365 IN UINT32 ApicId\r
366 )\r
367{\r
368 UINT64 MsrValue;\r
369 LOCAL_APIC_ICR_LOW IcrLowReg;\r
370 UINTN LocalApciBaseAddress;\r
371 UINT32 IcrHigh;\r
372 BOOLEAN InterruptState;\r
373\r
374 //\r
375 // Legacy APIC or X2APIC?\r
376 //\r
377 if (GetApicMode () == LOCAL_APIC_MODE_XAPIC) {\r
378 ASSERT (ApicId <= 0xff);\r
379\r
380 InterruptState = SaveAndDisableInterrupts ();\r
381\r
382 //\r
383 // Get base address of this LAPIC\r
384 //\r
385 LocalApciBaseAddress = GetLocalApicBaseAddress ();\r
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
403 MmioWrite32 (LocalApciBaseAddress + XAPIC_ICR_HIGH_OFFSET, ApicId << 24);\r
404 MmioWrite32 (LocalApciBaseAddress + XAPIC_ICR_LOW_OFFSET, IcrLow);\r
405\r
406 //\r
407 // Wait for DeliveryStatus clear again\r
408 //\r
409 do {\r
410 IcrLowReg.Uint32 = MmioRead32 (LocalApciBaseAddress + XAPIC_ICR_LOW_OFFSET);\r
411 } while (IcrLowReg.Bits.DeliveryStatus != 0);\r
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
419 } else {\r
420 //\r
421 // For x2APIC, A single MSR write to the Interrupt Command Register is required for dispatching an\r
422 // interrupt in x2APIC mode.\r
423 //\r
424 MsrValue = LShiftU64 ((UINT64)ApicId, 32) | IcrLow;\r
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
447 MSR_IA32_APIC_BASE_REGISTER ApicBaseMsr;\r
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
455\r
456 ApicBaseMsr.Uint64 = LocalApicReadMsrReg64 (MSR_IA32_APIC_BASE);\r
457 //\r
458 // Local APIC should have been enabled\r
459 //\r
460 ASSERT (ApicBaseMsr.Bits.EN != 0);\r
461 if (ApicBaseMsr.Bits.EXTD != 0) {\r
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
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
478**/\r
479VOID\r
480EFIAPI\r
481SetApicMode (\r
482 IN UINTN ApicMode\r
483 )\r
484{\r
485 UINTN CurrentMode;\r
486 MSR_IA32_APIC_BASE_REGISTER ApicBaseMsr;\r
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
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
501 ApicBaseMsr.Uint64 = LocalApicReadMsrReg64 (MSR_IA32_APIC_BASE);\r
502 ApicBaseMsr.Bits.EXTD = 1;\r
503 LocalApicWriteMsrReg64 (MSR_IA32_APIC_BASE, ApicBaseMsr.Uint64);\r
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
515 ApicBaseMsr.Uint64 = AsmReadMsr64 (MSR_IA32_APIC_BASE);\r
516 ApicBaseMsr.Bits.EXTD = 0;\r
517 ApicBaseMsr.Bits.EN = 0;\r
518 AsmWriteMsr64 (MSR_IA32_APIC_BASE, ApicBaseMsr.Uint64);\r
519 ApicBaseMsr.Bits.EN = 1;\r
520 AsmWriteMsr64 (MSR_IA32_APIC_BASE, ApicBaseMsr.Uint64);\r
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
533 In xAPIC mode, the initial local APIC ID may be different from current APIC ID.\r
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
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
545 UINT32 ApicId;\r
546 UINT32 MaxCpuIdIndex;\r
547 UINT32 RegEbx;\r
548\r
549 if (GetApicMode () == LOCAL_APIC_MODE_XAPIC) {\r
550 //\r
551 // Get the max index of basic CPUID\r
552 //\r
553 AsmCpuid (CPUID_SIGNATURE, &MaxCpuIdIndex, NULL, NULL, NULL);\r
554 //\r
555 // If CPUID Leaf B is supported,\r
556 // And CPUID.0BH:EBX[15:0] reports a non-zero value,\r
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
561 AsmCpuidEx (CPUID_EXTENDED_TOPOLOGY, 0, NULL, &RegEbx, NULL, &ApicId);\r
562 if ((RegEbx & (BIT16 - 1)) != 0) {\r
563 return ApicId;\r
564 }\r
565 }\r
566\r
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
585 UINT32 ApicId;\r
586 UINT32 InitApicId;\r
587\r
588 ApicId = ReadLocalApicReg (XAPIC_ID_OFFSET);\r
589 if (GetApicMode () == LOCAL_APIC_MODE_XAPIC) {\r
590 ApicId = ((InitApicId = GetInitialApicId ()) < 0x100) ? (ApicId >> 24) : InitApicId;\r
591 }\r
592\r
593 return ApicId;\r
594}\r
595\r
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
613 This function returns after the IPI has been accepted by the target processor.\r
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
621 IN UINT32 ApicId,\r
622 IN UINT8 Vector\r
623 )\r
624{\r
625 LOCAL_APIC_ICR_LOW IcrLow;\r
626\r
627 IcrLow.Uint32 = 0;\r
628 IcrLow.Bits.DeliveryMode = LOCAL_APIC_DELIVERY_MODE_FIXED;\r
629 IcrLow.Bits.Level = 1;\r
630 IcrLow.Bits.Vector = Vector;\r
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
637 This function returns after the IPI has been accepted by the target processors.\r
638\r
639 @param Vector The vector number of the interrupt being sent.\r
640**/\r
641VOID\r
642EFIAPI\r
643SendFixedIpiAllExcludingSelf (\r
644 IN UINT8 Vector\r
645 )\r
646{\r
647 LOCAL_APIC_ICR_LOW IcrLow;\r
648\r
649 IcrLow.Uint32 = 0;\r
650 IcrLow.Bits.DeliveryMode = LOCAL_APIC_DELIVERY_MODE_FIXED;\r
651 IcrLow.Bits.Level = 1;\r
652 IcrLow.Bits.DestinationShorthand = LOCAL_APIC_DESTINATION_SHORTHAND_ALL_EXCLUDING_SELF;\r
653 IcrLow.Bits.Vector = Vector;\r
654 SendIpi (IcrLow.Uint32, 0);\r
655}\r
656\r
657/**\r
658 Send a SMI IPI to a specified target processor.\r
659\r
660 This function returns after the IPI has been accepted by the target processor.\r
661\r
662 @param ApicId Specify the local APIC ID of the target processor.\r
663**/\r
664VOID\r
665EFIAPI\r
666SendSmiIpi (\r
667 IN UINT32 ApicId\r
668 )\r
669{\r
670 LOCAL_APIC_ICR_LOW IcrLow;\r
671\r
672 IcrLow.Uint32 = 0;\r
673 IcrLow.Bits.DeliveryMode = LOCAL_APIC_DELIVERY_MODE_SMI;\r
674 IcrLow.Bits.Level = 1;\r
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
681 This function returns after the IPI has been accepted by the target processors.\r
682**/\r
683VOID\r
684EFIAPI\r
685SendSmiIpiAllExcludingSelf (\r
686 VOID\r
687 )\r
688{\r
689 LOCAL_APIC_ICR_LOW IcrLow;\r
690\r
691 IcrLow.Uint32 = 0;\r
692 IcrLow.Bits.DeliveryMode = LOCAL_APIC_DELIVERY_MODE_SMI;\r
693 IcrLow.Bits.Level = 1;\r
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
701 This function returns after the IPI has been accepted by the target processor.\r
702\r
703 @param ApicId Specify the local APIC ID of the target processor.\r
704**/\r
705VOID\r
706EFIAPI\r
707SendInitIpi (\r
708 IN UINT32 ApicId\r
709 )\r
710{\r
711 LOCAL_APIC_ICR_LOW IcrLow;\r
712\r
713 IcrLow.Uint32 = 0;\r
714 IcrLow.Bits.DeliveryMode = LOCAL_APIC_DELIVERY_MODE_INIT;\r
715 IcrLow.Bits.Level = 1;\r
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
722 This function returns after the IPI has been accepted by the target processors.\r
723**/\r
724VOID\r
725EFIAPI\r
726SendInitIpiAllExcludingSelf (\r
727 VOID\r
728 )\r
729{\r
730 LOCAL_APIC_ICR_LOW IcrLow;\r
731\r
732 IcrLow.Uint32 = 0;\r
733 IcrLow.Bits.DeliveryMode = LOCAL_APIC_DELIVERY_MODE_INIT;\r
734 IcrLow.Bits.Level = 1;\r
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
742 This function returns after the IPI has been accepted by the target processor.\r
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
754 IN UINT32 ApicId,\r
755 IN UINT32 StartupRoutine\r
756 )\r
757{\r
758 LOCAL_APIC_ICR_LOW IcrLow;\r
759\r
760 ASSERT (StartupRoutine < 0x100000);\r
761 ASSERT ((StartupRoutine & 0xfff) == 0);\r
762\r
763 SendInitIpi (ApicId);\r
764 MicroSecondDelay (PcdGet32 (PcdCpuInitIpiDelayInMicroSeconds));\r
765 IcrLow.Uint32 = 0;\r
766 IcrLow.Bits.Vector = (StartupRoutine >> 12);\r
767 IcrLow.Bits.DeliveryMode = LOCAL_APIC_DELIVERY_MODE_STARTUP;\r
768 IcrLow.Bits.Level = 1;\r
769 SendIpi (IcrLow.Uint32, ApicId);\r
770 if (!StandardSignatureIsAuthenticAMD ()) {\r
771 MicroSecondDelay (200);\r
772 SendIpi (IcrLow.Uint32, ApicId);\r
773 }\r
774}\r
775\r
776/**\r
777 Send an INIT-Start-up-Start-up IPI sequence to all processors excluding self.\r
778\r
779 This function returns after the IPI has been accepted by the target processors.\r
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
790 IN UINT32 StartupRoutine\r
791 )\r
792{\r
793 LOCAL_APIC_ICR_LOW IcrLow;\r
794\r
795 ASSERT (StartupRoutine < 0x100000);\r
796 ASSERT ((StartupRoutine & 0xfff) == 0);\r
797\r
798 SendInitIpiAllExcludingSelf ();\r
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
804 IcrLow.Bits.DestinationShorthand = LOCAL_APIC_DESTINATION_SHORTHAND_ALL_EXCLUDING_SELF;\r
805 SendIpi (IcrLow.Uint32, 0);\r
806 if (!StandardSignatureIsAuthenticAMD ()) {\r
807 MicroSecondDelay (200);\r
808 SendIpi (IcrLow.Uint32, 0);\r
809 }\r
810}\r
811\r
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
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
859 LOCAL_APIC_SVR Svr;\r
860 LOCAL_APIC_LVT_LINT Lint;\r
861\r
862 //\r
863 // Enable the APIC via SVR and set the spurious interrupt to use Int 00F.\r
864 //\r
865 Svr.Uint32 = ReadLocalApicReg (XAPIC_SPURIOUS_VECTOR_OFFSET);\r
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
873 Lint.Uint32 = ReadLocalApicReg (XAPIC_LVT_LINT0_OFFSET);\r
874 Lint.Bits.DeliveryMode = LOCAL_APIC_DELIVERY_MODE_EXTINT;\r
875 Lint.Bits.InputPinPolarity = 0;\r
876 Lint.Bits.TriggerMode = 0;\r
877 Lint.Bits.Mask = 0;\r
878 WriteLocalApicReg (XAPIC_LVT_LINT0_OFFSET, Lint.Uint32);\r
879\r
880 //\r
881 // Program the LINT0 vector entry as NMI. Not masked, edge, active high.\r
882 //\r
883 Lint.Uint32 = ReadLocalApicReg (XAPIC_LVT_LINT1_OFFSET);\r
884 Lint.Bits.DeliveryMode = LOCAL_APIC_DELIVERY_MODE_NMI;\r
885 Lint.Bits.InputPinPolarity = 0;\r
886 Lint.Bits.TriggerMode = 0;\r
887 Lint.Bits.Mask = 0;\r
888 WriteLocalApicReg (XAPIC_LVT_LINT1_OFFSET, Lint.Uint32);\r
889}\r
890\r
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
902 LOCAL_APIC_LVT_LINT LvtLint;\r
903\r
904 LvtLint.Uint32 = ReadLocalApicReg (XAPIC_LVT_LINT0_OFFSET);\r
905 LvtLint.Bits.Mask = 1;\r
906 WriteLocalApicReg (XAPIC_LVT_LINT0_OFFSET, LvtLint.Uint32);\r
907\r
908 LvtLint.Uint32 = ReadLocalApicReg (XAPIC_LVT_LINT1_OFFSET);\r
909 LvtLint.Bits.Mask = 1;\r
910 WriteLocalApicReg (XAPIC_LVT_LINT1_OFFSET, LvtLint.Uint32);\r
911}\r
912\r
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
955 IN UINTN DivideValue,\r
956 IN UINT32 InitCount,\r
957 IN BOOLEAN PeriodicMode,\r
958 IN UINT8 Vector\r
959 )\r
960{\r
961 LOCAL_APIC_DCR Dcr;\r
962 LOCAL_APIC_LVT_TIMER LvtTimer;\r
963 UINT32 Divisor;\r
964\r
965 //\r
966 // Ensure local APIC is in software-enabled state.\r
967 //\r
968 InitializeLocalApicSoftwareEnable (TRUE);\r
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
977 ASSERT (DivideValue == GetPowerOfTwo32 ((UINT32)DivideValue));\r
978 Divisor = (UINT32)((HighBitSet32 ((UINT32)DivideValue) - 1) & 0x7);\r
979\r
980 Dcr.Uint32 = ReadLocalApicReg (XAPIC_TIMER_DIVIDE_CONFIGURATION_OFFSET);\r
981 Dcr.Bits.DivideValue1 = (Divisor & 0x3);\r
982 Dcr.Bits.DivideValue2 = (Divisor >> 2);\r
983 WriteLocalApicReg (XAPIC_TIMER_DIVIDE_CONFIGURATION_OFFSET, Dcr.Uint32);\r
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
995\r
996 LvtTimer.Bits.Mask = 0;\r
997 LvtTimer.Bits.Vector = Vector;\r
998 WriteLocalApicReg (XAPIC_LVT_TIMER_OFFSET, LvtTimer.Uint32);\r
999}\r
1000\r
1001/**\r
1002 Get the state of the local APIC timer.\r
1003\r
1004 This function will ASSERT if the local APIC is not software enabled.\r
1005\r
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
1018 UINT32 Divisor;\r
1019 LOCAL_APIC_DCR Dcr;\r
1020 LOCAL_APIC_LVT_TIMER LvtTimer;\r
1021\r
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
1027 ASSERT ((ReadLocalApicReg (XAPIC_SPURIOUS_VECTOR_OFFSET) & BIT8) != 0);\r
1028\r
1029 if (DivideValue != NULL) {\r
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
1033 *DivideValue = ((UINTN)1) << Divisor;\r
1034 }\r
1035\r
1036 if ((PeriodicMode != NULL) || (Vector != NULL)) {\r
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
1045\r
1046 if (Vector != NULL) {\r
1047 *Vector = (UINT8)LvtTimer.Bits.Vector;\r
1048 }\r
1049 }\r
1050}\r
1051\r
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
1061 LOCAL_APIC_LVT_TIMER LvtTimer;\r
1062\r
1063 LvtTimer.Uint32 = ReadLocalApicReg (XAPIC_LVT_TIMER_OFFSET);\r
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
1077 LOCAL_APIC_LVT_TIMER LvtTimer;\r
1078\r
1079 LvtTimer.Uint32 = ReadLocalApicReg (XAPIC_LVT_TIMER_OFFSET);\r
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
1096 LOCAL_APIC_LVT_TIMER LvtTimer;\r
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
1114/**\r
1115 Get the 32-bit address that a device should use to send a Message Signaled\r
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
1121EFIAPI\r
1122GetApicMsiAddress (\r
1123 VOID\r
1124 )\r
1125{\r
1126 LOCAL_APIC_MSI_ADDRESS MsiAddress;\r
1127\r
1128 //\r
1129 // Return address for an MSI interrupt to be delivered only to the APIC ID\r
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
1137\r
1138/**\r
1139 Get the 64-bit data value that a device should use to send a Message Signaled\r
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
1144\r
1145 @param Vector The 8-bit interrupt vector associated with the MSI.\r
1146 Must be in the range 0x10..0xFE\r
1147 @param DeliveryMode A 3-bit value that specifies how the recept of the MSI\r
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
1155\r
1156 @param LevelTriggered TRUE specifies a level triggered interrupt.\r
1157 FALSE specifies an edge triggered interrupt.\r
1158 @param AssertionLevel Ignored if LevelTriggered is FALSE.\r
1159 TRUE specifies a level triggered interrupt that active\r
1160 when the interrupt line is asserted.\r
1161 FALSE specifies a level triggered interrupt that active\r
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
1167EFIAPI\r
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
1179\r
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
1189\r
1190 return MsiData.Uint64;\r
1191}\r
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
1206EFIAPI\r
1207GetProcessorLocationByApicId (\r
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
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
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
1230 UINTN ThreadBits;\r
1231 UINTN CoreBits;\r
1232\r
1233 //\r
1234 // Check if the processor is capable of supporting more than one logical processor.\r
1235 //\r
1236 AsmCpuid (CPUID_VERSION_INFO, NULL, NULL, NULL, &VersionInfoEdx.Uint32);\r
1237 if (VersionInfoEdx.Bits.HTT == 0) {\r
1238 if (Thread != NULL) {\r
1239 *Thread = 0;\r
1240 }\r
1241\r
1242 if (Core != NULL) {\r
1243 *Core = 0;\r
1244 }\r
1245\r
1246 if (Package != NULL) {\r
1247 *Package = 0;\r
1248 }\r
1249\r
1250 return;\r
1251 }\r
1252\r
1253 //\r
1254 // Assume three-level mapping of APIC ID: Package|Core|Thread.\r
1255 //\r
1256 ThreadBits = 0;\r
1257 CoreBits = 0;\r
1258\r
1259 //\r
1260 // Get max index of CPUID\r
1261 //\r
1262 AsmCpuid (CPUID_SIGNATURE, &MaxStandardCpuIdIndex, NULL, NULL, NULL);\r
1263 AsmCpuid (CPUID_EXTENDED_FUNCTION, &MaxExtendedCpuIdIndex, NULL, NULL, NULL);\r
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
1269 TopologyLeafSupported = FALSE;\r
1270 if (MaxStandardCpuIdIndex >= CPUID_EXTENDED_TOPOLOGY) {\r
1271 AsmCpuidEx (\r
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
1292 ASSERT (LevelType == CPUID_EXTENDED_TOPOLOGY_LEVEL_TYPE_SMT);\r
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
1301 AsmCpuidEx (\r
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
1314\r
1315 SubIndex++;\r
1316 } while (LevelType != CPUID_EXTENDED_TOPOLOGY_LEVEL_TYPE_INVALID);\r
1317 }\r
1318 }\r
1319\r
1320 if (!TopologyLeafSupported) {\r
1321 //\r
1322 // Get logical processor count\r
1323 //\r
1324 AsmCpuid (CPUID_VERSION_INFO, NULL, &VersionInfoEbx.Uint32, NULL, NULL);\r
1325 MaxLogicProcessorsPerPackage = VersionInfoEbx.Bits.MaximumAddressableIdsForLogicalProcessors;\r
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
1335 if (StandardSignatureIsAuthenticAMD ()) {\r
1336 if (MaxExtendedCpuIdIndex >= CPUID_AMD_PROCESSOR_TOPOLOGY) {\r
1337 AsmCpuid (CPUID_EXTENDED_CPU_SIG, NULL, NULL, &AmdExtendedCpuSigEcx.Uint32, NULL);\r
1338 if (AmdExtendedCpuSigEcx.Bits.TopologyExtensions != 0) {\r
1339 //\r
1340 // Account for max possible thread count to decode ApicId\r
1341 //\r
1342 AsmCpuid (CPUID_VIR_PHY_ADDRESS_SIZE, NULL, NULL, &AmdVirPhyAddressSizeEcx.Uint32, NULL);\r
1343 MaxLogicProcessorsPerPackage = 1 << AmdVirPhyAddressSizeEcx.Bits.ApicIdCoreIdSize;\r
1344\r
1345 //\r
1346 // Get cores per processor package\r
1347 //\r
1348 AsmCpuid (CPUID_AMD_PROCESSOR_TOPOLOGY, NULL, &AmdProcessorTopologyEbx.Uint32, NULL, NULL);\r
1349 MaxCoresPerPackage = MaxLogicProcessorsPerPackage / (AmdProcessorTopologyEbx.Bits.ThreadsPerCore + 1);\r
1350 }\r
1351 }\r
1352 } else {\r
1353 //\r
1354 // Extract core count based on CACHE information\r
1355 //\r
1356 if (MaxStandardCpuIdIndex >= CPUID_CACHE_PARAMS) {\r
1357 AsmCpuidEx (CPUID_CACHE_PARAMS, 0, &CacheParamsEax.Uint32, NULL, NULL, NULL);\r
1358 if (CacheParamsEax.Uint32 != 0) {\r
1359 MaxCoresPerPackage = CacheParamsEax.Bits.MaximumAddressableIdsForLogicalProcessors + 1;\r
1360 }\r
1361 }\r
1362 }\r
1363\r
1364 ThreadBits = (UINTN)(HighBitSet32 (MaxLogicProcessorsPerPackage / MaxCoresPerPackage - 1) + 1);\r
1365 CoreBits = (UINTN)(HighBitSet32 (MaxCoresPerPackage - 1) + 1);\r
1366 }\r
1367\r
1368 if (Thread != NULL) {\r
1369 *Thread = InitialApicId & ((1 << ThreadBits) - 1);\r
1370 }\r
1371\r
1372 if (Core != NULL) {\r
1373 *Core = (InitialApicId >> ThreadBits) & ((1 << CoreBits) - 1);\r
1374 }\r
1375\r
1376 if (Package != NULL) {\r
1377 *Package = (InitialApicId >> (ThreadBits + CoreBits));\r
1378 }\r
1379}\r
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
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
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
1429\r
1430 if (Tile != NULL) {\r
1431 *Tile = 0;\r
1432 }\r
1433\r
1434 if (Module != NULL) {\r
1435 *Module = 0;\r
1436 }\r
1437\r
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
1447 AsmCpuidEx (\r
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
1465\r
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
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
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
1490 ; LevelType <= CPUID_V2_EXTENDED_TOPOLOGY_LEVEL_TYPE_DIE + 1\r
1491 ; LevelType++\r
1492 )\r
1493 {\r
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