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