Home | History | Annotate | Download | only in CpuDxe
      1 /** @file
      2   CPU DXE Module to produce CPU ARCH Protocol.
      3 
      4   Copyright (c) 2008 - 2016, Intel Corporation. All rights reserved.<BR>
      5   This program and the accompanying materials
      6   are licensed and made available under the terms and conditions of the BSD License
      7   which accompanies this distribution.  The full text of the license may be found at
      8   http://opensource.org/licenses/bsd-license.php
      9 
     10   THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
     11   WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
     12 
     13 **/
     14 
     15 #include "CpuDxe.h"
     16 #include "CpuMp.h"
     17 
     18 //
     19 // Global Variables
     20 //
     21 BOOLEAN                   InterruptState = FALSE;
     22 EFI_HANDLE                mCpuHandle = NULL;
     23 BOOLEAN                   mIsFlushingGCD;
     24 UINT64                    mValidMtrrAddressMask = MTRR_LIB_CACHE_VALID_ADDRESS;
     25 UINT64                    mValidMtrrBitsMask    = MTRR_LIB_MSR_VALID_MASK;
     26 
     27 FIXED_MTRR    mFixedMtrrTable[] = {
     28   {
     29     MTRR_LIB_IA32_MTRR_FIX64K_00000,
     30     0,
     31     0x10000
     32   },
     33   {
     34     MTRR_LIB_IA32_MTRR_FIX16K_80000,
     35     0x80000,
     36     0x4000
     37   },
     38   {
     39     MTRR_LIB_IA32_MTRR_FIX16K_A0000,
     40     0xA0000,
     41     0x4000
     42   },
     43   {
     44     MTRR_LIB_IA32_MTRR_FIX4K_C0000,
     45     0xC0000,
     46     0x1000
     47   },
     48   {
     49     MTRR_LIB_IA32_MTRR_FIX4K_C8000,
     50     0xC8000,
     51     0x1000
     52   },
     53   {
     54     MTRR_LIB_IA32_MTRR_FIX4K_D0000,
     55     0xD0000,
     56     0x1000
     57   },
     58   {
     59     MTRR_LIB_IA32_MTRR_FIX4K_D8000,
     60     0xD8000,
     61     0x1000
     62   },
     63   {
     64     MTRR_LIB_IA32_MTRR_FIX4K_E0000,
     65     0xE0000,
     66     0x1000
     67   },
     68   {
     69     MTRR_LIB_IA32_MTRR_FIX4K_E8000,
     70     0xE8000,
     71     0x1000
     72   },
     73   {
     74     MTRR_LIB_IA32_MTRR_FIX4K_F0000,
     75     0xF0000,
     76     0x1000
     77   },
     78   {
     79     MTRR_LIB_IA32_MTRR_FIX4K_F8000,
     80     0xF8000,
     81     0x1000
     82   },
     83 };
     84 
     85 
     86 EFI_CPU_ARCH_PROTOCOL  gCpu = {
     87   CpuFlushCpuDataCache,
     88   CpuEnableInterrupt,
     89   CpuDisableInterrupt,
     90   CpuGetInterruptState,
     91   CpuInit,
     92   CpuRegisterInterruptHandler,
     93   CpuGetTimerValue,
     94   CpuSetMemoryAttributes,
     95   1,                          // NumberOfTimers
     96   4                           // DmaBufferAlignment
     97 };
     98 
     99 //
    100 // CPU Arch Protocol Functions
    101 //
    102 
    103 /**
    104   Flush CPU data cache. If the instruction cache is fully coherent
    105   with all DMA operations then function can just return EFI_SUCCESS.
    106 
    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
    110                             granularity.
    111   @param  FlushType         Specifies the type of flush operation to perform.
    112 
    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.
    116 
    117 **/
    118 EFI_STATUS
    119 EFIAPI
    120 CpuFlushCpuDataCache (
    121   IN EFI_CPU_ARCH_PROTOCOL     *This,
    122   IN EFI_PHYSICAL_ADDRESS      Start,
    123   IN UINT64                    Length,
    124   IN EFI_CPU_FLUSH_TYPE        FlushType
    125   )
    126 {
    127   if (FlushType == EfiCpuFlushTypeWriteBackInvalidate) {
    128     AsmWbinvd ();
    129     return EFI_SUCCESS;
    130   } else if (FlushType == EfiCpuFlushTypeInvalidate) {
    131     AsmInvd ();
    132     return EFI_SUCCESS;
    133   } else {
    134     return EFI_UNSUPPORTED;
    135   }
    136 }
    137 
    138 
    139 /**
    140   Enables CPU interrupts.
    141 
    142   @param  This              Protocol instance structure
    143 
    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.
    146 
    147 **/
    148 EFI_STATUS
    149 EFIAPI
    150 CpuEnableInterrupt (
    151   IN EFI_CPU_ARCH_PROTOCOL          *This
    152   )
    153 {
    154   EnableInterrupts ();
    155 
    156   InterruptState = TRUE;
    157   return EFI_SUCCESS;
    158 }
    159 
    160 
    161 /**
    162   Disables CPU interrupts.
    163 
    164   @param  This              Protocol instance structure
    165 
    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.
    168 
    169 **/
    170 EFI_STATUS
    171 EFIAPI
    172 CpuDisableInterrupt (
    173   IN EFI_CPU_ARCH_PROTOCOL     *This
    174   )
    175 {
    176   DisableInterrupts ();
    177 
    178   InterruptState = FALSE;
    179   return EFI_SUCCESS;
    180 }
    181 
    182 
    183 /**
    184   Return the state of interrupts.
    185 
    186   @param  This                   Protocol instance structure
    187   @param  State                  Pointer to the CPU's current interrupt state
    188 
    189   @retval EFI_SUCCESS            If interrupts were disabled in the CPU.
    190   @retval EFI_INVALID_PARAMETER  State is NULL.
    191 
    192 **/
    193 EFI_STATUS
    194 EFIAPI
    195 CpuGetInterruptState (
    196   IN  EFI_CPU_ARCH_PROTOCOL     *This,
    197   OUT BOOLEAN                   *State
    198   )
    199 {
    200   if (State == NULL) {
    201     return EFI_INVALID_PARAMETER;
    202   }
    203 
    204   *State = InterruptState;
    205   return EFI_SUCCESS;
    206 }
    207 
    208 
    209 /**
    210   Generates an INIT to the CPU.
    211 
    212   @param  This              Protocol instance structure
    213   @param  InitType          Type of CPU INIT to perform
    214 
    215   @retval EFI_SUCCESS       If CPU INIT occurred. This value should never be
    216                             seen.
    217   @retval EFI_DEVICE_ERROR  If CPU INIT failed.
    218   @retval EFI_UNSUPPORTED   Requested type of CPU INIT not supported.
    219 
    220 **/
    221 EFI_STATUS
    222 EFIAPI
    223 CpuInit (
    224   IN EFI_CPU_ARCH_PROTOCOL      *This,
    225   IN EFI_CPU_INIT_TYPE          InitType
    226   )
    227 {
    228   return EFI_UNSUPPORTED;
    229 }
    230 
    231 
    232 /**
    233   Registers a function to be called from the CPU interrupt handler.
    234 
    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.
    242 
    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
    249                                  is not supported.
    250 
    251 **/
    252 EFI_STATUS
    253 EFIAPI
    254 CpuRegisterInterruptHandler (
    255   IN EFI_CPU_ARCH_PROTOCOL         *This,
    256   IN EFI_EXCEPTION_TYPE            InterruptType,
    257   IN EFI_CPU_INTERRUPT_HANDLER     InterruptHandler
    258   )
    259 {
    260   return RegisterCpuInterruptHandler (InterruptType, InterruptHandler);
    261 }
    262 
    263 
    264 /**
    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.
    267 
    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.
    280 
    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.
    285 
    286 **/
    287 EFI_STATUS
    288 EFIAPI
    289 CpuGetTimerValue (
    290   IN  EFI_CPU_ARCH_PROTOCOL     *This,
    291   IN  UINT32                    TimerIndex,
    292   OUT UINT64                    *TimerValue,
    293   OUT UINT64                    *TimerPeriod OPTIONAL
    294   )
    295 {
    296   if (TimerValue == NULL) {
    297     return EFI_INVALID_PARAMETER;
    298   }
    299 
    300   if (TimerIndex != 0) {
    301     return EFI_INVALID_PARAMETER;
    302   }
    303 
    304   *TimerValue = AsmReadTsc ();
    305 
    306   if (TimerPeriod != NULL) {
    307       //
    308       // BugBug: Hard coded. Don't know how to do this generically
    309       //
    310       *TimerPeriod = 1000000000;
    311   }
    312 
    313   return EFI_SUCCESS;
    314 }
    315 
    316 /**
    317   A minimal wrapper function that allows MtrrSetAllMtrrs() to be passed to
    318   EFI_MP_SERVICES_PROTOCOL.StartupAllAPs() as Procedure.
    319 
    320   @param[in] Buffer  Pointer to an MTRR_SETTINGS object, to be passed to
    321                      MtrrSetAllMtrrs().
    322 **/
    323 VOID
    324 EFIAPI
    325 SetMtrrsFromBuffer (
    326   IN VOID *Buffer
    327   )
    328 {
    329   MtrrSetAllMtrrs (Buffer);
    330 }
    331 
    332 /**
    333   Implementation of SetMemoryAttributes() service of CPU Architecture Protocol.
    334 
    335   This function modifies the attributes for the memory region specified by BaseAddress and
    336   Length from their current attributes to the attributes specified by Attributes.
    337 
    338   @param  This             The EFI_CPU_ARCH_PROTOCOL instance.
    339   @param  BaseAddress      The physical address that is the start address of a memory region.
    340   @param  Length           The size in bytes of the memory region.
    341   @param  Attributes       The bit mask of attributes to set for the memory region.
    342 
    343   @retval EFI_SUCCESS           The attributes were set for the memory region.
    344   @retval EFI_ACCESS_DENIED     The attributes for the memory resource range specified by
    345                                 BaseAddress and Length cannot be modified.
    346   @retval EFI_INVALID_PARAMETER Length is zero.
    347                                 Attributes specified an illegal combination of attributes that
    348                                 cannot be set together.
    349   @retval EFI_OUT_OF_RESOURCES  There are not enough system resources to modify the attributes of
    350                                 the memory resource range.
    351   @retval EFI_UNSUPPORTED       The processor does not support one or more bytes of the memory
    352                                 resource range specified by BaseAddress and Length.
    353                                 The bit mask of attributes is not support for the memory resource
    354                                 range specified by BaseAddress and Length.
    355 
    356 **/
    357 EFI_STATUS
    358 EFIAPI
    359 CpuSetMemoryAttributes (
    360   IN EFI_CPU_ARCH_PROTOCOL     *This,
    361   IN EFI_PHYSICAL_ADDRESS      BaseAddress,
    362   IN UINT64                    Length,
    363   IN UINT64                    Attributes
    364   )
    365 {
    366   RETURN_STATUS             Status;
    367   MTRR_MEMORY_CACHE_TYPE    CacheType;
    368   EFI_STATUS                MpStatus;
    369   EFI_MP_SERVICES_PROTOCOL  *MpService;
    370   MTRR_SETTINGS             MtrrSettings;
    371 
    372   if (!IsMtrrSupported ()) {
    373     return EFI_UNSUPPORTED;
    374   }
    375 
    376   //
    377   // If this function is called because GCD SetMemorySpaceAttributes () is called
    378   // by RefreshGcdMemoryAttributes (), then we are just synchronzing GCD memory
    379   // map with MTRR values. So there is no need to modify MTRRs, just return immediately
    380   // to avoid unnecessary computing.
    381   //
    382   if (mIsFlushingGCD) {
    383     DEBUG((EFI_D_INFO, "  Flushing GCD\n"));
    384     return EFI_SUCCESS;
    385   }
    386 
    387   switch (Attributes) {
    388   case EFI_MEMORY_UC:
    389     CacheType = CacheUncacheable;
    390     break;
    391 
    392   case EFI_MEMORY_WC:
    393     CacheType = CacheWriteCombining;
    394     break;
    395 
    396   case EFI_MEMORY_WT:
    397     CacheType = CacheWriteThrough;
    398     break;
    399 
    400   case EFI_MEMORY_WP:
    401     CacheType = CacheWriteProtected;
    402     break;
    403 
    404   case EFI_MEMORY_WB:
    405     CacheType = CacheWriteBack;
    406     break;
    407 
    408   case EFI_MEMORY_UCE:
    409   case EFI_MEMORY_RP:
    410   case EFI_MEMORY_XP:
    411   case EFI_MEMORY_RUNTIME:
    412     return EFI_UNSUPPORTED;
    413 
    414   default:
    415     return EFI_INVALID_PARAMETER;
    416   }
    417   //
    418   // call MTRR libary function
    419   //
    420   Status = MtrrSetMemoryAttribute (
    421              BaseAddress,
    422              Length,
    423              CacheType
    424              );
    425 
    426   if (!RETURN_ERROR (Status)) {
    427     MpStatus = gBS->LocateProtocol (
    428                       &gEfiMpServiceProtocolGuid,
    429                       NULL,
    430                       (VOID **)&MpService
    431                       );
    432     //
    433     // Synchronize the update with all APs
    434     //
    435     if (!EFI_ERROR (MpStatus)) {
    436       MtrrGetAllMtrrs (&MtrrSettings);
    437       MpStatus = MpService->StartupAllAPs (
    438                               MpService,          // This
    439                               SetMtrrsFromBuffer, // Procedure
    440                               FALSE,              // SingleThread
    441                               NULL,               // WaitEvent
    442                               0,                  // TimeoutInMicrosecsond
    443                               &MtrrSettings,      // ProcedureArgument
    444                               NULL                // FailedCpuList
    445                               );
    446       ASSERT (MpStatus == EFI_SUCCESS || MpStatus == EFI_NOT_STARTED);
    447     }
    448   }
    449   return (EFI_STATUS) Status;
    450 }
    451 
    452 /**
    453   Initializes the valid bits mask and valid address mask for MTRRs.
    454 
    455   This function initializes the valid bits mask and valid address mask for MTRRs.
    456 
    457 **/
    458 VOID
    459 InitializeMtrrMask (
    460   VOID
    461   )
    462 {
    463   UINT32                              RegEax;
    464   UINT8                               PhysicalAddressBits;
    465 
    466   AsmCpuid (0x80000000, &RegEax, NULL, NULL, NULL);
    467 
    468   if (RegEax >= 0x80000008) {
    469     AsmCpuid (0x80000008, &RegEax, NULL, NULL, NULL);
    470 
    471     PhysicalAddressBits = (UINT8) RegEax;
    472 
    473     mValidMtrrBitsMask    = LShiftU64 (1, PhysicalAddressBits) - 1;
    474     mValidMtrrAddressMask = mValidMtrrBitsMask & 0xfffffffffffff000ULL;
    475   } else {
    476     mValidMtrrBitsMask    = MTRR_LIB_MSR_VALID_MASK;
    477     mValidMtrrAddressMask = MTRR_LIB_CACHE_VALID_ADDRESS;
    478   }
    479 }
    480 
    481 /**
    482   Gets GCD Mem Space type from MTRR Type.
    483 
    484   This function gets GCD Mem Space type from MTRR Type.
    485 
    486   @param  MtrrAttributes  MTRR memory type
    487 
    488   @return GCD Mem Space type
    489 
    490 **/
    491 UINT64
    492 GetMemorySpaceAttributeFromMtrrType (
    493   IN UINT8                MtrrAttributes
    494   )
    495 {
    496   switch (MtrrAttributes) {
    497   case MTRR_CACHE_UNCACHEABLE:
    498     return EFI_MEMORY_UC;
    499   case MTRR_CACHE_WRITE_COMBINING:
    500     return EFI_MEMORY_WC;
    501   case MTRR_CACHE_WRITE_THROUGH:
    502     return EFI_MEMORY_WT;
    503   case MTRR_CACHE_WRITE_PROTECTED:
    504     return EFI_MEMORY_WP;
    505   case MTRR_CACHE_WRITE_BACK:
    506     return EFI_MEMORY_WB;
    507   default:
    508     return 0;
    509   }
    510 }
    511 
    512 /**
    513   Searches memory descriptors covered by given memory range.
    514 
    515   This function searches into the Gcd Memory Space for descriptors
    516   (from StartIndex to EndIndex) that contains the memory range
    517   specified by BaseAddress and Length.
    518 
    519   @param  MemorySpaceMap       Gcd Memory Space Map as array.
    520   @param  NumberOfDescriptors  Number of descriptors in map.
    521   @param  BaseAddress          BaseAddress for the requested range.
    522   @param  Length               Length for the requested range.
    523   @param  StartIndex           Start index into the Gcd Memory Space Map.
    524   @param  EndIndex             End index into the Gcd Memory Space Map.
    525 
    526   @retval EFI_SUCCESS          Search successfully.
    527   @retval EFI_NOT_FOUND        The requested descriptors does not exist.
    528 
    529 **/
    530 EFI_STATUS
    531 SearchGcdMemorySpaces (
    532   IN EFI_GCD_MEMORY_SPACE_DESCRIPTOR     *MemorySpaceMap,
    533   IN UINTN                               NumberOfDescriptors,
    534   IN EFI_PHYSICAL_ADDRESS                BaseAddress,
    535   IN UINT64                              Length,
    536   OUT UINTN                              *StartIndex,
    537   OUT UINTN                              *EndIndex
    538   )
    539 {
    540   UINTN           Index;
    541 
    542   *StartIndex = 0;
    543   *EndIndex   = 0;
    544   for (Index = 0; Index < NumberOfDescriptors; Index++) {
    545     if (BaseAddress >= MemorySpaceMap[Index].BaseAddress &&
    546         BaseAddress < MemorySpaceMap[Index].BaseAddress + MemorySpaceMap[Index].Length) {
    547       *StartIndex = Index;
    548     }
    549     if (BaseAddress + Length - 1 >= MemorySpaceMap[Index].BaseAddress &&
    550         BaseAddress + Length - 1 < MemorySpaceMap[Index].BaseAddress + MemorySpaceMap[Index].Length) {
    551       *EndIndex = Index;
    552       return EFI_SUCCESS;
    553     }
    554   }
    555   return EFI_NOT_FOUND;
    556 }
    557 
    558 /**
    559   Sets the attributes for a specified range in Gcd Memory Space Map.
    560 
    561   This function sets the attributes for a specified range in
    562   Gcd Memory Space Map.
    563 
    564   @param  MemorySpaceMap       Gcd Memory Space Map as array
    565   @param  NumberOfDescriptors  Number of descriptors in map
    566   @param  BaseAddress          BaseAddress for the range
    567   @param  Length               Length for the range
    568   @param  Attributes           Attributes to set
    569 
    570   @retval EFI_SUCCESS          Memory attributes set successfully
    571   @retval EFI_NOT_FOUND        The specified range does not exist in Gcd Memory Space
    572 
    573 **/
    574 EFI_STATUS
    575 SetGcdMemorySpaceAttributes (
    576   IN EFI_GCD_MEMORY_SPACE_DESCRIPTOR     *MemorySpaceMap,
    577   IN UINTN                               NumberOfDescriptors,
    578   IN EFI_PHYSICAL_ADDRESS                BaseAddress,
    579   IN UINT64                              Length,
    580   IN UINT64                              Attributes
    581   )
    582 {
    583   EFI_STATUS            Status;
    584   UINTN                 Index;
    585   UINTN                 StartIndex;
    586   UINTN                 EndIndex;
    587   EFI_PHYSICAL_ADDRESS  RegionStart;
    588   UINT64                RegionLength;
    589 
    590   //
    591   // Get all memory descriptors covered by the memory range
    592   //
    593   Status = SearchGcdMemorySpaces (
    594              MemorySpaceMap,
    595              NumberOfDescriptors,
    596              BaseAddress,
    597              Length,
    598              &StartIndex,
    599              &EndIndex
    600              );
    601   if (EFI_ERROR (Status)) {
    602     return Status;
    603   }
    604 
    605   //
    606   // Go through all related descriptors and set attributes accordingly
    607   //
    608   for (Index = StartIndex; Index <= EndIndex; Index++) {
    609     if (MemorySpaceMap[Index].GcdMemoryType == EfiGcdMemoryTypeNonExistent) {
    610       continue;
    611     }
    612     //
    613     // Calculate the start and end address of the overlapping range
    614     //
    615     if (BaseAddress >= MemorySpaceMap[Index].BaseAddress) {
    616       RegionStart = BaseAddress;
    617     } else {
    618       RegionStart = MemorySpaceMap[Index].BaseAddress;
    619     }
    620     if (BaseAddress + Length - 1 < MemorySpaceMap[Index].BaseAddress + MemorySpaceMap[Index].Length) {
    621       RegionLength = BaseAddress + Length - RegionStart;
    622     } else {
    623       RegionLength = MemorySpaceMap[Index].BaseAddress + MemorySpaceMap[Index].Length - RegionStart;
    624     }
    625     //
    626     // Set memory attributes according to MTRR attribute and the original attribute of descriptor
    627     //
    628     gDS->SetMemorySpaceAttributes (
    629            RegionStart,
    630            RegionLength,
    631            (MemorySpaceMap[Index].Attributes & ~EFI_MEMORY_CACHETYPE_MASK) | (MemorySpaceMap[Index].Capabilities & Attributes)
    632            );
    633   }
    634 
    635   return EFI_SUCCESS;
    636 }
    637 
    638 
    639 /**
    640   Refreshes the GCD Memory Space attributes according to MTRRs.
    641 
    642   This function refreshes the GCD Memory Space attributes according to MTRRs.
    643 
    644 **/
    645 VOID
    646 RefreshGcdMemoryAttributes (
    647   VOID
    648   )
    649 {
    650   EFI_STATUS                          Status;
    651   UINTN                               Index;
    652   UINTN                               SubIndex;
    653   UINT64                              RegValue;
    654   EFI_PHYSICAL_ADDRESS                BaseAddress;
    655   UINT64                              Length;
    656   UINT64                              Attributes;
    657   UINT64                              CurrentAttributes;
    658   UINT8                               MtrrType;
    659   UINTN                               NumberOfDescriptors;
    660   EFI_GCD_MEMORY_SPACE_DESCRIPTOR     *MemorySpaceMap;
    661   UINT64                              DefaultAttributes;
    662   VARIABLE_MTRR                       VariableMtrr[MTRR_NUMBER_OF_VARIABLE_MTRR];
    663   MTRR_FIXED_SETTINGS                 MtrrFixedSettings;
    664   UINT32                              FirmwareVariableMtrrCount;
    665   UINT8                               DefaultMemoryType;
    666 
    667   if (!IsMtrrSupported ()) {
    668     return;
    669   }
    670 
    671   FirmwareVariableMtrrCount = GetFirmwareVariableMtrrCount ();
    672   ASSERT (FirmwareVariableMtrrCount <= MTRR_NUMBER_OF_VARIABLE_MTRR);
    673 
    674   mIsFlushingGCD = TRUE;
    675   MemorySpaceMap = NULL;
    676 
    677   //
    678   // Initialize the valid bits mask and valid address mask for MTRRs
    679   //
    680   InitializeMtrrMask ();
    681 
    682   //
    683   // Get the memory attribute of variable MTRRs
    684   //
    685   MtrrGetMemoryAttributeInVariableMtrr (
    686     mValidMtrrBitsMask,
    687     mValidMtrrAddressMask,
    688     VariableMtrr
    689     );
    690 
    691   //
    692   // Get the memory space map from GCD
    693   //
    694   Status = gDS->GetMemorySpaceMap (
    695                   &NumberOfDescriptors,
    696                   &MemorySpaceMap
    697                   );
    698   ASSERT_EFI_ERROR (Status);
    699 
    700   DefaultMemoryType = (UINT8) MtrrGetDefaultMemoryType ();
    701   DefaultAttributes = GetMemorySpaceAttributeFromMtrrType (DefaultMemoryType);
    702 
    703   //
    704   // Set default attributes to all spaces.
    705   //
    706   for (Index = 0; Index < NumberOfDescriptors; Index++) {
    707     if (MemorySpaceMap[Index].GcdMemoryType == EfiGcdMemoryTypeNonExistent) {
    708       continue;
    709     }
    710     gDS->SetMemorySpaceAttributes (
    711            MemorySpaceMap[Index].BaseAddress,
    712            MemorySpaceMap[Index].Length,
    713            (MemorySpaceMap[Index].Attributes & ~EFI_MEMORY_CACHETYPE_MASK) |
    714            (MemorySpaceMap[Index].Capabilities & DefaultAttributes)
    715            );
    716   }
    717 
    718   //
    719   // Go for variable MTRRs with WB attribute
    720   //
    721   for (Index = 0; Index < FirmwareVariableMtrrCount; Index++) {
    722     if (VariableMtrr[Index].Valid &&
    723         VariableMtrr[Index].Type == MTRR_CACHE_WRITE_BACK) {
    724       SetGcdMemorySpaceAttributes (
    725         MemorySpaceMap,
    726         NumberOfDescriptors,
    727         VariableMtrr[Index].BaseAddress,
    728         VariableMtrr[Index].Length,
    729         EFI_MEMORY_WB
    730         );
    731     }
    732   }
    733 
    734   //
    735   // Go for variable MTRRs with the attribute except for WB and UC attributes
    736   //
    737   for (Index = 0; Index < FirmwareVariableMtrrCount; Index++) {
    738     if (VariableMtrr[Index].Valid &&
    739         VariableMtrr[Index].Type != MTRR_CACHE_WRITE_BACK &&
    740         VariableMtrr[Index].Type != MTRR_CACHE_UNCACHEABLE) {
    741       Attributes = GetMemorySpaceAttributeFromMtrrType ((UINT8) VariableMtrr[Index].Type);
    742       SetGcdMemorySpaceAttributes (
    743         MemorySpaceMap,
    744         NumberOfDescriptors,
    745         VariableMtrr[Index].BaseAddress,
    746         VariableMtrr[Index].Length,
    747         Attributes
    748         );
    749     }
    750   }
    751 
    752   //
    753   // Go for variable MTRRs with UC attribute
    754   //
    755   for (Index = 0; Index < FirmwareVariableMtrrCount; Index++) {
    756     if (VariableMtrr[Index].Valid &&
    757         VariableMtrr[Index].Type == MTRR_CACHE_UNCACHEABLE) {
    758       SetGcdMemorySpaceAttributes (
    759         MemorySpaceMap,
    760         NumberOfDescriptors,
    761         VariableMtrr[Index].BaseAddress,
    762         VariableMtrr[Index].Length,
    763         EFI_MEMORY_UC
    764         );
    765     }
    766   }
    767 
    768   //
    769   // Go for fixed MTRRs
    770   //
    771   Attributes  = 0;
    772   BaseAddress = 0;
    773   Length      = 0;
    774   MtrrGetFixedMtrr (&MtrrFixedSettings);
    775   for (Index = 0; Index < MTRR_NUMBER_OF_FIXED_MTRR; Index++) {
    776     RegValue = MtrrFixedSettings.Mtrr[Index];
    777     //
    778     // Check for continuous fixed MTRR sections
    779     //
    780     for (SubIndex = 0; SubIndex < 8; SubIndex++) {
    781       MtrrType = (UINT8) RShiftU64 (RegValue, SubIndex * 8);
    782       CurrentAttributes = GetMemorySpaceAttributeFromMtrrType (MtrrType);
    783       if (Length == 0) {
    784         //
    785         // A new MTRR attribute begins
    786         //
    787         Attributes = CurrentAttributes;
    788       } else {
    789         //
    790         // If fixed MTRR attribute changed, then set memory attribute for previous atrribute
    791         //
    792         if (CurrentAttributes != Attributes) {
    793           SetGcdMemorySpaceAttributes (
    794             MemorySpaceMap,
    795             NumberOfDescriptors,
    796             BaseAddress,
    797             Length,
    798             Attributes
    799             );
    800           BaseAddress = mFixedMtrrTable[Index].BaseAddress + mFixedMtrrTable[Index].Length * SubIndex;
    801           Length = 0;
    802           Attributes = CurrentAttributes;
    803         }
    804       }
    805       Length += mFixedMtrrTable[Index].Length;
    806     }
    807   }
    808   //
    809   // Handle the last fixed MTRR region
    810   //
    811   SetGcdMemorySpaceAttributes (
    812     MemorySpaceMap,
    813     NumberOfDescriptors,
    814     BaseAddress,
    815     Length,
    816     Attributes
    817     );
    818 
    819   //
    820   // Free memory space map allocated by GCD service GetMemorySpaceMap ()
    821   //
    822   if (MemorySpaceMap != NULL) {
    823     FreePool (MemorySpaceMap);
    824   }
    825 
    826   mIsFlushingGCD = FALSE;
    827 }
    828 
    829 /**
    830   Initialize Interrupt Descriptor Table for interrupt handling.
    831 
    832 **/
    833 VOID
    834 InitInterruptDescriptorTable (
    835   VOID
    836   )
    837 {
    838   EFI_STATUS                     Status;
    839   EFI_VECTOR_HANDOFF_INFO        *VectorInfoList;
    840   EFI_VECTOR_HANDOFF_INFO        *VectorInfo;
    841 
    842   VectorInfo = NULL;
    843   Status = EfiGetSystemConfigurationTable (&gEfiVectorHandoffTableGuid, (VOID **) &VectorInfoList);
    844   if (Status == EFI_SUCCESS && VectorInfoList != NULL) {
    845     VectorInfo = VectorInfoList;
    846   }
    847   Status = InitializeCpuInterruptHandlers (VectorInfo);
    848   ASSERT_EFI_ERROR (Status);
    849 }
    850 
    851 
    852 /**
    853   Callback function for idle events.
    854 
    855   @param  Event                 Event whose notification function is being invoked.
    856   @param  Context               The pointer to the notification function's context,
    857                                 which is implementation-dependent.
    858 
    859 **/
    860 VOID
    861 EFIAPI
    862 IdleLoopEventCallback (
    863   IN EFI_EVENT                Event,
    864   IN VOID                     *Context
    865   )
    866 {
    867   CpuSleep ();
    868 }
    869 
    870 
    871 /**
    872   Initialize the state information for the CPU Architectural Protocol.
    873 
    874   @param ImageHandle     Image handle this driver.
    875   @param SystemTable     Pointer to the System Table.
    876 
    877   @retval EFI_SUCCESS           Thread can be successfully created
    878   @retval EFI_OUT_OF_RESOURCES  Cannot allocate protocol data structure
    879   @retval EFI_DEVICE_ERROR      Cannot create the thread
    880 
    881 **/
    882 EFI_STATUS
    883 EFIAPI
    884 InitializeCpu (
    885   IN EFI_HANDLE                            ImageHandle,
    886   IN EFI_SYSTEM_TABLE                      *SystemTable
    887   )
    888 {
    889   EFI_STATUS  Status;
    890   EFI_EVENT   IdleLoopEvent;
    891 
    892   InitializeFloatingPointUnits ();
    893 
    894   //
    895   // Make sure interrupts are disabled
    896   //
    897   DisableInterrupts ();
    898 
    899   //
    900   // Init GDT for DXE
    901   //
    902   InitGlobalDescriptorTable ();
    903 
    904   //
    905   // Setup IDT pointer, IDT and interrupt entry points
    906   //
    907   InitInterruptDescriptorTable ();
    908 
    909   //
    910   // Enable the local APIC for Virtual Wire Mode.
    911   //
    912   ProgramVirtualWireMode ();
    913 
    914   //
    915   // Install CPU Architectural Protocol
    916   //
    917   Status = gBS->InstallMultipleProtocolInterfaces (
    918                   &mCpuHandle,
    919                   &gEfiCpuArchProtocolGuid, &gCpu,
    920                   NULL
    921                   );
    922   ASSERT_EFI_ERROR (Status);
    923 
    924   //
    925   // Refresh GCD memory space map according to MTRR value.
    926   //
    927   RefreshGcdMemoryAttributes ();
    928 
    929   //
    930   // Setup a callback for idle events
    931   //
    932   Status = gBS->CreateEventEx (
    933                   EVT_NOTIFY_SIGNAL,
    934                   TPL_NOTIFY,
    935                   IdleLoopEventCallback,
    936                   NULL,
    937                   &gIdleLoopEventGuid,
    938                   &IdleLoopEvent
    939                   );
    940   ASSERT_EFI_ERROR (Status);
    941 
    942   InitializeMpSupport ();
    943 
    944   return Status;
    945 }
    946 
    947