]> git.proxmox.com Git - mirror_edk2.git/blame - UefiCpuPkg/PiSmmCpuDxeSmm/SmramSaveState.c
UefiCpuPkg: PiSmmCpuDxeSmm: Check buffer size before accessing
[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
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
42} PROCESSOR_SMM_DESCRIPTOR;\r
43\r
44extern CONST PROCESSOR_SMM_DESCRIPTOR gcPsd;\r
45\r
529a5a86
MK
46//\r
47// EFER register LMA bit\r
48//\r
49#define LMA BIT10\r
50\r
51///\r
52/// Macro used to simplify the lookup table entries of type CPU_SMM_SAVE_STATE_LOOKUP_ENTRY\r
53///\r
54#define SMM_CPU_OFFSET(Field) OFFSET_OF (SMRAM_SAVE_STATE_MAP, Field)\r
55\r
56///\r
57/// Macro used to simplify the lookup table entries of type CPU_SMM_SAVE_STATE_REGISTER_RANGE\r
58///\r
59#define SMM_REGISTER_RANGE(Start, End) { Start, End, End - Start + 1 }\r
60\r
61///\r
62/// Structure used to describe a range of registers\r
63///\r
64typedef struct {\r
65 EFI_SMM_SAVE_STATE_REGISTER Start;\r
66 EFI_SMM_SAVE_STATE_REGISTER End;\r
67 UINTN Length;\r
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
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
79\r
80typedef struct {\r
81 UINT8 Width32;\r
82 UINT8 Width64;\r
83 UINT16 Offset32;\r
84 UINT16 Offset64Lo;\r
85 UINT16 Offset64Hi;\r
86 BOOLEAN Writeable;\r
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
93 UINT8 Width;\r
94 EFI_SMM_SAVE_STATE_IO_WIDTH IoWidth;\r
95} CPU_SMM_SAVE_STATE_IO_WIDTH;\r
96\r
97///\r
98/// Variables from SMI Handler\r
99///\r
5a1bfda4 100X86_ASSEMBLY_PATCH_LABEL gPatchSmbase;\r
fc504fde 101X86_ASSEMBLY_PATCH_LABEL gPatchSmiStack;\r
c455687f 102X86_ASSEMBLY_PATCH_LABEL gPatchSmiCr3;\r
5a1bfda4
LE
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
115CONST CPU_SMM_SAVE_STATE_REGISTER_RANGE mSmmCpuRegisterRanges[] = {\r
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
119 { (EFI_SMM_SAVE_STATE_REGISTER)0, (EFI_SMM_SAVE_STATE_REGISTER)0, 0 }\r
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
126CONST CPU_SMM_SAVE_STATE_LOOKUP_ENTRY mSmmCpuWidthOffset[] = {\r
127 {0, 0, 0, 0, 0, FALSE}, // Reserved\r
128\r
129 //\r
130 // Internally defined CPU Save State Registers. Not defined in PI SMM CPU Protocol.\r
131 //\r
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
135\r
136 //\r
137 // CPU Save State registers defined in PI SMM CPU Protocol.\r
138 //\r
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
179};\r
180\r
181///\r
182/// Lookup table for the IOMisc width information\r
183///\r
184CONST CPU_SMM_SAVE_STATE_IO_WIDTH mSmmCpuIoWidth[] = {\r
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
198CONST EFI_SMM_SAVE_STATE_IO_TYPE mSmmCpuIoType[] = {\r
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
240 if (Register >= mSmmCpuRegisterRanges[Index].Start && Register <= mSmmCpuRegisterRanges[Index].End) {\r
241 return Register - mSmmCpuRegisterRanges[Index].Start + Offset;\r
242 }\r
243 Offset += mSmmCpuRegisterRanges[Index].Length;\r
244 }\r
245 return 0;\r
246}\r
247\r
248/**\r
249 Read a CPU Save State register on the target processor.\r
250\r
251 This function abstracts the differences that whether the CPU Save State register is in the\r
252 IA32 CPU Save State Map or X64 CPU Save State Map.\r
253\r
254 This function supports reading a CPU Save State register in SMBase relocation handler.\r
255\r
256 @param[in] CpuIndex Specifies the zero-based index of the CPU save state.\r
257 @param[in] RegisterIndex Index into mSmmCpuWidthOffset[] look up table.\r
258 @param[in] Width The number of bytes to read from the CPU save state.\r
259 @param[out] Buffer Upon return, this holds the CPU register value read from the save state.\r
260\r
261 @retval EFI_SUCCESS The register was read from Save State.\r
262 @retval EFI_NOT_FOUND The register is not defined for the Save State of Processor.\r
ef62da4f 263 @retval EFI_INVALID_PARAMETER This or Buffer is NULL.\r
529a5a86
MK
264\r
265**/\r
266EFI_STATUS\r
267ReadSaveStateRegisterByIndex (\r
268 IN UINTN CpuIndex,\r
269 IN UINTN RegisterIndex,\r
270 IN UINTN Width,\r
271 OUT VOID *Buffer\r
272 )\r
273{\r
274 SMRAM_SAVE_STATE_MAP *CpuSaveState;\r
275\r
276 if (RegisterIndex == 0) {\r
277 return EFI_NOT_FOUND;\r
278 }\r
279\r
280 CpuSaveState = gSmst->CpuSaveState[CpuIndex];\r
281\r
282 if (mSmmSaveStateRegisterLma == EFI_SMM_SAVE_STATE_REGISTER_LMA_32BIT) {\r
283 //\r
284 // If 32-bit mode width is zero, then the specified register can not be accessed\r
285 //\r
286 if (mSmmCpuWidthOffset[RegisterIndex].Width32 == 0) {\r
287 return EFI_NOT_FOUND;\r
288 }\r
289\r
290 //\r
291 // If Width is bigger than the 32-bit mode width, then the specified register can not be accessed\r
292 //\r
293 if (Width > mSmmCpuWidthOffset[RegisterIndex].Width32) {\r
294 return EFI_INVALID_PARAMETER;\r
295 }\r
296\r
297 //\r
298 // Write return buffer\r
299 //\r
300 ASSERT(CpuSaveState != NULL);\r
301 CopyMem(Buffer, (UINT8 *)CpuSaveState + mSmmCpuWidthOffset[RegisterIndex].Offset32, Width);\r
302 } else {\r
303 //\r
304 // If 64-bit mode width is zero, then the specified register can not be accessed\r
305 //\r
306 if (mSmmCpuWidthOffset[RegisterIndex].Width64 == 0) {\r
307 return EFI_NOT_FOUND;\r
308 }\r
309\r
310 //\r
311 // If Width is bigger than the 64-bit mode width, then the specified register can not be accessed\r
312 //\r
313 if (Width > mSmmCpuWidthOffset[RegisterIndex].Width64) {\r
314 return EFI_INVALID_PARAMETER;\r
315 }\r
316\r
317 //\r
318 // Write lower 32-bits of return buffer\r
319 //\r
320 CopyMem(Buffer, (UINT8 *)CpuSaveState + mSmmCpuWidthOffset[RegisterIndex].Offset64Lo, MIN(4, Width));\r
321 if (Width >= 4) {\r
322 //\r
323 // Write upper 32-bits of return buffer\r
324 //\r
325 CopyMem((UINT8 *)Buffer + 4, (UINT8 *)CpuSaveState + mSmmCpuWidthOffset[RegisterIndex].Offset64Hi, Width - 4);\r
326 }\r
327 }\r
328 return EFI_SUCCESS;\r
329}\r
330\r
331/**\r
332 Read a CPU Save State register on the target processor.\r
333\r
334 This function abstracts the differences that whether the CPU Save State register is in the\r
335 IA32 CPU Save State Map or X64 CPU Save State Map.\r
336\r
337 This function supports reading a CPU Save State register in SMBase relocation handler.\r
338\r
339 @param[in] CpuIndex Specifies the zero-based index of the CPU save state.\r
340 @param[in] RegisterIndex Index into mSmmCpuWidthOffset[] look up table.\r
341 @param[in] Width The number of bytes to read from the CPU save state.\r
342 @param[out] Buffer Upon return, this holds the CPU register value read from the save state.\r
343\r
344 @retval EFI_SUCCESS The register was read from Save State.\r
345 @retval EFI_NOT_FOUND The register is not defined for the Save State of Processor.\r
a7d8e28b 346 @retval EFI_INVALID_PARAMETER Buffer is NULL, or Width does not meet requirement per Register type.\r
529a5a86
MK
347\r
348**/\r
349EFI_STATUS\r
350EFIAPI\r
351ReadSaveStateRegister (\r
352 IN UINTN CpuIndex,\r
353 IN EFI_SMM_SAVE_STATE_REGISTER Register,\r
354 IN UINTN Width,\r
355 OUT VOID *Buffer\r
356 )\r
357{\r
358 UINT32 SmmRevId;\r
359 SMRAM_SAVE_STATE_IOMISC IoMisc;\r
360 EFI_SMM_SAVE_STATE_IO_INFO *IoInfo;\r
529a5a86
MK
361\r
362 //\r
363 // Check for special EFI_SMM_SAVE_STATE_REGISTER_LMA\r
364 //\r
365 if (Register == EFI_SMM_SAVE_STATE_REGISTER_LMA) {\r
366 //\r
367 // Only byte access is supported for this register\r
368 //\r
369 if (Width != 1) {\r
370 return EFI_INVALID_PARAMETER;\r
371 }\r
372\r
373 *(UINT8 *)Buffer = mSmmSaveStateRegisterLma;\r
374\r
375 return EFI_SUCCESS;\r
376 }\r
377\r
378 //\r
379 // Check for special EFI_SMM_SAVE_STATE_REGISTER_IO\r
380 //\r
381 if (Register == EFI_SMM_SAVE_STATE_REGISTER_IO) {\r
382 //\r
383 // Get SMM Revision ID\r
384 //\r
385 ReadSaveStateRegisterByIndex (CpuIndex, SMM_SAVE_STATE_REGISTER_SMMREVID_INDEX, sizeof(SmmRevId), &SmmRevId);\r
386\r
387 //\r
388 // See if the CPU supports the IOMisc register in the save state\r
389 //\r
390 if (SmmRevId < SMRAM_SAVE_STATE_MIN_REV_ID_IOMISC) {\r
391 return EFI_NOT_FOUND;\r
392 }\r
393\r
394 //\r
395 // Get the IOMisc register value\r
396 //\r
397 ReadSaveStateRegisterByIndex (CpuIndex, SMM_SAVE_STATE_REGISTER_IOMISC_INDEX, sizeof(IoMisc.Uint32), &IoMisc.Uint32);\r
398\r
399 //\r
400 // Check for the SMI_FLAG in IOMisc\r
401 //\r
402 if (IoMisc.Bits.SmiFlag == 0) {\r
403 return EFI_NOT_FOUND;\r
404 }\r
405\r
cf574f0a
SZ
406 //\r
407 // Only support IN/OUT, but not INS/OUTS/REP INS/REP OUTS.\r
408 //\r
409 if ((mSmmCpuIoType[IoMisc.Bits.Type] != EFI_SMM_SAVE_STATE_IO_TYPE_INPUT) &&\r
410 (mSmmCpuIoType[IoMisc.Bits.Type] != EFI_SMM_SAVE_STATE_IO_TYPE_OUTPUT)) {\r
411 return EFI_NOT_FOUND;\r
412 }\r
413\r
529a5a86
MK
414 //\r
415 // Compute index for the I/O Length and I/O Type lookup tables\r
416 //\r
417 if (mSmmCpuIoWidth[IoMisc.Bits.Length].Width == 0 || mSmmCpuIoType[IoMisc.Bits.Type] == 0) {\r
418 return EFI_NOT_FOUND;\r
419 }\r
420\r
a7d8e28b
KQ
421 //\r
422 // Make sure the incoming buffer is large enough to hold IoInfo before accessing\r
423 //\r
424 if (Width < sizeof (EFI_SMM_SAVE_STATE_IO_INFO)) {\r
425 return EFI_INVALID_PARAMETER;\r
426 }\r
427\r
529a5a86
MK
428 //\r
429 // Zero the IoInfo structure that will be returned in Buffer\r
430 //\r
431 IoInfo = (EFI_SMM_SAVE_STATE_IO_INFO *)Buffer;\r
432 ZeroMem (IoInfo, sizeof(EFI_SMM_SAVE_STATE_IO_INFO));\r
433\r
434 //\r
435 // Use lookup tables to help fill in all the fields of the IoInfo structure\r
436 //\r
437 IoInfo->IoPort = (UINT16)IoMisc.Bits.Port;\r
438 IoInfo->IoWidth = mSmmCpuIoWidth[IoMisc.Bits.Length].IoWidth;\r
439 IoInfo->IoType = mSmmCpuIoType[IoMisc.Bits.Type];\r
cf574f0a 440 ReadSaveStateRegister (CpuIndex, EFI_SMM_SAVE_STATE_REGISTER_RAX, mSmmCpuIoWidth[IoMisc.Bits.Length].Width, &IoInfo->IoData);\r
529a5a86
MK
441 return EFI_SUCCESS;\r
442 }\r
443\r
444 //\r
445 // Convert Register to a register lookup table index\r
446 //\r
447 return ReadSaveStateRegisterByIndex (CpuIndex, GetRegisterIndex (Register), Width, Buffer);\r
448}\r
449\r
450/**\r
451 Write value to a CPU Save State register on the target processor.\r
452\r
453 This function abstracts the differences that whether the CPU Save State register is in the\r
454 IA32 CPU Save State Map or X64 CPU Save State Map.\r
455\r
456 This function supports writing a CPU Save State register in SMBase relocation handler.\r
457\r
458 @param[in] CpuIndex Specifies the zero-based index of the CPU save state.\r
459 @param[in] RegisterIndex Index into mSmmCpuWidthOffset[] look up table.\r
460 @param[in] Width The number of bytes to read from the CPU save state.\r
461 @param[in] Buffer Upon entry, this holds the new CPU register value.\r
462\r
463 @retval EFI_SUCCESS The register was written to Save State.\r
464 @retval EFI_NOT_FOUND The register is not defined for the Save State of Processor.\r
ef62da4f 465 @retval EFI_INVALID_PARAMETER ProcessorIndex or Width is not correct.\r
529a5a86
MK
466\r
467**/\r
468EFI_STATUS\r
469EFIAPI\r
470WriteSaveStateRegister (\r
471 IN UINTN CpuIndex,\r
472 IN EFI_SMM_SAVE_STATE_REGISTER Register,\r
473 IN UINTN Width,\r
474 IN CONST VOID *Buffer\r
475 )\r
476{\r
477 UINTN RegisterIndex;\r
478 SMRAM_SAVE_STATE_MAP *CpuSaveState;\r
479\r
480 //\r
481 // Writes to EFI_SMM_SAVE_STATE_REGISTER_LMA are ignored\r
482 //\r
483 if (Register == EFI_SMM_SAVE_STATE_REGISTER_LMA) {\r
484 return EFI_SUCCESS;\r
485 }\r
486\r
487 //\r
488 // Writes to EFI_SMM_SAVE_STATE_REGISTER_IO are not supported\r
489 //\r
490 if (Register == EFI_SMM_SAVE_STATE_REGISTER_IO) {\r
491 return EFI_NOT_FOUND;\r
492 }\r
493\r
494 //\r
495 // Convert Register to a register lookup table index\r
496 //\r
497 RegisterIndex = GetRegisterIndex (Register);\r
498 if (RegisterIndex == 0) {\r
499 return EFI_NOT_FOUND;\r
500 }\r
501\r
502 CpuSaveState = gSmst->CpuSaveState[CpuIndex];\r
503\r
504 //\r
505 // Do not write non-writable SaveState, because it will cause exception.\r
506 //\r
507 if (!mSmmCpuWidthOffset[RegisterIndex].Writeable) {\r
508 return EFI_UNSUPPORTED;\r
509 }\r
510\r
511 //\r
512 // Check CPU mode\r
513 //\r
514 if (mSmmSaveStateRegisterLma == EFI_SMM_SAVE_STATE_REGISTER_LMA_32BIT) {\r
515 //\r
516 // If 32-bit mode width is zero, then the specified register can not be accessed\r
517 //\r
518 if (mSmmCpuWidthOffset[RegisterIndex].Width32 == 0) {\r
519 return EFI_NOT_FOUND;\r
520 }\r
521\r
522 //\r
523 // If Width is bigger than the 32-bit mode width, then the specified register can not be accessed\r
524 //\r
525 if (Width > mSmmCpuWidthOffset[RegisterIndex].Width32) {\r
526 return EFI_INVALID_PARAMETER;\r
527 }\r
528 //\r
529 // Write SMM State register\r
530 //\r
531 ASSERT (CpuSaveState != NULL);\r
532 CopyMem((UINT8 *)CpuSaveState + mSmmCpuWidthOffset[RegisterIndex].Offset32, Buffer, Width);\r
533 } else {\r
534 //\r
535 // If 64-bit mode width is zero, then the specified register can not be accessed\r
536 //\r
537 if (mSmmCpuWidthOffset[RegisterIndex].Width64 == 0) {\r
538 return EFI_NOT_FOUND;\r
539 }\r
540\r
541 //\r
542 // If Width is bigger than the 64-bit mode width, then the specified register can not be accessed\r
543 //\r
544 if (Width > mSmmCpuWidthOffset[RegisterIndex].Width64) {\r
545 return EFI_INVALID_PARAMETER;\r
546 }\r
547\r
548 //\r
549 // Write lower 32-bits of SMM State register\r
550 //\r
551 CopyMem((UINT8 *)CpuSaveState + mSmmCpuWidthOffset[RegisterIndex].Offset64Lo, Buffer, MIN (4, Width));\r
552 if (Width >= 4) {\r
553 //\r
554 // Write upper 32-bits of SMM State register\r
555 //\r
556 CopyMem((UINT8 *)CpuSaveState + mSmmCpuWidthOffset[RegisterIndex].Offset64Hi, (UINT8 *)Buffer + 4, Width - 4);\r
557 }\r
558 }\r
559 return EFI_SUCCESS;\r
560}\r
561\r
562/**\r
563 Hook the code executed immediately after an RSM instruction on the currently\r
564 executing CPU. The mode of code executed immediately after RSM must be\r
565 detected, and the appropriate hook must be selected. Always clear the auto\r
566 HALT restart flag if it is set.\r
567\r
568 @param[in] CpuIndex The processor index for the currently\r
569 executing CPU.\r
570 @param[in] CpuState Pointer to SMRAM Save State Map for the\r
571 currently executing CPU.\r
572 @param[in] NewInstructionPointer32 Instruction pointer to use if resuming to\r
573 32-bit mode from 64-bit SMM.\r
574 @param[in] NewInstructionPointer Instruction pointer to use if resuming to\r
575 same mode as SMM.\r
576\r
577 @retval The value of the original instruction pointer before it was hooked.\r
578\r
579**/\r
580UINT64\r
581EFIAPI\r
582HookReturnFromSmm (\r
583 IN UINTN CpuIndex,\r
584 SMRAM_SAVE_STATE_MAP *CpuState,\r
585 UINT64 NewInstructionPointer32,\r
586 UINT64 NewInstructionPointer\r
587 )\r
588{\r
589 UINT64 OriginalInstructionPointer;\r
590\r
591 OriginalInstructionPointer = SmmCpuFeaturesHookReturnFromSmm (\r
592 CpuIndex,\r
593 CpuState,\r
594 NewInstructionPointer32,\r
595 NewInstructionPointer\r
596 );\r
597 if (OriginalInstructionPointer != 0) {\r
598 return OriginalInstructionPointer;\r
599 }\r
600\r
601 if (mSmmSaveStateRegisterLma == EFI_SMM_SAVE_STATE_REGISTER_LMA_32BIT) {\r
602 OriginalInstructionPointer = (UINT64)CpuState->x86._EIP;\r
603 CpuState->x86._EIP = (UINT32)NewInstructionPointer;\r
604 //\r
605 // Clear the auto HALT restart flag so the RSM instruction returns\r
606 // program control to the instruction following the HLT instruction.\r
607 //\r
608 if ((CpuState->x86.AutoHALTRestart & BIT0) != 0) {\r
609 CpuState->x86.AutoHALTRestart &= ~BIT0;\r
610 }\r
611 } else {\r
612 OriginalInstructionPointer = CpuState->x64._RIP;\r
613 if ((CpuState->x64.IA32_EFER & LMA) == 0) {\r
614 CpuState->x64._RIP = (UINT32)NewInstructionPointer32;\r
615 } else {\r
616 CpuState->x64._RIP = (UINT32)NewInstructionPointer;\r
617 }\r
618 //\r
619 // Clear the auto HALT restart flag so the RSM instruction returns\r
620 // program control to the instruction following the HLT instruction.\r
621 //\r
622 if ((CpuState->x64.AutoHALTRestart & BIT0) != 0) {\r
623 CpuState->x64.AutoHALTRestart &= ~BIT0;\r
624 }\r
625 }\r
626 return OriginalInstructionPointer;\r
627}\r
628\r
629/**\r
630 Get the size of the SMI Handler in bytes.\r
631\r
632 @retval The size, in bytes, of the SMI Handler.\r
633\r
634**/\r
635UINTN\r
636EFIAPI\r
637GetSmiHandlerSize (\r
638 VOID\r
639 )\r
640{\r
641 UINTN Size;\r
642\r
643 Size = SmmCpuFeaturesGetSmiHandlerSize ();\r
644 if (Size != 0) {\r
645 return Size;\r
646 }\r
647 return gcSmiHandlerSize;\r
648}\r
649\r
650/**\r
651 Install the SMI handler for the CPU specified by CpuIndex. This function\r
652 is called by the CPU that was elected as monarch during System Management\r
653 Mode initialization.\r
654\r
655 @param[in] CpuIndex The index of the CPU to install the custom SMI handler.\r
656 The value must be between 0 and the NumberOfCpus field\r
657 in the System Management System Table (SMST).\r
658 @param[in] SmBase The SMBASE address for the CPU specified by CpuIndex.\r
659 @param[in] SmiStack The stack to use when an SMI is processed by the\r
660 the CPU specified by CpuIndex.\r
661 @param[in] StackSize The size, in bytes, if the stack used when an SMI is\r
662 processed by the CPU specified by CpuIndex.\r
663 @param[in] GdtBase The base address of the GDT to use when an SMI is\r
664 processed by the CPU specified by CpuIndex.\r
665 @param[in] GdtSize The size, in bytes, of the GDT used when an SMI is\r
666 processed by the CPU specified by CpuIndex.\r
667 @param[in] IdtBase The base address of the IDT to use when an SMI is\r
668 processed by the CPU specified by CpuIndex.\r
669 @param[in] IdtSize The size, in bytes, of the IDT used when an SMI is\r
670 processed by the CPU specified by CpuIndex.\r
671 @param[in] Cr3 The base address of the page tables to use when an SMI\r
672 is processed by the CPU specified by CpuIndex.\r
673**/\r
674VOID\r
675EFIAPI\r
676InstallSmiHandler (\r
677 IN UINTN CpuIndex,\r
678 IN UINT32 SmBase,\r
679 IN VOID *SmiStack,\r
680 IN UINTN StackSize,\r
681 IN UINTN GdtBase,\r
682 IN UINTN GdtSize,\r
683 IN UINTN IdtBase,\r
684 IN UINTN IdtSize,\r
685 IN UINT32 Cr3\r
686 )\r
687{\r
f12367a0 688 PROCESSOR_SMM_DESCRIPTOR *Psd;\r
fc504fde 689 UINT32 CpuSmiStack;\r
f12367a0 690\r
a6b7bc7a
MK
691 //\r
692 // Initialize PROCESSOR_SMM_DESCRIPTOR\r
693 //\r
8491e302 694 Psd = (PROCESSOR_SMM_DESCRIPTOR *)(VOID *)((UINTN)SmBase + SMM_PSD_OFFSET);\r
a6b7bc7a
MK
695 CopyMem (Psd, &gcPsd, sizeof (gcPsd));\r
696 Psd->SmmGdtPtr = (UINT64)GdtBase;\r
697 Psd->SmmGdtSize = (UINT32)GdtSize;\r
698\r
529a5a86
MK
699 if (SmmCpuFeaturesGetSmiHandlerSize () != 0) {\r
700 //\r
701 // Install SMI handler provided by library\r
702 //\r
703 SmmCpuFeaturesInstallSmiHandler (\r
704 CpuIndex,\r
705 SmBase,\r
706 SmiStack,\r
707 StackSize,\r
708 GdtBase,\r
709 GdtSize,\r
710 IdtBase,\r
711 IdtSize,\r
712 Cr3\r
713 );\r
714 return;\r
715 }\r
716\r
3eb69b08
JY
717 InitShadowStack (CpuIndex, (VOID *)((UINTN)SmiStack + StackSize));\r
718\r
529a5a86
MK
719 //\r
720 // Initialize values in template before copy\r
721 //\r
fc504fde
LE
722 CpuSmiStack = (UINT32)((UINTN)SmiStack + StackSize - sizeof (UINTN));\r
723 PatchInstructionX86 (gPatchSmiStack, CpuSmiStack, 4);\r
c455687f 724 PatchInstructionX86 (gPatchSmiCr3, Cr3, 4);\r
5a1bfda4 725 PatchInstructionX86 (gPatchSmbase, SmBase, 4);\r
529a5a86
MK
726 gSmiHandlerIdtr.Base = IdtBase;\r
727 gSmiHandlerIdtr.Limit = (UINT16)(IdtSize - 1);\r
728\r
729 //\r
730 // Set the value at the top of the CPU stack to the CPU Index\r
731 //\r
fc504fde 732 *(UINTN*)(UINTN)CpuSmiStack = CpuIndex;\r
529a5a86
MK
733\r
734 //\r
735 // Copy template to CPU specific SMI handler location\r
736 //\r
737 CopyMem (\r
8491e302 738 (VOID*)((UINTN)SmBase + SMM_HANDLER_OFFSET),\r
529a5a86
MK
739 (VOID*)gcSmiHandlerTemplate,\r
740 gcSmiHandlerSize\r
741 );\r
742}\r