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