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