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>
18 #include "PiSmmCpuDxeSmm.h"
21 UINT64 Signature
; // Offset 0x00
22 UINT16 Reserved1
; // Offset 0x08
23 UINT16 Reserved2
; // Offset 0x0A
24 UINT16 Reserved3
; // Offset 0x0C
25 UINT16 SmmCs
; // Offset 0x0E
26 UINT16 SmmDs
; // Offset 0x10
27 UINT16 SmmSs
; // Offset 0x12
28 UINT16 SmmOtherSegment
; // Offset 0x14
29 UINT16 Reserved4
; // Offset 0x16
30 UINT64 Reserved5
; // Offset 0x18
31 UINT64 Reserved6
; // Offset 0x20
32 UINT64 Reserved7
; // Offset 0x28
33 UINT64 SmmGdtPtr
; // Offset 0x30
34 UINT32 SmmGdtSize
; // Offset 0x38
35 UINT32 Reserved8
; // Offset 0x3C
36 UINT64 Reserved9
; // Offset 0x40
37 UINT64 Reserved10
; // Offset 0x48
38 UINT16 Reserved11
; // Offset 0x50
39 UINT16 Reserved12
; // Offset 0x52
40 UINT32 Reserved13
; // Offset 0x54
41 UINT64 Reserved14
; // Offset 0x58
42 } PROCESSOR_SMM_DESCRIPTOR
;
44 extern CONST PROCESSOR_SMM_DESCRIPTOR gcPsd
;
47 // EFER register LMA bit
52 /// Macro used to simplify the lookup table entries of type CPU_SMM_SAVE_STATE_LOOKUP_ENTRY
54 #define SMM_CPU_OFFSET(Field) OFFSET_OF (SMRAM_SAVE_STATE_MAP, Field)
57 /// Macro used to simplify the lookup table entries of type CPU_SMM_SAVE_STATE_REGISTER_RANGE
59 #define SMM_REGISTER_RANGE(Start, End) { Start, End, End - Start + 1 }
62 /// Structure used to describe a range of registers
65 EFI_SMM_SAVE_STATE_REGISTER Start
;
66 EFI_SMM_SAVE_STATE_REGISTER End
;
68 } CPU_SMM_SAVE_STATE_REGISTER_RANGE
;
71 /// Structure used to build a lookup table to retrieve the widths and offsets
72 /// associated with each supported EFI_SMM_SAVE_STATE_REGISTER value
75 #define SMM_SAVE_STATE_REGISTER_SMMREVID_INDEX 1
76 #define SMM_SAVE_STATE_REGISTER_IOMISC_INDEX 2
77 #define SMM_SAVE_STATE_REGISTER_IOMEMADDR_INDEX 3
78 #define SMM_SAVE_STATE_REGISTER_MAX_INDEX 4
87 } CPU_SMM_SAVE_STATE_LOOKUP_ENTRY
;
90 /// Structure used to build a lookup table for the IOMisc width information
94 EFI_SMM_SAVE_STATE_IO_WIDTH IoWidth
;
95 } CPU_SMM_SAVE_STATE_IO_WIDTH
;
98 /// Variables from SMI Handler
100 X86_ASSEMBLY_PATCH_LABEL gPatchSmbase
;
101 X86_ASSEMBLY_PATCH_LABEL gPatchSmiStack
;
102 X86_ASSEMBLY_PATCH_LABEL gPatchSmiCr3
;
103 extern volatile UINT8 gcSmiHandlerTemplate
[];
104 extern CONST UINT16 gcSmiHandlerSize
;
107 // Variables used by SMI Handler
109 IA32_DESCRIPTOR gSmiHandlerIdtr
;
112 /// Table used by GetRegisterIndex() to convert an EFI_SMM_SAVE_STATE_REGISTER
113 /// value to an index into a table of type CPU_SMM_SAVE_STATE_LOOKUP_ENTRY
115 CONST CPU_SMM_SAVE_STATE_REGISTER_RANGE mSmmCpuRegisterRanges
[] = {
116 SMM_REGISTER_RANGE (EFI_SMM_SAVE_STATE_REGISTER_GDTBASE
, EFI_SMM_SAVE_STATE_REGISTER_LDTINFO
),
117 SMM_REGISTER_RANGE (EFI_SMM_SAVE_STATE_REGISTER_ES
, EFI_SMM_SAVE_STATE_REGISTER_RIP
),
118 SMM_REGISTER_RANGE (EFI_SMM_SAVE_STATE_REGISTER_RFLAGS
, EFI_SMM_SAVE_STATE_REGISTER_CR4
),
119 { (EFI_SMM_SAVE_STATE_REGISTER
)0, (EFI_SMM_SAVE_STATE_REGISTER
)0, 0 }
123 /// Lookup table used to retrieve the widths and offsets associated with each
124 /// supported EFI_SMM_SAVE_STATE_REGISTER value
126 CONST CPU_SMM_SAVE_STATE_LOOKUP_ENTRY mSmmCpuWidthOffset
[] = {
127 {0, 0, 0, 0, 0, FALSE
}, // Reserved
130 // Internally defined CPU Save State Registers. Not defined in PI SMM CPU Protocol.
132 {4, 4, SMM_CPU_OFFSET (x86
.SMMRevId
) , SMM_CPU_OFFSET (x64
.SMMRevId
) , 0 , FALSE
}, // SMM_SAVE_STATE_REGISTER_SMMREVID_INDEX = 1
133 {4, 4, SMM_CPU_OFFSET (x86
.IOMisc
) , SMM_CPU_OFFSET (x64
.IOMisc
) , 0 , FALSE
}, // SMM_SAVE_STATE_REGISTER_IOMISC_INDEX = 2
134 {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
137 // CPU Save State registers defined in PI SMM CPU Protocol.
139 {0, 8, 0 , SMM_CPU_OFFSET (x64
.GdtBaseLoDword
) , SMM_CPU_OFFSET (x64
.GdtBaseHiDword
), FALSE
}, // EFI_SMM_SAVE_STATE_REGISTER_GDTBASE = 4
140 {0, 8, 0 , SMM_CPU_OFFSET (x64
.IdtBaseLoDword
) , SMM_CPU_OFFSET (x64
.IdtBaseHiDword
), FALSE
}, // EFI_SMM_SAVE_STATE_REGISTER_IDTBASE = 5
141 {0, 8, 0 , SMM_CPU_OFFSET (x64
.LdtBaseLoDword
) , SMM_CPU_OFFSET (x64
.LdtBaseHiDword
), FALSE
}, // EFI_SMM_SAVE_STATE_REGISTER_LDTBASE = 6
142 {0, 0, 0 , 0 , 0 , FALSE
}, // EFI_SMM_SAVE_STATE_REGISTER_GDTLIMIT = 7
143 {0, 0, 0 , 0 , 0 , FALSE
}, // EFI_SMM_SAVE_STATE_REGISTER_IDTLIMIT = 8
144 {0, 0, 0 , 0 , 0 , FALSE
}, // EFI_SMM_SAVE_STATE_REGISTER_LDTLIMIT = 9
145 {0, 0, 0 , 0 , 0 , FALSE
}, // EFI_SMM_SAVE_STATE_REGISTER_LDTINFO = 10
147 {4, 4, SMM_CPU_OFFSET (x86
._ES
) , SMM_CPU_OFFSET (x64
._ES
) , 0 , FALSE
}, // EFI_SMM_SAVE_STATE_REGISTER_ES = 20
148 {4, 4, SMM_CPU_OFFSET (x86
._CS
) , SMM_CPU_OFFSET (x64
._CS
) , 0 , FALSE
}, // EFI_SMM_SAVE_STATE_REGISTER_CS = 21
149 {4, 4, SMM_CPU_OFFSET (x86
._SS
) , SMM_CPU_OFFSET (x64
._SS
) , 0 , FALSE
}, // EFI_SMM_SAVE_STATE_REGISTER_SS = 22
150 {4, 4, SMM_CPU_OFFSET (x86
._DS
) , SMM_CPU_OFFSET (x64
._DS
) , 0 , FALSE
}, // EFI_SMM_SAVE_STATE_REGISTER_DS = 23
151 {4, 4, SMM_CPU_OFFSET (x86
._FS
) , SMM_CPU_OFFSET (x64
._FS
) , 0 , FALSE
}, // EFI_SMM_SAVE_STATE_REGISTER_FS = 24
152 {4, 4, SMM_CPU_OFFSET (x86
._GS
) , SMM_CPU_OFFSET (x64
._GS
) , 0 , FALSE
}, // EFI_SMM_SAVE_STATE_REGISTER_GS = 25
153 {0, 4, 0 , SMM_CPU_OFFSET (x64
._LDTR
) , 0 , FALSE
}, // EFI_SMM_SAVE_STATE_REGISTER_LDTR_SEL = 26
154 {4, 4, SMM_CPU_OFFSET (x86
._TR
) , SMM_CPU_OFFSET (x64
._TR
) , 0 , FALSE
}, // EFI_SMM_SAVE_STATE_REGISTER_TR_SEL = 27
155 {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
156 {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
157 {0, 8, 0 , SMM_CPU_OFFSET (x64
._R8
) , SMM_CPU_OFFSET (x64
._R8
) + 4, TRUE
}, // EFI_SMM_SAVE_STATE_REGISTER_R8 = 30
158 {0, 8, 0 , SMM_CPU_OFFSET (x64
._R9
) , SMM_CPU_OFFSET (x64
._R9
) + 4, TRUE
}, // EFI_SMM_SAVE_STATE_REGISTER_R9 = 31
159 {0, 8, 0 , SMM_CPU_OFFSET (x64
._R10
) , SMM_CPU_OFFSET (x64
._R10
) + 4, TRUE
}, // EFI_SMM_SAVE_STATE_REGISTER_R10 = 32
160 {0, 8, 0 , SMM_CPU_OFFSET (x64
._R11
) , SMM_CPU_OFFSET (x64
._R11
) + 4, TRUE
}, // EFI_SMM_SAVE_STATE_REGISTER_R11 = 33
161 {0, 8, 0 , SMM_CPU_OFFSET (x64
._R12
) , SMM_CPU_OFFSET (x64
._R12
) + 4, TRUE
}, // EFI_SMM_SAVE_STATE_REGISTER_R12 = 34
162 {0, 8, 0 , SMM_CPU_OFFSET (x64
._R13
) , SMM_CPU_OFFSET (x64
._R13
) + 4, TRUE
}, // EFI_SMM_SAVE_STATE_REGISTER_R13 = 35
163 {0, 8, 0 , SMM_CPU_OFFSET (x64
._R14
) , SMM_CPU_OFFSET (x64
._R14
) + 4, TRUE
}, // EFI_SMM_SAVE_STATE_REGISTER_R14 = 36
164 {0, 8, 0 , SMM_CPU_OFFSET (x64
._R15
) , SMM_CPU_OFFSET (x64
._R15
) + 4, TRUE
}, // EFI_SMM_SAVE_STATE_REGISTER_R15 = 37
165 {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
166 {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
167 {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
168 {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
169 {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
170 {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
171 {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
172 {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
173 {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
175 {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
176 {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
177 {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
178 {0, 4, 0 , SMM_CPU_OFFSET (x64
._CR4
) , 0 , FALSE
}, // EFI_SMM_SAVE_STATE_REGISTER_CR4 = 54
182 /// Lookup table for the IOMisc width information
184 CONST CPU_SMM_SAVE_STATE_IO_WIDTH mSmmCpuIoWidth
[] = {
185 { 0, EFI_SMM_SAVE_STATE_IO_WIDTH_UINT8
}, // Undefined = 0
186 { 1, EFI_SMM_SAVE_STATE_IO_WIDTH_UINT8
}, // SMM_IO_LENGTH_BYTE = 1
187 { 2, EFI_SMM_SAVE_STATE_IO_WIDTH_UINT16
}, // SMM_IO_LENGTH_WORD = 2
188 { 0, EFI_SMM_SAVE_STATE_IO_WIDTH_UINT8
}, // Undefined = 3
189 { 4, EFI_SMM_SAVE_STATE_IO_WIDTH_UINT32
}, // SMM_IO_LENGTH_DWORD = 4
190 { 0, EFI_SMM_SAVE_STATE_IO_WIDTH_UINT8
}, // Undefined = 5
191 { 0, EFI_SMM_SAVE_STATE_IO_WIDTH_UINT8
}, // Undefined = 6
192 { 0, EFI_SMM_SAVE_STATE_IO_WIDTH_UINT8
} // Undefined = 7
196 /// Lookup table for the IOMisc type information
198 CONST EFI_SMM_SAVE_STATE_IO_TYPE mSmmCpuIoType
[] = {
199 EFI_SMM_SAVE_STATE_IO_TYPE_OUTPUT
, // SMM_IO_TYPE_OUT_DX = 0
200 EFI_SMM_SAVE_STATE_IO_TYPE_INPUT
, // SMM_IO_TYPE_IN_DX = 1
201 EFI_SMM_SAVE_STATE_IO_TYPE_STRING
, // SMM_IO_TYPE_OUTS = 2
202 EFI_SMM_SAVE_STATE_IO_TYPE_STRING
, // SMM_IO_TYPE_INS = 3
203 (EFI_SMM_SAVE_STATE_IO_TYPE
)0, // Undefined = 4
204 (EFI_SMM_SAVE_STATE_IO_TYPE
)0, // Undefined = 5
205 EFI_SMM_SAVE_STATE_IO_TYPE_REP_PREFIX
, // SMM_IO_TYPE_REP_OUTS = 6
206 EFI_SMM_SAVE_STATE_IO_TYPE_REP_PREFIX
, // SMM_IO_TYPE_REP_INS = 7
207 EFI_SMM_SAVE_STATE_IO_TYPE_OUTPUT
, // SMM_IO_TYPE_OUT_IMMEDIATE = 8
208 EFI_SMM_SAVE_STATE_IO_TYPE_INPUT
, // SMM_IO_TYPE_OUT_IMMEDIATE = 9
209 (EFI_SMM_SAVE_STATE_IO_TYPE
)0, // Undefined = 10
210 (EFI_SMM_SAVE_STATE_IO_TYPE
)0, // Undefined = 11
211 (EFI_SMM_SAVE_STATE_IO_TYPE
)0, // Undefined = 12
212 (EFI_SMM_SAVE_STATE_IO_TYPE
)0, // Undefined = 13
213 (EFI_SMM_SAVE_STATE_IO_TYPE
)0, // Undefined = 14
214 (EFI_SMM_SAVE_STATE_IO_TYPE
)0 // Undefined = 15
218 /// The mode of the CPU at the time an SMI occurs
220 UINT8 mSmmSaveStateRegisterLma
;
223 Read information from the CPU save state.
225 @param Register Specifies the CPU register to read form the save state.
227 @retval 0 Register is not valid
228 @retval >0 Index into mSmmCpuWidthOffset[] associated with Register
233 IN EFI_SMM_SAVE_STATE_REGISTER Register
239 for (Index
= 0, Offset
= SMM_SAVE_STATE_REGISTER_MAX_INDEX
; mSmmCpuRegisterRanges
[Index
].Length
!= 0; Index
++) {
240 if (Register
>= mSmmCpuRegisterRanges
[Index
].Start
&& Register
<= mSmmCpuRegisterRanges
[Index
].End
) {
241 return Register
- mSmmCpuRegisterRanges
[Index
].Start
+ Offset
;
243 Offset
+= mSmmCpuRegisterRanges
[Index
].Length
;
249 Read a CPU Save State register on the target processor.
251 This function abstracts the differences that whether the CPU Save State register is in the
252 IA32 CPU Save State Map or X64 CPU Save State Map.
254 This function supports reading a CPU Save State register in SMBase relocation handler.
256 @param[in] CpuIndex Specifies the zero-based index of the CPU save state.
257 @param[in] RegisterIndex Index into mSmmCpuWidthOffset[] look up table.
258 @param[in] Width The number of bytes to read from the CPU save state.
259 @param[out] Buffer Upon return, this holds the CPU register value read from the save state.
261 @retval EFI_SUCCESS The register was read from Save State.
262 @retval EFI_NOT_FOUND The register is not defined for the Save State of Processor.
263 @retval EFI_INVALID_PARAMETER This or Buffer is NULL.
267 ReadSaveStateRegisterByIndex (
269 IN UINTN RegisterIndex
,
274 SMRAM_SAVE_STATE_MAP
*CpuSaveState
;
276 if (RegisterIndex
== 0) {
277 return EFI_NOT_FOUND
;
280 CpuSaveState
= gSmst
->CpuSaveState
[CpuIndex
];
282 if (mSmmSaveStateRegisterLma
== EFI_SMM_SAVE_STATE_REGISTER_LMA_32BIT
) {
284 // If 32-bit mode width is zero, then the specified register can not be accessed
286 if (mSmmCpuWidthOffset
[RegisterIndex
].Width32
== 0) {
287 return EFI_NOT_FOUND
;
291 // If Width is bigger than the 32-bit mode width, then the specified register can not be accessed
293 if (Width
> mSmmCpuWidthOffset
[RegisterIndex
].Width32
) {
294 return EFI_INVALID_PARAMETER
;
298 // Write return buffer
300 ASSERT(CpuSaveState
!= NULL
);
301 CopyMem(Buffer
, (UINT8
*)CpuSaveState
+ mSmmCpuWidthOffset
[RegisterIndex
].Offset32
, Width
);
304 // If 64-bit mode width is zero, then the specified register can not be accessed
306 if (mSmmCpuWidthOffset
[RegisterIndex
].Width64
== 0) {
307 return EFI_NOT_FOUND
;
311 // If Width is bigger than the 64-bit mode width, then the specified register can not be accessed
313 if (Width
> mSmmCpuWidthOffset
[RegisterIndex
].Width64
) {
314 return EFI_INVALID_PARAMETER
;
318 // Write lower 32-bits of return buffer
320 CopyMem(Buffer
, (UINT8
*)CpuSaveState
+ mSmmCpuWidthOffset
[RegisterIndex
].Offset64Lo
, MIN(4, Width
));
323 // Write upper 32-bits of return buffer
325 CopyMem((UINT8
*)Buffer
+ 4, (UINT8
*)CpuSaveState
+ mSmmCpuWidthOffset
[RegisterIndex
].Offset64Hi
, Width
- 4);
332 Read a CPU Save State register on the target processor.
334 This function abstracts the differences that whether the CPU Save State register is in the
335 IA32 CPU Save State Map or X64 CPU Save State Map.
337 This function supports reading a CPU Save State register in SMBase relocation handler.
339 @param[in] CpuIndex Specifies the zero-based index of the CPU save state.
340 @param[in] RegisterIndex Index into mSmmCpuWidthOffset[] look up table.
341 @param[in] Width The number of bytes to read from the CPU save state.
342 @param[out] Buffer Upon return, this holds the CPU register value read from the save state.
344 @retval EFI_SUCCESS The register was read from Save State.
345 @retval EFI_NOT_FOUND The register is not defined for the Save State of Processor.
346 @retval EFI_INVALID_PARAMETER This or Buffer is NULL.
351 ReadSaveStateRegister (
353 IN EFI_SMM_SAVE_STATE_REGISTER Register
,
359 SMRAM_SAVE_STATE_IOMISC IoMisc
;
360 EFI_SMM_SAVE_STATE_IO_INFO
*IoInfo
;
363 // Check for special EFI_SMM_SAVE_STATE_REGISTER_LMA
365 if (Register
== EFI_SMM_SAVE_STATE_REGISTER_LMA
) {
367 // Only byte access is supported for this register
370 return EFI_INVALID_PARAMETER
;
373 *(UINT8
*)Buffer
= mSmmSaveStateRegisterLma
;
379 // Check for special EFI_SMM_SAVE_STATE_REGISTER_IO
381 if (Register
== EFI_SMM_SAVE_STATE_REGISTER_IO
) {
383 // Get SMM Revision ID
385 ReadSaveStateRegisterByIndex (CpuIndex
, SMM_SAVE_STATE_REGISTER_SMMREVID_INDEX
, sizeof(SmmRevId
), &SmmRevId
);
388 // See if the CPU supports the IOMisc register in the save state
390 if (SmmRevId
< SMRAM_SAVE_STATE_MIN_REV_ID_IOMISC
) {
391 return EFI_NOT_FOUND
;
395 // Get the IOMisc register value
397 ReadSaveStateRegisterByIndex (CpuIndex
, SMM_SAVE_STATE_REGISTER_IOMISC_INDEX
, sizeof(IoMisc
.Uint32
), &IoMisc
.Uint32
);
400 // Check for the SMI_FLAG in IOMisc
402 if (IoMisc
.Bits
.SmiFlag
== 0) {
403 return EFI_NOT_FOUND
;
407 // Only support IN/OUT, but not INS/OUTS/REP INS/REP OUTS.
409 if ((mSmmCpuIoType
[IoMisc
.Bits
.Type
] != EFI_SMM_SAVE_STATE_IO_TYPE_INPUT
) &&
410 (mSmmCpuIoType
[IoMisc
.Bits
.Type
] != EFI_SMM_SAVE_STATE_IO_TYPE_OUTPUT
)) {
411 return EFI_NOT_FOUND
;
415 // Compute index for the I/O Length and I/O Type lookup tables
417 if (mSmmCpuIoWidth
[IoMisc
.Bits
.Length
].Width
== 0 || mSmmCpuIoType
[IoMisc
.Bits
.Type
] == 0) {
418 return EFI_NOT_FOUND
;
422 // Zero the IoInfo structure that will be returned in Buffer
424 IoInfo
= (EFI_SMM_SAVE_STATE_IO_INFO
*)Buffer
;
425 ZeroMem (IoInfo
, sizeof(EFI_SMM_SAVE_STATE_IO_INFO
));
428 // Use lookup tables to help fill in all the fields of the IoInfo structure
430 IoInfo
->IoPort
= (UINT16
)IoMisc
.Bits
.Port
;
431 IoInfo
->IoWidth
= mSmmCpuIoWidth
[IoMisc
.Bits
.Length
].IoWidth
;
432 IoInfo
->IoType
= mSmmCpuIoType
[IoMisc
.Bits
.Type
];
433 ReadSaveStateRegister (CpuIndex
, EFI_SMM_SAVE_STATE_REGISTER_RAX
, mSmmCpuIoWidth
[IoMisc
.Bits
.Length
].Width
, &IoInfo
->IoData
);
438 // Convert Register to a register lookup table index
440 return ReadSaveStateRegisterByIndex (CpuIndex
, GetRegisterIndex (Register
), Width
, Buffer
);
444 Write value to a CPU Save State register on the target processor.
446 This function abstracts the differences that whether the CPU Save State register is in the
447 IA32 CPU Save State Map or X64 CPU Save State Map.
449 This function supports writing a CPU Save State register in SMBase relocation handler.
451 @param[in] CpuIndex Specifies the zero-based index of the CPU save state.
452 @param[in] RegisterIndex Index into mSmmCpuWidthOffset[] look up table.
453 @param[in] Width The number of bytes to read from the CPU save state.
454 @param[in] Buffer Upon entry, this holds the new CPU register value.
456 @retval EFI_SUCCESS The register was written to Save State.
457 @retval EFI_NOT_FOUND The register is not defined for the Save State of Processor.
458 @retval EFI_INVALID_PARAMETER ProcessorIndex or Width is not correct.
463 WriteSaveStateRegister (
465 IN EFI_SMM_SAVE_STATE_REGISTER Register
,
467 IN CONST VOID
*Buffer
471 SMRAM_SAVE_STATE_MAP
*CpuSaveState
;
474 // Writes to EFI_SMM_SAVE_STATE_REGISTER_LMA are ignored
476 if (Register
== EFI_SMM_SAVE_STATE_REGISTER_LMA
) {
481 // Writes to EFI_SMM_SAVE_STATE_REGISTER_IO are not supported
483 if (Register
== EFI_SMM_SAVE_STATE_REGISTER_IO
) {
484 return EFI_NOT_FOUND
;
488 // Convert Register to a register lookup table index
490 RegisterIndex
= GetRegisterIndex (Register
);
491 if (RegisterIndex
== 0) {
492 return EFI_NOT_FOUND
;
495 CpuSaveState
= gSmst
->CpuSaveState
[CpuIndex
];
498 // Do not write non-writable SaveState, because it will cause exception.
500 if (!mSmmCpuWidthOffset
[RegisterIndex
].Writeable
) {
501 return EFI_UNSUPPORTED
;
507 if (mSmmSaveStateRegisterLma
== EFI_SMM_SAVE_STATE_REGISTER_LMA_32BIT
) {
509 // If 32-bit mode width is zero, then the specified register can not be accessed
511 if (mSmmCpuWidthOffset
[RegisterIndex
].Width32
== 0) {
512 return EFI_NOT_FOUND
;
516 // If Width is bigger than the 32-bit mode width, then the specified register can not be accessed
518 if (Width
> mSmmCpuWidthOffset
[RegisterIndex
].Width32
) {
519 return EFI_INVALID_PARAMETER
;
522 // Write SMM State register
524 ASSERT (CpuSaveState
!= NULL
);
525 CopyMem((UINT8
*)CpuSaveState
+ mSmmCpuWidthOffset
[RegisterIndex
].Offset32
, Buffer
, Width
);
528 // If 64-bit mode width is zero, then the specified register can not be accessed
530 if (mSmmCpuWidthOffset
[RegisterIndex
].Width64
== 0) {
531 return EFI_NOT_FOUND
;
535 // If Width is bigger than the 64-bit mode width, then the specified register can not be accessed
537 if (Width
> mSmmCpuWidthOffset
[RegisterIndex
].Width64
) {
538 return EFI_INVALID_PARAMETER
;
542 // Write lower 32-bits of SMM State register
544 CopyMem((UINT8
*)CpuSaveState
+ mSmmCpuWidthOffset
[RegisterIndex
].Offset64Lo
, Buffer
, MIN (4, Width
));
547 // Write upper 32-bits of SMM State register
549 CopyMem((UINT8
*)CpuSaveState
+ mSmmCpuWidthOffset
[RegisterIndex
].Offset64Hi
, (UINT8
*)Buffer
+ 4, Width
- 4);
556 Hook the code executed immediately after an RSM instruction on the currently
557 executing CPU. The mode of code executed immediately after RSM must be
558 detected, and the appropriate hook must be selected. Always clear the auto
559 HALT restart flag if it is set.
561 @param[in] CpuIndex The processor index for the currently
563 @param[in] CpuState Pointer to SMRAM Save State Map for the
564 currently executing CPU.
565 @param[in] NewInstructionPointer32 Instruction pointer to use if resuming to
566 32-bit mode from 64-bit SMM.
567 @param[in] NewInstructionPointer Instruction pointer to use if resuming to
570 @retval The value of the original instruction pointer before it was hooked.
577 SMRAM_SAVE_STATE_MAP
*CpuState
,
578 UINT64 NewInstructionPointer32
,
579 UINT64 NewInstructionPointer
582 UINT64 OriginalInstructionPointer
;
584 OriginalInstructionPointer
= SmmCpuFeaturesHookReturnFromSmm (
587 NewInstructionPointer32
,
588 NewInstructionPointer
590 if (OriginalInstructionPointer
!= 0) {
591 return OriginalInstructionPointer
;
594 if (mSmmSaveStateRegisterLma
== EFI_SMM_SAVE_STATE_REGISTER_LMA_32BIT
) {
595 OriginalInstructionPointer
= (UINT64
)CpuState
->x86
._EIP
;
596 CpuState
->x86
._EIP
= (UINT32
)NewInstructionPointer
;
598 // Clear the auto HALT restart flag so the RSM instruction returns
599 // program control to the instruction following the HLT instruction.
601 if ((CpuState
->x86
.AutoHALTRestart
& BIT0
) != 0) {
602 CpuState
->x86
.AutoHALTRestart
&= ~BIT0
;
605 OriginalInstructionPointer
= CpuState
->x64
._RIP
;
606 if ((CpuState
->x64
.IA32_EFER
& LMA
) == 0) {
607 CpuState
->x64
._RIP
= (UINT32
)NewInstructionPointer32
;
609 CpuState
->x64
._RIP
= (UINT32
)NewInstructionPointer
;
612 // Clear the auto HALT restart flag so the RSM instruction returns
613 // program control to the instruction following the HLT instruction.
615 if ((CpuState
->x64
.AutoHALTRestart
& BIT0
) != 0) {
616 CpuState
->x64
.AutoHALTRestart
&= ~BIT0
;
619 return OriginalInstructionPointer
;
623 Get the size of the SMI Handler in bytes.
625 @retval The size, in bytes, of the SMI Handler.
636 Size
= SmmCpuFeaturesGetSmiHandlerSize ();
640 return gcSmiHandlerSize
;
644 Install the SMI handler for the CPU specified by CpuIndex. This function
645 is called by the CPU that was elected as monarch during System Management
648 @param[in] CpuIndex The index of the CPU to install the custom SMI handler.
649 The value must be between 0 and the NumberOfCpus field
650 in the System Management System Table (SMST).
651 @param[in] SmBase The SMBASE address for the CPU specified by CpuIndex.
652 @param[in] SmiStack The stack to use when an SMI is processed by the
653 the CPU specified by CpuIndex.
654 @param[in] StackSize The size, in bytes, if the stack used when an SMI is
655 processed by the CPU specified by CpuIndex.
656 @param[in] GdtBase The base address of the GDT to use when an SMI is
657 processed by the CPU specified by CpuIndex.
658 @param[in] GdtSize The size, in bytes, of the GDT used when an SMI is
659 processed by the CPU specified by CpuIndex.
660 @param[in] IdtBase The base address of the IDT to use when an SMI is
661 processed by the CPU specified by CpuIndex.
662 @param[in] IdtSize The size, in bytes, of the IDT used when an SMI is
663 processed by the CPU specified by CpuIndex.
664 @param[in] Cr3 The base address of the page tables to use when an SMI
665 is processed by the CPU specified by CpuIndex.
681 PROCESSOR_SMM_DESCRIPTOR
*Psd
;
685 // Initialize PROCESSOR_SMM_DESCRIPTOR
687 Psd
= (PROCESSOR_SMM_DESCRIPTOR
*)(VOID
*)((UINTN
)SmBase
+ SMM_PSD_OFFSET
);
688 CopyMem (Psd
, &gcPsd
, sizeof (gcPsd
));
689 Psd
->SmmGdtPtr
= (UINT64
)GdtBase
;
690 Psd
->SmmGdtSize
= (UINT32
)GdtSize
;
692 if (SmmCpuFeaturesGetSmiHandlerSize () != 0) {
694 // Install SMI handler provided by library
696 SmmCpuFeaturesInstallSmiHandler (
710 InitShadowStack (CpuIndex
, (VOID
*)((UINTN
)SmiStack
+ StackSize
));
713 // Initialize values in template before copy
715 CpuSmiStack
= (UINT32
)((UINTN
)SmiStack
+ StackSize
- sizeof (UINTN
));
716 PatchInstructionX86 (gPatchSmiStack
, CpuSmiStack
, 4);
717 PatchInstructionX86 (gPatchSmiCr3
, Cr3
, 4);
718 PatchInstructionX86 (gPatchSmbase
, SmBase
, 4);
719 gSmiHandlerIdtr
.Base
= IdtBase
;
720 gSmiHandlerIdtr
.Limit
= (UINT16
)(IdtSize
- 1);
723 // Set the value at the top of the CPU stack to the CPU Index
725 *(UINTN
*)(UINTN
)CpuSmiStack
= CpuIndex
;
728 // Copy template to CPU specific SMI handler location
731 (VOID
*)((UINTN
)SmBase
+ SMM_HANDLER_OFFSET
),
732 (VOID
*)gcSmiHandlerTemplate
,