2 Provides services to access SMRAM Save State Map
4 Copyright (c) 2010 - 2019, Intel Corporation. All rights reserved.<BR>
5 SPDX-License-Identifier: BSD-2-Clause-Patent
11 #include <Library/SmmCpuFeaturesLib.h>
13 #include <Library/BaseLib.h>
14 #include <Library/BaseMemoryLib.h>
15 #include <Library/SmmServicesTableLib.h>
16 #include <Library/DebugLib.h>
17 #include <Register/Cpuid.h>
18 #include <Register/SmramSaveStateMap.h>
20 #include "PiSmmCpuDxeSmm.h"
23 UINT64 Signature
; // Offset 0x00
24 UINT16 Reserved1
; // Offset 0x08
25 UINT16 Reserved2
; // Offset 0x0A
26 UINT16 Reserved3
; // Offset 0x0C
27 UINT16 SmmCs
; // Offset 0x0E
28 UINT16 SmmDs
; // Offset 0x10
29 UINT16 SmmSs
; // Offset 0x12
30 UINT16 SmmOtherSegment
; // Offset 0x14
31 UINT16 Reserved4
; // Offset 0x16
32 UINT64 Reserved5
; // Offset 0x18
33 UINT64 Reserved6
; // Offset 0x20
34 UINT64 Reserved7
; // Offset 0x28
35 UINT64 SmmGdtPtr
; // Offset 0x30
36 UINT32 SmmGdtSize
; // Offset 0x38
37 UINT32 Reserved8
; // Offset 0x3C
38 UINT64 Reserved9
; // Offset 0x40
39 UINT64 Reserved10
; // Offset 0x48
40 UINT16 Reserved11
; // Offset 0x50
41 UINT16 Reserved12
; // Offset 0x52
42 UINT32 Reserved13
; // Offset 0x54
43 UINT64 Reserved14
; // Offset 0x58
44 } PROCESSOR_SMM_DESCRIPTOR
;
46 extern CONST PROCESSOR_SMM_DESCRIPTOR gcPsd
;
49 // EFER register LMA bit
54 /// Macro used to simplify the lookup table entries of type CPU_SMM_SAVE_STATE_LOOKUP_ENTRY
56 #define SMM_CPU_OFFSET(Field) OFFSET_OF (SMRAM_SAVE_STATE_MAP, Field)
59 /// Macro used to simplify the lookup table entries of type CPU_SMM_SAVE_STATE_REGISTER_RANGE
61 #define SMM_REGISTER_RANGE(Start, End) { Start, End, End - Start + 1 }
64 /// Structure used to describe a range of registers
67 EFI_SMM_SAVE_STATE_REGISTER Start
;
68 EFI_SMM_SAVE_STATE_REGISTER End
;
70 } CPU_SMM_SAVE_STATE_REGISTER_RANGE
;
73 /// Structure used to build a lookup table to retrieve the widths and offsets
74 /// associated with each supported EFI_SMM_SAVE_STATE_REGISTER value
77 #define SMM_SAVE_STATE_REGISTER_SMMREVID_INDEX 1
78 #define SMM_SAVE_STATE_REGISTER_IOMISC_INDEX 2
79 #define SMM_SAVE_STATE_REGISTER_IOMEMADDR_INDEX 3
80 #define SMM_SAVE_STATE_REGISTER_MAX_INDEX 4
89 } CPU_SMM_SAVE_STATE_LOOKUP_ENTRY
;
92 /// Structure used to build a lookup table for the IOMisc width information
96 EFI_SMM_SAVE_STATE_IO_WIDTH IoWidth
;
97 } CPU_SMM_SAVE_STATE_IO_WIDTH
;
100 /// Variables from SMI Handler
102 X86_ASSEMBLY_PATCH_LABEL gPatchSmbase
;
103 X86_ASSEMBLY_PATCH_LABEL gPatchSmiStack
;
104 X86_ASSEMBLY_PATCH_LABEL gPatchSmiCr3
;
105 extern volatile UINT8 gcSmiHandlerTemplate
[];
106 extern CONST UINT16 gcSmiHandlerSize
;
109 // Variables used by SMI Handler
111 IA32_DESCRIPTOR gSmiHandlerIdtr
;
114 /// Table used by GetRegisterIndex() to convert an EFI_SMM_SAVE_STATE_REGISTER
115 /// value to an index into a table of type CPU_SMM_SAVE_STATE_LOOKUP_ENTRY
117 CONST CPU_SMM_SAVE_STATE_REGISTER_RANGE mSmmCpuRegisterRanges
[] = {
118 SMM_REGISTER_RANGE (EFI_SMM_SAVE_STATE_REGISTER_GDTBASE
, EFI_SMM_SAVE_STATE_REGISTER_LDTINFO
),
119 SMM_REGISTER_RANGE (EFI_SMM_SAVE_STATE_REGISTER_ES
, EFI_SMM_SAVE_STATE_REGISTER_RIP
),
120 SMM_REGISTER_RANGE (EFI_SMM_SAVE_STATE_REGISTER_RFLAGS
, EFI_SMM_SAVE_STATE_REGISTER_CR4
),
121 { (EFI_SMM_SAVE_STATE_REGISTER
)0, (EFI_SMM_SAVE_STATE_REGISTER
)0, 0 }
125 /// Lookup table used to retrieve the widths and offsets associated with each
126 /// supported EFI_SMM_SAVE_STATE_REGISTER value
128 CONST CPU_SMM_SAVE_STATE_LOOKUP_ENTRY mSmmCpuWidthOffset
[] = {
129 {0, 0, 0, 0, 0, FALSE
}, // Reserved
132 // Internally defined CPU Save State Registers. Not defined in PI SMM CPU Protocol.
134 {4, 4, SMM_CPU_OFFSET (x86
.SMMRevId
) , SMM_CPU_OFFSET (x64
.SMMRevId
) , 0 , FALSE
}, // SMM_SAVE_STATE_REGISTER_SMMREVID_INDEX = 1
135 {4, 4, SMM_CPU_OFFSET (x86
.IOMisc
) , SMM_CPU_OFFSET (x64
.IOMisc
) , 0 , FALSE
}, // SMM_SAVE_STATE_REGISTER_IOMISC_INDEX = 2
136 {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
139 // CPU Save State registers defined in PI SMM CPU Protocol.
141 {0, 8, 0 , SMM_CPU_OFFSET (x64
.GdtBaseLoDword
) , SMM_CPU_OFFSET (x64
.GdtBaseHiDword
), FALSE
}, // EFI_SMM_SAVE_STATE_REGISTER_GDTBASE = 4
142 {0, 8, 0 , SMM_CPU_OFFSET (x64
.IdtBaseLoDword
) , SMM_CPU_OFFSET (x64
.IdtBaseHiDword
), FALSE
}, // EFI_SMM_SAVE_STATE_REGISTER_IDTBASE = 5
143 {0, 8, 0 , SMM_CPU_OFFSET (x64
.LdtBaseLoDword
) , SMM_CPU_OFFSET (x64
.LdtBaseHiDword
), FALSE
}, // EFI_SMM_SAVE_STATE_REGISTER_LDTBASE = 6
144 {0, 0, 0 , 0 , 0 , FALSE
}, // EFI_SMM_SAVE_STATE_REGISTER_GDTLIMIT = 7
145 {0, 0, 0 , 0 , 0 , FALSE
}, // EFI_SMM_SAVE_STATE_REGISTER_IDTLIMIT = 8
146 {0, 0, 0 , 0 , 0 , FALSE
}, // EFI_SMM_SAVE_STATE_REGISTER_LDTLIMIT = 9
147 {0, 0, 0 , 0 , 0 , FALSE
}, // EFI_SMM_SAVE_STATE_REGISTER_LDTINFO = 10
149 {4, 4, SMM_CPU_OFFSET (x86
._ES
) , SMM_CPU_OFFSET (x64
._ES
) , 0 , FALSE
}, // EFI_SMM_SAVE_STATE_REGISTER_ES = 20
150 {4, 4, SMM_CPU_OFFSET (x86
._CS
) , SMM_CPU_OFFSET (x64
._CS
) , 0 , FALSE
}, // EFI_SMM_SAVE_STATE_REGISTER_CS = 21
151 {4, 4, SMM_CPU_OFFSET (x86
._SS
) , SMM_CPU_OFFSET (x64
._SS
) , 0 , FALSE
}, // EFI_SMM_SAVE_STATE_REGISTER_SS = 22
152 {4, 4, SMM_CPU_OFFSET (x86
._DS
) , SMM_CPU_OFFSET (x64
._DS
) , 0 , FALSE
}, // EFI_SMM_SAVE_STATE_REGISTER_DS = 23
153 {4, 4, SMM_CPU_OFFSET (x86
._FS
) , SMM_CPU_OFFSET (x64
._FS
) , 0 , FALSE
}, // EFI_SMM_SAVE_STATE_REGISTER_FS = 24
154 {4, 4, SMM_CPU_OFFSET (x86
._GS
) , SMM_CPU_OFFSET (x64
._GS
) , 0 , FALSE
}, // EFI_SMM_SAVE_STATE_REGISTER_GS = 25
155 {0, 4, 0 , SMM_CPU_OFFSET (x64
._LDTR
) , 0 , FALSE
}, // EFI_SMM_SAVE_STATE_REGISTER_LDTR_SEL = 26
156 {4, 4, SMM_CPU_OFFSET (x86
._TR
) , SMM_CPU_OFFSET (x64
._TR
) , 0 , FALSE
}, // EFI_SMM_SAVE_STATE_REGISTER_TR_SEL = 27
157 {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
158 {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
159 {0, 8, 0 , SMM_CPU_OFFSET (x64
._R8
) , SMM_CPU_OFFSET (x64
._R8
) + 4, TRUE
}, // EFI_SMM_SAVE_STATE_REGISTER_R8 = 30
160 {0, 8, 0 , SMM_CPU_OFFSET (x64
._R9
) , SMM_CPU_OFFSET (x64
._R9
) + 4, TRUE
}, // EFI_SMM_SAVE_STATE_REGISTER_R9 = 31
161 {0, 8, 0 , SMM_CPU_OFFSET (x64
._R10
) , SMM_CPU_OFFSET (x64
._R10
) + 4, TRUE
}, // EFI_SMM_SAVE_STATE_REGISTER_R10 = 32
162 {0, 8, 0 , SMM_CPU_OFFSET (x64
._R11
) , SMM_CPU_OFFSET (x64
._R11
) + 4, TRUE
}, // EFI_SMM_SAVE_STATE_REGISTER_R11 = 33
163 {0, 8, 0 , SMM_CPU_OFFSET (x64
._R12
) , SMM_CPU_OFFSET (x64
._R12
) + 4, TRUE
}, // EFI_SMM_SAVE_STATE_REGISTER_R12 = 34
164 {0, 8, 0 , SMM_CPU_OFFSET (x64
._R13
) , SMM_CPU_OFFSET (x64
._R13
) + 4, TRUE
}, // EFI_SMM_SAVE_STATE_REGISTER_R13 = 35
165 {0, 8, 0 , SMM_CPU_OFFSET (x64
._R14
) , SMM_CPU_OFFSET (x64
._R14
) + 4, TRUE
}, // EFI_SMM_SAVE_STATE_REGISTER_R14 = 36
166 {0, 8, 0 , SMM_CPU_OFFSET (x64
._R15
) , SMM_CPU_OFFSET (x64
._R15
) + 4, TRUE
}, // EFI_SMM_SAVE_STATE_REGISTER_R15 = 37
167 {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
168 {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
169 {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
170 {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
171 {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
172 {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
173 {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
174 {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
175 {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
177 {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
178 {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
179 {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
180 {0, 4, 0 , SMM_CPU_OFFSET (x64
._CR4
) , 0 , FALSE
}, // EFI_SMM_SAVE_STATE_REGISTER_CR4 = 54
184 /// Lookup table for the IOMisc width information
186 CONST CPU_SMM_SAVE_STATE_IO_WIDTH mSmmCpuIoWidth
[] = {
187 { 0, EFI_SMM_SAVE_STATE_IO_WIDTH_UINT8
}, // Undefined = 0
188 { 1, EFI_SMM_SAVE_STATE_IO_WIDTH_UINT8
}, // SMM_IO_LENGTH_BYTE = 1
189 { 2, EFI_SMM_SAVE_STATE_IO_WIDTH_UINT16
}, // SMM_IO_LENGTH_WORD = 2
190 { 0, EFI_SMM_SAVE_STATE_IO_WIDTH_UINT8
}, // Undefined = 3
191 { 4, EFI_SMM_SAVE_STATE_IO_WIDTH_UINT32
}, // SMM_IO_LENGTH_DWORD = 4
192 { 0, EFI_SMM_SAVE_STATE_IO_WIDTH_UINT8
}, // Undefined = 5
193 { 0, EFI_SMM_SAVE_STATE_IO_WIDTH_UINT8
}, // Undefined = 6
194 { 0, EFI_SMM_SAVE_STATE_IO_WIDTH_UINT8
} // Undefined = 7
198 /// Lookup table for the IOMisc type information
200 CONST EFI_SMM_SAVE_STATE_IO_TYPE mSmmCpuIoType
[] = {
201 EFI_SMM_SAVE_STATE_IO_TYPE_OUTPUT
, // SMM_IO_TYPE_OUT_DX = 0
202 EFI_SMM_SAVE_STATE_IO_TYPE_INPUT
, // SMM_IO_TYPE_IN_DX = 1
203 EFI_SMM_SAVE_STATE_IO_TYPE_STRING
, // SMM_IO_TYPE_OUTS = 2
204 EFI_SMM_SAVE_STATE_IO_TYPE_STRING
, // SMM_IO_TYPE_INS = 3
205 (EFI_SMM_SAVE_STATE_IO_TYPE
)0, // Undefined = 4
206 (EFI_SMM_SAVE_STATE_IO_TYPE
)0, // Undefined = 5
207 EFI_SMM_SAVE_STATE_IO_TYPE_REP_PREFIX
, // SMM_IO_TYPE_REP_OUTS = 6
208 EFI_SMM_SAVE_STATE_IO_TYPE_REP_PREFIX
, // SMM_IO_TYPE_REP_INS = 7
209 EFI_SMM_SAVE_STATE_IO_TYPE_OUTPUT
, // SMM_IO_TYPE_OUT_IMMEDIATE = 8
210 EFI_SMM_SAVE_STATE_IO_TYPE_INPUT
, // SMM_IO_TYPE_OUT_IMMEDIATE = 9
211 (EFI_SMM_SAVE_STATE_IO_TYPE
)0, // Undefined = 10
212 (EFI_SMM_SAVE_STATE_IO_TYPE
)0, // Undefined = 11
213 (EFI_SMM_SAVE_STATE_IO_TYPE
)0, // Undefined = 12
214 (EFI_SMM_SAVE_STATE_IO_TYPE
)0, // Undefined = 13
215 (EFI_SMM_SAVE_STATE_IO_TYPE
)0, // Undefined = 14
216 (EFI_SMM_SAVE_STATE_IO_TYPE
)0 // Undefined = 15
220 /// The mode of the CPU at the time an SMI occurs
222 UINT8 mSmmSaveStateRegisterLma
;
225 Read information from the CPU save state.
227 @param Register Specifies the CPU register to read form the save state.
229 @retval 0 Register is not valid
230 @retval >0 Index into mSmmCpuWidthOffset[] associated with Register
235 IN EFI_SMM_SAVE_STATE_REGISTER Register
241 for (Index
= 0, Offset
= SMM_SAVE_STATE_REGISTER_MAX_INDEX
; mSmmCpuRegisterRanges
[Index
].Length
!= 0; Index
++) {
242 if (Register
>= mSmmCpuRegisterRanges
[Index
].Start
&& Register
<= mSmmCpuRegisterRanges
[Index
].End
) {
243 return Register
- mSmmCpuRegisterRanges
[Index
].Start
+ Offset
;
245 Offset
+= mSmmCpuRegisterRanges
[Index
].Length
;
251 Read a CPU Save State register on the target processor.
253 This function abstracts the differences that whether the CPU Save State register is in the
254 IA32 CPU Save State Map or X64 CPU Save State Map.
256 This function supports reading a CPU Save State register in SMBase relocation handler.
258 @param[in] CpuIndex Specifies the zero-based index of the CPU save state.
259 @param[in] RegisterIndex Index into mSmmCpuWidthOffset[] look up table.
260 @param[in] Width The number of bytes to read from the CPU save state.
261 @param[out] Buffer Upon return, this holds the CPU register value read from the save state.
263 @retval EFI_SUCCESS The register was read from Save State.
264 @retval EFI_NOT_FOUND The register is not defined for the Save State of Processor.
265 @retval EFI_INVALID_PARAMTER This or Buffer is NULL.
269 ReadSaveStateRegisterByIndex (
271 IN UINTN RegisterIndex
,
276 SMRAM_SAVE_STATE_MAP
*CpuSaveState
;
278 if (RegisterIndex
== 0) {
279 return EFI_NOT_FOUND
;
282 CpuSaveState
= gSmst
->CpuSaveState
[CpuIndex
];
284 if (mSmmSaveStateRegisterLma
== EFI_SMM_SAVE_STATE_REGISTER_LMA_32BIT
) {
286 // If 32-bit mode width is zero, then the specified register can not be accessed
288 if (mSmmCpuWidthOffset
[RegisterIndex
].Width32
== 0) {
289 return EFI_NOT_FOUND
;
293 // If Width is bigger than the 32-bit mode width, then the specified register can not be accessed
295 if (Width
> mSmmCpuWidthOffset
[RegisterIndex
].Width32
) {
296 return EFI_INVALID_PARAMETER
;
300 // Write return buffer
302 ASSERT(CpuSaveState
!= NULL
);
303 CopyMem(Buffer
, (UINT8
*)CpuSaveState
+ mSmmCpuWidthOffset
[RegisterIndex
].Offset32
, Width
);
306 // If 64-bit mode width is zero, then the specified register can not be accessed
308 if (mSmmCpuWidthOffset
[RegisterIndex
].Width64
== 0) {
309 return EFI_NOT_FOUND
;
313 // If Width is bigger than the 64-bit mode width, then the specified register can not be accessed
315 if (Width
> mSmmCpuWidthOffset
[RegisterIndex
].Width64
) {
316 return EFI_INVALID_PARAMETER
;
320 // Write lower 32-bits of return buffer
322 CopyMem(Buffer
, (UINT8
*)CpuSaveState
+ mSmmCpuWidthOffset
[RegisterIndex
].Offset64Lo
, MIN(4, Width
));
325 // Write upper 32-bits of return buffer
327 CopyMem((UINT8
*)Buffer
+ 4, (UINT8
*)CpuSaveState
+ mSmmCpuWidthOffset
[RegisterIndex
].Offset64Hi
, Width
- 4);
334 Read a CPU Save State register on the target processor.
336 This function abstracts the differences that whether the CPU Save State register is in the
337 IA32 CPU Save State Map or X64 CPU Save State Map.
339 This function supports reading a CPU Save State register in SMBase relocation handler.
341 @param[in] CpuIndex Specifies the zero-based index of the CPU save state.
342 @param[in] RegisterIndex Index into mSmmCpuWidthOffset[] look up table.
343 @param[in] Width The number of bytes to read from the CPU save state.
344 @param[out] Buffer Upon return, this holds the CPU register value read from the save state.
346 @retval EFI_SUCCESS The register was read from Save State.
347 @retval EFI_NOT_FOUND The register is not defined for the Save State of Processor.
348 @retval EFI_INVALID_PARAMTER This or Buffer is NULL.
353 ReadSaveStateRegister (
355 IN EFI_SMM_SAVE_STATE_REGISTER Register
,
361 SMRAM_SAVE_STATE_IOMISC IoMisc
;
362 EFI_SMM_SAVE_STATE_IO_INFO
*IoInfo
;
366 // Check for special EFI_SMM_SAVE_STATE_REGISTER_LMA
368 if (Register
== EFI_SMM_SAVE_STATE_REGISTER_LMA
) {
370 // Only byte access is supported for this register
373 return EFI_INVALID_PARAMETER
;
376 *(UINT8
*)Buffer
= mSmmSaveStateRegisterLma
;
382 // Check for special EFI_SMM_SAVE_STATE_REGISTER_IO
384 if (Register
== EFI_SMM_SAVE_STATE_REGISTER_IO
) {
386 // Get SMM Revision ID
388 ReadSaveStateRegisterByIndex (CpuIndex
, SMM_SAVE_STATE_REGISTER_SMMREVID_INDEX
, sizeof(SmmRevId
), &SmmRevId
);
391 // See if the CPU supports the IOMisc register in the save state
393 if (SmmRevId
< SMRAM_SAVE_STATE_MIN_REV_ID_IOMISC
) {
394 return EFI_NOT_FOUND
;
398 // Get the IOMisc register value
400 ReadSaveStateRegisterByIndex (CpuIndex
, SMM_SAVE_STATE_REGISTER_IOMISC_INDEX
, sizeof(IoMisc
.Uint32
), &IoMisc
.Uint32
);
403 // Check for the SMI_FLAG in IOMisc
405 if (IoMisc
.Bits
.SmiFlag
== 0) {
406 return EFI_NOT_FOUND
;
410 // Compute index for the I/O Length and I/O Type lookup tables
412 if (mSmmCpuIoWidth
[IoMisc
.Bits
.Length
].Width
== 0 || mSmmCpuIoType
[IoMisc
.Bits
.Type
] == 0) {
413 return EFI_NOT_FOUND
;
417 // Zero the IoInfo structure that will be returned in Buffer
419 IoInfo
= (EFI_SMM_SAVE_STATE_IO_INFO
*)Buffer
;
420 ZeroMem (IoInfo
, sizeof(EFI_SMM_SAVE_STATE_IO_INFO
));
423 // Use lookup tables to help fill in all the fields of the IoInfo structure
425 IoInfo
->IoPort
= (UINT16
)IoMisc
.Bits
.Port
;
426 IoInfo
->IoWidth
= mSmmCpuIoWidth
[IoMisc
.Bits
.Length
].IoWidth
;
427 IoInfo
->IoType
= mSmmCpuIoType
[IoMisc
.Bits
.Type
];
428 if (IoInfo
->IoType
== EFI_SMM_SAVE_STATE_IO_TYPE_INPUT
|| IoInfo
->IoType
== EFI_SMM_SAVE_STATE_IO_TYPE_OUTPUT
) {
429 ReadSaveStateRegister (CpuIndex
, EFI_SMM_SAVE_STATE_REGISTER_RAX
, mSmmCpuIoWidth
[IoMisc
.Bits
.Length
].Width
, &IoInfo
->IoData
);
432 ReadSaveStateRegisterByIndex(CpuIndex
, SMM_SAVE_STATE_REGISTER_IOMEMADDR_INDEX
, sizeof(IoMemAddr
), &IoMemAddr
);
433 CopyMem(&IoInfo
->IoData
, IoMemAddr
, mSmmCpuIoWidth
[IoMisc
.Bits
.Length
].Width
);
439 // Convert Register to a register lookup table index
441 return ReadSaveStateRegisterByIndex (CpuIndex
, GetRegisterIndex (Register
), Width
, Buffer
);
445 Write value to a CPU Save State register on the target processor.
447 This function abstracts the differences that whether the CPU Save State register is in the
448 IA32 CPU Save State Map or X64 CPU Save State Map.
450 This function supports writing a CPU Save State register in SMBase relocation handler.
452 @param[in] CpuIndex Specifies the zero-based index of the CPU save state.
453 @param[in] RegisterIndex Index into mSmmCpuWidthOffset[] look up table.
454 @param[in] Width The number of bytes to read from the CPU save state.
455 @param[in] Buffer Upon entry, this holds the new CPU register value.
457 @retval EFI_SUCCESS The register was written to Save State.
458 @retval EFI_NOT_FOUND The register is not defined for the Save State of Processor.
459 @retval EFI_INVALID_PARAMTER ProcessorIndex or Width is not correct.
464 WriteSaveStateRegister (
466 IN EFI_SMM_SAVE_STATE_REGISTER Register
,
468 IN CONST VOID
*Buffer
472 SMRAM_SAVE_STATE_MAP
*CpuSaveState
;
475 // Writes to EFI_SMM_SAVE_STATE_REGISTER_LMA are ignored
477 if (Register
== EFI_SMM_SAVE_STATE_REGISTER_LMA
) {
482 // Writes to EFI_SMM_SAVE_STATE_REGISTER_IO are not supported
484 if (Register
== EFI_SMM_SAVE_STATE_REGISTER_IO
) {
485 return EFI_NOT_FOUND
;
489 // Convert Register to a register lookup table index
491 RegisterIndex
= GetRegisterIndex (Register
);
492 if (RegisterIndex
== 0) {
493 return EFI_NOT_FOUND
;
496 CpuSaveState
= gSmst
->CpuSaveState
[CpuIndex
];
499 // Do not write non-writable SaveState, because it will cause exception.
501 if (!mSmmCpuWidthOffset
[RegisterIndex
].Writeable
) {
502 return EFI_UNSUPPORTED
;
508 if (mSmmSaveStateRegisterLma
== EFI_SMM_SAVE_STATE_REGISTER_LMA_32BIT
) {
510 // If 32-bit mode width is zero, then the specified register can not be accessed
512 if (mSmmCpuWidthOffset
[RegisterIndex
].Width32
== 0) {
513 return EFI_NOT_FOUND
;
517 // If Width is bigger than the 32-bit mode width, then the specified register can not be accessed
519 if (Width
> mSmmCpuWidthOffset
[RegisterIndex
].Width32
) {
520 return EFI_INVALID_PARAMETER
;
523 // Write SMM State register
525 ASSERT (CpuSaveState
!= NULL
);
526 CopyMem((UINT8
*)CpuSaveState
+ mSmmCpuWidthOffset
[RegisterIndex
].Offset32
, Buffer
, Width
);
529 // If 64-bit mode width is zero, then the specified register can not be accessed
531 if (mSmmCpuWidthOffset
[RegisterIndex
].Width64
== 0) {
532 return EFI_NOT_FOUND
;
536 // If Width is bigger than the 64-bit mode width, then the specified register can not be accessed
538 if (Width
> mSmmCpuWidthOffset
[RegisterIndex
].Width64
) {
539 return EFI_INVALID_PARAMETER
;
543 // Write lower 32-bits of SMM State register
545 CopyMem((UINT8
*)CpuSaveState
+ mSmmCpuWidthOffset
[RegisterIndex
].Offset64Lo
, Buffer
, MIN (4, Width
));
548 // Write upper 32-bits of SMM State register
550 CopyMem((UINT8
*)CpuSaveState
+ mSmmCpuWidthOffset
[RegisterIndex
].Offset64Hi
, (UINT8
*)Buffer
+ 4, Width
- 4);
557 Hook the code executed immediately after an RSM instruction on the currently
558 executing CPU. The mode of code executed immediately after RSM must be
559 detected, and the appropriate hook must be selected. Always clear the auto
560 HALT restart flag if it is set.
562 @param[in] CpuIndex The processor index for the currently
564 @param[in] CpuState Pointer to SMRAM Save State Map for the
565 currently executing CPU.
566 @param[in] NewInstructionPointer32 Instruction pointer to use if resuming to
567 32-bit mode from 64-bit SMM.
568 @param[in] NewInstructionPointer Instruction pointer to use if resuming to
571 @retval The value of the original instruction pointer before it was hooked.
578 SMRAM_SAVE_STATE_MAP
*CpuState
,
579 UINT64 NewInstructionPointer32
,
580 UINT64 NewInstructionPointer
583 UINT64 OriginalInstructionPointer
;
585 OriginalInstructionPointer
= SmmCpuFeaturesHookReturnFromSmm (
588 NewInstructionPointer32
,
589 NewInstructionPointer
591 if (OriginalInstructionPointer
!= 0) {
592 return OriginalInstructionPointer
;
595 if (mSmmSaveStateRegisterLma
== EFI_SMM_SAVE_STATE_REGISTER_LMA_32BIT
) {
596 OriginalInstructionPointer
= (UINT64
)CpuState
->x86
._EIP
;
597 CpuState
->x86
._EIP
= (UINT32
)NewInstructionPointer
;
599 // Clear the auto HALT restart flag so the RSM instruction returns
600 // program control to the instruction following the HLT instruction.
602 if ((CpuState
->x86
.AutoHALTRestart
& BIT0
) != 0) {
603 CpuState
->x86
.AutoHALTRestart
&= ~BIT0
;
606 OriginalInstructionPointer
= CpuState
->x64
._RIP
;
607 if ((CpuState
->x64
.IA32_EFER
& LMA
) == 0) {
608 CpuState
->x64
._RIP
= (UINT32
)NewInstructionPointer32
;
610 CpuState
->x64
._RIP
= (UINT32
)NewInstructionPointer
;
613 // Clear the auto HALT restart flag so the RSM instruction returns
614 // program control to the instruction following the HLT instruction.
616 if ((CpuState
->x64
.AutoHALTRestart
& BIT0
) != 0) {
617 CpuState
->x64
.AutoHALTRestart
&= ~BIT0
;
620 return OriginalInstructionPointer
;
624 Get the size of the SMI Handler in bytes.
626 @retval The size, in bytes, of the SMI Handler.
637 Size
= SmmCpuFeaturesGetSmiHandlerSize ();
641 return gcSmiHandlerSize
;
645 Install the SMI handler for the CPU specified by CpuIndex. This function
646 is called by the CPU that was elected as monarch during System Management
649 @param[in] CpuIndex The index of the CPU to install the custom SMI handler.
650 The value must be between 0 and the NumberOfCpus field
651 in the System Management System Table (SMST).
652 @param[in] SmBase The SMBASE address for the CPU specified by CpuIndex.
653 @param[in] SmiStack The stack to use when an SMI is processed by the
654 the CPU specified by CpuIndex.
655 @param[in] StackSize The size, in bytes, if the stack used when an SMI is
656 processed by the CPU specified by CpuIndex.
657 @param[in] GdtBase The base address of the GDT to use when an SMI is
658 processed by the CPU specified by CpuIndex.
659 @param[in] GdtSize The size, in bytes, of the GDT used when an SMI is
660 processed by the CPU specified by CpuIndex.
661 @param[in] IdtBase The base address of the IDT to use when an SMI is
662 processed by the CPU specified by CpuIndex.
663 @param[in] IdtSize The size, in bytes, of the IDT used when an SMI is
664 processed by the CPU specified by CpuIndex.
665 @param[in] Cr3 The base address of the page tables to use when an SMI
666 is processed by the CPU specified by CpuIndex.
682 PROCESSOR_SMM_DESCRIPTOR
*Psd
;
686 // Initialize PROCESSOR_SMM_DESCRIPTOR
688 Psd
= (PROCESSOR_SMM_DESCRIPTOR
*)(VOID
*)((UINTN
)SmBase
+ SMM_PSD_OFFSET
);
689 CopyMem (Psd
, &gcPsd
, sizeof (gcPsd
));
690 Psd
->SmmGdtPtr
= (UINT64
)GdtBase
;
691 Psd
->SmmGdtSize
= (UINT32
)GdtSize
;
693 if (SmmCpuFeaturesGetSmiHandlerSize () != 0) {
695 // Install SMI handler provided by library
697 SmmCpuFeaturesInstallSmiHandler (
711 InitShadowStack (CpuIndex
, (VOID
*)((UINTN
)SmiStack
+ StackSize
));
714 // Initialize values in template before copy
716 CpuSmiStack
= (UINT32
)((UINTN
)SmiStack
+ StackSize
- sizeof (UINTN
));
717 PatchInstructionX86 (gPatchSmiStack
, CpuSmiStack
, 4);
718 PatchInstructionX86 (gPatchSmiCr3
, Cr3
, 4);
719 PatchInstructionX86 (gPatchSmbase
, SmBase
, 4);
720 gSmiHandlerIdtr
.Base
= IdtBase
;
721 gSmiHandlerIdtr
.Limit
= (UINT16
)(IdtSize
- 1);
724 // Set the value at the top of the CPU stack to the CPU Index
726 *(UINTN
*)(UINTN
)CpuSmiStack
= CpuIndex
;
729 // Copy template to CPU specific SMI handler location
732 (VOID
*)((UINTN
)SmBase
+ SMM_HANDLER_OFFSET
),
733 (VOID
*)gcSmiHandlerTemplate
,