2 CPU DXE Module to produce CPU ARCH Protocol.
4 Copyright (c) 2008 - 2018, Intel Corporation. All rights reserved.<BR>
5 SPDX-License-Identifier: BSD-2-Clause-Patent
11 #include "CpuPageTable.h"
13 #define CACHE_ATTRIBUTE_MASK (EFI_MEMORY_UC | EFI_MEMORY_WC | EFI_MEMORY_WT | EFI_MEMORY_WB | EFI_MEMORY_UCE | EFI_MEMORY_WP)
14 #define MEMORY_ATTRIBUTE_MASK (EFI_MEMORY_RP | EFI_MEMORY_XP | EFI_MEMORY_RO)
19 BOOLEAN InterruptState
= FALSE
;
20 EFI_HANDLE mCpuHandle
= NULL
;
21 BOOLEAN mIsFlushingGCD
;
22 BOOLEAN mIsAllocatingPageTable
= FALSE
;
23 UINT64 mValidMtrrAddressMask
;
24 UINT64 mValidMtrrBitsMask
;
25 UINT64 mTimerPeriod
= 0;
27 FIXED_MTRR mFixedMtrrTable
[] = {
29 MSR_IA32_MTRR_FIX64K_00000
,
34 MSR_IA32_MTRR_FIX16K_80000
,
39 MSR_IA32_MTRR_FIX16K_A0000
,
44 MSR_IA32_MTRR_FIX4K_C0000
,
49 MSR_IA32_MTRR_FIX4K_C8000
,
54 MSR_IA32_MTRR_FIX4K_D0000
,
59 MSR_IA32_MTRR_FIX4K_D8000
,
64 MSR_IA32_MTRR_FIX4K_E0000
,
69 MSR_IA32_MTRR_FIX4K_E8000
,
74 MSR_IA32_MTRR_FIX4K_F0000
,
79 MSR_IA32_MTRR_FIX4K_F8000
,
86 EFI_CPU_ARCH_PROTOCOL gCpu
= {
92 CpuRegisterInterruptHandler
,
94 CpuSetMemoryAttributes
,
96 4 // DmaBufferAlignment
100 // CPU Arch Protocol Functions
104 Flush CPU data cache. If the instruction cache is fully coherent
105 with all DMA operations then function can just return EFI_SUCCESS.
107 @param This Protocol instance structure
108 @param Start Physical address to start flushing from.
109 @param Length Number of bytes to flush. Round up to chipset
111 @param FlushType Specifies the type of flush operation to perform.
113 @retval EFI_SUCCESS If cache was flushed
114 @retval EFI_UNSUPPORTED If flush type is not supported.
115 @retval EFI_DEVICE_ERROR If requested range could not be flushed.
120 CpuFlushCpuDataCache (
121 IN EFI_CPU_ARCH_PROTOCOL
*This
,
122 IN EFI_PHYSICAL_ADDRESS Start
,
124 IN EFI_CPU_FLUSH_TYPE FlushType
127 if (FlushType
== EfiCpuFlushTypeWriteBackInvalidate
) {
130 } else if (FlushType
== EfiCpuFlushTypeInvalidate
) {
134 return EFI_UNSUPPORTED
;
140 Enables CPU interrupts.
142 @param This Protocol instance structure
144 @retval EFI_SUCCESS If interrupts were enabled in the CPU
145 @retval EFI_DEVICE_ERROR If interrupts could not be enabled on the CPU.
151 IN EFI_CPU_ARCH_PROTOCOL
*This
156 InterruptState
= TRUE
;
162 Disables CPU interrupts.
164 @param This Protocol instance structure
166 @retval EFI_SUCCESS If interrupts were disabled in the CPU.
167 @retval EFI_DEVICE_ERROR If interrupts could not be disabled on the CPU.
172 CpuDisableInterrupt (
173 IN EFI_CPU_ARCH_PROTOCOL
*This
176 DisableInterrupts ();
178 InterruptState
= FALSE
;
184 Return the state of interrupts.
186 @param This Protocol instance structure
187 @param State Pointer to the CPU's current interrupt state
189 @retval EFI_SUCCESS If interrupts were disabled in the CPU.
190 @retval EFI_INVALID_PARAMETER State is NULL.
195 CpuGetInterruptState (
196 IN EFI_CPU_ARCH_PROTOCOL
*This
,
201 return EFI_INVALID_PARAMETER
;
204 *State
= InterruptState
;
210 Generates an INIT to the CPU.
212 @param This Protocol instance structure
213 @param InitType Type of CPU INIT to perform
215 @retval EFI_SUCCESS If CPU INIT occurred. This value should never be
217 @retval EFI_DEVICE_ERROR If CPU INIT failed.
218 @retval EFI_UNSUPPORTED Requested type of CPU INIT not supported.
224 IN EFI_CPU_ARCH_PROTOCOL
*This
,
225 IN EFI_CPU_INIT_TYPE InitType
228 return EFI_UNSUPPORTED
;
233 Registers a function to be called from the CPU interrupt handler.
235 @param This Protocol instance structure
236 @param InterruptType Defines which interrupt to hook. IA-32
237 valid range is 0x00 through 0xFF
238 @param InterruptHandler A pointer to a function of type
239 EFI_CPU_INTERRUPT_HANDLER that is called
240 when a processor interrupt occurs. A null
241 pointer is an error condition.
243 @retval EFI_SUCCESS If handler installed or uninstalled.
244 @retval EFI_ALREADY_STARTED InterruptHandler is not NULL, and a handler
245 for InterruptType was previously installed.
246 @retval EFI_INVALID_PARAMETER InterruptHandler is NULL, and a handler for
247 InterruptType was not previously installed.
248 @retval EFI_UNSUPPORTED The interrupt specified by InterruptType
254 CpuRegisterInterruptHandler (
255 IN EFI_CPU_ARCH_PROTOCOL
*This
,
256 IN EFI_EXCEPTION_TYPE InterruptType
,
257 IN EFI_CPU_INTERRUPT_HANDLER InterruptHandler
260 return RegisterCpuInterruptHandler (InterruptType
, InterruptHandler
);
265 Returns a timer value from one of the CPU's internal timers. There is no
266 inherent time interval between ticks but is a function of the CPU frequency.
268 @param This - Protocol instance structure.
269 @param TimerIndex - Specifies which CPU timer is requested.
270 @param TimerValue - Pointer to the returned timer value.
271 @param TimerPeriod - A pointer to the amount of time that passes
272 in femtoseconds (10-15) for each increment
273 of TimerValue. If TimerValue does not
274 increment at a predictable rate, then 0 is
275 returned. The amount of time that has
276 passed between two calls to GetTimerValue()
277 can be calculated with the formula
278 (TimerValue2 - TimerValue1) * TimerPeriod.
279 This parameter is optional and may be NULL.
281 @retval EFI_SUCCESS - If the CPU timer count was returned.
282 @retval EFI_UNSUPPORTED - If the CPU does not have any readable timers.
283 @retval EFI_DEVICE_ERROR - If an error occurred while reading the timer.
284 @retval EFI_INVALID_PARAMETER - TimerIndex is not valid or TimerValue is NULL.
290 IN EFI_CPU_ARCH_PROTOCOL
*This
,
291 IN UINT32 TimerIndex
,
292 OUT UINT64
*TimerValue
,
293 OUT UINT64
*TimerPeriod OPTIONAL
299 if (TimerValue
== NULL
) {
300 return EFI_INVALID_PARAMETER
;
303 if (TimerIndex
!= 0) {
304 return EFI_INVALID_PARAMETER
;
307 *TimerValue
= AsmReadTsc ();
309 if (TimerPeriod
!= NULL
) {
310 if (mTimerPeriod
== 0) {
312 // Read time stamp counter before and after delay of 100 microseconds
314 BeginValue
= AsmReadTsc ();
315 MicroSecondDelay (100);
316 EndValue
= AsmReadTsc ();
318 // Calculate the actual frequency
320 mTimerPeriod
= DivU64x64Remainder (
325 EndValue
- BeginValue
,
329 *TimerPeriod
= mTimerPeriod
;
336 A minimal wrapper function that allows MtrrSetAllMtrrs() to be passed to
337 EFI_MP_SERVICES_PROTOCOL.StartupAllAPs() as Procedure.
339 @param[in] Buffer Pointer to an MTRR_SETTINGS object, to be passed to
348 MtrrSetAllMtrrs (Buffer
);
352 Implementation of SetMemoryAttributes() service of CPU Architecture Protocol.
354 This function modifies the attributes for the memory region specified by BaseAddress and
355 Length from their current attributes to the attributes specified by Attributes.
357 @param This The EFI_CPU_ARCH_PROTOCOL instance.
358 @param BaseAddress The physical address that is the start address of a memory region.
359 @param Length The size in bytes of the memory region.
360 @param Attributes The bit mask of attributes to set for the memory region.
362 @retval EFI_SUCCESS The attributes were set for the memory region.
363 @retval EFI_ACCESS_DENIED The attributes for the memory resource range specified by
364 BaseAddress and Length cannot be modified.
365 @retval EFI_INVALID_PARAMETER Length is zero.
366 Attributes specified an illegal combination of attributes that
367 cannot be set together.
368 @retval EFI_OUT_OF_RESOURCES There are not enough system resources to modify the attributes of
369 the memory resource range.
370 @retval EFI_UNSUPPORTED The processor does not support one or more bytes of the memory
371 resource range specified by BaseAddress and Length.
372 The bit mask of attributes is not support for the memory resource
373 range specified by BaseAddress and Length.
378 CpuSetMemoryAttributes (
379 IN EFI_CPU_ARCH_PROTOCOL
*This
,
380 IN EFI_PHYSICAL_ADDRESS BaseAddress
,
385 RETURN_STATUS Status
;
386 MTRR_MEMORY_CACHE_TYPE CacheType
;
388 EFI_MP_SERVICES_PROTOCOL
*MpService
;
389 MTRR_SETTINGS MtrrSettings
;
390 UINT64 CacheAttributes
;
391 UINT64 MemoryAttributes
;
392 MTRR_MEMORY_CACHE_TYPE CurrentCacheType
;
395 // If this function is called because GCD SetMemorySpaceAttributes () is called
396 // by RefreshGcdMemoryAttributes (), then we are just synchronizing GCD memory
397 // map with MTRR values. So there is no need to modify MTRRs, just return immediately
398 // to avoid unnecessary computing.
400 if (mIsFlushingGCD
) {
401 DEBUG((DEBUG_VERBOSE
, " Flushing GCD\n"));
406 // During memory attributes updating, new pages may be allocated to setup
407 // smaller granularity of page table. Page allocation action might then cause
408 // another calling of CpuSetMemoryAttributes() recursively, due to memory
409 // protection policy configured (such as PcdDxeNxMemoryProtectionPolicy).
410 // Since this driver will always protect memory used as page table by itself,
411 // there's no need to apply protection policy requested from memory service.
412 // So it's safe to just return EFI_SUCCESS if this time of calling is caused
413 // by page table memory allocation.
415 if (mIsAllocatingPageTable
) {
416 DEBUG((DEBUG_VERBOSE
, " Allocating page table memory\n"));
420 CacheAttributes
= Attributes
& CACHE_ATTRIBUTE_MASK
;
421 MemoryAttributes
= Attributes
& MEMORY_ATTRIBUTE_MASK
;
423 if (Attributes
!= (CacheAttributes
| MemoryAttributes
)) {
424 return EFI_INVALID_PARAMETER
;
427 if (CacheAttributes
!= 0) {
428 if (!IsMtrrSupported ()) {
429 return EFI_UNSUPPORTED
;
432 switch (CacheAttributes
) {
434 CacheType
= CacheUncacheable
;
438 CacheType
= CacheWriteCombining
;
442 CacheType
= CacheWriteThrough
;
446 CacheType
= CacheWriteProtected
;
450 CacheType
= CacheWriteBack
;
454 return EFI_INVALID_PARAMETER
;
456 CurrentCacheType
= MtrrGetMemoryAttribute(BaseAddress
);
457 if (CurrentCacheType
!= CacheType
) {
459 // call MTRR library function
461 Status
= MtrrSetMemoryAttribute (
467 if (!RETURN_ERROR (Status
)) {
468 MpStatus
= gBS
->LocateProtocol (
469 &gEfiMpServiceProtocolGuid
,
474 // Synchronize the update with all APs
476 if (!EFI_ERROR (MpStatus
)) {
477 MtrrGetAllMtrrs (&MtrrSettings
);
478 MpStatus
= MpService
->StartupAllAPs (
480 SetMtrrsFromBuffer
, // Procedure
481 FALSE
, // SingleThread
483 0, // TimeoutInMicrosecsond
484 &MtrrSettings
, // ProcedureArgument
485 NULL
// FailedCpuList
487 ASSERT (MpStatus
== EFI_SUCCESS
|| MpStatus
== EFI_NOT_STARTED
);
490 if (EFI_ERROR(Status
)) {
497 // Set memory attribute by page table
499 return AssignMemoryPageAttributes (NULL
, BaseAddress
, Length
, MemoryAttributes
, NULL
);
503 Initializes the valid bits mask and valid address mask for MTRRs.
505 This function initializes the valid bits mask and valid address mask for MTRRs.
514 UINT8 PhysicalAddressBits
;
516 AsmCpuid (0x80000000, &RegEax
, NULL
, NULL
, NULL
);
518 if (RegEax
>= 0x80000008) {
519 AsmCpuid (0x80000008, &RegEax
, NULL
, NULL
, NULL
);
521 PhysicalAddressBits
= (UINT8
) RegEax
;
523 PhysicalAddressBits
= 36;
526 mValidMtrrBitsMask
= LShiftU64 (1, PhysicalAddressBits
) - 1;
527 mValidMtrrAddressMask
= mValidMtrrBitsMask
& 0xfffffffffffff000ULL
;
531 Gets GCD Mem Space type from MTRR Type.
533 This function gets GCD Mem Space type from MTRR Type.
535 @param MtrrAttributes MTRR memory type
537 @return GCD Mem Space type
541 GetMemorySpaceAttributeFromMtrrType (
542 IN UINT8 MtrrAttributes
545 switch (MtrrAttributes
) {
546 case MTRR_CACHE_UNCACHEABLE
:
547 return EFI_MEMORY_UC
;
548 case MTRR_CACHE_WRITE_COMBINING
:
549 return EFI_MEMORY_WC
;
550 case MTRR_CACHE_WRITE_THROUGH
:
551 return EFI_MEMORY_WT
;
552 case MTRR_CACHE_WRITE_PROTECTED
:
553 return EFI_MEMORY_WP
;
554 case MTRR_CACHE_WRITE_BACK
:
555 return EFI_MEMORY_WB
;
562 Searches memory descriptors covered by given memory range.
564 This function searches into the Gcd Memory Space for descriptors
565 (from StartIndex to EndIndex) that contains the memory range
566 specified by BaseAddress and Length.
568 @param MemorySpaceMap Gcd Memory Space Map as array.
569 @param NumberOfDescriptors Number of descriptors in map.
570 @param BaseAddress BaseAddress for the requested range.
571 @param Length Length for the requested range.
572 @param StartIndex Start index into the Gcd Memory Space Map.
573 @param EndIndex End index into the Gcd Memory Space Map.
575 @retval EFI_SUCCESS Search successfully.
576 @retval EFI_NOT_FOUND The requested descriptors does not exist.
580 SearchGcdMemorySpaces (
581 IN EFI_GCD_MEMORY_SPACE_DESCRIPTOR
*MemorySpaceMap
,
582 IN UINTN NumberOfDescriptors
,
583 IN EFI_PHYSICAL_ADDRESS BaseAddress
,
585 OUT UINTN
*StartIndex
,
593 for (Index
= 0; Index
< NumberOfDescriptors
; Index
++) {
594 if (BaseAddress
>= MemorySpaceMap
[Index
].BaseAddress
&&
595 BaseAddress
< MemorySpaceMap
[Index
].BaseAddress
+ MemorySpaceMap
[Index
].Length
) {
598 if (BaseAddress
+ Length
- 1 >= MemorySpaceMap
[Index
].BaseAddress
&&
599 BaseAddress
+ Length
- 1 < MemorySpaceMap
[Index
].BaseAddress
+ MemorySpaceMap
[Index
].Length
) {
604 return EFI_NOT_FOUND
;
608 Sets the attributes for a specified range in Gcd Memory Space Map.
610 This function sets the attributes for a specified range in
611 Gcd Memory Space Map.
613 @param MemorySpaceMap Gcd Memory Space Map as array
614 @param NumberOfDescriptors Number of descriptors in map
615 @param BaseAddress BaseAddress for the range
616 @param Length Length for the range
617 @param Attributes Attributes to set
619 @retval EFI_SUCCESS Memory attributes set successfully
620 @retval EFI_NOT_FOUND The specified range does not exist in Gcd Memory Space
624 SetGcdMemorySpaceAttributes (
625 IN EFI_GCD_MEMORY_SPACE_DESCRIPTOR
*MemorySpaceMap
,
626 IN UINTN NumberOfDescriptors
,
627 IN EFI_PHYSICAL_ADDRESS BaseAddress
,
636 EFI_PHYSICAL_ADDRESS RegionStart
;
640 // Get all memory descriptors covered by the memory range
642 Status
= SearchGcdMemorySpaces (
650 if (EFI_ERROR (Status
)) {
655 // Go through all related descriptors and set attributes accordingly
657 for (Index
= StartIndex
; Index
<= EndIndex
; Index
++) {
658 if (MemorySpaceMap
[Index
].GcdMemoryType
== EfiGcdMemoryTypeNonExistent
) {
662 // Calculate the start and end address of the overlapping range
664 if (BaseAddress
>= MemorySpaceMap
[Index
].BaseAddress
) {
665 RegionStart
= BaseAddress
;
667 RegionStart
= MemorySpaceMap
[Index
].BaseAddress
;
669 if (BaseAddress
+ Length
- 1 < MemorySpaceMap
[Index
].BaseAddress
+ MemorySpaceMap
[Index
].Length
) {
670 RegionLength
= BaseAddress
+ Length
- RegionStart
;
672 RegionLength
= MemorySpaceMap
[Index
].BaseAddress
+ MemorySpaceMap
[Index
].Length
- RegionStart
;
675 // Set memory attributes according to MTRR attribute and the original attribute of descriptor
677 gDS
->SetMemorySpaceAttributes (
680 (MemorySpaceMap
[Index
].Attributes
& ~EFI_MEMORY_CACHETYPE_MASK
) | (MemorySpaceMap
[Index
].Capabilities
& Attributes
)
689 Refreshes the GCD Memory Space attributes according to MTRRs.
691 This function refreshes the GCD Memory Space attributes according to MTRRs.
695 RefreshMemoryAttributesFromMtrr (
703 EFI_PHYSICAL_ADDRESS BaseAddress
;
706 UINT64 CurrentAttributes
;
708 UINTN NumberOfDescriptors
;
709 EFI_GCD_MEMORY_SPACE_DESCRIPTOR
*MemorySpaceMap
;
710 UINT64 DefaultAttributes
;
711 VARIABLE_MTRR VariableMtrr
[MTRR_NUMBER_OF_VARIABLE_MTRR
];
712 MTRR_FIXED_SETTINGS MtrrFixedSettings
;
713 UINT32 FirmwareVariableMtrrCount
;
714 UINT8 DefaultMemoryType
;
716 FirmwareVariableMtrrCount
= GetFirmwareVariableMtrrCount ();
717 ASSERT (FirmwareVariableMtrrCount
<= MTRR_NUMBER_OF_VARIABLE_MTRR
);
719 MemorySpaceMap
= NULL
;
722 // Initialize the valid bits mask and valid address mask for MTRRs
724 InitializeMtrrMask ();
727 // Get the memory attribute of variable MTRRs
729 MtrrGetMemoryAttributeInVariableMtrr (
731 mValidMtrrAddressMask
,
736 // Get the memory space map from GCD
738 Status
= gDS
->GetMemorySpaceMap (
739 &NumberOfDescriptors
,
742 ASSERT_EFI_ERROR (Status
);
744 DefaultMemoryType
= (UINT8
) MtrrGetDefaultMemoryType ();
745 DefaultAttributes
= GetMemorySpaceAttributeFromMtrrType (DefaultMemoryType
);
748 // Set default attributes to all spaces.
750 for (Index
= 0; Index
< NumberOfDescriptors
; Index
++) {
751 if (MemorySpaceMap
[Index
].GcdMemoryType
== EfiGcdMemoryTypeNonExistent
) {
754 gDS
->SetMemorySpaceAttributes (
755 MemorySpaceMap
[Index
].BaseAddress
,
756 MemorySpaceMap
[Index
].Length
,
757 (MemorySpaceMap
[Index
].Attributes
& ~EFI_MEMORY_CACHETYPE_MASK
) |
758 (MemorySpaceMap
[Index
].Capabilities
& DefaultAttributes
)
763 // Go for variable MTRRs with WB attribute
765 for (Index
= 0; Index
< FirmwareVariableMtrrCount
; Index
++) {
766 if (VariableMtrr
[Index
].Valid
&&
767 VariableMtrr
[Index
].Type
== MTRR_CACHE_WRITE_BACK
) {
768 SetGcdMemorySpaceAttributes (
771 VariableMtrr
[Index
].BaseAddress
,
772 VariableMtrr
[Index
].Length
,
779 // Go for variable MTRRs with the attribute except for WB and UC attributes
781 for (Index
= 0; Index
< FirmwareVariableMtrrCount
; Index
++) {
782 if (VariableMtrr
[Index
].Valid
&&
783 VariableMtrr
[Index
].Type
!= MTRR_CACHE_WRITE_BACK
&&
784 VariableMtrr
[Index
].Type
!= MTRR_CACHE_UNCACHEABLE
) {
785 Attributes
= GetMemorySpaceAttributeFromMtrrType ((UINT8
) VariableMtrr
[Index
].Type
);
786 SetGcdMemorySpaceAttributes (
789 VariableMtrr
[Index
].BaseAddress
,
790 VariableMtrr
[Index
].Length
,
797 // Go for variable MTRRs with UC attribute
799 for (Index
= 0; Index
< FirmwareVariableMtrrCount
; Index
++) {
800 if (VariableMtrr
[Index
].Valid
&&
801 VariableMtrr
[Index
].Type
== MTRR_CACHE_UNCACHEABLE
) {
802 SetGcdMemorySpaceAttributes (
805 VariableMtrr
[Index
].BaseAddress
,
806 VariableMtrr
[Index
].Length
,
813 // Go for fixed MTRRs
818 MtrrGetFixedMtrr (&MtrrFixedSettings
);
819 for (Index
= 0; Index
< MTRR_NUMBER_OF_FIXED_MTRR
; Index
++) {
820 RegValue
= MtrrFixedSettings
.Mtrr
[Index
];
822 // Check for continuous fixed MTRR sections
824 for (SubIndex
= 0; SubIndex
< 8; SubIndex
++) {
825 MtrrType
= (UINT8
) RShiftU64 (RegValue
, SubIndex
* 8);
826 CurrentAttributes
= GetMemorySpaceAttributeFromMtrrType (MtrrType
);
829 // A new MTRR attribute begins
831 Attributes
= CurrentAttributes
;
834 // If fixed MTRR attribute changed, then set memory attribute for previous attribute
836 if (CurrentAttributes
!= Attributes
) {
837 SetGcdMemorySpaceAttributes (
844 BaseAddress
= mFixedMtrrTable
[Index
].BaseAddress
+ mFixedMtrrTable
[Index
].Length
* SubIndex
;
846 Attributes
= CurrentAttributes
;
849 Length
+= mFixedMtrrTable
[Index
].Length
;
853 // Handle the last fixed MTRR region
855 SetGcdMemorySpaceAttributes (
864 // Free memory space map allocated by GCD service GetMemorySpaceMap ()
866 if (MemorySpaceMap
!= NULL
) {
867 FreePool (MemorySpaceMap
);
872 Check if paging is enabled or not.
875 IsPagingAndPageAddressExtensionsEnabled (
882 Cr0
.UintN
= AsmReadCr0 ();
883 Cr4
.UintN
= AsmReadCr4 ();
885 return ((Cr0
.Bits
.PG
!= 0) && (Cr4
.Bits
.PAE
!= 0));
889 Refreshes the GCD Memory Space attributes according to MTRRs and Paging.
891 This function refreshes the GCD Memory Space attributes according to MTRRs
896 RefreshGcdMemoryAttributes (
900 mIsFlushingGCD
= TRUE
;
902 if (IsMtrrSupported ()) {
903 RefreshMemoryAttributesFromMtrr ();
906 if (IsPagingAndPageAddressExtensionsEnabled ()) {
907 RefreshGcdMemoryAttributesFromPaging ();
910 mIsFlushingGCD
= FALSE
;
914 Initialize Interrupt Descriptor Table for interrupt handling.
918 InitInterruptDescriptorTable (
923 EFI_VECTOR_HANDOFF_INFO
*VectorInfoList
;
924 EFI_VECTOR_HANDOFF_INFO
*VectorInfo
;
927 Status
= EfiGetSystemConfigurationTable (&gEfiVectorHandoffTableGuid
, (VOID
**) &VectorInfoList
);
928 if (Status
== EFI_SUCCESS
&& VectorInfoList
!= NULL
) {
929 VectorInfo
= VectorInfoList
;
931 Status
= InitializeCpuInterruptHandlers (VectorInfo
);
932 ASSERT_EFI_ERROR (Status
);
937 Callback function for idle events.
939 @param Event Event whose notification function is being invoked.
940 @param Context The pointer to the notification function's context,
941 which is implementation-dependent.
946 IdleLoopEventCallback (
955 Ensure the compatibility of a memory space descriptor with the MMIO aperture.
957 The memory space descriptor can come from the GCD memory space map, or it can
958 represent a gap between two neighboring memory space descriptors. In the
959 latter case, the GcdMemoryType field is expected to be
960 EfiGcdMemoryTypeNonExistent.
962 If the memory space descriptor already has type
963 EfiGcdMemoryTypeMemoryMappedIo, and its capabilities are a superset of the
964 required capabilities, then no action is taken -- it is by definition
965 compatible with the aperture.
967 Otherwise, the intersection of the memory space descriptor is calculated with
968 the aperture. If the intersection is the empty set (no overlap), no action is
969 taken; the memory space descriptor is compatible with the aperture.
971 Otherwise, the type of the descriptor is investigated again. If the type is
972 EfiGcdMemoryTypeNonExistent (representing a gap, or a genuine descriptor with
973 such a type), then an attempt is made to add the intersection as MMIO space
974 to the GCD memory space map, with the specified capabilities. This ensures
975 continuity for the aperture, and the descriptor is deemed compatible with the
978 Otherwise, the memory space descriptor is incompatible with the MMIO
981 @param[in] Base Base address of the aperture.
982 @param[in] Length Length of the aperture.
983 @param[in] Capabilities Capabilities required by the aperture.
984 @param[in] Descriptor The descriptor to ensure compatibility with the
987 @retval EFI_SUCCESS The descriptor is compatible. The GCD memory
988 space map may have been updated, for
989 continuity within the aperture.
990 @retval EFI_INVALID_PARAMETER The descriptor is incompatible.
991 @return Error codes from gDS->AddMemorySpace().
994 IntersectMemoryDescriptor (
997 IN UINT64 Capabilities
,
998 IN CONST EFI_GCD_MEMORY_SPACE_DESCRIPTOR
*Descriptor
1001 UINT64 IntersectionBase
;
1002 UINT64 IntersectionEnd
;
1005 if (Descriptor
->GcdMemoryType
== EfiGcdMemoryTypeMemoryMappedIo
&&
1006 (Descriptor
->Capabilities
& Capabilities
) == Capabilities
) {
1010 IntersectionBase
= MAX (Base
, Descriptor
->BaseAddress
);
1011 IntersectionEnd
= MIN (Base
+ Length
,
1012 Descriptor
->BaseAddress
+ Descriptor
->Length
);
1013 if (IntersectionBase
>= IntersectionEnd
) {
1015 // The descriptor and the aperture don't overlap.
1020 if (Descriptor
->GcdMemoryType
== EfiGcdMemoryTypeNonExistent
) {
1021 Status
= gDS
->AddMemorySpace (EfiGcdMemoryTypeMemoryMappedIo
,
1022 IntersectionBase
, IntersectionEnd
- IntersectionBase
,
1025 DEBUG ((EFI_ERROR (Status
) ? DEBUG_ERROR
: DEBUG_VERBOSE
,
1026 "%a: %a: add [%Lx, %Lx): %r\n", gEfiCallerBaseName
, __FUNCTION__
,
1027 IntersectionBase
, IntersectionEnd
, Status
));
1031 DEBUG ((DEBUG_ERROR
, "%a: %a: desc [%Lx, %Lx) type %u cap %Lx conflicts "
1032 "with aperture [%Lx, %Lx) cap %Lx\n", gEfiCallerBaseName
, __FUNCTION__
,
1033 Descriptor
->BaseAddress
, Descriptor
->BaseAddress
+ Descriptor
->Length
,
1034 (UINT32
)Descriptor
->GcdMemoryType
, Descriptor
->Capabilities
,
1035 Base
, Base
+ Length
, Capabilities
));
1036 return EFI_INVALID_PARAMETER
;
1040 Add MMIO space to GCD.
1041 The routine checks the GCD database and only adds those which are
1042 not added in the specified range to GCD.
1044 @param Base Base address of the MMIO space.
1045 @param Length Length of the MMIO space.
1046 @param Capabilities Capabilities of the MMIO space.
1048 @retval EFI_SUCCESS The MMIO space was added successfully.
1051 AddMemoryMappedIoSpace (
1054 IN UINT64 Capabilities
1059 UINTN NumberOfDescriptors
;
1060 EFI_GCD_MEMORY_SPACE_DESCRIPTOR
*MemorySpaceMap
;
1062 Status
= gDS
->GetMemorySpaceMap (&NumberOfDescriptors
, &MemorySpaceMap
);
1063 if (EFI_ERROR (Status
)) {
1064 DEBUG ((DEBUG_ERROR
, "%a: %a: GetMemorySpaceMap(): %r\n",
1065 gEfiCallerBaseName
, __FUNCTION__
, Status
));
1069 for (Index
= 0; Index
< NumberOfDescriptors
; Index
++) {
1070 Status
= IntersectMemoryDescriptor (Base
, Length
, Capabilities
,
1071 &MemorySpaceMap
[Index
]);
1072 if (EFI_ERROR (Status
)) {
1073 goto FreeMemorySpaceMap
;
1079 // Make sure there are adjacent descriptors covering [Base, Base + Length).
1080 // It is possible that they have not been merged; merging can be prevented
1081 // by allocation and different capabilities.
1084 EFI_STATUS CheckStatus
;
1085 EFI_GCD_MEMORY_SPACE_DESCRIPTOR Descriptor
;
1087 for (CheckBase
= Base
;
1088 CheckBase
< Base
+ Length
;
1089 CheckBase
= Descriptor
.BaseAddress
+ Descriptor
.Length
) {
1090 CheckStatus
= gDS
->GetMemorySpaceDescriptor (CheckBase
, &Descriptor
);
1091 ASSERT_EFI_ERROR (CheckStatus
);
1092 ASSERT (Descriptor
.GcdMemoryType
== EfiGcdMemoryTypeMemoryMappedIo
);
1093 ASSERT ((Descriptor
.Capabilities
& Capabilities
) == Capabilities
);
1098 FreePool (MemorySpaceMap
);
1104 Add and allocate CPU local APIC memory mapped space.
1106 @param[in]ImageHandle Image handle this driver.
1110 AddLocalApicMemorySpace (
1111 IN EFI_HANDLE ImageHandle
1115 EFI_PHYSICAL_ADDRESS BaseAddress
;
1117 BaseAddress
= (EFI_PHYSICAL_ADDRESS
) GetLocalApicBaseAddress();
1118 Status
= AddMemoryMappedIoSpace (BaseAddress
, SIZE_4KB
, EFI_MEMORY_UC
);
1119 ASSERT_EFI_ERROR (Status
);
1122 // Try to allocate APIC memory mapped space, does not check return
1123 // status because it may be allocated by other driver, or DXE Core if
1124 // this range is built into Memory Allocation HOB.
1126 Status
= gDS
->AllocateMemorySpace (
1127 EfiGcdAllocateAddress
,
1128 EfiGcdMemoryTypeMemoryMappedIo
,
1135 if (EFI_ERROR (Status
)) {
1136 DEBUG ((DEBUG_INFO
, "%a: %a: AllocateMemorySpace() Status - %r\n",
1137 gEfiCallerBaseName
, __FUNCTION__
, Status
));
1142 Initialize the state information for the CPU Architectural Protocol.
1144 @param ImageHandle Image handle this driver.
1145 @param SystemTable Pointer to the System Table.
1147 @retval EFI_SUCCESS Thread can be successfully created
1148 @retval EFI_OUT_OF_RESOURCES Cannot allocate protocol data structure
1149 @retval EFI_DEVICE_ERROR Cannot create the thread
1155 IN EFI_HANDLE ImageHandle
,
1156 IN EFI_SYSTEM_TABLE
*SystemTable
1160 EFI_EVENT IdleLoopEvent
;
1162 InitializePageTableLib();
1164 InitializeFloatingPointUnits ();
1167 // Make sure interrupts are disabled
1169 DisableInterrupts ();
1174 InitGlobalDescriptorTable ();
1177 // Setup IDT pointer, IDT and interrupt entry points
1179 InitInterruptDescriptorTable ();
1182 // Install CPU Architectural Protocol
1184 Status
= gBS
->InstallMultipleProtocolInterfaces (
1186 &gEfiCpuArchProtocolGuid
, &gCpu
,
1189 ASSERT_EFI_ERROR (Status
);
1192 // Refresh GCD memory space map according to MTRR value.
1194 RefreshGcdMemoryAttributes ();
1197 // Add and allocate local APIC memory mapped space
1199 AddLocalApicMemorySpace (ImageHandle
);
1202 // Setup a callback for idle events
1204 Status
= gBS
->CreateEventEx (
1207 IdleLoopEventCallback
,
1209 &gIdleLoopEventGuid
,
1212 ASSERT_EFI_ERROR (Status
);
1214 InitializeMpSupport ();