2 Provides services to access SMRAM Save State Map
4 Copyright (c) 2010 - 2017, 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>
26 #include "PiSmmCpuDxeSmm.h"
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
;
52 extern CONST PROCESSOR_SMM_DESCRIPTOR gcPsd
;
55 // EFER register LMA bit
60 /// Macro used to simplify the lookup table entries of type CPU_SMM_SAVE_STATE_LOOKUP_ENTRY
62 #define SMM_CPU_OFFSET(Field) OFFSET_OF (SMRAM_SAVE_STATE_MAP, Field)
65 /// Macro used to simplify the lookup table entries of type CPU_SMM_SAVE_STATE_REGISTER_RANGE
67 #define SMM_REGISTER_RANGE(Start, End) { Start, End, End - Start + 1 }
70 /// Structure used to describe a range of registers
73 EFI_SMM_SAVE_STATE_REGISTER Start
;
74 EFI_SMM_SAVE_STATE_REGISTER End
;
76 } CPU_SMM_SAVE_STATE_REGISTER_RANGE
;
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
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
95 } CPU_SMM_SAVE_STATE_LOOKUP_ENTRY
;
98 /// Structure used to build a lookup table for the IOMisc width information
102 EFI_SMM_SAVE_STATE_IO_WIDTH IoWidth
;
103 } CPU_SMM_SAVE_STATE_IO_WIDTH
;
106 /// Variables from SMI Handler
108 extern UINT32 gSmbase
;
109 extern volatile UINT32 gSmiStack
;
110 extern UINT32 gSmiCr3
;
111 extern volatile UINT8 gcSmiHandlerTemplate
[];
112 extern CONST UINT16 gcSmiHandlerSize
;
115 // Variables used by SMI Handler
117 IA32_DESCRIPTOR gSmiHandlerIdtr
;
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
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 }
131 /// Lookup table used to retrieve the widths and offsets associated with each
132 /// supported EFI_SMM_SAVE_STATE_REGISTER value
134 CONST CPU_SMM_SAVE_STATE_LOOKUP_ENTRY mSmmCpuWidthOffset
[] = {
135 {0, 0, 0, 0, 0, FALSE
}, // Reserved
138 // Internally defined CPU Save State Registers. Not defined in PI SMM CPU Protocol.
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
145 // CPU Save State registers defined in PI SMM CPU Protocol.
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
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
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
190 /// Lookup table for the IOMisc width information
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
204 /// Lookup table for the IOMisc type information
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
226 /// The mode of the CPU at the time an SMI occurs
228 UINT8 mSmmSaveStateRegisterLma
;
231 Read information from the CPU save state.
233 @param Register Specifies the CPU register to read form the save state.
235 @retval 0 Register is not valid
236 @retval >0 Index into mSmmCpuWidthOffset[] associated with Register
241 IN EFI_SMM_SAVE_STATE_REGISTER Register
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
;
251 Offset
+= mSmmCpuRegisterRanges
[Index
].Length
;
257 Read a CPU Save State register on the target processor.
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.
262 This function supports reading a CPU Save State register in SMBase relocation handler.
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.
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.
275 ReadSaveStateRegisterByIndex (
277 IN UINTN RegisterIndex
,
282 SMRAM_SAVE_STATE_MAP
*CpuSaveState
;
284 if (RegisterIndex
== 0) {
285 return EFI_NOT_FOUND
;
288 CpuSaveState
= gSmst
->CpuSaveState
[CpuIndex
];
290 if (mSmmSaveStateRegisterLma
== EFI_SMM_SAVE_STATE_REGISTER_LMA_32BIT
) {
292 // If 32-bit mode width is zero, then the specified register can not be accessed
294 if (mSmmCpuWidthOffset
[RegisterIndex
].Width32
== 0) {
295 return EFI_NOT_FOUND
;
299 // If Width is bigger than the 32-bit mode width, then the specified register can not be accessed
301 if (Width
> mSmmCpuWidthOffset
[RegisterIndex
].Width32
) {
302 return EFI_INVALID_PARAMETER
;
306 // Write return buffer
308 ASSERT(CpuSaveState
!= NULL
);
309 CopyMem(Buffer
, (UINT8
*)CpuSaveState
+ mSmmCpuWidthOffset
[RegisterIndex
].Offset32
, Width
);
312 // If 64-bit mode width is zero, then the specified register can not be accessed
314 if (mSmmCpuWidthOffset
[RegisterIndex
].Width64
== 0) {
315 return EFI_NOT_FOUND
;
319 // If Width is bigger than the 64-bit mode width, then the specified register can not be accessed
321 if (Width
> mSmmCpuWidthOffset
[RegisterIndex
].Width64
) {
322 return EFI_INVALID_PARAMETER
;
326 // Write lower 32-bits of return buffer
328 CopyMem(Buffer
, (UINT8
*)CpuSaveState
+ mSmmCpuWidthOffset
[RegisterIndex
].Offset64Lo
, MIN(4, Width
));
331 // Write upper 32-bits of return buffer
333 CopyMem((UINT8
*)Buffer
+ 4, (UINT8
*)CpuSaveState
+ mSmmCpuWidthOffset
[RegisterIndex
].Offset64Hi
, Width
- 4);
340 Read a CPU Save State register on the target processor.
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.
345 This function supports reading a CPU Save State register in SMBase relocation handler.
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.
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.
359 ReadSaveStateRegister (
361 IN EFI_SMM_SAVE_STATE_REGISTER Register
,
367 SMRAM_SAVE_STATE_IOMISC IoMisc
;
368 EFI_SMM_SAVE_STATE_IO_INFO
*IoInfo
;
372 // Check for special EFI_SMM_SAVE_STATE_REGISTER_LMA
374 if (Register
== EFI_SMM_SAVE_STATE_REGISTER_LMA
) {
376 // Only byte access is supported for this register
379 return EFI_INVALID_PARAMETER
;
382 *(UINT8
*)Buffer
= mSmmSaveStateRegisterLma
;
388 // Check for special EFI_SMM_SAVE_STATE_REGISTER_IO
390 if (Register
== EFI_SMM_SAVE_STATE_REGISTER_IO
) {
392 // Get SMM Revision ID
394 ReadSaveStateRegisterByIndex (CpuIndex
, SMM_SAVE_STATE_REGISTER_SMMREVID_INDEX
, sizeof(SmmRevId
), &SmmRevId
);
397 // See if the CPU supports the IOMisc register in the save state
399 if (SmmRevId
< SMRAM_SAVE_STATE_MIN_REV_ID_IOMISC
) {
400 return EFI_NOT_FOUND
;
404 // Get the IOMisc register value
406 ReadSaveStateRegisterByIndex (CpuIndex
, SMM_SAVE_STATE_REGISTER_IOMISC_INDEX
, sizeof(IoMisc
.Uint32
), &IoMisc
.Uint32
);
409 // Check for the SMI_FLAG in IOMisc
411 if (IoMisc
.Bits
.SmiFlag
== 0) {
412 return EFI_NOT_FOUND
;
416 // Compute index for the I/O Length and I/O Type lookup tables
418 if (mSmmCpuIoWidth
[IoMisc
.Bits
.Length
].Width
== 0 || mSmmCpuIoType
[IoMisc
.Bits
.Type
] == 0) {
419 return EFI_NOT_FOUND
;
423 // Zero the IoInfo structure that will be returned in Buffer
425 IoInfo
= (EFI_SMM_SAVE_STATE_IO_INFO
*)Buffer
;
426 ZeroMem (IoInfo
, sizeof(EFI_SMM_SAVE_STATE_IO_INFO
));
429 // Use lookup tables to help fill in all the fields of the IoInfo structure
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
);
438 ReadSaveStateRegisterByIndex(CpuIndex
, SMM_SAVE_STATE_REGISTER_IOMEMADDR_INDEX
, sizeof(IoMemAddr
), &IoMemAddr
);
439 CopyMem(&IoInfo
->IoData
, IoMemAddr
, mSmmCpuIoWidth
[IoMisc
.Bits
.Length
].Width
);
445 // Convert Register to a register lookup table index
447 return ReadSaveStateRegisterByIndex (CpuIndex
, GetRegisterIndex (Register
), Width
, Buffer
);
451 Write value to a CPU Save State register on the target processor.
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.
456 This function supports writing a CPU Save State register in SMBase relocation handler.
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.
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.
470 WriteSaveStateRegister (
472 IN EFI_SMM_SAVE_STATE_REGISTER Register
,
474 IN CONST VOID
*Buffer
478 SMRAM_SAVE_STATE_MAP
*CpuSaveState
;
481 // Writes to EFI_SMM_SAVE_STATE_REGISTER_LMA are ignored
483 if (Register
== EFI_SMM_SAVE_STATE_REGISTER_LMA
) {
488 // Writes to EFI_SMM_SAVE_STATE_REGISTER_IO are not supported
490 if (Register
== EFI_SMM_SAVE_STATE_REGISTER_IO
) {
491 return EFI_NOT_FOUND
;
495 // Convert Register to a register lookup table index
497 RegisterIndex
= GetRegisterIndex (Register
);
498 if (RegisterIndex
== 0) {
499 return EFI_NOT_FOUND
;
502 CpuSaveState
= gSmst
->CpuSaveState
[CpuIndex
];
505 // Do not write non-writable SaveState, because it will cause exception.
507 if (!mSmmCpuWidthOffset
[RegisterIndex
].Writeable
) {
508 return EFI_UNSUPPORTED
;
514 if (mSmmSaveStateRegisterLma
== EFI_SMM_SAVE_STATE_REGISTER_LMA_32BIT
) {
516 // If 32-bit mode width is zero, then the specified register can not be accessed
518 if (mSmmCpuWidthOffset
[RegisterIndex
].Width32
== 0) {
519 return EFI_NOT_FOUND
;
523 // If Width is bigger than the 32-bit mode width, then the specified register can not be accessed
525 if (Width
> mSmmCpuWidthOffset
[RegisterIndex
].Width32
) {
526 return EFI_INVALID_PARAMETER
;
529 // Write SMM State register
531 ASSERT (CpuSaveState
!= NULL
);
532 CopyMem((UINT8
*)CpuSaveState
+ mSmmCpuWidthOffset
[RegisterIndex
].Offset32
, Buffer
, Width
);
535 // If 64-bit mode width is zero, then the specified register can not be accessed
537 if (mSmmCpuWidthOffset
[RegisterIndex
].Width64
== 0) {
538 return EFI_NOT_FOUND
;
542 // If Width is bigger than the 64-bit mode width, then the specified register can not be accessed
544 if (Width
> mSmmCpuWidthOffset
[RegisterIndex
].Width64
) {
545 return EFI_INVALID_PARAMETER
;
549 // Write lower 32-bits of SMM State register
551 CopyMem((UINT8
*)CpuSaveState
+ mSmmCpuWidthOffset
[RegisterIndex
].Offset64Lo
, Buffer
, MIN (4, Width
));
554 // Write upper 32-bits of SMM State register
556 CopyMem((UINT8
*)CpuSaveState
+ mSmmCpuWidthOffset
[RegisterIndex
].Offset64Hi
, (UINT8
*)Buffer
+ 4, Width
- 4);
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.
568 @param[in] CpuIndex The processor index for the currently
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
577 @retval The value of the original instruction pointer before it was hooked.
584 SMRAM_SAVE_STATE_MAP
*CpuState
,
585 UINT64 NewInstructionPointer32
,
586 UINT64 NewInstructionPointer
589 UINT64 OriginalInstructionPointer
;
591 OriginalInstructionPointer
= SmmCpuFeaturesHookReturnFromSmm (
594 NewInstructionPointer32
,
595 NewInstructionPointer
597 if (OriginalInstructionPointer
!= 0) {
598 return OriginalInstructionPointer
;
601 if (mSmmSaveStateRegisterLma
== EFI_SMM_SAVE_STATE_REGISTER_LMA_32BIT
) {
602 OriginalInstructionPointer
= (UINT64
)CpuState
->x86
._EIP
;
603 CpuState
->x86
._EIP
= (UINT32
)NewInstructionPointer
;
605 // Clear the auto HALT restart flag so the RSM instruction returns
606 // program control to the instruction following the HLT instruction.
608 if ((CpuState
->x86
.AutoHALTRestart
& BIT0
) != 0) {
609 CpuState
->x86
.AutoHALTRestart
&= ~BIT0
;
612 OriginalInstructionPointer
= CpuState
->x64
._RIP
;
613 if ((CpuState
->x64
.IA32_EFER
& LMA
) == 0) {
614 CpuState
->x64
._RIP
= (UINT32
)NewInstructionPointer32
;
616 CpuState
->x64
._RIP
= (UINT32
)NewInstructionPointer
;
619 // Clear the auto HALT restart flag so the RSM instruction returns
620 // program control to the instruction following the HLT instruction.
622 if ((CpuState
->x64
.AutoHALTRestart
& BIT0
) != 0) {
623 CpuState
->x64
.AutoHALTRestart
&= ~BIT0
;
626 return OriginalInstructionPointer
;
630 Get the size of the SMI Handler in bytes.
632 @retval The size, in bytes, of the SMI Handler.
643 Size
= SmmCpuFeaturesGetSmiHandlerSize ();
647 return gcSmiHandlerSize
;
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
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.
688 PROCESSOR_SMM_DESCRIPTOR
*Psd
;
691 // Initialize PROCESSOR_SMM_DESCRIPTOR
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
;
698 if (SmmCpuFeaturesGetSmiHandlerSize () != 0) {
700 // Install SMI handler provided by library
702 SmmCpuFeaturesInstallSmiHandler (
717 // Initialize values in template before copy
719 gSmiStack
= (UINT32
)((UINTN
)SmiStack
+ StackSize
- sizeof (UINTN
));
722 gSmiHandlerIdtr
.Base
= IdtBase
;
723 gSmiHandlerIdtr
.Limit
= (UINT16
)(IdtSize
- 1);
726 // Set the value at the top of the CPU stack to the CPU Index
728 *(UINTN
*)(UINTN
)gSmiStack
= CpuIndex
;
731 // Copy template to CPU specific SMI handler location
734 (VOID
*)((UINTN
)SmBase
+ SMM_HANDLER_OFFSET
),
735 (VOID
*)gcSmiHandlerTemplate
,