]> git.proxmox.com Git - mirror_edk2.git/blame_incremental - OvmfPkg/Library/SmmCpuFeaturesLib/SmmCpuFeaturesLib.c
UefiCpuPkg: Move AsmRelocateApLoopStart from Mpfuncs.nasm to AmdSev.nasm
[mirror_edk2.git] / OvmfPkg / Library / SmmCpuFeaturesLib / SmmCpuFeaturesLib.c
... / ...
CommitLineData
1/** @file\r
2 The CPU specific programming for PiSmmCpuDxeSmm module.\r
3\r
4 Copyright (c) 2010 - 2023, Intel Corporation. All rights reserved.<BR>\r
5\r
6 SPDX-License-Identifier: BSD-2-Clause-Patent\r
7**/\r
8\r
9#include <IndustryStandard/Q35MchIch9.h>\r
10#include <Library/BaseLib.h>\r
11#include <Library/BaseMemoryLib.h>\r
12#include <Library/DebugLib.h>\r
13#include <Library/MemEncryptSevLib.h>\r
14#include <Library/MemoryAllocationLib.h>\r
15#include <Library/PcdLib.h>\r
16#include <Library/SafeIntLib.h>\r
17#include <Library/SmmCpuFeaturesLib.h>\r
18#include <Library/SmmServicesTableLib.h>\r
19#include <Library/UefiBootServicesTableLib.h>\r
20#include <Library/HobLib.h>\r
21#include <Pcd/CpuHotEjectData.h>\r
22#include <PiSmm.h>\r
23#include <Register/Intel/SmramSaveStateMap.h>\r
24#include <Register/QemuSmramSaveStateMap.h>\r
25#include <Guid/SmmBaseHob.h>\r
26\r
27//\r
28// EFER register LMA bit\r
29//\r
30#define LMA BIT10\r
31\r
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
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
54 //\r
55 // No need to program SMRRs on our virtual platform.\r
56 //\r
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
93 QEMU_SMRAM_SAVE_STATE_MAP *CpuState;\r
94\r
95 //\r
96 // Configure SMBASE.\r
97 //\r
98 CpuState = (QEMU_SMRAM_SAVE_STATE_MAP *)(UINTN)(\r
99 SMM_DEFAULT_SMBASE +\r
100 SMRAM_SAVE_STATE_MAP_OFFSET\r
101 );\r
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
107\r
108 //\r
109 // No need to program SMRRs on our virtual platform.\r
110 //\r
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
131 field in the System Management System\r
132 Table (SMST).\r
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
153 UINT64 OriginalInstructionPointer;\r
154 QEMU_SMRAM_SAVE_STATE_MAP *CpuSaveState;\r
155\r
156 CpuSaveState = (QEMU_SMRAM_SAVE_STATE_MAP *)CpuState;\r
157 if ((CpuSaveState->x86.SMMRevId & 0xFFFF) == 0) {\r
158 OriginalInstructionPointer = (UINT64)CpuSaveState->x86._EIP;\r
159 CpuSaveState->x86._EIP = (UINT32)NewInstructionPointer;\r
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
174\r
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
183\r
184 return OriginalInstructionPointer;\r
185}\r
186\r
187STATIC CPU_HOT_EJECT_DATA *mCpuHotEjectData = NULL;\r
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
221 RETURN_ERROR (SafeUintnAdd (Size, sizeof (UINT64) - 1, &Size)))\r
222 {\r
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
233 mCpuHotEjectData->Handler = NULL;\r
234 mCpuHotEjectData->ArrayLength = MaxNumberOfCpus;\r
235\r
236 mCpuHotEjectData->QemuSelectorMap = ALIGN_POINTER (\r
237 mCpuHotEjectData + 1,\r
238 sizeof (UINT64)\r
239 );\r
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
251 PcdStatus = PcdSet64S (\r
252 PcdCpuHotEjectDataAddress,\r
253 (UINTN)(VOID *)mCpuHotEjectData\r
254 );\r
255 ASSERT_RETURN_ERROR (PcdStatus);\r
256\r
257 return;\r
258\r
259Fatal:\r
260 CpuDeadLoop ();\r
261}\r
262\r
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
276 EFI_STATUS Status;\r
277 UINTN MapPagesBase;\r
278 UINTN MapPagesCount;\r
279\r
280 InitCpuHotEjectData ();\r
281\r
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
300 MapPagesCount // NumPages\r
301 );\r
302 if (EFI_ERROR (Status)) {\r
303 DEBUG ((\r
304 DEBUG_ERROR,\r
305 "%a: MemEncryptSevSetPageEncMask(): %r\n",\r
306 __FUNCTION__,\r
307 Status\r
308 ));\r
309 ASSERT (FALSE);\r
310 CpuDeadLoop ();\r
311 }\r
312\r
313 ZeroMem ((VOID *)MapPagesBase, EFI_PAGES_TO_SIZE (MapPagesCount));\r
314\r
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
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
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
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
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
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
408 return FALSE;\r
409}\r
410\r
411/**\r
412 Disable SMRR register if SMRR is supported and\r
413 SmmCpuFeaturesNeedConfigureMtrrs() returns TRUE.\r
414**/\r
415VOID\r
416EFIAPI\r
417SmmCpuFeaturesDisableSmrr (\r
418 VOID\r
419 )\r
420{\r
421 //\r
422 // No SMRR support, nothing to do\r
423 //\r
424}\r
425\r
426/**\r
427 Enable SMRR register if SMRR is supported and\r
428 SmmCpuFeaturesNeedConfigureMtrrs() returns TRUE.\r
429**/\r
430VOID\r
431EFIAPI\r
432SmmCpuFeaturesReenableSmrr (\r
433 VOID\r
434 )\r
435{\r
436 //\r
437 // No SMRR support, nothing to do\r
438 //\r
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
455 // No SMRR support, nothing to do\r
456 //\r
457}\r
458\r
459/**\r
460 Processor specific hook point each time a CPU exits System Management Mode.\r
461\r
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
465**/\r
466VOID\r
467EFIAPI\r
468SmmCpuFeaturesRendezvousExit (\r
469 IN UINTN CpuIndex\r
470 )\r
471{\r
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
479 CPU_HOT_EJECT_HANDLER Handler;\r
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
498 MemoryFence ();\r
499\r
500 Handler = mCpuHotEjectData->Handler;\r
501\r
502 if (Handler != NULL) {\r
503 Handler (CpuIndex);\r
504 }\r
505 }\r
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
528 ASSERT (RegName == SmmRegFeatureControl);\r
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
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
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
578 ASSERT (FALSE);\r
579}\r
580\r
581///\r
582/// Macro used to simplify the lookup table entries of type\r
583/// CPU_SMM_SAVE_STATE_LOOKUP_ENTRY\r
584///\r
585#define SMM_CPU_OFFSET(Field) OFFSET_OF (QEMU_SMRAM_SAVE_STATE_MAP, Field)\r
586\r
587///\r
588/// Macro used to simplify the lookup table entries of type\r
589/// CPU_SMM_SAVE_STATE_REGISTER_RANGE\r
590///\r
591#define SMM_REGISTER_RANGE(Start, End) { Start, End, End - Start + 1 }\r
592\r
593///\r
594/// Structure used to describe a range of registers\r
595///\r
596typedef struct {\r
597 EFI_SMM_SAVE_STATE_REGISTER Start;\r
598 EFI_SMM_SAVE_STATE_REGISTER End;\r
599 UINTN Length;\r
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
607#define SMM_SAVE_STATE_REGISTER_FIRST_INDEX 1\r
608\r
609typedef struct {\r
610 UINT8 Width32;\r
611 UINT8 Width64;\r
612 UINT16 Offset32;\r
613 UINT16 Offset64Lo;\r
614 UINT16 Offset64Hi;\r
615 BOOLEAN Writeable;\r
616} CPU_SMM_SAVE_STATE_LOOKUP_ENTRY;\r
617\r
618///\r
619/// Table used by GetRegisterIndex() to convert an EFI_SMM_SAVE_STATE_REGISTER\r
620/// value to an index into a table of type CPU_SMM_SAVE_STATE_LOOKUP_ENTRY\r
621///\r
622STATIC CONST CPU_SMM_SAVE_STATE_REGISTER_RANGE mSmmCpuRegisterRanges[] = {\r
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
635 { (EFI_SMM_SAVE_STATE_REGISTER)0, (EFI_SMM_SAVE_STATE_REGISTER)0,0 }\r
636};\r
637\r
638///\r
639/// Lookup table used to retrieve the widths and offsets associated with each\r
640/// supported EFI_SMM_SAVE_STATE_REGISTER value\r
641///\r
642STATIC CONST CPU_SMM_SAVE_STATE_LOOKUP_ENTRY mSmmCpuWidthOffset[] = {\r
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
651\r
652 //\r
653 // CPU Save State registers defined in PI SMM CPU Protocol.\r
654 //\r
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
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
1011STATIC\r
1012UINTN\r
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
1020 for (Index = 0, Offset = SMM_SAVE_STATE_REGISTER_FIRST_INDEX;\r
1021 mSmmCpuRegisterRanges[Index].Length != 0;\r
1022 Index++)\r
1023 {\r
1024 if ((Register >= mSmmCpuRegisterRanges[Index].Start) &&\r
1025 (Register <= mSmmCpuRegisterRanges[Index].End))\r
1026 {\r
1027 return Register - mSmmCpuRegisterRanges[Index].Start + Offset;\r
1028 }\r
1029\r
1030 Offset += mSmmCpuRegisterRanges[Index].Length;\r
1031 }\r
1032\r
1033 return 0;\r
1034}\r
1035\r
1036/**\r
1037 Read a CPU Save State register on the target processor.\r
1038\r
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
1041\r
1042 This function supports reading a CPU Save State register in SMBase relocation\r
1043 handler.\r
1044\r
1045 @param[in] CpuIndex Specifies the zero-based index of the CPU save\r
1046 state.\r
1047 @param[in] RegisterIndex Index into mSmmCpuWidthOffset[] look up table.\r
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
1052\r
1053 @retval EFI_SUCCESS The register was read from Save State.\r
1054 @retval EFI_NOT_FOUND The register is not defined for the Save State\r
1055 of Processor.\r
1056 @retval EFI_INVALID_PARAMTER This or Buffer is NULL.\r
1057\r
1058**/\r
1059STATIC\r
1060EFI_STATUS\r
1061ReadSaveStateRegisterByIndex (\r
1062 IN UINTN CpuIndex,\r
1063 IN UINTN RegisterIndex,\r
1064 IN UINTN Width,\r
1065 OUT VOID *Buffer\r
1066 )\r
1067{\r
1068 QEMU_SMRAM_SAVE_STATE_MAP *CpuSaveState;\r
1069\r
1070 CpuSaveState = (QEMU_SMRAM_SAVE_STATE_MAP *)gSmst->CpuSaveState[CpuIndex];\r
1071\r
1072 if ((CpuSaveState->x86.SMMRevId & 0xFFFF) == 0) {\r
1073 //\r
1074 // If 32-bit mode width is zero, then the specified register can not be\r
1075 // accessed\r
1076 //\r
1077 if (mSmmCpuWidthOffset[RegisterIndex].Width32 == 0) {\r
1078 return EFI_NOT_FOUND;\r
1079 }\r
1080\r
1081 //\r
1082 // If Width is bigger than the 32-bit mode width, then the specified\r
1083 // register can not be accessed\r
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
1092 ASSERT (CpuSaveState != NULL);\r
1093 CopyMem (\r
1094 Buffer,\r
1095 (UINT8 *)CpuSaveState + mSmmCpuWidthOffset[RegisterIndex].Offset32,\r
1096 Width\r
1097 );\r
1098 } else {\r
1099 //\r
1100 // If 64-bit mode width is zero, then the specified register can not be\r
1101 // accessed\r
1102 //\r
1103 if (mSmmCpuWidthOffset[RegisterIndex].Width64 == 0) {\r
1104 return EFI_NOT_FOUND;\r
1105 }\r
1106\r
1107 //\r
1108 // If Width is bigger than the 64-bit mode width, then the specified\r
1109 // register can not be accessed\r
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
1118 CopyMem (\r
1119 Buffer,\r
1120 (UINT8 *)CpuSaveState + mSmmCpuWidthOffset[RegisterIndex].Offset64Lo,\r
1121 MIN (4, Width)\r
1122 );\r
1123 if (Width >= 4) {\r
1124 //\r
1125 // Write upper 32-bits of return buffer\r
1126 //\r
1127 CopyMem (\r
1128 (UINT8 *)Buffer + 4,\r
1129 (UINT8 *)CpuSaveState + mSmmCpuWidthOffset[RegisterIndex].Offset64Hi,\r
1130 Width - 4\r
1131 );\r
1132 }\r
1133 }\r
1134\r
1135 return EFI_SUCCESS;\r
1136}\r
1137\r
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
1153 @retval EFI_UNSUPPORTED This function does not support reading\r
1154 Register.\r
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
1165 UINTN RegisterIndex;\r
1166 QEMU_SMRAM_SAVE_STATE_MAP *CpuSaveState;\r
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
1179 CpuSaveState = (QEMU_SMRAM_SAVE_STATE_MAP *)gSmst->CpuSaveState[CpuIndex];\r
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
1207 return (Register < EFI_SMM_SAVE_STATE_REGISTER_IO ?\r
1208 EFI_NOT_FOUND :\r
1209 EFI_UNSUPPORTED);\r
1210 }\r
1211\r
1212 return ReadSaveStateRegisterByIndex (CpuIndex, RegisterIndex, Width, Buffer);\r
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
1229 @retval EFI_UNSUPPORTED This function does not support writing\r
1230 Register.\r
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
1241 UINTN RegisterIndex;\r
1242 QEMU_SMRAM_SAVE_STATE_MAP *CpuSaveState;\r
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
1265 return (Register < EFI_SMM_SAVE_STATE_REGISTER_IO ?\r
1266 EFI_NOT_FOUND :\r
1267 EFI_UNSUPPORTED);\r
1268 }\r
1269\r
1270 CpuSaveState = (QEMU_SMRAM_SAVE_STATE_MAP *)gSmst->CpuSaveState[CpuIndex];\r
1271\r
1272 //\r
1273 // Do not write non-writable SaveState, because it will cause exception.\r
1274 //\r
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
1284 // If 32-bit mode width is zero, then the specified register can not be\r
1285 // accessed\r
1286 //\r
1287 if (mSmmCpuWidthOffset[RegisterIndex].Width32 == 0) {\r
1288 return EFI_NOT_FOUND;\r
1289 }\r
1290\r
1291 //\r
1292 // If Width is bigger than the 32-bit mode width, then the specified\r
1293 // register can not be accessed\r
1294 //\r
1295 if (Width > mSmmCpuWidthOffset[RegisterIndex].Width32) {\r
1296 return EFI_INVALID_PARAMETER;\r
1297 }\r
1298\r
1299 //\r
1300 // Write SMM State register\r
1301 //\r
1302 ASSERT (CpuSaveState != NULL);\r
1303 CopyMem (\r
1304 (UINT8 *)CpuSaveState + mSmmCpuWidthOffset[RegisterIndex].Offset32,\r
1305 Buffer,\r
1306 Width\r
1307 );\r
1308 } else {\r
1309 //\r
1310 // If 64-bit mode width is zero, then the specified register can not be\r
1311 // accessed\r
1312 //\r
1313 if (mSmmCpuWidthOffset[RegisterIndex].Width64 == 0) {\r
1314 return EFI_NOT_FOUND;\r
1315 }\r
1316\r
1317 //\r
1318 // If Width is bigger than the 64-bit mode width, then the specified\r
1319 // register can not be accessed\r
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
1328 CopyMem (\r
1329 (UINT8 *)CpuSaveState + mSmmCpuWidthOffset[RegisterIndex].Offset64Lo,\r
1330 Buffer,\r
1331 MIN (4, Width)\r
1332 );\r
1333 if (Width >= 4) {\r
1334 //\r
1335 // Write upper 32-bits of SMM State register\r
1336 //\r
1337 CopyMem (\r
1338 (UINT8 *)CpuSaveState + mSmmCpuWidthOffset[RegisterIndex].Offset64Hi,\r
1339 (UINT8 *)Buffer + 4,\r
1340 Width - 4\r
1341 );\r
1342 }\r
1343 }\r
1344\r
1345 return EFI_SUCCESS;\r
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