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