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