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