]> git.proxmox.com Git - mirror_edk2.git/blame - UefiCpuPkg/PiSmmCpuDxeSmm/SmramSaveState.c
UefiCpuPkg: Move AsmRelocateApLoopStart from Mpfuncs.nasm to AmdSev.nasm
[mirror_edk2.git] / UefiCpuPkg / PiSmmCpuDxeSmm / SmramSaveState.c
CommitLineData
529a5a86
MK
1/** @file\r
2Provides services to access SMRAM Save State Map\r
3\r
3eb69b08 4Copyright (c) 2010 - 2019, Intel Corporation. All rights reserved.<BR>\r
0acd8697 5SPDX-License-Identifier: BSD-2-Clause-Patent\r
529a5a86
MK
6\r
7**/\r
8\r
9#include <PiSmm.h>\r
10\r
11#include <Library/SmmCpuFeaturesLib.h>\r
12\r
13#include <Library/BaseLib.h>\r
14#include <Library/BaseMemoryLib.h>\r
15#include <Library/SmmServicesTableLib.h>\r
16#include <Library/DebugLib.h>\r
529a5a86 17\r
f12367a0
MK
18#include "PiSmmCpuDxeSmm.h"\r
19\r
20typedef struct {\r
053e878b
MK
21 UINT64 Signature; // Offset 0x00\r
22 UINT16 Reserved1; // Offset 0x08\r
23 UINT16 Reserved2; // Offset 0x0A\r
24 UINT16 Reserved3; // Offset 0x0C\r
25 UINT16 SmmCs; // Offset 0x0E\r
26 UINT16 SmmDs; // Offset 0x10\r
27 UINT16 SmmSs; // Offset 0x12\r
28 UINT16 SmmOtherSegment; // Offset 0x14\r
29 UINT16 Reserved4; // Offset 0x16\r
30 UINT64 Reserved5; // Offset 0x18\r
31 UINT64 Reserved6; // Offset 0x20\r
32 UINT64 Reserved7; // Offset 0x28\r
33 UINT64 SmmGdtPtr; // Offset 0x30\r
34 UINT32 SmmGdtSize; // Offset 0x38\r
35 UINT32 Reserved8; // Offset 0x3C\r
36 UINT64 Reserved9; // Offset 0x40\r
37 UINT64 Reserved10; // Offset 0x48\r
38 UINT16 Reserved11; // Offset 0x50\r
39 UINT16 Reserved12; // Offset 0x52\r
40 UINT32 Reserved13; // Offset 0x54\r
41 UINT64 Reserved14; // Offset 0x58\r
f12367a0
MK
42} PROCESSOR_SMM_DESCRIPTOR;\r
43\r
053e878b 44extern CONST PROCESSOR_SMM_DESCRIPTOR gcPsd;\r
f12367a0 45\r
529a5a86
MK
46//\r
47// EFER register LMA bit\r
48//\r
053e878b 49#define LMA BIT10\r
529a5a86
MK
50\r
51///\r
52/// Macro used to simplify the lookup table entries of type CPU_SMM_SAVE_STATE_LOOKUP_ENTRY\r
53///\r
053e878b 54#define SMM_CPU_OFFSET(Field) OFFSET_OF (SMRAM_SAVE_STATE_MAP, Field)\r
529a5a86
MK
55\r
56///\r
57/// Macro used to simplify the lookup table entries of type CPU_SMM_SAVE_STATE_REGISTER_RANGE\r
58///\r
053e878b 59#define SMM_REGISTER_RANGE(Start, End) { Start, End, End - Start + 1 }\r
529a5a86
MK
60\r
61///\r
62/// Structure used to describe a range of registers\r
63///\r
64typedef struct {\r
053e878b
MK
65 EFI_SMM_SAVE_STATE_REGISTER Start;\r
66 EFI_SMM_SAVE_STATE_REGISTER End;\r
67 UINTN Length;\r
529a5a86
MK
68} CPU_SMM_SAVE_STATE_REGISTER_RANGE;\r
69\r
70///\r
71/// Structure used to build a lookup table to retrieve the widths and offsets\r
72/// associated with each supported EFI_SMM_SAVE_STATE_REGISTER value\r
73///\r
74\r
053e878b
MK
75#define SMM_SAVE_STATE_REGISTER_SMMREVID_INDEX 1\r
76#define SMM_SAVE_STATE_REGISTER_IOMISC_INDEX 2\r
77#define SMM_SAVE_STATE_REGISTER_IOMEMADDR_INDEX 3\r
78#define SMM_SAVE_STATE_REGISTER_MAX_INDEX 4\r
529a5a86
MK
79\r
80typedef struct {\r
053e878b
MK
81 UINT8 Width32;\r
82 UINT8 Width64;\r
83 UINT16 Offset32;\r
84 UINT16 Offset64Lo;\r
85 UINT16 Offset64Hi;\r
86 BOOLEAN Writeable;\r
529a5a86
MK
87} CPU_SMM_SAVE_STATE_LOOKUP_ENTRY;\r
88\r
89///\r
90/// Structure used to build a lookup table for the IOMisc width information\r
91///\r
92typedef struct {\r
053e878b
MK
93 UINT8 Width;\r
94 EFI_SMM_SAVE_STATE_IO_WIDTH IoWidth;\r
529a5a86
MK
95} CPU_SMM_SAVE_STATE_IO_WIDTH;\r
96\r
97///\r
98/// Variables from SMI Handler\r
99///\r
053e878b
MK
100X86_ASSEMBLY_PATCH_LABEL gPatchSmbase;\r
101X86_ASSEMBLY_PATCH_LABEL gPatchSmiStack;\r
102X86_ASSEMBLY_PATCH_LABEL gPatchSmiCr3;\r
103extern volatile UINT8 gcSmiHandlerTemplate[];\r
104extern CONST UINT16 gcSmiHandlerSize;\r
529a5a86
MK
105\r
106//\r
107// Variables used by SMI Handler\r
108//\r
109IA32_DESCRIPTOR gSmiHandlerIdtr;\r
110\r
111///\r
112/// Table used by GetRegisterIndex() to convert an EFI_SMM_SAVE_STATE_REGISTER\r
113/// value to an index into a table of type CPU_SMM_SAVE_STATE_LOOKUP_ENTRY\r
114///\r
053e878b 115CONST CPU_SMM_SAVE_STATE_REGISTER_RANGE mSmmCpuRegisterRanges[] = {\r
529a5a86
MK
116 SMM_REGISTER_RANGE (EFI_SMM_SAVE_STATE_REGISTER_GDTBASE, EFI_SMM_SAVE_STATE_REGISTER_LDTINFO),\r
117 SMM_REGISTER_RANGE (EFI_SMM_SAVE_STATE_REGISTER_ES, EFI_SMM_SAVE_STATE_REGISTER_RIP),\r
118 SMM_REGISTER_RANGE (EFI_SMM_SAVE_STATE_REGISTER_RFLAGS, EFI_SMM_SAVE_STATE_REGISTER_CR4),\r
053e878b 119 { (EFI_SMM_SAVE_STATE_REGISTER)0, (EFI_SMM_SAVE_STATE_REGISTER)0, 0}\r
529a5a86
MK
120};\r
121\r
122///\r
123/// Lookup table used to retrieve the widths and offsets associated with each\r
124/// supported EFI_SMM_SAVE_STATE_REGISTER value\r
125///\r
053e878b
MK
126CONST CPU_SMM_SAVE_STATE_LOOKUP_ENTRY mSmmCpuWidthOffset[] = {\r
127 { 0, 0, 0, 0, 0, FALSE }, // Reserved\r
529a5a86
MK
128\r
129 //\r
130 // Internally defined CPU Save State Registers. Not defined in PI SMM CPU Protocol.\r
131 //\r
053e878b
MK
132 { 4, 4, SMM_CPU_OFFSET (x86.SMMRevId), SMM_CPU_OFFSET (x64.SMMRevId), 0, FALSE }, // SMM_SAVE_STATE_REGISTER_SMMREVID_INDEX = 1\r
133 { 4, 4, SMM_CPU_OFFSET (x86.IOMisc), SMM_CPU_OFFSET (x64.IOMisc), 0, FALSE }, // SMM_SAVE_STATE_REGISTER_IOMISC_INDEX = 2\r
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\r
529a5a86
MK
135\r
136 //\r
137 // CPU Save State registers defined in PI SMM CPU Protocol.\r
138 //\r
053e878b
MK
139 { 0, 8, 0, SMM_CPU_OFFSET (x64.GdtBaseLoDword), SMM_CPU_OFFSET (x64.GdtBaseHiDword), FALSE }, // EFI_SMM_SAVE_STATE_REGISTER_GDTBASE = 4\r
140 { 0, 8, 0, SMM_CPU_OFFSET (x64.IdtBaseLoDword), SMM_CPU_OFFSET (x64.IdtBaseHiDword), FALSE }, // EFI_SMM_SAVE_STATE_REGISTER_IDTBASE = 5\r
141 { 0, 8, 0, SMM_CPU_OFFSET (x64.LdtBaseLoDword), SMM_CPU_OFFSET (x64.LdtBaseHiDword), FALSE }, // EFI_SMM_SAVE_STATE_REGISTER_LDTBASE = 6\r
142 { 0, 0, 0, 0, 0, FALSE }, // EFI_SMM_SAVE_STATE_REGISTER_GDTLIMIT = 7\r
143 { 0, 0, 0, 0, 0, FALSE }, // EFI_SMM_SAVE_STATE_REGISTER_IDTLIMIT = 8\r
144 { 0, 0, 0, 0, 0, FALSE }, // EFI_SMM_SAVE_STATE_REGISTER_LDTLIMIT = 9\r
145 { 0, 0, 0, 0, 0, FALSE }, // EFI_SMM_SAVE_STATE_REGISTER_LDTINFO = 10\r
146\r
147 { 4, 4, SMM_CPU_OFFSET (x86._ES), SMM_CPU_OFFSET (x64._ES), 0, FALSE }, // EFI_SMM_SAVE_STATE_REGISTER_ES = 20\r
148 { 4, 4, SMM_CPU_OFFSET (x86._CS), SMM_CPU_OFFSET (x64._CS), 0, FALSE }, // EFI_SMM_SAVE_STATE_REGISTER_CS = 21\r
149 { 4, 4, SMM_CPU_OFFSET (x86._SS), SMM_CPU_OFFSET (x64._SS), 0, FALSE }, // EFI_SMM_SAVE_STATE_REGISTER_SS = 22\r
150 { 4, 4, SMM_CPU_OFFSET (x86._DS), SMM_CPU_OFFSET (x64._DS), 0, FALSE }, // EFI_SMM_SAVE_STATE_REGISTER_DS = 23\r
151 { 4, 4, SMM_CPU_OFFSET (x86._FS), SMM_CPU_OFFSET (x64._FS), 0, FALSE }, // EFI_SMM_SAVE_STATE_REGISTER_FS = 24\r
152 { 4, 4, SMM_CPU_OFFSET (x86._GS), SMM_CPU_OFFSET (x64._GS), 0, FALSE }, // EFI_SMM_SAVE_STATE_REGISTER_GS = 25\r
153 { 0, 4, 0, SMM_CPU_OFFSET (x64._LDTR), 0, FALSE }, // EFI_SMM_SAVE_STATE_REGISTER_LDTR_SEL = 26\r
154 { 4, 4, SMM_CPU_OFFSET (x86._TR), SMM_CPU_OFFSET (x64._TR), 0, FALSE }, // EFI_SMM_SAVE_STATE_REGISTER_TR_SEL = 27\r
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\r
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\r
157 { 0, 8, 0, SMM_CPU_OFFSET (x64._R8), SMM_CPU_OFFSET (x64._R8) + 4, TRUE }, // EFI_SMM_SAVE_STATE_REGISTER_R8 = 30\r
158 { 0, 8, 0, SMM_CPU_OFFSET (x64._R9), SMM_CPU_OFFSET (x64._R9) + 4, TRUE }, // EFI_SMM_SAVE_STATE_REGISTER_R9 = 31\r
159 { 0, 8, 0, SMM_CPU_OFFSET (x64._R10), SMM_CPU_OFFSET (x64._R10) + 4, TRUE }, // EFI_SMM_SAVE_STATE_REGISTER_R10 = 32\r
160 { 0, 8, 0, SMM_CPU_OFFSET (x64._R11), SMM_CPU_OFFSET (x64._R11) + 4, TRUE }, // EFI_SMM_SAVE_STATE_REGISTER_R11 = 33\r
161 { 0, 8, 0, SMM_CPU_OFFSET (x64._R12), SMM_CPU_OFFSET (x64._R12) + 4, TRUE }, // EFI_SMM_SAVE_STATE_REGISTER_R12 = 34\r
162 { 0, 8, 0, SMM_CPU_OFFSET (x64._R13), SMM_CPU_OFFSET (x64._R13) + 4, TRUE }, // EFI_SMM_SAVE_STATE_REGISTER_R13 = 35\r
163 { 0, 8, 0, SMM_CPU_OFFSET (x64._R14), SMM_CPU_OFFSET (x64._R14) + 4, TRUE }, // EFI_SMM_SAVE_STATE_REGISTER_R14 = 36\r
164 { 0, 8, 0, SMM_CPU_OFFSET (x64._R15), SMM_CPU_OFFSET (x64._R15) + 4, TRUE }, // EFI_SMM_SAVE_STATE_REGISTER_R15 = 37\r
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\r
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\r
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\r
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\r
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\r
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\r
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\r
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\r
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\r
174\r
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\r
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\r
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\r
178 { 0, 4, 0, SMM_CPU_OFFSET (x64._CR4), 0, FALSE }, // EFI_SMM_SAVE_STATE_REGISTER_CR4 = 54\r
529a5a86
MK
179};\r
180\r
181///\r
182/// Lookup table for the IOMisc width information\r
183///\r
053e878b 184CONST CPU_SMM_SAVE_STATE_IO_WIDTH mSmmCpuIoWidth[] = {\r
529a5a86
MK
185 { 0, EFI_SMM_SAVE_STATE_IO_WIDTH_UINT8 }, // Undefined = 0\r
186 { 1, EFI_SMM_SAVE_STATE_IO_WIDTH_UINT8 }, // SMM_IO_LENGTH_BYTE = 1\r
187 { 2, EFI_SMM_SAVE_STATE_IO_WIDTH_UINT16 }, // SMM_IO_LENGTH_WORD = 2\r
188 { 0, EFI_SMM_SAVE_STATE_IO_WIDTH_UINT8 }, // Undefined = 3\r
189 { 4, EFI_SMM_SAVE_STATE_IO_WIDTH_UINT32 }, // SMM_IO_LENGTH_DWORD = 4\r
190 { 0, EFI_SMM_SAVE_STATE_IO_WIDTH_UINT8 }, // Undefined = 5\r
191 { 0, EFI_SMM_SAVE_STATE_IO_WIDTH_UINT8 }, // Undefined = 6\r
192 { 0, EFI_SMM_SAVE_STATE_IO_WIDTH_UINT8 } // Undefined = 7\r
193};\r
194\r
195///\r
196/// Lookup table for the IOMisc type information\r
197///\r
053e878b 198CONST EFI_SMM_SAVE_STATE_IO_TYPE mSmmCpuIoType[] = {\r
529a5a86
MK
199 EFI_SMM_SAVE_STATE_IO_TYPE_OUTPUT, // SMM_IO_TYPE_OUT_DX = 0\r
200 EFI_SMM_SAVE_STATE_IO_TYPE_INPUT, // SMM_IO_TYPE_IN_DX = 1\r
201 EFI_SMM_SAVE_STATE_IO_TYPE_STRING, // SMM_IO_TYPE_OUTS = 2\r
202 EFI_SMM_SAVE_STATE_IO_TYPE_STRING, // SMM_IO_TYPE_INS = 3\r
203 (EFI_SMM_SAVE_STATE_IO_TYPE)0, // Undefined = 4\r
204 (EFI_SMM_SAVE_STATE_IO_TYPE)0, // Undefined = 5\r
205 EFI_SMM_SAVE_STATE_IO_TYPE_REP_PREFIX, // SMM_IO_TYPE_REP_OUTS = 6\r
206 EFI_SMM_SAVE_STATE_IO_TYPE_REP_PREFIX, // SMM_IO_TYPE_REP_INS = 7\r
207 EFI_SMM_SAVE_STATE_IO_TYPE_OUTPUT, // SMM_IO_TYPE_OUT_IMMEDIATE = 8\r
208 EFI_SMM_SAVE_STATE_IO_TYPE_INPUT, // SMM_IO_TYPE_OUT_IMMEDIATE = 9\r
209 (EFI_SMM_SAVE_STATE_IO_TYPE)0, // Undefined = 10\r
210 (EFI_SMM_SAVE_STATE_IO_TYPE)0, // Undefined = 11\r
211 (EFI_SMM_SAVE_STATE_IO_TYPE)0, // Undefined = 12\r
212 (EFI_SMM_SAVE_STATE_IO_TYPE)0, // Undefined = 13\r
213 (EFI_SMM_SAVE_STATE_IO_TYPE)0, // Undefined = 14\r
214 (EFI_SMM_SAVE_STATE_IO_TYPE)0 // Undefined = 15\r
215};\r
216\r
217///\r
218/// The mode of the CPU at the time an SMI occurs\r
219///\r
220UINT8 mSmmSaveStateRegisterLma;\r
221\r
222/**\r
223 Read information from the CPU save state.\r
224\r
225 @param Register Specifies the CPU register to read form the save state.\r
226\r
227 @retval 0 Register is not valid\r
228 @retval >0 Index into mSmmCpuWidthOffset[] associated with Register\r
229\r
230**/\r
231UINTN\r
232GetRegisterIndex (\r
233 IN EFI_SMM_SAVE_STATE_REGISTER Register\r
234 )\r
235{\r
236 UINTN Index;\r
237 UINTN Offset;\r
238\r
239 for (Index = 0, Offset = SMM_SAVE_STATE_REGISTER_MAX_INDEX; mSmmCpuRegisterRanges[Index].Length != 0; Index++) {\r
053e878b 240 if ((Register >= mSmmCpuRegisterRanges[Index].Start) && (Register <= mSmmCpuRegisterRanges[Index].End)) {\r
529a5a86
MK
241 return Register - mSmmCpuRegisterRanges[Index].Start + Offset;\r
242 }\r
053e878b 243\r
529a5a86
MK
244 Offset += mSmmCpuRegisterRanges[Index].Length;\r
245 }\r
053e878b 246\r
529a5a86
MK
247 return 0;\r
248}\r
249\r
250/**\r
251 Read a CPU Save State register on the target processor.\r
252\r
253 This function abstracts the differences that whether the CPU Save State register is in the\r
254 IA32 CPU Save State Map or X64 CPU Save State Map.\r
255\r
256 This function supports reading a CPU Save State register in SMBase relocation handler.\r
257\r
258 @param[in] CpuIndex Specifies the zero-based index of the CPU save state.\r
259 @param[in] RegisterIndex Index into mSmmCpuWidthOffset[] look up table.\r
260 @param[in] Width The number of bytes to read from the CPU save state.\r
261 @param[out] Buffer Upon return, this holds the CPU register value read from the save state.\r
262\r
263 @retval EFI_SUCCESS The register was read from Save State.\r
264 @retval EFI_NOT_FOUND The register is not defined for the Save State of Processor.\r
ef62da4f 265 @retval EFI_INVALID_PARAMETER This or Buffer is NULL.\r
529a5a86
MK
266\r
267**/\r
268EFI_STATUS\r
269ReadSaveStateRegisterByIndex (\r
053e878b
MK
270 IN UINTN CpuIndex,\r
271 IN UINTN RegisterIndex,\r
272 IN UINTN Width,\r
273 OUT VOID *Buffer\r
529a5a86
MK
274 )\r
275{\r
276 SMRAM_SAVE_STATE_MAP *CpuSaveState;\r
277\r
278 if (RegisterIndex == 0) {\r
279 return EFI_NOT_FOUND;\r
280 }\r
281\r
282 CpuSaveState = gSmst->CpuSaveState[CpuIndex];\r
283\r
284 if (mSmmSaveStateRegisterLma == EFI_SMM_SAVE_STATE_REGISTER_LMA_32BIT) {\r
285 //\r
286 // If 32-bit mode width is zero, then the specified register can not be accessed\r
287 //\r
288 if (mSmmCpuWidthOffset[RegisterIndex].Width32 == 0) {\r
289 return EFI_NOT_FOUND;\r
290 }\r
291\r
292 //\r
293 // If Width is bigger than the 32-bit mode width, then the specified register can not be accessed\r
294 //\r
295 if (Width > mSmmCpuWidthOffset[RegisterIndex].Width32) {\r
296 return EFI_INVALID_PARAMETER;\r
297 }\r
298\r
299 //\r
300 // Write return buffer\r
301 //\r
053e878b
MK
302 ASSERT (CpuSaveState != NULL);\r
303 CopyMem (Buffer, (UINT8 *)CpuSaveState + mSmmCpuWidthOffset[RegisterIndex].Offset32, Width);\r
529a5a86
MK
304 } else {\r
305 //\r
306 // If 64-bit mode width is zero, then the specified register can not be accessed\r
307 //\r
308 if (mSmmCpuWidthOffset[RegisterIndex].Width64 == 0) {\r
309 return EFI_NOT_FOUND;\r
310 }\r
311\r
312 //\r
313 // If Width is bigger than the 64-bit mode width, then the specified register can not be accessed\r
314 //\r
315 if (Width > mSmmCpuWidthOffset[RegisterIndex].Width64) {\r
316 return EFI_INVALID_PARAMETER;\r
317 }\r
318\r
319 //\r
b1708065 320 // Write at most 4 of the lower bytes of the return buffer\r
529a5a86 321 //\r
053e878b 322 CopyMem (Buffer, (UINT8 *)CpuSaveState + mSmmCpuWidthOffset[RegisterIndex].Offset64Lo, MIN (4, Width));\r
b1708065 323 if (Width > 4) {\r
529a5a86 324 //\r
b1708065 325 // Write at most 4 of the upper bytes of the return buffer\r
529a5a86 326 //\r
053e878b 327 CopyMem ((UINT8 *)Buffer + 4, (UINT8 *)CpuSaveState + mSmmCpuWidthOffset[RegisterIndex].Offset64Hi, Width - 4);\r
529a5a86
MK
328 }\r
329 }\r
053e878b 330\r
529a5a86
MK
331 return EFI_SUCCESS;\r
332}\r
333\r
334/**\r
335 Read a CPU Save State register on the target processor.\r
336\r
337 This function abstracts the differences that whether the CPU Save State register is in the\r
338 IA32 CPU Save State Map or X64 CPU Save State Map.\r
339\r
340 This function supports reading a CPU Save State register in SMBase relocation handler.\r
341\r
342 @param[in] CpuIndex Specifies the zero-based index of the CPU save state.\r
343 @param[in] RegisterIndex Index into mSmmCpuWidthOffset[] look up table.\r
344 @param[in] Width The number of bytes to read from the CPU save state.\r
345 @param[out] Buffer Upon return, this holds the CPU register value read from the save state.\r
346\r
347 @retval EFI_SUCCESS The register was read from Save State.\r
348 @retval EFI_NOT_FOUND The register is not defined for the Save State of Processor.\r
a7d8e28b 349 @retval EFI_INVALID_PARAMETER Buffer is NULL, or Width does not meet requirement per Register type.\r
529a5a86
MK
350\r
351**/\r
352EFI_STATUS\r
353EFIAPI\r
354ReadSaveStateRegister (\r
355 IN UINTN CpuIndex,\r
356 IN EFI_SMM_SAVE_STATE_REGISTER Register,\r
357 IN UINTN Width,\r
358 OUT VOID *Buffer\r
359 )\r
360{\r
361 UINT32 SmmRevId;\r
362 SMRAM_SAVE_STATE_IOMISC IoMisc;\r
363 EFI_SMM_SAVE_STATE_IO_INFO *IoInfo;\r
529a5a86
MK
364\r
365 //\r
366 // Check for special EFI_SMM_SAVE_STATE_REGISTER_LMA\r
367 //\r
368 if (Register == EFI_SMM_SAVE_STATE_REGISTER_LMA) {\r
369 //\r
370 // Only byte access is supported for this register\r
371 //\r
372 if (Width != 1) {\r
373 return EFI_INVALID_PARAMETER;\r
374 }\r
375\r
376 *(UINT8 *)Buffer = mSmmSaveStateRegisterLma;\r
377\r
378 return EFI_SUCCESS;\r
379 }\r
380\r
381 //\r
382 // Check for special EFI_SMM_SAVE_STATE_REGISTER_IO\r
383 //\r
384 if (Register == EFI_SMM_SAVE_STATE_REGISTER_IO) {\r
385 //\r
386 // Get SMM Revision ID\r
387 //\r
053e878b 388 ReadSaveStateRegisterByIndex (CpuIndex, SMM_SAVE_STATE_REGISTER_SMMREVID_INDEX, sizeof (SmmRevId), &SmmRevId);\r
529a5a86
MK
389\r
390 //\r
391 // See if the CPU supports the IOMisc register in the save state\r
392 //\r
393 if (SmmRevId < SMRAM_SAVE_STATE_MIN_REV_ID_IOMISC) {\r
394 return EFI_NOT_FOUND;\r
395 }\r
396\r
397 //\r
398 // Get the IOMisc register value\r
399 //\r
053e878b 400 ReadSaveStateRegisterByIndex (CpuIndex, SMM_SAVE_STATE_REGISTER_IOMISC_INDEX, sizeof (IoMisc.Uint32), &IoMisc.Uint32);\r
529a5a86
MK
401\r
402 //\r
403 // Check for the SMI_FLAG in IOMisc\r
404 //\r
405 if (IoMisc.Bits.SmiFlag == 0) {\r
406 return EFI_NOT_FOUND;\r
407 }\r
408\r
cf574f0a
SZ
409 //\r
410 // Only support IN/OUT, but not INS/OUTS/REP INS/REP OUTS.\r
411 //\r
412 if ((mSmmCpuIoType[IoMisc.Bits.Type] != EFI_SMM_SAVE_STATE_IO_TYPE_INPUT) &&\r
053e878b
MK
413 (mSmmCpuIoType[IoMisc.Bits.Type] != EFI_SMM_SAVE_STATE_IO_TYPE_OUTPUT))\r
414 {\r
cf574f0a
SZ
415 return EFI_NOT_FOUND;\r
416 }\r
417\r
529a5a86
MK
418 //\r
419 // Compute index for the I/O Length and I/O Type lookup tables\r
420 //\r
053e878b 421 if ((mSmmCpuIoWidth[IoMisc.Bits.Length].Width == 0) || (mSmmCpuIoType[IoMisc.Bits.Type] == 0)) {\r
529a5a86
MK
422 return EFI_NOT_FOUND;\r
423 }\r
424\r
a7d8e28b
KQ
425 //\r
426 // Make sure the incoming buffer is large enough to hold IoInfo before accessing\r
427 //\r
428 if (Width < sizeof (EFI_SMM_SAVE_STATE_IO_INFO)) {\r
429 return EFI_INVALID_PARAMETER;\r
430 }\r
431\r
529a5a86
MK
432 //\r
433 // Zero the IoInfo structure that will be returned in Buffer\r
434 //\r
435 IoInfo = (EFI_SMM_SAVE_STATE_IO_INFO *)Buffer;\r
053e878b 436 ZeroMem (IoInfo, sizeof (EFI_SMM_SAVE_STATE_IO_INFO));\r
529a5a86
MK
437\r
438 //\r
439 // Use lookup tables to help fill in all the fields of the IoInfo structure\r
440 //\r
053e878b 441 IoInfo->IoPort = (UINT16)IoMisc.Bits.Port;\r
529a5a86 442 IoInfo->IoWidth = mSmmCpuIoWidth[IoMisc.Bits.Length].IoWidth;\r
053e878b 443 IoInfo->IoType = mSmmCpuIoType[IoMisc.Bits.Type];\r
cf574f0a 444 ReadSaveStateRegister (CpuIndex, EFI_SMM_SAVE_STATE_REGISTER_RAX, mSmmCpuIoWidth[IoMisc.Bits.Length].Width, &IoInfo->IoData);\r
529a5a86
MK
445 return EFI_SUCCESS;\r
446 }\r
447\r
448 //\r
449 // Convert Register to a register lookup table index\r
450 //\r
451 return ReadSaveStateRegisterByIndex (CpuIndex, GetRegisterIndex (Register), Width, Buffer);\r
452}\r
453\r
454/**\r
455 Write value to a CPU Save State register on the target processor.\r
456\r
457 This function abstracts the differences that whether the CPU Save State register is in the\r
458 IA32 CPU Save State Map or X64 CPU Save State Map.\r
459\r
460 This function supports writing a CPU Save State register in SMBase relocation handler.\r
461\r
462 @param[in] CpuIndex Specifies the zero-based index of the CPU save state.\r
463 @param[in] RegisterIndex Index into mSmmCpuWidthOffset[] look up table.\r
464 @param[in] Width The number of bytes to read from the CPU save state.\r
465 @param[in] Buffer Upon entry, this holds the new CPU register value.\r
466\r
467 @retval EFI_SUCCESS The register was written to Save State.\r
468 @retval EFI_NOT_FOUND The register is not defined for the Save State of Processor.\r
ef62da4f 469 @retval EFI_INVALID_PARAMETER ProcessorIndex or Width is not correct.\r
529a5a86
MK
470\r
471**/\r
472EFI_STATUS\r
473EFIAPI\r
474WriteSaveStateRegister (\r
475 IN UINTN CpuIndex,\r
476 IN EFI_SMM_SAVE_STATE_REGISTER Register,\r
477 IN UINTN Width,\r
478 IN CONST VOID *Buffer\r
479 )\r
480{\r
481 UINTN RegisterIndex;\r
482 SMRAM_SAVE_STATE_MAP *CpuSaveState;\r
483\r
484 //\r
485 // Writes to EFI_SMM_SAVE_STATE_REGISTER_LMA are ignored\r
486 //\r
487 if (Register == EFI_SMM_SAVE_STATE_REGISTER_LMA) {\r
488 return EFI_SUCCESS;\r
489 }\r
490\r
491 //\r
492 // Writes to EFI_SMM_SAVE_STATE_REGISTER_IO are not supported\r
493 //\r
494 if (Register == EFI_SMM_SAVE_STATE_REGISTER_IO) {\r
495 return EFI_NOT_FOUND;\r
496 }\r
497\r
498 //\r
499 // Convert Register to a register lookup table index\r
500 //\r
501 RegisterIndex = GetRegisterIndex (Register);\r
502 if (RegisterIndex == 0) {\r
503 return EFI_NOT_FOUND;\r
504 }\r
505\r
506 CpuSaveState = gSmst->CpuSaveState[CpuIndex];\r
507\r
508 //\r
509 // Do not write non-writable SaveState, because it will cause exception.\r
510 //\r
511 if (!mSmmCpuWidthOffset[RegisterIndex].Writeable) {\r
512 return EFI_UNSUPPORTED;\r
513 }\r
514\r
515 //\r
516 // Check CPU mode\r
517 //\r
518 if (mSmmSaveStateRegisterLma == EFI_SMM_SAVE_STATE_REGISTER_LMA_32BIT) {\r
519 //\r
520 // If 32-bit mode width is zero, then the specified register can not be accessed\r
521 //\r
522 if (mSmmCpuWidthOffset[RegisterIndex].Width32 == 0) {\r
523 return EFI_NOT_FOUND;\r
524 }\r
525\r
526 //\r
527 // If Width is bigger than the 32-bit mode width, then the specified register can not be accessed\r
528 //\r
529 if (Width > mSmmCpuWidthOffset[RegisterIndex].Width32) {\r
530 return EFI_INVALID_PARAMETER;\r
531 }\r
053e878b 532\r
529a5a86
MK
533 //\r
534 // Write SMM State register\r
535 //\r
536 ASSERT (CpuSaveState != NULL);\r
053e878b 537 CopyMem ((UINT8 *)CpuSaveState + mSmmCpuWidthOffset[RegisterIndex].Offset32, Buffer, Width);\r
529a5a86
MK
538 } else {\r
539 //\r
540 // If 64-bit mode width is zero, then the specified register can not be accessed\r
541 //\r
542 if (mSmmCpuWidthOffset[RegisterIndex].Width64 == 0) {\r
543 return EFI_NOT_FOUND;\r
544 }\r
545\r
546 //\r
547 // If Width is bigger than the 64-bit mode width, then the specified register can not be accessed\r
548 //\r
549 if (Width > mSmmCpuWidthOffset[RegisterIndex].Width64) {\r
550 return EFI_INVALID_PARAMETER;\r
551 }\r
552\r
553 //\r
b1708065 554 // Write at most 4 of the lower bytes of SMM State register\r
529a5a86 555 //\r
053e878b 556 CopyMem ((UINT8 *)CpuSaveState + mSmmCpuWidthOffset[RegisterIndex].Offset64Lo, Buffer, MIN (4, Width));\r
b1708065 557 if (Width > 4) {\r
529a5a86 558 //\r
b1708065 559 // Write at most 4 of the upper bytes of SMM State register\r
529a5a86 560 //\r
053e878b 561 CopyMem ((UINT8 *)CpuSaveState + mSmmCpuWidthOffset[RegisterIndex].Offset64Hi, (UINT8 *)Buffer + 4, Width - 4);\r
529a5a86
MK
562 }\r
563 }\r
053e878b 564\r
529a5a86
MK
565 return EFI_SUCCESS;\r
566}\r
567\r
568/**\r
569 Hook the code executed immediately after an RSM instruction on the currently\r
570 executing CPU. The mode of code executed immediately after RSM must be\r
571 detected, and the appropriate hook must be selected. Always clear the auto\r
572 HALT restart flag if it is set.\r
573\r
574 @param[in] CpuIndex The processor index for the currently\r
575 executing CPU.\r
576 @param[in] CpuState Pointer to SMRAM Save State Map for the\r
577 currently executing CPU.\r
578 @param[in] NewInstructionPointer32 Instruction pointer to use if resuming to\r
579 32-bit mode from 64-bit SMM.\r
580 @param[in] NewInstructionPointer Instruction pointer to use if resuming to\r
581 same mode as SMM.\r
582\r
583 @retval The value of the original instruction pointer before it was hooked.\r
584\r
585**/\r
586UINT64\r
587EFIAPI\r
588HookReturnFromSmm (\r
589 IN UINTN CpuIndex,\r
590 SMRAM_SAVE_STATE_MAP *CpuState,\r
591 UINT64 NewInstructionPointer32,\r
592 UINT64 NewInstructionPointer\r
593 )\r
594{\r
595 UINT64 OriginalInstructionPointer;\r
596\r
597 OriginalInstructionPointer = SmmCpuFeaturesHookReturnFromSmm (\r
598 CpuIndex,\r
599 CpuState,\r
600 NewInstructionPointer32,\r
601 NewInstructionPointer\r
602 );\r
603 if (OriginalInstructionPointer != 0) {\r
604 return OriginalInstructionPointer;\r
605 }\r
606\r
607 if (mSmmSaveStateRegisterLma == EFI_SMM_SAVE_STATE_REGISTER_LMA_32BIT) {\r
608 OriginalInstructionPointer = (UINT64)CpuState->x86._EIP;\r
053e878b 609 CpuState->x86._EIP = (UINT32)NewInstructionPointer;\r
529a5a86
MK
610 //\r
611 // Clear the auto HALT restart flag so the RSM instruction returns\r
612 // program control to the instruction following the HLT instruction.\r
613 //\r
614 if ((CpuState->x86.AutoHALTRestart & BIT0) != 0) {\r
615 CpuState->x86.AutoHALTRestart &= ~BIT0;\r
616 }\r
617 } else {\r
618 OriginalInstructionPointer = CpuState->x64._RIP;\r
619 if ((CpuState->x64.IA32_EFER & LMA) == 0) {\r
620 CpuState->x64._RIP = (UINT32)NewInstructionPointer32;\r
621 } else {\r
622 CpuState->x64._RIP = (UINT32)NewInstructionPointer;\r
623 }\r
053e878b 624\r
529a5a86
MK
625 //\r
626 // Clear the auto HALT restart flag so the RSM instruction returns\r
627 // program control to the instruction following the HLT instruction.\r
628 //\r
629 if ((CpuState->x64.AutoHALTRestart & BIT0) != 0) {\r
630 CpuState->x64.AutoHALTRestart &= ~BIT0;\r
631 }\r
632 }\r
053e878b 633\r
529a5a86
MK
634 return OriginalInstructionPointer;\r
635}\r
636\r
637/**\r
638 Get the size of the SMI Handler in bytes.\r
639\r
640 @retval The size, in bytes, of the SMI Handler.\r
641\r
642**/\r
643UINTN\r
644EFIAPI\r
645GetSmiHandlerSize (\r
646 VOID\r
647 )\r
648{\r
649 UINTN Size;\r
650\r
651 Size = SmmCpuFeaturesGetSmiHandlerSize ();\r
652 if (Size != 0) {\r
653 return Size;\r
654 }\r
053e878b 655\r
529a5a86
MK
656 return gcSmiHandlerSize;\r
657}\r
658\r
659/**\r
660 Install the SMI handler for the CPU specified by CpuIndex. This function\r
661 is called by the CPU that was elected as monarch during System Management\r
662 Mode initialization.\r
663\r
664 @param[in] CpuIndex The index of the CPU to install the custom SMI handler.\r
665 The value must be between 0 and the NumberOfCpus field\r
666 in the System Management System Table (SMST).\r
667 @param[in] SmBase The SMBASE address for the CPU specified by CpuIndex.\r
668 @param[in] SmiStack The stack to use when an SMI is processed by the\r
669 the CPU specified by CpuIndex.\r
670 @param[in] StackSize The size, in bytes, if the stack used when an SMI is\r
671 processed by the CPU specified by CpuIndex.\r
672 @param[in] GdtBase The base address of the GDT to use when an SMI is\r
673 processed by the CPU specified by CpuIndex.\r
674 @param[in] GdtSize The size, in bytes, of the GDT used when an SMI is\r
675 processed by the CPU specified by CpuIndex.\r
676 @param[in] IdtBase The base address of the IDT to use when an SMI is\r
677 processed by the CPU specified by CpuIndex.\r
678 @param[in] IdtSize The size, in bytes, of the IDT used when an SMI is\r
679 processed by the CPU specified by CpuIndex.\r
680 @param[in] Cr3 The base address of the page tables to use when an SMI\r
681 is processed by the CPU specified by CpuIndex.\r
682**/\r
683VOID\r
684EFIAPI\r
685InstallSmiHandler (\r
686 IN UINTN CpuIndex,\r
687 IN UINT32 SmBase,\r
688 IN VOID *SmiStack,\r
689 IN UINTN StackSize,\r
690 IN UINTN GdtBase,\r
691 IN UINTN GdtSize,\r
692 IN UINTN IdtBase,\r
693 IN UINTN IdtSize,\r
694 IN UINT32 Cr3\r
695 )\r
696{\r
f12367a0 697 PROCESSOR_SMM_DESCRIPTOR *Psd;\r
fc504fde 698 UINT32 CpuSmiStack;\r
f12367a0 699\r
a6b7bc7a
MK
700 //\r
701 // Initialize PROCESSOR_SMM_DESCRIPTOR\r
702 //\r
8491e302 703 Psd = (PROCESSOR_SMM_DESCRIPTOR *)(VOID *)((UINTN)SmBase + SMM_PSD_OFFSET);\r
a6b7bc7a 704 CopyMem (Psd, &gcPsd, sizeof (gcPsd));\r
053e878b 705 Psd->SmmGdtPtr = (UINT64)GdtBase;\r
a6b7bc7a
MK
706 Psd->SmmGdtSize = (UINT32)GdtSize;\r
707\r
529a5a86
MK
708 if (SmmCpuFeaturesGetSmiHandlerSize () != 0) {\r
709 //\r
710 // Install SMI handler provided by library\r
711 //\r
712 SmmCpuFeaturesInstallSmiHandler (\r
713 CpuIndex,\r
714 SmBase,\r
715 SmiStack,\r
716 StackSize,\r
717 GdtBase,\r
718 GdtSize,\r
719 IdtBase,\r
720 IdtSize,\r
721 Cr3\r
722 );\r
723 return;\r
724 }\r
725\r
3eb69b08
JY
726 InitShadowStack (CpuIndex, (VOID *)((UINTN)SmiStack + StackSize));\r
727\r
529a5a86
MK
728 //\r
729 // Initialize values in template before copy\r
730 //\r
fc504fde
LE
731 CpuSmiStack = (UINT32)((UINTN)SmiStack + StackSize - sizeof (UINTN));\r
732 PatchInstructionX86 (gPatchSmiStack, CpuSmiStack, 4);\r
c455687f 733 PatchInstructionX86 (gPatchSmiCr3, Cr3, 4);\r
5a1bfda4 734 PatchInstructionX86 (gPatchSmbase, SmBase, 4);\r
529a5a86
MK
735 gSmiHandlerIdtr.Base = IdtBase;\r
736 gSmiHandlerIdtr.Limit = (UINT16)(IdtSize - 1);\r
737\r
738 //\r
739 // Set the value at the top of the CPU stack to the CPU Index\r
740 //\r
053e878b 741 *(UINTN *)(UINTN)CpuSmiStack = CpuIndex;\r
529a5a86
MK
742\r
743 //\r
744 // Copy template to CPU specific SMI handler location\r
745 //\r
746 CopyMem (\r
053e878b
MK
747 (VOID *)((UINTN)SmBase + SMM_HANDLER_OFFSET),\r
748 (VOID *)gcSmiHandlerTemplate,\r
529a5a86
MK
749 gcSmiHandlerSize\r
750 );\r
751}\r