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