Home | History | Annotate | Download | only in CpuDxe
      1 /** @file
      2   CPU DXE Module.
      3 
      4   Copyright (c) 2008 - 2013, 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 /**
    318   Implementation of SetMemoryAttributes() service of CPU Architecture Protocol.
    319 
    320   This function modifies the attributes for the memory region specified by BaseAddress and
    321   Length from their current attributes to the attributes specified by Attributes.
    322 
    323   @param  This             The EFI_CPU_ARCH_PROTOCOL instance.
    324   @param  BaseAddress      The physical address that is the start address of a memory region.
    325   @param  Length           The size in bytes of the memory region.
    326   @param  Attributes       The bit mask of attributes to set for the memory region.
    327 
    328   @retval EFI_SUCCESS           The attributes were set for the memory region.
    329   @retval EFI_ACCESS_DENIED     The attributes for the memory resource range specified by
    330                                 BaseAddress and Length cannot be modified.
    331   @retval EFI_INVALID_PARAMETER Length is zero.
    332                                 Attributes specified an illegal combination of attributes that
    333                                 cannot be set together.
    334   @retval EFI_OUT_OF_RESOURCES  There are not enough system resources to modify the attributes of
    335                                 the memory resource range.
    336   @retval EFI_UNSUPPORTED       The processor does not support one or more bytes of the memory
    337                                 resource range specified by BaseAddress and Length.
    338                                 The bit mask of attributes is not support for the memory resource
    339                                 range specified by BaseAddress and Length.
    340 
    341 **/
    342 EFI_STATUS
    343 EFIAPI
    344 CpuSetMemoryAttributes (
    345   IN EFI_CPU_ARCH_PROTOCOL     *This,
    346   IN EFI_PHYSICAL_ADDRESS      BaseAddress,
    347   IN UINT64                    Length,
    348   IN UINT64                    Attributes
    349   )
    350 {
    351   RETURN_STATUS             Status;
    352   MTRR_MEMORY_CACHE_TYPE    CacheType;
    353   EFI_STATUS                MpStatus;
    354   EFI_MP_SERVICES_PROTOCOL  *MpService;
    355   MTRR_SETTINGS             MtrrSettings;
    356 
    357   if (!IsMtrrSupported ()) {
    358     return EFI_UNSUPPORTED;
    359   }
    360 
    361   //
    362   // If this function is called because GCD SetMemorySpaceAttributes () is called
    363   // by RefreshGcdMemoryAttributes (), then we are just synchronzing GCD memory
    364   // map with MTRR values. So there is no need to modify MTRRs, just return immediately
    365   // to avoid unnecessary computing.
    366   //
    367   if (mIsFlushingGCD) {
    368     DEBUG((EFI_D_INFO, "  Flushing GCD\n"));
    369     return EFI_SUCCESS;
    370   }
    371 
    372   switch (Attributes) {
    373   case EFI_MEMORY_UC:
    374     CacheType = CacheUncacheable;
    375     break;
    376 
    377   case EFI_MEMORY_WC:
    378     CacheType = CacheWriteCombining;
    379     break;
    380 
    381   case EFI_MEMORY_WT:
    382     CacheType = CacheWriteThrough;
    383     break;
    384 
    385   case EFI_MEMORY_WP:
    386     CacheType = CacheWriteProtected;
    387     break;
    388 
    389   case EFI_MEMORY_WB:
    390     CacheType = CacheWriteBack;
    391     break;
    392 
    393   case EFI_MEMORY_UCE:
    394   case EFI_MEMORY_RP:
    395   case EFI_MEMORY_XP:
    396   case EFI_MEMORY_RUNTIME:
    397     return EFI_UNSUPPORTED;
    398 
    399   default:
    400     return EFI_INVALID_PARAMETER;
    401   }
    402   //
    403   // call MTRR libary function
    404   //
    405   Status = MtrrSetMemoryAttribute (
    406              BaseAddress,
    407              Length,
    408              CacheType
    409              );
    410 
    411   if (!RETURN_ERROR (Status)) {
    412     MpStatus = gBS->LocateProtocol (
    413                       &gEfiMpServiceProtocolGuid,
    414                       NULL,
    415                       (VOID **)&MpService
    416                       );
    417     //
    418     // Synchronize the update with all APs
    419     //
    420     if (!EFI_ERROR (MpStatus)) {
    421       MtrrGetAllMtrrs (&MtrrSettings);
    422       MpStatus = MpService->StartupAllAPs (
    423                               MpService,          // This
    424                               SetMtrrsFromBuffer, // Procedure
    425                               TRUE,               // SingleThread
    426                               NULL,               // WaitEvent
    427                               0,                  // TimeoutInMicrosecsond
    428                               &MtrrSettings,      // ProcedureArgument
    429                               NULL                // FailedCpuList
    430                               );
    431       ASSERT (MpStatus == EFI_SUCCESS || MpStatus == EFI_NOT_STARTED);
    432     }
    433   }
    434   return (EFI_STATUS) Status;
    435 }
    436 
    437 /**
    438   Initializes the valid bits mask and valid address mask for MTRRs.
    439 
    440   This function initializes the valid bits mask and valid address mask for MTRRs.
    441 
    442 **/
    443 VOID
    444 InitializeMtrrMask (
    445   VOID
    446   )
    447 {
    448   UINT32                              RegEax;
    449   UINT8                               PhysicalAddressBits;
    450 
    451   AsmCpuid (0x80000000, &RegEax, NULL, NULL, NULL);
    452 
    453   if (RegEax >= 0x80000008) {
    454     AsmCpuid (0x80000008, &RegEax, NULL, NULL, NULL);
    455 
    456     PhysicalAddressBits = (UINT8) RegEax;
    457 
    458     mValidMtrrBitsMask    = LShiftU64 (1, PhysicalAddressBits) - 1;
    459     mValidMtrrAddressMask = mValidMtrrBitsMask & 0xfffffffffffff000ULL;
    460   } else {
    461     mValidMtrrBitsMask    = MTRR_LIB_MSR_VALID_MASK;
    462     mValidMtrrAddressMask = MTRR_LIB_CACHE_VALID_ADDRESS;
    463   }
    464 }
    465 
    466 /**
    467   Gets GCD Mem Space type from MTRR Type.
    468 
    469   This function gets GCD Mem Space type from MTRR Type.
    470 
    471   @param  MtrrAttributes  MTRR memory type
    472 
    473   @return GCD Mem Space type
    474 
    475 **/
    476 UINT64
    477 GetMemorySpaceAttributeFromMtrrType (
    478   IN UINT8                MtrrAttributes
    479   )
    480 {
    481   switch (MtrrAttributes) {
    482   case MTRR_CACHE_UNCACHEABLE:
    483     return EFI_MEMORY_UC;
    484   case MTRR_CACHE_WRITE_COMBINING:
    485     return EFI_MEMORY_WC;
    486   case MTRR_CACHE_WRITE_THROUGH:
    487     return EFI_MEMORY_WT;
    488   case MTRR_CACHE_WRITE_PROTECTED:
    489     return EFI_MEMORY_WP;
    490   case MTRR_CACHE_WRITE_BACK:
    491     return EFI_MEMORY_WB;
    492   default:
    493     return 0;
    494   }
    495 }
    496 
    497 /**
    498   Searches memory descriptors covered by given memory range.
    499 
    500   This function searches into the Gcd Memory Space for descriptors
    501   (from StartIndex to EndIndex) that contains the memory range
    502   specified by BaseAddress and Length.
    503 
    504   @param  MemorySpaceMap       Gcd Memory Space Map as array.
    505   @param  NumberOfDescriptors  Number of descriptors in map.
    506   @param  BaseAddress          BaseAddress for the requested range.
    507   @param  Length               Length for the requested range.
    508   @param  StartIndex           Start index into the Gcd Memory Space Map.
    509   @param  EndIndex             End index into the Gcd Memory Space Map.
    510 
    511   @retval EFI_SUCCESS          Search successfully.
    512   @retval EFI_NOT_FOUND        The requested descriptors does not exist.
    513 
    514 **/
    515 EFI_STATUS
    516 SearchGcdMemorySpaces (
    517   IN EFI_GCD_MEMORY_SPACE_DESCRIPTOR     *MemorySpaceMap,
    518   IN UINTN                               NumberOfDescriptors,
    519   IN EFI_PHYSICAL_ADDRESS                BaseAddress,
    520   IN UINT64                              Length,
    521   OUT UINTN                              *StartIndex,
    522   OUT UINTN                              *EndIndex
    523   )
    524 {
    525   UINTN           Index;
    526 
    527   *StartIndex = 0;
    528   *EndIndex   = 0;
    529   for (Index = 0; Index < NumberOfDescriptors; Index++) {
    530     if (BaseAddress >= MemorySpaceMap[Index].BaseAddress &&
    531         BaseAddress < MemorySpaceMap[Index].BaseAddress + MemorySpaceMap[Index].Length) {
    532       *StartIndex = Index;
    533     }
    534     if (BaseAddress + Length - 1 >= MemorySpaceMap[Index].BaseAddress &&
    535         BaseAddress + Length - 1 < MemorySpaceMap[Index].BaseAddress + MemorySpaceMap[Index].Length) {
    536       *EndIndex = Index;
    537       return EFI_SUCCESS;
    538     }
    539   }
    540   return EFI_NOT_FOUND;
    541 }
    542 
    543 /**
    544   Sets the attributes for a specified range in Gcd Memory Space Map.
    545 
    546   This function sets the attributes for a specified range in
    547   Gcd Memory Space Map.
    548 
    549   @param  MemorySpaceMap       Gcd Memory Space Map as array
    550   @param  NumberOfDescriptors  Number of descriptors in map
    551   @param  BaseAddress          BaseAddress for the range
    552   @param  Length               Length for the range
    553   @param  Attributes           Attributes to set
    554 
    555   @retval EFI_SUCCESS          Memory attributes set successfully
    556   @retval EFI_NOT_FOUND        The specified range does not exist in Gcd Memory Space
    557 
    558 **/
    559 EFI_STATUS
    560 SetGcdMemorySpaceAttributes (
    561   IN EFI_GCD_MEMORY_SPACE_DESCRIPTOR     *MemorySpaceMap,
    562   IN UINTN                               NumberOfDescriptors,
    563   IN EFI_PHYSICAL_ADDRESS                BaseAddress,
    564   IN UINT64                              Length,
    565   IN UINT64                              Attributes
    566   )
    567 {
    568   EFI_STATUS            Status;
    569   UINTN                 Index;
    570   UINTN                 StartIndex;
    571   UINTN                 EndIndex;
    572   EFI_PHYSICAL_ADDRESS  RegionStart;
    573   UINT64                RegionLength;
    574 
    575   //
    576   // Get all memory descriptors covered by the memory range
    577   //
    578   Status = SearchGcdMemorySpaces (
    579              MemorySpaceMap,
    580              NumberOfDescriptors,
    581              BaseAddress,
    582              Length,
    583              &StartIndex,
    584              &EndIndex
    585              );
    586   if (EFI_ERROR (Status)) {
    587     return Status;
    588   }
    589 
    590   //
    591   // Go through all related descriptors and set attributes accordingly
    592   //
    593   for (Index = StartIndex; Index <= EndIndex; Index++) {
    594     if (MemorySpaceMap[Index].GcdMemoryType == EfiGcdMemoryTypeNonExistent) {
    595       continue;
    596     }
    597     //
    598     // Calculate the start and end address of the overlapping range
    599     //
    600     if (BaseAddress >= MemorySpaceMap[Index].BaseAddress) {
    601       RegionStart = BaseAddress;
    602     } else {
    603       RegionStart = MemorySpaceMap[Index].BaseAddress;
    604     }
    605     if (BaseAddress + Length - 1 < MemorySpaceMap[Index].BaseAddress + MemorySpaceMap[Index].Length) {
    606       RegionLength = BaseAddress + Length - RegionStart;
    607     } else {
    608       RegionLength = MemorySpaceMap[Index].BaseAddress + MemorySpaceMap[Index].Length - RegionStart;
    609     }
    610     //
    611     // Set memory attributes according to MTRR attribute and the original attribute of descriptor
    612     //
    613     gDS->SetMemorySpaceAttributes (
    614            RegionStart,
    615            RegionLength,
    616            (MemorySpaceMap[Index].Attributes & ~EFI_MEMORY_CACHETYPE_MASK) | (MemorySpaceMap[Index].Capabilities & Attributes)
    617            );
    618   }
    619 
    620   return EFI_SUCCESS;
    621 }
    622 
    623 
    624 /**
    625   Refreshes the GCD Memory Space attributes according to MTRRs.
    626 
    627   This function refreshes the GCD Memory Space attributes according to MTRRs.
    628 
    629 **/
    630 VOID
    631 RefreshGcdMemoryAttributes (
    632   VOID
    633   )
    634 {
    635   EFI_STATUS                          Status;
    636   UINTN                               Index;
    637   UINTN                               SubIndex;
    638   UINT64                              RegValue;
    639   EFI_PHYSICAL_ADDRESS                BaseAddress;
    640   UINT64                              Length;
    641   UINT64                              Attributes;
    642   UINT64                              CurrentAttributes;
    643   UINT8                               MtrrType;
    644   UINTN                               NumberOfDescriptors;
    645   EFI_GCD_MEMORY_SPACE_DESCRIPTOR     *MemorySpaceMap;
    646   UINT64                              DefaultAttributes;
    647   VARIABLE_MTRR                       VariableMtrr[MTRR_NUMBER_OF_VARIABLE_MTRR];
    648   MTRR_FIXED_SETTINGS                 MtrrFixedSettings;
    649   UINT32                              FirmwareVariableMtrrCount;
    650   UINT8                               DefaultMemoryType;
    651 
    652   if (!IsMtrrSupported ()) {
    653     return;
    654   }
    655 
    656   FirmwareVariableMtrrCount = GetFirmwareVariableMtrrCount ();
    657   ASSERT (FirmwareVariableMtrrCount <= MTRR_NUMBER_OF_VARIABLE_MTRR);
    658 
    659   mIsFlushingGCD = TRUE;
    660   MemorySpaceMap = NULL;
    661 
    662   //
    663   // Initialize the valid bits mask and valid address mask for MTRRs
    664   //
    665   InitializeMtrrMask ();
    666 
    667   //
    668   // Get the memory attribute of variable MTRRs
    669   //
    670   MtrrGetMemoryAttributeInVariableMtrr (
    671     mValidMtrrBitsMask,
    672     mValidMtrrAddressMask,
    673     VariableMtrr
    674     );
    675 
    676   //
    677   // Get the memory space map from GCD
    678   //
    679   Status = gDS->GetMemorySpaceMap (
    680                   &NumberOfDescriptors,
    681                   &MemorySpaceMap
    682                   );
    683   ASSERT_EFI_ERROR (Status);
    684 
    685   DefaultMemoryType = (UINT8) MtrrGetDefaultMemoryType ();
    686   DefaultAttributes = GetMemorySpaceAttributeFromMtrrType (DefaultMemoryType);
    687 
    688   //
    689   // Set default attributes to all spaces.
    690   //
    691   for (Index = 0; Index < NumberOfDescriptors; Index++) {
    692     if (MemorySpaceMap[Index].GcdMemoryType == EfiGcdMemoryTypeNonExistent) {
    693       continue;
    694     }
    695     gDS->SetMemorySpaceAttributes (
    696            MemorySpaceMap[Index].BaseAddress,
    697            MemorySpaceMap[Index].Length,
    698            (MemorySpaceMap[Index].Attributes & ~EFI_MEMORY_CACHETYPE_MASK) |
    699            (MemorySpaceMap[Index].Capabilities & DefaultAttributes)
    700            );
    701   }
    702 
    703   //
    704   // Go for variable MTRRs with WB attribute
    705   //
    706   for (Index = 0; Index < FirmwareVariableMtrrCount; Index++) {
    707     if (VariableMtrr[Index].Valid &&
    708         VariableMtrr[Index].Type == MTRR_CACHE_WRITE_BACK) {
    709       SetGcdMemorySpaceAttributes (
    710         MemorySpaceMap,
    711         NumberOfDescriptors,
    712         VariableMtrr[Index].BaseAddress,
    713         VariableMtrr[Index].Length,
    714         EFI_MEMORY_WB
    715         );
    716     }
    717   }
    718 
    719   //
    720   // Go for variable MTRRs with the attribute except for WB and UC attributes
    721   //
    722   for (Index = 0; Index < FirmwareVariableMtrrCount; Index++) {
    723     if (VariableMtrr[Index].Valid &&
    724         VariableMtrr[Index].Type != MTRR_CACHE_WRITE_BACK &&
    725         VariableMtrr[Index].Type != MTRR_CACHE_UNCACHEABLE) {
    726       Attributes = GetMemorySpaceAttributeFromMtrrType ((UINT8) VariableMtrr[Index].Type);
    727       SetGcdMemorySpaceAttributes (
    728         MemorySpaceMap,
    729         NumberOfDescriptors,
    730         VariableMtrr[Index].BaseAddress,
    731         VariableMtrr[Index].Length,
    732         Attributes
    733         );
    734     }
    735   }
    736 
    737   //
    738   // Go for variable MTRRs with UC attribute
    739   //
    740   for (Index = 0; Index < FirmwareVariableMtrrCount; Index++) {
    741     if (VariableMtrr[Index].Valid &&
    742         VariableMtrr[Index].Type == MTRR_CACHE_UNCACHEABLE) {
    743       SetGcdMemorySpaceAttributes (
    744         MemorySpaceMap,
    745         NumberOfDescriptors,
    746         VariableMtrr[Index].BaseAddress,
    747         VariableMtrr[Index].Length,
    748         EFI_MEMORY_UC
    749         );
    750     }
    751   }
    752 
    753   //
    754   // Go for fixed MTRRs
    755   //
    756   Attributes  = 0;
    757   BaseAddress = 0;
    758   Length      = 0;
    759   MtrrGetFixedMtrr (&MtrrFixedSettings);
    760   for (Index = 0; Index < MTRR_NUMBER_OF_FIXED_MTRR; Index++) {
    761     RegValue = MtrrFixedSettings.Mtrr[Index];
    762     //
    763     // Check for continuous fixed MTRR sections
    764     //
    765     for (SubIndex = 0; SubIndex < 8; SubIndex++) {
    766       MtrrType = (UINT8) RShiftU64 (RegValue, SubIndex * 8);
    767       CurrentAttributes = GetMemorySpaceAttributeFromMtrrType (MtrrType);
    768       if (Length == 0) {
    769         //
    770         // A new MTRR attribute begins
    771         //
    772         Attributes = CurrentAttributes;
    773       } else {
    774         //
    775         // If fixed MTRR attribute changed, then set memory attribute for previous atrribute
    776         //
    777         if (CurrentAttributes != Attributes) {
    778           SetGcdMemorySpaceAttributes (
    779             MemorySpaceMap,
    780             NumberOfDescriptors,
    781             BaseAddress,
    782             Length,
    783             Attributes
    784             );
    785           BaseAddress = mFixedMtrrTable[Index].BaseAddress + mFixedMtrrTable[Index].Length * SubIndex;
    786           Length = 0;
    787           Attributes = CurrentAttributes;
    788         }
    789       }
    790       Length += mFixedMtrrTable[Index].Length;
    791     }
    792   }
    793   //
    794   // Handle the last fixed MTRR region
    795   //
    796   SetGcdMemorySpaceAttributes (
    797     MemorySpaceMap,
    798     NumberOfDescriptors,
    799     BaseAddress,
    800     Length,
    801     Attributes
    802     );
    803 
    804   //
    805   // Free memory space map allocated by GCD service GetMemorySpaceMap ()
    806   //
    807   if (MemorySpaceMap != NULL) {
    808     FreePool (MemorySpaceMap);
    809   }
    810 
    811   mIsFlushingGCD = FALSE;
    812 }
    813 
    814 /**
    815   Initialize Interrupt Descriptor Table for interrupt handling.
    816 
    817 **/
    818 VOID
    819 InitInterruptDescriptorTable (
    820   VOID
    821   )
    822 {
    823   EFI_STATUS                     Status;
    824   EFI_VECTOR_HANDOFF_INFO        *VectorInfoList;
    825   EFI_VECTOR_HANDOFF_INFO        *VectorInfo;
    826 
    827   VectorInfo = NULL;
    828   Status = EfiGetSystemConfigurationTable (&gEfiVectorHandoffTableGuid, (VOID **) &VectorInfoList);
    829   if (Status == EFI_SUCCESS && VectorInfoList != NULL) {
    830     VectorInfo = VectorInfoList;
    831   }
    832   Status = InitializeCpuInterruptHandlers (VectorInfo);
    833   ASSERT_EFI_ERROR (Status);
    834 }
    835 
    836 
    837 /**
    838   Callback function for idle events.
    839 
    840   @param  Event                 Event whose notification function is being invoked.
    841   @param  Context               The pointer to the notification function's context,
    842                                 which is implementation-dependent.
    843 
    844 **/
    845 VOID
    846 EFIAPI
    847 IdleLoopEventCallback (
    848   IN EFI_EVENT                Event,
    849   IN VOID                     *Context
    850   )
    851 {
    852   CpuSleep ();
    853 }
    854 
    855 
    856 /**
    857   Initialize the state information for the CPU Architectural Protocol.
    858 
    859   @param ImageHandle     Image handle this driver.
    860   @param SystemTable     Pointer to the System Table.
    861 
    862   @retval EFI_SUCCESS           Thread can be successfully created
    863   @retval EFI_OUT_OF_RESOURCES  Cannot allocate protocol data structure
    864   @retval EFI_DEVICE_ERROR      Cannot create the thread
    865 
    866 **/
    867 EFI_STATUS
    868 EFIAPI
    869 InitializeCpu (
    870   IN EFI_HANDLE                            ImageHandle,
    871   IN EFI_SYSTEM_TABLE                      *SystemTable
    872   )
    873 {
    874   EFI_STATUS  Status;
    875   EFI_EVENT   IdleLoopEvent;
    876 
    877   InitializeFloatingPointUnits ();
    878 
    879   //
    880   // Make sure interrupts are disabled
    881   //
    882   DisableInterrupts ();
    883 
    884   //
    885   // Init GDT for DXE
    886   //
    887   InitGlobalDescriptorTable ();
    888 
    889   //
    890   // Setup IDT pointer, IDT and interrupt entry points
    891   //
    892   InitInterruptDescriptorTable ();
    893 
    894   //
    895   // Enable the local APIC for Virtual Wire Mode.
    896   //
    897   ProgramVirtualWireMode ();
    898 
    899   //
    900   // Install CPU Architectural Protocol
    901   //
    902   Status = gBS->InstallMultipleProtocolInterfaces (
    903                   &mCpuHandle,
    904                   &gEfiCpuArchProtocolGuid, &gCpu,
    905                   NULL
    906                   );
    907   ASSERT_EFI_ERROR (Status);
    908 
    909   //
    910   // Refresh GCD memory space map according to MTRR value.
    911   //
    912   RefreshGcdMemoryAttributes ();
    913 
    914   //
    915   // Setup a callback for idle events
    916   //
    917   Status = gBS->CreateEventEx (
    918                   EVT_NOTIFY_SIGNAL,
    919                   TPL_NOTIFY,
    920                   IdleLoopEventCallback,
    921                   NULL,
    922                   &gIdleLoopEventGuid,
    923                   &IdleLoopEvent
    924                   );
    925   ASSERT_EFI_ERROR (Status);
    926 
    927   InitializeMpSupport ();
    928 
    929   return Status;
    930 }
    931 
    932