2 SMM Base Helper SMM driver.
4 This driver is the counterpart of the SMM Base On SMM Base2 Thunk driver. It
5 provides helping services in SMM to the SMM Base On SMM Base2 Thunk driver.
7 Copyright (c) 2009 - 2010, Intel Corporation
8 All rights reserved. This program and the accompanying materials
9 are licensed and made available under the terms and conditions of the BSD License
10 which accompanies this distribution. The full text of the license may be found at
11 http://opensource.org/licenses/bsd-license.php
13 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
14 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
19 #include <Library/DebugLib.h>
20 #include <Library/UefiBootServicesTableLib.h>
21 #include <Library/SmmServicesTableLib.h>
22 #include <Library/BaseLib.h>
23 #include <Library/BaseMemoryLib.h>
24 #include <Library/PeCoffLib.h>
25 #include <Library/DevicePathLib.h>
26 #include <Library/CacheMaintenanceLib.h>
27 #include <Library/MemoryAllocationLib.h>
28 #include <Library/SynchronizationLib.h>
29 #include <Library/CpuLib.h>
30 #include <Guid/SmmBaseThunkCommunication.h>
31 #include <Protocol/SmmBaseHelperReady.h>
32 #include <Protocol/SmmCpu.h>
33 #include <Protocol/LoadedImage.h>
34 #include <Protocol/SmmCpuSaveState.h>
35 #include <Protocol/MpService.h>
36 #include <Protocol/LoadPe32Image.h>
37 #include <Protocol/SmmReadyToLock.h>
40 /// Structure for tracking paired information of registered Framework SMI handler
41 /// and correpsonding dispatch handle for SMI handler thunk.
45 EFI_HANDLE DispatchHandle
;
46 EFI_HANDLE SmmImageHandle
;
47 EFI_SMM_CALLBACK_ENTRY_POINT CallbackAddress
;
48 VOID
*CommunicationBuffer
;
54 /// PI SMM CPU Save State register index
56 EFI_SMM_SAVE_STATE_REGISTER Register
;
58 /// Offset in Framework SMST
61 } CPU_SAVE_STATE_CONVERSION
;
63 #define CPU_SAVE_STATE_GET_OFFSET(Field) (UINTN)(&(((EFI_SMM_CPU_SAVE_STATE *) 0)->Ia32SaveState.Field))
66 EFI_HANDLE mDispatchHandle
;
67 EFI_SMM_CPU_PROTOCOL
*mSmmCpu
;
68 EFI_PE32_IMAGE_PROTOCOL
*mLoadPe32Image
;
69 EFI_GUID mEfiSmmCpuIoGuid
= EFI_SMM_CPU_IO_GUID
;
70 EFI_SMM_BASE_HELPER_READY_PROTOCOL
*mSmmBaseHelperReady
;
71 EFI_SMM_SYSTEM_TABLE
*mFrameworkSmst
;
72 UINTN mNumberOfProcessors
;
73 BOOLEAN mLocked
= FALSE
;
74 BOOLEAN mPageTableHookEnabled
;
75 BOOLEAN mHookInitialized
;
76 UINT64
*mCpuStatePageTable
;
79 VOID
*mOriginalHandler
;
80 EFI_SMM_CPU_SAVE_STATE
*mShadowSaveState
;
82 LIST_ENTRY mCallbackInfoListHead
= INITIALIZE_LIST_HEAD_VARIABLE (mCallbackInfoListHead
);
84 CPU_SAVE_STATE_CONVERSION mCpuSaveStateConvTable
[] = {
85 {EFI_SMM_SAVE_STATE_REGISTER_LDTBASE
, CPU_SAVE_STATE_GET_OFFSET(LDTBase
)},
86 {EFI_SMM_SAVE_STATE_REGISTER_ES
, CPU_SAVE_STATE_GET_OFFSET(ES
)},
87 {EFI_SMM_SAVE_STATE_REGISTER_CS
, CPU_SAVE_STATE_GET_OFFSET(CS
)},
88 {EFI_SMM_SAVE_STATE_REGISTER_SS
, CPU_SAVE_STATE_GET_OFFSET(SS
)},
89 {EFI_SMM_SAVE_STATE_REGISTER_DS
, CPU_SAVE_STATE_GET_OFFSET(DS
)},
90 {EFI_SMM_SAVE_STATE_REGISTER_FS
, CPU_SAVE_STATE_GET_OFFSET(FS
)},
91 {EFI_SMM_SAVE_STATE_REGISTER_GS
, CPU_SAVE_STATE_GET_OFFSET(GS
)},
92 {EFI_SMM_SAVE_STATE_REGISTER_TR_SEL
, CPU_SAVE_STATE_GET_OFFSET(TR
)},
93 {EFI_SMM_SAVE_STATE_REGISTER_DR7
, CPU_SAVE_STATE_GET_OFFSET(DR7
)},
94 {EFI_SMM_SAVE_STATE_REGISTER_DR6
, CPU_SAVE_STATE_GET_OFFSET(DR6
)},
95 {EFI_SMM_SAVE_STATE_REGISTER_RAX
, CPU_SAVE_STATE_GET_OFFSET(EAX
)},
96 {EFI_SMM_SAVE_STATE_REGISTER_RBX
, CPU_SAVE_STATE_GET_OFFSET(EBX
)},
97 {EFI_SMM_SAVE_STATE_REGISTER_RCX
, CPU_SAVE_STATE_GET_OFFSET(ECX
)},
98 {EFI_SMM_SAVE_STATE_REGISTER_RDX
, CPU_SAVE_STATE_GET_OFFSET(EDX
)},
99 {EFI_SMM_SAVE_STATE_REGISTER_RSP
, CPU_SAVE_STATE_GET_OFFSET(ESP
)},
100 {EFI_SMM_SAVE_STATE_REGISTER_RBP
, CPU_SAVE_STATE_GET_OFFSET(EBP
)},
101 {EFI_SMM_SAVE_STATE_REGISTER_RSI
, CPU_SAVE_STATE_GET_OFFSET(ESI
)},
102 {EFI_SMM_SAVE_STATE_REGISTER_RDI
, CPU_SAVE_STATE_GET_OFFSET(EDI
)},
103 {EFI_SMM_SAVE_STATE_REGISTER_RIP
, CPU_SAVE_STATE_GET_OFFSET(EIP
)},
104 {EFI_SMM_SAVE_STATE_REGISTER_RFLAGS
, CPU_SAVE_STATE_GET_OFFSET(EFLAGS
)},
105 {EFI_SMM_SAVE_STATE_REGISTER_CR0
, CPU_SAVE_STATE_GET_OFFSET(CR0
)},
106 {EFI_SMM_SAVE_STATE_REGISTER_CR3
, CPU_SAVE_STATE_GET_OFFSET(CR3
)}
110 PageFaultHandlerHook (
117 EFI_SMM_CPU_SAVE_STATE
*ToRead
122 EFI_SMM_CPU_STATE
*State
;
123 EFI_SMI_CPU_SAVE_STATE
*SaveState
;
125 State
= (EFI_SMM_CPU_STATE
*)gSmst
->CpuSaveState
[CpuIndex
];
126 if (ToRead
!= NULL
) {
127 SaveState
= &ToRead
->Ia32SaveState
;
129 SaveState
= &mFrameworkSmst
->CpuSaveState
[CpuIndex
].Ia32SaveState
;
132 if (State
->x86
.SMMRevId
< EFI_SMM_MIN_REV_ID_x64
) {
133 SaveState
->SMBASE
= State
->x86
.SMBASE
;
134 SaveState
->SMMRevId
= State
->x86
.SMMRevId
;
135 SaveState
->IORestart
= State
->x86
.IORestart
;
136 SaveState
->AutoHALTRestart
= State
->x86
.AutoHALTRestart
;
138 SaveState
->SMBASE
= State
->x64
.SMBASE
;
139 SaveState
->SMMRevId
= State
->x64
.SMMRevId
;
140 SaveState
->IORestart
= State
->x64
.IORestart
;
141 SaveState
->AutoHALTRestart
= State
->x64
.AutoHALTRestart
;
144 for (Index
= 0; Index
< sizeof (mCpuSaveStateConvTable
) / sizeof (CPU_SAVE_STATE_CONVERSION
); Index
++) {
146 /// Try to use SMM CPU Protocol to access CPU save states if possible
148 Status
= mSmmCpu
->ReadSaveState (
150 (UINTN
)sizeof (UINT32
),
151 mCpuSaveStateConvTable
[Index
].Register
,
153 ((UINT8
*)SaveState
) + mCpuSaveStateConvTable
[Index
].Offset
155 ASSERT_EFI_ERROR (Status
);
162 EFI_SMM_CPU_SAVE_STATE
*ToWrite
167 EFI_SMI_CPU_SAVE_STATE
*SaveState
;
169 if (ToWrite
!= NULL
) {
170 SaveState
= &ToWrite
->Ia32SaveState
;
172 SaveState
= &mFrameworkSmst
->CpuSaveState
[CpuIndex
].Ia32SaveState
;
175 for (Index
= 0; Index
< sizeof (mCpuSaveStateConvTable
) / sizeof (CPU_SAVE_STATE_CONVERSION
); Index
++) {
176 Status
= mSmmCpu
->WriteSaveState (
178 (UINTN
)sizeof (UINT32
),
179 mCpuSaveStateConvTable
[Index
].Register
,
181 ((UINT8
*)SaveState
) +
182 mCpuSaveStateConvTable
[Index
].Offset
188 ReadWriteCpuStatePage (
193 UINTN FirstSSIndex
; // Index of first CpuSaveState in the page
194 UINTN LastSSIndex
; // Index of last CpuSaveState in the page
195 BOOLEAN FirstSSAligned
; // Whether first CpuSaveState is page-aligned
196 BOOLEAN LastSSAligned
; // Whether the end of last CpuSaveState is page-aligned
200 FirstSSIndex
= ((UINTN
)PageAddress
- (UINTN
)mFrameworkSmst
->CpuSaveState
) / sizeof (EFI_SMM_CPU_SAVE_STATE
);
201 FirstSSAligned
= TRUE
;
202 if (((UINTN
)PageAddress
- (UINTN
)mFrameworkSmst
->CpuSaveState
) % sizeof (EFI_SMM_CPU_SAVE_STATE
) != 0) {
204 FirstSSAligned
= FALSE
;
206 LastSSIndex
= ((UINTN
)PageAddress
+ SIZE_4KB
- (UINTN
)mFrameworkSmst
->CpuSaveState
- 1) / sizeof (EFI_SMM_CPU_SAVE_STATE
);
207 LastSSAligned
= TRUE
;
208 if (((UINTN
)PageAddress
+ SIZE_4KB
- (UINTN
)mFrameworkSmst
->CpuSaveState
) % sizeof (EFI_SMM_CPU_SAVE_STATE
) != 0) {
210 LastSSAligned
= FALSE
;
212 for (CpuIndex
= FirstSSIndex
; CpuIndex
<= LastSSIndex
&& CpuIndex
< mNumberOfProcessors
; CpuIndex
++) {
214 ReadCpuSaveState (CpuIndex
, NULL
);
216 WriteCpuSaveState (CpuIndex
, NULL
);
219 if (!FirstSSAligned
) {
220 ReadCpuSaveState (FirstSSIndex
- 1, mShadowSaveState
);
221 ClippedSize
= (UINTN
)&mFrameworkSmst
->CpuSaveState
[FirstSSIndex
] & (SIZE_4KB
- 1);
223 CopyMem ((VOID
*)(UINTN
)PageAddress
, (VOID
*)((UINTN
)(mShadowSaveState
+ 1) - ClippedSize
), ClippedSize
);
225 CopyMem ((VOID
*)((UINTN
)(mShadowSaveState
+ 1) - ClippedSize
), (VOID
*)(UINTN
)PageAddress
, ClippedSize
);
226 WriteCpuSaveState (FirstSSIndex
- 1, mShadowSaveState
);
229 if (!LastSSAligned
&& LastSSIndex
+ 1 < mNumberOfProcessors
) {
230 ReadCpuSaveState (LastSSIndex
+ 1, mShadowSaveState
);
231 ClippedSize
= SIZE_4KB
- ((UINTN
)&mFrameworkSmst
->CpuSaveState
[LastSSIndex
+ 1] & (SIZE_4KB
- 1));
233 CopyMem (&mFrameworkSmst
->CpuSaveState
[LastSSIndex
+ 1], mShadowSaveState
, ClippedSize
);
235 CopyMem (mShadowSaveState
, &mFrameworkSmst
->CpuSaveState
[LastSSIndex
+ 1], ClippedSize
);
236 WriteCpuSaveState (LastSSIndex
+ 1, mShadowSaveState
);
249 UINTN NumCpuStatePages
;
251 ASSERT (mPageTableHookEnabled
);
252 AcquireSpinLock (&mPFLock
);
254 PageTable
= (UINT64
*)(UINTN
)(AsmReadCr3 () & mPhyMask
);
255 PFAddress
= AsmReadCr2 ();
256 NumCpuStatePages
= EFI_SIZE_TO_PAGES (mNumberOfProcessors
* sizeof (EFI_SMM_CPU_SAVE_STATE
));
258 if (((UINTN
)mFrameworkSmst
->CpuSaveState
& ~(SIZE_2MB
-1)) == (PFAddress
& ~(SIZE_2MB
-1))) {
259 if ((UINTN
)mFrameworkSmst
->CpuSaveState
<= PFAddress
&&
260 PFAddress
< (UINTN
)mFrameworkSmst
->CpuSaveState
+ EFI_PAGES_TO_SIZE (NumCpuStatePages
)
262 mCpuStatePageTable
[BitFieldRead64 (PFAddress
, 12, 20)] |= BIT0
| BIT1
; // present and rw
264 ReadWriteCpuStatePage (PFAddress
& ~(SIZE_4KB
-1), TRUE
);
271 ReleaseSpinLock (&mPFLock
);
276 WriteBackDirtyPages (
280 UINTN NumCpuStatePages
;
285 NumCpuStatePages
= EFI_SIZE_TO_PAGES (mNumberOfProcessors
* sizeof (EFI_SMM_CPU_SAVE_STATE
));
286 PTStartIndex
= (UINTN
)BitFieldRead64 ((UINT64
)mFrameworkSmst
->CpuSaveState
, 12, 20);
287 PTEndIndex
= (UINTN
)BitFieldRead64 ((UINT64
)mFrameworkSmst
->CpuSaveState
+ EFI_PAGES_TO_SIZE(NumCpuStatePages
) - 1, 12, 20);
288 for (PTIndex
= PTStartIndex
; PTIndex
<= PTEndIndex
; PTIndex
++) {
289 if ((mCpuStatePageTable
[PTIndex
] & (BIT0
|BIT6
)) == (BIT0
|BIT6
)) { // present and dirty?
290 ReadWriteCpuStatePage (mCpuStatePageTable
[PTIndex
] & mPhyMask
, FALSE
);
296 HookPageFaultHandler (
300 IA32_DESCRIPTOR Idtr
;
301 IA32_IDT_GATE_DESCRIPTOR
*IdtGateDesc
;
304 InitializeSpinLock (&mPFLock
);
307 IdtGateDesc
= (IA32_IDT_GATE_DESCRIPTOR
*) Idtr
.Base
;
308 OffsetUpper
= *(UINT32
*)((UINT64
*)IdtGateDesc
+ 1);
309 mOriginalHandler
= (VOID
*)(UINTN
)(LShiftU64 (OffsetUpper
, 32) + IdtGateDesc
[14].Bits
.OffsetLow
+ (IdtGateDesc
[14].Bits
.OffsetHigh
<< 16));
310 IdtGateDesc
[14].Bits
.OffsetLow
= (UINT32
)((UINTN
)PageFaultHandlerHook
& ((1 << 16) - 1));
311 IdtGateDesc
[14].Bits
.OffsetHigh
= (UINT32
)(((UINTN
)PageFaultHandlerHook
>> 16) & ((1 << 16) - 1));
315 InitCpuStatePageTable (
327 // Initialize physical address mask
328 // NOTE: Physical memory above virtual address limit is not supported !!!
330 AsmCpuid (0x80000008, (UINT32
*)&Index
, NULL
, NULL
, NULL
);
331 mPhyMask
= LShiftU64 (1, (UINT8
)Index
) - 1;
332 mPhyMask
&= (1ull << 48) - EFI_PAGE_SIZE
;
334 HookAddress
= (UINT64
)(UINTN
)HookData
;
335 PageTable
= (UINT64
*)(UINTN
)(AsmReadCr3 () & mPhyMask
);
336 PageTable
= (UINT64
*)(UINTN
)(PageTable
[BitFieldRead64 (HookAddress
, 39, 47)] & mPhyMask
);
337 PageTable
= (UINT64
*)(UINTN
)(PageTable
[BitFieldRead64 (HookAddress
, 30, 38)] & mPhyMask
);
339 PDPTE
= (UINT64
*)(UINTN
)PageTable
;
340 PDE
= PDPTE
[BitFieldRead64 (HookAddress
, 21, 29)];
341 ASSERT ((PDE
& BIT0
) != 0); // Present and 2M Page
343 if ((PDE
& BIT7
) == 0) { // 4KB Page Directory
344 PageTable
= (UINT64
*)(UINTN
)(PDE
& mPhyMask
);
346 ASSERT ((PDE
& mPhyMask
) == (HookAddress
& ~(SIZE_2MB
-1))); // 2MB Page Point to HookAddress
347 PageTable
= AllocatePages (1);
348 Address
= HookAddress
& ~(SIZE_2MB
-1);
349 for (Index
= 0; Index
< 512; Index
++) {
350 PageTable
[Index
] = Address
| BIT0
| BIT1
; // Present and RW
353 PDPTE
[BitFieldRead64 (HookAddress
, 21, 29)] = (UINT64
)(UINTN
)PageTable
| BIT0
| BIT1
; // Present and RW
360 EFI_SMM_CPU_SAVE_STATE
*CpuSaveState
367 PTStartIndex
= BitFieldRead64 ((UINTN
)CpuSaveState
, 12, 20);
368 PTEndIndex
= BitFieldRead64 ((UINTN
)CpuSaveState
+ mNumberOfProcessors
* sizeof (EFI_SMM_CPU_SAVE_STATE
) - 1, 12, 20);
369 for (Index
= PTStartIndex
; Index
<= PTEndIndex
; Index
++) {
370 mCpuStatePageTable
[Index
] &= ~(BIT0
|BIT5
|BIT6
); // not present nor accessed nor dirty
375 Framework SMST SmmInstallConfigurationTable() Thunk.
377 This thunk calls the PI SMM SmmInstallConfigurationTable() and then update the configuration
378 table related fields in the Framework SMST because the PI SMM SmmInstallConfigurationTable()
379 function may modify these fields.
381 @param[in] SystemTable A pointer to the SMM System Table.
382 @param[in] Guid A pointer to the GUID for the entry to add, update, or remove.
383 @param[in] Table A pointer to the buffer of the table to add.
384 @param[in] TableSize The size of the table to install.
386 @retval EFI_SUCCESS The (Guid, Table) pair was added, updated, or removed.
387 @retval EFI_INVALID_PARAMETER Guid is not valid.
388 @retval EFI_NOT_FOUND An attempt was made to delete a non-existent entry.
389 @retval EFI_OUT_OF_RESOURCES There is not enough memory available to complete the operation.
393 SmmInstallConfigurationTable (
394 IN EFI_SMM_SYSTEM_TABLE
*SystemTable
,
402 Status
= gSmst
->SmmInstallConfigurationTable (gSmst
, Guid
, Table
, TableSize
);
403 if (!EFI_ERROR (Status
)) {
404 mFrameworkSmst
->NumberOfTableEntries
= gSmst
->NumberOfTableEntries
;
405 mFrameworkSmst
->SmmConfigurationTable
= gSmst
->SmmConfigurationTable
;
412 EFI_SMM_SYSTEM_TABLE
*FrameworkSmst
415 UINTN NumCpuStatePages
;
420 mPageTableHookEnabled
= FALSE
;
421 NumCpuStatePages
= EFI_SIZE_TO_PAGES (mNumberOfProcessors
* sizeof (EFI_SMM_CPU_SAVE_STATE
));
423 // Only hook page table for X64 image and less than 2MB needed to hold all CPU Save States
425 if (EFI_IMAGE_MACHINE_TYPE_SUPPORTED(EFI_IMAGE_MACHINE_X64
) && NumCpuStatePages
<= EFI_SIZE_TO_PAGES (SIZE_2MB
)) {
427 // Allocate double page size to make sure all CPU Save States are in one 2MB page.
429 CpuStatePage
= (UINTN
)AllocatePages (NumCpuStatePages
* 2);
430 ASSERT (CpuStatePage
!= 0);
431 Bottom2MPage
= CpuStatePage
& ~(SIZE_2MB
-1);
432 Top2MPage
= (CpuStatePage
+ EFI_PAGES_TO_SIZE (NumCpuStatePages
* 2) - 1) & ~(SIZE_2MB
-1);
433 if (Bottom2MPage
== Top2MPage
||
434 CpuStatePage
+ EFI_PAGES_TO_SIZE (NumCpuStatePages
* 2) - Top2MPage
>= EFI_PAGES_TO_SIZE (NumCpuStatePages
)
437 // If the allocated 4KB pages are within the same 2MB page or higher portion is larger, use higher portion pages.
439 FrameworkSmst
->CpuSaveState
= (EFI_SMM_CPU_SAVE_STATE
*)(CpuStatePage
+ EFI_PAGES_TO_SIZE (NumCpuStatePages
));
440 FreePages ((VOID
*)CpuStatePage
, NumCpuStatePages
);
442 FrameworkSmst
->CpuSaveState
= (EFI_SMM_CPU_SAVE_STATE
*)CpuStatePage
;
443 FreePages ((VOID
*)(CpuStatePage
+ EFI_PAGES_TO_SIZE (NumCpuStatePages
)), NumCpuStatePages
);
446 // Add temporary working buffer for hooking
448 mShadowSaveState
= (EFI_SMM_CPU_SAVE_STATE
*) AllocatePool (sizeof (EFI_SMM_CPU_SAVE_STATE
));
449 ASSERT (mShadowSaveState
!= NULL
);
451 // Allocate and initialize 4KB Page Table for hooking CpuSaveState.
452 // Replace the original 2MB PDE with new 4KB page table.
454 mCpuStatePageTable
= InitCpuStatePageTable (FrameworkSmst
->CpuSaveState
);
456 // Mark PTE for CpuSaveState as non-exist.
458 HookCpuStateMemory (FrameworkSmst
->CpuSaveState
);
459 HookPageFaultHandler ();
461 mPageTableHookEnabled
= TRUE
;
463 mHookInitialized
= TRUE
;
467 Construct a Framework SMST based on the PI SMM SMST.
469 @return Pointer to the constructed Framework SMST.
471 EFI_SMM_SYSTEM_TABLE
*
472 ConstructFrameworkSmst (
476 EFI_SMM_SYSTEM_TABLE
*FrameworkSmst
;
478 FrameworkSmst
= (EFI_SMM_SYSTEM_TABLE
*)AllocatePool (sizeof (EFI_SMM_SYSTEM_TABLE
));
479 ASSERT (FrameworkSmst
!= NULL
);
482 /// Copy same things from PI SMST to Framework SMST
484 CopyMem (FrameworkSmst
, gSmst
, (UINTN
)(&((EFI_SMM_SYSTEM_TABLE
*)0)->SmmIo
));
486 &FrameworkSmst
->SmmIo
,
488 sizeof (EFI_SMM_SYSTEM_TABLE
) - (UINTN
)(&((EFI_SMM_SYSTEM_TABLE
*)0)->SmmIo
)
492 /// Update Framework SMST
494 FrameworkSmst
->Hdr
.Revision
= EFI_SMM_SYSTEM_TABLE_REVISION
;
495 CopyGuid (&FrameworkSmst
->EfiSmmCpuIoGuid
, &mEfiSmmCpuIoGuid
);
497 mHookInitialized
= FALSE
;
498 FrameworkSmst
->CpuSaveState
= (EFI_SMM_CPU_SAVE_STATE
*)AllocateZeroPool (mNumberOfProcessors
* sizeof (EFI_SMM_CPU_SAVE_STATE
));
499 ASSERT (FrameworkSmst
->CpuSaveState
!= NULL
);
502 /// Do not support floating point state now
504 FrameworkSmst
->CpuOptionalFloatingPointState
= NULL
;
506 FrameworkSmst
->SmmInstallConfigurationTable
= SmmInstallConfigurationTable
;
508 return FrameworkSmst
;
512 Load a given Framework SMM driver into SMRAM and invoke its entry point.
514 @param[in] ParentImageHandle Parent Image Handle.
515 @param[in] FilePath Location of the image to be installed as the handler.
516 @param[in] SourceBuffer Optional source buffer in case the image file
518 @param[in] SourceSize Size of the source image file, if in memory.
519 @param[out] ImageHandle The handle that the base driver uses to decode
520 the handler. Unique among SMM handlers only,
521 not unique across DXE/EFI.
523 @retval EFI_SUCCESS The operation was successful.
524 @retval EFI_OUT_OF_RESOURCES There were no additional SMRAM resources to load the handler
525 @retval EFI_UNSUPPORTED Can not find its copy in normal memory.
526 @retval EFI_INVALID_PARAMETER The handlers was not the correct image type
530 IN EFI_HANDLE ParentImageHandle
,
531 IN EFI_DEVICE_PATH_PROTOCOL
*FilePath
,
532 IN VOID
*SourceBuffer
,
534 OUT EFI_HANDLE
*ImageHandle
540 EFI_PHYSICAL_ADDRESS DstBuffer
;
542 if (FilePath
== NULL
|| ImageHandle
== NULL
) {
543 return EFI_INVALID_PARAMETER
;
548 OrgPageCount
= PageCount
;
549 DstBuffer
= (UINTN
)-1;
550 Status
= gSmst
->SmmAllocatePages (
552 EfiRuntimeServicesCode
,
556 if (EFI_ERROR (Status
)) {
560 Status
= mLoadPe32Image
->LoadPeImage (
570 EFI_LOAD_PE_IMAGE_ATTRIBUTE_NONE
572 if (EFI_ERROR (Status
)) {
573 FreePages ((VOID
*)(UINTN
)DstBuffer
, OrgPageCount
);
575 } while (Status
== EFI_BUFFER_TOO_SMALL
);
577 if (!EFI_ERROR (Status
)) {
579 /// Update MP state in Framework SMST before transferring control to Framework SMM driver entry point
580 /// in case it may invoke AP
582 mFrameworkSmst
->CurrentlyExecutingCpu
= gSmst
->CurrentlyExecutingCpu
;
584 Status
= gBS
->StartImage (*ImageHandle
, NULL
, NULL
);
585 if (EFI_ERROR (Status
)) {
586 mLoadPe32Image
->UnLoadPeImage (mLoadPe32Image
, *ImageHandle
);
588 FreePages ((VOID
*)(UINTN
)DstBuffer
, PageCount
);
597 Thunk service of EFI_SMM_BASE_PROTOCOL.Register().
599 @param[in, out] FunctionData Pointer to SMMBASE_FUNCTION_DATA.
603 IN OUT SMMBASE_FUNCTION_DATA
*FunctionData
608 if (mLocked
|| FunctionData
->Args
.Register
.LegacyIA32Binary
) {
609 Status
= EFI_UNSUPPORTED
;
612 FunctionData
->SmmBaseImageHandle
,
613 FunctionData
->Args
.Register
.FilePath
,
614 FunctionData
->Args
.Register
.SourceBuffer
,
615 FunctionData
->Args
.Register
.SourceSize
,
616 FunctionData
->Args
.Register
.ImageHandle
619 FunctionData
->Status
= Status
;
623 Thunk service of EFI_SMM_BASE_PROTOCOL.UnRegister().
625 @param[in, out] FunctionData Pointer to SMMBASE_FUNCTION_DATA.
629 IN OUT SMMBASE_FUNCTION_DATA
*FunctionData
633 /// Unregister not supported now
635 FunctionData
->Status
= EFI_UNSUPPORTED
;
639 Search for Framework SMI handler information according to specific PI SMM dispatch handle.
641 @param[in] DispatchHandle The unique handle assigned by SmiHandlerRegister().
643 @return Pointer to CALLBACK_INFO. If NULL, no callback info record is found.
647 IN EFI_HANDLE DispatchHandle
652 Node
= GetFirstNode (&mCallbackInfoListHead
);
653 while (!IsNull (&mCallbackInfoListHead
, Node
)) {
654 if (((CALLBACK_INFO
*)Node
)->DispatchHandle
== DispatchHandle
) {
655 return (CALLBACK_INFO
*)Node
;
657 Node
= GetNextNode (&mCallbackInfoListHead
, Node
);
663 Callback thunk for Framework SMI handler.
665 This thunk functions calls the Framework SMI handler and converts the return value
666 defined from Framework SMI handlers to a correpsonding return value defined by PI SMM.
668 @param[in] DispatchHandle The unique handle assigned to this handler by SmiHandlerRegister().
669 @param[in] Context Points to an optional handler context which was specified when the
670 handler was registered.
671 @param[in, out] CommBuffer A pointer to a collection of data in memory that will
672 be conveyed from a non-SMM environment into an SMM environment.
673 @param[in, out] CommBufferSize The size of the CommBuffer.
675 @retval EFI_SUCCESS The interrupt was handled and quiesced. No other handlers
676 should still be called.
677 @retval EFI_WARN_INTERRUPT_SOURCE_QUIESCED The interrupt has been quiesced but other handlers should
679 @retval EFI_WARN_INTERRUPT_SOURCE_PENDING The interrupt is still pending and other handlers should still
681 @retval EFI_INTERRUPT_PENDING The interrupt could not be quiesced.
686 IN EFI_HANDLE DispatchHandle
,
687 IN CONST VOID
*Context OPTIONAL
,
688 IN OUT VOID
*CommBuffer OPTIONAL
,
689 IN OUT UINTN
*CommBufferSize OPTIONAL
693 CALLBACK_INFO
*CallbackInfo
;
697 /// Before transferring the control into the Framework SMI handler, update CPU Save States
698 /// and MP states in the Framework SMST.
701 if (!mHookInitialized
) {
702 InitHook (mFrameworkSmst
);
704 if (mPageTableHookEnabled
) {
705 HookCpuStateMemory (mFrameworkSmst
->CpuSaveState
);
708 for (CpuIndex
= 0; CpuIndex
< mNumberOfProcessors
; CpuIndex
++) {
709 ReadCpuSaveState (CpuIndex
, NULL
);
713 mFrameworkSmst
->SmmStartupThisAp
= gSmst
->SmmStartupThisAp
;
714 mFrameworkSmst
->NumberOfCpus
= mNumberOfProcessors
;
715 mFrameworkSmst
->CurrentlyExecutingCpu
= gSmst
->CurrentlyExecutingCpu
;
718 /// Search for Framework SMI handler information
720 CallbackInfo
= GetCallbackInfo (DispatchHandle
);
721 ASSERT (CallbackInfo
!= NULL
);
724 /// Thunk into original Framwork SMI handler
726 Status
= (CallbackInfo
->CallbackAddress
) (
727 CallbackInfo
->SmmImageHandle
,
728 CallbackInfo
->CommunicationBuffer
,
729 CallbackInfo
->SourceSize
732 /// Save CPU Save States in case any of them was modified
734 if (mPageTableHookEnabled
) {
735 WriteBackDirtyPages ();
737 for (CpuIndex
= 0; CpuIndex
< mNumberOfProcessors
; CpuIndex
++) {
738 WriteCpuSaveState (CpuIndex
, NULL
);
743 /// Conversion of returned status code
746 case EFI_HANDLER_SUCCESS
:
747 Status
= EFI_WARN_INTERRUPT_SOURCE_QUIESCED
;
749 case EFI_HANDLER_CRITICAL_EXIT
:
750 case EFI_HANDLER_SOURCE_QUIESCED
:
751 Status
= EFI_SUCCESS
;
753 case EFI_HANDLER_SOURCE_PENDING
:
754 Status
= EFI_WARN_INTERRUPT_SOURCE_PENDING
;
761 Thunk service of EFI_SMM_BASE_PROTOCOL.RegisterCallback().
763 @param[in, out] FunctionData Pointer to SMMBASE_FUNCTION_DATA.
767 IN OUT SMMBASE_FUNCTION_DATA
*FunctionData
770 CALLBACK_INFO
*Buffer
;
773 FunctionData
->Status
= EFI_UNSUPPORTED
;
778 /// Note that MakeLast and FloatingPointSave options are not supported in PI SMM
782 /// Allocate buffer for callback thunk information
784 Buffer
= (CALLBACK_INFO
*)AllocateZeroPool (sizeof (CALLBACK_INFO
));
785 if (Buffer
== NULL
) {
786 FunctionData
->Status
= EFI_OUT_OF_RESOURCES
;
791 /// Fill SmmImageHandle and CallbackAddress into the thunk
793 Buffer
->SmmImageHandle
= FunctionData
->Args
.RegisterCallback
.SmmImageHandle
;
794 Buffer
->CallbackAddress
= FunctionData
->Args
.RegisterCallback
.CallbackAddress
;
797 /// Register the thunk code as a root SMI handler
799 FunctionData
->Status
= gSmst
->SmiHandlerRegister (
802 &Buffer
->DispatchHandle
804 if (EFI_ERROR (FunctionData
->Status
)) {
810 /// Save this callback info
812 InsertTailList (&mCallbackInfoListHead
, &Buffer
->Link
);
817 Thunk service of EFI_SMM_BASE_PROTOCOL.SmmAllocatePool().
819 @param[in, out] FunctionData Pointer to SMMBASE_FUNCTION_DATA.
823 IN OUT SMMBASE_FUNCTION_DATA
*FunctionData
827 FunctionData
->Status
= EFI_UNSUPPORTED
;
829 FunctionData
->Status
= gSmst
->SmmAllocatePool (
830 FunctionData
->Args
.AllocatePool
.PoolType
,
831 FunctionData
->Args
.AllocatePool
.Size
,
832 FunctionData
->Args
.AllocatePool
.Buffer
838 Thunk service of EFI_SMM_BASE_PROTOCOL.SmmFreePool().
840 @param[in, out] FunctionData Pointer to SMMBASE_FUNCTION_DATA.
844 IN OUT SMMBASE_FUNCTION_DATA
*FunctionData
848 FunctionData
->Status
= EFI_UNSUPPORTED
;
850 FreePool (FunctionData
->Args
.FreePool
.Buffer
);
851 FunctionData
->Status
= EFI_SUCCESS
;
856 Thunk service of EFI_SMM_BASE_PROTOCOL.Communicate().
858 @param[in, out] FunctionData Pointer to SMMBASE_FUNCTION_DATA.
862 IN OUT SMMBASE_FUNCTION_DATA
*FunctionData
866 CALLBACK_INFO
*CallbackInfo
;
868 if (FunctionData
->Args
.Communicate
.CommunicationBuffer
== NULL
) {
869 FunctionData
->Status
= EFI_INVALID_PARAMETER
;
873 Node
= GetFirstNode (&mCallbackInfoListHead
);
874 while (!IsNull (&mCallbackInfoListHead
, Node
)) {
875 CallbackInfo
= (CALLBACK_INFO
*)Node
;
877 if (FunctionData
->Args
.Communicate
.ImageHandle
== CallbackInfo
->SmmImageHandle
) {
878 CallbackInfo
->CommunicationBuffer
= FunctionData
->Args
.Communicate
.CommunicationBuffer
;
879 CallbackInfo
->SourceSize
= FunctionData
->Args
.Communicate
.SourceSize
;
882 /// The message was successfully posted.
884 FunctionData
->Status
= EFI_SUCCESS
;
887 Node
= GetNextNode (&mCallbackInfoListHead
, Node
);
890 FunctionData
->Status
= EFI_INVALID_PARAMETER
;
894 Communication service SMI Handler entry.
896 This SMI handler provides services for the SMM Base Thunk driver.
898 @param[in] DispatchHandle The unique handle assigned to this handler by SmiHandlerRegister().
899 @param[in] RegisterContext Points to an optional handler context which was specified when the
900 handler was registered.
901 @param[in, out] CommBuffer A pointer to a collection of data in memory that will
902 be conveyed from a non-SMM environment into an SMM environment.
903 @param[in, out] CommBufferSize The size of the CommBuffer.
905 @retval EFI_SUCCESS The interrupt was handled and quiesced. No other handlers
906 should still be called.
907 @retval EFI_WARN_INTERRUPT_SOURCE_QUIESCED The interrupt has been quiesced but other handlers should
909 @retval EFI_WARN_INTERRUPT_SOURCE_PENDING The interrupt is still pending and other handlers should still
911 @retval EFI_INTERRUPT_PENDING The interrupt could not be quiesced.
916 IN EFI_HANDLE DispatchHandle
,
917 IN CONST VOID
*RegisterContext
,
918 IN OUT VOID
*CommBuffer
,
919 IN OUT UINTN
*CommBufferSize
922 SMMBASE_FUNCTION_DATA
*FunctionData
;
924 ASSERT (CommBuffer
!= NULL
);
925 ASSERT (*CommBufferSize
== sizeof (SMMBASE_FUNCTION_DATA
));
927 FunctionData
= (SMMBASE_FUNCTION_DATA
*)CommBuffer
;
929 switch (FunctionData
->Function
) {
930 case SmmBaseFunctionRegister
:
931 Register (FunctionData
);
933 case SmmBaseFunctionUnregister
:
934 UnRegister (FunctionData
);
936 case SmmBaseFunctionRegisterCallback
:
937 RegisterCallback (FunctionData
);
939 case SmmBaseFunctionAllocatePool
:
940 HelperAllocatePool (FunctionData
);
942 case SmmBaseFunctionFreePool
:
943 HelperFreePool (FunctionData
);
945 case SmmBaseFunctionCommunicate
:
946 HelperCommunicate (FunctionData
);
950 FunctionData
->Status
= EFI_UNSUPPORTED
;
956 Smm Ready To Lock event notification handler.
958 It sets a flag indicating that SMRAM has been locked.
960 @param[in] Protocol Points to the protocol's unique identifier.
961 @param[in] Interface Points to the interface instance.
962 @param[in] Handle The handle on which the interface was installed.
964 @retval EFI_SUCCESS Notification handler runs successfully.
968 SmmReadyToLockEventNotify (
969 IN CONST EFI_GUID
*Protocol
,
979 Entry point function of the SMM Base Helper SMM driver.
981 @param[in] ImageHandle The firmware allocated handle for the EFI image.
982 @param[in] SystemTable A pointer to the EFI System Table.
984 @retval EFI_SUCCESS The entry point is executed successfully.
985 @retval other Some error occurs when executing this entry point.
990 IN EFI_HANDLE ImageHandle
,
991 IN EFI_SYSTEM_TABLE
*SystemTable
995 EFI_MP_SERVICES_PROTOCOL
*MpServices
;
997 UINTN NumberOfEnabledProcessors
;
1002 /// Locate SMM CPU Protocol which is used later to retrieve/update CPU Save States
1004 Status
= gSmst
->SmmLocateProtocol (&gEfiSmmCpuProtocolGuid
, NULL
, (VOID
**) &mSmmCpu
);
1005 ASSERT_EFI_ERROR (Status
);
1008 /// Locate PE32 Image Protocol which is used later to load Framework SMM driver
1010 Status
= SystemTable
->BootServices
->LocateProtocol (&gEfiLoadPeImageProtocolGuid
, NULL
, (VOID
**) &mLoadPe32Image
);
1011 ASSERT_EFI_ERROR (Status
);
1014 // Get MP Services Protocol
1016 Status
= SystemTable
->BootServices
->LocateProtocol (&gEfiMpServiceProtocolGuid
, NULL
, (VOID
**)&MpServices
);
1017 ASSERT_EFI_ERROR (Status
);
1020 // Use MP Services Protocol to retrieve the number of processors and number of enabled processors
1022 Status
= MpServices
->GetNumberOfProcessors (MpServices
, &mNumberOfProcessors
, &NumberOfEnabledProcessors
);
1023 ASSERT_EFI_ERROR (Status
);
1026 /// Interface structure of SMM BASE Helper Ready Protocol is allocated from UEFI pool
1027 /// instead of SMM pool so that SMM Base Thunk driver can access it in Non-SMM mode.
1029 Status
= gBS
->AllocatePool (
1030 EfiBootServicesData
,
1031 sizeof (EFI_SMM_BASE_HELPER_READY_PROTOCOL
),
1032 (VOID
**)&mSmmBaseHelperReady
1034 ASSERT_EFI_ERROR (Status
);
1037 /// Construct Framework SMST from PI SMST
1039 mFrameworkSmst
= ConstructFrameworkSmst ();
1040 mSmmBaseHelperReady
->FrameworkSmst
= mFrameworkSmst
;
1041 mSmmBaseHelperReady
->ServiceEntry
= SmmHandlerEntry
;
1044 // Register SMM Ready To Lock Protocol notification
1046 Status
= gSmst
->SmmRegisterProtocolNotify (
1047 &gEfiSmmReadyToLockProtocolGuid
,
1048 SmmReadyToLockEventNotify
,
1051 ASSERT_EFI_ERROR (Status
);
1054 /// Register SMM Base Helper services for SMM Base Thunk driver
1056 Status
= gSmst
->SmiHandlerRegister (SmmHandlerEntry
, &gEfiSmmBaseThunkCommunicationGuid
, &mDispatchHandle
);
1057 ASSERT_EFI_ERROR (Status
);
1060 /// Install EFI SMM Base Helper Protocol in the UEFI handle database
1062 Status
= gBS
->InstallProtocolInterface (
1064 &gEfiSmmBaseHelperReadyProtocolGuid
,
1065 EFI_NATIVE_INTERFACE
,
1068 ASSERT_EFI_ERROR (Status
);