REF: https://bugzilla.tianocore.org/show_bug.cgi?id=3737 Apply uncrustify changes to .c/.h files in the UefiCpuPkg package Cc: Andrew Fish <afish@apple.com> Cc: Leif Lindholm <leif@nuviainc.com> Cc: Michael D Kinney <michael.d.kinney@intel.com> Signed-off-by: Michael Kubacki <michael.kubacki@microsoft.com> Reviewed-by: Ray Ni <ray.ni@intel.com>
		
			
				
	
	
		
			1261 lines
		
	
	
		
			36 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			1261 lines
		
	
	
		
			36 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /** @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;
 | |
| }
 |