123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260 |
- /** @file
- CPU DXE Module to produce CPU ARCH Protocol.
- Copyright (c) 2008 - 2018, Intel Corporation. All rights reserved.<BR>
- SPDX-License-Identifier: BSD-2-Clause-Patent
- **/
- #include "CpuDxe.h"
- #include "CpuMp.h"
- #include "CpuPageTable.h"
- //
- // Global Variables
- //
- BOOLEAN InterruptState = FALSE;
- EFI_HANDLE mCpuHandle = NULL;
- BOOLEAN mIsFlushingGCD;
- BOOLEAN mIsAllocatingPageTable = FALSE;
- UINT64 mValidMtrrAddressMask;
- UINT64 mValidMtrrBitsMask;
- UINT64 mTimerPeriod = 0;
- FIXED_MTRR mFixedMtrrTable[] = {
- {
- MSR_IA32_MTRR_FIX64K_00000,
- 0,
- 0x10000
- },
- {
- MSR_IA32_MTRR_FIX16K_80000,
- 0x80000,
- 0x4000
- },
- {
- MSR_IA32_MTRR_FIX16K_A0000,
- 0xA0000,
- 0x4000
- },
- {
- MSR_IA32_MTRR_FIX4K_C0000,
- 0xC0000,
- 0x1000
- },
- {
- MSR_IA32_MTRR_FIX4K_C8000,
- 0xC8000,
- 0x1000
- },
- {
- MSR_IA32_MTRR_FIX4K_D0000,
- 0xD0000,
- 0x1000
- },
- {
- MSR_IA32_MTRR_FIX4K_D8000,
- 0xD8000,
- 0x1000
- },
- {
- MSR_IA32_MTRR_FIX4K_E0000,
- 0xE0000,
- 0x1000
- },
- {
- MSR_IA32_MTRR_FIX4K_E8000,
- 0xE8000,
- 0x1000
- },
- {
- MSR_IA32_MTRR_FIX4K_F0000,
- 0xF0000,
- 0x1000
- },
- {
- MSR_IA32_MTRR_FIX4K_F8000,
- 0xF8000,
- 0x1000
- },
- };
- EFI_CPU_ARCH_PROTOCOL gCpu = {
- CpuFlushCpuDataCache,
- CpuEnableInterrupt,
- CpuDisableInterrupt,
- CpuGetInterruptState,
- CpuInit,
- CpuRegisterInterruptHandler,
- CpuGetTimerValue,
- CpuSetMemoryAttributes,
- 1, // NumberOfTimers
- 4 // DmaBufferAlignment
- };
- //
- // CPU Arch Protocol Functions
- //
- /**
- Flush CPU data cache. If the instruction cache is fully coherent
- with all DMA operations then function can just return EFI_SUCCESS.
- @param This Protocol instance structure
- @param Start Physical address to start flushing from.
- @param Length Number of bytes to flush. Round up to chipset
- granularity.
- @param FlushType Specifies the type of flush operation to perform.
- @retval EFI_SUCCESS If cache was flushed
- @retval EFI_UNSUPPORTED If flush type is not supported.
- @retval EFI_DEVICE_ERROR If requested range could not be flushed.
- **/
- EFI_STATUS
- EFIAPI
- CpuFlushCpuDataCache (
- IN EFI_CPU_ARCH_PROTOCOL *This,
- IN EFI_PHYSICAL_ADDRESS Start,
- IN UINT64 Length,
- IN EFI_CPU_FLUSH_TYPE FlushType
- )
- {
- if (FlushType == EfiCpuFlushTypeWriteBackInvalidate) {
- AsmWbinvd ();
- return EFI_SUCCESS;
- } else if (FlushType == EfiCpuFlushTypeInvalidate) {
- AsmInvd ();
- return EFI_SUCCESS;
- } else {
- return EFI_UNSUPPORTED;
- }
- }
- /**
- Enables CPU interrupts.
- @param This Protocol instance structure
- @retval EFI_SUCCESS If interrupts were enabled in the CPU
- @retval EFI_DEVICE_ERROR If interrupts could not be enabled on the CPU.
- **/
- EFI_STATUS
- EFIAPI
- CpuEnableInterrupt (
- IN EFI_CPU_ARCH_PROTOCOL *This
- )
- {
- EnableInterrupts ();
- InterruptState = TRUE;
- return EFI_SUCCESS;
- }
- /**
- Disables CPU interrupts.
- @param This Protocol instance structure
- @retval EFI_SUCCESS If interrupts were disabled in the CPU.
- @retval EFI_DEVICE_ERROR If interrupts could not be disabled on the CPU.
- **/
- EFI_STATUS
- EFIAPI
- CpuDisableInterrupt (
- IN EFI_CPU_ARCH_PROTOCOL *This
- )
- {
- DisableInterrupts ();
- InterruptState = FALSE;
- return EFI_SUCCESS;
- }
- /**
- Return the state of interrupts.
- @param This Protocol instance structure
- @param State Pointer to the CPU's current interrupt state
- @retval EFI_SUCCESS If interrupts were disabled in the CPU.
- @retval EFI_INVALID_PARAMETER State is NULL.
- **/
- EFI_STATUS
- EFIAPI
- CpuGetInterruptState (
- IN EFI_CPU_ARCH_PROTOCOL *This,
- OUT BOOLEAN *State
- )
- {
- if (State == NULL) {
- return EFI_INVALID_PARAMETER;
- }
- *State = InterruptState;
- return EFI_SUCCESS;
- }
- /**
- Generates an INIT to the CPU.
- @param This Protocol instance structure
- @param InitType Type of CPU INIT to perform
- @retval EFI_SUCCESS If CPU INIT occurred. This value should never be
- seen.
- @retval EFI_DEVICE_ERROR If CPU INIT failed.
- @retval EFI_UNSUPPORTED Requested type of CPU INIT not supported.
- **/
- EFI_STATUS
- EFIAPI
- CpuInit (
- IN EFI_CPU_ARCH_PROTOCOL *This,
- IN EFI_CPU_INIT_TYPE InitType
- )
- {
- return EFI_UNSUPPORTED;
- }
- /**
- Registers a function to be called from the CPU interrupt handler.
- @param This Protocol instance structure
- @param InterruptType Defines which interrupt to hook. IA-32
- valid range is 0x00 through 0xFF
- @param InterruptHandler A pointer to a function of type
- EFI_CPU_INTERRUPT_HANDLER that is called
- when a processor interrupt occurs. A null
- pointer is an error condition.
- @retval EFI_SUCCESS If handler installed or uninstalled.
- @retval EFI_ALREADY_STARTED InterruptHandler is not NULL, and a handler
- for InterruptType was previously installed.
- @retval EFI_INVALID_PARAMETER InterruptHandler is NULL, and a handler for
- InterruptType was not previously installed.
- @retval EFI_UNSUPPORTED The interrupt specified by InterruptType
- is not supported.
- **/
- EFI_STATUS
- EFIAPI
- CpuRegisterInterruptHandler (
- IN EFI_CPU_ARCH_PROTOCOL *This,
- IN EFI_EXCEPTION_TYPE InterruptType,
- IN EFI_CPU_INTERRUPT_HANDLER InterruptHandler
- )
- {
- return RegisterCpuInterruptHandler (InterruptType, InterruptHandler);
- }
- /**
- Returns a timer value from one of the CPU's internal timers. There is no
- inherent time interval between ticks but is a function of the CPU frequency.
- @param This - Protocol instance structure.
- @param TimerIndex - Specifies which CPU timer is requested.
- @param TimerValue - Pointer to the returned timer value.
- @param TimerPeriod - A pointer to the amount of time that passes
- in femtoseconds (10-15) for each increment
- of TimerValue. If TimerValue does not
- increment at a predictable rate, then 0 is
- returned. The amount of time that has
- passed between two calls to GetTimerValue()
- can be calculated with the formula
- (TimerValue2 - TimerValue1) * TimerPeriod.
- This parameter is optional and may be NULL.
- @retval EFI_SUCCESS - If the CPU timer count was returned.
- @retval EFI_UNSUPPORTED - If the CPU does not have any readable timers.
- @retval EFI_DEVICE_ERROR - If an error occurred while reading the timer.
- @retval EFI_INVALID_PARAMETER - TimerIndex is not valid or TimerValue is NULL.
- **/
- EFI_STATUS
- EFIAPI
- CpuGetTimerValue (
- IN EFI_CPU_ARCH_PROTOCOL *This,
- IN UINT32 TimerIndex,
- OUT UINT64 *TimerValue,
- OUT UINT64 *TimerPeriod OPTIONAL
- )
- {
- UINT64 BeginValue;
- UINT64 EndValue;
- if (TimerValue == NULL) {
- return EFI_INVALID_PARAMETER;
- }
- if (TimerIndex != 0) {
- return EFI_INVALID_PARAMETER;
- }
- *TimerValue = AsmReadTsc ();
- if (TimerPeriod != NULL) {
- if (mTimerPeriod == 0) {
- //
- // Read time stamp counter before and after delay of 100 microseconds
- //
- BeginValue = AsmReadTsc ();
- MicroSecondDelay (100);
- EndValue = AsmReadTsc ();
- //
- // Calculate the actual frequency
- //
- mTimerPeriod = DivU64x64Remainder (
- MultU64x32 (
- 1000 * 1000 * 1000,
- 100
- ),
- EndValue - BeginValue,
- NULL
- );
- }
- *TimerPeriod = mTimerPeriod;
- }
- return EFI_SUCCESS;
- }
- /**
- A minimal wrapper function that allows MtrrSetAllMtrrs() to be passed to
- EFI_MP_SERVICES_PROTOCOL.StartupAllAPs() as Procedure.
- @param[in] Buffer Pointer to an MTRR_SETTINGS object, to be passed to
- MtrrSetAllMtrrs().
- **/
- VOID
- EFIAPI
- SetMtrrsFromBuffer (
- IN VOID *Buffer
- )
- {
- MtrrSetAllMtrrs (Buffer);
- }
- /**
- Implementation of SetMemoryAttributes() service of CPU Architecture Protocol.
- This function modifies the attributes for the memory region specified by BaseAddress and
- Length from their current attributes to the attributes specified by Attributes.
- @param This The EFI_CPU_ARCH_PROTOCOL instance.
- @param BaseAddress The physical address that is the start address of a memory region.
- @param Length The size in bytes of the memory region.
- @param Attributes The bit mask of attributes to set for the memory region.
- @retval EFI_SUCCESS The attributes were set for the memory region.
- @retval EFI_ACCESS_DENIED The attributes for the memory resource range specified by
- BaseAddress and Length cannot be modified.
- @retval EFI_INVALID_PARAMETER Length is zero.
- Attributes specified an illegal combination of attributes that
- cannot be set together.
- @retval EFI_OUT_OF_RESOURCES There are not enough system resources to modify the attributes of
- the memory resource range.
- @retval EFI_UNSUPPORTED The processor does not support one or more bytes of the memory
- resource range specified by BaseAddress and Length.
- The bit mask of attributes is not support for the memory resource
- range specified by BaseAddress and Length.
- **/
- EFI_STATUS
- EFIAPI
- CpuSetMemoryAttributes (
- IN EFI_CPU_ARCH_PROTOCOL *This,
- IN EFI_PHYSICAL_ADDRESS BaseAddress,
- IN UINT64 Length,
- IN UINT64 Attributes
- )
- {
- RETURN_STATUS Status;
- MTRR_MEMORY_CACHE_TYPE CacheType;
- EFI_STATUS MpStatus;
- EFI_MP_SERVICES_PROTOCOL *MpService;
- MTRR_SETTINGS MtrrSettings;
- UINT64 CacheAttributes;
- UINT64 MemoryAttributes;
- MTRR_MEMORY_CACHE_TYPE CurrentCacheType;
- //
- // If this function is called because GCD SetMemorySpaceAttributes () is called
- // by RefreshGcdMemoryAttributes (), then we are just synchronizing GCD memory
- // map with MTRR values. So there is no need to modify MTRRs, just return immediately
- // to avoid unnecessary computing.
- //
- if (mIsFlushingGCD) {
- DEBUG ((DEBUG_VERBOSE, " Flushing GCD\n"));
- return EFI_SUCCESS;
- }
- //
- // During memory attributes updating, new pages may be allocated to setup
- // smaller granularity of page table. Page allocation action might then cause
- // another calling of CpuSetMemoryAttributes() recursively, due to memory
- // protection policy configured (such as PcdDxeNxMemoryProtectionPolicy).
- // Since this driver will always protect memory used as page table by itself,
- // there's no need to apply protection policy requested from memory service.
- // So it's safe to just return EFI_SUCCESS if this time of calling is caused
- // by page table memory allocation.
- //
- if (mIsAllocatingPageTable) {
- DEBUG ((DEBUG_VERBOSE, " Allocating page table memory\n"));
- return EFI_SUCCESS;
- }
- CacheAttributes = Attributes & EFI_CACHE_ATTRIBUTE_MASK;
- MemoryAttributes = Attributes & EFI_MEMORY_ATTRIBUTE_MASK;
- if (Attributes != (CacheAttributes | MemoryAttributes)) {
- return EFI_INVALID_PARAMETER;
- }
- if (CacheAttributes != 0) {
- if (!IsMtrrSupported ()) {
- return EFI_UNSUPPORTED;
- }
- switch (CacheAttributes) {
- case EFI_MEMORY_UC:
- CacheType = CacheUncacheable;
- break;
- case EFI_MEMORY_WC:
- CacheType = CacheWriteCombining;
- break;
- case EFI_MEMORY_WT:
- CacheType = CacheWriteThrough;
- break;
- case EFI_MEMORY_WP:
- CacheType = CacheWriteProtected;
- break;
- case EFI_MEMORY_WB:
- CacheType = CacheWriteBack;
- break;
- default:
- return EFI_INVALID_PARAMETER;
- }
- CurrentCacheType = MtrrGetMemoryAttribute (BaseAddress);
- if (CurrentCacheType != CacheType) {
- //
- // call MTRR library function
- //
- Status = MtrrSetMemoryAttribute (
- BaseAddress,
- Length,
- CacheType
- );
- if (!RETURN_ERROR (Status)) {
- MpStatus = gBS->LocateProtocol (
- &gEfiMpServiceProtocolGuid,
- NULL,
- (VOID **)&MpService
- );
- //
- // Synchronize the update with all APs
- //
- if (!EFI_ERROR (MpStatus)) {
- MtrrGetAllMtrrs (&MtrrSettings);
- MpStatus = MpService->StartupAllAPs (
- MpService, // This
- SetMtrrsFromBuffer, // Procedure
- FALSE, // SingleThread
- NULL, // WaitEvent
- 0, // TimeoutInMicrosecsond
- &MtrrSettings, // ProcedureArgument
- NULL // FailedCpuList
- );
- ASSERT (MpStatus == EFI_SUCCESS || MpStatus == EFI_NOT_STARTED);
- }
- }
- if (EFI_ERROR (Status)) {
- return Status;
- }
- }
- }
- //
- // Set memory attribute by page table
- //
- return AssignMemoryPageAttributes (NULL, BaseAddress, Length, MemoryAttributes, NULL);
- }
- /**
- Initializes the valid bits mask and valid address mask for MTRRs.
- This function initializes the valid bits mask and valid address mask for MTRRs.
- **/
- VOID
- InitializeMtrrMask (
- VOID
- )
- {
- UINT32 RegEax;
- UINT8 PhysicalAddressBits;
- AsmCpuid (0x80000000, &RegEax, NULL, NULL, NULL);
- if (RegEax >= 0x80000008) {
- AsmCpuid (0x80000008, &RegEax, NULL, NULL, NULL);
- PhysicalAddressBits = (UINT8)RegEax;
- } else {
- PhysicalAddressBits = 36;
- }
- mValidMtrrBitsMask = LShiftU64 (1, PhysicalAddressBits) - 1;
- mValidMtrrAddressMask = mValidMtrrBitsMask & 0xfffffffffffff000ULL;
- }
- /**
- Gets GCD Mem Space type from MTRR Type.
- This function gets GCD Mem Space type from MTRR Type.
- @param MtrrAttributes MTRR memory type
- @return GCD Mem Space type
- **/
- UINT64
- GetMemorySpaceAttributeFromMtrrType (
- IN UINT8 MtrrAttributes
- )
- {
- switch (MtrrAttributes) {
- case MTRR_CACHE_UNCACHEABLE:
- return EFI_MEMORY_UC;
- case MTRR_CACHE_WRITE_COMBINING:
- return EFI_MEMORY_WC;
- case MTRR_CACHE_WRITE_THROUGH:
- return EFI_MEMORY_WT;
- case MTRR_CACHE_WRITE_PROTECTED:
- return EFI_MEMORY_WP;
- case MTRR_CACHE_WRITE_BACK:
- return EFI_MEMORY_WB;
- default:
- return 0;
- }
- }
- /**
- Searches memory descriptors covered by given memory range.
- This function searches into the Gcd Memory Space for descriptors
- (from StartIndex to EndIndex) that contains the memory range
- specified by BaseAddress and Length.
- @param MemorySpaceMap Gcd Memory Space Map as array.
- @param NumberOfDescriptors Number of descriptors in map.
- @param BaseAddress BaseAddress for the requested range.
- @param Length Length for the requested range.
- @param StartIndex Start index into the Gcd Memory Space Map.
- @param EndIndex End index into the Gcd Memory Space Map.
- @retval EFI_SUCCESS Search successfully.
- @retval EFI_NOT_FOUND The requested descriptors does not exist.
- **/
- EFI_STATUS
- SearchGcdMemorySpaces (
- IN EFI_GCD_MEMORY_SPACE_DESCRIPTOR *MemorySpaceMap,
- IN UINTN NumberOfDescriptors,
- IN EFI_PHYSICAL_ADDRESS BaseAddress,
- IN UINT64 Length,
- OUT UINTN *StartIndex,
- OUT UINTN *EndIndex
- )
- {
- UINTN Index;
- *StartIndex = 0;
- *EndIndex = 0;
- for (Index = 0; Index < NumberOfDescriptors; Index++) {
- if ((BaseAddress >= MemorySpaceMap[Index].BaseAddress) &&
- (BaseAddress < MemorySpaceMap[Index].BaseAddress + MemorySpaceMap[Index].Length))
- {
- *StartIndex = Index;
- }
- if ((BaseAddress + Length - 1 >= MemorySpaceMap[Index].BaseAddress) &&
- (BaseAddress + Length - 1 < MemorySpaceMap[Index].BaseAddress + MemorySpaceMap[Index].Length))
- {
- *EndIndex = Index;
- return EFI_SUCCESS;
- }
- }
- return EFI_NOT_FOUND;
- }
- /**
- Sets the attributes for a specified range in Gcd Memory Space Map.
- This function sets the attributes for a specified range in
- Gcd Memory Space Map.
- @param MemorySpaceMap Gcd Memory Space Map as array
- @param NumberOfDescriptors Number of descriptors in map
- @param BaseAddress BaseAddress for the range
- @param Length Length for the range
- @param Attributes Attributes to set
- @retval EFI_SUCCESS Memory attributes set successfully
- @retval EFI_NOT_FOUND The specified range does not exist in Gcd Memory Space
- **/
- EFI_STATUS
- SetGcdMemorySpaceAttributes (
- IN EFI_GCD_MEMORY_SPACE_DESCRIPTOR *MemorySpaceMap,
- IN UINTN NumberOfDescriptors,
- IN EFI_PHYSICAL_ADDRESS BaseAddress,
- IN UINT64 Length,
- IN UINT64 Attributes
- )
- {
- EFI_STATUS Status;
- UINTN Index;
- UINTN StartIndex;
- UINTN EndIndex;
- EFI_PHYSICAL_ADDRESS RegionStart;
- UINT64 RegionLength;
- //
- // Get all memory descriptors covered by the memory range
- //
- Status = SearchGcdMemorySpaces (
- MemorySpaceMap,
- NumberOfDescriptors,
- BaseAddress,
- Length,
- &StartIndex,
- &EndIndex
- );
- if (EFI_ERROR (Status)) {
- return Status;
- }
- //
- // Go through all related descriptors and set attributes accordingly
- //
- for (Index = StartIndex; Index <= EndIndex; Index++) {
- if (MemorySpaceMap[Index].GcdMemoryType == EfiGcdMemoryTypeNonExistent) {
- continue;
- }
- //
- // Calculate the start and end address of the overlapping range
- //
- if (BaseAddress >= MemorySpaceMap[Index].BaseAddress) {
- RegionStart = BaseAddress;
- } else {
- RegionStart = MemorySpaceMap[Index].BaseAddress;
- }
- if (BaseAddress + Length - 1 < MemorySpaceMap[Index].BaseAddress + MemorySpaceMap[Index].Length) {
- RegionLength = BaseAddress + Length - RegionStart;
- } else {
- RegionLength = MemorySpaceMap[Index].BaseAddress + MemorySpaceMap[Index].Length - RegionStart;
- }
- //
- // Set memory attributes according to MTRR attribute and the original attribute of descriptor
- //
- gDS->SetMemorySpaceAttributes (
- RegionStart,
- RegionLength,
- (MemorySpaceMap[Index].Attributes & ~EFI_CACHE_ATTRIBUTE_MASK) | (MemorySpaceMap[Index].Capabilities & Attributes)
- );
- }
- return EFI_SUCCESS;
- }
- /**
- Refreshes the GCD Memory Space attributes according to MTRRs.
- This function refreshes the GCD Memory Space attributes according to MTRRs.
- **/
- VOID
- RefreshMemoryAttributesFromMtrr (
- VOID
- )
- {
- EFI_STATUS Status;
- UINTN Index;
- UINTN SubIndex;
- UINT64 RegValue;
- EFI_PHYSICAL_ADDRESS BaseAddress;
- UINT64 Length;
- UINT64 Attributes;
- UINT64 CurrentAttributes;
- UINT8 MtrrType;
- UINTN NumberOfDescriptors;
- EFI_GCD_MEMORY_SPACE_DESCRIPTOR *MemorySpaceMap;
- UINT64 DefaultAttributes;
- VARIABLE_MTRR VariableMtrr[MTRR_NUMBER_OF_VARIABLE_MTRR];
- MTRR_FIXED_SETTINGS MtrrFixedSettings;
- UINT32 FirmwareVariableMtrrCount;
- UINT8 DefaultMemoryType;
- FirmwareVariableMtrrCount = GetFirmwareVariableMtrrCount ();
- ASSERT (FirmwareVariableMtrrCount <= MTRR_NUMBER_OF_VARIABLE_MTRR);
- MemorySpaceMap = NULL;
- //
- // Initialize the valid bits mask and valid address mask for MTRRs
- //
- InitializeMtrrMask ();
- //
- // Get the memory attribute of variable MTRRs
- //
- MtrrGetMemoryAttributeInVariableMtrr (
- mValidMtrrBitsMask,
- mValidMtrrAddressMask,
- VariableMtrr
- );
- //
- // Get the memory space map from GCD
- //
- Status = gDS->GetMemorySpaceMap (
- &NumberOfDescriptors,
- &MemorySpaceMap
- );
- ASSERT_EFI_ERROR (Status);
- DefaultMemoryType = (UINT8)MtrrGetDefaultMemoryType ();
- DefaultAttributes = GetMemorySpaceAttributeFromMtrrType (DefaultMemoryType);
- //
- // Set default attributes to all spaces.
- //
- for (Index = 0; Index < NumberOfDescriptors; Index++) {
- if (MemorySpaceMap[Index].GcdMemoryType == EfiGcdMemoryTypeNonExistent) {
- continue;
- }
- gDS->SetMemorySpaceAttributes (
- MemorySpaceMap[Index].BaseAddress,
- MemorySpaceMap[Index].Length,
- (MemorySpaceMap[Index].Attributes & ~EFI_CACHE_ATTRIBUTE_MASK) |
- (MemorySpaceMap[Index].Capabilities & DefaultAttributes)
- );
- }
- //
- // Go for variable MTRRs with WB attribute
- //
- for (Index = 0; Index < FirmwareVariableMtrrCount; Index++) {
- if (VariableMtrr[Index].Valid &&
- (VariableMtrr[Index].Type == MTRR_CACHE_WRITE_BACK))
- {
- SetGcdMemorySpaceAttributes (
- MemorySpaceMap,
- NumberOfDescriptors,
- VariableMtrr[Index].BaseAddress,
- VariableMtrr[Index].Length,
- EFI_MEMORY_WB
- );
- }
- }
- //
- // Go for variable MTRRs with the attribute except for WB and UC attributes
- //
- for (Index = 0; Index < FirmwareVariableMtrrCount; Index++) {
- if (VariableMtrr[Index].Valid &&
- (VariableMtrr[Index].Type != MTRR_CACHE_WRITE_BACK) &&
- (VariableMtrr[Index].Type != MTRR_CACHE_UNCACHEABLE))
- {
- Attributes = GetMemorySpaceAttributeFromMtrrType ((UINT8)VariableMtrr[Index].Type);
- SetGcdMemorySpaceAttributes (
- MemorySpaceMap,
- NumberOfDescriptors,
- VariableMtrr[Index].BaseAddress,
- VariableMtrr[Index].Length,
- Attributes
- );
- }
- }
- //
- // Go for variable MTRRs with UC attribute
- //
- for (Index = 0; Index < FirmwareVariableMtrrCount; Index++) {
- if (VariableMtrr[Index].Valid &&
- (VariableMtrr[Index].Type == MTRR_CACHE_UNCACHEABLE))
- {
- SetGcdMemorySpaceAttributes (
- MemorySpaceMap,
- NumberOfDescriptors,
- VariableMtrr[Index].BaseAddress,
- VariableMtrr[Index].Length,
- EFI_MEMORY_UC
- );
- }
- }
- //
- // Go for fixed MTRRs
- //
- Attributes = 0;
- BaseAddress = 0;
- Length = 0;
- MtrrGetFixedMtrr (&MtrrFixedSettings);
- for (Index = 0; Index < MTRR_NUMBER_OF_FIXED_MTRR; Index++) {
- RegValue = MtrrFixedSettings.Mtrr[Index];
- //
- // Check for continuous fixed MTRR sections
- //
- for (SubIndex = 0; SubIndex < 8; SubIndex++) {
- MtrrType = (UINT8)RShiftU64 (RegValue, SubIndex * 8);
- CurrentAttributes = GetMemorySpaceAttributeFromMtrrType (MtrrType);
- if (Length == 0) {
- //
- // A new MTRR attribute begins
- //
- Attributes = CurrentAttributes;
- } else {
- //
- // If fixed MTRR attribute changed, then set memory attribute for previous attribute
- //
- if (CurrentAttributes != Attributes) {
- SetGcdMemorySpaceAttributes (
- MemorySpaceMap,
- NumberOfDescriptors,
- BaseAddress,
- Length,
- Attributes
- );
- BaseAddress = mFixedMtrrTable[Index].BaseAddress + mFixedMtrrTable[Index].Length * SubIndex;
- Length = 0;
- Attributes = CurrentAttributes;
- }
- }
- Length += mFixedMtrrTable[Index].Length;
- }
- }
- //
- // Handle the last fixed MTRR region
- //
- SetGcdMemorySpaceAttributes (
- MemorySpaceMap,
- NumberOfDescriptors,
- BaseAddress,
- Length,
- Attributes
- );
- //
- // Free memory space map allocated by GCD service GetMemorySpaceMap ()
- //
- if (MemorySpaceMap != NULL) {
- FreePool (MemorySpaceMap);
- }
- }
- /**
- Check if paging is enabled or not.
- **/
- BOOLEAN
- IsPagingAndPageAddressExtensionsEnabled (
- VOID
- )
- {
- IA32_CR0 Cr0;
- IA32_CR4 Cr4;
- Cr0.UintN = AsmReadCr0 ();
- Cr4.UintN = AsmReadCr4 ();
- return ((Cr0.Bits.PG != 0) && (Cr4.Bits.PAE != 0));
- }
- /**
- Refreshes the GCD Memory Space attributes according to MTRRs and Paging.
- This function refreshes the GCD Memory Space attributes according to MTRRs
- and page tables.
- **/
- VOID
- RefreshGcdMemoryAttributes (
- VOID
- )
- {
- mIsFlushingGCD = TRUE;
- if (IsMtrrSupported ()) {
- RefreshMemoryAttributesFromMtrr ();
- }
- if (IsPagingAndPageAddressExtensionsEnabled ()) {
- RefreshGcdMemoryAttributesFromPaging ();
- }
- mIsFlushingGCD = FALSE;
- }
- /**
- Initialize Interrupt Descriptor Table for interrupt handling.
- **/
- VOID
- InitInterruptDescriptorTable (
- VOID
- )
- {
- EFI_STATUS Status;
- EFI_VECTOR_HANDOFF_INFO *VectorInfoList;
- EFI_VECTOR_HANDOFF_INFO *VectorInfo;
- VectorInfo = NULL;
- Status = EfiGetSystemConfigurationTable (&gEfiVectorHandoffTableGuid, (VOID **)&VectorInfoList);
- if ((Status == EFI_SUCCESS) && (VectorInfoList != NULL)) {
- VectorInfo = VectorInfoList;
- }
- Status = InitializeCpuInterruptHandlers (VectorInfo);
- ASSERT_EFI_ERROR (Status);
- }
- /**
- Callback function for idle events.
- @param Event Event whose notification function is being invoked.
- @param Context The pointer to the notification function's context,
- which is implementation-dependent.
- **/
- VOID
- EFIAPI
- IdleLoopEventCallback (
- IN EFI_EVENT Event,
- IN VOID *Context
- )
- {
- CpuSleep ();
- }
- /**
- Ensure the compatibility of a memory space descriptor with the MMIO aperture.
- The memory space descriptor can come from the GCD memory space map, or it can
- represent a gap between two neighboring memory space descriptors. In the
- latter case, the GcdMemoryType field is expected to be
- EfiGcdMemoryTypeNonExistent.
- If the memory space descriptor already has type
- EfiGcdMemoryTypeMemoryMappedIo, and its capabilities are a superset of the
- required capabilities, then no action is taken -- it is by definition
- compatible with the aperture.
- Otherwise, the intersection of the memory space descriptor is calculated with
- the aperture. If the intersection is the empty set (no overlap), no action is
- taken; the memory space descriptor is compatible with the aperture.
- Otherwise, the type of the descriptor is investigated again. If the type is
- EfiGcdMemoryTypeNonExistent (representing a gap, or a genuine descriptor with
- such a type), then an attempt is made to add the intersection as MMIO space
- to the GCD memory space map, with the specified capabilities. This ensures
- continuity for the aperture, and the descriptor is deemed compatible with the
- aperture.
- Otherwise, the memory space descriptor is incompatible with the MMIO
- aperture.
- @param[in] Base Base address of the aperture.
- @param[in] Length Length of the aperture.
- @param[in] Capabilities Capabilities required by the aperture.
- @param[in] Descriptor The descriptor to ensure compatibility with the
- aperture for.
- @retval EFI_SUCCESS The descriptor is compatible. The GCD memory
- space map may have been updated, for
- continuity within the aperture.
- @retval EFI_INVALID_PARAMETER The descriptor is incompatible.
- @return Error codes from gDS->AddMemorySpace().
- **/
- EFI_STATUS
- IntersectMemoryDescriptor (
- IN UINT64 Base,
- IN UINT64 Length,
- IN UINT64 Capabilities,
- IN CONST EFI_GCD_MEMORY_SPACE_DESCRIPTOR *Descriptor
- )
- {
- UINT64 IntersectionBase;
- UINT64 IntersectionEnd;
- EFI_STATUS Status;
- if ((Descriptor->GcdMemoryType == EfiGcdMemoryTypeMemoryMappedIo) &&
- ((Descriptor->Capabilities & Capabilities) == Capabilities))
- {
- return EFI_SUCCESS;
- }
- IntersectionBase = MAX (Base, Descriptor->BaseAddress);
- IntersectionEnd = MIN (
- Base + Length,
- Descriptor->BaseAddress + Descriptor->Length
- );
- if (IntersectionBase >= IntersectionEnd) {
- //
- // The descriptor and the aperture don't overlap.
- //
- return EFI_SUCCESS;
- }
- if (Descriptor->GcdMemoryType == EfiGcdMemoryTypeNonExistent) {
- Status = gDS->AddMemorySpace (
- EfiGcdMemoryTypeMemoryMappedIo,
- IntersectionBase,
- IntersectionEnd - IntersectionBase,
- Capabilities
- );
- DEBUG ((
- EFI_ERROR (Status) ? DEBUG_ERROR : DEBUG_VERBOSE,
- "%a: %a: add [%Lx, %Lx): %r\n",
- gEfiCallerBaseName,
- __FUNCTION__,
- IntersectionBase,
- IntersectionEnd,
- Status
- ));
- return Status;
- }
- DEBUG ((
- DEBUG_ERROR,
- "%a: %a: desc [%Lx, %Lx) type %u cap %Lx conflicts "
- "with aperture [%Lx, %Lx) cap %Lx\n",
- gEfiCallerBaseName,
- __FUNCTION__,
- Descriptor->BaseAddress,
- Descriptor->BaseAddress + Descriptor->Length,
- (UINT32)Descriptor->GcdMemoryType,
- Descriptor->Capabilities,
- Base,
- Base + Length,
- Capabilities
- ));
- return EFI_INVALID_PARAMETER;
- }
- /**
- Add MMIO space to GCD.
- The routine checks the GCD database and only adds those which are
- not added in the specified range to GCD.
- @param Base Base address of the MMIO space.
- @param Length Length of the MMIO space.
- @param Capabilities Capabilities of the MMIO space.
- @retval EFI_SUCCESS The MMIO space was added successfully.
- **/
- EFI_STATUS
- AddMemoryMappedIoSpace (
- IN UINT64 Base,
- IN UINT64 Length,
- IN UINT64 Capabilities
- )
- {
- EFI_STATUS Status;
- UINTN Index;
- UINTN NumberOfDescriptors;
- EFI_GCD_MEMORY_SPACE_DESCRIPTOR *MemorySpaceMap;
- Status = gDS->GetMemorySpaceMap (&NumberOfDescriptors, &MemorySpaceMap);
- if (EFI_ERROR (Status)) {
- DEBUG ((
- DEBUG_ERROR,
- "%a: %a: GetMemorySpaceMap(): %r\n",
- gEfiCallerBaseName,
- __FUNCTION__,
- Status
- ));
- return Status;
- }
- for (Index = 0; Index < NumberOfDescriptors; Index++) {
- Status = IntersectMemoryDescriptor (
- Base,
- Length,
- Capabilities,
- &MemorySpaceMap[Index]
- );
- if (EFI_ERROR (Status)) {
- goto FreeMemorySpaceMap;
- }
- }
- DEBUG_CODE_BEGIN ();
- //
- // Make sure there are adjacent descriptors covering [Base, Base + Length).
- // It is possible that they have not been merged; merging can be prevented
- // by allocation and different capabilities.
- //
- UINT64 CheckBase;
- EFI_STATUS CheckStatus;
- EFI_GCD_MEMORY_SPACE_DESCRIPTOR Descriptor;
- for (CheckBase = Base;
- CheckBase < Base + Length;
- CheckBase = Descriptor.BaseAddress + Descriptor.Length)
- {
- CheckStatus = gDS->GetMemorySpaceDescriptor (CheckBase, &Descriptor);
- ASSERT_EFI_ERROR (CheckStatus);
- ASSERT (Descriptor.GcdMemoryType == EfiGcdMemoryTypeMemoryMappedIo);
- ASSERT ((Descriptor.Capabilities & Capabilities) == Capabilities);
- }
- DEBUG_CODE_END ();
- FreeMemorySpaceMap:
- FreePool (MemorySpaceMap);
- return Status;
- }
- /**
- Add and allocate CPU local APIC memory mapped space.
- @param[in]ImageHandle Image handle this driver.
- **/
- VOID
- AddLocalApicMemorySpace (
- IN EFI_HANDLE ImageHandle
- )
- {
- EFI_STATUS Status;
- EFI_PHYSICAL_ADDRESS BaseAddress;
- BaseAddress = (EFI_PHYSICAL_ADDRESS)GetLocalApicBaseAddress ();
- Status = AddMemoryMappedIoSpace (BaseAddress, SIZE_4KB, EFI_MEMORY_UC);
- ASSERT_EFI_ERROR (Status);
- //
- // Try to allocate APIC memory mapped space, does not check return
- // status because it may be allocated by other driver, or DXE Core if
- // this range is built into Memory Allocation HOB.
- //
- Status = gDS->AllocateMemorySpace (
- EfiGcdAllocateAddress,
- EfiGcdMemoryTypeMemoryMappedIo,
- 0,
- SIZE_4KB,
- &BaseAddress,
- ImageHandle,
- NULL
- );
- if (EFI_ERROR (Status)) {
- DEBUG ((
- DEBUG_INFO,
- "%a: %a: AllocateMemorySpace() Status - %r\n",
- gEfiCallerBaseName,
- __FUNCTION__,
- Status
- ));
- }
- }
- /**
- Initialize the state information for the CPU Architectural Protocol.
- @param ImageHandle Image handle this driver.
- @param SystemTable Pointer to the System Table.
- @retval EFI_SUCCESS Thread can be successfully created
- @retval EFI_OUT_OF_RESOURCES Cannot allocate protocol data structure
- @retval EFI_DEVICE_ERROR Cannot create the thread
- **/
- EFI_STATUS
- EFIAPI
- InitializeCpu (
- IN EFI_HANDLE ImageHandle,
- IN EFI_SYSTEM_TABLE *SystemTable
- )
- {
- EFI_STATUS Status;
- EFI_EVENT IdleLoopEvent;
- InitializePageTableLib ();
- InitializeFloatingPointUnits ();
- //
- // Make sure interrupts are disabled
- //
- DisableInterrupts ();
- //
- // Init GDT for DXE
- //
- InitGlobalDescriptorTable ();
- //
- // Setup IDT pointer, IDT and interrupt entry points
- //
- InitInterruptDescriptorTable ();
- //
- // Install CPU Architectural Protocol
- //
- Status = gBS->InstallMultipleProtocolInterfaces (
- &mCpuHandle,
- &gEfiCpuArchProtocolGuid,
- &gCpu,
- NULL
- );
- ASSERT_EFI_ERROR (Status);
- //
- // Refresh GCD memory space map according to MTRR value.
- //
- RefreshGcdMemoryAttributes ();
- //
- // Add and allocate local APIC memory mapped space
- //
- AddLocalApicMemorySpace (ImageHandle);
- //
- // Setup a callback for idle events
- //
- Status = gBS->CreateEventEx (
- EVT_NOTIFY_SIGNAL,
- TPL_NOTIFY,
- IdleLoopEventCallback,
- NULL,
- &gIdleLoopEventGuid,
- &IdleLoopEvent
- );
- ASSERT_EFI_ERROR (Status);
- InitializeMpSupport ();
- return Status;
- }
|