Home | History | Annotate | Download | only in PiSmmCpuDxeSmm
      1 /** @file
      2 Provides services to access SMRAM Save State Map
      3 
      4 Copyright (c) 2010 - 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 <PiSmm.h>
     16 
     17 #include <Library/SmmCpuFeaturesLib.h>
     18 
     19 #include <Library/BaseLib.h>
     20 #include <Library/BaseMemoryLib.h>
     21 #include <Library/SmmServicesTableLib.h>
     22 #include <Library/DebugLib.h>
     23 #include <Register/Cpuid.h>
     24 #include <Register/SmramSaveStateMap.h>
     25 
     26 #include "PiSmmCpuDxeSmm.h"
     27 
     28 typedef struct {
     29   UINT64                            Signature;              // Offset 0x00
     30   UINT16                            Reserved1;              // Offset 0x08
     31   UINT16                            Reserved2;              // Offset 0x0A
     32   UINT16                            Reserved3;              // Offset 0x0C
     33   UINT16                            SmmCs;                  // Offset 0x0E
     34   UINT16                            SmmDs;                  // Offset 0x10
     35   UINT16                            SmmSs;                  // Offset 0x12
     36   UINT16                            SmmOtherSegment;        // Offset 0x14
     37   UINT16                            Reserved4;              // Offset 0x16
     38   UINT64                            Reserved5;              // Offset 0x18
     39   UINT64                            Reserved6;              // Offset 0x20
     40   UINT64                            Reserved7;              // Offset 0x28
     41   UINT64                            SmmGdtPtr;              // Offset 0x30
     42   UINT32                            SmmGdtSize;             // Offset 0x38
     43   UINT32                            Reserved8;              // Offset 0x3C
     44   UINT64                            Reserved9;              // Offset 0x40
     45   UINT64                            Reserved10;             // Offset 0x48
     46   UINT16                            Reserved11;             // Offset 0x50
     47   UINT16                            Reserved12;             // Offset 0x52
     48   UINT32                            Reserved13;             // Offset 0x54
     49   UINT64                            Reserved14;             // Offset 0x58
     50 } PROCESSOR_SMM_DESCRIPTOR;
     51 
     52 extern CONST PROCESSOR_SMM_DESCRIPTOR      gcPsd;
     53 
     54 //
     55 // EFER register LMA bit
     56 //
     57 #define LMA BIT10
     58 
     59 ///
     60 /// Macro used to simplify the lookup table entries of type CPU_SMM_SAVE_STATE_LOOKUP_ENTRY
     61 ///
     62 #define SMM_CPU_OFFSET(Field) OFFSET_OF (SMRAM_SAVE_STATE_MAP, Field)
     63 
     64 ///
     65 /// Macro used to simplify the lookup table entries of type CPU_SMM_SAVE_STATE_REGISTER_RANGE
     66 ///
     67 #define SMM_REGISTER_RANGE(Start, End) { Start, End, End - Start + 1 }
     68 
     69 ///
     70 /// Structure used to describe a range of registers
     71 ///
     72 typedef struct {
     73   EFI_SMM_SAVE_STATE_REGISTER  Start;
     74   EFI_SMM_SAVE_STATE_REGISTER  End;
     75   UINTN                        Length;
     76 } CPU_SMM_SAVE_STATE_REGISTER_RANGE;
     77 
     78 ///
     79 /// Structure used to build a lookup table to retrieve the widths and offsets
     80 /// associated with each supported EFI_SMM_SAVE_STATE_REGISTER value
     81 ///
     82 
     83 #define SMM_SAVE_STATE_REGISTER_SMMREVID_INDEX        1
     84 #define SMM_SAVE_STATE_REGISTER_IOMISC_INDEX          2
     85 #define SMM_SAVE_STATE_REGISTER_IOMEMADDR_INDEX       3
     86 #define SMM_SAVE_STATE_REGISTER_MAX_INDEX             4
     87 
     88 typedef struct {
     89   UINT8   Width32;
     90   UINT8   Width64;
     91   UINT16  Offset32;
     92   UINT16  Offset64Lo;
     93   UINT16  Offset64Hi;
     94   BOOLEAN Writeable;
     95 } CPU_SMM_SAVE_STATE_LOOKUP_ENTRY;
     96 
     97 ///
     98 /// Structure used to build a lookup table for the IOMisc width information
     99 ///
    100 typedef struct {
    101   UINT8                        Width;
    102   EFI_SMM_SAVE_STATE_IO_WIDTH  IoWidth;
    103 } CPU_SMM_SAVE_STATE_IO_WIDTH;
    104 
    105 ///
    106 /// Variables from SMI Handler
    107 ///
    108 extern UINT32           gSmbase;
    109 extern volatile UINT32  gSmiStack;
    110 extern UINT32           gSmiCr3;
    111 extern volatile UINT8   gcSmiHandlerTemplate[];
    112 extern CONST UINT16     gcSmiHandlerSize;
    113 
    114 //
    115 // Variables used by SMI Handler
    116 //
    117 IA32_DESCRIPTOR  gSmiHandlerIdtr;
    118 
    119 ///
    120 /// Table used by GetRegisterIndex() to convert an EFI_SMM_SAVE_STATE_REGISTER
    121 /// value to an index into a table of type CPU_SMM_SAVE_STATE_LOOKUP_ENTRY
    122 ///
    123 CONST CPU_SMM_SAVE_STATE_REGISTER_RANGE mSmmCpuRegisterRanges[] = {
    124   SMM_REGISTER_RANGE (EFI_SMM_SAVE_STATE_REGISTER_GDTBASE, EFI_SMM_SAVE_STATE_REGISTER_LDTINFO),
    125   SMM_REGISTER_RANGE (EFI_SMM_SAVE_STATE_REGISTER_ES,      EFI_SMM_SAVE_STATE_REGISTER_RIP),
    126   SMM_REGISTER_RANGE (EFI_SMM_SAVE_STATE_REGISTER_RFLAGS,  EFI_SMM_SAVE_STATE_REGISTER_CR4),
    127   { (EFI_SMM_SAVE_STATE_REGISTER)0, (EFI_SMM_SAVE_STATE_REGISTER)0, 0 }
    128 };
    129 
    130 ///
    131 /// Lookup table used to retrieve the widths and offsets associated with each
    132 /// supported EFI_SMM_SAVE_STATE_REGISTER value
    133 ///
    134 CONST CPU_SMM_SAVE_STATE_LOOKUP_ENTRY mSmmCpuWidthOffset[] = {
    135   {0, 0, 0, 0, 0, FALSE},                                                                                                     //  Reserved
    136 
    137   //
    138   // Internally defined CPU Save State Registers. Not defined in PI SMM CPU Protocol.
    139   //
    140   {4, 4, SMM_CPU_OFFSET (x86.SMMRevId)  , SMM_CPU_OFFSET (x64.SMMRevId)  , 0                                 , FALSE}, // SMM_SAVE_STATE_REGISTER_SMMREVID_INDEX  = 1
    141   {4, 4, SMM_CPU_OFFSET (x86.IOMisc)    , SMM_CPU_OFFSET (x64.IOMisc)    , 0                                 , FALSE}, // SMM_SAVE_STATE_REGISTER_IOMISC_INDEX    = 2
    142   {4, 8, SMM_CPU_OFFSET (x86.IOMemAddr) , SMM_CPU_OFFSET (x64.IOMemAddr) , SMM_CPU_OFFSET (x64.IOMemAddr) + 4, FALSE}, // SMM_SAVE_STATE_REGISTER_IOMEMADDR_INDEX = 3
    143 
    144   //
    145   // CPU Save State registers defined in PI SMM CPU Protocol.
    146   //
    147   {0, 8, 0                            , SMM_CPU_OFFSET (x64.GdtBaseLoDword) , SMM_CPU_OFFSET (x64.GdtBaseHiDword), FALSE},  //  EFI_SMM_SAVE_STATE_REGISTER_GDTBASE  = 4
    148   {0, 8, 0                            , SMM_CPU_OFFSET (x64.IdtBaseLoDword) , SMM_CPU_OFFSET (x64.IdtBaseHiDword), FALSE},  //  EFI_SMM_SAVE_STATE_REGISTER_IDTBASE  = 5
    149   {0, 8, 0                            , SMM_CPU_OFFSET (x64.LdtBaseLoDword) , SMM_CPU_OFFSET (x64.LdtBaseHiDword), FALSE},  //  EFI_SMM_SAVE_STATE_REGISTER_LDTBASE  = 6
    150   {0, 0, 0                            , 0                                   , 0                                  , FALSE},  //  EFI_SMM_SAVE_STATE_REGISTER_GDTLIMIT = 7
    151   {0, 0, 0                            , 0                                   , 0                                  , FALSE},  //  EFI_SMM_SAVE_STATE_REGISTER_IDTLIMIT = 8
    152   {0, 0, 0                            , 0                                   , 0                                  , FALSE},  //  EFI_SMM_SAVE_STATE_REGISTER_LDTLIMIT = 9
    153   {0, 0, 0                            , 0                                   , 0                                  , FALSE},  //  EFI_SMM_SAVE_STATE_REGISTER_LDTINFO  = 10
    154 
    155   {4, 4, SMM_CPU_OFFSET (x86._ES)     , SMM_CPU_OFFSET (x64._ES)     , 0                               , FALSE},  //  EFI_SMM_SAVE_STATE_REGISTER_ES       = 20
    156   {4, 4, SMM_CPU_OFFSET (x86._CS)     , SMM_CPU_OFFSET (x64._CS)     , 0                               , FALSE},  //  EFI_SMM_SAVE_STATE_REGISTER_CS       = 21
    157   {4, 4, SMM_CPU_OFFSET (x86._SS)     , SMM_CPU_OFFSET (x64._SS)     , 0                               , FALSE},  //  EFI_SMM_SAVE_STATE_REGISTER_SS       = 22
    158   {4, 4, SMM_CPU_OFFSET (x86._DS)     , SMM_CPU_OFFSET (x64._DS)     , 0                               , FALSE},  //  EFI_SMM_SAVE_STATE_REGISTER_DS       = 23
    159   {4, 4, SMM_CPU_OFFSET (x86._FS)     , SMM_CPU_OFFSET (x64._FS)     , 0                               , FALSE},  //  EFI_SMM_SAVE_STATE_REGISTER_FS       = 24
    160   {4, 4, SMM_CPU_OFFSET (x86._GS)     , SMM_CPU_OFFSET (x64._GS)     , 0                               , FALSE},  //  EFI_SMM_SAVE_STATE_REGISTER_GS       = 25
    161   {0, 4, 0                            , SMM_CPU_OFFSET (x64._LDTR)   , 0                               , FALSE},  //  EFI_SMM_SAVE_STATE_REGISTER_LDTR_SEL = 26
    162   {4, 4, SMM_CPU_OFFSET (x86._TR)     , SMM_CPU_OFFSET (x64._TR)     , 0                               , FALSE},  //  EFI_SMM_SAVE_STATE_REGISTER_TR_SEL   = 27
    163   {4, 8, SMM_CPU_OFFSET (x86._DR7)    , SMM_CPU_OFFSET (x64._DR7)    , SMM_CPU_OFFSET (x64._DR7)    + 4, FALSE},  //  EFI_SMM_SAVE_STATE_REGISTER_DR7      = 28
    164   {4, 8, SMM_CPU_OFFSET (x86._DR6)    , SMM_CPU_OFFSET (x64._DR6)    , SMM_CPU_OFFSET (x64._DR6)    + 4, FALSE},  //  EFI_SMM_SAVE_STATE_REGISTER_DR6      = 29
    165   {0, 8, 0                            , SMM_CPU_OFFSET (x64._R8)     , SMM_CPU_OFFSET (x64._R8)     + 4, TRUE },  //  EFI_SMM_SAVE_STATE_REGISTER_R8       = 30
    166   {0, 8, 0                            , SMM_CPU_OFFSET (x64._R9)     , SMM_CPU_OFFSET (x64._R9)     + 4, TRUE },  //  EFI_SMM_SAVE_STATE_REGISTER_R9       = 31
    167   {0, 8, 0                            , SMM_CPU_OFFSET (x64._R10)    , SMM_CPU_OFFSET (x64._R10)    + 4, TRUE },  //  EFI_SMM_SAVE_STATE_REGISTER_R10      = 32
    168   {0, 8, 0                            , SMM_CPU_OFFSET (x64._R11)    , SMM_CPU_OFFSET (x64._R11)    + 4, TRUE },  //  EFI_SMM_SAVE_STATE_REGISTER_R11      = 33
    169   {0, 8, 0                            , SMM_CPU_OFFSET (x64._R12)    , SMM_CPU_OFFSET (x64._R12)    + 4, TRUE },  //  EFI_SMM_SAVE_STATE_REGISTER_R12      = 34
    170   {0, 8, 0                            , SMM_CPU_OFFSET (x64._R13)    , SMM_CPU_OFFSET (x64._R13)    + 4, TRUE },  //  EFI_SMM_SAVE_STATE_REGISTER_R13      = 35
    171   {0, 8, 0                            , SMM_CPU_OFFSET (x64._R14)    , SMM_CPU_OFFSET (x64._R14)    + 4, TRUE },  //  EFI_SMM_SAVE_STATE_REGISTER_R14      = 36
    172   {0, 8, 0                            , SMM_CPU_OFFSET (x64._R15)    , SMM_CPU_OFFSET (x64._R15)    + 4, TRUE },  //  EFI_SMM_SAVE_STATE_REGISTER_R15      = 37
    173   {4, 8, SMM_CPU_OFFSET (x86._EAX)    , SMM_CPU_OFFSET (x64._RAX)    , SMM_CPU_OFFSET (x64._RAX)    + 4, TRUE },  //  EFI_SMM_SAVE_STATE_REGISTER_RAX      = 38
    174   {4, 8, SMM_CPU_OFFSET (x86._EBX)    , SMM_CPU_OFFSET (x64._RBX)    , SMM_CPU_OFFSET (x64._RBX)    + 4, TRUE },  //  EFI_SMM_SAVE_STATE_REGISTER_RBX      = 39
    175   {4, 8, SMM_CPU_OFFSET (x86._ECX)    , SMM_CPU_OFFSET (x64._RCX)    , SMM_CPU_OFFSET (x64._RCX)    + 4, TRUE },  //  EFI_SMM_SAVE_STATE_REGISTER_RCX      = 40
    176   {4, 8, SMM_CPU_OFFSET (x86._EDX)    , SMM_CPU_OFFSET (x64._RDX)    , SMM_CPU_OFFSET (x64._RDX)    + 4, TRUE },  //  EFI_SMM_SAVE_STATE_REGISTER_RDX      = 41
    177   {4, 8, SMM_CPU_OFFSET (x86._ESP)    , SMM_CPU_OFFSET (x64._RSP)    , SMM_CPU_OFFSET (x64._RSP)    + 4, TRUE },  //  EFI_SMM_SAVE_STATE_REGISTER_RSP      = 42
    178   {4, 8, SMM_CPU_OFFSET (x86._EBP)    , SMM_CPU_OFFSET (x64._RBP)    , SMM_CPU_OFFSET (x64._RBP)    + 4, TRUE },  //  EFI_SMM_SAVE_STATE_REGISTER_RBP      = 43
    179   {4, 8, SMM_CPU_OFFSET (x86._ESI)    , SMM_CPU_OFFSET (x64._RSI)    , SMM_CPU_OFFSET (x64._RSI)    + 4, TRUE },  //  EFI_SMM_SAVE_STATE_REGISTER_RSI      = 44
    180   {4, 8, SMM_CPU_OFFSET (x86._EDI)    , SMM_CPU_OFFSET (x64._RDI)    , SMM_CPU_OFFSET (x64._RDI)    + 4, TRUE },  //  EFI_SMM_SAVE_STATE_REGISTER_RDI      = 45
    181   {4, 8, SMM_CPU_OFFSET (x86._EIP)    , SMM_CPU_OFFSET (x64._RIP)    , SMM_CPU_OFFSET (x64._RIP)    + 4, TRUE },  //  EFI_SMM_SAVE_STATE_REGISTER_RIP      = 46
    182 
    183   {4, 8, SMM_CPU_OFFSET (x86._EFLAGS) , SMM_CPU_OFFSET (x64._RFLAGS) , SMM_CPU_OFFSET (x64._RFLAGS) + 4, TRUE },  //  EFI_SMM_SAVE_STATE_REGISTER_RFLAGS   = 51
    184   {4, 8, SMM_CPU_OFFSET (x86._CR0)    , SMM_CPU_OFFSET (x64._CR0)    , SMM_CPU_OFFSET (x64._CR0)    + 4, FALSE},  //  EFI_SMM_SAVE_STATE_REGISTER_CR0      = 52
    185   {4, 8, SMM_CPU_OFFSET (x86._CR3)    , SMM_CPU_OFFSET (x64._CR3)    , SMM_CPU_OFFSET (x64._CR3)    + 4, FALSE},  //  EFI_SMM_SAVE_STATE_REGISTER_CR3      = 53
    186   {0, 4, 0                            , SMM_CPU_OFFSET (x64._CR4)    , 0                               , FALSE},  //  EFI_SMM_SAVE_STATE_REGISTER_CR4      = 54
    187 };
    188 
    189 ///
    190 /// Lookup table for the IOMisc width information
    191 ///
    192 CONST CPU_SMM_SAVE_STATE_IO_WIDTH mSmmCpuIoWidth[] = {
    193   { 0, EFI_SMM_SAVE_STATE_IO_WIDTH_UINT8  },  // Undefined           = 0
    194   { 1, EFI_SMM_SAVE_STATE_IO_WIDTH_UINT8  },  // SMM_IO_LENGTH_BYTE  = 1
    195   { 2, EFI_SMM_SAVE_STATE_IO_WIDTH_UINT16 },  // SMM_IO_LENGTH_WORD  = 2
    196   { 0, EFI_SMM_SAVE_STATE_IO_WIDTH_UINT8  },  // Undefined           = 3
    197   { 4, EFI_SMM_SAVE_STATE_IO_WIDTH_UINT32 },  // SMM_IO_LENGTH_DWORD = 4
    198   { 0, EFI_SMM_SAVE_STATE_IO_WIDTH_UINT8  },  // Undefined           = 5
    199   { 0, EFI_SMM_SAVE_STATE_IO_WIDTH_UINT8  },  // Undefined           = 6
    200   { 0, EFI_SMM_SAVE_STATE_IO_WIDTH_UINT8  }   // Undefined           = 7
    201 };
    202 
    203 ///
    204 /// Lookup table for the IOMisc type information
    205 ///
    206 CONST EFI_SMM_SAVE_STATE_IO_TYPE mSmmCpuIoType[] = {
    207   EFI_SMM_SAVE_STATE_IO_TYPE_OUTPUT,     // SMM_IO_TYPE_OUT_DX        = 0
    208   EFI_SMM_SAVE_STATE_IO_TYPE_INPUT,      // SMM_IO_TYPE_IN_DX         = 1
    209   EFI_SMM_SAVE_STATE_IO_TYPE_STRING,     // SMM_IO_TYPE_OUTS          = 2
    210   EFI_SMM_SAVE_STATE_IO_TYPE_STRING,     // SMM_IO_TYPE_INS           = 3
    211   (EFI_SMM_SAVE_STATE_IO_TYPE)0,         // Undefined                 = 4
    212   (EFI_SMM_SAVE_STATE_IO_TYPE)0,         // Undefined                 = 5
    213   EFI_SMM_SAVE_STATE_IO_TYPE_REP_PREFIX, // SMM_IO_TYPE_REP_OUTS      = 6
    214   EFI_SMM_SAVE_STATE_IO_TYPE_REP_PREFIX, // SMM_IO_TYPE_REP_INS       = 7
    215   EFI_SMM_SAVE_STATE_IO_TYPE_OUTPUT,     // SMM_IO_TYPE_OUT_IMMEDIATE = 8
    216   EFI_SMM_SAVE_STATE_IO_TYPE_INPUT,      // SMM_IO_TYPE_OUT_IMMEDIATE = 9
    217   (EFI_SMM_SAVE_STATE_IO_TYPE)0,         // Undefined                 = 10
    218   (EFI_SMM_SAVE_STATE_IO_TYPE)0,         // Undefined                 = 11
    219   (EFI_SMM_SAVE_STATE_IO_TYPE)0,         // Undefined                 = 12
    220   (EFI_SMM_SAVE_STATE_IO_TYPE)0,         // Undefined                 = 13
    221   (EFI_SMM_SAVE_STATE_IO_TYPE)0,         // Undefined                 = 14
    222   (EFI_SMM_SAVE_STATE_IO_TYPE)0          // Undefined                 = 15
    223 };
    224 
    225 ///
    226 /// The mode of the CPU at the time an SMI occurs
    227 ///
    228 UINT8  mSmmSaveStateRegisterLma;
    229 
    230 /**
    231   Read information from the CPU save state.
    232 
    233   @param  Register  Specifies the CPU register to read form the save state.
    234 
    235   @retval 0   Register is not valid
    236   @retval >0  Index into mSmmCpuWidthOffset[] associated with Register
    237 
    238 **/
    239 UINTN
    240 GetRegisterIndex (
    241   IN EFI_SMM_SAVE_STATE_REGISTER  Register
    242   )
    243 {
    244   UINTN  Index;
    245   UINTN  Offset;
    246 
    247   for (Index = 0, Offset = SMM_SAVE_STATE_REGISTER_MAX_INDEX; mSmmCpuRegisterRanges[Index].Length != 0; Index++) {
    248     if (Register >= mSmmCpuRegisterRanges[Index].Start && Register <= mSmmCpuRegisterRanges[Index].End) {
    249       return Register - mSmmCpuRegisterRanges[Index].Start + Offset;
    250     }
    251     Offset += mSmmCpuRegisterRanges[Index].Length;
    252   }
    253   return 0;
    254 }
    255 
    256 /**
    257   Read a CPU Save State register on the target processor.
    258 
    259   This function abstracts the differences that whether the CPU Save State register is in the
    260   IA32 CPU Save State Map or X64 CPU Save State Map.
    261 
    262   This function supports reading a CPU Save State register in SMBase relocation handler.
    263 
    264   @param[in]  CpuIndex       Specifies the zero-based index of the CPU save state.
    265   @param[in]  RegisterIndex  Index into mSmmCpuWidthOffset[] look up table.
    266   @param[in]  Width          The number of bytes to read from the CPU save state.
    267   @param[out] Buffer         Upon return, this holds the CPU register value read from the save state.
    268 
    269   @retval EFI_SUCCESS           The register was read from Save State.
    270   @retval EFI_NOT_FOUND         The register is not defined for the Save State of Processor.
    271   @retval EFI_INVALID_PARAMTER  This or Buffer is NULL.
    272 
    273 **/
    274 EFI_STATUS
    275 ReadSaveStateRegisterByIndex (
    276   IN UINTN   CpuIndex,
    277   IN UINTN   RegisterIndex,
    278   IN UINTN   Width,
    279   OUT VOID   *Buffer
    280   )
    281 {
    282   SMRAM_SAVE_STATE_MAP  *CpuSaveState;
    283 
    284   if (RegisterIndex == 0) {
    285     return EFI_NOT_FOUND;
    286   }
    287 
    288   CpuSaveState = gSmst->CpuSaveState[CpuIndex];
    289 
    290   if (mSmmSaveStateRegisterLma == EFI_SMM_SAVE_STATE_REGISTER_LMA_32BIT) {
    291     //
    292     // If 32-bit mode width is zero, then the specified register can not be accessed
    293     //
    294     if (mSmmCpuWidthOffset[RegisterIndex].Width32 == 0) {
    295       return EFI_NOT_FOUND;
    296     }
    297 
    298     //
    299     // If Width is bigger than the 32-bit mode width, then the specified register can not be accessed
    300     //
    301     if (Width > mSmmCpuWidthOffset[RegisterIndex].Width32) {
    302       return EFI_INVALID_PARAMETER;
    303     }
    304 
    305     //
    306     // Write return buffer
    307     //
    308     ASSERT(CpuSaveState != NULL);
    309     CopyMem(Buffer, (UINT8 *)CpuSaveState + mSmmCpuWidthOffset[RegisterIndex].Offset32, Width);
    310   } else {
    311     //
    312     // If 64-bit mode width is zero, then the specified register can not be accessed
    313     //
    314     if (mSmmCpuWidthOffset[RegisterIndex].Width64 == 0) {
    315       return EFI_NOT_FOUND;
    316     }
    317 
    318     //
    319     // If Width is bigger than the 64-bit mode width, then the specified register can not be accessed
    320     //
    321     if (Width > mSmmCpuWidthOffset[RegisterIndex].Width64) {
    322       return EFI_INVALID_PARAMETER;
    323     }
    324 
    325     //
    326     // Write lower 32-bits of return buffer
    327     //
    328     CopyMem(Buffer, (UINT8 *)CpuSaveState + mSmmCpuWidthOffset[RegisterIndex].Offset64Lo, MIN(4, Width));
    329     if (Width >= 4) {
    330       //
    331       // Write upper 32-bits of return buffer
    332       //
    333       CopyMem((UINT8 *)Buffer + 4, (UINT8 *)CpuSaveState + mSmmCpuWidthOffset[RegisterIndex].Offset64Hi, Width - 4);
    334     }
    335   }
    336   return EFI_SUCCESS;
    337 }
    338 
    339 /**
    340   Read a CPU Save State register on the target processor.
    341 
    342   This function abstracts the differences that whether the CPU Save State register is in the
    343   IA32 CPU Save State Map or X64 CPU Save State Map.
    344 
    345   This function supports reading a CPU Save State register in SMBase relocation handler.
    346 
    347   @param[in]  CpuIndex       Specifies the zero-based index of the CPU save state.
    348   @param[in]  RegisterIndex  Index into mSmmCpuWidthOffset[] look up table.
    349   @param[in]  Width          The number of bytes to read from the CPU save state.
    350   @param[out] Buffer         Upon return, this holds the CPU register value read from the save state.
    351 
    352   @retval EFI_SUCCESS           The register was read from Save State.
    353   @retval EFI_NOT_FOUND         The register is not defined for the Save State of Processor.
    354   @retval EFI_INVALID_PARAMTER  This or Buffer is NULL.
    355 
    356 **/
    357 EFI_STATUS
    358 EFIAPI
    359 ReadSaveStateRegister (
    360   IN UINTN                        CpuIndex,
    361   IN EFI_SMM_SAVE_STATE_REGISTER  Register,
    362   IN UINTN                        Width,
    363   OUT VOID                        *Buffer
    364   )
    365 {
    366   UINT32                      SmmRevId;
    367   SMRAM_SAVE_STATE_IOMISC     IoMisc;
    368   EFI_SMM_SAVE_STATE_IO_INFO  *IoInfo;
    369   VOID                        *IoMemAddr;
    370 
    371   //
    372   // Check for special EFI_SMM_SAVE_STATE_REGISTER_LMA
    373   //
    374   if (Register == EFI_SMM_SAVE_STATE_REGISTER_LMA) {
    375     //
    376     // Only byte access is supported for this register
    377     //
    378     if (Width != 1) {
    379       return EFI_INVALID_PARAMETER;
    380     }
    381 
    382     *(UINT8 *)Buffer = mSmmSaveStateRegisterLma;
    383 
    384     return EFI_SUCCESS;
    385   }
    386 
    387   //
    388   // Check for special EFI_SMM_SAVE_STATE_REGISTER_IO
    389   //
    390   if (Register == EFI_SMM_SAVE_STATE_REGISTER_IO) {
    391     //
    392     // Get SMM Revision ID
    393     //
    394     ReadSaveStateRegisterByIndex (CpuIndex, SMM_SAVE_STATE_REGISTER_SMMREVID_INDEX, sizeof(SmmRevId), &SmmRevId);
    395 
    396     //
    397     // See if the CPU supports the IOMisc register in the save state
    398     //
    399     if (SmmRevId < SMRAM_SAVE_STATE_MIN_REV_ID_IOMISC) {
    400       return EFI_NOT_FOUND;
    401     }
    402 
    403     //
    404     // Get the IOMisc register value
    405     //
    406     ReadSaveStateRegisterByIndex (CpuIndex, SMM_SAVE_STATE_REGISTER_IOMISC_INDEX, sizeof(IoMisc.Uint32), &IoMisc.Uint32);
    407 
    408     //
    409     // Check for the SMI_FLAG in IOMisc
    410     //
    411     if (IoMisc.Bits.SmiFlag == 0) {
    412       return EFI_NOT_FOUND;
    413     }
    414 
    415     //
    416     // Compute index for the I/O Length and I/O Type lookup tables
    417     //
    418     if (mSmmCpuIoWidth[IoMisc.Bits.Length].Width == 0 || mSmmCpuIoType[IoMisc.Bits.Type] == 0) {
    419       return EFI_NOT_FOUND;
    420     }
    421 
    422     //
    423     // Zero the IoInfo structure that will be returned in Buffer
    424     //
    425     IoInfo = (EFI_SMM_SAVE_STATE_IO_INFO *)Buffer;
    426     ZeroMem (IoInfo, sizeof(EFI_SMM_SAVE_STATE_IO_INFO));
    427 
    428     //
    429     // Use lookup tables to help fill in all the fields of the IoInfo structure
    430     //
    431     IoInfo->IoPort = (UINT16)IoMisc.Bits.Port;
    432     IoInfo->IoWidth = mSmmCpuIoWidth[IoMisc.Bits.Length].IoWidth;
    433     IoInfo->IoType = mSmmCpuIoType[IoMisc.Bits.Type];
    434     if (IoInfo->IoType == EFI_SMM_SAVE_STATE_IO_TYPE_INPUT || IoInfo->IoType == EFI_SMM_SAVE_STATE_IO_TYPE_OUTPUT) {
    435       ReadSaveStateRegister (CpuIndex, EFI_SMM_SAVE_STATE_REGISTER_RAX, mSmmCpuIoWidth[IoMisc.Bits.Length].Width, &IoInfo->IoData);
    436     }
    437     else {
    438       ReadSaveStateRegisterByIndex(CpuIndex, SMM_SAVE_STATE_REGISTER_IOMEMADDR_INDEX, sizeof(IoMemAddr), &IoMemAddr);
    439       CopyMem(&IoInfo->IoData, IoMemAddr, mSmmCpuIoWidth[IoMisc.Bits.Length].Width);
    440     }
    441     return EFI_SUCCESS;
    442   }
    443 
    444   //
    445   // Convert Register to a register lookup table index
    446   //
    447   return ReadSaveStateRegisterByIndex (CpuIndex, GetRegisterIndex (Register), Width, Buffer);
    448 }
    449 
    450 /**
    451   Write value to a CPU Save State register on the target processor.
    452 
    453   This function abstracts the differences that whether the CPU Save State register is in the
    454   IA32 CPU Save State Map or X64 CPU Save State Map.
    455 
    456   This function supports writing a CPU Save State register in SMBase relocation handler.
    457 
    458   @param[in] CpuIndex       Specifies the zero-based index of the CPU save state.
    459   @param[in] RegisterIndex  Index into mSmmCpuWidthOffset[] look up table.
    460   @param[in] Width          The number of bytes to read from the CPU save state.
    461   @param[in] Buffer         Upon entry, this holds the new CPU register value.
    462 
    463   @retval EFI_SUCCESS           The register was written to Save State.
    464   @retval EFI_NOT_FOUND         The register is not defined for the Save State of Processor.
    465   @retval EFI_INVALID_PARAMTER  ProcessorIndex or Width is not correct.
    466 
    467 **/
    468 EFI_STATUS
    469 EFIAPI
    470 WriteSaveStateRegister (
    471   IN UINTN                        CpuIndex,
    472   IN EFI_SMM_SAVE_STATE_REGISTER  Register,
    473   IN UINTN                        Width,
    474   IN CONST VOID                   *Buffer
    475   )
    476 {
    477   UINTN                 RegisterIndex;
    478   SMRAM_SAVE_STATE_MAP  *CpuSaveState;
    479 
    480   //
    481   // Writes to EFI_SMM_SAVE_STATE_REGISTER_LMA are ignored
    482   //
    483   if (Register == EFI_SMM_SAVE_STATE_REGISTER_LMA) {
    484     return EFI_SUCCESS;
    485   }
    486 
    487   //
    488   // Writes to EFI_SMM_SAVE_STATE_REGISTER_IO are not supported
    489   //
    490   if (Register == EFI_SMM_SAVE_STATE_REGISTER_IO) {
    491     return EFI_NOT_FOUND;
    492   }
    493 
    494   //
    495   // Convert Register to a register lookup table index
    496   //
    497   RegisterIndex = GetRegisterIndex (Register);
    498   if (RegisterIndex == 0) {
    499     return EFI_NOT_FOUND;
    500   }
    501 
    502   CpuSaveState = gSmst->CpuSaveState[CpuIndex];
    503 
    504   //
    505   // Do not write non-writable SaveState, because it will cause exception.
    506   //
    507   if (!mSmmCpuWidthOffset[RegisterIndex].Writeable) {
    508     return EFI_UNSUPPORTED;
    509   }
    510 
    511   //
    512   // Check CPU mode
    513   //
    514   if (mSmmSaveStateRegisterLma == EFI_SMM_SAVE_STATE_REGISTER_LMA_32BIT) {
    515     //
    516     // If 32-bit mode width is zero, then the specified register can not be accessed
    517     //
    518     if (mSmmCpuWidthOffset[RegisterIndex].Width32 == 0) {
    519       return EFI_NOT_FOUND;
    520     }
    521 
    522     //
    523     // If Width is bigger than the 32-bit mode width, then the specified register can not be accessed
    524     //
    525     if (Width > mSmmCpuWidthOffset[RegisterIndex].Width32) {
    526       return EFI_INVALID_PARAMETER;
    527     }
    528     //
    529     // Write SMM State register
    530     //
    531     ASSERT (CpuSaveState != NULL);
    532     CopyMem((UINT8 *)CpuSaveState + mSmmCpuWidthOffset[RegisterIndex].Offset32, Buffer, Width);
    533   } else {
    534     //
    535     // If 64-bit mode width is zero, then the specified register can not be accessed
    536     //
    537     if (mSmmCpuWidthOffset[RegisterIndex].Width64 == 0) {
    538       return EFI_NOT_FOUND;
    539     }
    540 
    541     //
    542     // If Width is bigger than the 64-bit mode width, then the specified register can not be accessed
    543     //
    544     if (Width > mSmmCpuWidthOffset[RegisterIndex].Width64) {
    545       return EFI_INVALID_PARAMETER;
    546     }
    547 
    548     //
    549     // Write lower 32-bits of SMM State register
    550     //
    551     CopyMem((UINT8 *)CpuSaveState + mSmmCpuWidthOffset[RegisterIndex].Offset64Lo, Buffer, MIN (4, Width));
    552     if (Width >= 4) {
    553       //
    554       // Write upper 32-bits of SMM State register
    555       //
    556       CopyMem((UINT8 *)CpuSaveState + mSmmCpuWidthOffset[RegisterIndex].Offset64Hi, (UINT8 *)Buffer + 4, Width - 4);
    557     }
    558   }
    559   return EFI_SUCCESS;
    560 }
    561 
    562 /**
    563   Hook the code executed immediately after an RSM instruction on the currently
    564   executing CPU.  The mode of code executed immediately after RSM must be
    565   detected, and the appropriate hook must be selected.  Always clear the auto
    566   HALT restart flag if it is set.
    567 
    568   @param[in] CpuIndex                 The processor index for the currently
    569                                       executing CPU.
    570   @param[in] CpuState                 Pointer to SMRAM Save State Map for the
    571                                       currently executing CPU.
    572   @param[in] NewInstructionPointer32  Instruction pointer to use if resuming to
    573                                       32-bit mode from 64-bit SMM.
    574   @param[in] NewInstructionPointer    Instruction pointer to use if resuming to
    575                                       same mode as SMM.
    576 
    577   @retval The value of the original instruction pointer before it was hooked.
    578 
    579 **/
    580 UINT64
    581 EFIAPI
    582 HookReturnFromSmm (
    583   IN UINTN              CpuIndex,
    584   SMRAM_SAVE_STATE_MAP  *CpuState,
    585   UINT64                NewInstructionPointer32,
    586   UINT64                NewInstructionPointer
    587   )
    588 {
    589   UINT64  OriginalInstructionPointer;
    590 
    591   OriginalInstructionPointer = SmmCpuFeaturesHookReturnFromSmm (
    592                                  CpuIndex,
    593                                  CpuState,
    594                                  NewInstructionPointer32,
    595                                  NewInstructionPointer
    596                                  );
    597   if (OriginalInstructionPointer != 0) {
    598     return OriginalInstructionPointer;
    599   }
    600 
    601   if (mSmmSaveStateRegisterLma == EFI_SMM_SAVE_STATE_REGISTER_LMA_32BIT) {
    602     OriginalInstructionPointer = (UINT64)CpuState->x86._EIP;
    603     CpuState->x86._EIP = (UINT32)NewInstructionPointer;
    604     //
    605     // Clear the auto HALT restart flag so the RSM instruction returns
    606     // program control to the instruction following the HLT instruction.
    607     //
    608     if ((CpuState->x86.AutoHALTRestart & BIT0) != 0) {
    609       CpuState->x86.AutoHALTRestart &= ~BIT0;
    610     }
    611   } else {
    612     OriginalInstructionPointer = CpuState->x64._RIP;
    613     if ((CpuState->x64.IA32_EFER & LMA) == 0) {
    614       CpuState->x64._RIP = (UINT32)NewInstructionPointer32;
    615     } else {
    616       CpuState->x64._RIP = (UINT32)NewInstructionPointer;
    617     }
    618     //
    619     // Clear the auto HALT restart flag so the RSM instruction returns
    620     // program control to the instruction following the HLT instruction.
    621     //
    622     if ((CpuState->x64.AutoHALTRestart & BIT0) != 0) {
    623       CpuState->x64.AutoHALTRestart &= ~BIT0;
    624     }
    625   }
    626   return OriginalInstructionPointer;
    627 }
    628 
    629 /**
    630   Get the size of the SMI Handler in bytes.
    631 
    632   @retval The size, in bytes, of the SMI Handler.
    633 
    634 **/
    635 UINTN
    636 EFIAPI
    637 GetSmiHandlerSize (
    638   VOID
    639   )
    640 {
    641   UINTN  Size;
    642 
    643   Size = SmmCpuFeaturesGetSmiHandlerSize ();
    644   if (Size != 0) {
    645     return Size;
    646   }
    647   return gcSmiHandlerSize;
    648 }
    649 
    650 /**
    651   Install the SMI handler for the CPU specified by CpuIndex.  This function
    652   is called by the CPU that was elected as monarch during System Management
    653   Mode initialization.
    654 
    655   @param[in] CpuIndex   The index of the CPU to install the custom SMI handler.
    656                         The value must be between 0 and the NumberOfCpus field
    657                         in the System Management System Table (SMST).
    658   @param[in] SmBase     The SMBASE address for the CPU specified by CpuIndex.
    659   @param[in] SmiStack   The stack to use when an SMI is processed by the
    660                         the CPU specified by CpuIndex.
    661   @param[in] StackSize  The size, in bytes, if the stack used when an SMI is
    662                         processed by the CPU specified by CpuIndex.
    663   @param[in] GdtBase    The base address of the GDT to use when an SMI is
    664                         processed by the CPU specified by CpuIndex.
    665   @param[in] GdtSize    The size, in bytes, of the GDT used when an SMI is
    666                         processed by the CPU specified by CpuIndex.
    667   @param[in] IdtBase    The base address of the IDT to use when an SMI is
    668                         processed by the CPU specified by CpuIndex.
    669   @param[in] IdtSize    The size, in bytes, of the IDT used when an SMI is
    670                         processed by the CPU specified by CpuIndex.
    671   @param[in] Cr3        The base address of the page tables to use when an SMI
    672                         is processed by the CPU specified by CpuIndex.
    673 **/
    674 VOID
    675 EFIAPI
    676 InstallSmiHandler (
    677   IN UINTN   CpuIndex,
    678   IN UINT32  SmBase,
    679   IN VOID    *SmiStack,
    680   IN UINTN   StackSize,
    681   IN UINTN   GdtBase,
    682   IN UINTN   GdtSize,
    683   IN UINTN   IdtBase,
    684   IN UINTN   IdtSize,
    685   IN UINT32  Cr3
    686   )
    687 {
    688   PROCESSOR_SMM_DESCRIPTOR  *Psd;
    689 
    690   //
    691   // Initialize PROCESSOR_SMM_DESCRIPTOR
    692   //
    693   Psd = (PROCESSOR_SMM_DESCRIPTOR *)(VOID *)(UINTN)(SmBase + SMM_PSD_OFFSET);
    694   CopyMem (Psd, &gcPsd, sizeof (gcPsd));
    695   Psd->SmmGdtPtr = (UINT64)GdtBase;
    696   Psd->SmmGdtSize = (UINT32)GdtSize;
    697 
    698   if (SmmCpuFeaturesGetSmiHandlerSize () != 0) {
    699     //
    700     // Install SMI handler provided by library
    701     //
    702     SmmCpuFeaturesInstallSmiHandler (
    703       CpuIndex,
    704       SmBase,
    705       SmiStack,
    706       StackSize,
    707       GdtBase,
    708       GdtSize,
    709       IdtBase,
    710       IdtSize,
    711       Cr3
    712       );
    713     return;
    714   }
    715 
    716   //
    717   // Initialize values in template before copy
    718   //
    719   gSmiStack             = (UINT32)((UINTN)SmiStack + StackSize - sizeof (UINTN));
    720   gSmiCr3               = Cr3;
    721   gSmbase               = SmBase;
    722   gSmiHandlerIdtr.Base  = IdtBase;
    723   gSmiHandlerIdtr.Limit = (UINT16)(IdtSize - 1);
    724 
    725   //
    726   // Set the value at the top of the CPU stack to the CPU Index
    727   //
    728   *(UINTN*)(UINTN)gSmiStack = CpuIndex;
    729 
    730   //
    731   // Copy template to CPU specific SMI handler location
    732   //
    733   CopyMem (
    734     (VOID*)(UINTN)(SmBase + SMM_HANDLER_OFFSET),
    735     (VOID*)gcSmiHandlerTemplate,
    736     gcSmiHandlerSize
    737     );
    738 }
    739