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