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