]> git.proxmox.com Git - mirror_edk2.git/blame - OvmfPkg/Library/SmmCpuFeaturesLib/SmmCpuFeaturesLib.c
UefiCpuPkg: Move AsmRelocateApLoopStart from Mpfuncs.nasm to AmdSev.nasm
[mirror_edk2.git] / OvmfPkg / Library / SmmCpuFeaturesLib / SmmCpuFeaturesLib.c
CommitLineData
86d71589 1/** @file\r
b1bfdd65 2 The CPU specific programming for PiSmmCpuDxeSmm module.\r
86d71589 3\r
a1d595fc 4 Copyright (c) 2010 - 2023, Intel Corporation. All rights reserved.<BR>\r
86d71589 5\r
b26f0cf9 6 SPDX-License-Identifier: BSD-2-Clause-Patent\r
86d71589
PB
7**/\r
8\r
300aae11 9#include <IndustryStandard/Q35MchIch9.h>\r
86d71589 10#include <Library/BaseLib.h>\r
4036b4e5 11#include <Library/BaseMemoryLib.h>\r
4a9b250b 12#include <Library/DebugLib.h>\r
5ef3b66f 13#include <Library/MemEncryptSevLib.h>\r
b6d59967 14#include <Library/MemoryAllocationLib.h>\r
300aae11 15#include <Library/PcdLib.h>\r
b6d59967 16#include <Library/SafeIntLib.h>\r
4a9b250b 17#include <Library/SmmCpuFeaturesLib.h>\r
4036b4e5 18#include <Library/SmmServicesTableLib.h>\r
5ef3b66f 19#include <Library/UefiBootServicesTableLib.h>\r
a1d595fc 20#include <Library/HobLib.h>\r
b6d59967 21#include <Pcd/CpuHotEjectData.h>\r
4a9b250b 22#include <PiSmm.h>\r
300aae11 23#include <Register/Intel/SmramSaveStateMap.h>\r
c1fcd80b 24#include <Register/QemuSmramSaveStateMap.h>\r
a1d595fc 25#include <Guid/SmmBaseHob.h>\r
86d71589 26\r
4036b4e5
PB
27//\r
28// EFER register LMA bit\r
29//\r
ac0a286f 30#define LMA BIT10\r
4036b4e5 31\r
86d71589
PB
32/**\r
33 The constructor function\r
34\r
35 @param[in] ImageHandle The firmware allocated handle for the EFI image.\r
36 @param[in] SystemTable A pointer to the EFI System Table.\r
37\r
38 @retval EFI_SUCCESS The constructor always returns EFI_SUCCESS.\r
39\r
40**/\r
41EFI_STATUS\r
42EFIAPI\r
43SmmCpuFeaturesLibConstructor (\r
44 IN EFI_HANDLE ImageHandle,\r
45 IN EFI_SYSTEM_TABLE *SystemTable\r
46 )\r
47{\r
a1d595fc
WJ
48 //\r
49 // If gSmmBaseHobGuid found, means SmBase info has been relocated and recorded\r
50 // in the SmBase array. ASSERT it's not supported in OVMF.\r
51 //\r
52 ASSERT (GetFirstGuidHob (&gSmmBaseHobGuid) == NULL);\r
53\r
86d71589 54 //\r
d7e71b29 55 // No need to program SMRRs on our virtual platform.\r
86d71589 56 //\r
86d71589
PB
57 return EFI_SUCCESS;\r
58}\r
59\r
60/**\r
61 Called during the very first SMI into System Management Mode to initialize\r
62 CPU features, including SMBASE, for the currently executing CPU. Since this\r
63 is the first SMI, the SMRAM Save State Map is at the default address of\r
64 SMM_DEFAULT_SMBASE + SMRAM_SAVE_STATE_MAP_OFFSET. The currently executing\r
65 CPU is specified by CpuIndex and CpuIndex can be used to access information\r
66 about the currently executing CPU in the ProcessorInfo array and the\r
67 HotPlugCpuData data structure.\r
68\r
69 @param[in] CpuIndex The index of the CPU to initialize. The value\r
70 must be between 0 and the NumberOfCpus field in\r
71 the System Management System Table (SMST).\r
72 @param[in] IsMonarch TRUE if the CpuIndex is the index of the CPU that\r
73 was elected as monarch during System Management\r
74 Mode initialization.\r
75 FALSE if the CpuIndex is not the index of the CPU\r
76 that was elected as monarch during System\r
77 Management Mode initialization.\r
78 @param[in] ProcessorInfo Pointer to an array of EFI_PROCESSOR_INFORMATION\r
79 structures. ProcessorInfo[CpuIndex] contains the\r
80 information for the currently executing CPU.\r
81 @param[in] CpuHotPlugData Pointer to the CPU_HOT_PLUG_DATA structure that\r
82 contains the ApidId and SmBase arrays.\r
83**/\r
84VOID\r
85EFIAPI\r
86SmmCpuFeaturesInitializeProcessor (\r
87 IN UINTN CpuIndex,\r
88 IN BOOLEAN IsMonarch,\r
89 IN EFI_PROCESSOR_INFORMATION *ProcessorInfo,\r
90 IN CPU_HOT_PLUG_DATA *CpuHotPlugData\r
91 )\r
92{\r
c1fcd80b 93 QEMU_SMRAM_SAVE_STATE_MAP *CpuState;\r
86d71589
PB
94\r
95 //\r
96 // Configure SMBASE.\r
97 //\r
b1bfdd65 98 CpuState = (QEMU_SMRAM_SAVE_STATE_MAP *)(UINTN)(\r
ac0a286f
MK
99 SMM_DEFAULT_SMBASE +\r
100 SMRAM_SAVE_STATE_MAP_OFFSET\r
101 );\r
c1fcd80b
PB
102 if ((CpuState->x86.SMMRevId & 0xFFFF) == 0) {\r
103 CpuState->x86.SMBASE = (UINT32)CpuHotPlugData->SmBase[CpuIndex];\r
104 } else {\r
105 CpuState->x64.SMBASE = (UINT32)CpuHotPlugData->SmBase[CpuIndex];\r
106 }\r
86d71589
PB
107\r
108 //\r
d7e71b29 109 // No need to program SMRRs on our virtual platform.\r
86d71589 110 //\r
86d71589
PB
111}\r
112\r
113/**\r
114 This function updates the SMRAM save state on the currently executing CPU\r
115 to resume execution at a specific address after an RSM instruction. This\r
116 function must evaluate the SMRAM save state to determine the execution mode\r
117 the RSM instruction resumes and update the resume execution address with\r
118 either NewInstructionPointer32 or NewInstructionPoint. The auto HALT restart\r
119 flag in the SMRAM save state must always be cleared. This function returns\r
120 the value of the instruction pointer from the SMRAM save state that was\r
121 replaced. If this function returns 0, then the SMRAM save state was not\r
122 modified.\r
123\r
124 This function is called during the very first SMI on each CPU after\r
125 SmmCpuFeaturesInitializeProcessor() to set a flag in normal execution mode\r
126 to signal that the SMBASE of each CPU has been updated before the default\r
127 SMBASE address is used for the first SMI to the next CPU.\r
128\r
129 @param[in] CpuIndex The index of the CPU to hook. The value\r
130 must be between 0 and the NumberOfCpus\r
b1bfdd65
LE
131 field in the System Management System\r
132 Table (SMST).\r
86d71589
PB
133 @param[in] CpuState Pointer to SMRAM Save State Map for the\r
134 currently executing CPU.\r
135 @param[in] NewInstructionPointer32 Instruction pointer to use if resuming to\r
136 32-bit execution mode from 64-bit SMM.\r
137 @param[in] NewInstructionPointer Instruction pointer to use if resuming to\r
138 same execution mode as SMM.\r
139\r
140 @retval 0 This function did modify the SMRAM save state.\r
141 @retval > 0 The original instruction pointer value from the SMRAM save state\r
142 before it was replaced.\r
143**/\r
144UINT64\r
145EFIAPI\r
146SmmCpuFeaturesHookReturnFromSmm (\r
147 IN UINTN CpuIndex,\r
148 IN SMRAM_SAVE_STATE_MAP *CpuState,\r
149 IN UINT64 NewInstructionPointer32,\r
150 IN UINT64 NewInstructionPointer\r
151 )\r
152{\r
ac0a286f
MK
153 UINT64 OriginalInstructionPointer;\r
154 QEMU_SMRAM_SAVE_STATE_MAP *CpuSaveState;\r
4036b4e5 155\r
b1bfdd65 156 CpuSaveState = (QEMU_SMRAM_SAVE_STATE_MAP *)CpuState;\r
4036b4e5
PB
157 if ((CpuSaveState->x86.SMMRevId & 0xFFFF) == 0) {\r
158 OriginalInstructionPointer = (UINT64)CpuSaveState->x86._EIP;\r
ac0a286f 159 CpuSaveState->x86._EIP = (UINT32)NewInstructionPointer;\r
4036b4e5
PB
160 //\r
161 // Clear the auto HALT restart flag so the RSM instruction returns\r
162 // program control to the instruction following the HLT instruction.\r
163 //\r
164 if ((CpuSaveState->x86.AutoHALTRestart & BIT0) != 0) {\r
165 CpuSaveState->x86.AutoHALTRestart &= ~BIT0;\r
166 }\r
167 } else {\r
168 OriginalInstructionPointer = CpuSaveState->x64._RIP;\r
169 if ((CpuSaveState->x64.IA32_EFER & LMA) == 0) {\r
170 CpuSaveState->x64._RIP = (UINT32)NewInstructionPointer32;\r
171 } else {\r
172 CpuSaveState->x64._RIP = (UINT32)NewInstructionPointer;\r
173 }\r
ac0a286f 174\r
4036b4e5
PB
175 //\r
176 // Clear the auto HALT restart flag so the RSM instruction returns\r
177 // program control to the instruction following the HLT instruction.\r
178 //\r
179 if ((CpuSaveState->x64.AutoHALTRestart & BIT0) != 0) {\r
180 CpuSaveState->x64.AutoHALTRestart &= ~BIT0;\r
181 }\r
182 }\r
ac0a286f 183\r
4036b4e5 184 return OriginalInstructionPointer;\r
86d71589
PB
185}\r
186\r
ac0a286f 187STATIC CPU_HOT_EJECT_DATA *mCpuHotEjectData = NULL;\r
b6d59967
AA
188\r
189/**\r
190 Initialize mCpuHotEjectData if PcdCpuMaxLogicalProcessorNumber > 1.\r
191\r
192 Also setup the corresponding PcdCpuHotEjectDataAddress.\r
193**/\r
194STATIC\r
195VOID\r
196InitCpuHotEjectData (\r
197 VOID\r
198 )\r
199{\r
200 UINTN Size;\r
201 UINT32 Idx;\r
202 UINT32 MaxNumberOfCpus;\r
203 RETURN_STATUS PcdStatus;\r
204\r
205 MaxNumberOfCpus = PcdGet32 (PcdCpuMaxLogicalProcessorNumber);\r
206 if (MaxNumberOfCpus == 1) {\r
207 return;\r
208 }\r
209\r
210 //\r
211 // We allocate CPU_HOT_EJECT_DATA and CPU_HOT_EJECT_DATA->QemuSelectorMap[]\r
212 // in a single allocation, and explicitly align the QemuSelectorMap[] (which\r
213 // is a UINT64 array) at its natural boundary.\r
214 // Accordingly, allocate:\r
215 // sizeof(*mCpuHotEjectData) + (MaxNumberOfCpus * sizeof(UINT64))\r
216 // and, add sizeof(UINT64) - 1 to use as padding if needed.\r
217 //\r
218\r
219 if (RETURN_ERROR (SafeUintnMult (MaxNumberOfCpus, sizeof (UINT64), &Size)) ||\r
220 RETURN_ERROR (SafeUintnAdd (Size, sizeof (*mCpuHotEjectData), &Size)) ||\r
ac0a286f
MK
221 RETURN_ERROR (SafeUintnAdd (Size, sizeof (UINT64) - 1, &Size)))\r
222 {\r
b6d59967
AA
223 DEBUG ((DEBUG_ERROR, "%a: invalid CPU_HOT_EJECT_DATA\n", __FUNCTION__));\r
224 goto Fatal;\r
225 }\r
226\r
227 mCpuHotEjectData = AllocatePool (Size);\r
228 if (mCpuHotEjectData == NULL) {\r
229 ASSERT (mCpuHotEjectData != NULL);\r
230 goto Fatal;\r
231 }\r
232\r
ac0a286f 233 mCpuHotEjectData->Handler = NULL;\r
b6d59967
AA
234 mCpuHotEjectData->ArrayLength = MaxNumberOfCpus;\r
235\r
ac0a286f
MK
236 mCpuHotEjectData->QemuSelectorMap = ALIGN_POINTER (\r
237 mCpuHotEjectData + 1,\r
238 sizeof (UINT64)\r
239 );\r
b6d59967
AA
240 //\r
241 // We use mCpuHotEjectData->QemuSelectorMap to map\r
242 // ProcessorNum -> QemuSelector. Initialize to invalid values.\r
243 //\r
244 for (Idx = 0; Idx < mCpuHotEjectData->ArrayLength; Idx++) {\r
245 mCpuHotEjectData->QemuSelectorMap[Idx] = CPU_EJECT_QEMU_SELECTOR_INVALID;\r
246 }\r
247\r
248 //\r
249 // Expose address of CPU Hot eject Data structure\r
250 //\r
ac0a286f
MK
251 PcdStatus = PcdSet64S (\r
252 PcdCpuHotEjectDataAddress,\r
253 (UINTN)(VOID *)mCpuHotEjectData\r
254 );\r
b6d59967
AA
255 ASSERT_RETURN_ERROR (PcdStatus);\r
256\r
257 return;\r
258\r
259Fatal:\r
260 CpuDeadLoop ();\r
261}\r
262\r
86d71589
PB
263/**\r
264 Hook point in normal execution mode that allows the one CPU that was elected\r
265 as monarch during System Management Mode initialization to perform additional\r
266 initialization actions immediately after all of the CPUs have processed their\r
267 first SMI and called SmmCpuFeaturesInitializeProcessor() relocating SMBASE\r
268 into a buffer in SMRAM and called SmmCpuFeaturesHookReturnFromSmm().\r
269**/\r
270VOID\r
271EFIAPI\r
272SmmCpuFeaturesSmmRelocationComplete (\r
273 VOID\r
274 )\r
275{\r
ac0a286f
MK
276 EFI_STATUS Status;\r
277 UINTN MapPagesBase;\r
278 UINTN MapPagesCount;\r
b6d59967
AA
279\r
280 InitCpuHotEjectData ();\r
281\r
5ef3b66f
LE
282 if (!MemEncryptSevIsEnabled ()) {\r
283 return;\r
284 }\r
285\r
286 //\r
287 // Now that SMBASE relocation is complete, re-encrypt the original SMRAM save\r
288 // state map's container pages, and release the pages to DXE. (The pages were\r
289 // allocated in PlatformPei.)\r
290 //\r
291 Status = MemEncryptSevLocateInitialSmramSaveStateMapPages (\r
292 &MapPagesBase,\r
293 &MapPagesCount\r
294 );\r
295 ASSERT_EFI_ERROR (Status);\r
296\r
297 Status = MemEncryptSevSetPageEncMask (\r
298 0, // Cr3BaseAddress -- use current CR3\r
299 MapPagesBase, // BaseAddress\r
adfa3327 300 MapPagesCount // NumPages\r
5ef3b66f
LE
301 );\r
302 if (EFI_ERROR (Status)) {\r
ac0a286f
MK
303 DEBUG ((\r
304 DEBUG_ERROR,\r
305 "%a: MemEncryptSevSetPageEncMask(): %r\n",\r
306 __FUNCTION__,\r
307 Status\r
308 ));\r
5ef3b66f
LE
309 ASSERT (FALSE);\r
310 CpuDeadLoop ();\r
311 }\r
312\r
313 ZeroMem ((VOID *)MapPagesBase, EFI_PAGES_TO_SIZE (MapPagesCount));\r
314\r
300aae11
LE
315 if (PcdGetBool (PcdQ35SmramAtDefaultSmbase)) {\r
316 //\r
317 // The initial SMRAM Save State Map has been covered as part of a larger\r
318 // reserved memory allocation in PlatformPei's InitializeRamRegions(). That\r
319 // allocation is supposed to survive into OS runtime; we must not release\r
320 // any part of it. Only re-assert the containment here.\r
321 //\r
322 ASSERT (SMM_DEFAULT_SMBASE <= MapPagesBase);\r
323 ASSERT (\r
324 (MapPagesBase + EFI_PAGES_TO_SIZE (MapPagesCount) <=\r
325 SMM_DEFAULT_SMBASE + MCH_DEFAULT_SMBASE_SIZE)\r
326 );\r
327 } else {\r
328 Status = gBS->FreePages (MapPagesBase, MapPagesCount);\r
329 ASSERT_EFI_ERROR (Status);\r
330 }\r
86d71589
PB
331}\r
332\r
333/**\r
334 Return the size, in bytes, of a custom SMI Handler in bytes. If 0 is\r
335 returned, then a custom SMI handler is not provided by this library,\r
336 and the default SMI handler must be used.\r
337\r
338 @retval 0 Use the default SMI handler.\r
b1bfdd65
LE
339 @retval > 0 Use the SMI handler installed by\r
340 SmmCpuFeaturesInstallSmiHandler(). The caller is required to\r
341 allocate enough SMRAM for each CPU to support the size of the\r
342 custom SMI handler.\r
86d71589
PB
343**/\r
344UINTN\r
345EFIAPI\r
346SmmCpuFeaturesGetSmiHandlerSize (\r
347 VOID\r
348 )\r
349{\r
350 return 0;\r
351}\r
352\r
353/**\r
b1bfdd65
LE
354 Install a custom SMI handler for the CPU specified by CpuIndex. This\r
355 function is only called if SmmCpuFeaturesGetSmiHandlerSize() returns a size\r
356 is greater than zero and is called by the CPU that was elected as monarch\r
357 during System Management Mode initialization.\r
86d71589
PB
358\r
359 @param[in] CpuIndex The index of the CPU to install the custom SMI handler.\r
360 The value must be between 0 and the NumberOfCpus field\r
361 in the System Management System Table (SMST).\r
362 @param[in] SmBase The SMBASE address for the CPU specified by CpuIndex.\r
363 @param[in] SmiStack The stack to use when an SMI is processed by the\r
364 the CPU specified by CpuIndex.\r
365 @param[in] StackSize The size, in bytes, if the stack used when an SMI is\r
366 processed by the CPU specified by CpuIndex.\r
367 @param[in] GdtBase The base address of the GDT to use when an SMI is\r
368 processed by the CPU specified by CpuIndex.\r
369 @param[in] GdtSize The size, in bytes, of the GDT used when an SMI is\r
370 processed by the CPU specified by CpuIndex.\r
371 @param[in] IdtBase The base address of the IDT to use when an SMI is\r
372 processed by the CPU specified by CpuIndex.\r
373 @param[in] IdtSize The size, in bytes, of the IDT used when an SMI is\r
374 processed by the CPU specified by CpuIndex.\r
375 @param[in] Cr3 The base address of the page tables to use when an SMI\r
376 is processed by the CPU specified by CpuIndex.\r
377**/\r
378VOID\r
379EFIAPI\r
380SmmCpuFeaturesInstallSmiHandler (\r
381 IN UINTN CpuIndex,\r
382 IN UINT32 SmBase,\r
383 IN VOID *SmiStack,\r
384 IN UINTN StackSize,\r
385 IN UINTN GdtBase,\r
386 IN UINTN GdtSize,\r
387 IN UINTN IdtBase,\r
388 IN UINTN IdtSize,\r
389 IN UINT32 Cr3\r
390 )\r
391{\r
392}\r
393\r
394/**\r
395 Determines if MTRR registers must be configured to set SMRAM cache-ability\r
396 when executing in System Management Mode.\r
397\r
398 @retval TRUE MTRR registers must be configured to set SMRAM cache-ability.\r
399 @retval FALSE MTRR registers do not need to be configured to set SMRAM\r
400 cache-ability.\r
401**/\r
402BOOLEAN\r
403EFIAPI\r
404SmmCpuFeaturesNeedConfigureMtrrs (\r
405 VOID\r
406 )\r
407{\r
d7e71b29 408 return FALSE;\r
86d71589
PB
409}\r
410\r
411/**\r
b1bfdd65
LE
412 Disable SMRR register if SMRR is supported and\r
413 SmmCpuFeaturesNeedConfigureMtrrs() returns TRUE.\r
86d71589
PB
414**/\r
415VOID\r
416EFIAPI\r
417SmmCpuFeaturesDisableSmrr (\r
418 VOID\r
419 )\r
420{\r
d7e71b29
PB
421 //\r
422 // No SMRR support, nothing to do\r
423 //\r
86d71589
PB
424}\r
425\r
426/**\r
b1bfdd65
LE
427 Enable SMRR register if SMRR is supported and\r
428 SmmCpuFeaturesNeedConfigureMtrrs() returns TRUE.\r
86d71589
PB
429**/\r
430VOID\r
431EFIAPI\r
432SmmCpuFeaturesReenableSmrr (\r
433 VOID\r
434 )\r
435{\r
d7e71b29
PB
436 //\r
437 // No SMRR support, nothing to do\r
438 //\r
86d71589
PB
439}\r
440\r
441/**\r
442 Processor specific hook point each time a CPU enters System Management Mode.\r
443\r
444 @param[in] CpuIndex The index of the CPU that has entered SMM. The value\r
445 must be between 0 and the NumberOfCpus field in the\r
446 System Management System Table (SMST).\r
447**/\r
448VOID\r
449EFIAPI\r
450SmmCpuFeaturesRendezvousEntry (\r
451 IN UINTN CpuIndex\r
452 )\r
453{\r
454 //\r
d7e71b29 455 // No SMRR support, nothing to do\r
86d71589 456 //\r
86d71589
PB
457}\r
458\r
459/**\r
460 Processor specific hook point each time a CPU exits System Management Mode.\r
461\r
b1bfdd65
LE
462 @param[in] CpuIndex The index of the CPU that is exiting SMM. The value\r
463 must be between 0 and the NumberOfCpus field in the\r
464 System Management System Table (SMST).\r
86d71589
PB
465**/\r
466VOID\r
467EFIAPI\r
468SmmCpuFeaturesRendezvousExit (\r
469 IN UINTN CpuIndex\r
470 )\r
471{\r
af9c77e1
AA
472 //\r
473 // We only call the Handler if CPU hot-eject is enabled\r
474 // (PcdCpuMaxLogicalProcessorNumber > 1), and hot-eject is needed\r
475 // in this SMI exit (otherwise mCpuHotEjectData->Handler is not armed.)\r
476 //\r
477\r
478 if (mCpuHotEjectData != NULL) {\r
ac0a286f 479 CPU_HOT_EJECT_HANDLER Handler;\r
af9c77e1
AA
480\r
481 //\r
482 // As the comment above mentions, mCpuHotEjectData->Handler might be\r
483 // written to on the BSP as part of handling of the CPU-ejection.\r
484 //\r
485 // We know that any initial assignment to mCpuHotEjectData->Handler\r
486 // (on the BSP, in the CpuHotplugMmi() context) is ordered-before the\r
487 // load below, since it is guaranteed to happen before the\r
488 // control-dependency of the BSP's SMI exit signal -- by way of a store\r
489 // to AllCpusInSync (on the BSP, in BspHandler()) and the corresponding\r
490 // AllCpusInSync loop (on the APs, in SmiRendezvous()) which depends on\r
491 // that store.\r
492 //\r
493 // This guarantees that these pieces of code can never execute\r
494 // simultaneously. In addition, we ensure that the following load is\r
495 // ordered-after the AllCpusInSync loop by using a MemoryFence() with\r
496 // acquire semantics.\r
497 //\r
ac0a286f 498 MemoryFence ();\r
af9c77e1
AA
499\r
500 Handler = mCpuHotEjectData->Handler;\r
501\r
502 if (Handler != NULL) {\r
503 Handler (CpuIndex);\r
504 }\r
505 }\r
86d71589
PB
506}\r
507\r
508/**\r
509 Check to see if an SMM register is supported by a specified CPU.\r
510\r
511 @param[in] CpuIndex The index of the CPU to check for SMM register support.\r
512 The value must be between 0 and the NumberOfCpus field\r
513 in the System Management System Table (SMST).\r
514 @param[in] RegName Identifies the SMM register to check for support.\r
515\r
516 @retval TRUE The SMM register specified by RegName is supported by the CPU\r
517 specified by CpuIndex.\r
518 @retval FALSE The SMM register specified by RegName is not supported by the\r
519 CPU specified by CpuIndex.\r
520**/\r
521BOOLEAN\r
522EFIAPI\r
523SmmCpuFeaturesIsSmmRegisterSupported (\r
524 IN UINTN CpuIndex,\r
525 IN SMM_REG_NAME RegName\r
526 )\r
527{\r
d7e71b29 528 ASSERT (RegName == SmmRegFeatureControl);\r
86d71589
PB
529 return FALSE;\r
530}\r
531\r
532/**\r
533 Returns the current value of the SMM register for the specified CPU.\r
534 If the SMM register is not supported, then 0 is returned.\r
535\r
536 @param[in] CpuIndex The index of the CPU to read the SMM register. The\r
537 value must be between 0 and the NumberOfCpus field in\r
538 the System Management System Table (SMST).\r
539 @param[in] RegName Identifies the SMM register to read.\r
540\r
541 @return The value of the SMM register specified by RegName from the CPU\r
542 specified by CpuIndex.\r
543**/\r
544UINT64\r
545EFIAPI\r
546SmmCpuFeaturesGetSmmRegister (\r
547 IN UINTN CpuIndex,\r
548 IN SMM_REG_NAME RegName\r
549 )\r
550{\r
d7e71b29
PB
551 //\r
552 // This is called for SmmRegSmmDelayed, SmmRegSmmBlocked, SmmRegSmmEnable.\r
553 // The last of these should actually be SmmRegSmmDisable, so we can just\r
554 // return FALSE.\r
555 //\r
86d71589
PB
556 return 0;\r
557}\r
558\r
559/**\r
560 Sets the value of an SMM register on a specified CPU.\r
561 If the SMM register is not supported, then no action is performed.\r
562\r
563 @param[in] CpuIndex The index of the CPU to write the SMM register. The\r
564 value must be between 0 and the NumberOfCpus field in\r
565 the System Management System Table (SMST).\r
566 @param[in] RegName Identifies the SMM register to write.\r
567 registers are read-only.\r
568 @param[in] Value The value to write to the SMM register.\r
569**/\r
570VOID\r
571EFIAPI\r
572SmmCpuFeaturesSetSmmRegister (\r
573 IN UINTN CpuIndex,\r
574 IN SMM_REG_NAME RegName,\r
575 IN UINT64 Value\r
576 )\r
577{\r
d7e71b29 578 ASSERT (FALSE);\r
86d71589
PB
579}\r
580\r
4036b4e5 581///\r
b1bfdd65
LE
582/// Macro used to simplify the lookup table entries of type\r
583/// CPU_SMM_SAVE_STATE_LOOKUP_ENTRY\r
4036b4e5 584///\r
ac0a286f 585#define SMM_CPU_OFFSET(Field) OFFSET_OF (QEMU_SMRAM_SAVE_STATE_MAP, Field)\r
4036b4e5
PB
586\r
587///\r
b1bfdd65
LE
588/// Macro used to simplify the lookup table entries of type\r
589/// CPU_SMM_SAVE_STATE_REGISTER_RANGE\r
4036b4e5 590///\r
ac0a286f 591#define SMM_REGISTER_RANGE(Start, End) { Start, End, End - Start + 1 }\r
4036b4e5
PB
592\r
593///\r
594/// Structure used to describe a range of registers\r
595///\r
596typedef struct {\r
ac0a286f
MK
597 EFI_SMM_SAVE_STATE_REGISTER Start;\r
598 EFI_SMM_SAVE_STATE_REGISTER End;\r
599 UINTN Length;\r
4036b4e5
PB
600} CPU_SMM_SAVE_STATE_REGISTER_RANGE;\r
601\r
602///\r
603/// Structure used to build a lookup table to retrieve the widths and offsets\r
604/// associated with each supported EFI_SMM_SAVE_STATE_REGISTER value\r
605///\r
606\r
ac0a286f 607#define SMM_SAVE_STATE_REGISTER_FIRST_INDEX 1\r
4036b4e5
PB
608\r
609typedef struct {\r
ac0a286f
MK
610 UINT8 Width32;\r
611 UINT8 Width64;\r
612 UINT16 Offset32;\r
613 UINT16 Offset64Lo;\r
614 UINT16 Offset64Hi;\r
615 BOOLEAN Writeable;\r
4036b4e5
PB
616} CPU_SMM_SAVE_STATE_LOOKUP_ENTRY;\r
617\r
618///\r
b1bfdd65 619/// Table used by GetRegisterIndex() to convert an EFI_SMM_SAVE_STATE_REGISTER\r
4036b4e5
PB
620/// value to an index into a table of type CPU_SMM_SAVE_STATE_LOOKUP_ENTRY\r
621///\r
ac0a286f 622STATIC CONST CPU_SMM_SAVE_STATE_REGISTER_RANGE mSmmCpuRegisterRanges[] = {\r
b1bfdd65
LE
623 SMM_REGISTER_RANGE (\r
624 EFI_SMM_SAVE_STATE_REGISTER_GDTBASE,\r
625 EFI_SMM_SAVE_STATE_REGISTER_LDTINFO\r
626 ),\r
627 SMM_REGISTER_RANGE (\r
628 EFI_SMM_SAVE_STATE_REGISTER_ES,\r
629 EFI_SMM_SAVE_STATE_REGISTER_RIP\r
630 ),\r
631 SMM_REGISTER_RANGE (\r
632 EFI_SMM_SAVE_STATE_REGISTER_RFLAGS,\r
633 EFI_SMM_SAVE_STATE_REGISTER_CR4\r
634 ),\r
ac0a286f 635 { (EFI_SMM_SAVE_STATE_REGISTER)0, (EFI_SMM_SAVE_STATE_REGISTER)0,0 }\r
4036b4e5
PB
636};\r
637\r
638///\r
b1bfdd65
LE
639/// Lookup table used to retrieve the widths and offsets associated with each\r
640/// supported EFI_SMM_SAVE_STATE_REGISTER value\r
4036b4e5 641///\r
ac0a286f 642STATIC CONST CPU_SMM_SAVE_STATE_LOOKUP_ENTRY mSmmCpuWidthOffset[] = {\r
b1bfdd65
LE
643 {\r
644 0, // Width32\r
645 0, // Width64\r
646 0, // Offset32\r
647 0, // Offset64Lo\r
648 0, // Offset64Hi\r
649 FALSE // Writeable\r
650 }, // Reserved\r
4036b4e5
PB
651\r
652 //\r
653 // CPU Save State registers defined in PI SMM CPU Protocol.\r
654 //\r
b1bfdd65
LE
655 {\r
656 0, // Width32\r
657 8, // Width64\r
658 0, // Offset32\r
659 SMM_CPU_OFFSET (x64._GDTRBase), // Offset64Lo\r
660 SMM_CPU_OFFSET (x64._GDTRBase) + 4, // Offset64Hi\r
661 FALSE // Writeable\r
662 }, // EFI_SMM_SAVE_STATE_REGISTER_GDTBASE = 4\r
663\r
664 {\r
665 0, // Width32\r
666 8, // Width64\r
667 0, // Offset32\r
668 SMM_CPU_OFFSET (x64._IDTRBase), // Offset64Lo\r
669 SMM_CPU_OFFSET (x64._IDTRBase) + 4, // Offset64Hi\r
670 FALSE // Writeable\r
671 }, // EFI_SMM_SAVE_STATE_REGISTER_IDTBASE = 5\r
672\r
673 {\r
674 0, // Width32\r
675 8, // Width64\r
676 0, // Offset32\r
677 SMM_CPU_OFFSET (x64._LDTRBase), // Offset64Lo\r
678 SMM_CPU_OFFSET (x64._LDTRBase) + 4, // Offset64Hi\r
679 FALSE // Writeable\r
680 }, // EFI_SMM_SAVE_STATE_REGISTER_LDTBASE = 6\r
681\r
682 {\r
683 0, // Width32\r
684 0, // Width64\r
685 0, // Offset32\r
686 SMM_CPU_OFFSET (x64._GDTRLimit), // Offset64Lo\r
687 SMM_CPU_OFFSET (x64._GDTRLimit) + 4, // Offset64Hi\r
688 FALSE // Writeable\r
689 }, // EFI_SMM_SAVE_STATE_REGISTER_GDTLIMIT = 7\r
690\r
691 {\r
692 0, // Width32\r
693 0, // Width64\r
694 0, // Offset32\r
695 SMM_CPU_OFFSET (x64._IDTRLimit), // Offset64Lo\r
696 SMM_CPU_OFFSET (x64._IDTRLimit) + 4, // Offset64Hi\r
697 FALSE // Writeable\r
698 }, // EFI_SMM_SAVE_STATE_REGISTER_IDTLIMIT = 8\r
699\r
700 {\r
701 0, // Width32\r
702 0, // Width64\r
703 0, // Offset32\r
704 SMM_CPU_OFFSET (x64._LDTRLimit), // Offset64Lo\r
705 SMM_CPU_OFFSET (x64._LDTRLimit) + 4, // Offset64Hi\r
706 FALSE // Writeable\r
707 }, // EFI_SMM_SAVE_STATE_REGISTER_LDTLIMIT = 9\r
708\r
709 {\r
710 0, // Width32\r
711 0, // Width64\r
712 0, // Offset32\r
713 0, // Offset64Lo\r
714 0 + 4, // Offset64Hi\r
715 FALSE // Writeable\r
716 }, // EFI_SMM_SAVE_STATE_REGISTER_LDTINFO = 10\r
717\r
718 {\r
719 4, // Width32\r
720 4, // Width64\r
721 SMM_CPU_OFFSET (x86._ES), // Offset32\r
722 SMM_CPU_OFFSET (x64._ES), // Offset64Lo\r
723 0, // Offset64Hi\r
724 FALSE // Writeable\r
725 }, // EFI_SMM_SAVE_STATE_REGISTER_ES = 20\r
726\r
727 {\r
728 4, // Width32\r
729 4, // Width64\r
730 SMM_CPU_OFFSET (x86._CS), // Offset32\r
731 SMM_CPU_OFFSET (x64._CS), // Offset64Lo\r
732 0, // Offset64Hi\r
733 FALSE // Writeable\r
734 }, // EFI_SMM_SAVE_STATE_REGISTER_CS = 21\r
735\r
736 {\r
737 4, // Width32\r
738 4, // Width64\r
739 SMM_CPU_OFFSET (x86._SS), // Offset32\r
740 SMM_CPU_OFFSET (x64._SS), // Offset64Lo\r
741 0, // Offset64Hi\r
742 FALSE // Writeable\r
743 }, // EFI_SMM_SAVE_STATE_REGISTER_SS = 22\r
744\r
745 {\r
746 4, // Width32\r
747 4, // Width64\r
748 SMM_CPU_OFFSET (x86._DS), // Offset32\r
749 SMM_CPU_OFFSET (x64._DS), // Offset64Lo\r
750 0, // Offset64Hi\r
751 FALSE // Writeable\r
752 }, // EFI_SMM_SAVE_STATE_REGISTER_DS = 23\r
753\r
754 {\r
755 4, // Width32\r
756 4, // Width64\r
757 SMM_CPU_OFFSET (x86._FS), // Offset32\r
758 SMM_CPU_OFFSET (x64._FS), // Offset64Lo\r
759 0, // Offset64Hi\r
760 FALSE // Writeable\r
761 }, // EFI_SMM_SAVE_STATE_REGISTER_FS = 24\r
762\r
763 {\r
764 4, // Width32\r
765 4, // Width64\r
766 SMM_CPU_OFFSET (x86._GS), // Offset32\r
767 SMM_CPU_OFFSET (x64._GS), // Offset64Lo\r
768 0, // Offset64Hi\r
769 FALSE // Writeable\r
770 }, // EFI_SMM_SAVE_STATE_REGISTER_GS = 25\r
771\r
772 {\r
773 0, // Width32\r
774 4, // Width64\r
775 0, // Offset32\r
776 SMM_CPU_OFFSET (x64._LDTR), // Offset64Lo\r
777 0, // Offset64Hi\r
778 FALSE // Writeable\r
779 }, // EFI_SMM_SAVE_STATE_REGISTER_LDTR_SEL = 26\r
780\r
781 {\r
782 4, // Width32\r
783 4, // Width64\r
784 SMM_CPU_OFFSET (x86._TR), // Offset32\r
785 SMM_CPU_OFFSET (x64._TR), // Offset64Lo\r
786 0, // Offset64Hi\r
787 FALSE // Writeable\r
788 }, // EFI_SMM_SAVE_STATE_REGISTER_TR_SEL = 27\r
789\r
790 {\r
791 4, // Width32\r
792 8, // Width64\r
793 SMM_CPU_OFFSET (x86._DR7), // Offset32\r
794 SMM_CPU_OFFSET (x64._DR7), // Offset64Lo\r
795 SMM_CPU_OFFSET (x64._DR7) + 4, // Offset64Hi\r
796 FALSE // Writeable\r
797 }, // EFI_SMM_SAVE_STATE_REGISTER_DR7 = 28\r
798\r
799 {\r
800 4, // Width32\r
801 8, // Width64\r
802 SMM_CPU_OFFSET (x86._DR6), // Offset32\r
803 SMM_CPU_OFFSET (x64._DR6), // Offset64Lo\r
804 SMM_CPU_OFFSET (x64._DR6) + 4, // Offset64Hi\r
805 FALSE // Writeable\r
806 }, // EFI_SMM_SAVE_STATE_REGISTER_DR6 = 29\r
807\r
808 {\r
809 0, // Width32\r
810 8, // Width64\r
811 0, // Offset32\r
812 SMM_CPU_OFFSET (x64._R8), // Offset64Lo\r
813 SMM_CPU_OFFSET (x64._R8) + 4, // Offset64Hi\r
814 TRUE // Writeable\r
815 }, // EFI_SMM_SAVE_STATE_REGISTER_R8 = 30\r
816\r
817 {\r
818 0, // Width32\r
819 8, // Width64\r
820 0, // Offset32\r
821 SMM_CPU_OFFSET (x64._R9), // Offset64Lo\r
822 SMM_CPU_OFFSET (x64._R9) + 4, // Offset64Hi\r
823 TRUE // Writeable\r
824 }, // EFI_SMM_SAVE_STATE_REGISTER_R9 = 31\r
825\r
826 {\r
827 0, // Width32\r
828 8, // Width64\r
829 0, // Offset32\r
830 SMM_CPU_OFFSET (x64._R10), // Offset64Lo\r
831 SMM_CPU_OFFSET (x64._R10) + 4, // Offset64Hi\r
832 TRUE // Writeable\r
833 }, // EFI_SMM_SAVE_STATE_REGISTER_R10 = 32\r
834\r
835 {\r
836 0, // Width32\r
837 8, // Width64\r
838 0, // Offset32\r
839 SMM_CPU_OFFSET (x64._R11), // Offset64Lo\r
840 SMM_CPU_OFFSET (x64._R11) + 4, // Offset64Hi\r
841 TRUE // Writeable\r
842 }, // EFI_SMM_SAVE_STATE_REGISTER_R11 = 33\r
843\r
844 {\r
845 0, // Width32\r
846 8, // Width64\r
847 0, // Offset32\r
848 SMM_CPU_OFFSET (x64._R12), // Offset64Lo\r
849 SMM_CPU_OFFSET (x64._R12) + 4, // Offset64Hi\r
850 TRUE // Writeable\r
851 }, // EFI_SMM_SAVE_STATE_REGISTER_R12 = 34\r
852\r
853 {\r
854 0, // Width32\r
855 8, // Width64\r
856 0, // Offset32\r
857 SMM_CPU_OFFSET (x64._R13), // Offset64Lo\r
858 SMM_CPU_OFFSET (x64._R13) + 4, // Offset64Hi\r
859 TRUE // Writeable\r
860 }, // EFI_SMM_SAVE_STATE_REGISTER_R13 = 35\r
861\r
862 {\r
863 0, // Width32\r
864 8, // Width64\r
865 0, // Offset32\r
866 SMM_CPU_OFFSET (x64._R14), // Offset64Lo\r
867 SMM_CPU_OFFSET (x64._R14) + 4, // Offset64Hi\r
868 TRUE // Writeable\r
869 }, // EFI_SMM_SAVE_STATE_REGISTER_R14 = 36\r
870\r
871 {\r
872 0, // Width32\r
873 8, // Width64\r
874 0, // Offset32\r
875 SMM_CPU_OFFSET (x64._R15), // Offset64Lo\r
876 SMM_CPU_OFFSET (x64._R15) + 4, // Offset64Hi\r
877 TRUE // Writeable\r
878 }, // EFI_SMM_SAVE_STATE_REGISTER_R15 = 37\r
879\r
880 {\r
881 4, // Width32\r
882 8, // Width64\r
883 SMM_CPU_OFFSET (x86._EAX), // Offset32\r
884 SMM_CPU_OFFSET (x64._RAX), // Offset64Lo\r
885 SMM_CPU_OFFSET (x64._RAX) + 4, // Offset64Hi\r
886 TRUE // Writeable\r
887 }, // EFI_SMM_SAVE_STATE_REGISTER_RAX = 38\r
888\r
889 {\r
890 4, // Width32\r
891 8, // Width64\r
892 SMM_CPU_OFFSET (x86._EBX), // Offset32\r
893 SMM_CPU_OFFSET (x64._RBX), // Offset64Lo\r
894 SMM_CPU_OFFSET (x64._RBX) + 4, // Offset64Hi\r
895 TRUE // Writeable\r
896 }, // EFI_SMM_SAVE_STATE_REGISTER_RBX = 39\r
897\r
898 {\r
899 4, // Width32\r
900 8, // Width64\r
901 SMM_CPU_OFFSET (x86._ECX), // Offset32\r
902 SMM_CPU_OFFSET (x64._RCX), // Offset64Lo\r
903 SMM_CPU_OFFSET (x64._RCX) + 4, // Offset64Hi\r
904 TRUE // Writeable\r
905 }, // EFI_SMM_SAVE_STATE_REGISTER_RCX = 40\r
906\r
907 {\r
908 4, // Width32\r
909 8, // Width64\r
910 SMM_CPU_OFFSET (x86._EDX), // Offset32\r
911 SMM_CPU_OFFSET (x64._RDX), // Offset64Lo\r
912 SMM_CPU_OFFSET (x64._RDX) + 4, // Offset64Hi\r
913 TRUE // Writeable\r
914 }, // EFI_SMM_SAVE_STATE_REGISTER_RDX = 41\r
915\r
916 {\r
917 4, // Width32\r
918 8, // Width64\r
919 SMM_CPU_OFFSET (x86._ESP), // Offset32\r
920 SMM_CPU_OFFSET (x64._RSP), // Offset64Lo\r
921 SMM_CPU_OFFSET (x64._RSP) + 4, // Offset64Hi\r
922 TRUE // Writeable\r
923 }, // EFI_SMM_SAVE_STATE_REGISTER_RSP = 42\r
924\r
925 {\r
926 4, // Width32\r
927 8, // Width64\r
928 SMM_CPU_OFFSET (x86._EBP), // Offset32\r
929 SMM_CPU_OFFSET (x64._RBP), // Offset64Lo\r
930 SMM_CPU_OFFSET (x64._RBP) + 4, // Offset64Hi\r
931 TRUE // Writeable\r
932 }, // EFI_SMM_SAVE_STATE_REGISTER_RBP = 43\r
933\r
934 {\r
935 4, // Width32\r
936 8, // Width64\r
937 SMM_CPU_OFFSET (x86._ESI), // Offset32\r
938 SMM_CPU_OFFSET (x64._RSI), // Offset64Lo\r
939 SMM_CPU_OFFSET (x64._RSI) + 4, // Offset64Hi\r
940 TRUE // Writeable\r
941 }, // EFI_SMM_SAVE_STATE_REGISTER_RSI = 44\r
942\r
943 {\r
944 4, // Width32\r
945 8, // Width64\r
946 SMM_CPU_OFFSET (x86._EDI), // Offset32\r
947 SMM_CPU_OFFSET (x64._RDI), // Offset64Lo\r
948 SMM_CPU_OFFSET (x64._RDI) + 4, // Offset64Hi\r
949 TRUE // Writeable\r
950 }, // EFI_SMM_SAVE_STATE_REGISTER_RDI = 45\r
951\r
952 {\r
953 4, // Width32\r
954 8, // Width64\r
955 SMM_CPU_OFFSET (x86._EIP), // Offset32\r
956 SMM_CPU_OFFSET (x64._RIP), // Offset64Lo\r
957 SMM_CPU_OFFSET (x64._RIP) + 4, // Offset64Hi\r
958 TRUE // Writeable\r
959 }, // EFI_SMM_SAVE_STATE_REGISTER_RIP = 46\r
960\r
961 {\r
962 4, // Width32\r
963 8, // Width64\r
964 SMM_CPU_OFFSET (x86._EFLAGS), // Offset32\r
965 SMM_CPU_OFFSET (x64._RFLAGS), // Offset64Lo\r
966 SMM_CPU_OFFSET (x64._RFLAGS) + 4, // Offset64Hi\r
967 TRUE // Writeable\r
968 }, // EFI_SMM_SAVE_STATE_REGISTER_RFLAGS = 51\r
969\r
970 {\r
971 4, // Width32\r
972 8, // Width64\r
973 SMM_CPU_OFFSET (x86._CR0), // Offset32\r
974 SMM_CPU_OFFSET (x64._CR0), // Offset64Lo\r
975 SMM_CPU_OFFSET (x64._CR0) + 4, // Offset64Hi\r
976 FALSE // Writeable\r
977 }, // EFI_SMM_SAVE_STATE_REGISTER_CR0 = 52\r
978\r
979 {\r
980 4, // Width32\r
981 8, // Width64\r
982 SMM_CPU_OFFSET (x86._CR3), // Offset32\r
983 SMM_CPU_OFFSET (x64._CR3), // Offset64Lo\r
984 SMM_CPU_OFFSET (x64._CR3) + 4, // Offset64Hi\r
985 FALSE // Writeable\r
986 }, // EFI_SMM_SAVE_STATE_REGISTER_CR3 = 53\r
987\r
988 {\r
989 0, // Width32\r
990 4, // Width64\r
991 0, // Offset32\r
992 SMM_CPU_OFFSET (x64._CR4), // Offset64Lo\r
993 SMM_CPU_OFFSET (x64._CR4) + 4, // Offset64Hi\r
994 FALSE // Writeable\r
995 }, // EFI_SMM_SAVE_STATE_REGISTER_CR4 = 54\r
4036b4e5
PB
996};\r
997\r
998//\r
999// No support for I/O restart\r
1000//\r
1001\r
1002/**\r
1003 Read information from the CPU save state.\r
1004\r
1005 @param Register Specifies the CPU register to read form the save state.\r
1006\r
1007 @retval 0 Register is not valid\r
1008 @retval >0 Index into mSmmCpuWidthOffset[] associated with Register\r
1009\r
1010**/\r
ea992760
LE
1011STATIC\r
1012UINTN\r
4036b4e5
PB
1013GetRegisterIndex (\r
1014 IN EFI_SMM_SAVE_STATE_REGISTER Register\r
1015 )\r
1016{\r
1017 UINTN Index;\r
1018 UINTN Offset;\r
1019\r
b1bfdd65
LE
1020 for (Index = 0, Offset = SMM_SAVE_STATE_REGISTER_FIRST_INDEX;\r
1021 mSmmCpuRegisterRanges[Index].Length != 0;\r
ac0a286f
MK
1022 Index++)\r
1023 {\r
1024 if ((Register >= mSmmCpuRegisterRanges[Index].Start) &&\r
1025 (Register <= mSmmCpuRegisterRanges[Index].End))\r
1026 {\r
4036b4e5
PB
1027 return Register - mSmmCpuRegisterRanges[Index].Start + Offset;\r
1028 }\r
ac0a286f 1029\r
4036b4e5
PB
1030 Offset += mSmmCpuRegisterRanges[Index].Length;\r
1031 }\r
ac0a286f 1032\r
4036b4e5
PB
1033 return 0;\r
1034}\r
1035\r
1036/**\r
1037 Read a CPU Save State register on the target processor.\r
1038\r
b1bfdd65
LE
1039 This function abstracts the differences that whether the CPU Save State\r
1040 register is in the IA32 CPU Save State Map or X64 CPU Save State Map.\r
4036b4e5 1041\r
b1bfdd65
LE
1042 This function supports reading a CPU Save State register in SMBase relocation\r
1043 handler.\r
4036b4e5 1044\r
b1bfdd65
LE
1045 @param[in] CpuIndex Specifies the zero-based index of the CPU save\r
1046 state.\r
4036b4e5 1047 @param[in] RegisterIndex Index into mSmmCpuWidthOffset[] look up table.\r
b1bfdd65
LE
1048 @param[in] Width The number of bytes to read from the CPU save\r
1049 state.\r
1050 @param[out] Buffer Upon return, this holds the CPU register value\r
1051 read from the save state.\r
4036b4e5
PB
1052\r
1053 @retval EFI_SUCCESS The register was read from Save State.\r
b1bfdd65
LE
1054 @retval EFI_NOT_FOUND The register is not defined for the Save State\r
1055 of Processor.\r
4036b4e5
PB
1056 @retval EFI_INVALID_PARAMTER This or Buffer is NULL.\r
1057\r
1058**/\r
ea992760
LE
1059STATIC\r
1060EFI_STATUS\r
4036b4e5 1061ReadSaveStateRegisterByIndex (\r
ac0a286f
MK
1062 IN UINTN CpuIndex,\r
1063 IN UINTN RegisterIndex,\r
1064 IN UINTN Width,\r
1065 OUT VOID *Buffer\r
4036b4e5
PB
1066 )\r
1067{\r
c1fcd80b 1068 QEMU_SMRAM_SAVE_STATE_MAP *CpuSaveState;\r
4036b4e5 1069\r
c1fcd80b 1070 CpuSaveState = (QEMU_SMRAM_SAVE_STATE_MAP *)gSmst->CpuSaveState[CpuIndex];\r
4036b4e5
PB
1071\r
1072 if ((CpuSaveState->x86.SMMRevId & 0xFFFF) == 0) {\r
1073 //\r
b1bfdd65
LE
1074 // If 32-bit mode width is zero, then the specified register can not be\r
1075 // accessed\r
4036b4e5
PB
1076 //\r
1077 if (mSmmCpuWidthOffset[RegisterIndex].Width32 == 0) {\r
1078 return EFI_NOT_FOUND;\r
1079 }\r
1080\r
1081 //\r
b1bfdd65
LE
1082 // If Width is bigger than the 32-bit mode width, then the specified\r
1083 // register can not be accessed\r
4036b4e5
PB
1084 //\r
1085 if (Width > mSmmCpuWidthOffset[RegisterIndex].Width32) {\r
1086 return EFI_INVALID_PARAMETER;\r
1087 }\r
1088\r
1089 //\r
1090 // Write return buffer\r
1091 //\r
ac0a286f 1092 ASSERT (CpuSaveState != NULL);\r
b1bfdd65
LE
1093 CopyMem (\r
1094 Buffer,\r
1095 (UINT8 *)CpuSaveState + mSmmCpuWidthOffset[RegisterIndex].Offset32,\r
1096 Width\r
1097 );\r
4036b4e5
PB
1098 } else {\r
1099 //\r
b1bfdd65
LE
1100 // If 64-bit mode width is zero, then the specified register can not be\r
1101 // accessed\r
4036b4e5
PB
1102 //\r
1103 if (mSmmCpuWidthOffset[RegisterIndex].Width64 == 0) {\r
1104 return EFI_NOT_FOUND;\r
1105 }\r
1106\r
1107 //\r
b1bfdd65
LE
1108 // If Width is bigger than the 64-bit mode width, then the specified\r
1109 // register can not be accessed\r
4036b4e5
PB
1110 //\r
1111 if (Width > mSmmCpuWidthOffset[RegisterIndex].Width64) {\r
1112 return EFI_INVALID_PARAMETER;\r
1113 }\r
1114\r
1115 //\r
1116 // Write lower 32-bits of return buffer\r
1117 //\r
b1bfdd65
LE
1118 CopyMem (\r
1119 Buffer,\r
1120 (UINT8 *)CpuSaveState + mSmmCpuWidthOffset[RegisterIndex].Offset64Lo,\r
1121 MIN (4, Width)\r
1122 );\r
4036b4e5
PB
1123 if (Width >= 4) {\r
1124 //\r
1125 // Write upper 32-bits of return buffer\r
1126 //\r
b1bfdd65
LE
1127 CopyMem (\r
1128 (UINT8 *)Buffer + 4,\r
1129 (UINT8 *)CpuSaveState + mSmmCpuWidthOffset[RegisterIndex].Offset64Hi,\r
1130 Width - 4\r
1131 );\r
4036b4e5
PB
1132 }\r
1133 }\r
ac0a286f 1134\r
4036b4e5
PB
1135 return EFI_SUCCESS;\r
1136}\r
1137\r
86d71589
PB
1138/**\r
1139 Read an SMM Save State register on the target processor. If this function\r
1140 returns EFI_UNSUPPORTED, then the caller is responsible for reading the\r
1141 SMM Save Sate register.\r
1142\r
1143 @param[in] CpuIndex The index of the CPU to read the SMM Save State. The\r
1144 value must be between 0 and the NumberOfCpus field in\r
1145 the System Management System Table (SMST).\r
1146 @param[in] Register The SMM Save State register to read.\r
1147 @param[in] Width The number of bytes to read from the CPU save state.\r
1148 @param[out] Buffer Upon return, this holds the CPU register value read\r
1149 from the save state.\r
1150\r
1151 @retval EFI_SUCCESS The register was read from Save State.\r
1152 @retval EFI_INVALID_PARAMTER Buffer is NULL.\r
b1bfdd65
LE
1153 @retval EFI_UNSUPPORTED This function does not support reading\r
1154 Register.\r
86d71589
PB
1155**/\r
1156EFI_STATUS\r
1157EFIAPI\r
1158SmmCpuFeaturesReadSaveStateRegister (\r
1159 IN UINTN CpuIndex,\r
1160 IN EFI_SMM_SAVE_STATE_REGISTER Register,\r
1161 IN UINTN Width,\r
1162 OUT VOID *Buffer\r
1163 )\r
1164{\r
ac0a286f 1165 UINTN RegisterIndex;\r
c1fcd80b 1166 QEMU_SMRAM_SAVE_STATE_MAP *CpuSaveState;\r
4036b4e5
PB
1167\r
1168 //\r
1169 // Check for special EFI_SMM_SAVE_STATE_REGISTER_LMA\r
1170 //\r
1171 if (Register == EFI_SMM_SAVE_STATE_REGISTER_LMA) {\r
1172 //\r
1173 // Only byte access is supported for this register\r
1174 //\r
1175 if (Width != 1) {\r
1176 return EFI_INVALID_PARAMETER;\r
1177 }\r
1178\r
c1fcd80b 1179 CpuSaveState = (QEMU_SMRAM_SAVE_STATE_MAP *)gSmst->CpuSaveState[CpuIndex];\r
4036b4e5
PB
1180\r
1181 //\r
1182 // Check CPU mode\r
1183 //\r
1184 if ((CpuSaveState->x86.SMMRevId & 0xFFFF) == 0) {\r
1185 *(UINT8 *)Buffer = 32;\r
1186 } else {\r
1187 *(UINT8 *)Buffer = 64;\r
1188 }\r
1189\r
1190 return EFI_SUCCESS;\r
1191 }\r
1192\r
1193 //\r
1194 // Check for special EFI_SMM_SAVE_STATE_REGISTER_IO\r
1195 //\r
1196 if (Register == EFI_SMM_SAVE_STATE_REGISTER_IO) {\r
1197 return EFI_NOT_FOUND;\r
1198 }\r
1199\r
1200 //\r
1201 // Convert Register to a register lookup table index. Let\r
1202 // PiSmmCpuDxeSmm implement other special registers (currently\r
1203 // there is only EFI_SMM_SAVE_STATE_REGISTER_PROCESSOR_ID).\r
1204 //\r
1205 RegisterIndex = GetRegisterIndex (Register);\r
1206 if (RegisterIndex == 0) {\r
b1bfdd65
LE
1207 return (Register < EFI_SMM_SAVE_STATE_REGISTER_IO ?\r
1208 EFI_NOT_FOUND :\r
1209 EFI_UNSUPPORTED);\r
4036b4e5
PB
1210 }\r
1211\r
1212 return ReadSaveStateRegisterByIndex (CpuIndex, RegisterIndex, Width, Buffer);\r
86d71589
PB
1213}\r
1214\r
1215/**\r
1216 Writes an SMM Save State register on the target processor. If this function\r
1217 returns EFI_UNSUPPORTED, then the caller is responsible for writing the\r
1218 SMM Save Sate register.\r
1219\r
1220 @param[in] CpuIndex The index of the CPU to write the SMM Save State. The\r
1221 value must be between 0 and the NumberOfCpus field in\r
1222 the System Management System Table (SMST).\r
1223 @param[in] Register The SMM Save State register to write.\r
1224 @param[in] Width The number of bytes to write to the CPU save state.\r
1225 @param[in] Buffer Upon entry, this holds the new CPU register value.\r
1226\r
1227 @retval EFI_SUCCESS The register was written to Save State.\r
1228 @retval EFI_INVALID_PARAMTER Buffer is NULL.\r
b1bfdd65
LE
1229 @retval EFI_UNSUPPORTED This function does not support writing\r
1230 Register.\r
86d71589
PB
1231**/\r
1232EFI_STATUS\r
1233EFIAPI\r
1234SmmCpuFeaturesWriteSaveStateRegister (\r
1235 IN UINTN CpuIndex,\r
1236 IN EFI_SMM_SAVE_STATE_REGISTER Register,\r
1237 IN UINTN Width,\r
1238 IN CONST VOID *Buffer\r
1239 )\r
1240{\r
ac0a286f 1241 UINTN RegisterIndex;\r
c1fcd80b 1242 QEMU_SMRAM_SAVE_STATE_MAP *CpuSaveState;\r
4036b4e5
PB
1243\r
1244 //\r
1245 // Writes to EFI_SMM_SAVE_STATE_REGISTER_LMA are ignored\r
1246 //\r
1247 if (Register == EFI_SMM_SAVE_STATE_REGISTER_LMA) {\r
1248 return EFI_SUCCESS;\r
1249 }\r
1250\r
1251 //\r
1252 // Writes to EFI_SMM_SAVE_STATE_REGISTER_IO are not supported\r
1253 //\r
1254 if (Register == EFI_SMM_SAVE_STATE_REGISTER_IO) {\r
1255 return EFI_NOT_FOUND;\r
1256 }\r
1257\r
1258 //\r
1259 // Convert Register to a register lookup table index. Let\r
1260 // PiSmmCpuDxeSmm implement other special registers (currently\r
1261 // there is only EFI_SMM_SAVE_STATE_REGISTER_PROCESSOR_ID).\r
1262 //\r
1263 RegisterIndex = GetRegisterIndex (Register);\r
1264 if (RegisterIndex == 0) {\r
b1bfdd65
LE
1265 return (Register < EFI_SMM_SAVE_STATE_REGISTER_IO ?\r
1266 EFI_NOT_FOUND :\r
1267 EFI_UNSUPPORTED);\r
4036b4e5
PB
1268 }\r
1269\r
c1fcd80b 1270 CpuSaveState = (QEMU_SMRAM_SAVE_STATE_MAP *)gSmst->CpuSaveState[CpuIndex];\r
4036b4e5
PB
1271\r
1272 //\r
1273 // Do not write non-writable SaveState, because it will cause exception.\r
b1bfdd65 1274 //\r
4036b4e5
PB
1275 if (!mSmmCpuWidthOffset[RegisterIndex].Writeable) {\r
1276 return EFI_UNSUPPORTED;\r
1277 }\r
1278\r
1279 //\r
1280 // Check CPU mode\r
1281 //\r
1282 if ((CpuSaveState->x86.SMMRevId & 0xFFFF) == 0) {\r
1283 //\r
b1bfdd65
LE
1284 // If 32-bit mode width is zero, then the specified register can not be\r
1285 // accessed\r
4036b4e5
PB
1286 //\r
1287 if (mSmmCpuWidthOffset[RegisterIndex].Width32 == 0) {\r
1288 return EFI_NOT_FOUND;\r
1289 }\r
1290\r
1291 //\r
b1bfdd65
LE
1292 // If Width is bigger than the 32-bit mode width, then the specified\r
1293 // register can not be accessed\r
4036b4e5
PB
1294 //\r
1295 if (Width > mSmmCpuWidthOffset[RegisterIndex].Width32) {\r
1296 return EFI_INVALID_PARAMETER;\r
1297 }\r
ac0a286f 1298\r
4036b4e5
PB
1299 //\r
1300 // Write SMM State register\r
1301 //\r
1302 ASSERT (CpuSaveState != NULL);\r
b1bfdd65
LE
1303 CopyMem (\r
1304 (UINT8 *)CpuSaveState + mSmmCpuWidthOffset[RegisterIndex].Offset32,\r
1305 Buffer,\r
1306 Width\r
1307 );\r
4036b4e5
PB
1308 } else {\r
1309 //\r
b1bfdd65
LE
1310 // If 64-bit mode width is zero, then the specified register can not be\r
1311 // accessed\r
4036b4e5
PB
1312 //\r
1313 if (mSmmCpuWidthOffset[RegisterIndex].Width64 == 0) {\r
1314 return EFI_NOT_FOUND;\r
1315 }\r
1316\r
1317 //\r
b1bfdd65
LE
1318 // If Width is bigger than the 64-bit mode width, then the specified\r
1319 // register can not be accessed\r
4036b4e5
PB
1320 //\r
1321 if (Width > mSmmCpuWidthOffset[RegisterIndex].Width64) {\r
1322 return EFI_INVALID_PARAMETER;\r
1323 }\r
1324\r
1325 //\r
1326 // Write lower 32-bits of SMM State register\r
1327 //\r
b1bfdd65
LE
1328 CopyMem (\r
1329 (UINT8 *)CpuSaveState + mSmmCpuWidthOffset[RegisterIndex].Offset64Lo,\r
1330 Buffer,\r
1331 MIN (4, Width)\r
1332 );\r
4036b4e5
PB
1333 if (Width >= 4) {\r
1334 //\r
1335 // Write upper 32-bits of SMM State register\r
1336 //\r
b1bfdd65
LE
1337 CopyMem (\r
1338 (UINT8 *)CpuSaveState + mSmmCpuWidthOffset[RegisterIndex].Offset64Hi,\r
1339 (UINT8 *)Buffer + 4,\r
1340 Width - 4\r
1341 );\r
4036b4e5
PB
1342 }\r
1343 }\r
ac0a286f 1344\r
4036b4e5 1345 return EFI_SUCCESS;\r
86d71589
PB
1346}\r
1347\r
1348/**\r
1349 This function is hook point called after the gEfiSmmReadyToLockProtocolGuid\r
1350 notification is completely processed.\r
1351**/\r
1352VOID\r
1353EFIAPI\r
1354SmmCpuFeaturesCompleteSmmReadyToLock (\r
1355 VOID\r
1356 )\r
1357{\r
1358}\r