VirtualBox

source: vbox/trunk/src/VBox/Devices/EFI/FirmwareNew/UefiCpuPkg/Library/MmSaveStateLib/AmdMmSaveState.c@ 101291

Last change on this file since 101291 was 101291, checked in by vboxsync, 14 months ago

EFI/FirmwareNew: Make edk2-stable202308 build on all supported platforms (using gcc at least, msvc not tested yet), bugref:4643

  • Property svn:eol-style set to native
File size: 15.0 KB
Line 
1/** @file
2Provides services to access SMRAM Save State Map
3
4Copyright (c) 2010 - 2019, Intel Corporation. All rights reserved.<BR>
5Copyright (C) 2023 Advanced Micro Devices, Inc. All rights reserved.<BR>
6SPDX-License-Identifier: BSD-2-Clause-Patent
7
8**/
9
10#include "MmSaveState.h"
11#include <Register/Amd/SmramSaveStateMap.h>
12#include <Library/BaseLib.h>
13
14// EFER register LMA bit
15#define LMA BIT10
16#define EFER_ADDRESS 0xC0000080ul
17#define AMD_MM_SAVE_STATE_REGISTER_SMMREVID_INDEX 1
18#define AMD_MM_SAVE_STATE_REGISTER_MAX_INDEX 2
19
20// Macro used to simplify the lookup table entries of type CPU_MM_SAVE_STATE_LOOKUP_ENTRY
21#define MM_CPU_OFFSET(Field) OFFSET_OF (AMD_SMRAM_SAVE_STATE_MAP, Field)
22
23// Lookup table used to retrieve the widths and offsets associated with each
24// supported EFI_MM_SAVE_STATE_REGISTER value
25CONST CPU_MM_SAVE_STATE_LOOKUP_ENTRY mCpuWidthOffset[] = {
26 { 0, 0, 0, 0, FALSE }, // Reserved
27
28 //
29 // Internally defined CPU Save State Registers. Not defined in PI SMM CPU Protocol.
30 //
31 { 4, 4, MM_CPU_OFFSET (x86.SMMRevId), MM_CPU_OFFSET (x64.SMMRevId), 0, FALSE}, // AMD_MM_SAVE_STATE_REGISTER_SMMREVID_INDEX = 1
32
33 //
34 // CPU Save State registers defined in PI SMM CPU Protocol.
35 //
36 { 4, 8, MM_CPU_OFFSET (x86.GDTBase), MM_CPU_OFFSET (x64._GDTRBaseLoDword), MM_CPU_OFFSET (x64._GDTRBaseHiDword), FALSE}, // EFI_MM_SAVE_STATE_REGISTER_GDTBASE = 4
37 { 0, 8, 0, MM_CPU_OFFSET (x64._IDTRBaseLoDword), MM_CPU_OFFSET (x64._IDTRBaseLoDword), FALSE}, // EFI_MM_SAVE_STATE_REGISTER_IDTBASE = 5
38 { 0, 8, 0, MM_CPU_OFFSET (x64._LDTRBaseLoDword), MM_CPU_OFFSET (x64._LDTRBaseLoDword), FALSE}, // EFI_MM_SAVE_STATE_REGISTER_LDTBASE = 6
39 { 0, 2, 0, MM_CPU_OFFSET (x64._GDTRLimit), 0, FALSE}, // EFI_MM_SAVE_STATE_REGISTER_GDTLIMIT = 7
40 { 0, 2, 0, MM_CPU_OFFSET (x64._IDTRLimit), 0, FALSE}, // EFI_MM_SAVE_STATE_REGISTER_IDTLIMIT = 8
41 { 0, 4, 0, MM_CPU_OFFSET (x64._LDTRLimit), 0, FALSE}, // EFI_MM_SAVE_STATE_REGISTER_LDTLIMIT = 9
42 { 0, 0, 0, 0, 0, FALSE}, // EFI_MM_SAVE_STATE_REGISTER_LDTINFO = 10
43 { 4, 2, MM_CPU_OFFSET (x86._ES), MM_CPU_OFFSET (x64._ES), 0, FALSE}, // EFI_MM_SAVE_STATE_REGISTER_ES = 20
44 { 4, 2, MM_CPU_OFFSET (x86._CS), MM_CPU_OFFSET (x64._CS), 0, FALSE}, // EFI_MM_SAVE_STATE_REGISTER_CS = 21
45 { 4, 2, MM_CPU_OFFSET (x86._SS), MM_CPU_OFFSET (x64._SS), 0, FALSE}, // EFI_MM_SAVE_STATE_REGISTER_SS = 22
46 { 4, 2, MM_CPU_OFFSET (x86._DS), MM_CPU_OFFSET (x64._DS), 0, FALSE}, // EFI_MM_SAVE_STATE_REGISTER_DS = 23
47 { 4, 2, MM_CPU_OFFSET (x86._FS), MM_CPU_OFFSET (x64._FS), 0, FALSE}, // EFI_MM_SAVE_STATE_REGISTER_FS = 24
48 { 4, 2, MM_CPU_OFFSET (x86._GS), MM_CPU_OFFSET (x64._GS), 0, FALSE}, // EFI_MM_SAVE_STATE_REGISTER_GS = 25
49 { 0, 2, 0, MM_CPU_OFFSET (x64._LDTR), 0, FALSE}, // EFI_MM_SAVE_STATE_REGISTER_LDTR_SEL = 26
50 { 0, 2, 0, MM_CPU_OFFSET (x64._TR), 0, FALSE}, // EFI_MM_SAVE_STATE_REGISTER_TR_SEL = 27
51 { 4, 8, MM_CPU_OFFSET (x86._DR7), MM_CPU_OFFSET (x64._DR7), MM_CPU_OFFSET (x64._DR7) + 4, FALSE}, // EFI_MM_SAVE_STATE_REGISTER_DR7 = 28
52 { 4, 8, MM_CPU_OFFSET (x86._DR6), MM_CPU_OFFSET (x64._DR6), MM_CPU_OFFSET (x64._DR6) + 4, FALSE}, // EFI_MM_SAVE_STATE_REGISTER_DR6 = 29
53 { 0, 8, 0, MM_CPU_OFFSET (x64._R8), MM_CPU_OFFSET (x64._R8) + 4, TRUE}, // EFI_MM_SAVE_STATE_REGISTER_R8 = 30
54 { 0, 8, 0, MM_CPU_OFFSET (x64._R9), MM_CPU_OFFSET (x64._R9) + 4, TRUE}, // EFI_MM_SAVE_STATE_REGISTER_R9 = 31
55 { 0, 8, 0, MM_CPU_OFFSET (x64._R10), MM_CPU_OFFSET (x64._R10) + 4, TRUE}, // EFI_MM_SAVE_STATE_REGISTER_R10 = 32
56 { 0, 8, 0, MM_CPU_OFFSET (x64._R11), MM_CPU_OFFSET (x64._R11) + 4, TRUE}, // EFI_MM_SAVE_STATE_REGISTER_R11 = 33
57 { 0, 8, 0, MM_CPU_OFFSET (x64._R12), MM_CPU_OFFSET (x64._R12) + 4, TRUE}, // EFI_MM_SAVE_STATE_REGISTER_R12 = 34
58 { 0, 8, 0, MM_CPU_OFFSET (x64._R13), MM_CPU_OFFSET (x64._R13) + 4, TRUE}, // EFI_MM_SAVE_STATE_REGISTER_R13 = 35
59 { 0, 8, 0, MM_CPU_OFFSET (x64._R14), MM_CPU_OFFSET (x64._R14) + 4, TRUE}, // EFI_MM_SAVE_STATE_REGISTER_R14 = 36
60 { 0, 8, 0, MM_CPU_OFFSET (x64._R15), MM_CPU_OFFSET (x64._R15) + 4, TRUE}, // EFI_MM_SAVE_STATE_REGISTER_R15 = 37
61 { 4, 8, MM_CPU_OFFSET (x86._EAX), MM_CPU_OFFSET (x64._RAX), MM_CPU_OFFSET (x64._RAX) + 4, TRUE}, // EFI_MM_SAVE_STATE_REGISTER_RAX = 38
62 { 4, 8, MM_CPU_OFFSET (x86._EBX), MM_CPU_OFFSET (x64._RBX), MM_CPU_OFFSET (x64._RBX) + 4, TRUE}, // EFI_MM_SAVE_STATE_REGISTER_RBX = 39
63 { 4, 8, MM_CPU_OFFSET (x86._ECX), MM_CPU_OFFSET (x64._RCX), MM_CPU_OFFSET (x64._RCX) + 4, TRUE}, // EFI_MM_SAVE_STATE_REGISTER_RBX = 39
64 { 4, 8, MM_CPU_OFFSET (x86._EDX), MM_CPU_OFFSET (x64._RDX), MM_CPU_OFFSET (x64._RDX) + 4, TRUE}, // EFI_MM_SAVE_STATE_REGISTER_RDX = 41
65 { 4, 8, MM_CPU_OFFSET (x86._ESP), MM_CPU_OFFSET (x64._RSP), MM_CPU_OFFSET (x64._RSP) + 4, TRUE}, // EFI_MM_SAVE_STATE_REGISTER_RSP = 42
66 { 4, 8, MM_CPU_OFFSET (x86._EBP), MM_CPU_OFFSET (x64._RBP), MM_CPU_OFFSET (x64._RBP) + 4, TRUE}, // EFI_MM_SAVE_STATE_REGISTER_RBP = 43
67 { 4, 8, MM_CPU_OFFSET (x86._ESI), MM_CPU_OFFSET (x64._RSI), MM_CPU_OFFSET (x64._RSI) + 4, TRUE}, // EFI_MM_SAVE_STATE_REGISTER_RSI = 44
68 { 4, 8, MM_CPU_OFFSET (x86._EDI), MM_CPU_OFFSET (x64._RDI), MM_CPU_OFFSET (x64._RDI) + 4, TRUE}, // EFI_MM_SAVE_STATE_REGISTER_RDI = 45
69 { 4, 8, MM_CPU_OFFSET (x86._EIP), MM_CPU_OFFSET (x64._RIP), MM_CPU_OFFSET (x64._RIP) + 4, TRUE}, // EFI_MM_SAVE_STATE_REGISTER_RIP = 46
70
71 { 4, 8, MM_CPU_OFFSET (x86._EFLAGS), MM_CPU_OFFSET (x64._RFLAGS), MM_CPU_OFFSET (x64._RFLAGS) + 4, TRUE}, // EFI_MM_SAVE_STATE_REGISTER_RFLAGS = 51
72 { 4, 8, MM_CPU_OFFSET (x86._CR0), MM_CPU_OFFSET (x64._CR0), MM_CPU_OFFSET (x64._CR0) + 4, FALSE}, // EFI_MM_SAVE_STATE_REGISTER_CR0 = 52
73 { 4, 8, MM_CPU_OFFSET (x86._CR3), MM_CPU_OFFSET (x64._CR3), MM_CPU_OFFSET (x64._CR3) + 4, FALSE}, // EFI_MM_SAVE_STATE_REGISTER_CR3 = 53
74 { 0, 8, 0, MM_CPU_OFFSET (x64._CR4), MM_CPU_OFFSET (x64._CR4) + 4, FALSE}, // EFI_MM_SAVE_STATE_REGISTER_CR4 = 54
75 { 0, 0, 0, 0, 0 }
76};
77
78/**
79 Read a save state register on the target processor. If this function
80 returns EFI_UNSUPPORTED, then the caller is responsible for reading the
81 MM Save State register.
82
83 @param[in] CpuIndex The index of the CPU to read the Save State register.
84 The value must be between 0 and the NumberOfCpus field in
85 the System Management System Table (SMST).
86 @param[in] Register The MM Save State register to read.
87 @param[in] Width The number of bytes to read from the CPU save state.
88 @param[out] Buffer Upon return, this holds the CPU register value read
89 from the save state.
90
91 @retval EFI_SUCCESS The register was read from Save State.
92 @retval EFI_INVALID_PARAMTER Buffer is NULL.
93 @retval EFI_UNSUPPORTED This function does not support reading Register.
94 @retval EFI_NOT_FOUND If desired Register not found.
95**/
96EFI_STATUS
97EFIAPI
98MmSaveStateReadRegister (
99 IN UINTN CpuIndex,
100 IN EFI_MM_SAVE_STATE_REGISTER Register,
101 IN UINTN Width,
102 OUT VOID *Buffer
103 )
104{
105 UINT32 SmmRevId;
106 EFI_MM_SAVE_STATE_IO_INFO *IoInfo;
107 AMD_SMRAM_SAVE_STATE_MAP *CpuSaveState;
108 UINT8 DataWidth;
109
110 // Read CPU State
111 CpuSaveState = (AMD_SMRAM_SAVE_STATE_MAP *)gMmst->CpuSaveState[CpuIndex];
112
113 // Check for special EFI_MM_SAVE_STATE_REGISTER_LMA
114 if (Register == EFI_MM_SAVE_STATE_REGISTER_LMA) {
115 // Only byte access is supported for this register
116 if (Width != 1) {
117 return EFI_INVALID_PARAMETER;
118 }
119
120 *(UINT8 *)Buffer = MmSaveStateGetRegisterLma ();
121
122 return EFI_SUCCESS;
123 }
124
125 // Check for special EFI_MM_SAVE_STATE_REGISTER_IO
126 if (Register == EFI_MM_SAVE_STATE_REGISTER_IO) {
127 //
128 // Get SMM Revision ID
129 //
130 MmSaveStateReadRegisterByIndex (CpuIndex, AMD_MM_SAVE_STATE_REGISTER_SMMREVID_INDEX, sizeof (SmmRevId), &SmmRevId);
131
132 //
133 // See if the CPU supports the IOMisc register in the save state
134 //
135 if (SmmRevId < AMD_SMM_MIN_REV_ID_X64) {
136 return EFI_NOT_FOUND;
137 }
138
139 // Check if IO Restart Dword [IO Trap] is valid or not using bit 1.
140 if (!(CpuSaveState->x64.IO_DWord & 0x02u)) {
141 return EFI_NOT_FOUND;
142 }
143
144 // Zero the IoInfo structure that will be returned in Buffer
145 IoInfo = (EFI_MM_SAVE_STATE_IO_INFO *)Buffer;
146 ZeroMem (IoInfo, sizeof (EFI_MM_SAVE_STATE_IO_INFO));
147
148 IoInfo->IoPort = (UINT16)(CpuSaveState->x64.IO_DWord >> 16u);
149
150 if (CpuSaveState->x64.IO_DWord & 0x10u) {
151 IoInfo->IoWidth = EFI_MM_SAVE_STATE_IO_WIDTH_UINT8;
152 DataWidth = 0x01u;
153 } else if (CpuSaveState->x64.IO_DWord & 0x20u) {
154 IoInfo->IoWidth = EFI_MM_SAVE_STATE_IO_WIDTH_UINT16;
155 DataWidth = 0x02u;
156 } else {
157 IoInfo->IoWidth = EFI_MM_SAVE_STATE_IO_WIDTH_UINT32;
158 DataWidth = 0x04u;
159 }
160
161 if (CpuSaveState->x64.IO_DWord & 0x01u) {
162 IoInfo->IoType = EFI_MM_SAVE_STATE_IO_TYPE_INPUT;
163 } else {
164 IoInfo->IoType = EFI_MM_SAVE_STATE_IO_TYPE_OUTPUT;
165 }
166
167 if ((IoInfo->IoType == EFI_MM_SAVE_STATE_IO_TYPE_INPUT) || (IoInfo->IoType == EFI_MM_SAVE_STATE_IO_TYPE_OUTPUT)) {
168 MmSaveStateReadRegister (CpuIndex, EFI_MM_SAVE_STATE_REGISTER_RAX, DataWidth, &IoInfo->IoData);
169 }
170
171 return EFI_SUCCESS;
172 }
173
174 // Convert Register to a register lookup table index
175 return MmSaveStateReadRegisterByIndex (CpuIndex, MmSaveStateGetRegisterIndex (Register, AMD_MM_SAVE_STATE_REGISTER_MAX_INDEX), Width, Buffer);
176}
177
178/**
179 Writes a save state register on the target processor. If this function
180 returns EFI_UNSUPPORTED, then the caller is responsible for writing the
181 MM save state register.
182
183 @param[in] CpuIndex The index of the CPU to write the MM Save State. The
184 value must be between 0 and the NumberOfCpus field in
185 the System Management System Table (SMST).
186 @param[in] Register The MM Save State register to write.
187 @param[in] Width The number of bytes to write to the CPU save state.
188 @param[in] Buffer Upon entry, this holds the new CPU register value.
189
190 @retval EFI_SUCCESS The register was written to Save State.
191 @retval EFI_INVALID_PARAMTER Buffer is NULL.
192 @retval EFI_UNSUPPORTED This function does not support writing Register.
193 @retval EFI_NOT_FOUND If desired Register not found.
194**/
195EFI_STATUS
196EFIAPI
197MmSaveStateWriteRegister (
198 IN UINTN CpuIndex,
199 IN EFI_MM_SAVE_STATE_REGISTER Register,
200 IN UINTN Width,
201 IN CONST VOID *Buffer
202 )
203{
204 UINTN RegisterIndex;
205 AMD_SMRAM_SAVE_STATE_MAP *CpuSaveState;
206
207 //
208 // Writes to EFI_MM_SAVE_STATE_REGISTER_LMA are ignored
209 //
210 if (Register == EFI_MM_SAVE_STATE_REGISTER_LMA) {
211 return EFI_SUCCESS;
212 }
213
214 //
215 // Writes to EFI_MM_SAVE_STATE_REGISTER_IO are not supported
216 //
217 if (Register == EFI_MM_SAVE_STATE_REGISTER_IO) {
218 return EFI_NOT_FOUND;
219 }
220
221 //
222 // Convert Register to a register lookup table index
223 //
224 RegisterIndex = MmSaveStateGetRegisterIndex (Register, AMD_MM_SAVE_STATE_REGISTER_MAX_INDEX);
225 if (RegisterIndex == 0) {
226 return EFI_NOT_FOUND;
227 }
228
229 CpuSaveState = gMmst->CpuSaveState[CpuIndex];
230
231 //
232 // Do not write non-writable SaveState, because it will cause exception.
233 //
234 if (!mCpuWidthOffset[RegisterIndex].Writeable) {
235 return EFI_UNSUPPORTED;
236 }
237
238 //
239 // Check CPU mode
240 //
241 if (MmSaveStateGetRegisterLma () == EFI_MM_SAVE_STATE_REGISTER_LMA_32BIT) {
242 //
243 // If 32-bit mode width is zero, then the specified register can not be accessed
244 //
245 if (mCpuWidthOffset[RegisterIndex].Width32 == 0) {
246 return EFI_NOT_FOUND;
247 }
248
249 //
250 // If Width is bigger than the 32-bit mode width, then the specified register can not be accessed
251 //
252 if (Width > mCpuWidthOffset[RegisterIndex].Width32) {
253 return EFI_INVALID_PARAMETER;
254 }
255
256 //
257 // Write SMM State register
258 //
259 ASSERT (CpuSaveState != NULL);
260 CopyMem ((UINT8 *)CpuSaveState + mCpuWidthOffset[RegisterIndex].Offset32, Buffer, Width);
261 } else {
262 //
263 // If 64-bit mode width is zero, then the specified register can not be accessed
264 //
265 if (mCpuWidthOffset[RegisterIndex].Width64 == 0) {
266 return EFI_NOT_FOUND;
267 }
268
269 //
270 // If Width is bigger than the 64-bit mode width, then the specified register can not be accessed
271 //
272 if (Width > mCpuWidthOffset[RegisterIndex].Width64) {
273 return EFI_INVALID_PARAMETER;
274 }
275
276 //
277 // Write lower 32-bits of SMM State register
278 //
279 CopyMem ((UINT8 *)CpuSaveState + mCpuWidthOffset[RegisterIndex].Offset64Lo, Buffer, MIN (4, Width));
280 if (Width >= 4) {
281 //
282 // Write upper 32-bits of SMM State register
283 //
284 CopyMem ((UINT8 *)CpuSaveState + mCpuWidthOffset[RegisterIndex].Offset64Hi, (UINT8 *)Buffer + 4, Width - 4);
285 }
286 }
287
288 return EFI_SUCCESS;
289}
290
291/**
292 Returns LMA value of the Processor.
293
294 @retval UINT8 returns LMA bit value.
295**/
296UINT8
297MmSaveStateGetRegisterLma (
298 VOID
299 )
300{
301 UINT32 LMAValue;
302
303 LMAValue = (UINT32)AsmReadMsr64 (EFER_ADDRESS) & LMA;
304 if (LMAValue) {
305 return EFI_MM_SAVE_STATE_REGISTER_LMA_64BIT;
306 }
307
308 return EFI_MM_SAVE_STATE_REGISTER_LMA_32BIT;
309}
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette