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