]> git.proxmox.com Git - mirror_edk2.git/blame - OvmfPkg/Library/SmmCpuFeaturesLib/SmmCpuFeaturesLib.c
OvmfPkg/SmmCpuFeaturesLib: init CPU ejection state
[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
286 MapPagesCount, // NumPages\r
287 TRUE // Flush\r
288 );\r
289 if (EFI_ERROR (Status)) {\r
290 DEBUG ((DEBUG_ERROR, "%a: MemEncryptSevSetPageEncMask(): %r\n",\r
291 __FUNCTION__, Status));\r
292 ASSERT (FALSE);\r
293 CpuDeadLoop ();\r
294 }\r
295\r
296 ZeroMem ((VOID *)MapPagesBase, EFI_PAGES_TO_SIZE (MapPagesCount));\r
297\r
300aae11
LE
298 if (PcdGetBool (PcdQ35SmramAtDefaultSmbase)) {\r
299 //\r
300 // The initial SMRAM Save State Map has been covered as part of a larger\r
301 // reserved memory allocation in PlatformPei's InitializeRamRegions(). That\r
302 // allocation is supposed to survive into OS runtime; we must not release\r
303 // any part of it. Only re-assert the containment here.\r
304 //\r
305 ASSERT (SMM_DEFAULT_SMBASE <= MapPagesBase);\r
306 ASSERT (\r
307 (MapPagesBase + EFI_PAGES_TO_SIZE (MapPagesCount) <=\r
308 SMM_DEFAULT_SMBASE + MCH_DEFAULT_SMBASE_SIZE)\r
309 );\r
310 } else {\r
311 Status = gBS->FreePages (MapPagesBase, MapPagesCount);\r
312 ASSERT_EFI_ERROR (Status);\r
313 }\r
86d71589
PB
314}\r
315\r
316/**\r
317 Return the size, in bytes, of a custom SMI Handler in bytes. If 0 is\r
318 returned, then a custom SMI handler is not provided by this library,\r
319 and the default SMI handler must be used.\r
320\r
321 @retval 0 Use the default SMI handler.\r
b1bfdd65
LE
322 @retval > 0 Use the SMI handler installed by\r
323 SmmCpuFeaturesInstallSmiHandler(). The caller is required to\r
324 allocate enough SMRAM for each CPU to support the size of the\r
325 custom SMI handler.\r
86d71589
PB
326**/\r
327UINTN\r
328EFIAPI\r
329SmmCpuFeaturesGetSmiHandlerSize (\r
330 VOID\r
331 )\r
332{\r
333 return 0;\r
334}\r
335\r
336/**\r
b1bfdd65
LE
337 Install a custom SMI handler for the CPU specified by CpuIndex. This\r
338 function is only called if SmmCpuFeaturesGetSmiHandlerSize() returns a size\r
339 is greater than zero and is called by the CPU that was elected as monarch\r
340 during System Management Mode initialization.\r
86d71589
PB
341\r
342 @param[in] CpuIndex The index of the CPU to install the custom SMI handler.\r
343 The value must be between 0 and the NumberOfCpus field\r
344 in the System Management System Table (SMST).\r
345 @param[in] SmBase The SMBASE address for the CPU specified by CpuIndex.\r
346 @param[in] SmiStack The stack to use when an SMI is processed by the\r
347 the CPU specified by CpuIndex.\r
348 @param[in] StackSize The size, in bytes, if the stack used when an SMI is\r
349 processed by the CPU specified by CpuIndex.\r
350 @param[in] GdtBase The base address of the GDT to use when an SMI is\r
351 processed by the CPU specified by CpuIndex.\r
352 @param[in] GdtSize The size, in bytes, of the GDT used when an SMI is\r
353 processed by the CPU specified by CpuIndex.\r
354 @param[in] IdtBase The base address of the IDT to use when an SMI is\r
355 processed by the CPU specified by CpuIndex.\r
356 @param[in] IdtSize The size, in bytes, of the IDT used when an SMI is\r
357 processed by the CPU specified by CpuIndex.\r
358 @param[in] Cr3 The base address of the page tables to use when an SMI\r
359 is processed by the CPU specified by CpuIndex.\r
360**/\r
361VOID\r
362EFIAPI\r
363SmmCpuFeaturesInstallSmiHandler (\r
364 IN UINTN CpuIndex,\r
365 IN UINT32 SmBase,\r
366 IN VOID *SmiStack,\r
367 IN UINTN StackSize,\r
368 IN UINTN GdtBase,\r
369 IN UINTN GdtSize,\r
370 IN UINTN IdtBase,\r
371 IN UINTN IdtSize,\r
372 IN UINT32 Cr3\r
373 )\r
374{\r
375}\r
376\r
377/**\r
378 Determines if MTRR registers must be configured to set SMRAM cache-ability\r
379 when executing in System Management Mode.\r
380\r
381 @retval TRUE MTRR registers must be configured to set SMRAM cache-ability.\r
382 @retval FALSE MTRR registers do not need to be configured to set SMRAM\r
383 cache-ability.\r
384**/\r
385BOOLEAN\r
386EFIAPI\r
387SmmCpuFeaturesNeedConfigureMtrrs (\r
388 VOID\r
389 )\r
390{\r
d7e71b29 391 return FALSE;\r
86d71589
PB
392}\r
393\r
394/**\r
b1bfdd65
LE
395 Disable SMRR register if SMRR is supported and\r
396 SmmCpuFeaturesNeedConfigureMtrrs() returns TRUE.\r
86d71589
PB
397**/\r
398VOID\r
399EFIAPI\r
400SmmCpuFeaturesDisableSmrr (\r
401 VOID\r
402 )\r
403{\r
d7e71b29
PB
404 //\r
405 // No SMRR support, nothing to do\r
406 //\r
86d71589
PB
407}\r
408\r
409/**\r
b1bfdd65
LE
410 Enable SMRR register if SMRR is supported and\r
411 SmmCpuFeaturesNeedConfigureMtrrs() returns TRUE.\r
86d71589
PB
412**/\r
413VOID\r
414EFIAPI\r
415SmmCpuFeaturesReenableSmrr (\r
416 VOID\r
417 )\r
418{\r
d7e71b29
PB
419 //\r
420 // No SMRR support, nothing to do\r
421 //\r
86d71589
PB
422}\r
423\r
424/**\r
425 Processor specific hook point each time a CPU enters System Management Mode.\r
426\r
427 @param[in] CpuIndex The index of the CPU that has entered SMM. The value\r
428 must be between 0 and the NumberOfCpus field in the\r
429 System Management System Table (SMST).\r
430**/\r
431VOID\r
432EFIAPI\r
433SmmCpuFeaturesRendezvousEntry (\r
434 IN UINTN CpuIndex\r
435 )\r
436{\r
437 //\r
d7e71b29 438 // No SMRR support, nothing to do\r
86d71589 439 //\r
86d71589
PB
440}\r
441\r
442/**\r
443 Processor specific hook point each time a CPU exits System Management Mode.\r
444\r
b1bfdd65
LE
445 @param[in] CpuIndex The index of the CPU that is exiting SMM. The value\r
446 must be between 0 and the NumberOfCpus field in the\r
447 System Management System Table (SMST).\r
86d71589
PB
448**/\r
449VOID\r
450EFIAPI\r
451SmmCpuFeaturesRendezvousExit (\r
452 IN UINTN CpuIndex\r
453 )\r
454{\r
455}\r
456\r
457/**\r
458 Check to see if an SMM register is supported by a specified CPU.\r
459\r
460 @param[in] CpuIndex The index of the CPU to check for SMM register support.\r
461 The value must be between 0 and the NumberOfCpus field\r
462 in the System Management System Table (SMST).\r
463 @param[in] RegName Identifies the SMM register to check for support.\r
464\r
465 @retval TRUE The SMM register specified by RegName is supported by the CPU\r
466 specified by CpuIndex.\r
467 @retval FALSE The SMM register specified by RegName is not supported by the\r
468 CPU specified by CpuIndex.\r
469**/\r
470BOOLEAN\r
471EFIAPI\r
472SmmCpuFeaturesIsSmmRegisterSupported (\r
473 IN UINTN CpuIndex,\r
474 IN SMM_REG_NAME RegName\r
475 )\r
476{\r
d7e71b29 477 ASSERT (RegName == SmmRegFeatureControl);\r
86d71589
PB
478 return FALSE;\r
479}\r
480\r
481/**\r
482 Returns the current value of the SMM register for the specified CPU.\r
483 If the SMM register is not supported, then 0 is returned.\r
484\r
485 @param[in] CpuIndex The index of the CPU to read the SMM register. The\r
486 value must be between 0 and the NumberOfCpus field in\r
487 the System Management System Table (SMST).\r
488 @param[in] RegName Identifies the SMM register to read.\r
489\r
490 @return The value of the SMM register specified by RegName from the CPU\r
491 specified by CpuIndex.\r
492**/\r
493UINT64\r
494EFIAPI\r
495SmmCpuFeaturesGetSmmRegister (\r
496 IN UINTN CpuIndex,\r
497 IN SMM_REG_NAME RegName\r
498 )\r
499{\r
d7e71b29
PB
500 //\r
501 // This is called for SmmRegSmmDelayed, SmmRegSmmBlocked, SmmRegSmmEnable.\r
502 // The last of these should actually be SmmRegSmmDisable, so we can just\r
503 // return FALSE.\r
504 //\r
86d71589
PB
505 return 0;\r
506}\r
507\r
508/**\r
509 Sets the value of an SMM register on a specified CPU.\r
510 If the SMM register is not supported, then no action is performed.\r
511\r
512 @param[in] CpuIndex The index of the CPU to write the SMM register. The\r
513 value must be between 0 and the NumberOfCpus field in\r
514 the System Management System Table (SMST).\r
515 @param[in] RegName Identifies the SMM register to write.\r
516 registers are read-only.\r
517 @param[in] Value The value to write to the SMM register.\r
518**/\r
519VOID\r
520EFIAPI\r
521SmmCpuFeaturesSetSmmRegister (\r
522 IN UINTN CpuIndex,\r
523 IN SMM_REG_NAME RegName,\r
524 IN UINT64 Value\r
525 )\r
526{\r
d7e71b29 527 ASSERT (FALSE);\r
86d71589
PB
528}\r
529\r
4036b4e5 530///\r
b1bfdd65
LE
531/// Macro used to simplify the lookup table entries of type\r
532/// CPU_SMM_SAVE_STATE_LOOKUP_ENTRY\r
4036b4e5 533///\r
c1fcd80b 534#define SMM_CPU_OFFSET(Field) OFFSET_OF (QEMU_SMRAM_SAVE_STATE_MAP, Field)\r
4036b4e5
PB
535\r
536///\r
b1bfdd65
LE
537/// Macro used to simplify the lookup table entries of type\r
538/// CPU_SMM_SAVE_STATE_REGISTER_RANGE\r
4036b4e5
PB
539///\r
540#define SMM_REGISTER_RANGE(Start, End) { Start, End, End - Start + 1 }\r
541\r
542///\r
543/// Structure used to describe a range of registers\r
544///\r
545typedef struct {\r
546 EFI_SMM_SAVE_STATE_REGISTER Start;\r
547 EFI_SMM_SAVE_STATE_REGISTER End;\r
548 UINTN Length;\r
549} CPU_SMM_SAVE_STATE_REGISTER_RANGE;\r
550\r
551///\r
552/// Structure used to build a lookup table to retrieve the widths and offsets\r
553/// associated with each supported EFI_SMM_SAVE_STATE_REGISTER value\r
554///\r
555\r
556#define SMM_SAVE_STATE_REGISTER_FIRST_INDEX 1\r
557\r
558typedef struct {\r
559 UINT8 Width32;\r
560 UINT8 Width64;\r
561 UINT16 Offset32;\r
562 UINT16 Offset64Lo;\r
563 UINT16 Offset64Hi;\r
564 BOOLEAN Writeable;\r
565} CPU_SMM_SAVE_STATE_LOOKUP_ENTRY;\r
566\r
567///\r
b1bfdd65 568/// Table used by GetRegisterIndex() to convert an EFI_SMM_SAVE_STATE_REGISTER\r
4036b4e5
PB
569/// value to an index into a table of type CPU_SMM_SAVE_STATE_LOOKUP_ENTRY\r
570///\r
ea992760 571STATIC CONST CPU_SMM_SAVE_STATE_REGISTER_RANGE mSmmCpuRegisterRanges[] = {\r
b1bfdd65
LE
572 SMM_REGISTER_RANGE (\r
573 EFI_SMM_SAVE_STATE_REGISTER_GDTBASE,\r
574 EFI_SMM_SAVE_STATE_REGISTER_LDTINFO\r
575 ),\r
576 SMM_REGISTER_RANGE (\r
577 EFI_SMM_SAVE_STATE_REGISTER_ES,\r
578 EFI_SMM_SAVE_STATE_REGISTER_RIP\r
579 ),\r
580 SMM_REGISTER_RANGE (\r
581 EFI_SMM_SAVE_STATE_REGISTER_RFLAGS,\r
582 EFI_SMM_SAVE_STATE_REGISTER_CR4\r
583 ),\r
4036b4e5
PB
584 { (EFI_SMM_SAVE_STATE_REGISTER)0, (EFI_SMM_SAVE_STATE_REGISTER)0, 0 }\r
585};\r
586\r
587///\r
b1bfdd65
LE
588/// Lookup table used to retrieve the widths and offsets associated with each\r
589/// supported EFI_SMM_SAVE_STATE_REGISTER value\r
4036b4e5 590///\r
ea992760 591STATIC CONST CPU_SMM_SAVE_STATE_LOOKUP_ENTRY mSmmCpuWidthOffset[] = {\r
b1bfdd65
LE
592 {\r
593 0, // Width32\r
594 0, // Width64\r
595 0, // Offset32\r
596 0, // Offset64Lo\r
597 0, // Offset64Hi\r
598 FALSE // Writeable\r
599 }, // Reserved\r
4036b4e5
PB
600\r
601 //\r
602 // CPU Save State registers defined in PI SMM CPU Protocol.\r
603 //\r
b1bfdd65
LE
604 {\r
605 0, // Width32\r
606 8, // Width64\r
607 0, // Offset32\r
608 SMM_CPU_OFFSET (x64._GDTRBase), // Offset64Lo\r
609 SMM_CPU_OFFSET (x64._GDTRBase) + 4, // Offset64Hi\r
610 FALSE // Writeable\r
611 }, // EFI_SMM_SAVE_STATE_REGISTER_GDTBASE = 4\r
612\r
613 {\r
614 0, // Width32\r
615 8, // Width64\r
616 0, // Offset32\r
617 SMM_CPU_OFFSET (x64._IDTRBase), // Offset64Lo\r
618 SMM_CPU_OFFSET (x64._IDTRBase) + 4, // Offset64Hi\r
619 FALSE // Writeable\r
620 }, // EFI_SMM_SAVE_STATE_REGISTER_IDTBASE = 5\r
621\r
622 {\r
623 0, // Width32\r
624 8, // Width64\r
625 0, // Offset32\r
626 SMM_CPU_OFFSET (x64._LDTRBase), // Offset64Lo\r
627 SMM_CPU_OFFSET (x64._LDTRBase) + 4, // Offset64Hi\r
628 FALSE // Writeable\r
629 }, // EFI_SMM_SAVE_STATE_REGISTER_LDTBASE = 6\r
630\r
631 {\r
632 0, // Width32\r
633 0, // Width64\r
634 0, // Offset32\r
635 SMM_CPU_OFFSET (x64._GDTRLimit), // Offset64Lo\r
636 SMM_CPU_OFFSET (x64._GDTRLimit) + 4, // Offset64Hi\r
637 FALSE // Writeable\r
638 }, // EFI_SMM_SAVE_STATE_REGISTER_GDTLIMIT = 7\r
639\r
640 {\r
641 0, // Width32\r
642 0, // Width64\r
643 0, // Offset32\r
644 SMM_CPU_OFFSET (x64._IDTRLimit), // Offset64Lo\r
645 SMM_CPU_OFFSET (x64._IDTRLimit) + 4, // Offset64Hi\r
646 FALSE // Writeable\r
647 }, // EFI_SMM_SAVE_STATE_REGISTER_IDTLIMIT = 8\r
648\r
649 {\r
650 0, // Width32\r
651 0, // Width64\r
652 0, // Offset32\r
653 SMM_CPU_OFFSET (x64._LDTRLimit), // Offset64Lo\r
654 SMM_CPU_OFFSET (x64._LDTRLimit) + 4, // Offset64Hi\r
655 FALSE // Writeable\r
656 }, // EFI_SMM_SAVE_STATE_REGISTER_LDTLIMIT = 9\r
657\r
658 {\r
659 0, // Width32\r
660 0, // Width64\r
661 0, // Offset32\r
662 0, // Offset64Lo\r
663 0 + 4, // Offset64Hi\r
664 FALSE // Writeable\r
665 }, // EFI_SMM_SAVE_STATE_REGISTER_LDTINFO = 10\r
666\r
667 {\r
668 4, // Width32\r
669 4, // Width64\r
670 SMM_CPU_OFFSET (x86._ES), // Offset32\r
671 SMM_CPU_OFFSET (x64._ES), // Offset64Lo\r
672 0, // Offset64Hi\r
673 FALSE // Writeable\r
674 }, // EFI_SMM_SAVE_STATE_REGISTER_ES = 20\r
675\r
676 {\r
677 4, // Width32\r
678 4, // Width64\r
679 SMM_CPU_OFFSET (x86._CS), // Offset32\r
680 SMM_CPU_OFFSET (x64._CS), // Offset64Lo\r
681 0, // Offset64Hi\r
682 FALSE // Writeable\r
683 }, // EFI_SMM_SAVE_STATE_REGISTER_CS = 21\r
684\r
685 {\r
686 4, // Width32\r
687 4, // Width64\r
688 SMM_CPU_OFFSET (x86._SS), // Offset32\r
689 SMM_CPU_OFFSET (x64._SS), // Offset64Lo\r
690 0, // Offset64Hi\r
691 FALSE // Writeable\r
692 }, // EFI_SMM_SAVE_STATE_REGISTER_SS = 22\r
693\r
694 {\r
695 4, // Width32\r
696 4, // Width64\r
697 SMM_CPU_OFFSET (x86._DS), // Offset32\r
698 SMM_CPU_OFFSET (x64._DS), // Offset64Lo\r
699 0, // Offset64Hi\r
700 FALSE // Writeable\r
701 }, // EFI_SMM_SAVE_STATE_REGISTER_DS = 23\r
702\r
703 {\r
704 4, // Width32\r
705 4, // Width64\r
706 SMM_CPU_OFFSET (x86._FS), // Offset32\r
707 SMM_CPU_OFFSET (x64._FS), // Offset64Lo\r
708 0, // Offset64Hi\r
709 FALSE // Writeable\r
710 }, // EFI_SMM_SAVE_STATE_REGISTER_FS = 24\r
711\r
712 {\r
713 4, // Width32\r
714 4, // Width64\r
715 SMM_CPU_OFFSET (x86._GS), // Offset32\r
716 SMM_CPU_OFFSET (x64._GS), // Offset64Lo\r
717 0, // Offset64Hi\r
718 FALSE // Writeable\r
719 }, // EFI_SMM_SAVE_STATE_REGISTER_GS = 25\r
720\r
721 {\r
722 0, // Width32\r
723 4, // Width64\r
724 0, // Offset32\r
725 SMM_CPU_OFFSET (x64._LDTR), // Offset64Lo\r
726 0, // Offset64Hi\r
727 FALSE // Writeable\r
728 }, // EFI_SMM_SAVE_STATE_REGISTER_LDTR_SEL = 26\r
729\r
730 {\r
731 4, // Width32\r
732 4, // Width64\r
733 SMM_CPU_OFFSET (x86._TR), // Offset32\r
734 SMM_CPU_OFFSET (x64._TR), // Offset64Lo\r
735 0, // Offset64Hi\r
736 FALSE // Writeable\r
737 }, // EFI_SMM_SAVE_STATE_REGISTER_TR_SEL = 27\r
738\r
739 {\r
740 4, // Width32\r
741 8, // Width64\r
742 SMM_CPU_OFFSET (x86._DR7), // Offset32\r
743 SMM_CPU_OFFSET (x64._DR7), // Offset64Lo\r
744 SMM_CPU_OFFSET (x64._DR7) + 4, // Offset64Hi\r
745 FALSE // Writeable\r
746 }, // EFI_SMM_SAVE_STATE_REGISTER_DR7 = 28\r
747\r
748 {\r
749 4, // Width32\r
750 8, // Width64\r
751 SMM_CPU_OFFSET (x86._DR6), // Offset32\r
752 SMM_CPU_OFFSET (x64._DR6), // Offset64Lo\r
753 SMM_CPU_OFFSET (x64._DR6) + 4, // Offset64Hi\r
754 FALSE // Writeable\r
755 }, // EFI_SMM_SAVE_STATE_REGISTER_DR6 = 29\r
756\r
757 {\r
758 0, // Width32\r
759 8, // Width64\r
760 0, // Offset32\r
761 SMM_CPU_OFFSET (x64._R8), // Offset64Lo\r
762 SMM_CPU_OFFSET (x64._R8) + 4, // Offset64Hi\r
763 TRUE // Writeable\r
764 }, // EFI_SMM_SAVE_STATE_REGISTER_R8 = 30\r
765\r
766 {\r
767 0, // Width32\r
768 8, // Width64\r
769 0, // Offset32\r
770 SMM_CPU_OFFSET (x64._R9), // Offset64Lo\r
771 SMM_CPU_OFFSET (x64._R9) + 4, // Offset64Hi\r
772 TRUE // Writeable\r
773 }, // EFI_SMM_SAVE_STATE_REGISTER_R9 = 31\r
774\r
775 {\r
776 0, // Width32\r
777 8, // Width64\r
778 0, // Offset32\r
779 SMM_CPU_OFFSET (x64._R10), // Offset64Lo\r
780 SMM_CPU_OFFSET (x64._R10) + 4, // Offset64Hi\r
781 TRUE // Writeable\r
782 }, // EFI_SMM_SAVE_STATE_REGISTER_R10 = 32\r
783\r
784 {\r
785 0, // Width32\r
786 8, // Width64\r
787 0, // Offset32\r
788 SMM_CPU_OFFSET (x64._R11), // Offset64Lo\r
789 SMM_CPU_OFFSET (x64._R11) + 4, // Offset64Hi\r
790 TRUE // Writeable\r
791 }, // EFI_SMM_SAVE_STATE_REGISTER_R11 = 33\r
792\r
793 {\r
794 0, // Width32\r
795 8, // Width64\r
796 0, // Offset32\r
797 SMM_CPU_OFFSET (x64._R12), // Offset64Lo\r
798 SMM_CPU_OFFSET (x64._R12) + 4, // Offset64Hi\r
799 TRUE // Writeable\r
800 }, // EFI_SMM_SAVE_STATE_REGISTER_R12 = 34\r
801\r
802 {\r
803 0, // Width32\r
804 8, // Width64\r
805 0, // Offset32\r
806 SMM_CPU_OFFSET (x64._R13), // Offset64Lo\r
807 SMM_CPU_OFFSET (x64._R13) + 4, // Offset64Hi\r
808 TRUE // Writeable\r
809 }, // EFI_SMM_SAVE_STATE_REGISTER_R13 = 35\r
810\r
811 {\r
812 0, // Width32\r
813 8, // Width64\r
814 0, // Offset32\r
815 SMM_CPU_OFFSET (x64._R14), // Offset64Lo\r
816 SMM_CPU_OFFSET (x64._R14) + 4, // Offset64Hi\r
817 TRUE // Writeable\r
818 }, // EFI_SMM_SAVE_STATE_REGISTER_R14 = 36\r
819\r
820 {\r
821 0, // Width32\r
822 8, // Width64\r
823 0, // Offset32\r
824 SMM_CPU_OFFSET (x64._R15), // Offset64Lo\r
825 SMM_CPU_OFFSET (x64._R15) + 4, // Offset64Hi\r
826 TRUE // Writeable\r
827 }, // EFI_SMM_SAVE_STATE_REGISTER_R15 = 37\r
828\r
829 {\r
830 4, // Width32\r
831 8, // Width64\r
832 SMM_CPU_OFFSET (x86._EAX), // Offset32\r
833 SMM_CPU_OFFSET (x64._RAX), // Offset64Lo\r
834 SMM_CPU_OFFSET (x64._RAX) + 4, // Offset64Hi\r
835 TRUE // Writeable\r
836 }, // EFI_SMM_SAVE_STATE_REGISTER_RAX = 38\r
837\r
838 {\r
839 4, // Width32\r
840 8, // Width64\r
841 SMM_CPU_OFFSET (x86._EBX), // Offset32\r
842 SMM_CPU_OFFSET (x64._RBX), // Offset64Lo\r
843 SMM_CPU_OFFSET (x64._RBX) + 4, // Offset64Hi\r
844 TRUE // Writeable\r
845 }, // EFI_SMM_SAVE_STATE_REGISTER_RBX = 39\r
846\r
847 {\r
848 4, // Width32\r
849 8, // Width64\r
850 SMM_CPU_OFFSET (x86._ECX), // Offset32\r
851 SMM_CPU_OFFSET (x64._RCX), // Offset64Lo\r
852 SMM_CPU_OFFSET (x64._RCX) + 4, // Offset64Hi\r
853 TRUE // Writeable\r
854 }, // EFI_SMM_SAVE_STATE_REGISTER_RCX = 40\r
855\r
856 {\r
857 4, // Width32\r
858 8, // Width64\r
859 SMM_CPU_OFFSET (x86._EDX), // Offset32\r
860 SMM_CPU_OFFSET (x64._RDX), // Offset64Lo\r
861 SMM_CPU_OFFSET (x64._RDX) + 4, // Offset64Hi\r
862 TRUE // Writeable\r
863 }, // EFI_SMM_SAVE_STATE_REGISTER_RDX = 41\r
864\r
865 {\r
866 4, // Width32\r
867 8, // Width64\r
868 SMM_CPU_OFFSET (x86._ESP), // Offset32\r
869 SMM_CPU_OFFSET (x64._RSP), // Offset64Lo\r
870 SMM_CPU_OFFSET (x64._RSP) + 4, // Offset64Hi\r
871 TRUE // Writeable\r
872 }, // EFI_SMM_SAVE_STATE_REGISTER_RSP = 42\r
873\r
874 {\r
875 4, // Width32\r
876 8, // Width64\r
877 SMM_CPU_OFFSET (x86._EBP), // Offset32\r
878 SMM_CPU_OFFSET (x64._RBP), // Offset64Lo\r
879 SMM_CPU_OFFSET (x64._RBP) + 4, // Offset64Hi\r
880 TRUE // Writeable\r
881 }, // EFI_SMM_SAVE_STATE_REGISTER_RBP = 43\r
882\r
883 {\r
884 4, // Width32\r
885 8, // Width64\r
886 SMM_CPU_OFFSET (x86._ESI), // Offset32\r
887 SMM_CPU_OFFSET (x64._RSI), // Offset64Lo\r
888 SMM_CPU_OFFSET (x64._RSI) + 4, // Offset64Hi\r
889 TRUE // Writeable\r
890 }, // EFI_SMM_SAVE_STATE_REGISTER_RSI = 44\r
891\r
892 {\r
893 4, // Width32\r
894 8, // Width64\r
895 SMM_CPU_OFFSET (x86._EDI), // Offset32\r
896 SMM_CPU_OFFSET (x64._RDI), // Offset64Lo\r
897 SMM_CPU_OFFSET (x64._RDI) + 4, // Offset64Hi\r
898 TRUE // Writeable\r
899 }, // EFI_SMM_SAVE_STATE_REGISTER_RDI = 45\r
900\r
901 {\r
902 4, // Width32\r
903 8, // Width64\r
904 SMM_CPU_OFFSET (x86._EIP), // Offset32\r
905 SMM_CPU_OFFSET (x64._RIP), // Offset64Lo\r
906 SMM_CPU_OFFSET (x64._RIP) + 4, // Offset64Hi\r
907 TRUE // Writeable\r
908 }, // EFI_SMM_SAVE_STATE_REGISTER_RIP = 46\r
909\r
910 {\r
911 4, // Width32\r
912 8, // Width64\r
913 SMM_CPU_OFFSET (x86._EFLAGS), // Offset32\r
914 SMM_CPU_OFFSET (x64._RFLAGS), // Offset64Lo\r
915 SMM_CPU_OFFSET (x64._RFLAGS) + 4, // Offset64Hi\r
916 TRUE // Writeable\r
917 }, // EFI_SMM_SAVE_STATE_REGISTER_RFLAGS = 51\r
918\r
919 {\r
920 4, // Width32\r
921 8, // Width64\r
922 SMM_CPU_OFFSET (x86._CR0), // Offset32\r
923 SMM_CPU_OFFSET (x64._CR0), // Offset64Lo\r
924 SMM_CPU_OFFSET (x64._CR0) + 4, // Offset64Hi\r
925 FALSE // Writeable\r
926 }, // EFI_SMM_SAVE_STATE_REGISTER_CR0 = 52\r
927\r
928 {\r
929 4, // Width32\r
930 8, // Width64\r
931 SMM_CPU_OFFSET (x86._CR3), // Offset32\r
932 SMM_CPU_OFFSET (x64._CR3), // Offset64Lo\r
933 SMM_CPU_OFFSET (x64._CR3) + 4, // Offset64Hi\r
934 FALSE // Writeable\r
935 }, // EFI_SMM_SAVE_STATE_REGISTER_CR3 = 53\r
936\r
937 {\r
938 0, // Width32\r
939 4, // Width64\r
940 0, // Offset32\r
941 SMM_CPU_OFFSET (x64._CR4), // Offset64Lo\r
942 SMM_CPU_OFFSET (x64._CR4) + 4, // Offset64Hi\r
943 FALSE // Writeable\r
944 }, // EFI_SMM_SAVE_STATE_REGISTER_CR4 = 54\r
4036b4e5
PB
945};\r
946\r
947//\r
948// No support for I/O restart\r
949//\r
950\r
951/**\r
952 Read information from the CPU save state.\r
953\r
954 @param Register Specifies the CPU register to read form the save state.\r
955\r
956 @retval 0 Register is not valid\r
957 @retval >0 Index into mSmmCpuWidthOffset[] associated with Register\r
958\r
959**/\r
ea992760
LE
960STATIC\r
961UINTN\r
4036b4e5
PB
962GetRegisterIndex (\r
963 IN EFI_SMM_SAVE_STATE_REGISTER Register\r
964 )\r
965{\r
966 UINTN Index;\r
967 UINTN Offset;\r
968\r
b1bfdd65
LE
969 for (Index = 0, Offset = SMM_SAVE_STATE_REGISTER_FIRST_INDEX;\r
970 mSmmCpuRegisterRanges[Index].Length != 0;\r
971 Index++) {\r
972 if (Register >= mSmmCpuRegisterRanges[Index].Start &&\r
973 Register <= mSmmCpuRegisterRanges[Index].End) {\r
4036b4e5
PB
974 return Register - mSmmCpuRegisterRanges[Index].Start + Offset;\r
975 }\r
976 Offset += mSmmCpuRegisterRanges[Index].Length;\r
977 }\r
978 return 0;\r
979}\r
980\r
981/**\r
982 Read a CPU Save State register on the target processor.\r
983\r
b1bfdd65
LE
984 This function abstracts the differences that whether the CPU Save State\r
985 register is in the IA32 CPU Save State Map or X64 CPU Save State Map.\r
4036b4e5 986\r
b1bfdd65
LE
987 This function supports reading a CPU Save State register in SMBase relocation\r
988 handler.\r
4036b4e5 989\r
b1bfdd65
LE
990 @param[in] CpuIndex Specifies the zero-based index of the CPU save\r
991 state.\r
4036b4e5 992 @param[in] RegisterIndex Index into mSmmCpuWidthOffset[] look up table.\r
b1bfdd65
LE
993 @param[in] Width The number of bytes to read from the CPU save\r
994 state.\r
995 @param[out] Buffer Upon return, this holds the CPU register value\r
996 read from the save state.\r
4036b4e5
PB
997\r
998 @retval EFI_SUCCESS The register was read from Save State.\r
b1bfdd65
LE
999 @retval EFI_NOT_FOUND The register is not defined for the Save State\r
1000 of Processor.\r
4036b4e5
PB
1001 @retval EFI_INVALID_PARAMTER This or Buffer is NULL.\r
1002\r
1003**/\r
ea992760
LE
1004STATIC\r
1005EFI_STATUS\r
4036b4e5
PB
1006ReadSaveStateRegisterByIndex (\r
1007 IN UINTN CpuIndex,\r
1008 IN UINTN RegisterIndex,\r
1009 IN UINTN Width,\r
1010 OUT VOID *Buffer\r
1011 )\r
1012{\r
c1fcd80b 1013 QEMU_SMRAM_SAVE_STATE_MAP *CpuSaveState;\r
4036b4e5 1014\r
c1fcd80b 1015 CpuSaveState = (QEMU_SMRAM_SAVE_STATE_MAP *)gSmst->CpuSaveState[CpuIndex];\r
4036b4e5
PB
1016\r
1017 if ((CpuSaveState->x86.SMMRevId & 0xFFFF) == 0) {\r
1018 //\r
b1bfdd65
LE
1019 // If 32-bit mode width is zero, then the specified register can not be\r
1020 // accessed\r
4036b4e5
PB
1021 //\r
1022 if (mSmmCpuWidthOffset[RegisterIndex].Width32 == 0) {\r
1023 return EFI_NOT_FOUND;\r
1024 }\r
1025\r
1026 //\r
b1bfdd65
LE
1027 // If Width is bigger than the 32-bit mode width, then the specified\r
1028 // register can not be accessed\r
4036b4e5
PB
1029 //\r
1030 if (Width > mSmmCpuWidthOffset[RegisterIndex].Width32) {\r
1031 return EFI_INVALID_PARAMETER;\r
1032 }\r
1033\r
1034 //\r
1035 // Write return buffer\r
1036 //\r
1037 ASSERT(CpuSaveState != NULL);\r
b1bfdd65
LE
1038 CopyMem (\r
1039 Buffer,\r
1040 (UINT8 *)CpuSaveState + mSmmCpuWidthOffset[RegisterIndex].Offset32,\r
1041 Width\r
1042 );\r
4036b4e5
PB
1043 } else {\r
1044 //\r
b1bfdd65
LE
1045 // If 64-bit mode width is zero, then the specified register can not be\r
1046 // accessed\r
4036b4e5
PB
1047 //\r
1048 if (mSmmCpuWidthOffset[RegisterIndex].Width64 == 0) {\r
1049 return EFI_NOT_FOUND;\r
1050 }\r
1051\r
1052 //\r
b1bfdd65
LE
1053 // If Width is bigger than the 64-bit mode width, then the specified\r
1054 // register can not be accessed\r
4036b4e5
PB
1055 //\r
1056 if (Width > mSmmCpuWidthOffset[RegisterIndex].Width64) {\r
1057 return EFI_INVALID_PARAMETER;\r
1058 }\r
1059\r
1060 //\r
1061 // Write lower 32-bits of return buffer\r
1062 //\r
b1bfdd65
LE
1063 CopyMem (\r
1064 Buffer,\r
1065 (UINT8 *)CpuSaveState + mSmmCpuWidthOffset[RegisterIndex].Offset64Lo,\r
1066 MIN (4, Width)\r
1067 );\r
4036b4e5
PB
1068 if (Width >= 4) {\r
1069 //\r
1070 // Write upper 32-bits of return buffer\r
1071 //\r
b1bfdd65
LE
1072 CopyMem (\r
1073 (UINT8 *)Buffer + 4,\r
1074 (UINT8 *)CpuSaveState + mSmmCpuWidthOffset[RegisterIndex].Offset64Hi,\r
1075 Width - 4\r
1076 );\r
4036b4e5
PB
1077 }\r
1078 }\r
1079 return EFI_SUCCESS;\r
1080}\r
1081\r
86d71589
PB
1082/**\r
1083 Read an SMM Save State register on the target processor. If this function\r
1084 returns EFI_UNSUPPORTED, then the caller is responsible for reading the\r
1085 SMM Save Sate register.\r
1086\r
1087 @param[in] CpuIndex The index of the CPU to read the SMM Save State. The\r
1088 value must be between 0 and the NumberOfCpus field in\r
1089 the System Management System Table (SMST).\r
1090 @param[in] Register The SMM Save State register to read.\r
1091 @param[in] Width The number of bytes to read from the CPU save state.\r
1092 @param[out] Buffer Upon return, this holds the CPU register value read\r
1093 from the save state.\r
1094\r
1095 @retval EFI_SUCCESS The register was read from Save State.\r
1096 @retval EFI_INVALID_PARAMTER Buffer is NULL.\r
b1bfdd65
LE
1097 @retval EFI_UNSUPPORTED This function does not support reading\r
1098 Register.\r
86d71589
PB
1099**/\r
1100EFI_STATUS\r
1101EFIAPI\r
1102SmmCpuFeaturesReadSaveStateRegister (\r
1103 IN UINTN CpuIndex,\r
1104 IN EFI_SMM_SAVE_STATE_REGISTER Register,\r
1105 IN UINTN Width,\r
1106 OUT VOID *Buffer\r
1107 )\r
1108{\r
c1fcd80b
PB
1109 UINTN RegisterIndex;\r
1110 QEMU_SMRAM_SAVE_STATE_MAP *CpuSaveState;\r
4036b4e5
PB
1111\r
1112 //\r
1113 // Check for special EFI_SMM_SAVE_STATE_REGISTER_LMA\r
1114 //\r
1115 if (Register == EFI_SMM_SAVE_STATE_REGISTER_LMA) {\r
1116 //\r
1117 // Only byte access is supported for this register\r
1118 //\r
1119 if (Width != 1) {\r
1120 return EFI_INVALID_PARAMETER;\r
1121 }\r
1122\r
c1fcd80b 1123 CpuSaveState = (QEMU_SMRAM_SAVE_STATE_MAP *)gSmst->CpuSaveState[CpuIndex];\r
4036b4e5
PB
1124\r
1125 //\r
1126 // Check CPU mode\r
1127 //\r
1128 if ((CpuSaveState->x86.SMMRevId & 0xFFFF) == 0) {\r
1129 *(UINT8 *)Buffer = 32;\r
1130 } else {\r
1131 *(UINT8 *)Buffer = 64;\r
1132 }\r
1133\r
1134 return EFI_SUCCESS;\r
1135 }\r
1136\r
1137 //\r
1138 // Check for special EFI_SMM_SAVE_STATE_REGISTER_IO\r
1139 //\r
1140 if (Register == EFI_SMM_SAVE_STATE_REGISTER_IO) {\r
1141 return EFI_NOT_FOUND;\r
1142 }\r
1143\r
1144 //\r
1145 // Convert Register to a register lookup table index. Let\r
1146 // PiSmmCpuDxeSmm implement other special registers (currently\r
1147 // there is only EFI_SMM_SAVE_STATE_REGISTER_PROCESSOR_ID).\r
1148 //\r
1149 RegisterIndex = GetRegisterIndex (Register);\r
1150 if (RegisterIndex == 0) {\r
b1bfdd65
LE
1151 return (Register < EFI_SMM_SAVE_STATE_REGISTER_IO ?\r
1152 EFI_NOT_FOUND :\r
1153 EFI_UNSUPPORTED);\r
4036b4e5
PB
1154 }\r
1155\r
1156 return ReadSaveStateRegisterByIndex (CpuIndex, RegisterIndex, Width, Buffer);\r
86d71589
PB
1157}\r
1158\r
1159/**\r
1160 Writes an SMM Save State register on the target processor. If this function\r
1161 returns EFI_UNSUPPORTED, then the caller is responsible for writing the\r
1162 SMM Save Sate register.\r
1163\r
1164 @param[in] CpuIndex The index of the CPU to write the SMM Save State. The\r
1165 value must be between 0 and the NumberOfCpus field in\r
1166 the System Management System Table (SMST).\r
1167 @param[in] Register The SMM Save State register to write.\r
1168 @param[in] Width The number of bytes to write to the CPU save state.\r
1169 @param[in] Buffer Upon entry, this holds the new CPU register value.\r
1170\r
1171 @retval EFI_SUCCESS The register was written to Save State.\r
1172 @retval EFI_INVALID_PARAMTER Buffer is NULL.\r
b1bfdd65
LE
1173 @retval EFI_UNSUPPORTED This function does not support writing\r
1174 Register.\r
86d71589
PB
1175**/\r
1176EFI_STATUS\r
1177EFIAPI\r
1178SmmCpuFeaturesWriteSaveStateRegister (\r
1179 IN UINTN CpuIndex,\r
1180 IN EFI_SMM_SAVE_STATE_REGISTER Register,\r
1181 IN UINTN Width,\r
1182 IN CONST VOID *Buffer\r
1183 )\r
1184{\r
c1fcd80b
PB
1185 UINTN RegisterIndex;\r
1186 QEMU_SMRAM_SAVE_STATE_MAP *CpuSaveState;\r
4036b4e5
PB
1187\r
1188 //\r
1189 // Writes to EFI_SMM_SAVE_STATE_REGISTER_LMA are ignored\r
1190 //\r
1191 if (Register == EFI_SMM_SAVE_STATE_REGISTER_LMA) {\r
1192 return EFI_SUCCESS;\r
1193 }\r
1194\r
1195 //\r
1196 // Writes to EFI_SMM_SAVE_STATE_REGISTER_IO are not supported\r
1197 //\r
1198 if (Register == EFI_SMM_SAVE_STATE_REGISTER_IO) {\r
1199 return EFI_NOT_FOUND;\r
1200 }\r
1201\r
1202 //\r
1203 // Convert Register to a register lookup table index. Let\r
1204 // PiSmmCpuDxeSmm implement other special registers (currently\r
1205 // there is only EFI_SMM_SAVE_STATE_REGISTER_PROCESSOR_ID).\r
1206 //\r
1207 RegisterIndex = GetRegisterIndex (Register);\r
1208 if (RegisterIndex == 0) {\r
b1bfdd65
LE
1209 return (Register < EFI_SMM_SAVE_STATE_REGISTER_IO ?\r
1210 EFI_NOT_FOUND :\r
1211 EFI_UNSUPPORTED);\r
4036b4e5
PB
1212 }\r
1213\r
c1fcd80b 1214 CpuSaveState = (QEMU_SMRAM_SAVE_STATE_MAP *)gSmst->CpuSaveState[CpuIndex];\r
4036b4e5
PB
1215\r
1216 //\r
1217 // Do not write non-writable SaveState, because it will cause exception.\r
b1bfdd65 1218 //\r
4036b4e5
PB
1219 if (!mSmmCpuWidthOffset[RegisterIndex].Writeable) {\r
1220 return EFI_UNSUPPORTED;\r
1221 }\r
1222\r
1223 //\r
1224 // Check CPU mode\r
1225 //\r
1226 if ((CpuSaveState->x86.SMMRevId & 0xFFFF) == 0) {\r
1227 //\r
b1bfdd65
LE
1228 // If 32-bit mode width is zero, then the specified register can not be\r
1229 // accessed\r
4036b4e5
PB
1230 //\r
1231 if (mSmmCpuWidthOffset[RegisterIndex].Width32 == 0) {\r
1232 return EFI_NOT_FOUND;\r
1233 }\r
1234\r
1235 //\r
b1bfdd65
LE
1236 // If Width is bigger than the 32-bit mode width, then the specified\r
1237 // register can not be accessed\r
4036b4e5
PB
1238 //\r
1239 if (Width > mSmmCpuWidthOffset[RegisterIndex].Width32) {\r
1240 return EFI_INVALID_PARAMETER;\r
1241 }\r
1242 //\r
1243 // Write SMM State register\r
1244 //\r
1245 ASSERT (CpuSaveState != NULL);\r
b1bfdd65
LE
1246 CopyMem (\r
1247 (UINT8 *)CpuSaveState + mSmmCpuWidthOffset[RegisterIndex].Offset32,\r
1248 Buffer,\r
1249 Width\r
1250 );\r
4036b4e5
PB
1251 } else {\r
1252 //\r
b1bfdd65
LE
1253 // If 64-bit mode width is zero, then the specified register can not be\r
1254 // accessed\r
4036b4e5
PB
1255 //\r
1256 if (mSmmCpuWidthOffset[RegisterIndex].Width64 == 0) {\r
1257 return EFI_NOT_FOUND;\r
1258 }\r
1259\r
1260 //\r
b1bfdd65
LE
1261 // If Width is bigger than the 64-bit mode width, then the specified\r
1262 // register can not be accessed\r
4036b4e5
PB
1263 //\r
1264 if (Width > mSmmCpuWidthOffset[RegisterIndex].Width64) {\r
1265 return EFI_INVALID_PARAMETER;\r
1266 }\r
1267\r
1268 //\r
1269 // Write lower 32-bits of SMM State register\r
1270 //\r
b1bfdd65
LE
1271 CopyMem (\r
1272 (UINT8 *)CpuSaveState + mSmmCpuWidthOffset[RegisterIndex].Offset64Lo,\r
1273 Buffer,\r
1274 MIN (4, Width)\r
1275 );\r
4036b4e5
PB
1276 if (Width >= 4) {\r
1277 //\r
1278 // Write upper 32-bits of SMM State register\r
1279 //\r
b1bfdd65
LE
1280 CopyMem (\r
1281 (UINT8 *)CpuSaveState + mSmmCpuWidthOffset[RegisterIndex].Offset64Hi,\r
1282 (UINT8 *)Buffer + 4,\r
1283 Width - 4\r
1284 );\r
4036b4e5
PB
1285 }\r
1286 }\r
1287 return EFI_SUCCESS;\r
86d71589
PB
1288}\r
1289\r
1290/**\r
1291 This function is hook point called after the gEfiSmmReadyToLockProtocolGuid\r
1292 notification is completely processed.\r
1293**/\r
1294VOID\r
1295EFIAPI\r
1296SmmCpuFeaturesCompleteSmmReadyToLock (\r
1297 VOID\r
1298 )\r
1299{\r
1300}\r
1301\r
1302/**\r
b1bfdd65
LE
1303 This API provides a method for a CPU to allocate a specific region for\r
1304 storing page tables.\r
86d71589
PB
1305\r
1306 This API can be called more once to allocate memory for page tables.\r
1307\r
b1bfdd65
LE
1308 Allocates the number of 4KB pages of type EfiRuntimeServicesData and returns\r
1309 a pointer to the allocated buffer. The buffer returned is aligned on a 4KB\r
1310 boundary. If Pages is 0, then NULL is returned. If there is not enough\r
1311 memory remaining to satisfy the request, then NULL is returned.\r
86d71589 1312\r
b1bfdd65
LE
1313 This function can also return NULL if there is no preference on where the\r
1314 page tables are allocated in SMRAM.\r
86d71589
PB
1315\r
1316 @param Pages The number of 4 KB pages to allocate.\r
1317\r
1318 @return A pointer to the allocated buffer for page tables.\r
1319 @retval NULL Fail to allocate a specific region for storing page tables,\r
b1bfdd65
LE
1320 Or there is no preference on where the page tables are\r
1321 allocated in SMRAM.\r
86d71589
PB
1322\r
1323**/\r
1324VOID *\r
1325EFIAPI\r
1326SmmCpuFeaturesAllocatePageTableMemory (\r
1327 IN UINTN Pages\r
1328 )\r
1329{\r
1330 return NULL;\r
1331}\r
1332\r