2 Provides services to access SMRAM Save State Map
4 Copyright (c) 2010 - 2015, 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
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.
17 #include <Library/SmmCpuFeaturesLib.h>
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>
27 // EFER register LMA bit
32 /// Macro used to simplify the lookup table entries of type CPU_SMM_SAVE_STATE_LOOKUP_ENTRY
34 #define SMM_CPU_OFFSET(Field) OFFSET_OF (SMRAM_SAVE_STATE_MAP, Field)
37 /// Macro used to simplify the lookup table entries of type CPU_SMM_SAVE_STATE_REGISTER_RANGE
39 #define SMM_REGISTER_RANGE(Start, End) { Start, End, End - Start + 1 }
42 /// Structure used to describe a range of registers
45 EFI_SMM_SAVE_STATE_REGISTER Start
;
46 EFI_SMM_SAVE_STATE_REGISTER End
;
48 } CPU_SMM_SAVE_STATE_REGISTER_RANGE
;
51 /// Structure used to build a lookup table to retrieve the widths and offsets
52 /// associated with each supported EFI_SMM_SAVE_STATE_REGISTER value
55 #define SMM_SAVE_STATE_REGISTER_SMMREVID_INDEX 1
56 #define SMM_SAVE_STATE_REGISTER_IOMISC_INDEX 2
57 #define SMM_SAVE_STATE_REGISTER_IOMEMADDR_INDEX 3
58 #define SMM_SAVE_STATE_REGISTER_MAX_INDEX 4
67 } CPU_SMM_SAVE_STATE_LOOKUP_ENTRY
;
70 /// Structure used to build a lookup table for the IOMisc width information
74 EFI_SMM_SAVE_STATE_IO_WIDTH IoWidth
;
75 } CPU_SMM_SAVE_STATE_IO_WIDTH
;
78 /// Variables from SMI Handler
80 extern UINT32 gSmbase
;
81 extern volatile UINT32 gSmiStack
;
82 extern UINT32 gSmiCr3
;
83 extern volatile UINT8 gcSmiHandlerTemplate
[];
84 extern CONST UINT16 gcSmiHandlerSize
;
87 // Variables used by SMI Handler
89 IA32_DESCRIPTOR gSmiHandlerIdtr
;
92 /// Table used by GetRegisterIndex() to convert an EFI_SMM_SAVE_STATE_REGISTER
93 /// value to an index into a table of type CPU_SMM_SAVE_STATE_LOOKUP_ENTRY
95 CONST CPU_SMM_SAVE_STATE_REGISTER_RANGE mSmmCpuRegisterRanges
[] = {
96 SMM_REGISTER_RANGE (EFI_SMM_SAVE_STATE_REGISTER_GDTBASE
, EFI_SMM_SAVE_STATE_REGISTER_LDTINFO
),
97 SMM_REGISTER_RANGE (EFI_SMM_SAVE_STATE_REGISTER_ES
, EFI_SMM_SAVE_STATE_REGISTER_RIP
),
98 SMM_REGISTER_RANGE (EFI_SMM_SAVE_STATE_REGISTER_RFLAGS
, EFI_SMM_SAVE_STATE_REGISTER_CR4
),
99 { (EFI_SMM_SAVE_STATE_REGISTER
)0, (EFI_SMM_SAVE_STATE_REGISTER
)0, 0 }
103 /// Lookup table used to retrieve the widths and offsets associated with each
104 /// supported EFI_SMM_SAVE_STATE_REGISTER value
106 CONST CPU_SMM_SAVE_STATE_LOOKUP_ENTRY mSmmCpuWidthOffset
[] = {
107 {0, 0, 0, 0, 0, FALSE
}, // Reserved
110 // Internally defined CPU Save State Registers. Not defined in PI SMM CPU Protocol.
112 {4, 4, SMM_CPU_OFFSET (x86
.SMMRevId
) , SMM_CPU_OFFSET (x64
.SMMRevId
) , 0 , FALSE
}, // SMM_SAVE_STATE_REGISTER_SMMREVID_INDEX = 1
113 {4, 4, SMM_CPU_OFFSET (x86
.IOMisc
) , SMM_CPU_OFFSET (x64
.IOMisc
) , 0 , FALSE
}, // SMM_SAVE_STATE_REGISTER_IOMISC_INDEX = 2
114 {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
117 // CPU Save State registers defined in PI SMM CPU Protocol.
119 {0, 8, 0 , SMM_CPU_OFFSET (x64
.GdtBaseLoDword
) , SMM_CPU_OFFSET (x64
.GdtBaseHiDword
), FALSE
}, // EFI_SMM_SAVE_STATE_REGISTER_GDTBASE = 4
120 {0, 8, 0 , SMM_CPU_OFFSET (x64
.IdtBaseLoDword
) , SMM_CPU_OFFSET (x64
.IdtBaseHiDword
), FALSE
}, // EFI_SMM_SAVE_STATE_REGISTER_IDTBASE = 5
121 {0, 8, 0 , SMM_CPU_OFFSET (x64
.LdtBaseLoDword
) , SMM_CPU_OFFSET (x64
.LdtBaseHiDword
), FALSE
}, // EFI_SMM_SAVE_STATE_REGISTER_LDTBASE = 6
122 {0, 0, 0 , 0 , 0 , FALSE
}, // EFI_SMM_SAVE_STATE_REGISTER_GDTLIMIT = 7
123 {0, 0, 0 , 0 , 0 , FALSE
}, // EFI_SMM_SAVE_STATE_REGISTER_IDTLIMIT = 8
124 {0, 0, 0 , 0 , 0 , FALSE
}, // EFI_SMM_SAVE_STATE_REGISTER_LDTLIMIT = 9
125 {0, 0, 0 , 0 , 0 , FALSE
}, // EFI_SMM_SAVE_STATE_REGISTER_LDTINFO = 10
127 {4, 4, SMM_CPU_OFFSET (x86
._ES
) , SMM_CPU_OFFSET (x64
._ES
) , 0 , FALSE
}, // EFI_SMM_SAVE_STATE_REGISTER_ES = 20
128 {4, 4, SMM_CPU_OFFSET (x86
._CS
) , SMM_CPU_OFFSET (x64
._CS
) , 0 , FALSE
}, // EFI_SMM_SAVE_STATE_REGISTER_CS = 21
129 {4, 4, SMM_CPU_OFFSET (x86
._SS
) , SMM_CPU_OFFSET (x64
._SS
) , 0 , FALSE
}, // EFI_SMM_SAVE_STATE_REGISTER_SS = 22
130 {4, 4, SMM_CPU_OFFSET (x86
._DS
) , SMM_CPU_OFFSET (x64
._DS
) , 0 , FALSE
}, // EFI_SMM_SAVE_STATE_REGISTER_DS = 23
131 {4, 4, SMM_CPU_OFFSET (x86
._FS
) , SMM_CPU_OFFSET (x64
._FS
) , 0 , FALSE
}, // EFI_SMM_SAVE_STATE_REGISTER_FS = 24
132 {4, 4, SMM_CPU_OFFSET (x86
._GS
) , SMM_CPU_OFFSET (x64
._GS
) , 0 , FALSE
}, // EFI_SMM_SAVE_STATE_REGISTER_GS = 25
133 {0, 4, 0 , SMM_CPU_OFFSET (x64
._LDTR
) , 0 , FALSE
}, // EFI_SMM_SAVE_STATE_REGISTER_LDTR_SEL = 26
134 {4, 4, SMM_CPU_OFFSET (x86
._TR
) , SMM_CPU_OFFSET (x64
._TR
) , 0 , FALSE
}, // EFI_SMM_SAVE_STATE_REGISTER_TR_SEL = 27
135 {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
136 {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
137 {0, 8, 0 , SMM_CPU_OFFSET (x64
._R8
) , SMM_CPU_OFFSET (x64
._R8
) + 4, TRUE
}, // EFI_SMM_SAVE_STATE_REGISTER_R8 = 30
138 {0, 8, 0 , SMM_CPU_OFFSET (x64
._R9
) , SMM_CPU_OFFSET (x64
._R9
) + 4, TRUE
}, // EFI_SMM_SAVE_STATE_REGISTER_R9 = 31
139 {0, 8, 0 , SMM_CPU_OFFSET (x64
._R10
) , SMM_CPU_OFFSET (x64
._R10
) + 4, TRUE
}, // EFI_SMM_SAVE_STATE_REGISTER_R10 = 32
140 {0, 8, 0 , SMM_CPU_OFFSET (x64
._R11
) , SMM_CPU_OFFSET (x64
._R11
) + 4, TRUE
}, // EFI_SMM_SAVE_STATE_REGISTER_R11 = 33
141 {0, 8, 0 , SMM_CPU_OFFSET (x64
._R12
) , SMM_CPU_OFFSET (x64
._R12
) + 4, TRUE
}, // EFI_SMM_SAVE_STATE_REGISTER_R12 = 34
142 {0, 8, 0 , SMM_CPU_OFFSET (x64
._R13
) , SMM_CPU_OFFSET (x64
._R13
) + 4, TRUE
}, // EFI_SMM_SAVE_STATE_REGISTER_R13 = 35
143 {0, 8, 0 , SMM_CPU_OFFSET (x64
._R14
) , SMM_CPU_OFFSET (x64
._R14
) + 4, TRUE
}, // EFI_SMM_SAVE_STATE_REGISTER_R14 = 36
144 {0, 8, 0 , SMM_CPU_OFFSET (x64
._R15
) , SMM_CPU_OFFSET (x64
._R15
) + 4, TRUE
}, // EFI_SMM_SAVE_STATE_REGISTER_R15 = 37
145 {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
146 {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
147 {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
148 {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
149 {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
150 {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
151 {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
152 {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
153 {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
155 {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
156 {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
157 {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
158 {0, 4, 0 , SMM_CPU_OFFSET (x64
._CR4
) , 0 , FALSE
}, // EFI_SMM_SAVE_STATE_REGISTER_CR4 = 54
162 /// Lookup table for the IOMisc width information
164 CONST CPU_SMM_SAVE_STATE_IO_WIDTH mSmmCpuIoWidth
[] = {
165 { 0, EFI_SMM_SAVE_STATE_IO_WIDTH_UINT8
}, // Undefined = 0
166 { 1, EFI_SMM_SAVE_STATE_IO_WIDTH_UINT8
}, // SMM_IO_LENGTH_BYTE = 1
167 { 2, EFI_SMM_SAVE_STATE_IO_WIDTH_UINT16
}, // SMM_IO_LENGTH_WORD = 2
168 { 0, EFI_SMM_SAVE_STATE_IO_WIDTH_UINT8
}, // Undefined = 3
169 { 4, EFI_SMM_SAVE_STATE_IO_WIDTH_UINT32
}, // SMM_IO_LENGTH_DWORD = 4
170 { 0, EFI_SMM_SAVE_STATE_IO_WIDTH_UINT8
}, // Undefined = 5
171 { 0, EFI_SMM_SAVE_STATE_IO_WIDTH_UINT8
}, // Undefined = 6
172 { 0, EFI_SMM_SAVE_STATE_IO_WIDTH_UINT8
} // Undefined = 7
176 /// Lookup table for the IOMisc type information
178 CONST EFI_SMM_SAVE_STATE_IO_TYPE mSmmCpuIoType
[] = {
179 EFI_SMM_SAVE_STATE_IO_TYPE_OUTPUT
, // SMM_IO_TYPE_OUT_DX = 0
180 EFI_SMM_SAVE_STATE_IO_TYPE_INPUT
, // SMM_IO_TYPE_IN_DX = 1
181 EFI_SMM_SAVE_STATE_IO_TYPE_STRING
, // SMM_IO_TYPE_OUTS = 2
182 EFI_SMM_SAVE_STATE_IO_TYPE_STRING
, // SMM_IO_TYPE_INS = 3
183 (EFI_SMM_SAVE_STATE_IO_TYPE
)0, // Undefined = 4
184 (EFI_SMM_SAVE_STATE_IO_TYPE
)0, // Undefined = 5
185 EFI_SMM_SAVE_STATE_IO_TYPE_REP_PREFIX
, // SMM_IO_TYPE_REP_OUTS = 6
186 EFI_SMM_SAVE_STATE_IO_TYPE_REP_PREFIX
, // SMM_IO_TYPE_REP_INS = 7
187 EFI_SMM_SAVE_STATE_IO_TYPE_OUTPUT
, // SMM_IO_TYPE_OUT_IMMEDIATE = 8
188 EFI_SMM_SAVE_STATE_IO_TYPE_INPUT
, // SMM_IO_TYPE_OUT_IMMEDIATE = 9
189 (EFI_SMM_SAVE_STATE_IO_TYPE
)0, // Undefined = 10
190 (EFI_SMM_SAVE_STATE_IO_TYPE
)0, // Undefined = 11
191 (EFI_SMM_SAVE_STATE_IO_TYPE
)0, // Undefined = 12
192 (EFI_SMM_SAVE_STATE_IO_TYPE
)0, // Undefined = 13
193 (EFI_SMM_SAVE_STATE_IO_TYPE
)0, // Undefined = 14
194 (EFI_SMM_SAVE_STATE_IO_TYPE
)0 // Undefined = 15
198 /// The mode of the CPU at the time an SMI occurs
200 UINT8 mSmmSaveStateRegisterLma
;
203 Read information from the CPU save state.
205 @param Register Specifies the CPU register to read form the save state.
207 @retval 0 Register is not valid
208 @retval >0 Index into mSmmCpuWidthOffset[] associated with Register
213 IN EFI_SMM_SAVE_STATE_REGISTER Register
219 for (Index
= 0, Offset
= SMM_SAVE_STATE_REGISTER_MAX_INDEX
; mSmmCpuRegisterRanges
[Index
].Length
!= 0; Index
++) {
220 if (Register
>= mSmmCpuRegisterRanges
[Index
].Start
&& Register
<= mSmmCpuRegisterRanges
[Index
].End
) {
221 return Register
- mSmmCpuRegisterRanges
[Index
].Start
+ Offset
;
223 Offset
+= mSmmCpuRegisterRanges
[Index
].Length
;
229 Read a CPU Save State register on the target processor.
231 This function abstracts the differences that whether the CPU Save State register is in the
232 IA32 CPU Save State Map or X64 CPU Save State Map.
234 This function supports reading a CPU Save State register in SMBase relocation handler.
236 @param[in] CpuIndex Specifies the zero-based index of the CPU save state.
237 @param[in] RegisterIndex Index into mSmmCpuWidthOffset[] look up table.
238 @param[in] Width The number of bytes to read from the CPU save state.
239 @param[out] Buffer Upon return, this holds the CPU register value read from the save state.
241 @retval EFI_SUCCESS The register was read from Save State.
242 @retval EFI_NOT_FOUND The register is not defined for the Save State of Processor.
243 @retval EFI_INVALID_PARAMTER This or Buffer is NULL.
247 ReadSaveStateRegisterByIndex (
249 IN UINTN RegisterIndex
,
254 SMRAM_SAVE_STATE_MAP
*CpuSaveState
;
256 if (RegisterIndex
== 0) {
257 return EFI_NOT_FOUND
;
260 CpuSaveState
= gSmst
->CpuSaveState
[CpuIndex
];
262 if (mSmmSaveStateRegisterLma
== EFI_SMM_SAVE_STATE_REGISTER_LMA_32BIT
) {
264 // If 32-bit mode width is zero, then the specified register can not be accessed
266 if (mSmmCpuWidthOffset
[RegisterIndex
].Width32
== 0) {
267 return EFI_NOT_FOUND
;
271 // If Width is bigger than the 32-bit mode width, then the specified register can not be accessed
273 if (Width
> mSmmCpuWidthOffset
[RegisterIndex
].Width32
) {
274 return EFI_INVALID_PARAMETER
;
278 // Write return buffer
280 ASSERT(CpuSaveState
!= NULL
);
281 CopyMem(Buffer
, (UINT8
*)CpuSaveState
+ mSmmCpuWidthOffset
[RegisterIndex
].Offset32
, Width
);
284 // If 64-bit mode width is zero, then the specified register can not be accessed
286 if (mSmmCpuWidthOffset
[RegisterIndex
].Width64
== 0) {
287 return EFI_NOT_FOUND
;
291 // If Width is bigger than the 64-bit mode width, then the specified register can not be accessed
293 if (Width
> mSmmCpuWidthOffset
[RegisterIndex
].Width64
) {
294 return EFI_INVALID_PARAMETER
;
298 // Write lower 32-bits of return buffer
300 CopyMem(Buffer
, (UINT8
*)CpuSaveState
+ mSmmCpuWidthOffset
[RegisterIndex
].Offset64Lo
, MIN(4, Width
));
303 // Write upper 32-bits of return buffer
305 CopyMem((UINT8
*)Buffer
+ 4, (UINT8
*)CpuSaveState
+ mSmmCpuWidthOffset
[RegisterIndex
].Offset64Hi
, Width
- 4);
312 Read a CPU Save State register on the target processor.
314 This function abstracts the differences that whether the CPU Save State register is in the
315 IA32 CPU Save State Map or X64 CPU Save State Map.
317 This function supports reading a CPU Save State register in SMBase relocation handler.
319 @param[in] CpuIndex Specifies the zero-based index of the CPU save state.
320 @param[in] RegisterIndex Index into mSmmCpuWidthOffset[] look up table.
321 @param[in] Width The number of bytes to read from the CPU save state.
322 @param[out] Buffer Upon return, this holds the CPU register value read from the save state.
324 @retval EFI_SUCCESS The register was read from Save State.
325 @retval EFI_NOT_FOUND The register is not defined for the Save State of Processor.
326 @retval EFI_INVALID_PARAMTER This or Buffer is NULL.
331 ReadSaveStateRegister (
333 IN EFI_SMM_SAVE_STATE_REGISTER Register
,
339 SMRAM_SAVE_STATE_IOMISC IoMisc
;
340 EFI_SMM_SAVE_STATE_IO_INFO
*IoInfo
;
344 // Check for special EFI_SMM_SAVE_STATE_REGISTER_LMA
346 if (Register
== EFI_SMM_SAVE_STATE_REGISTER_LMA
) {
348 // Only byte access is supported for this register
351 return EFI_INVALID_PARAMETER
;
354 *(UINT8
*)Buffer
= mSmmSaveStateRegisterLma
;
360 // Check for special EFI_SMM_SAVE_STATE_REGISTER_IO
362 if (Register
== EFI_SMM_SAVE_STATE_REGISTER_IO
) {
364 // Get SMM Revision ID
366 ReadSaveStateRegisterByIndex (CpuIndex
, SMM_SAVE_STATE_REGISTER_SMMREVID_INDEX
, sizeof(SmmRevId
), &SmmRevId
);
369 // See if the CPU supports the IOMisc register in the save state
371 if (SmmRevId
< SMRAM_SAVE_STATE_MIN_REV_ID_IOMISC
) {
372 return EFI_NOT_FOUND
;
376 // Get the IOMisc register value
378 ReadSaveStateRegisterByIndex (CpuIndex
, SMM_SAVE_STATE_REGISTER_IOMISC_INDEX
, sizeof(IoMisc
.Uint32
), &IoMisc
.Uint32
);
381 // Check for the SMI_FLAG in IOMisc
383 if (IoMisc
.Bits
.SmiFlag
== 0) {
384 return EFI_NOT_FOUND
;
388 // Compute index for the I/O Length and I/O Type lookup tables
390 if (mSmmCpuIoWidth
[IoMisc
.Bits
.Length
].Width
== 0 || mSmmCpuIoType
[IoMisc
.Bits
.Type
] == 0) {
391 return EFI_NOT_FOUND
;
395 // Zero the IoInfo structure that will be returned in Buffer
397 IoInfo
= (EFI_SMM_SAVE_STATE_IO_INFO
*)Buffer
;
398 ZeroMem (IoInfo
, sizeof(EFI_SMM_SAVE_STATE_IO_INFO
));
401 // Use lookup tables to help fill in all the fields of the IoInfo structure
403 IoInfo
->IoPort
= (UINT16
)IoMisc
.Bits
.Port
;
404 IoInfo
->IoWidth
= mSmmCpuIoWidth
[IoMisc
.Bits
.Length
].IoWidth
;
405 IoInfo
->IoType
= mSmmCpuIoType
[IoMisc
.Bits
.Type
];
406 if (IoInfo
->IoType
== EFI_SMM_SAVE_STATE_IO_TYPE_INPUT
|| IoInfo
->IoType
== EFI_SMM_SAVE_STATE_IO_TYPE_OUTPUT
) {
407 ReadSaveStateRegister (CpuIndex
, EFI_SMM_SAVE_STATE_REGISTER_RAX
, mSmmCpuIoWidth
[IoMisc
.Bits
.Length
].Width
, &IoInfo
->IoData
);
410 ReadSaveStateRegisterByIndex(CpuIndex
, SMM_SAVE_STATE_REGISTER_IOMEMADDR_INDEX
, sizeof(IoMemAddr
), &IoMemAddr
);
411 CopyMem(&IoInfo
->IoData
, IoMemAddr
, mSmmCpuIoWidth
[IoMisc
.Bits
.Length
].Width
);
417 // Convert Register to a register lookup table index
419 return ReadSaveStateRegisterByIndex (CpuIndex
, GetRegisterIndex (Register
), Width
, Buffer
);
423 Write value to a CPU Save State register on the target processor.
425 This function abstracts the differences that whether the CPU Save State register is in the
426 IA32 CPU Save State Map or X64 CPU Save State Map.
428 This function supports writing a CPU Save State register in SMBase relocation handler.
430 @param[in] CpuIndex Specifies the zero-based index of the CPU save state.
431 @param[in] RegisterIndex Index into mSmmCpuWidthOffset[] look up table.
432 @param[in] Width The number of bytes to read from the CPU save state.
433 @param[in] Buffer Upon entry, this holds the new CPU register value.
435 @retval EFI_SUCCESS The register was written to Save State.
436 @retval EFI_NOT_FOUND The register is not defined for the Save State of Processor.
437 @retval EFI_INVALID_PARAMTER ProcessorIndex or Width is not correct.
442 WriteSaveStateRegister (
444 IN EFI_SMM_SAVE_STATE_REGISTER Register
,
446 IN CONST VOID
*Buffer
450 SMRAM_SAVE_STATE_MAP
*CpuSaveState
;
453 // Writes to EFI_SMM_SAVE_STATE_REGISTER_LMA are ignored
455 if (Register
== EFI_SMM_SAVE_STATE_REGISTER_LMA
) {
460 // Writes to EFI_SMM_SAVE_STATE_REGISTER_IO are not supported
462 if (Register
== EFI_SMM_SAVE_STATE_REGISTER_IO
) {
463 return EFI_NOT_FOUND
;
467 // Convert Register to a register lookup table index
469 RegisterIndex
= GetRegisterIndex (Register
);
470 if (RegisterIndex
== 0) {
471 return EFI_NOT_FOUND
;
474 CpuSaveState
= gSmst
->CpuSaveState
[CpuIndex
];
477 // Do not write non-writable SaveState, because it will cause exception.
479 if (!mSmmCpuWidthOffset
[RegisterIndex
].Writeable
) {
480 return EFI_UNSUPPORTED
;
486 if (mSmmSaveStateRegisterLma
== EFI_SMM_SAVE_STATE_REGISTER_LMA_32BIT
) {
488 // If 32-bit mode width is zero, then the specified register can not be accessed
490 if (mSmmCpuWidthOffset
[RegisterIndex
].Width32
== 0) {
491 return EFI_NOT_FOUND
;
495 // If Width is bigger than the 32-bit mode width, then the specified register can not be accessed
497 if (Width
> mSmmCpuWidthOffset
[RegisterIndex
].Width32
) {
498 return EFI_INVALID_PARAMETER
;
501 // Write SMM State register
503 ASSERT (CpuSaveState
!= NULL
);
504 CopyMem((UINT8
*)CpuSaveState
+ mSmmCpuWidthOffset
[RegisterIndex
].Offset32
, Buffer
, Width
);
507 // If 64-bit mode width is zero, then the specified register can not be accessed
509 if (mSmmCpuWidthOffset
[RegisterIndex
].Width64
== 0) {
510 return EFI_NOT_FOUND
;
514 // If Width is bigger than the 64-bit mode width, then the specified register can not be accessed
516 if (Width
> mSmmCpuWidthOffset
[RegisterIndex
].Width64
) {
517 return EFI_INVALID_PARAMETER
;
521 // Write lower 32-bits of SMM State register
523 CopyMem((UINT8
*)CpuSaveState
+ mSmmCpuWidthOffset
[RegisterIndex
].Offset64Lo
, Buffer
, MIN (4, Width
));
526 // Write upper 32-bits of SMM State register
528 CopyMem((UINT8
*)CpuSaveState
+ mSmmCpuWidthOffset
[RegisterIndex
].Offset64Hi
, (UINT8
*)Buffer
+ 4, Width
- 4);
535 Hook the code executed immediately after an RSM instruction on the currently
536 executing CPU. The mode of code executed immediately after RSM must be
537 detected, and the appropriate hook must be selected. Always clear the auto
538 HALT restart flag if it is set.
540 @param[in] CpuIndex The processor index for the currently
542 @param[in] CpuState Pointer to SMRAM Save State Map for the
543 currently executing CPU.
544 @param[in] NewInstructionPointer32 Instruction pointer to use if resuming to
545 32-bit mode from 64-bit SMM.
546 @param[in] NewInstructionPointer Instruction pointer to use if resuming to
549 @retval The value of the original instruction pointer before it was hooked.
556 SMRAM_SAVE_STATE_MAP
*CpuState
,
557 UINT64 NewInstructionPointer32
,
558 UINT64 NewInstructionPointer
561 UINT64 OriginalInstructionPointer
;
563 OriginalInstructionPointer
= SmmCpuFeaturesHookReturnFromSmm (
566 NewInstructionPointer32
,
567 NewInstructionPointer
569 if (OriginalInstructionPointer
!= 0) {
570 return OriginalInstructionPointer
;
573 if (mSmmSaveStateRegisterLma
== EFI_SMM_SAVE_STATE_REGISTER_LMA_32BIT
) {
574 OriginalInstructionPointer
= (UINT64
)CpuState
->x86
._EIP
;
575 CpuState
->x86
._EIP
= (UINT32
)NewInstructionPointer
;
577 // Clear the auto HALT restart flag so the RSM instruction returns
578 // program control to the instruction following the HLT instruction.
580 if ((CpuState
->x86
.AutoHALTRestart
& BIT0
) != 0) {
581 CpuState
->x86
.AutoHALTRestart
&= ~BIT0
;
584 OriginalInstructionPointer
= CpuState
->x64
._RIP
;
585 if ((CpuState
->x64
.IA32_EFER
& LMA
) == 0) {
586 CpuState
->x64
._RIP
= (UINT32
)NewInstructionPointer32
;
588 CpuState
->x64
._RIP
= (UINT32
)NewInstructionPointer
;
591 // Clear the auto HALT restart flag so the RSM instruction returns
592 // program control to the instruction following the HLT instruction.
594 if ((CpuState
->x64
.AutoHALTRestart
& BIT0
) != 0) {
595 CpuState
->x64
.AutoHALTRestart
&= ~BIT0
;
598 return OriginalInstructionPointer
;
602 Get the size of the SMI Handler in bytes.
604 @retval The size, in bytes, of the SMI Handler.
615 Size
= SmmCpuFeaturesGetSmiHandlerSize ();
619 return gcSmiHandlerSize
;
623 Install the SMI handler for the CPU specified by CpuIndex. This function
624 is called by the CPU that was elected as monarch during System Management
627 @param[in] CpuIndex The index of the CPU to install the custom SMI handler.
628 The value must be between 0 and the NumberOfCpus field
629 in the System Management System Table (SMST).
630 @param[in] SmBase The SMBASE address for the CPU specified by CpuIndex.
631 @param[in] SmiStack The stack to use when an SMI is processed by the
632 the CPU specified by CpuIndex.
633 @param[in] StackSize The size, in bytes, if the stack used when an SMI is
634 processed by the CPU specified by CpuIndex.
635 @param[in] GdtBase The base address of the GDT to use when an SMI is
636 processed by the CPU specified by CpuIndex.
637 @param[in] GdtSize The size, in bytes, of the GDT used when an SMI is
638 processed by the CPU specified by CpuIndex.
639 @param[in] IdtBase The base address of the IDT to use when an SMI is
640 processed by the CPU specified by CpuIndex.
641 @param[in] IdtSize The size, in bytes, of the IDT used when an SMI is
642 processed by the CPU specified by CpuIndex.
643 @param[in] Cr3 The base address of the page tables to use when an SMI
644 is processed by the CPU specified by CpuIndex.
660 if (SmmCpuFeaturesGetSmiHandlerSize () != 0) {
662 // Install SMI handler provided by library
664 SmmCpuFeaturesInstallSmiHandler (
679 // Initialize values in template before copy
681 gSmiStack
= (UINT32
)((UINTN
)SmiStack
+ StackSize
- sizeof (UINTN
));
684 gSmiHandlerIdtr
.Base
= IdtBase
;
685 gSmiHandlerIdtr
.Limit
= (UINT16
)(IdtSize
- 1);
688 // Set the value at the top of the CPU stack to the CPU Index
690 *(UINTN
*)(UINTN
)gSmiStack
= CpuIndex
;
693 // Copy template to CPU specific SMI handler location
696 (VOID
*)(UINTN
)(SmBase
+ SMM_HANDLER_OFFSET
),
697 (VOID
*)gcSmiHandlerTemplate
,