2 The CPU specific programming for PiSmmCpuDxeSmm module.
4 Copyright (c) 2010 - 2015, Intel Corporation. All rights reserved.<BR>
6 SPDX-License-Identifier: BSD-2-Clause-Patent
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/MemoryAllocationLib.h>
15 #include <Library/PcdLib.h>
16 #include <Library/SafeIntLib.h>
17 #include <Library/SmmCpuFeaturesLib.h>
18 #include <Library/SmmServicesTableLib.h>
19 #include <Library/UefiBootServicesTableLib.h>
20 #include <Pcd/CpuHotEjectData.h>
22 #include <Register/Intel/SmramSaveStateMap.h>
23 #include <Register/QemuSmramSaveStateMap.h>
26 // EFER register LMA bit
31 The constructor function
33 @param[in] ImageHandle The firmware allocated handle for the EFI image.
34 @param[in] SystemTable A pointer to the EFI System Table.
36 @retval EFI_SUCCESS The constructor always returns EFI_SUCCESS.
41 SmmCpuFeaturesLibConstructor (
42 IN EFI_HANDLE ImageHandle
,
43 IN EFI_SYSTEM_TABLE
*SystemTable
47 // No need to program SMRRs on our virtual platform.
53 Called during the very first SMI into System Management Mode to initialize
54 CPU features, including SMBASE, for the currently executing CPU. Since this
55 is the first SMI, the SMRAM Save State Map is at the default address of
56 SMM_DEFAULT_SMBASE + SMRAM_SAVE_STATE_MAP_OFFSET. The currently executing
57 CPU is specified by CpuIndex and CpuIndex can be used to access information
58 about the currently executing CPU in the ProcessorInfo array and the
59 HotPlugCpuData data structure.
61 @param[in] CpuIndex The index of the CPU to initialize. The value
62 must be between 0 and the NumberOfCpus field in
63 the System Management System Table (SMST).
64 @param[in] IsMonarch TRUE if the CpuIndex is the index of the CPU that
65 was elected as monarch during System Management
67 FALSE if the CpuIndex is not the index of the CPU
68 that was elected as monarch during System
69 Management Mode initialization.
70 @param[in] ProcessorInfo Pointer to an array of EFI_PROCESSOR_INFORMATION
71 structures. ProcessorInfo[CpuIndex] contains the
72 information for the currently executing CPU.
73 @param[in] CpuHotPlugData Pointer to the CPU_HOT_PLUG_DATA structure that
74 contains the ApidId and SmBase arrays.
78 SmmCpuFeaturesInitializeProcessor (
81 IN EFI_PROCESSOR_INFORMATION
*ProcessorInfo
,
82 IN CPU_HOT_PLUG_DATA
*CpuHotPlugData
85 QEMU_SMRAM_SAVE_STATE_MAP
*CpuState
;
90 CpuState
= (QEMU_SMRAM_SAVE_STATE_MAP
*)(UINTN
)(
92 SMRAM_SAVE_STATE_MAP_OFFSET
94 if ((CpuState
->x86
.SMMRevId
& 0xFFFF) == 0) {
95 CpuState
->x86
.SMBASE
= (UINT32
)CpuHotPlugData
->SmBase
[CpuIndex
];
97 CpuState
->x64
.SMBASE
= (UINT32
)CpuHotPlugData
->SmBase
[CpuIndex
];
101 // No need to program SMRRs on our virtual platform.
106 This function updates the SMRAM save state on the currently executing CPU
107 to resume execution at a specific address after an RSM instruction. This
108 function must evaluate the SMRAM save state to determine the execution mode
109 the RSM instruction resumes and update the resume execution address with
110 either NewInstructionPointer32 or NewInstructionPoint. The auto HALT restart
111 flag in the SMRAM save state must always be cleared. This function returns
112 the value of the instruction pointer from the SMRAM save state that was
113 replaced. If this function returns 0, then the SMRAM save state was not
116 This function is called during the very first SMI on each CPU after
117 SmmCpuFeaturesInitializeProcessor() to set a flag in normal execution mode
118 to signal that the SMBASE of each CPU has been updated before the default
119 SMBASE address is used for the first SMI to the next CPU.
121 @param[in] CpuIndex The index of the CPU to hook. The value
122 must be between 0 and the NumberOfCpus
123 field in the System Management System
125 @param[in] CpuState Pointer to SMRAM Save State Map for the
126 currently executing CPU.
127 @param[in] NewInstructionPointer32 Instruction pointer to use if resuming to
128 32-bit execution mode from 64-bit SMM.
129 @param[in] NewInstructionPointer Instruction pointer to use if resuming to
130 same execution mode as SMM.
132 @retval 0 This function did modify the SMRAM save state.
133 @retval > 0 The original instruction pointer value from the SMRAM save state
134 before it was replaced.
138 SmmCpuFeaturesHookReturnFromSmm (
140 IN SMRAM_SAVE_STATE_MAP
*CpuState
,
141 IN UINT64 NewInstructionPointer32
,
142 IN UINT64 NewInstructionPointer
145 UINT64 OriginalInstructionPointer
;
146 QEMU_SMRAM_SAVE_STATE_MAP
*CpuSaveState
;
148 CpuSaveState
= (QEMU_SMRAM_SAVE_STATE_MAP
*)CpuState
;
149 if ((CpuSaveState
->x86
.SMMRevId
& 0xFFFF) == 0) {
150 OriginalInstructionPointer
= (UINT64
)CpuSaveState
->x86
._EIP
;
151 CpuSaveState
->x86
._EIP
= (UINT32
)NewInstructionPointer
;
153 // Clear the auto HALT restart flag so the RSM instruction returns
154 // program control to the instruction following the HLT instruction.
156 if ((CpuSaveState
->x86
.AutoHALTRestart
& BIT0
) != 0) {
157 CpuSaveState
->x86
.AutoHALTRestart
&= ~BIT0
;
160 OriginalInstructionPointer
= CpuSaveState
->x64
._RIP
;
161 if ((CpuSaveState
->x64
.IA32_EFER
& LMA
) == 0) {
162 CpuSaveState
->x64
._RIP
= (UINT32
)NewInstructionPointer32
;
164 CpuSaveState
->x64
._RIP
= (UINT32
)NewInstructionPointer
;
168 // Clear the auto HALT restart flag so the RSM instruction returns
169 // program control to the instruction following the HLT instruction.
171 if ((CpuSaveState
->x64
.AutoHALTRestart
& BIT0
) != 0) {
172 CpuSaveState
->x64
.AutoHALTRestart
&= ~BIT0
;
176 return OriginalInstructionPointer
;
179 STATIC CPU_HOT_EJECT_DATA
*mCpuHotEjectData
= NULL
;
182 Initialize mCpuHotEjectData if PcdCpuMaxLogicalProcessorNumber > 1.
184 Also setup the corresponding PcdCpuHotEjectDataAddress.
188 InitCpuHotEjectData (
194 UINT32 MaxNumberOfCpus
;
195 RETURN_STATUS PcdStatus
;
197 MaxNumberOfCpus
= PcdGet32 (PcdCpuMaxLogicalProcessorNumber
);
198 if (MaxNumberOfCpus
== 1) {
203 // We allocate CPU_HOT_EJECT_DATA and CPU_HOT_EJECT_DATA->QemuSelectorMap[]
204 // in a single allocation, and explicitly align the QemuSelectorMap[] (which
205 // is a UINT64 array) at its natural boundary.
206 // Accordingly, allocate:
207 // sizeof(*mCpuHotEjectData) + (MaxNumberOfCpus * sizeof(UINT64))
208 // and, add sizeof(UINT64) - 1 to use as padding if needed.
211 if (RETURN_ERROR (SafeUintnMult (MaxNumberOfCpus
, sizeof (UINT64
), &Size
)) ||
212 RETURN_ERROR (SafeUintnAdd (Size
, sizeof (*mCpuHotEjectData
), &Size
)) ||
213 RETURN_ERROR (SafeUintnAdd (Size
, sizeof (UINT64
) - 1, &Size
)))
215 DEBUG ((DEBUG_ERROR
, "%a: invalid CPU_HOT_EJECT_DATA\n", __FUNCTION__
));
219 mCpuHotEjectData
= AllocatePool (Size
);
220 if (mCpuHotEjectData
== NULL
) {
221 ASSERT (mCpuHotEjectData
!= NULL
);
225 mCpuHotEjectData
->Handler
= NULL
;
226 mCpuHotEjectData
->ArrayLength
= MaxNumberOfCpus
;
228 mCpuHotEjectData
->QemuSelectorMap
= ALIGN_POINTER (
229 mCpuHotEjectData
+ 1,
233 // We use mCpuHotEjectData->QemuSelectorMap to map
234 // ProcessorNum -> QemuSelector. Initialize to invalid values.
236 for (Idx
= 0; Idx
< mCpuHotEjectData
->ArrayLength
; Idx
++) {
237 mCpuHotEjectData
->QemuSelectorMap
[Idx
] = CPU_EJECT_QEMU_SELECTOR_INVALID
;
241 // Expose address of CPU Hot eject Data structure
243 PcdStatus
= PcdSet64S (
244 PcdCpuHotEjectDataAddress
,
245 (UINTN
)(VOID
*)mCpuHotEjectData
247 ASSERT_RETURN_ERROR (PcdStatus
);
256 Hook point in normal execution mode that allows the one CPU that was elected
257 as monarch during System Management Mode initialization to perform additional
258 initialization actions immediately after all of the CPUs have processed their
259 first SMI and called SmmCpuFeaturesInitializeProcessor() relocating SMBASE
260 into a buffer in SMRAM and called SmmCpuFeaturesHookReturnFromSmm().
264 SmmCpuFeaturesSmmRelocationComplete (
272 InitCpuHotEjectData ();
274 if (!MemEncryptSevIsEnabled ()) {
279 // Now that SMBASE relocation is complete, re-encrypt the original SMRAM save
280 // state map's container pages, and release the pages to DXE. (The pages were
281 // allocated in PlatformPei.)
283 Status
= MemEncryptSevLocateInitialSmramSaveStateMapPages (
287 ASSERT_EFI_ERROR (Status
);
289 Status
= MemEncryptSevSetPageEncMask (
290 0, // Cr3BaseAddress -- use current CR3
291 MapPagesBase
, // BaseAddress
292 MapPagesCount
// NumPages
294 if (EFI_ERROR (Status
)) {
297 "%a: MemEncryptSevSetPageEncMask(): %r\n",
305 ZeroMem ((VOID
*)MapPagesBase
, EFI_PAGES_TO_SIZE (MapPagesCount
));
307 if (PcdGetBool (PcdQ35SmramAtDefaultSmbase
)) {
309 // The initial SMRAM Save State Map has been covered as part of a larger
310 // reserved memory allocation in PlatformPei's InitializeRamRegions(). That
311 // allocation is supposed to survive into OS runtime; we must not release
312 // any part of it. Only re-assert the containment here.
314 ASSERT (SMM_DEFAULT_SMBASE
<= MapPagesBase
);
316 (MapPagesBase
+ EFI_PAGES_TO_SIZE (MapPagesCount
) <=
317 SMM_DEFAULT_SMBASE
+ MCH_DEFAULT_SMBASE_SIZE
)
320 Status
= gBS
->FreePages (MapPagesBase
, MapPagesCount
);
321 ASSERT_EFI_ERROR (Status
);
326 Return the size, in bytes, of a custom SMI Handler in bytes. If 0 is
327 returned, then a custom SMI handler is not provided by this library,
328 and the default SMI handler must be used.
330 @retval 0 Use the default SMI handler.
331 @retval > 0 Use the SMI handler installed by
332 SmmCpuFeaturesInstallSmiHandler(). The caller is required to
333 allocate enough SMRAM for each CPU to support the size of the
338 SmmCpuFeaturesGetSmiHandlerSize (
346 Install a custom SMI handler for the CPU specified by CpuIndex. This
347 function is only called if SmmCpuFeaturesGetSmiHandlerSize() returns a size
348 is greater than zero and is called by the CPU that was elected as monarch
349 during System Management Mode initialization.
351 @param[in] CpuIndex The index of the CPU to install the custom SMI handler.
352 The value must be between 0 and the NumberOfCpus field
353 in the System Management System Table (SMST).
354 @param[in] SmBase The SMBASE address for the CPU specified by CpuIndex.
355 @param[in] SmiStack The stack to use when an SMI is processed by the
356 the CPU specified by CpuIndex.
357 @param[in] StackSize The size, in bytes, if the stack used when an SMI is
358 processed by the CPU specified by CpuIndex.
359 @param[in] GdtBase The base address of the GDT to use when an SMI is
360 processed by the CPU specified by CpuIndex.
361 @param[in] GdtSize The size, in bytes, of the GDT used when an SMI is
362 processed by the CPU specified by CpuIndex.
363 @param[in] IdtBase The base address of the IDT to use when an SMI is
364 processed by the CPU specified by CpuIndex.
365 @param[in] IdtSize The size, in bytes, of the IDT used when an SMI is
366 processed by the CPU specified by CpuIndex.
367 @param[in] Cr3 The base address of the page tables to use when an SMI
368 is processed by the CPU specified by CpuIndex.
372 SmmCpuFeaturesInstallSmiHandler (
387 Determines if MTRR registers must be configured to set SMRAM cache-ability
388 when executing in System Management Mode.
390 @retval TRUE MTRR registers must be configured to set SMRAM cache-ability.
391 @retval FALSE MTRR registers do not need to be configured to set SMRAM
396 SmmCpuFeaturesNeedConfigureMtrrs (
404 Disable SMRR register if SMRR is supported and
405 SmmCpuFeaturesNeedConfigureMtrrs() returns TRUE.
409 SmmCpuFeaturesDisableSmrr (
414 // No SMRR support, nothing to do
419 Enable SMRR register if SMRR is supported and
420 SmmCpuFeaturesNeedConfigureMtrrs() returns TRUE.
424 SmmCpuFeaturesReenableSmrr (
429 // No SMRR support, nothing to do
434 Processor specific hook point each time a CPU enters System Management Mode.
436 @param[in] CpuIndex The index of the CPU that has entered SMM. The value
437 must be between 0 and the NumberOfCpus field in the
438 System Management System Table (SMST).
442 SmmCpuFeaturesRendezvousEntry (
447 // No SMRR support, nothing to do
452 Processor specific hook point each time a CPU exits System Management Mode.
454 @param[in] CpuIndex The index of the CPU that is exiting SMM. The value
455 must be between 0 and the NumberOfCpus field in the
456 System Management System Table (SMST).
460 SmmCpuFeaturesRendezvousExit (
465 // We only call the Handler if CPU hot-eject is enabled
466 // (PcdCpuMaxLogicalProcessorNumber > 1), and hot-eject is needed
467 // in this SMI exit (otherwise mCpuHotEjectData->Handler is not armed.)
470 if (mCpuHotEjectData
!= NULL
) {
471 CPU_HOT_EJECT_HANDLER Handler
;
474 // As the comment above mentions, mCpuHotEjectData->Handler might be
475 // written to on the BSP as part of handling of the CPU-ejection.
477 // We know that any initial assignment to mCpuHotEjectData->Handler
478 // (on the BSP, in the CpuHotplugMmi() context) is ordered-before the
479 // load below, since it is guaranteed to happen before the
480 // control-dependency of the BSP's SMI exit signal -- by way of a store
481 // to AllCpusInSync (on the BSP, in BspHandler()) and the corresponding
482 // AllCpusInSync loop (on the APs, in SmiRendezvous()) which depends on
485 // This guarantees that these pieces of code can never execute
486 // simultaneously. In addition, we ensure that the following load is
487 // ordered-after the AllCpusInSync loop by using a MemoryFence() with
488 // acquire semantics.
492 Handler
= mCpuHotEjectData
->Handler
;
494 if (Handler
!= NULL
) {
501 Check to see if an SMM register is supported by a specified CPU.
503 @param[in] CpuIndex The index of the CPU to check for SMM register support.
504 The value must be between 0 and the NumberOfCpus field
505 in the System Management System Table (SMST).
506 @param[in] RegName Identifies the SMM register to check for support.
508 @retval TRUE The SMM register specified by RegName is supported by the CPU
509 specified by CpuIndex.
510 @retval FALSE The SMM register specified by RegName is not supported by the
511 CPU specified by CpuIndex.
515 SmmCpuFeaturesIsSmmRegisterSupported (
517 IN SMM_REG_NAME RegName
520 ASSERT (RegName
== SmmRegFeatureControl
);
525 Returns the current value of the SMM register for the specified CPU.
526 If the SMM register is not supported, then 0 is returned.
528 @param[in] CpuIndex The index of the CPU to read the SMM register. The
529 value must be between 0 and the NumberOfCpus field in
530 the System Management System Table (SMST).
531 @param[in] RegName Identifies the SMM register to read.
533 @return The value of the SMM register specified by RegName from the CPU
534 specified by CpuIndex.
538 SmmCpuFeaturesGetSmmRegister (
540 IN SMM_REG_NAME RegName
544 // This is called for SmmRegSmmDelayed, SmmRegSmmBlocked, SmmRegSmmEnable.
545 // The last of these should actually be SmmRegSmmDisable, so we can just
552 Sets the value of an SMM register on a specified CPU.
553 If the SMM register is not supported, then no action is performed.
555 @param[in] CpuIndex The index of the CPU to write the SMM register. The
556 value must be between 0 and the NumberOfCpus field in
557 the System Management System Table (SMST).
558 @param[in] RegName Identifies the SMM register to write.
559 registers are read-only.
560 @param[in] Value The value to write to the SMM register.
564 SmmCpuFeaturesSetSmmRegister (
566 IN SMM_REG_NAME RegName
,
574 /// Macro used to simplify the lookup table entries of type
575 /// CPU_SMM_SAVE_STATE_LOOKUP_ENTRY
577 #define SMM_CPU_OFFSET(Field) OFFSET_OF (QEMU_SMRAM_SAVE_STATE_MAP, Field)
580 /// Macro used to simplify the lookup table entries of type
581 /// CPU_SMM_SAVE_STATE_REGISTER_RANGE
583 #define SMM_REGISTER_RANGE(Start, End) { Start, End, End - Start + 1 }
586 /// Structure used to describe a range of registers
589 EFI_SMM_SAVE_STATE_REGISTER Start
;
590 EFI_SMM_SAVE_STATE_REGISTER End
;
592 } CPU_SMM_SAVE_STATE_REGISTER_RANGE
;
595 /// Structure used to build a lookup table to retrieve the widths and offsets
596 /// associated with each supported EFI_SMM_SAVE_STATE_REGISTER value
599 #define SMM_SAVE_STATE_REGISTER_FIRST_INDEX 1
608 } CPU_SMM_SAVE_STATE_LOOKUP_ENTRY
;
611 /// Table used by GetRegisterIndex() to convert an EFI_SMM_SAVE_STATE_REGISTER
612 /// value to an index into a table of type CPU_SMM_SAVE_STATE_LOOKUP_ENTRY
614 STATIC CONST CPU_SMM_SAVE_STATE_REGISTER_RANGE mSmmCpuRegisterRanges
[] = {
616 EFI_SMM_SAVE_STATE_REGISTER_GDTBASE
,
617 EFI_SMM_SAVE_STATE_REGISTER_LDTINFO
620 EFI_SMM_SAVE_STATE_REGISTER_ES
,
621 EFI_SMM_SAVE_STATE_REGISTER_RIP
624 EFI_SMM_SAVE_STATE_REGISTER_RFLAGS
,
625 EFI_SMM_SAVE_STATE_REGISTER_CR4
627 { (EFI_SMM_SAVE_STATE_REGISTER
)0, (EFI_SMM_SAVE_STATE_REGISTER
)0,0 }
631 /// Lookup table used to retrieve the widths and offsets associated with each
632 /// supported EFI_SMM_SAVE_STATE_REGISTER value
634 STATIC CONST CPU_SMM_SAVE_STATE_LOOKUP_ENTRY mSmmCpuWidthOffset
[] = {
645 // CPU Save State registers defined in PI SMM CPU Protocol.
651 SMM_CPU_OFFSET (x64
._GDTRBase
), // Offset64Lo
652 SMM_CPU_OFFSET (x64
._GDTRBase
) + 4, // Offset64Hi
654 }, // EFI_SMM_SAVE_STATE_REGISTER_GDTBASE = 4
660 SMM_CPU_OFFSET (x64
._IDTRBase
), // Offset64Lo
661 SMM_CPU_OFFSET (x64
._IDTRBase
) + 4, // Offset64Hi
663 }, // EFI_SMM_SAVE_STATE_REGISTER_IDTBASE = 5
669 SMM_CPU_OFFSET (x64
._LDTRBase
), // Offset64Lo
670 SMM_CPU_OFFSET (x64
._LDTRBase
) + 4, // Offset64Hi
672 }, // EFI_SMM_SAVE_STATE_REGISTER_LDTBASE = 6
678 SMM_CPU_OFFSET (x64
._GDTRLimit
), // Offset64Lo
679 SMM_CPU_OFFSET (x64
._GDTRLimit
) + 4, // Offset64Hi
681 }, // EFI_SMM_SAVE_STATE_REGISTER_GDTLIMIT = 7
687 SMM_CPU_OFFSET (x64
._IDTRLimit
), // Offset64Lo
688 SMM_CPU_OFFSET (x64
._IDTRLimit
) + 4, // Offset64Hi
690 }, // EFI_SMM_SAVE_STATE_REGISTER_IDTLIMIT = 8
696 SMM_CPU_OFFSET (x64
._LDTRLimit
), // Offset64Lo
697 SMM_CPU_OFFSET (x64
._LDTRLimit
) + 4, // Offset64Hi
699 }, // EFI_SMM_SAVE_STATE_REGISTER_LDTLIMIT = 9
708 }, // EFI_SMM_SAVE_STATE_REGISTER_LDTINFO = 10
713 SMM_CPU_OFFSET (x86
._ES
), // Offset32
714 SMM_CPU_OFFSET (x64
._ES
), // Offset64Lo
717 }, // EFI_SMM_SAVE_STATE_REGISTER_ES = 20
722 SMM_CPU_OFFSET (x86
._CS
), // Offset32
723 SMM_CPU_OFFSET (x64
._CS
), // Offset64Lo
726 }, // EFI_SMM_SAVE_STATE_REGISTER_CS = 21
731 SMM_CPU_OFFSET (x86
._SS
), // Offset32
732 SMM_CPU_OFFSET (x64
._SS
), // Offset64Lo
735 }, // EFI_SMM_SAVE_STATE_REGISTER_SS = 22
740 SMM_CPU_OFFSET (x86
._DS
), // Offset32
741 SMM_CPU_OFFSET (x64
._DS
), // Offset64Lo
744 }, // EFI_SMM_SAVE_STATE_REGISTER_DS = 23
749 SMM_CPU_OFFSET (x86
._FS
), // Offset32
750 SMM_CPU_OFFSET (x64
._FS
), // Offset64Lo
753 }, // EFI_SMM_SAVE_STATE_REGISTER_FS = 24
758 SMM_CPU_OFFSET (x86
._GS
), // Offset32
759 SMM_CPU_OFFSET (x64
._GS
), // Offset64Lo
762 }, // EFI_SMM_SAVE_STATE_REGISTER_GS = 25
768 SMM_CPU_OFFSET (x64
._LDTR
), // Offset64Lo
771 }, // EFI_SMM_SAVE_STATE_REGISTER_LDTR_SEL = 26
776 SMM_CPU_OFFSET (x86
._TR
), // Offset32
777 SMM_CPU_OFFSET (x64
._TR
), // Offset64Lo
780 }, // EFI_SMM_SAVE_STATE_REGISTER_TR_SEL = 27
785 SMM_CPU_OFFSET (x86
._DR7
), // Offset32
786 SMM_CPU_OFFSET (x64
._DR7
), // Offset64Lo
787 SMM_CPU_OFFSET (x64
._DR7
) + 4, // Offset64Hi
789 }, // EFI_SMM_SAVE_STATE_REGISTER_DR7 = 28
794 SMM_CPU_OFFSET (x86
._DR6
), // Offset32
795 SMM_CPU_OFFSET (x64
._DR6
), // Offset64Lo
796 SMM_CPU_OFFSET (x64
._DR6
) + 4, // Offset64Hi
798 }, // EFI_SMM_SAVE_STATE_REGISTER_DR6 = 29
804 SMM_CPU_OFFSET (x64
._R8
), // Offset64Lo
805 SMM_CPU_OFFSET (x64
._R8
) + 4, // Offset64Hi
807 }, // EFI_SMM_SAVE_STATE_REGISTER_R8 = 30
813 SMM_CPU_OFFSET (x64
._R9
), // Offset64Lo
814 SMM_CPU_OFFSET (x64
._R9
) + 4, // Offset64Hi
816 }, // EFI_SMM_SAVE_STATE_REGISTER_R9 = 31
822 SMM_CPU_OFFSET (x64
._R10
), // Offset64Lo
823 SMM_CPU_OFFSET (x64
._R10
) + 4, // Offset64Hi
825 }, // EFI_SMM_SAVE_STATE_REGISTER_R10 = 32
831 SMM_CPU_OFFSET (x64
._R11
), // Offset64Lo
832 SMM_CPU_OFFSET (x64
._R11
) + 4, // Offset64Hi
834 }, // EFI_SMM_SAVE_STATE_REGISTER_R11 = 33
840 SMM_CPU_OFFSET (x64
._R12
), // Offset64Lo
841 SMM_CPU_OFFSET (x64
._R12
) + 4, // Offset64Hi
843 }, // EFI_SMM_SAVE_STATE_REGISTER_R12 = 34
849 SMM_CPU_OFFSET (x64
._R13
), // Offset64Lo
850 SMM_CPU_OFFSET (x64
._R13
) + 4, // Offset64Hi
852 }, // EFI_SMM_SAVE_STATE_REGISTER_R13 = 35
858 SMM_CPU_OFFSET (x64
._R14
), // Offset64Lo
859 SMM_CPU_OFFSET (x64
._R14
) + 4, // Offset64Hi
861 }, // EFI_SMM_SAVE_STATE_REGISTER_R14 = 36
867 SMM_CPU_OFFSET (x64
._R15
), // Offset64Lo
868 SMM_CPU_OFFSET (x64
._R15
) + 4, // Offset64Hi
870 }, // EFI_SMM_SAVE_STATE_REGISTER_R15 = 37
875 SMM_CPU_OFFSET (x86
._EAX
), // Offset32
876 SMM_CPU_OFFSET (x64
._RAX
), // Offset64Lo
877 SMM_CPU_OFFSET (x64
._RAX
) + 4, // Offset64Hi
879 }, // EFI_SMM_SAVE_STATE_REGISTER_RAX = 38
884 SMM_CPU_OFFSET (x86
._EBX
), // Offset32
885 SMM_CPU_OFFSET (x64
._RBX
), // Offset64Lo
886 SMM_CPU_OFFSET (x64
._RBX
) + 4, // Offset64Hi
888 }, // EFI_SMM_SAVE_STATE_REGISTER_RBX = 39
893 SMM_CPU_OFFSET (x86
._ECX
), // Offset32
894 SMM_CPU_OFFSET (x64
._RCX
), // Offset64Lo
895 SMM_CPU_OFFSET (x64
._RCX
) + 4, // Offset64Hi
897 }, // EFI_SMM_SAVE_STATE_REGISTER_RCX = 40
902 SMM_CPU_OFFSET (x86
._EDX
), // Offset32
903 SMM_CPU_OFFSET (x64
._RDX
), // Offset64Lo
904 SMM_CPU_OFFSET (x64
._RDX
) + 4, // Offset64Hi
906 }, // EFI_SMM_SAVE_STATE_REGISTER_RDX = 41
911 SMM_CPU_OFFSET (x86
._ESP
), // Offset32
912 SMM_CPU_OFFSET (x64
._RSP
), // Offset64Lo
913 SMM_CPU_OFFSET (x64
._RSP
) + 4, // Offset64Hi
915 }, // EFI_SMM_SAVE_STATE_REGISTER_RSP = 42
920 SMM_CPU_OFFSET (x86
._EBP
), // Offset32
921 SMM_CPU_OFFSET (x64
._RBP
), // Offset64Lo
922 SMM_CPU_OFFSET (x64
._RBP
) + 4, // Offset64Hi
924 }, // EFI_SMM_SAVE_STATE_REGISTER_RBP = 43
929 SMM_CPU_OFFSET (x86
._ESI
), // Offset32
930 SMM_CPU_OFFSET (x64
._RSI
), // Offset64Lo
931 SMM_CPU_OFFSET (x64
._RSI
) + 4, // Offset64Hi
933 }, // EFI_SMM_SAVE_STATE_REGISTER_RSI = 44
938 SMM_CPU_OFFSET (x86
._EDI
), // Offset32
939 SMM_CPU_OFFSET (x64
._RDI
), // Offset64Lo
940 SMM_CPU_OFFSET (x64
._RDI
) + 4, // Offset64Hi
942 }, // EFI_SMM_SAVE_STATE_REGISTER_RDI = 45
947 SMM_CPU_OFFSET (x86
._EIP
), // Offset32
948 SMM_CPU_OFFSET (x64
._RIP
), // Offset64Lo
949 SMM_CPU_OFFSET (x64
._RIP
) + 4, // Offset64Hi
951 }, // EFI_SMM_SAVE_STATE_REGISTER_RIP = 46
956 SMM_CPU_OFFSET (x86
._EFLAGS
), // Offset32
957 SMM_CPU_OFFSET (x64
._RFLAGS
), // Offset64Lo
958 SMM_CPU_OFFSET (x64
._RFLAGS
) + 4, // Offset64Hi
960 }, // EFI_SMM_SAVE_STATE_REGISTER_RFLAGS = 51
965 SMM_CPU_OFFSET (x86
._CR0
), // Offset32
966 SMM_CPU_OFFSET (x64
._CR0
), // Offset64Lo
967 SMM_CPU_OFFSET (x64
._CR0
) + 4, // Offset64Hi
969 }, // EFI_SMM_SAVE_STATE_REGISTER_CR0 = 52
974 SMM_CPU_OFFSET (x86
._CR3
), // Offset32
975 SMM_CPU_OFFSET (x64
._CR3
), // Offset64Lo
976 SMM_CPU_OFFSET (x64
._CR3
) + 4, // Offset64Hi
978 }, // EFI_SMM_SAVE_STATE_REGISTER_CR3 = 53
984 SMM_CPU_OFFSET (x64
._CR4
), // Offset64Lo
985 SMM_CPU_OFFSET (x64
._CR4
) + 4, // Offset64Hi
987 }, // EFI_SMM_SAVE_STATE_REGISTER_CR4 = 54
991 // No support for I/O restart
995 Read information from the CPU save state.
997 @param Register Specifies the CPU register to read form the save state.
999 @retval 0 Register is not valid
1000 @retval >0 Index into mSmmCpuWidthOffset[] associated with Register
1006 IN EFI_SMM_SAVE_STATE_REGISTER Register
1012 for (Index
= 0, Offset
= SMM_SAVE_STATE_REGISTER_FIRST_INDEX
;
1013 mSmmCpuRegisterRanges
[Index
].Length
!= 0;
1016 if ((Register
>= mSmmCpuRegisterRanges
[Index
].Start
) &&
1017 (Register
<= mSmmCpuRegisterRanges
[Index
].End
))
1019 return Register
- mSmmCpuRegisterRanges
[Index
].Start
+ Offset
;
1022 Offset
+= mSmmCpuRegisterRanges
[Index
].Length
;
1029 Read a CPU Save State register on the target processor.
1031 This function abstracts the differences that whether the CPU Save State
1032 register is in the IA32 CPU Save State Map or X64 CPU Save State Map.
1034 This function supports reading a CPU Save State register in SMBase relocation
1037 @param[in] CpuIndex Specifies the zero-based index of the CPU save
1039 @param[in] RegisterIndex Index into mSmmCpuWidthOffset[] look up table.
1040 @param[in] Width The number of bytes to read from the CPU save
1042 @param[out] Buffer Upon return, this holds the CPU register value
1043 read from the save state.
1045 @retval EFI_SUCCESS The register was read from Save State.
1046 @retval EFI_NOT_FOUND The register is not defined for the Save State
1048 @retval EFI_INVALID_PARAMTER This or Buffer is NULL.
1053 ReadSaveStateRegisterByIndex (
1055 IN UINTN RegisterIndex
,
1060 QEMU_SMRAM_SAVE_STATE_MAP
*CpuSaveState
;
1062 CpuSaveState
= (QEMU_SMRAM_SAVE_STATE_MAP
*)gSmst
->CpuSaveState
[CpuIndex
];
1064 if ((CpuSaveState
->x86
.SMMRevId
& 0xFFFF) == 0) {
1066 // If 32-bit mode width is zero, then the specified register can not be
1069 if (mSmmCpuWidthOffset
[RegisterIndex
].Width32
== 0) {
1070 return EFI_NOT_FOUND
;
1074 // If Width is bigger than the 32-bit mode width, then the specified
1075 // register can not be accessed
1077 if (Width
> mSmmCpuWidthOffset
[RegisterIndex
].Width32
) {
1078 return EFI_INVALID_PARAMETER
;
1082 // Write return buffer
1084 ASSERT (CpuSaveState
!= NULL
);
1087 (UINT8
*)CpuSaveState
+ mSmmCpuWidthOffset
[RegisterIndex
].Offset32
,
1092 // If 64-bit mode width is zero, then the specified register can not be
1095 if (mSmmCpuWidthOffset
[RegisterIndex
].Width64
== 0) {
1096 return EFI_NOT_FOUND
;
1100 // If Width is bigger than the 64-bit mode width, then the specified
1101 // register can not be accessed
1103 if (Width
> mSmmCpuWidthOffset
[RegisterIndex
].Width64
) {
1104 return EFI_INVALID_PARAMETER
;
1108 // Write lower 32-bits of return buffer
1112 (UINT8
*)CpuSaveState
+ mSmmCpuWidthOffset
[RegisterIndex
].Offset64Lo
,
1117 // Write upper 32-bits of return buffer
1120 (UINT8
*)Buffer
+ 4,
1121 (UINT8
*)CpuSaveState
+ mSmmCpuWidthOffset
[RegisterIndex
].Offset64Hi
,
1131 Read an SMM Save State register on the target processor. If this function
1132 returns EFI_UNSUPPORTED, then the caller is responsible for reading the
1133 SMM Save Sate register.
1135 @param[in] CpuIndex The index of the CPU to read the SMM Save State. The
1136 value must be between 0 and the NumberOfCpus field in
1137 the System Management System Table (SMST).
1138 @param[in] Register The SMM Save State register to read.
1139 @param[in] Width The number of bytes to read from the CPU save state.
1140 @param[out] Buffer Upon return, this holds the CPU register value read
1141 from the save state.
1143 @retval EFI_SUCCESS The register was read from Save State.
1144 @retval EFI_INVALID_PARAMTER Buffer is NULL.
1145 @retval EFI_UNSUPPORTED This function does not support reading
1150 SmmCpuFeaturesReadSaveStateRegister (
1152 IN EFI_SMM_SAVE_STATE_REGISTER Register
,
1157 UINTN RegisterIndex
;
1158 QEMU_SMRAM_SAVE_STATE_MAP
*CpuSaveState
;
1161 // Check for special EFI_SMM_SAVE_STATE_REGISTER_LMA
1163 if (Register
== EFI_SMM_SAVE_STATE_REGISTER_LMA
) {
1165 // Only byte access is supported for this register
1168 return EFI_INVALID_PARAMETER
;
1171 CpuSaveState
= (QEMU_SMRAM_SAVE_STATE_MAP
*)gSmst
->CpuSaveState
[CpuIndex
];
1176 if ((CpuSaveState
->x86
.SMMRevId
& 0xFFFF) == 0) {
1177 *(UINT8
*)Buffer
= 32;
1179 *(UINT8
*)Buffer
= 64;
1186 // Check for special EFI_SMM_SAVE_STATE_REGISTER_IO
1188 if (Register
== EFI_SMM_SAVE_STATE_REGISTER_IO
) {
1189 return EFI_NOT_FOUND
;
1193 // Convert Register to a register lookup table index. Let
1194 // PiSmmCpuDxeSmm implement other special registers (currently
1195 // there is only EFI_SMM_SAVE_STATE_REGISTER_PROCESSOR_ID).
1197 RegisterIndex
= GetRegisterIndex (Register
);
1198 if (RegisterIndex
== 0) {
1199 return (Register
< EFI_SMM_SAVE_STATE_REGISTER_IO
?
1204 return ReadSaveStateRegisterByIndex (CpuIndex
, RegisterIndex
, Width
, Buffer
);
1208 Writes an SMM Save State register on the target processor. If this function
1209 returns EFI_UNSUPPORTED, then the caller is responsible for writing the
1210 SMM Save Sate register.
1212 @param[in] CpuIndex The index of the CPU to write the SMM Save State. The
1213 value must be between 0 and the NumberOfCpus field in
1214 the System Management System Table (SMST).
1215 @param[in] Register The SMM Save State register to write.
1216 @param[in] Width The number of bytes to write to the CPU save state.
1217 @param[in] Buffer Upon entry, this holds the new CPU register value.
1219 @retval EFI_SUCCESS The register was written to Save State.
1220 @retval EFI_INVALID_PARAMTER Buffer is NULL.
1221 @retval EFI_UNSUPPORTED This function does not support writing
1226 SmmCpuFeaturesWriteSaveStateRegister (
1228 IN EFI_SMM_SAVE_STATE_REGISTER Register
,
1230 IN CONST VOID
*Buffer
1233 UINTN RegisterIndex
;
1234 QEMU_SMRAM_SAVE_STATE_MAP
*CpuSaveState
;
1237 // Writes to EFI_SMM_SAVE_STATE_REGISTER_LMA are ignored
1239 if (Register
== EFI_SMM_SAVE_STATE_REGISTER_LMA
) {
1244 // Writes to EFI_SMM_SAVE_STATE_REGISTER_IO are not supported
1246 if (Register
== EFI_SMM_SAVE_STATE_REGISTER_IO
) {
1247 return EFI_NOT_FOUND
;
1251 // Convert Register to a register lookup table index. Let
1252 // PiSmmCpuDxeSmm implement other special registers (currently
1253 // there is only EFI_SMM_SAVE_STATE_REGISTER_PROCESSOR_ID).
1255 RegisterIndex
= GetRegisterIndex (Register
);
1256 if (RegisterIndex
== 0) {
1257 return (Register
< EFI_SMM_SAVE_STATE_REGISTER_IO
?
1262 CpuSaveState
= (QEMU_SMRAM_SAVE_STATE_MAP
*)gSmst
->CpuSaveState
[CpuIndex
];
1265 // Do not write non-writable SaveState, because it will cause exception.
1267 if (!mSmmCpuWidthOffset
[RegisterIndex
].Writeable
) {
1268 return EFI_UNSUPPORTED
;
1274 if ((CpuSaveState
->x86
.SMMRevId
& 0xFFFF) == 0) {
1276 // If 32-bit mode width is zero, then the specified register can not be
1279 if (mSmmCpuWidthOffset
[RegisterIndex
].Width32
== 0) {
1280 return EFI_NOT_FOUND
;
1284 // If Width is bigger than the 32-bit mode width, then the specified
1285 // register can not be accessed
1287 if (Width
> mSmmCpuWidthOffset
[RegisterIndex
].Width32
) {
1288 return EFI_INVALID_PARAMETER
;
1292 // Write SMM State register
1294 ASSERT (CpuSaveState
!= NULL
);
1296 (UINT8
*)CpuSaveState
+ mSmmCpuWidthOffset
[RegisterIndex
].Offset32
,
1302 // If 64-bit mode width is zero, then the specified register can not be
1305 if (mSmmCpuWidthOffset
[RegisterIndex
].Width64
== 0) {
1306 return EFI_NOT_FOUND
;
1310 // If Width is bigger than the 64-bit mode width, then the specified
1311 // register can not be accessed
1313 if (Width
> mSmmCpuWidthOffset
[RegisterIndex
].Width64
) {
1314 return EFI_INVALID_PARAMETER
;
1318 // Write lower 32-bits of SMM State register
1321 (UINT8
*)CpuSaveState
+ mSmmCpuWidthOffset
[RegisterIndex
].Offset64Lo
,
1327 // Write upper 32-bits of SMM State register
1330 (UINT8
*)CpuSaveState
+ mSmmCpuWidthOffset
[RegisterIndex
].Offset64Hi
,
1331 (UINT8
*)Buffer
+ 4,
1341 This function is hook point called after the gEfiSmmReadyToLockProtocolGuid
1342 notification is completely processed.
1346 SmmCpuFeaturesCompleteSmmReadyToLock (
1353 This API provides a method for a CPU to allocate a specific region for
1354 storing page tables.
1356 This API can be called more once to allocate memory for page tables.
1358 Allocates the number of 4KB pages of type EfiRuntimeServicesData and returns
1359 a pointer to the allocated buffer. The buffer returned is aligned on a 4KB
1360 boundary. If Pages is 0, then NULL is returned. If there is not enough
1361 memory remaining to satisfy the request, then NULL is returned.
1363 This function can also return NULL if there is no preference on where the
1364 page tables are allocated in SMRAM.
1366 @param Pages The number of 4 KB pages to allocate.
1368 @return A pointer to the allocated buffer for page tables.
1369 @retval NULL Fail to allocate a specific region for storing page tables,
1370 Or there is no preference on where the page tables are
1376 SmmCpuFeaturesAllocatePageTableMemory (