Home | History | Annotate | Download | only in PiSmmCpuDxeSmm
      1 /** @file
      2 Agent Module to load other modules to deploy SMM Entry Vector for X86 CPU.
      3 
      4 Copyright (c) 2009 - 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 #ifndef _CPU_PISMMCPUDXESMM_H_
     16 #define _CPU_PISMMCPUDXESMM_H_
     17 
     18 #include <PiSmm.h>
     19 
     20 #include <Protocol/MpService.h>
     21 #include <Protocol/SmmConfiguration.h>
     22 #include <Protocol/SmmCpu.h>
     23 #include <Protocol/SmmAccess2.h>
     24 #include <Protocol/SmmReadyToLock.h>
     25 #include <Protocol/SmmCpuService.h>
     26 
     27 #include <Guid/AcpiS3Context.h>
     28 #include <Guid/PiSmmMemoryAttributesTable.h>
     29 
     30 #include <Library/BaseLib.h>
     31 #include <Library/IoLib.h>
     32 #include <Library/TimerLib.h>
     33 #include <Library/SynchronizationLib.h>
     34 #include <Library/DebugLib.h>
     35 #include <Library/BaseMemoryLib.h>
     36 #include <Library/PcdLib.h>
     37 #include <Library/CacheMaintenanceLib.h>
     38 #include <Library/MtrrLib.h>
     39 #include <Library/SmmCpuPlatformHookLib.h>
     40 #include <Library/SmmServicesTableLib.h>
     41 #include <Library/MemoryAllocationLib.h>
     42 #include <Library/UefiBootServicesTableLib.h>
     43 #include <Library/UefiRuntimeServicesTableLib.h>
     44 #include <Library/DebugAgentLib.h>
     45 #include <Library/HobLib.h>
     46 #include <Library/LocalApicLib.h>
     47 #include <Library/UefiCpuLib.h>
     48 #include <Library/CpuExceptionHandlerLib.h>
     49 #include <Library/ReportStatusCodeLib.h>
     50 #include <Library/SmmCpuFeaturesLib.h>
     51 #include <Library/PeCoffGetEntryPointLib.h>
     52 
     53 #include <AcpiCpuData.h>
     54 #include <CpuHotPlugData.h>
     55 
     56 #include <Register/Cpuid.h>
     57 #include <Register/Msr.h>
     58 
     59 #include "CpuService.h"
     60 #include "SmmProfile.h"
     61 
     62 //
     63 // MSRs required for configuration of SMM Code Access Check
     64 //
     65 #define EFI_MSR_SMM_MCA_CAP                    0x17D
     66 #define  SMM_CODE_ACCESS_CHK_BIT               BIT58
     67 
     68 #define  SMM_FEATURE_CONTROL_LOCK_BIT          BIT0
     69 #define  SMM_CODE_CHK_EN_BIT                   BIT2
     70 
     71 ///
     72 /// Page Table Entry
     73 ///
     74 #define IA32_PG_P                   BIT0
     75 #define IA32_PG_RW                  BIT1
     76 #define IA32_PG_U                   BIT2
     77 #define IA32_PG_WT                  BIT3
     78 #define IA32_PG_CD                  BIT4
     79 #define IA32_PG_A                   BIT5
     80 #define IA32_PG_D                   BIT6
     81 #define IA32_PG_PS                  BIT7
     82 #define IA32_PG_PAT_2M              BIT12
     83 #define IA32_PG_PAT_4K              IA32_PG_PS
     84 #define IA32_PG_PMNT                BIT62
     85 #define IA32_PG_NX                  BIT63
     86 
     87 #define PAGE_ATTRIBUTE_BITS         (IA32_PG_D | IA32_PG_A | IA32_PG_U | IA32_PG_RW | IA32_PG_P)
     88 //
     89 // Bits 1, 2, 5, 6 are reserved in the IA32 PAE PDPTE
     90 // X64 PAE PDPTE does not have such restriction
     91 //
     92 #define IA32_PAE_PDPTE_ATTRIBUTE_BITS    (IA32_PG_P)
     93 
     94 #define PAGE_PROGATE_BITS           (IA32_PG_NX | PAGE_ATTRIBUTE_BITS)
     95 
     96 #define PAGING_4K_MASK  0xFFF
     97 #define PAGING_2M_MASK  0x1FFFFF
     98 #define PAGING_1G_MASK  0x3FFFFFFF
     99 
    100 #define PAGING_PAE_INDEX_MASK  0x1FF
    101 
    102 #define PAGING_4K_ADDRESS_MASK_64 0x000FFFFFFFFFF000ull
    103 #define PAGING_2M_ADDRESS_MASK_64 0x000FFFFFFFE00000ull
    104 #define PAGING_1G_ADDRESS_MASK_64 0x000FFFFFC0000000ull
    105 
    106 typedef enum {
    107   PageNone,
    108   Page4K,
    109   Page2M,
    110   Page1G,
    111 } PAGE_ATTRIBUTE;
    112 
    113 typedef struct {
    114   PAGE_ATTRIBUTE   Attribute;
    115   UINT64           Length;
    116   UINT64           AddressMask;
    117 } PAGE_ATTRIBUTE_TABLE;
    118 
    119 //
    120 // Size of Task-State Segment defined in IA32 Manual
    121 //
    122 #define TSS_SIZE              104
    123 #define TSS_X64_IST1_OFFSET   36
    124 #define TSS_IA32_CR3_OFFSET   28
    125 #define TSS_IA32_ESP_OFFSET   56
    126 
    127 #define CR0_WP                BIT16
    128 
    129 //
    130 // Code select value
    131 //
    132 #define PROTECT_MODE_CODE_SEGMENT          0x08
    133 #define LONG_MODE_CODE_SEGMENT             0x38
    134 
    135 //
    136 // The size 0x20 must be bigger than
    137 // the size of template code of SmmInit. Currently,
    138 // the size of SmmInit requires the 0x16 Bytes buffer
    139 // at least.
    140 //
    141 #define BACK_BUF_SIZE  0x20
    142 
    143 #define EXCEPTION_VECTOR_NUMBER     0x20
    144 
    145 #define INVALID_APIC_ID 0xFFFFFFFFFFFFFFFFULL
    146 
    147 typedef UINT32                              SMM_CPU_ARRIVAL_EXCEPTIONS;
    148 #define ARRIVAL_EXCEPTION_BLOCKED           0x1
    149 #define ARRIVAL_EXCEPTION_DELAYED           0x2
    150 #define ARRIVAL_EXCEPTION_SMI_DISABLED      0x4
    151 
    152 //
    153 // Private structure for the SMM CPU module that is stored in DXE Runtime memory
    154 // Contains the SMM Configuration Protocols that is produced.
    155 // Contains a mix of DXE and SMM contents.  All the fields must be used properly.
    156 //
    157 #define SMM_CPU_PRIVATE_DATA_SIGNATURE  SIGNATURE_32 ('s', 'c', 'p', 'u')
    158 
    159 typedef struct {
    160   UINTN                           Signature;
    161 
    162   EFI_HANDLE                      SmmCpuHandle;
    163 
    164   EFI_PROCESSOR_INFORMATION       *ProcessorInfo;
    165   SMM_CPU_OPERATION               *Operation;
    166   UINTN                           *CpuSaveStateSize;
    167   VOID                            **CpuSaveState;
    168 
    169   EFI_SMM_RESERVED_SMRAM_REGION   SmmReservedSmramRegion[1];
    170   EFI_SMM_ENTRY_CONTEXT           SmmCoreEntryContext;
    171   EFI_SMM_ENTRY_POINT             SmmCoreEntry;
    172 
    173   EFI_SMM_CONFIGURATION_PROTOCOL  SmmConfiguration;
    174 } SMM_CPU_PRIVATE_DATA;
    175 
    176 extern SMM_CPU_PRIVATE_DATA  *gSmmCpuPrivate;
    177 extern CPU_HOT_PLUG_DATA      mCpuHotPlugData;
    178 extern UINTN                  mMaxNumberOfCpus;
    179 extern UINTN                  mNumberOfCpus;
    180 extern EFI_SMM_CPU_PROTOCOL   mSmmCpu;
    181 
    182 ///
    183 /// The mode of the CPU at the time an SMI occurs
    184 ///
    185 extern UINT8  mSmmSaveStateRegisterLma;
    186 
    187 
    188 //
    189 // SMM CPU Protocol function prototypes.
    190 //
    191 
    192 /**
    193   Read information from the CPU save state.
    194 
    195   @param  This      EFI_SMM_CPU_PROTOCOL instance
    196   @param  Width     The number of bytes to read from the CPU save state.
    197   @param  Register  Specifies the CPU register to read form the save state.
    198   @param  CpuIndex  Specifies the zero-based index of the CPU save state
    199   @param  Buffer    Upon return, this holds the CPU register value read from the save state.
    200 
    201   @retval EFI_SUCCESS   The register was read from Save State
    202   @retval EFI_NOT_FOUND The register is not defined for the Save State of Processor
    203   @retval EFI_INVALID_PARAMTER   This or Buffer is NULL.
    204 
    205 **/
    206 EFI_STATUS
    207 EFIAPI
    208 SmmReadSaveState (
    209   IN CONST EFI_SMM_CPU_PROTOCOL         *This,
    210   IN UINTN                              Width,
    211   IN EFI_SMM_SAVE_STATE_REGISTER        Register,
    212   IN UINTN                              CpuIndex,
    213   OUT VOID                              *Buffer
    214   );
    215 
    216 /**
    217   Write data to the CPU save state.
    218 
    219   @param  This      EFI_SMM_CPU_PROTOCOL instance
    220   @param  Width     The number of bytes to read from the CPU save state.
    221   @param  Register  Specifies the CPU register to write to the save state.
    222   @param  CpuIndex  Specifies the zero-based index of the CPU save state
    223   @param  Buffer    Upon entry, this holds the new CPU register value.
    224 
    225   @retval EFI_SUCCESS   The register was written from Save State
    226   @retval EFI_NOT_FOUND The register is not defined for the Save State of Processor
    227   @retval EFI_INVALID_PARAMTER   ProcessorIndex or Width is not correct
    228 
    229 **/
    230 EFI_STATUS
    231 EFIAPI
    232 SmmWriteSaveState (
    233   IN CONST EFI_SMM_CPU_PROTOCOL         *This,
    234   IN UINTN                              Width,
    235   IN EFI_SMM_SAVE_STATE_REGISTER        Register,
    236   IN UINTN                              CpuIndex,
    237   IN CONST VOID                         *Buffer
    238   );
    239 
    240 /**
    241 Read a CPU Save State register on the target processor.
    242 
    243 This function abstracts the differences that whether the CPU Save State register is in the
    244 IA32 CPU Save State Map or X64 CPU Save State Map.
    245 
    246 This function supports reading a CPU Save State register in SMBase relocation handler.
    247 
    248 @param[in]  CpuIndex       Specifies the zero-based index of the CPU save state.
    249 @param[in]  RegisterIndex  Index into mSmmCpuWidthOffset[] look up table.
    250 @param[in]  Width          The number of bytes to read from the CPU save state.
    251 @param[out] Buffer         Upon return, this holds the CPU register value read from the save state.
    252 
    253 @retval EFI_SUCCESS           The register was read from Save State.
    254 @retval EFI_NOT_FOUND         The register is not defined for the Save State of Processor.
    255 @retval EFI_INVALID_PARAMTER  This or Buffer is NULL.
    256 
    257 **/
    258 EFI_STATUS
    259 EFIAPI
    260 ReadSaveStateRegister (
    261   IN UINTN                        CpuIndex,
    262   IN EFI_SMM_SAVE_STATE_REGISTER  Register,
    263   IN UINTN                        Width,
    264   OUT VOID                        *Buffer
    265   );
    266 
    267 /**
    268 Write value to a CPU Save State register on the target processor.
    269 
    270 This function abstracts the differences that whether the CPU Save State register is in the
    271 IA32 CPU Save State Map or X64 CPU Save State Map.
    272 
    273 This function supports writing a CPU Save State register in SMBase relocation handler.
    274 
    275 @param[in] CpuIndex       Specifies the zero-based index of the CPU save state.
    276 @param[in] RegisterIndex  Index into mSmmCpuWidthOffset[] look up table.
    277 @param[in] Width          The number of bytes to read from the CPU save state.
    278 @param[in] Buffer         Upon entry, this holds the new CPU register value.
    279 
    280 @retval EFI_SUCCESS           The register was written to Save State.
    281 @retval EFI_NOT_FOUND         The register is not defined for the Save State of Processor.
    282 @retval EFI_INVALID_PARAMTER  ProcessorIndex or Width is not correct.
    283 
    284 **/
    285 EFI_STATUS
    286 EFIAPI
    287 WriteSaveStateRegister (
    288   IN UINTN                        CpuIndex,
    289   IN EFI_SMM_SAVE_STATE_REGISTER  Register,
    290   IN UINTN                        Width,
    291   IN CONST VOID                   *Buffer
    292   );
    293 
    294 //
    295 //
    296 //
    297 typedef struct {
    298   UINT32                            Offset;
    299   UINT16                            Segment;
    300   UINT16                            Reserved;
    301 } IA32_FAR_ADDRESS;
    302 
    303 extern IA32_FAR_ADDRESS             gSmmJmpAddr;
    304 
    305 extern CONST UINT8                  gcSmmInitTemplate[];
    306 extern CONST UINT16                 gcSmmInitSize;
    307 extern UINT32                       gSmmCr0;
    308 extern UINT32                       gSmmCr3;
    309 extern UINT32                       gSmmCr4;
    310 extern UINTN                        gSmmInitStack;
    311 
    312 /**
    313   Semaphore operation for all processor relocate SMMBase.
    314 **/
    315 VOID
    316 EFIAPI
    317 SmmRelocationSemaphoreComplete (
    318   VOID
    319   );
    320 
    321 ///
    322 /// The type of SMM CPU Information
    323 ///
    324 typedef struct {
    325   SPIN_LOCK                         *Busy;
    326   volatile EFI_AP_PROCEDURE         Procedure;
    327   volatile VOID                     *Parameter;
    328   volatile UINT32                   *Run;
    329   volatile BOOLEAN                  *Present;
    330 } SMM_CPU_DATA_BLOCK;
    331 
    332 typedef enum {
    333   SmmCpuSyncModeTradition,
    334   SmmCpuSyncModeRelaxedAp,
    335   SmmCpuSyncModeMax
    336 } SMM_CPU_SYNC_MODE;
    337 
    338 typedef struct {
    339   //
    340   // Pointer to an array. The array should be located immediately after this structure
    341   // so that UC cache-ability can be set together.
    342   //
    343   SMM_CPU_DATA_BLOCK            *CpuData;
    344   volatile UINT32               *Counter;
    345   volatile UINT32               BspIndex;
    346   volatile BOOLEAN              *InsideSmm;
    347   volatile BOOLEAN              *AllCpusInSync;
    348   volatile SMM_CPU_SYNC_MODE    EffectiveSyncMode;
    349   volatile BOOLEAN              SwitchBsp;
    350   volatile BOOLEAN              *CandidateBsp;
    351 } SMM_DISPATCHER_MP_SYNC_DATA;
    352 
    353 #define MSR_SPIN_LOCK_INIT_NUM 15
    354 
    355 typedef struct {
    356   SPIN_LOCK    *SpinLock;
    357   UINT32       MsrIndex;
    358 } MP_MSR_LOCK;
    359 
    360 #define SMM_PSD_OFFSET              0xfb00
    361 
    362 ///
    363 /// All global semaphores' pointer
    364 ///
    365 typedef struct {
    366   volatile UINT32      *Counter;
    367   volatile BOOLEAN     *InsideSmm;
    368   volatile BOOLEAN     *AllCpusInSync;
    369   SPIN_LOCK            *PFLock;
    370   SPIN_LOCK            *CodeAccessCheckLock;
    371   SPIN_LOCK            *MemoryMappedLock;
    372 } SMM_CPU_SEMAPHORE_GLOBAL;
    373 
    374 ///
    375 /// All semaphores for each processor
    376 ///
    377 typedef struct {
    378   SPIN_LOCK                         *Busy;
    379   volatile UINT32                   *Run;
    380   volatile BOOLEAN                  *Present;
    381 } SMM_CPU_SEMAPHORE_CPU;
    382 
    383 ///
    384 /// All MSRs semaphores' pointer and counter
    385 ///
    386 typedef struct {
    387   SPIN_LOCK            *Msr;
    388   UINTN                AvailableCounter;
    389 } SMM_CPU_SEMAPHORE_MSR;
    390 
    391 ///
    392 /// All semaphores' information
    393 ///
    394 typedef struct {
    395   SMM_CPU_SEMAPHORE_GLOBAL          SemaphoreGlobal;
    396   SMM_CPU_SEMAPHORE_CPU             SemaphoreCpu;
    397   SMM_CPU_SEMAPHORE_MSR             SemaphoreMsr;
    398 } SMM_CPU_SEMAPHORES;
    399 
    400 extern IA32_DESCRIPTOR                     gcSmiGdtr;
    401 extern EFI_PHYSICAL_ADDRESS                mGdtBuffer;
    402 extern UINTN                               mGdtBufferSize;
    403 extern IA32_DESCRIPTOR                     gcSmiIdtr;
    404 extern VOID                                *gcSmiIdtrPtr;
    405 extern UINT64                              gPhyMask;
    406 extern SMM_DISPATCHER_MP_SYNC_DATA         *mSmmMpSyncData;
    407 extern UINTN                               mSmmStackArrayBase;
    408 extern UINTN                               mSmmStackArrayEnd;
    409 extern UINTN                               mSmmStackSize;
    410 extern EFI_SMM_CPU_SERVICE_PROTOCOL        mSmmCpuService;
    411 extern IA32_DESCRIPTOR                     gcSmiInitGdtr;
    412 extern SMM_CPU_SEMAPHORES                  mSmmCpuSemaphores;
    413 extern UINTN                               mSemaphoreSize;
    414 extern SPIN_LOCK                           *mPFLock;
    415 extern SPIN_LOCK                           *mConfigSmmCodeAccessCheckLock;
    416 extern SPIN_LOCK                           *mMemoryMappedLock;
    417 
    418 /**
    419   Create 4G PageTable in SMRAM.
    420 
    421   @param[in]      Is32BitPageTable Whether the page table is 32-bit PAE
    422   @return         PageTable Address
    423 
    424 **/
    425 UINT32
    426 Gen4GPageTable (
    427   IN      BOOLEAN                   Is32BitPageTable
    428   );
    429 
    430 
    431 /**
    432   Initialize global data for MP synchronization.
    433 
    434   @param Stacks       Base address of SMI stack buffer for all processors.
    435   @param StackSize    Stack size for each processor in SMM.
    436 
    437 **/
    438 UINT32
    439 InitializeMpServiceData (
    440   IN VOID        *Stacks,
    441   IN UINTN       StackSize
    442   );
    443 
    444 /**
    445   Initialize Timer for SMM AP Sync.
    446 
    447 **/
    448 VOID
    449 InitializeSmmTimer (
    450   VOID
    451   );
    452 
    453 /**
    454   Start Timer for SMM AP Sync.
    455 
    456 **/
    457 UINT64
    458 EFIAPI
    459 StartSyncTimer (
    460   VOID
    461   );
    462 
    463 /**
    464   Check if the SMM AP Sync timer is timeout.
    465 
    466   @param Timer  The start timer from the begin.
    467 
    468 **/
    469 BOOLEAN
    470 EFIAPI
    471 IsSyncTimerTimeout (
    472   IN      UINT64                    Timer
    473   );
    474 
    475 /**
    476   Initialize IDT for SMM Stack Guard.
    477 
    478 **/
    479 VOID
    480 EFIAPI
    481 InitializeIDTSmmStackGuard (
    482   VOID
    483   );
    484 
    485 /**
    486   Initialize Gdt for all processors.
    487 
    488   @param[in]   Cr3          CR3 value.
    489   @param[out]  GdtStepSize  The step size for GDT table.
    490 
    491   @return GdtBase for processor 0.
    492           GdtBase for processor X is: GdtBase + (GdtStepSize * X)
    493 **/
    494 VOID *
    495 InitGdt (
    496   IN  UINTN  Cr3,
    497   OUT UINTN  *GdtStepSize
    498   );
    499 
    500 /**
    501   This function sets GDT/IDT buffer to be RO and XP.
    502 **/
    503 VOID
    504 PatchGdtIdtMap (
    505   VOID
    506   );
    507 
    508 /**
    509 
    510   Register the SMM Foundation entry point.
    511 
    512   @param          This              Pointer to EFI_SMM_CONFIGURATION_PROTOCOL instance
    513   @param          SmmEntryPoint     SMM Foundation EntryPoint
    514 
    515   @retval         EFI_SUCCESS       Successfully to register SMM foundation entry point
    516 
    517 **/
    518 EFI_STATUS
    519 EFIAPI
    520 RegisterSmmEntry (
    521   IN CONST EFI_SMM_CONFIGURATION_PROTOCOL  *This,
    522   IN EFI_SMM_ENTRY_POINT                   SmmEntryPoint
    523   );
    524 
    525 /**
    526   Create PageTable for SMM use.
    527 
    528   @return     PageTable Address
    529 
    530 **/
    531 UINT32
    532 SmmInitPageTable (
    533   VOID
    534   );
    535 
    536 /**
    537   Schedule a procedure to run on the specified CPU.
    538 
    539   @param   Procedure        The address of the procedure to run
    540   @param   CpuIndex         Target CPU number
    541   @param   ProcArguments    The parameter to pass to the procedure
    542 
    543   @retval   EFI_INVALID_PARAMETER    CpuNumber not valid
    544   @retval   EFI_INVALID_PARAMETER    CpuNumber specifying BSP
    545   @retval   EFI_INVALID_PARAMETER    The AP specified by CpuNumber did not enter SMM
    546   @retval   EFI_INVALID_PARAMETER    The AP specified by CpuNumber is busy
    547   @retval   EFI_SUCCESS - The procedure has been successfully scheduled
    548 
    549 **/
    550 EFI_STATUS
    551 EFIAPI
    552 SmmStartupThisAp (
    553   IN      EFI_AP_PROCEDURE          Procedure,
    554   IN      UINTN                     CpuIndex,
    555   IN OUT  VOID                      *ProcArguments OPTIONAL
    556   );
    557 
    558 /**
    559   Schedule a procedure to run on the specified CPU in a blocking fashion.
    560 
    561   @param  Procedure                The address of the procedure to run
    562   @param  CpuIndex                 Target CPU Index
    563   @param  ProcArguments            The parameter to pass to the procedure
    564 
    565   @retval EFI_INVALID_PARAMETER    CpuNumber not valid
    566   @retval EFI_INVALID_PARAMETER    CpuNumber specifying BSP
    567   @retval EFI_INVALID_PARAMETER    The AP specified by CpuNumber did not enter SMM
    568   @retval EFI_INVALID_PARAMETER    The AP specified by CpuNumber is busy
    569   @retval EFI_SUCCESS              The procedure has been successfully scheduled
    570 
    571 **/
    572 EFI_STATUS
    573 EFIAPI
    574 SmmBlockingStartupThisAp (
    575   IN      EFI_AP_PROCEDURE          Procedure,
    576   IN      UINTN                     CpuIndex,
    577   IN OUT  VOID                      *ProcArguments OPTIONAL
    578   );
    579 
    580 /**
    581   This function sets the attributes for the memory region specified by BaseAddress and
    582   Length from their current attributes to the attributes specified by Attributes.
    583 
    584   @param[in]  BaseAddress      The physical address that is the start address of a memory region.
    585   @param[in]  Length           The size in bytes of the memory region.
    586   @param[in]  Attributes       The bit mask of attributes to set for the memory region.
    587 
    588   @retval EFI_SUCCESS           The attributes were set for the memory region.
    589   @retval EFI_ACCESS_DENIED     The attributes for the memory resource range specified by
    590                                 BaseAddress and Length cannot be modified.
    591   @retval EFI_INVALID_PARAMETER Length is zero.
    592                                 Attributes specified an illegal combination of attributes that
    593                                 cannot be set together.
    594   @retval EFI_OUT_OF_RESOURCES  There are not enough system resources to modify the attributes of
    595                                 the memory resource range.
    596   @retval EFI_UNSUPPORTED       The processor does not support one or more bytes of the memory
    597                                 resource range specified by BaseAddress and Length.
    598                                 The bit mask of attributes is not support for the memory resource
    599                                 range specified by BaseAddress and Length.
    600 
    601 **/
    602 EFI_STATUS
    603 EFIAPI
    604 SmmSetMemoryAttributes (
    605   IN  EFI_PHYSICAL_ADDRESS                       BaseAddress,
    606   IN  UINT64                                     Length,
    607   IN  UINT64                                     Attributes
    608   );
    609 
    610 /**
    611   This function clears the attributes for the memory region specified by BaseAddress and
    612   Length from their current attributes to the attributes specified by Attributes.
    613 
    614   @param[in]  BaseAddress      The physical address that is the start address of a memory region.
    615   @param[in]  Length           The size in bytes of the memory region.
    616   @param[in]  Attributes       The bit mask of attributes to clear for the memory region.
    617 
    618   @retval EFI_SUCCESS           The attributes were cleared for the memory region.
    619   @retval EFI_ACCESS_DENIED     The attributes for the memory resource range specified by
    620                                 BaseAddress and Length cannot be modified.
    621   @retval EFI_INVALID_PARAMETER Length is zero.
    622                                 Attributes specified an illegal combination of attributes that
    623                                 cannot be set together.
    624   @retval EFI_OUT_OF_RESOURCES  There are not enough system resources to modify the attributes of
    625                                 the memory resource range.
    626   @retval EFI_UNSUPPORTED       The processor does not support one or more bytes of the memory
    627                                 resource range specified by BaseAddress and Length.
    628                                 The bit mask of attributes is not support for the memory resource
    629                                 range specified by BaseAddress and Length.
    630 
    631 **/
    632 EFI_STATUS
    633 EFIAPI
    634 SmmClearMemoryAttributes (
    635   IN  EFI_PHYSICAL_ADDRESS                       BaseAddress,
    636   IN  UINT64                                     Length,
    637   IN  UINT64                                     Attributes
    638   );
    639 
    640 /**
    641   Initialize MP synchronization data.
    642 
    643 **/
    644 VOID
    645 EFIAPI
    646 InitializeMpSyncData (
    647   VOID
    648   );
    649 
    650 /**
    651 
    652   Find out SMRAM information including SMRR base and SMRR size.
    653 
    654   @param          SmrrBase          SMRR base
    655   @param          SmrrSize          SMRR size
    656 
    657 **/
    658 VOID
    659 FindSmramInfo (
    660   OUT UINT32   *SmrrBase,
    661   OUT UINT32   *SmrrSize
    662   );
    663 
    664 /**
    665   Relocate SmmBases for each processor.
    666 
    667   Execute on first boot and all S3 resumes
    668 
    669 **/
    670 VOID
    671 EFIAPI
    672 SmmRelocateBases (
    673   VOID
    674   );
    675 
    676 /**
    677   Page Fault handler for SMM use.
    678 
    679   @param  InterruptType    Defines the type of interrupt or exception that
    680                            occurred on the processor.This parameter is processor architecture specific.
    681   @param  SystemContext    A pointer to the processor context when
    682                            the interrupt occurred on the processor.
    683 **/
    684 VOID
    685 EFIAPI
    686 SmiPFHandler (
    687     IN EFI_EXCEPTION_TYPE   InterruptType,
    688     IN EFI_SYSTEM_CONTEXT   SystemContext
    689   );
    690 
    691 /**
    692   Perform the remaining tasks.
    693 
    694 **/
    695 VOID
    696 PerformRemainingTasks (
    697   VOID
    698   );
    699 
    700 /**
    701   Perform the pre tasks.
    702 
    703 **/
    704 VOID
    705 PerformPreTasks (
    706   VOID
    707   );
    708 
    709 /**
    710   Initialize MSR spin lock by MSR index.
    711 
    712   @param  MsrIndex       MSR index value.
    713 
    714 **/
    715 VOID
    716 InitMsrSpinLockByIndex (
    717   IN UINT32      MsrIndex
    718   );
    719 
    720 /**
    721   Hook return address of SMM Save State so that semaphore code
    722   can be executed immediately after AP exits SMM to indicate to
    723   the BSP that an AP has exited SMM after SMBASE relocation.
    724 
    725   @param[in] CpuIndex     The processor index.
    726   @param[in] RebasedFlag  A pointer to a flag that is set to TRUE
    727                           immediately after AP exits SMM.
    728 
    729 **/
    730 VOID
    731 SemaphoreHook (
    732   IN UINTN             CpuIndex,
    733   IN volatile BOOLEAN  *RebasedFlag
    734   );
    735 
    736 /**
    737 Configure SMM Code Access Check feature for all processors.
    738 SMM Feature Control MSR will be locked after configuration.
    739 **/
    740 VOID
    741 ConfigSmmCodeAccessCheck (
    742   VOID
    743   );
    744 
    745 /**
    746   Hook the code executed immediately after an RSM instruction on the currently
    747   executing CPU.  The mode of code executed immediately after RSM must be
    748   detected, and the appropriate hook must be selected.  Always clear the auto
    749   HALT restart flag if it is set.
    750 
    751   @param[in] CpuIndex                 The processor index for the currently
    752                                       executing CPU.
    753   @param[in] CpuState                 Pointer to SMRAM Save State Map for the
    754                                       currently executing CPU.
    755   @param[in] NewInstructionPointer32  Instruction pointer to use if resuming to
    756                                       32-bit mode from 64-bit SMM.
    757   @param[in] NewInstructionPointer    Instruction pointer to use if resuming to
    758                                       same mode as SMM.
    759 
    760   @retval The value of the original instruction pointer before it was hooked.
    761 
    762 **/
    763 UINT64
    764 EFIAPI
    765 HookReturnFromSmm (
    766   IN UINTN              CpuIndex,
    767   SMRAM_SAVE_STATE_MAP  *CpuState,
    768   UINT64                NewInstructionPointer32,
    769   UINT64                NewInstructionPointer
    770   );
    771 
    772 /**
    773   Get the size of the SMI Handler in bytes.
    774 
    775   @retval The size, in bytes, of the SMI Handler.
    776 
    777 **/
    778 UINTN
    779 EFIAPI
    780 GetSmiHandlerSize (
    781   VOID
    782   );
    783 
    784 /**
    785   Install the SMI handler for the CPU specified by CpuIndex.  This function
    786   is called by the CPU that was elected as monarch during System Management
    787   Mode initialization.
    788 
    789   @param[in] CpuIndex   The index of the CPU to install the custom SMI handler.
    790                         The value must be between 0 and the NumberOfCpus field
    791                         in the System Management System Table (SMST).
    792   @param[in] SmBase     The SMBASE address for the CPU specified by CpuIndex.
    793   @param[in] SmiStack   The stack to use when an SMI is processed by the
    794                         the CPU specified by CpuIndex.
    795   @param[in] StackSize  The size, in bytes, if the stack used when an SMI is
    796                         processed by the CPU specified by CpuIndex.
    797   @param[in] GdtBase    The base address of the GDT to use when an SMI is
    798                         processed by the CPU specified by CpuIndex.
    799   @param[in] GdtSize    The size, in bytes, of the GDT used when an SMI is
    800                         processed by the CPU specified by CpuIndex.
    801   @param[in] IdtBase    The base address of the IDT to use when an SMI is
    802                         processed by the CPU specified by CpuIndex.
    803   @param[in] IdtSize    The size, in bytes, of the IDT used when an SMI is
    804                         processed by the CPU specified by CpuIndex.
    805   @param[in] Cr3        The base address of the page tables to use when an SMI
    806                         is processed by the CPU specified by CpuIndex.
    807 **/
    808 VOID
    809 EFIAPI
    810 InstallSmiHandler (
    811   IN UINTN   CpuIndex,
    812   IN UINT32  SmBase,
    813   IN VOID    *SmiStack,
    814   IN UINTN   StackSize,
    815   IN UINTN   GdtBase,
    816   IN UINTN   GdtSize,
    817   IN UINTN   IdtBase,
    818   IN UINTN   IdtSize,
    819   IN UINT32  Cr3
    820   );
    821 
    822 /**
    823   Search module name by input IP address and output it.
    824 
    825   @param CallerIpAddress   Caller instruction pointer.
    826 
    827 **/
    828 VOID
    829 DumpModuleInfoByIp (
    830   IN  UINTN              CallerIpAddress
    831   );
    832 
    833 /**
    834   This function sets memory attribute according to MemoryAttributesTable.
    835 **/
    836 VOID
    837 SetMemMapAttributes (
    838   VOID
    839   );
    840 
    841 /**
    842   This function sets UEFI memory attribute according to UEFI memory map.
    843 **/
    844 VOID
    845 SetUefiMemMapAttributes (
    846   VOID
    847   );
    848 
    849 /**
    850   Return if the Address is forbidden as SMM communication buffer.
    851 
    852   @param[in] Address the address to be checked
    853 
    854   @return TRUE  The address is forbidden as SMM communication buffer.
    855   @return FALSE The address is allowed as SMM communication buffer.
    856 **/
    857 BOOLEAN
    858 IsSmmCommBufferForbiddenAddress (
    859   IN UINT64  Address
    860   );
    861 
    862 /**
    863   This function caches the UEFI memory map information.
    864 **/
    865 VOID
    866 GetUefiMemoryMap (
    867   VOID
    868   );
    869 
    870 /**
    871   This function sets memory attribute for page table.
    872 **/
    873 VOID
    874 SetPageTableAttributes (
    875   VOID
    876   );
    877 
    878 /**
    879   Return page table base.
    880 
    881   @return page table base.
    882 **/
    883 UINTN
    884 GetPageTableBase (
    885   VOID
    886   );
    887 
    888 /**
    889   This function sets the attributes for the memory region specified by BaseAddress and
    890   Length from their current attributes to the attributes specified by Attributes.
    891 
    892   @param[in]   BaseAddress      The physical address that is the start address of a memory region.
    893   @param[in]   Length           The size in bytes of the memory region.
    894   @param[in]   Attributes       The bit mask of attributes to set for the memory region.
    895   @param[out]  IsSplitted       TRUE means page table splitted. FALSE means page table not splitted.
    896 
    897   @retval EFI_SUCCESS           The attributes were set for the memory region.
    898   @retval EFI_ACCESS_DENIED     The attributes for the memory resource range specified by
    899                                 BaseAddress and Length cannot be modified.
    900   @retval EFI_INVALID_PARAMETER Length is zero.
    901                                 Attributes specified an illegal combination of attributes that
    902                                 cannot be set together.
    903   @retval EFI_OUT_OF_RESOURCES  There are not enough system resources to modify the attributes of
    904                                 the memory resource range.
    905   @retval EFI_UNSUPPORTED       The processor does not support one or more bytes of the memory
    906                                 resource range specified by BaseAddress and Length.
    907                                 The bit mask of attributes is not support for the memory resource
    908                                 range specified by BaseAddress and Length.
    909 
    910 **/
    911 EFI_STATUS
    912 EFIAPI
    913 SmmSetMemoryAttributesEx (
    914   IN  EFI_PHYSICAL_ADDRESS                       BaseAddress,
    915   IN  UINT64                                     Length,
    916   IN  UINT64                                     Attributes,
    917   OUT BOOLEAN                                    *IsSplitted  OPTIONAL
    918   );
    919 
    920 /**
    921   This function clears the attributes for the memory region specified by BaseAddress and
    922   Length from their current attributes to the attributes specified by Attributes.
    923 
    924   @param[in]   BaseAddress      The physical address that is the start address of a memory region.
    925   @param[in]   Length           The size in bytes of the memory region.
    926   @param[in]   Attributes       The bit mask of attributes to clear for the memory region.
    927   @param[out]  IsSplitted       TRUE means page table splitted. FALSE means page table not splitted.
    928 
    929   @retval EFI_SUCCESS           The attributes were cleared for the memory region.
    930   @retval EFI_ACCESS_DENIED     The attributes for the memory resource range specified by
    931                                 BaseAddress and Length cannot be modified.
    932   @retval EFI_INVALID_PARAMETER Length is zero.
    933                                 Attributes specified an illegal combination of attributes that
    934                                 cannot be set together.
    935   @retval EFI_OUT_OF_RESOURCES  There are not enough system resources to modify the attributes of
    936                                 the memory resource range.
    937   @retval EFI_UNSUPPORTED       The processor does not support one or more bytes of the memory
    938                                 resource range specified by BaseAddress and Length.
    939                                 The bit mask of attributes is not support for the memory resource
    940                                 range specified by BaseAddress and Length.
    941 
    942 **/
    943 EFI_STATUS
    944 EFIAPI
    945 SmmClearMemoryAttributesEx (
    946   IN  EFI_PHYSICAL_ADDRESS                       BaseAddress,
    947   IN  UINT64                                     Length,
    948   IN  UINT64                                     Attributes,
    949   OUT BOOLEAN                                    *IsSplitted  OPTIONAL
    950   );
    951 
    952 /**
    953   This API provides a way to allocate memory for page table.
    954 
    955   This API can be called more once to allocate memory for page tables.
    956 
    957   Allocates the number of 4KB pages of type EfiRuntimeServicesData and returns a pointer to the
    958   allocated buffer.  The buffer returned is aligned on a 4KB boundary.  If Pages is 0, then NULL
    959   is returned.  If there is not enough memory remaining to satisfy the request, then NULL is
    960   returned.
    961 
    962   @param  Pages                 The number of 4 KB pages to allocate.
    963 
    964   @return A pointer to the allocated buffer or NULL if allocation fails.
    965 
    966 **/
    967 VOID *
    968 AllocatePageTableMemory (
    969   IN UINTN           Pages
    970   );
    971 
    972 /**
    973   Allocate pages for code.
    974 
    975   @param[in]  Pages Number of pages to be allocated.
    976 
    977   @return Allocated memory.
    978 **/
    979 VOID *
    980 AllocateCodePages (
    981   IN UINTN           Pages
    982   );
    983 
    984 /**
    985   Allocate aligned pages for code.
    986 
    987   @param[in]  Pages                 Number of pages to be allocated.
    988   @param[in]  Alignment             The requested alignment of the allocation.
    989                                     Must be a power of two.
    990                                     If Alignment is zero, then byte alignment is used.
    991 
    992   @return Allocated memory.
    993 **/
    994 VOID *
    995 AllocateAlignedCodePages (
    996   IN UINTN            Pages,
    997   IN UINTN            Alignment
    998   );
    999 
   1000 
   1001 //
   1002 // S3 related global variable and function prototype.
   1003 //
   1004 
   1005 extern BOOLEAN                mSmmS3Flag;
   1006 
   1007 /**
   1008   Initialize SMM S3 resume state structure used during S3 Resume.
   1009 
   1010   @param[in] Cr3    The base address of the page tables to use in SMM.
   1011 
   1012 **/
   1013 VOID
   1014 InitSmmS3ResumeState (
   1015   IN UINT32  Cr3
   1016   );
   1017 
   1018 /**
   1019   Get ACPI CPU data.
   1020 
   1021 **/
   1022 VOID
   1023 GetAcpiCpuData (
   1024   VOID
   1025   );
   1026 
   1027 /**
   1028   Restore SMM Configuration in S3 boot path.
   1029 
   1030 **/
   1031 VOID
   1032 RestoreSmmConfigurationInS3 (
   1033   VOID
   1034   );
   1035 
   1036 /**
   1037   Get ACPI S3 enable flag.
   1038 
   1039 **/
   1040 VOID
   1041 GetAcpiS3EnableFlag (
   1042   VOID
   1043   );
   1044 
   1045 /**
   1046   Transfer AP to safe hlt-loop after it finished restore CPU features on S3 patch.
   1047 
   1048   @param[in] ApHltLoopCode          The address of the safe hlt-loop function.
   1049   @param[in] TopOfStack             A pointer to the new stack to use for the ApHltLoopCode.
   1050   @param[in] NumberToFinishAddress  Address of Semaphore of APs finish count.
   1051 
   1052 **/
   1053 VOID
   1054 TransferApToSafeState (
   1055   IN UINTN  ApHltLoopCode,
   1056   IN UINTN  TopOfStack,
   1057   IN UINTN  NumberToFinishAddress
   1058   );
   1059 
   1060 #endif
   1061