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 <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>
17 #include <Register/QemuSmramSaveStateMap.h>
20 // EFER register LMA bit
25 The constructor function
27 @param[in] ImageHandle The firmware allocated handle for the EFI image.
28 @param[in] SystemTable A pointer to the EFI System Table.
30 @retval EFI_SUCCESS The constructor always returns EFI_SUCCESS.
35 SmmCpuFeaturesLibConstructor (
36 IN EFI_HANDLE ImageHandle
,
37 IN EFI_SYSTEM_TABLE
*SystemTable
41 // No need to program SMRRs on our virtual platform.
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.
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
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.
72 SmmCpuFeaturesInitializeProcessor (
75 IN EFI_PROCESSOR_INFORMATION
*ProcessorInfo
,
76 IN CPU_HOT_PLUG_DATA
*CpuHotPlugData
79 QEMU_SMRAM_SAVE_STATE_MAP
*CpuState
;
84 CpuState
= (QEMU_SMRAM_SAVE_STATE_MAP
*)(UINTN
)(
86 SMRAM_SAVE_STATE_MAP_OFFSET
88 if ((CpuState
->x86
.SMMRevId
& 0xFFFF) == 0) {
89 CpuState
->x86
.SMBASE
= (UINT32
)CpuHotPlugData
->SmBase
[CpuIndex
];
91 CpuState
->x64
.SMBASE
= (UINT32
)CpuHotPlugData
->SmBase
[CpuIndex
];
95 // No need to program SMRRs on our virtual platform.
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
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.
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
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.
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.
132 SmmCpuFeaturesHookReturnFromSmm (
134 IN SMRAM_SAVE_STATE_MAP
*CpuState
,
135 IN UINT64 NewInstructionPointer32
,
136 IN UINT64 NewInstructionPointer
139 UINT64 OriginalInstructionPointer
;
140 QEMU_SMRAM_SAVE_STATE_MAP
*CpuSaveState
;
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
;
147 // Clear the auto HALT restart flag so the RSM instruction returns
148 // program control to the instruction following the HLT instruction.
150 if ((CpuSaveState
->x86
.AutoHALTRestart
& BIT0
) != 0) {
151 CpuSaveState
->x86
.AutoHALTRestart
&= ~BIT0
;
154 OriginalInstructionPointer
= CpuSaveState
->x64
._RIP
;
155 if ((CpuSaveState
->x64
.IA32_EFER
& LMA
) == 0) {
156 CpuSaveState
->x64
._RIP
= (UINT32
)NewInstructionPointer32
;
158 CpuSaveState
->x64
._RIP
= (UINT32
)NewInstructionPointer
;
161 // Clear the auto HALT restart flag so the RSM instruction returns
162 // program control to the instruction following the HLT instruction.
164 if ((CpuSaveState
->x64
.AutoHALTRestart
& BIT0
) != 0) {
165 CpuSaveState
->x64
.AutoHALTRestart
&= ~BIT0
;
168 return OriginalInstructionPointer
;
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().
180 SmmCpuFeaturesSmmRelocationComplete (
188 if (!MemEncryptSevIsEnabled ()) {
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.)
197 Status
= MemEncryptSevLocateInitialSmramSaveStateMapPages (
201 ASSERT_EFI_ERROR (Status
);
203 Status
= MemEncryptSevSetPageEncMask (
204 0, // Cr3BaseAddress -- use current CR3
205 MapPagesBase
, // BaseAddress
206 MapPagesCount
, // NumPages
209 if (EFI_ERROR (Status
)) {
210 DEBUG ((DEBUG_ERROR
, "%a: MemEncryptSevSetPageEncMask(): %r\n",
211 __FUNCTION__
, Status
));
216 ZeroMem ((VOID
*)MapPagesBase
, EFI_PAGES_TO_SIZE (MapPagesCount
));
218 Status
= gBS
->FreePages (MapPagesBase
, MapPagesCount
);
219 ASSERT_EFI_ERROR (Status
);
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.
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
235 SmmCpuFeaturesGetSmiHandlerSize (
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.
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.
269 SmmCpuFeaturesInstallSmiHandler (
284 Determines if MTRR registers must be configured to set SMRAM cache-ability
285 when executing in System Management Mode.
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
293 SmmCpuFeaturesNeedConfigureMtrrs (
301 Disable SMRR register if SMRR is supported and
302 SmmCpuFeaturesNeedConfigureMtrrs() returns TRUE.
306 SmmCpuFeaturesDisableSmrr (
311 // No SMRR support, nothing to do
316 Enable SMRR register if SMRR is supported and
317 SmmCpuFeaturesNeedConfigureMtrrs() returns TRUE.
321 SmmCpuFeaturesReenableSmrr (
326 // No SMRR support, nothing to do
331 Processor specific hook point each time a CPU enters System Management Mode.
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).
339 SmmCpuFeaturesRendezvousEntry (
344 // No SMRR support, nothing to do
349 Processor specific hook point each time a CPU exits System Management Mode.
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).
357 SmmCpuFeaturesRendezvousExit (
364 Check to see if an SMM register is supported by a specified CPU.
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.
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.
378 SmmCpuFeaturesIsSmmRegisterSupported (
380 IN SMM_REG_NAME RegName
383 ASSERT (RegName
== SmmRegFeatureControl
);
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.
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.
396 @return The value of the SMM register specified by RegName from the CPU
397 specified by CpuIndex.
401 SmmCpuFeaturesGetSmmRegister (
403 IN SMM_REG_NAME RegName
407 // This is called for SmmRegSmmDelayed, SmmRegSmmBlocked, SmmRegSmmEnable.
408 // The last of these should actually be SmmRegSmmDisable, so we can just
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.
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.
427 SmmCpuFeaturesSetSmmRegister (
429 IN SMM_REG_NAME RegName
,
437 /// Macro used to simplify the lookup table entries of type
438 /// CPU_SMM_SAVE_STATE_LOOKUP_ENTRY
440 #define SMM_CPU_OFFSET(Field) OFFSET_OF (QEMU_SMRAM_SAVE_STATE_MAP, Field)
443 /// Macro used to simplify the lookup table entries of type
444 /// CPU_SMM_SAVE_STATE_REGISTER_RANGE
446 #define SMM_REGISTER_RANGE(Start, End) { Start, End, End - Start + 1 }
449 /// Structure used to describe a range of registers
452 EFI_SMM_SAVE_STATE_REGISTER Start
;
453 EFI_SMM_SAVE_STATE_REGISTER End
;
455 } CPU_SMM_SAVE_STATE_REGISTER_RANGE
;
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
462 #define SMM_SAVE_STATE_REGISTER_FIRST_INDEX 1
471 } CPU_SMM_SAVE_STATE_LOOKUP_ENTRY
;
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
477 STATIC CONST CPU_SMM_SAVE_STATE_REGISTER_RANGE mSmmCpuRegisterRanges
[] = {
479 EFI_SMM_SAVE_STATE_REGISTER_GDTBASE
,
480 EFI_SMM_SAVE_STATE_REGISTER_LDTINFO
483 EFI_SMM_SAVE_STATE_REGISTER_ES
,
484 EFI_SMM_SAVE_STATE_REGISTER_RIP
487 EFI_SMM_SAVE_STATE_REGISTER_RFLAGS
,
488 EFI_SMM_SAVE_STATE_REGISTER_CR4
490 { (EFI_SMM_SAVE_STATE_REGISTER
)0, (EFI_SMM_SAVE_STATE_REGISTER
)0, 0 }
494 /// Lookup table used to retrieve the widths and offsets associated with each
495 /// supported EFI_SMM_SAVE_STATE_REGISTER value
497 STATIC CONST CPU_SMM_SAVE_STATE_LOOKUP_ENTRY mSmmCpuWidthOffset
[] = {
508 // CPU Save State registers defined in PI SMM CPU Protocol.
514 SMM_CPU_OFFSET (x64
._GDTRBase
), // Offset64Lo
515 SMM_CPU_OFFSET (x64
._GDTRBase
) + 4, // Offset64Hi
517 }, // EFI_SMM_SAVE_STATE_REGISTER_GDTBASE = 4
523 SMM_CPU_OFFSET (x64
._IDTRBase
), // Offset64Lo
524 SMM_CPU_OFFSET (x64
._IDTRBase
) + 4, // Offset64Hi
526 }, // EFI_SMM_SAVE_STATE_REGISTER_IDTBASE = 5
532 SMM_CPU_OFFSET (x64
._LDTRBase
), // Offset64Lo
533 SMM_CPU_OFFSET (x64
._LDTRBase
) + 4, // Offset64Hi
535 }, // EFI_SMM_SAVE_STATE_REGISTER_LDTBASE = 6
541 SMM_CPU_OFFSET (x64
._GDTRLimit
), // Offset64Lo
542 SMM_CPU_OFFSET (x64
._GDTRLimit
) + 4, // Offset64Hi
544 }, // EFI_SMM_SAVE_STATE_REGISTER_GDTLIMIT = 7
550 SMM_CPU_OFFSET (x64
._IDTRLimit
), // Offset64Lo
551 SMM_CPU_OFFSET (x64
._IDTRLimit
) + 4, // Offset64Hi
553 }, // EFI_SMM_SAVE_STATE_REGISTER_IDTLIMIT = 8
559 SMM_CPU_OFFSET (x64
._LDTRLimit
), // Offset64Lo
560 SMM_CPU_OFFSET (x64
._LDTRLimit
) + 4, // Offset64Hi
562 }, // EFI_SMM_SAVE_STATE_REGISTER_LDTLIMIT = 9
571 }, // EFI_SMM_SAVE_STATE_REGISTER_LDTINFO = 10
576 SMM_CPU_OFFSET (x86
._ES
), // Offset32
577 SMM_CPU_OFFSET (x64
._ES
), // Offset64Lo
580 }, // EFI_SMM_SAVE_STATE_REGISTER_ES = 20
585 SMM_CPU_OFFSET (x86
._CS
), // Offset32
586 SMM_CPU_OFFSET (x64
._CS
), // Offset64Lo
589 }, // EFI_SMM_SAVE_STATE_REGISTER_CS = 21
594 SMM_CPU_OFFSET (x86
._SS
), // Offset32
595 SMM_CPU_OFFSET (x64
._SS
), // Offset64Lo
598 }, // EFI_SMM_SAVE_STATE_REGISTER_SS = 22
603 SMM_CPU_OFFSET (x86
._DS
), // Offset32
604 SMM_CPU_OFFSET (x64
._DS
), // Offset64Lo
607 }, // EFI_SMM_SAVE_STATE_REGISTER_DS = 23
612 SMM_CPU_OFFSET (x86
._FS
), // Offset32
613 SMM_CPU_OFFSET (x64
._FS
), // Offset64Lo
616 }, // EFI_SMM_SAVE_STATE_REGISTER_FS = 24
621 SMM_CPU_OFFSET (x86
._GS
), // Offset32
622 SMM_CPU_OFFSET (x64
._GS
), // Offset64Lo
625 }, // EFI_SMM_SAVE_STATE_REGISTER_GS = 25
631 SMM_CPU_OFFSET (x64
._LDTR
), // Offset64Lo
634 }, // EFI_SMM_SAVE_STATE_REGISTER_LDTR_SEL = 26
639 SMM_CPU_OFFSET (x86
._TR
), // Offset32
640 SMM_CPU_OFFSET (x64
._TR
), // Offset64Lo
643 }, // EFI_SMM_SAVE_STATE_REGISTER_TR_SEL = 27
648 SMM_CPU_OFFSET (x86
._DR7
), // Offset32
649 SMM_CPU_OFFSET (x64
._DR7
), // Offset64Lo
650 SMM_CPU_OFFSET (x64
._DR7
) + 4, // Offset64Hi
652 }, // EFI_SMM_SAVE_STATE_REGISTER_DR7 = 28
657 SMM_CPU_OFFSET (x86
._DR6
), // Offset32
658 SMM_CPU_OFFSET (x64
._DR6
), // Offset64Lo
659 SMM_CPU_OFFSET (x64
._DR6
) + 4, // Offset64Hi
661 }, // EFI_SMM_SAVE_STATE_REGISTER_DR6 = 29
667 SMM_CPU_OFFSET (x64
._R8
), // Offset64Lo
668 SMM_CPU_OFFSET (x64
._R8
) + 4, // Offset64Hi
670 }, // EFI_SMM_SAVE_STATE_REGISTER_R8 = 30
676 SMM_CPU_OFFSET (x64
._R9
), // Offset64Lo
677 SMM_CPU_OFFSET (x64
._R9
) + 4, // Offset64Hi
679 }, // EFI_SMM_SAVE_STATE_REGISTER_R9 = 31
685 SMM_CPU_OFFSET (x64
._R10
), // Offset64Lo
686 SMM_CPU_OFFSET (x64
._R10
) + 4, // Offset64Hi
688 }, // EFI_SMM_SAVE_STATE_REGISTER_R10 = 32
694 SMM_CPU_OFFSET (x64
._R11
), // Offset64Lo
695 SMM_CPU_OFFSET (x64
._R11
) + 4, // Offset64Hi
697 }, // EFI_SMM_SAVE_STATE_REGISTER_R11 = 33
703 SMM_CPU_OFFSET (x64
._R12
), // Offset64Lo
704 SMM_CPU_OFFSET (x64
._R12
) + 4, // Offset64Hi
706 }, // EFI_SMM_SAVE_STATE_REGISTER_R12 = 34
712 SMM_CPU_OFFSET (x64
._R13
), // Offset64Lo
713 SMM_CPU_OFFSET (x64
._R13
) + 4, // Offset64Hi
715 }, // EFI_SMM_SAVE_STATE_REGISTER_R13 = 35
721 SMM_CPU_OFFSET (x64
._R14
), // Offset64Lo
722 SMM_CPU_OFFSET (x64
._R14
) + 4, // Offset64Hi
724 }, // EFI_SMM_SAVE_STATE_REGISTER_R14 = 36
730 SMM_CPU_OFFSET (x64
._R15
), // Offset64Lo
731 SMM_CPU_OFFSET (x64
._R15
) + 4, // Offset64Hi
733 }, // EFI_SMM_SAVE_STATE_REGISTER_R15 = 37
738 SMM_CPU_OFFSET (x86
._EAX
), // Offset32
739 SMM_CPU_OFFSET (x64
._RAX
), // Offset64Lo
740 SMM_CPU_OFFSET (x64
._RAX
) + 4, // Offset64Hi
742 }, // EFI_SMM_SAVE_STATE_REGISTER_RAX = 38
747 SMM_CPU_OFFSET (x86
._EBX
), // Offset32
748 SMM_CPU_OFFSET (x64
._RBX
), // Offset64Lo
749 SMM_CPU_OFFSET (x64
._RBX
) + 4, // Offset64Hi
751 }, // EFI_SMM_SAVE_STATE_REGISTER_RBX = 39
756 SMM_CPU_OFFSET (x86
._ECX
), // Offset32
757 SMM_CPU_OFFSET (x64
._RCX
), // Offset64Lo
758 SMM_CPU_OFFSET (x64
._RCX
) + 4, // Offset64Hi
760 }, // EFI_SMM_SAVE_STATE_REGISTER_RCX = 40
765 SMM_CPU_OFFSET (x86
._EDX
), // Offset32
766 SMM_CPU_OFFSET (x64
._RDX
), // Offset64Lo
767 SMM_CPU_OFFSET (x64
._RDX
) + 4, // Offset64Hi
769 }, // EFI_SMM_SAVE_STATE_REGISTER_RDX = 41
774 SMM_CPU_OFFSET (x86
._ESP
), // Offset32
775 SMM_CPU_OFFSET (x64
._RSP
), // Offset64Lo
776 SMM_CPU_OFFSET (x64
._RSP
) + 4, // Offset64Hi
778 }, // EFI_SMM_SAVE_STATE_REGISTER_RSP = 42
783 SMM_CPU_OFFSET (x86
._EBP
), // Offset32
784 SMM_CPU_OFFSET (x64
._RBP
), // Offset64Lo
785 SMM_CPU_OFFSET (x64
._RBP
) + 4, // Offset64Hi
787 }, // EFI_SMM_SAVE_STATE_REGISTER_RBP = 43
792 SMM_CPU_OFFSET (x86
._ESI
), // Offset32
793 SMM_CPU_OFFSET (x64
._RSI
), // Offset64Lo
794 SMM_CPU_OFFSET (x64
._RSI
) + 4, // Offset64Hi
796 }, // EFI_SMM_SAVE_STATE_REGISTER_RSI = 44
801 SMM_CPU_OFFSET (x86
._EDI
), // Offset32
802 SMM_CPU_OFFSET (x64
._RDI
), // Offset64Lo
803 SMM_CPU_OFFSET (x64
._RDI
) + 4, // Offset64Hi
805 }, // EFI_SMM_SAVE_STATE_REGISTER_RDI = 45
810 SMM_CPU_OFFSET (x86
._EIP
), // Offset32
811 SMM_CPU_OFFSET (x64
._RIP
), // Offset64Lo
812 SMM_CPU_OFFSET (x64
._RIP
) + 4, // Offset64Hi
814 }, // EFI_SMM_SAVE_STATE_REGISTER_RIP = 46
819 SMM_CPU_OFFSET (x86
._EFLAGS
), // Offset32
820 SMM_CPU_OFFSET (x64
._RFLAGS
), // Offset64Lo
821 SMM_CPU_OFFSET (x64
._RFLAGS
) + 4, // Offset64Hi
823 }, // EFI_SMM_SAVE_STATE_REGISTER_RFLAGS = 51
828 SMM_CPU_OFFSET (x86
._CR0
), // Offset32
829 SMM_CPU_OFFSET (x64
._CR0
), // Offset64Lo
830 SMM_CPU_OFFSET (x64
._CR0
) + 4, // Offset64Hi
832 }, // EFI_SMM_SAVE_STATE_REGISTER_CR0 = 52
837 SMM_CPU_OFFSET (x86
._CR3
), // Offset32
838 SMM_CPU_OFFSET (x64
._CR3
), // Offset64Lo
839 SMM_CPU_OFFSET (x64
._CR3
) + 4, // Offset64Hi
841 }, // EFI_SMM_SAVE_STATE_REGISTER_CR3 = 53
847 SMM_CPU_OFFSET (x64
._CR4
), // Offset64Lo
848 SMM_CPU_OFFSET (x64
._CR4
) + 4, // Offset64Hi
850 }, // EFI_SMM_SAVE_STATE_REGISTER_CR4 = 54
854 // No support for I/O restart
858 Read information from the CPU save state.
860 @param Register Specifies the CPU register to read form the save state.
862 @retval 0 Register is not valid
863 @retval >0 Index into mSmmCpuWidthOffset[] associated with Register
869 IN EFI_SMM_SAVE_STATE_REGISTER Register
875 for (Index
= 0, Offset
= SMM_SAVE_STATE_REGISTER_FIRST_INDEX
;
876 mSmmCpuRegisterRanges
[Index
].Length
!= 0;
878 if (Register
>= mSmmCpuRegisterRanges
[Index
].Start
&&
879 Register
<= mSmmCpuRegisterRanges
[Index
].End
) {
880 return Register
- mSmmCpuRegisterRanges
[Index
].Start
+ Offset
;
882 Offset
+= mSmmCpuRegisterRanges
[Index
].Length
;
888 Read a CPU Save State register on the target processor.
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.
893 This function supports reading a CPU Save State register in SMBase relocation
896 @param[in] CpuIndex Specifies the zero-based index of the CPU save
898 @param[in] RegisterIndex Index into mSmmCpuWidthOffset[] look up table.
899 @param[in] Width The number of bytes to read from the CPU save
901 @param[out] Buffer Upon return, this holds the CPU register value
902 read from the save state.
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
907 @retval EFI_INVALID_PARAMTER This or Buffer is NULL.
912 ReadSaveStateRegisterByIndex (
914 IN UINTN RegisterIndex
,
919 QEMU_SMRAM_SAVE_STATE_MAP
*CpuSaveState
;
921 CpuSaveState
= (QEMU_SMRAM_SAVE_STATE_MAP
*)gSmst
->CpuSaveState
[CpuIndex
];
923 if ((CpuSaveState
->x86
.SMMRevId
& 0xFFFF) == 0) {
925 // If 32-bit mode width is zero, then the specified register can not be
928 if (mSmmCpuWidthOffset
[RegisterIndex
].Width32
== 0) {
929 return EFI_NOT_FOUND
;
933 // If Width is bigger than the 32-bit mode width, then the specified
934 // register can not be accessed
936 if (Width
> mSmmCpuWidthOffset
[RegisterIndex
].Width32
) {
937 return EFI_INVALID_PARAMETER
;
941 // Write return buffer
943 ASSERT(CpuSaveState
!= NULL
);
946 (UINT8
*)CpuSaveState
+ mSmmCpuWidthOffset
[RegisterIndex
].Offset32
,
951 // If 64-bit mode width is zero, then the specified register can not be
954 if (mSmmCpuWidthOffset
[RegisterIndex
].Width64
== 0) {
955 return EFI_NOT_FOUND
;
959 // If Width is bigger than the 64-bit mode width, then the specified
960 // register can not be accessed
962 if (Width
> mSmmCpuWidthOffset
[RegisterIndex
].Width64
) {
963 return EFI_INVALID_PARAMETER
;
967 // Write lower 32-bits of return buffer
971 (UINT8
*)CpuSaveState
+ mSmmCpuWidthOffset
[RegisterIndex
].Offset64Lo
,
976 // Write upper 32-bits of return buffer
980 (UINT8
*)CpuSaveState
+ mSmmCpuWidthOffset
[RegisterIndex
].Offset64Hi
,
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.
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
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
1008 SmmCpuFeaturesReadSaveStateRegister (
1010 IN EFI_SMM_SAVE_STATE_REGISTER Register
,
1015 UINTN RegisterIndex
;
1016 QEMU_SMRAM_SAVE_STATE_MAP
*CpuSaveState
;
1019 // Check for special EFI_SMM_SAVE_STATE_REGISTER_LMA
1021 if (Register
== EFI_SMM_SAVE_STATE_REGISTER_LMA
) {
1023 // Only byte access is supported for this register
1026 return EFI_INVALID_PARAMETER
;
1029 CpuSaveState
= (QEMU_SMRAM_SAVE_STATE_MAP
*)gSmst
->CpuSaveState
[CpuIndex
];
1034 if ((CpuSaveState
->x86
.SMMRevId
& 0xFFFF) == 0) {
1035 *(UINT8
*)Buffer
= 32;
1037 *(UINT8
*)Buffer
= 64;
1044 // Check for special EFI_SMM_SAVE_STATE_REGISTER_IO
1046 if (Register
== EFI_SMM_SAVE_STATE_REGISTER_IO
) {
1047 return EFI_NOT_FOUND
;
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).
1055 RegisterIndex
= GetRegisterIndex (Register
);
1056 if (RegisterIndex
== 0) {
1057 return (Register
< EFI_SMM_SAVE_STATE_REGISTER_IO
?
1062 return ReadSaveStateRegisterByIndex (CpuIndex
, RegisterIndex
, Width
, Buffer
);
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.
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.
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
1084 SmmCpuFeaturesWriteSaveStateRegister (
1086 IN EFI_SMM_SAVE_STATE_REGISTER Register
,
1088 IN CONST VOID
*Buffer
1091 UINTN RegisterIndex
;
1092 QEMU_SMRAM_SAVE_STATE_MAP
*CpuSaveState
;
1095 // Writes to EFI_SMM_SAVE_STATE_REGISTER_LMA are ignored
1097 if (Register
== EFI_SMM_SAVE_STATE_REGISTER_LMA
) {
1102 // Writes to EFI_SMM_SAVE_STATE_REGISTER_IO are not supported
1104 if (Register
== EFI_SMM_SAVE_STATE_REGISTER_IO
) {
1105 return EFI_NOT_FOUND
;
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).
1113 RegisterIndex
= GetRegisterIndex (Register
);
1114 if (RegisterIndex
== 0) {
1115 return (Register
< EFI_SMM_SAVE_STATE_REGISTER_IO
?
1120 CpuSaveState
= (QEMU_SMRAM_SAVE_STATE_MAP
*)gSmst
->CpuSaveState
[CpuIndex
];
1123 // Do not write non-writable SaveState, because it will cause exception.
1125 if (!mSmmCpuWidthOffset
[RegisterIndex
].Writeable
) {
1126 return EFI_UNSUPPORTED
;
1132 if ((CpuSaveState
->x86
.SMMRevId
& 0xFFFF) == 0) {
1134 // If 32-bit mode width is zero, then the specified register can not be
1137 if (mSmmCpuWidthOffset
[RegisterIndex
].Width32
== 0) {
1138 return EFI_NOT_FOUND
;
1142 // If Width is bigger than the 32-bit mode width, then the specified
1143 // register can not be accessed
1145 if (Width
> mSmmCpuWidthOffset
[RegisterIndex
].Width32
) {
1146 return EFI_INVALID_PARAMETER
;
1149 // Write SMM State register
1151 ASSERT (CpuSaveState
!= NULL
);
1153 (UINT8
*)CpuSaveState
+ mSmmCpuWidthOffset
[RegisterIndex
].Offset32
,
1159 // If 64-bit mode width is zero, then the specified register can not be
1162 if (mSmmCpuWidthOffset
[RegisterIndex
].Width64
== 0) {
1163 return EFI_NOT_FOUND
;
1167 // If Width is bigger than the 64-bit mode width, then the specified
1168 // register can not be accessed
1170 if (Width
> mSmmCpuWidthOffset
[RegisterIndex
].Width64
) {
1171 return EFI_INVALID_PARAMETER
;
1175 // Write lower 32-bits of SMM State register
1178 (UINT8
*)CpuSaveState
+ mSmmCpuWidthOffset
[RegisterIndex
].Offset64Lo
,
1184 // Write upper 32-bits of SMM State register
1187 (UINT8
*)CpuSaveState
+ mSmmCpuWidthOffset
[RegisterIndex
].Offset64Hi
,
1188 (UINT8
*)Buffer
+ 4,
1197 This function is hook point called after the gEfiSmmReadyToLockProtocolGuid
1198 notification is completely processed.
1202 SmmCpuFeaturesCompleteSmmReadyToLock (
1209 This API provides a method for a CPU to allocate a specific region for
1210 storing page tables.
1212 This API can be called more once to allocate memory for page tables.
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.
1219 This function can also return NULL if there is no preference on where the
1220 page tables are allocated in SMRAM.
1222 @param Pages The number of 4 KB pages to allocate.
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
1232 SmmCpuFeaturesAllocatePageTableMemory (