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