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