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