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