]> git.proxmox.com Git - mirror_edk2.git/blob - UefiCpuPkg/PiSmmCpuDxeSmm/SmramSaveState.c
UefiCpuPkg: Replace BSD License with BSD+Patent License
[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 VOID *IoMemAddr;
364
365 //
366 // Check for special EFI_SMM_SAVE_STATE_REGISTER_LMA
367 //
368 if (Register == EFI_SMM_SAVE_STATE_REGISTER_LMA) {
369 //
370 // Only byte access is supported for this register
371 //
372 if (Width != 1) {
373 return EFI_INVALID_PARAMETER;
374 }
375
376 *(UINT8 *)Buffer = mSmmSaveStateRegisterLma;
377
378 return EFI_SUCCESS;
379 }
380
381 //
382 // Check for special EFI_SMM_SAVE_STATE_REGISTER_IO
383 //
384 if (Register == EFI_SMM_SAVE_STATE_REGISTER_IO) {
385 //
386 // Get SMM Revision ID
387 //
388 ReadSaveStateRegisterByIndex (CpuIndex, SMM_SAVE_STATE_REGISTER_SMMREVID_INDEX, sizeof(SmmRevId), &SmmRevId);
389
390 //
391 // See if the CPU supports the IOMisc register in the save state
392 //
393 if (SmmRevId < SMRAM_SAVE_STATE_MIN_REV_ID_IOMISC) {
394 return EFI_NOT_FOUND;
395 }
396
397 //
398 // Get the IOMisc register value
399 //
400 ReadSaveStateRegisterByIndex (CpuIndex, SMM_SAVE_STATE_REGISTER_IOMISC_INDEX, sizeof(IoMisc.Uint32), &IoMisc.Uint32);
401
402 //
403 // Check for the SMI_FLAG in IOMisc
404 //
405 if (IoMisc.Bits.SmiFlag == 0) {
406 return EFI_NOT_FOUND;
407 }
408
409 //
410 // Compute index for the I/O Length and I/O Type lookup tables
411 //
412 if (mSmmCpuIoWidth[IoMisc.Bits.Length].Width == 0 || mSmmCpuIoType[IoMisc.Bits.Type] == 0) {
413 return EFI_NOT_FOUND;
414 }
415
416 //
417 // Zero the IoInfo structure that will be returned in Buffer
418 //
419 IoInfo = (EFI_SMM_SAVE_STATE_IO_INFO *)Buffer;
420 ZeroMem (IoInfo, sizeof(EFI_SMM_SAVE_STATE_IO_INFO));
421
422 //
423 // Use lookup tables to help fill in all the fields of the IoInfo structure
424 //
425 IoInfo->IoPort = (UINT16)IoMisc.Bits.Port;
426 IoInfo->IoWidth = mSmmCpuIoWidth[IoMisc.Bits.Length].IoWidth;
427 IoInfo->IoType = mSmmCpuIoType[IoMisc.Bits.Type];
428 if (IoInfo->IoType == EFI_SMM_SAVE_STATE_IO_TYPE_INPUT || IoInfo->IoType == EFI_SMM_SAVE_STATE_IO_TYPE_OUTPUT) {
429 ReadSaveStateRegister (CpuIndex, EFI_SMM_SAVE_STATE_REGISTER_RAX, mSmmCpuIoWidth[IoMisc.Bits.Length].Width, &IoInfo->IoData);
430 }
431 else {
432 ReadSaveStateRegisterByIndex(CpuIndex, SMM_SAVE_STATE_REGISTER_IOMEMADDR_INDEX, sizeof(IoMemAddr), &IoMemAddr);
433 CopyMem(&IoInfo->IoData, IoMemAddr, mSmmCpuIoWidth[IoMisc.Bits.Length].Width);
434 }
435 return EFI_SUCCESS;
436 }
437
438 //
439 // Convert Register to a register lookup table index
440 //
441 return ReadSaveStateRegisterByIndex (CpuIndex, GetRegisterIndex (Register), Width, Buffer);
442 }
443
444 /**
445 Write value to a CPU Save State register on the target processor.
446
447 This function abstracts the differences that whether the CPU Save State register is in the
448 IA32 CPU Save State Map or X64 CPU Save State Map.
449
450 This function supports writing a CPU Save State register in SMBase relocation handler.
451
452 @param[in] CpuIndex Specifies the zero-based index of the CPU save state.
453 @param[in] RegisterIndex Index into mSmmCpuWidthOffset[] look up table.
454 @param[in] Width The number of bytes to read from the CPU save state.
455 @param[in] Buffer Upon entry, this holds the new CPU register value.
456
457 @retval EFI_SUCCESS The register was written to Save State.
458 @retval EFI_NOT_FOUND The register is not defined for the Save State of Processor.
459 @retval EFI_INVALID_PARAMTER ProcessorIndex or Width is not correct.
460
461 **/
462 EFI_STATUS
463 EFIAPI
464 WriteSaveStateRegister (
465 IN UINTN CpuIndex,
466 IN EFI_SMM_SAVE_STATE_REGISTER Register,
467 IN UINTN Width,
468 IN CONST VOID *Buffer
469 )
470 {
471 UINTN RegisterIndex;
472 SMRAM_SAVE_STATE_MAP *CpuSaveState;
473
474 //
475 // Writes to EFI_SMM_SAVE_STATE_REGISTER_LMA are ignored
476 //
477 if (Register == EFI_SMM_SAVE_STATE_REGISTER_LMA) {
478 return EFI_SUCCESS;
479 }
480
481 //
482 // Writes to EFI_SMM_SAVE_STATE_REGISTER_IO are not supported
483 //
484 if (Register == EFI_SMM_SAVE_STATE_REGISTER_IO) {
485 return EFI_NOT_FOUND;
486 }
487
488 //
489 // Convert Register to a register lookup table index
490 //
491 RegisterIndex = GetRegisterIndex (Register);
492 if (RegisterIndex == 0) {
493 return EFI_NOT_FOUND;
494 }
495
496 CpuSaveState = gSmst->CpuSaveState[CpuIndex];
497
498 //
499 // Do not write non-writable SaveState, because it will cause exception.
500 //
501 if (!mSmmCpuWidthOffset[RegisterIndex].Writeable) {
502 return EFI_UNSUPPORTED;
503 }
504
505 //
506 // Check CPU mode
507 //
508 if (mSmmSaveStateRegisterLma == EFI_SMM_SAVE_STATE_REGISTER_LMA_32BIT) {
509 //
510 // If 32-bit mode width is zero, then the specified register can not be accessed
511 //
512 if (mSmmCpuWidthOffset[RegisterIndex].Width32 == 0) {
513 return EFI_NOT_FOUND;
514 }
515
516 //
517 // If Width is bigger than the 32-bit mode width, then the specified register can not be accessed
518 //
519 if (Width > mSmmCpuWidthOffset[RegisterIndex].Width32) {
520 return EFI_INVALID_PARAMETER;
521 }
522 //
523 // Write SMM State register
524 //
525 ASSERT (CpuSaveState != NULL);
526 CopyMem((UINT8 *)CpuSaveState + mSmmCpuWidthOffset[RegisterIndex].Offset32, Buffer, Width);
527 } else {
528 //
529 // If 64-bit mode width is zero, then the specified register can not be accessed
530 //
531 if (mSmmCpuWidthOffset[RegisterIndex].Width64 == 0) {
532 return EFI_NOT_FOUND;
533 }
534
535 //
536 // If Width is bigger than the 64-bit mode width, then the specified register can not be accessed
537 //
538 if (Width > mSmmCpuWidthOffset[RegisterIndex].Width64) {
539 return EFI_INVALID_PARAMETER;
540 }
541
542 //
543 // Write lower 32-bits of SMM State register
544 //
545 CopyMem((UINT8 *)CpuSaveState + mSmmCpuWidthOffset[RegisterIndex].Offset64Lo, Buffer, MIN (4, Width));
546 if (Width >= 4) {
547 //
548 // Write upper 32-bits of SMM State register
549 //
550 CopyMem((UINT8 *)CpuSaveState + mSmmCpuWidthOffset[RegisterIndex].Offset64Hi, (UINT8 *)Buffer + 4, Width - 4);
551 }
552 }
553 return EFI_SUCCESS;
554 }
555
556 /**
557 Hook the code executed immediately after an RSM instruction on the currently
558 executing CPU. The mode of code executed immediately after RSM must be
559 detected, and the appropriate hook must be selected. Always clear the auto
560 HALT restart flag if it is set.
561
562 @param[in] CpuIndex The processor index for the currently
563 executing CPU.
564 @param[in] CpuState Pointer to SMRAM Save State Map for the
565 currently executing CPU.
566 @param[in] NewInstructionPointer32 Instruction pointer to use if resuming to
567 32-bit mode from 64-bit SMM.
568 @param[in] NewInstructionPointer Instruction pointer to use if resuming to
569 same mode as SMM.
570
571 @retval The value of the original instruction pointer before it was hooked.
572
573 **/
574 UINT64
575 EFIAPI
576 HookReturnFromSmm (
577 IN UINTN CpuIndex,
578 SMRAM_SAVE_STATE_MAP *CpuState,
579 UINT64 NewInstructionPointer32,
580 UINT64 NewInstructionPointer
581 )
582 {
583 UINT64 OriginalInstructionPointer;
584
585 OriginalInstructionPointer = SmmCpuFeaturesHookReturnFromSmm (
586 CpuIndex,
587 CpuState,
588 NewInstructionPointer32,
589 NewInstructionPointer
590 );
591 if (OriginalInstructionPointer != 0) {
592 return OriginalInstructionPointer;
593 }
594
595 if (mSmmSaveStateRegisterLma == EFI_SMM_SAVE_STATE_REGISTER_LMA_32BIT) {
596 OriginalInstructionPointer = (UINT64)CpuState->x86._EIP;
597 CpuState->x86._EIP = (UINT32)NewInstructionPointer;
598 //
599 // Clear the auto HALT restart flag so the RSM instruction returns
600 // program control to the instruction following the HLT instruction.
601 //
602 if ((CpuState->x86.AutoHALTRestart & BIT0) != 0) {
603 CpuState->x86.AutoHALTRestart &= ~BIT0;
604 }
605 } else {
606 OriginalInstructionPointer = CpuState->x64._RIP;
607 if ((CpuState->x64.IA32_EFER & LMA) == 0) {
608 CpuState->x64._RIP = (UINT32)NewInstructionPointer32;
609 } else {
610 CpuState->x64._RIP = (UINT32)NewInstructionPointer;
611 }
612 //
613 // Clear the auto HALT restart flag so the RSM instruction returns
614 // program control to the instruction following the HLT instruction.
615 //
616 if ((CpuState->x64.AutoHALTRestart & BIT0) != 0) {
617 CpuState->x64.AutoHALTRestart &= ~BIT0;
618 }
619 }
620 return OriginalInstructionPointer;
621 }
622
623 /**
624 Get the size of the SMI Handler in bytes.
625
626 @retval The size, in bytes, of the SMI Handler.
627
628 **/
629 UINTN
630 EFIAPI
631 GetSmiHandlerSize (
632 VOID
633 )
634 {
635 UINTN Size;
636
637 Size = SmmCpuFeaturesGetSmiHandlerSize ();
638 if (Size != 0) {
639 return Size;
640 }
641 return gcSmiHandlerSize;
642 }
643
644 /**
645 Install the SMI handler for the CPU specified by CpuIndex. This function
646 is called by the CPU that was elected as monarch during System Management
647 Mode initialization.
648
649 @param[in] CpuIndex The index of the CPU to install the custom SMI handler.
650 The value must be between 0 and the NumberOfCpus field
651 in the System Management System Table (SMST).
652 @param[in] SmBase The SMBASE address for the CPU specified by CpuIndex.
653 @param[in] SmiStack The stack to use when an SMI is processed by the
654 the CPU specified by CpuIndex.
655 @param[in] StackSize The size, in bytes, if the stack used when an SMI is
656 processed by the CPU specified by CpuIndex.
657 @param[in] GdtBase The base address of the GDT to use when an SMI is
658 processed by the CPU specified by CpuIndex.
659 @param[in] GdtSize The size, in bytes, of the GDT used when an SMI is
660 processed by the CPU specified by CpuIndex.
661 @param[in] IdtBase The base address of the IDT to use when an SMI is
662 processed by the CPU specified by CpuIndex.
663 @param[in] IdtSize The size, in bytes, of the IDT used when an SMI is
664 processed by the CPU specified by CpuIndex.
665 @param[in] Cr3 The base address of the page tables to use when an SMI
666 is processed by the CPU specified by CpuIndex.
667 **/
668 VOID
669 EFIAPI
670 InstallSmiHandler (
671 IN UINTN CpuIndex,
672 IN UINT32 SmBase,
673 IN VOID *SmiStack,
674 IN UINTN StackSize,
675 IN UINTN GdtBase,
676 IN UINTN GdtSize,
677 IN UINTN IdtBase,
678 IN UINTN IdtSize,
679 IN UINT32 Cr3
680 )
681 {
682 PROCESSOR_SMM_DESCRIPTOR *Psd;
683 UINT32 CpuSmiStack;
684
685 //
686 // Initialize PROCESSOR_SMM_DESCRIPTOR
687 //
688 Psd = (PROCESSOR_SMM_DESCRIPTOR *)(VOID *)((UINTN)SmBase + SMM_PSD_OFFSET);
689 CopyMem (Psd, &gcPsd, sizeof (gcPsd));
690 Psd->SmmGdtPtr = (UINT64)GdtBase;
691 Psd->SmmGdtSize = (UINT32)GdtSize;
692
693 if (SmmCpuFeaturesGetSmiHandlerSize () != 0) {
694 //
695 // Install SMI handler provided by library
696 //
697 SmmCpuFeaturesInstallSmiHandler (
698 CpuIndex,
699 SmBase,
700 SmiStack,
701 StackSize,
702 GdtBase,
703 GdtSize,
704 IdtBase,
705 IdtSize,
706 Cr3
707 );
708 return;
709 }
710
711 InitShadowStack (CpuIndex, (VOID *)((UINTN)SmiStack + StackSize));
712
713 //
714 // Initialize values in template before copy
715 //
716 CpuSmiStack = (UINT32)((UINTN)SmiStack + StackSize - sizeof (UINTN));
717 PatchInstructionX86 (gPatchSmiStack, CpuSmiStack, 4);
718 PatchInstructionX86 (gPatchSmiCr3, Cr3, 4);
719 PatchInstructionX86 (gPatchSmbase, SmBase, 4);
720 gSmiHandlerIdtr.Base = IdtBase;
721 gSmiHandlerIdtr.Limit = (UINT16)(IdtSize - 1);
722
723 //
724 // Set the value at the top of the CPU stack to the CPU Index
725 //
726 *(UINTN*)(UINTN)CpuSmiStack = CpuIndex;
727
728 //
729 // Copy template to CPU specific SMI handler location
730 //
731 CopyMem (
732 (VOID*)((UINTN)SmBase + SMM_HANDLER_OFFSET),
733 (VOID*)gcSmiHandlerTemplate,
734 gcSmiHandlerSize
735 );
736 }