VirtualBox

source: vbox/trunk/src/VBox/Devices/EFI/FirmwareNew/UefiCpuPkg/Library/BaseXApicLib/BaseXApicLib.c@ 89983

Last change on this file since 89983 was 89983, checked in by vboxsync, 3 years ago

Devices/EFI: Merge edk-stable202105 and openssl 1.1.1j and make it build, bugref:4643

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

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette