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 - 2011, Intel Corporation. All rights reserved.<BR>
8 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
)}
114 PageFaultHandlerHook (
119 Read CpuSaveStates from PI for Framework use.
121 The function reads PI style CpuSaveStates of CpuIndex-th CPU for Framework driver use. If
122 ToRead is specified, the CpuSaveStates will be copied to ToRead, otherwise copied to
123 mFrameworkSmst->CpuSaveState[CpuIndex].
125 @param[in] CpuIndex The zero-based CPU index.
126 @param[in, out] ToRead If not NULL, CpuSaveStates will be copied to it.
132 IN OUT EFI_SMM_CPU_SAVE_STATE
*ToRead
137 EFI_SMM_CPU_STATE
*State
;
138 EFI_SMI_CPU_SAVE_STATE
*SaveState
;
140 State
= (EFI_SMM_CPU_STATE
*)gSmst
->CpuSaveState
[CpuIndex
];
141 if (ToRead
!= NULL
) {
142 SaveState
= &ToRead
->Ia32SaveState
;
144 SaveState
= &mFrameworkSmst
->CpuSaveState
[CpuIndex
].Ia32SaveState
;
148 // Note that SMBASE/SMMRevId/IORestart/AutoHALTRestart are in same location in IA32 and X64 CPU Save State Map.
150 SaveState
->SMBASE
= State
->x86
.SMBASE
;
151 SaveState
->SMMRevId
= State
->x86
.SMMRevId
;
152 SaveState
->IORestart
= State
->x86
.IORestart
;
153 SaveState
->AutoHALTRestart
= State
->x86
.AutoHALTRestart
;
155 for (Index
= 0; Index
< sizeof (mCpuSaveStateConvTable
) / sizeof (CPU_SAVE_STATE_CONVERSION
); Index
++) {
157 /// Try to use SMM CPU Protocol to access CPU save states if possible
159 Status
= mSmmCpu
->ReadSaveState (
161 (UINTN
)sizeof (UINT32
),
162 mCpuSaveStateConvTable
[Index
].Register
,
164 ((UINT8
*)SaveState
) + mCpuSaveStateConvTable
[Index
].Offset
166 ASSERT_EFI_ERROR (Status
);
171 Write CpuSaveStates from Framework into PI.
173 The function writes back CpuSaveStates of CpuIndex-th CPU from PI to Framework. If
174 ToWrite is specified, it contains the CpuSaveStates to write from, otherwise CpuSaveStates
175 to write from mFrameworkSmst->CpuSaveState[CpuIndex].
177 @param[in] CpuIndex The zero-based CPU index.
178 @param[in] ToWrite If not NULL, CpuSaveStates to write from.
184 IN EFI_SMM_CPU_SAVE_STATE
*ToWrite
189 EFI_SMM_CPU_STATE
*State
;
190 EFI_SMI_CPU_SAVE_STATE
*SaveState
;
192 State
= (EFI_SMM_CPU_STATE
*)gSmst
->CpuSaveState
[CpuIndex
];
194 if (ToWrite
!= NULL
) {
195 SaveState
= &ToWrite
->Ia32SaveState
;
197 SaveState
= &mFrameworkSmst
->CpuSaveState
[CpuIndex
].Ia32SaveState
;
201 // SMMRevId is read-only.
202 // Note that SMBASE/IORestart/AutoHALTRestart are in same location in IA32 and X64 CPU Save State Map.
204 State
->x86
.SMBASE
= SaveState
->SMBASE
;
205 State
->x86
.IORestart
= SaveState
->IORestart
;
206 State
->x86
.AutoHALTRestart
= SaveState
->AutoHALTRestart
;
208 for (Index
= 0; Index
< sizeof (mCpuSaveStateConvTable
) / sizeof (CPU_SAVE_STATE_CONVERSION
); Index
++) {
209 Status
= mSmmCpu
->WriteSaveState (
211 (UINTN
)sizeof (UINT32
),
212 mCpuSaveStateConvTable
[Index
].Register
,
214 ((UINT8
*)SaveState
) +
215 mCpuSaveStateConvTable
[Index
].Offset
221 Read or write a page that contains CpuSaveStates. Read is from PI to Framework.
222 Write is from Framework to PI.
224 This function reads or writes a page that contains CpuSaveStates. The page contains Framework
225 CpuSaveStates. On read, it reads PI style CpuSaveStates and fill the page up. On write, it
226 writes back from the page content to PI CpuSaveStates struct.
227 The first Framework CpuSaveStates (for CPU 0) is from mFrameworkSmst->CpuSaveState which is
228 page aligned. Because Framework CpuSaveStates are continuous, we can know which CPUs' SaveStates
229 are in the page start from PageAddress.
231 @param[in] PageAddress The base address for a page.
232 @param[in] IsRead TRUE for Read, FALSE for Write.
236 ReadWriteCpuStatePage (
237 IN UINT64 PageAddress
,
241 UINTN FirstSSIndex
; // Index of first CpuSaveState in the page
242 UINTN LastSSIndex
; // Index of last CpuSaveState in the page
243 BOOLEAN FirstSSAligned
; // Whether first CpuSaveState is page-aligned
244 BOOLEAN LastSSAligned
; // Whether the end of last CpuSaveState is page-aligned
248 FirstSSIndex
= ((UINTN
)PageAddress
- (UINTN
)mFrameworkSmst
->CpuSaveState
) / sizeof (EFI_SMM_CPU_SAVE_STATE
);
249 FirstSSAligned
= TRUE
;
250 if (((UINTN
)PageAddress
- (UINTN
)mFrameworkSmst
->CpuSaveState
) % sizeof (EFI_SMM_CPU_SAVE_STATE
) != 0) {
252 FirstSSAligned
= FALSE
;
254 LastSSIndex
= ((UINTN
)PageAddress
+ SIZE_4KB
- (UINTN
)mFrameworkSmst
->CpuSaveState
- 1) / sizeof (EFI_SMM_CPU_SAVE_STATE
);
255 LastSSAligned
= TRUE
;
256 if (((UINTN
)PageAddress
+ SIZE_4KB
- (UINTN
)mFrameworkSmst
->CpuSaveState
) % sizeof (EFI_SMM_CPU_SAVE_STATE
) != 0) {
258 LastSSAligned
= FALSE
;
260 for (CpuIndex
= FirstSSIndex
; CpuIndex
<= LastSSIndex
&& CpuIndex
< mNumberOfProcessors
; CpuIndex
++) {
262 ReadCpuSaveState (CpuIndex
, NULL
);
264 WriteCpuSaveState (CpuIndex
, NULL
);
267 if (!FirstSSAligned
) {
268 ReadCpuSaveState (FirstSSIndex
- 1, mShadowSaveState
);
269 ClippedSize
= (UINTN
)&mFrameworkSmst
->CpuSaveState
[FirstSSIndex
] & (SIZE_4KB
- 1);
271 CopyMem ((VOID
*)(UINTN
)PageAddress
, (VOID
*)((UINTN
)(mShadowSaveState
+ 1) - ClippedSize
), ClippedSize
);
273 CopyMem ((VOID
*)((UINTN
)(mShadowSaveState
+ 1) - ClippedSize
), (VOID
*)(UINTN
)PageAddress
, ClippedSize
);
274 WriteCpuSaveState (FirstSSIndex
- 1, mShadowSaveState
);
277 if (!LastSSAligned
&& LastSSIndex
+ 1 < mNumberOfProcessors
) {
278 ReadCpuSaveState (LastSSIndex
+ 1, mShadowSaveState
);
279 ClippedSize
= SIZE_4KB
- ((UINTN
)&mFrameworkSmst
->CpuSaveState
[LastSSIndex
+ 1] & (SIZE_4KB
- 1));
281 CopyMem (&mFrameworkSmst
->CpuSaveState
[LastSSIndex
+ 1], mShadowSaveState
, ClippedSize
);
283 CopyMem (mShadowSaveState
, &mFrameworkSmst
->CpuSaveState
[LastSSIndex
+ 1], ClippedSize
);
284 WriteCpuSaveState (LastSSIndex
+ 1, mShadowSaveState
);
290 The page fault handler that on-demand read PI CpuSaveStates for framework use. If the fault
291 is not targeted to mFrameworkSmst->CpuSaveState range, the function will return FALSE to let
292 PageFaultHandlerHook know it needs to pass the fault over to original page fault handler.
294 @retval TRUE The page fault is correctly handled.
295 @retval FALSE The page fault is not handled and is passed through to original handler.
306 UINTN NumCpuStatePages
;
308 ASSERT (mPageTableHookEnabled
);
309 AcquireSpinLock (&mPFLock
);
311 PageTable
= (UINT64
*)(UINTN
)(AsmReadCr3 () & mPhyMask
);
312 PFAddress
= AsmReadCr2 ();
313 NumCpuStatePages
= EFI_SIZE_TO_PAGES (mNumberOfProcessors
* sizeof (EFI_SMM_CPU_SAVE_STATE
));
315 if (((UINTN
)mFrameworkSmst
->CpuSaveState
& ~(SIZE_2MB
-1)) == (PFAddress
& ~(SIZE_2MB
-1))) {
316 if ((UINTN
)mFrameworkSmst
->CpuSaveState
<= PFAddress
&&
317 PFAddress
< (UINTN
)mFrameworkSmst
->CpuSaveState
+ EFI_PAGES_TO_SIZE (NumCpuStatePages
)
319 mCpuStatePageTable
[BitFieldRead64 (PFAddress
, 12, 20)] |= BIT0
| BIT1
; // present and rw
321 ReadWriteCpuStatePage (PFAddress
& ~(SIZE_4KB
-1), TRUE
);
328 ReleaseSpinLock (&mPFLock
);
333 Write back the dirty Framework CpuSaveStates to PI.
335 The function scans the page table for dirty pages in mFrameworkSmst->CpuSaveState
336 to write back to PI CpuSaveStates. It is meant to be called on each SmmBaseHelper SMI
337 callback after Framework handler is called.
341 WriteBackDirtyPages (
345 UINTN NumCpuStatePages
;
350 NumCpuStatePages
= EFI_SIZE_TO_PAGES (mNumberOfProcessors
* sizeof (EFI_SMM_CPU_SAVE_STATE
));
351 PTStartIndex
= (UINTN
)BitFieldRead64 ((UINT64
) (UINTN
) mFrameworkSmst
->CpuSaveState
, 12, 20);
352 PTEndIndex
= (UINTN
)BitFieldRead64 ((UINT64
) (UINTN
) mFrameworkSmst
->CpuSaveState
+ EFI_PAGES_TO_SIZE(NumCpuStatePages
) - 1, 12, 20);
353 for (PTIndex
= PTStartIndex
; PTIndex
<= PTEndIndex
; PTIndex
++) {
354 if ((mCpuStatePageTable
[PTIndex
] & (BIT0
|BIT6
)) == (BIT0
|BIT6
)) { // present and dirty?
355 ReadWriteCpuStatePage (mCpuStatePageTable
[PTIndex
] & mPhyMask
, FALSE
);
361 Hook IDT with our page fault handler so that the on-demand paging works on page fault.
363 The function hooks the IDT with PageFaultHandlerHook to get on-demand paging work for
364 PI<->Framework CpuSaveStates marshalling. It also saves original handler for pass-through
369 HookPageFaultHandler (
373 IA32_DESCRIPTOR Idtr
;
374 IA32_IDT_GATE_DESCRIPTOR
*IdtGateDesc
;
377 InitializeSpinLock (&mPFLock
);
380 IdtGateDesc
= (IA32_IDT_GATE_DESCRIPTOR
*) Idtr
.Base
;
381 OffsetUpper
= *(UINT32
*)((UINT64
*)IdtGateDesc
+ 1);
382 mOriginalHandler
= (VOID
*)(UINTN
)(LShiftU64 (OffsetUpper
, 32) + IdtGateDesc
[14].Bits
.OffsetLow
+ (IdtGateDesc
[14].Bits
.OffsetHigh
<< 16));
383 IdtGateDesc
[14].Bits
.OffsetLow
= (UINT32
)((UINTN
)PageFaultHandlerHook
& ((1 << 16) - 1));
384 IdtGateDesc
[14].Bits
.OffsetHigh
= (UINT32
)(((UINTN
)PageFaultHandlerHook
>> 16) & ((1 << 16) - 1));
388 Initialize page table for pages contain HookData.
390 The function initialize PDE for 2MB range that contains HookData. If the related PDE points
391 to a 2MB page, a page table will be allocated and initialized for 4KB pages. Otherwise we juse
392 use the original page table.
394 @param[in] HookData Based on which to initialize page table.
396 @return The pointer to a Page Table that points to 4KB pages which contain HookData.
399 InitCpuStatePageTable (
411 // Initialize physical address mask
412 // NOTE: Physical memory above virtual address limit is not supported !!!
414 AsmCpuid (0x80000008, (UINT32
*)&Index
, NULL
, NULL
, NULL
);
415 mPhyMask
= LShiftU64 (1, (UINT8
)Index
) - 1;
416 mPhyMask
&= (1ull << 48) - EFI_PAGE_SIZE
;
418 HookAddress
= (UINT64
)(UINTN
)HookData
;
419 PageTable
= (UINT64
*)(UINTN
)(AsmReadCr3 () & mPhyMask
);
420 PageTable
= (UINT64
*)(UINTN
)(PageTable
[BitFieldRead64 (HookAddress
, 39, 47)] & mPhyMask
);
421 PageTable
= (UINT64
*)(UINTN
)(PageTable
[BitFieldRead64 (HookAddress
, 30, 38)] & mPhyMask
);
423 Pdpte
= (UINT64
*)(UINTN
)PageTable
;
424 Pde
= Pdpte
[BitFieldRead64 (HookAddress
, 21, 29)];
425 ASSERT ((Pde
& BIT0
) != 0); // Present and 2M Page
427 if ((Pde
& BIT7
) == 0) { // 4KB Page Directory
428 PageTable
= (UINT64
*)(UINTN
)(Pde
& mPhyMask
);
430 ASSERT ((Pde
& mPhyMask
) == (HookAddress
& ~(SIZE_2MB
-1))); // 2MB Page Point to HookAddress
431 PageTable
= AllocatePages (1);
432 ASSERT (PageTable
!= NULL
);
433 Address
= HookAddress
& ~(SIZE_2MB
-1);
434 for (Index
= 0; Index
< 512; Index
++) {
435 PageTable
[Index
] = Address
| BIT0
| BIT1
; // Present and RW
438 Pdpte
[BitFieldRead64 (HookAddress
, 21, 29)] = (UINT64
)(UINTN
)PageTable
| BIT0
| BIT1
; // Present and RW
444 Mark all the CpuSaveStates as not present.
446 The function marks all CpuSaveStates memory range as not present so that page fault can be triggered
447 on CpuSaveStates access. It is meant to be called on each SmmBaseHelper SMI callback before Framework
450 @param[in] CpuSaveState The base of CpuSaveStates.
455 IN EFI_SMM_CPU_SAVE_STATE
*CpuSaveState
462 PTStartIndex
= BitFieldRead64 ((UINTN
)CpuSaveState
, 12, 20);
463 PTEndIndex
= BitFieldRead64 ((UINTN
)CpuSaveState
+ mNumberOfProcessors
* sizeof (EFI_SMM_CPU_SAVE_STATE
) - 1, 12, 20);
464 for (Index
= PTStartIndex
; Index
<= PTEndIndex
; Index
++) {
465 mCpuStatePageTable
[Index
] &= ~(BIT0
|BIT5
|BIT6
); // not present nor accessed nor dirty
470 Framework SMST SmmInstallConfigurationTable() Thunk.
472 This thunk calls the PI SMM SmmInstallConfigurationTable() and then update the configuration
473 table related fields in the Framework SMST because the PI SMM SmmInstallConfigurationTable()
474 function may modify these fields.
476 @param[in] SystemTable A pointer to the SMM System Table.
477 @param[in] Guid A pointer to the GUID for the entry to add, update, or remove.
478 @param[in] Table A pointer to the buffer of the table to add.
479 @param[in] TableSize The size of the table to install.
481 @retval EFI_SUCCESS The (Guid, Table) pair was added, updated, or removed.
482 @retval EFI_INVALID_PARAMETER Guid is not valid.
483 @retval EFI_NOT_FOUND An attempt was made to delete a non-existent entry.
484 @retval EFI_OUT_OF_RESOURCES There is not enough memory available to complete the operation.
488 SmmInstallConfigurationTable (
489 IN EFI_SMM_SYSTEM_TABLE
*SystemTable
,
497 Status
= gSmst
->SmmInstallConfigurationTable (gSmst
, Guid
, Table
, TableSize
);
498 if (!EFI_ERROR (Status
)) {
499 mFrameworkSmst
->NumberOfTableEntries
= gSmst
->NumberOfTableEntries
;
500 mFrameworkSmst
->SmmConfigurationTable
= gSmst
->SmmConfigurationTable
;
506 Initialize all the stuff needed for on-demand paging hooks for PI<->Framework
507 CpuSaveStates marshalling.
509 @param[in] FrameworkSmst Framework SMM system table pointer.
514 IN EFI_SMM_SYSTEM_TABLE
*FrameworkSmst
517 UINTN NumCpuStatePages
;
522 mPageTableHookEnabled
= FALSE
;
523 NumCpuStatePages
= EFI_SIZE_TO_PAGES (mNumberOfProcessors
* sizeof (EFI_SMM_CPU_SAVE_STATE
));
525 // Only hook page table for X64 image and less than 2MB needed to hold all CPU Save States
527 if (EFI_IMAGE_MACHINE_TYPE_SUPPORTED(EFI_IMAGE_MACHINE_X64
) && NumCpuStatePages
<= EFI_SIZE_TO_PAGES (SIZE_2MB
)) {
529 // Allocate double page size to make sure all CPU Save States are in one 2MB page.
531 CpuStatePage
= (UINTN
)AllocatePages (NumCpuStatePages
* 2);
532 ASSERT (CpuStatePage
!= 0);
533 Bottom2MPage
= CpuStatePage
& ~(SIZE_2MB
-1);
534 Top2MPage
= (CpuStatePage
+ EFI_PAGES_TO_SIZE (NumCpuStatePages
* 2) - 1) & ~(SIZE_2MB
-1);
535 if (Bottom2MPage
== Top2MPage
||
536 CpuStatePage
+ EFI_PAGES_TO_SIZE (NumCpuStatePages
* 2) - Top2MPage
>= EFI_PAGES_TO_SIZE (NumCpuStatePages
)
539 // If the allocated 4KB pages are within the same 2MB page or higher portion is larger, use higher portion pages.
541 FrameworkSmst
->CpuSaveState
= (EFI_SMM_CPU_SAVE_STATE
*)(CpuStatePage
+ EFI_PAGES_TO_SIZE (NumCpuStatePages
));
542 FreePages ((VOID
*)CpuStatePage
, NumCpuStatePages
);
544 FrameworkSmst
->CpuSaveState
= (EFI_SMM_CPU_SAVE_STATE
*)CpuStatePage
;
545 FreePages ((VOID
*)(CpuStatePage
+ EFI_PAGES_TO_SIZE (NumCpuStatePages
)), NumCpuStatePages
);
548 // Add temporary working buffer for hooking
550 mShadowSaveState
= (EFI_SMM_CPU_SAVE_STATE
*) AllocatePool (sizeof (EFI_SMM_CPU_SAVE_STATE
));
551 ASSERT (mShadowSaveState
!= NULL
);
553 // Allocate and initialize 4KB Page Table for hooking CpuSaveState.
554 // Replace the original 2MB PDE with new 4KB page table.
556 mCpuStatePageTable
= InitCpuStatePageTable (FrameworkSmst
->CpuSaveState
);
558 // Mark PTE for CpuSaveState as non-exist.
560 HookCpuStateMemory (FrameworkSmst
->CpuSaveState
);
561 HookPageFaultHandler ();
563 mPageTableHookEnabled
= TRUE
;
565 mHookInitialized
= TRUE
;
569 Construct a Framework SMST based on the PI SMM SMST.
571 @return Pointer to the constructed Framework SMST.
573 EFI_SMM_SYSTEM_TABLE
*
574 ConstructFrameworkSmst (
578 EFI_SMM_SYSTEM_TABLE
*FrameworkSmst
;
580 FrameworkSmst
= (EFI_SMM_SYSTEM_TABLE
*)AllocatePool (sizeof (EFI_SMM_SYSTEM_TABLE
));
581 ASSERT (FrameworkSmst
!= NULL
);
584 /// Copy same things from PI SMST to Framework SMST
586 CopyMem (FrameworkSmst
, gSmst
, (UINTN
)(&((EFI_SMM_SYSTEM_TABLE
*)0)->SmmIo
));
588 &FrameworkSmst
->SmmIo
,
590 sizeof (EFI_SMM_SYSTEM_TABLE
) - (UINTN
)(&((EFI_SMM_SYSTEM_TABLE
*)0)->SmmIo
)
594 /// Update Framework SMST
596 FrameworkSmst
->Hdr
.Revision
= EFI_SMM_SYSTEM_TABLE_REVISION
;
597 CopyGuid (&FrameworkSmst
->EfiSmmCpuIoGuid
, &mEfiSmmCpuIoGuid
);
599 mHookInitialized
= FALSE
;
600 FrameworkSmst
->CpuSaveState
= (EFI_SMM_CPU_SAVE_STATE
*)AllocateZeroPool (mNumberOfProcessors
* sizeof (EFI_SMM_CPU_SAVE_STATE
));
601 ASSERT (FrameworkSmst
->CpuSaveState
!= NULL
);
604 /// Do not support floating point state now
606 FrameworkSmst
->CpuOptionalFloatingPointState
= NULL
;
608 FrameworkSmst
->SmmInstallConfigurationTable
= SmmInstallConfigurationTable
;
610 return FrameworkSmst
;
614 Load a given Framework SMM driver into SMRAM and invoke its entry point.
616 @param[in] ParentImageHandle Parent Image Handle.
617 @param[in] FilePath Location of the image to be installed as the handler.
618 @param[in] SourceBuffer Optional source buffer in case the image file
620 @param[in] SourceSize Size of the source image file, if in memory.
621 @param[out] ImageHandle The handle that the base driver uses to decode
622 the handler. Unique among SMM handlers only,
623 not unique across DXE/EFI.
625 @retval EFI_SUCCESS The operation was successful.
626 @retval EFI_OUT_OF_RESOURCES There were no additional SMRAM resources to load the handler
627 @retval EFI_UNSUPPORTED Can not find its copy in normal memory.
628 @retval EFI_INVALID_PARAMETER The handlers was not the correct image type
632 IN EFI_HANDLE ParentImageHandle
,
633 IN EFI_DEVICE_PATH_PROTOCOL
*FilePath
,
634 IN VOID
*SourceBuffer
,
636 OUT EFI_HANDLE
*ImageHandle
642 EFI_PHYSICAL_ADDRESS DstBuffer
;
644 if (FilePath
== NULL
|| ImageHandle
== NULL
) {
645 return EFI_INVALID_PARAMETER
;
650 OrgPageCount
= PageCount
;
651 DstBuffer
= (UINTN
)-1;
652 Status
= gSmst
->SmmAllocatePages (
654 EfiRuntimeServicesCode
,
658 if (EFI_ERROR (Status
)) {
662 Status
= mLoadPe32Image
->LoadPeImage (
672 EFI_LOAD_PE_IMAGE_ATTRIBUTE_NONE
674 if (EFI_ERROR (Status
)) {
675 FreePages ((VOID
*)(UINTN
)DstBuffer
, OrgPageCount
);
677 } while (Status
== EFI_BUFFER_TOO_SMALL
);
679 if (!EFI_ERROR (Status
)) {
681 /// Update MP state in Framework SMST before transferring control to Framework SMM driver entry point
683 mFrameworkSmst
->SmmStartupThisAp
= gSmst
->SmmStartupThisAp
;
684 mFrameworkSmst
->NumberOfCpus
= mNumberOfProcessors
;
685 mFrameworkSmst
->CurrentlyExecutingCpu
= gSmst
->CurrentlyExecutingCpu
;
687 Status
= gBS
->StartImage (*ImageHandle
, NULL
, NULL
);
688 if (EFI_ERROR (Status
)) {
689 mLoadPe32Image
->UnLoadPeImage (mLoadPe32Image
, *ImageHandle
);
691 FreePages ((VOID
*)(UINTN
)DstBuffer
, PageCount
);
700 Thunk service of EFI_SMM_BASE_PROTOCOL.Register().
702 @param[in, out] FunctionData Pointer to SMMBASE_FUNCTION_DATA.
706 IN OUT SMMBASE_FUNCTION_DATA
*FunctionData
711 if (mLocked
|| FunctionData
->Args
.Register
.LegacyIA32Binary
) {
712 Status
= EFI_UNSUPPORTED
;
715 FunctionData
->SmmBaseImageHandle
,
716 FunctionData
->Args
.Register
.FilePath
,
717 FunctionData
->Args
.Register
.SourceBuffer
,
718 FunctionData
->Args
.Register
.SourceSize
,
719 FunctionData
->Args
.Register
.ImageHandle
722 FunctionData
->Status
= Status
;
726 Thunk service of EFI_SMM_BASE_PROTOCOL.UnRegister().
728 @param[in, out] FunctionData Pointer to SMMBASE_FUNCTION_DATA.
732 IN OUT SMMBASE_FUNCTION_DATA
*FunctionData
736 /// Unregister not supported now
738 FunctionData
->Status
= EFI_UNSUPPORTED
;
742 Search for Framework SMI handler information according to specific PI SMM dispatch handle.
744 @param[in] DispatchHandle The unique handle assigned by SmiHandlerRegister().
746 @return Pointer to CALLBACK_INFO. If NULL, no callback info record is found.
750 IN EFI_HANDLE DispatchHandle
755 Node
= GetFirstNode (&mCallbackInfoListHead
);
756 while (!IsNull (&mCallbackInfoListHead
, Node
)) {
757 if (((CALLBACK_INFO
*)Node
)->DispatchHandle
== DispatchHandle
) {
758 return (CALLBACK_INFO
*)Node
;
760 Node
= GetNextNode (&mCallbackInfoListHead
, Node
);
766 Callback thunk for Framework SMI handler.
768 This thunk functions calls the Framework SMI handler and converts the return value
769 defined from Framework SMI handlers to a correpsonding return value defined by PI SMM.
771 @param[in] DispatchHandle The unique handle assigned to this handler by SmiHandlerRegister().
772 @param[in] Context Points to an optional handler context which was specified when the
773 handler was registered.
774 @param[in, out] CommBuffer A pointer to a collection of data in memory that will
775 be conveyed from a non-SMM environment into an SMM environment.
776 @param[in, out] CommBufferSize The size of the CommBuffer.
778 @retval EFI_SUCCESS The interrupt was handled and quiesced. No other handlers
779 should still be called.
780 @retval EFI_WARN_INTERRUPT_SOURCE_QUIESCED The interrupt has been quiesced but other handlers should
782 @retval EFI_WARN_INTERRUPT_SOURCE_PENDING The interrupt is still pending and other handlers should still
784 @retval EFI_INTERRUPT_PENDING The interrupt could not be quiesced.
789 IN EFI_HANDLE DispatchHandle
,
790 IN CONST VOID
*Context OPTIONAL
,
791 IN OUT VOID
*CommBuffer OPTIONAL
,
792 IN OUT UINTN
*CommBufferSize OPTIONAL
796 CALLBACK_INFO
*CallbackInfo
;
800 /// Before transferring the control into the Framework SMI handler, update CPU Save States
801 /// and MP states in the Framework SMST.
804 if (!mHookInitialized
) {
805 InitHook (mFrameworkSmst
);
807 if (mPageTableHookEnabled
) {
808 HookCpuStateMemory (mFrameworkSmst
->CpuSaveState
);
811 for (CpuIndex
= 0; CpuIndex
< mNumberOfProcessors
; CpuIndex
++) {
812 ReadCpuSaveState (CpuIndex
, NULL
);
816 mFrameworkSmst
->SmmStartupThisAp
= gSmst
->SmmStartupThisAp
;
817 mFrameworkSmst
->NumberOfCpus
= mNumberOfProcessors
;
818 mFrameworkSmst
->CurrentlyExecutingCpu
= gSmst
->CurrentlyExecutingCpu
;
821 /// Search for Framework SMI handler information
823 CallbackInfo
= GetCallbackInfo (DispatchHandle
);
824 ASSERT (CallbackInfo
!= NULL
);
827 /// Thunk into original Framwork SMI handler
829 Status
= (CallbackInfo
->CallbackAddress
) (
830 CallbackInfo
->SmmImageHandle
,
831 CallbackInfo
->CommunicationBuffer
,
832 CallbackInfo
->SourceSize
835 /// Save CPU Save States in case any of them was modified
837 if (mPageTableHookEnabled
) {
838 WriteBackDirtyPages ();
840 for (CpuIndex
= 0; CpuIndex
< mNumberOfProcessors
; CpuIndex
++) {
841 WriteCpuSaveState (CpuIndex
, NULL
);
846 /// Conversion of returned status code
849 case EFI_HANDLER_SUCCESS
:
850 Status
= EFI_WARN_INTERRUPT_SOURCE_QUIESCED
;
852 case EFI_HANDLER_CRITICAL_EXIT
:
853 case EFI_HANDLER_SOURCE_QUIESCED
:
854 Status
= EFI_SUCCESS
;
856 case EFI_HANDLER_SOURCE_PENDING
:
857 Status
= EFI_WARN_INTERRUPT_SOURCE_PENDING
;
864 Thunk service of EFI_SMM_BASE_PROTOCOL.RegisterCallback().
866 @param[in, out] FunctionData Pointer to SMMBASE_FUNCTION_DATA.
870 IN OUT SMMBASE_FUNCTION_DATA
*FunctionData
873 CALLBACK_INFO
*Buffer
;
876 FunctionData
->Status
= EFI_UNSUPPORTED
;
881 /// Note that MakeLast and FloatingPointSave options are not supported in PI SMM
885 /// Allocate buffer for callback thunk information
887 Buffer
= (CALLBACK_INFO
*)AllocateZeroPool (sizeof (CALLBACK_INFO
));
888 if (Buffer
== NULL
) {
889 FunctionData
->Status
= EFI_OUT_OF_RESOURCES
;
894 /// Fill SmmImageHandle and CallbackAddress into the thunk
896 Buffer
->SmmImageHandle
= FunctionData
->Args
.RegisterCallback
.SmmImageHandle
;
897 Buffer
->CallbackAddress
= FunctionData
->Args
.RegisterCallback
.CallbackAddress
;
900 /// Register the thunk code as a root SMI handler
902 FunctionData
->Status
= gSmst
->SmiHandlerRegister (
905 &Buffer
->DispatchHandle
907 if (EFI_ERROR (FunctionData
->Status
)) {
913 /// Save this callback info
915 InsertTailList (&mCallbackInfoListHead
, &Buffer
->Link
);
920 Thunk service of EFI_SMM_BASE_PROTOCOL.SmmAllocatePool().
922 @param[in, out] FunctionData Pointer to SMMBASE_FUNCTION_DATA.
926 IN OUT SMMBASE_FUNCTION_DATA
*FunctionData
930 FunctionData
->Status
= EFI_UNSUPPORTED
;
932 FunctionData
->Status
= gSmst
->SmmAllocatePool (
933 FunctionData
->Args
.AllocatePool
.PoolType
,
934 FunctionData
->Args
.AllocatePool
.Size
,
935 FunctionData
->Args
.AllocatePool
.Buffer
941 Thunk service of EFI_SMM_BASE_PROTOCOL.SmmFreePool().
943 @param[in, out] FunctionData Pointer to SMMBASE_FUNCTION_DATA.
947 IN OUT SMMBASE_FUNCTION_DATA
*FunctionData
951 FunctionData
->Status
= EFI_UNSUPPORTED
;
953 FreePool (FunctionData
->Args
.FreePool
.Buffer
);
954 FunctionData
->Status
= EFI_SUCCESS
;
959 Thunk service of EFI_SMM_BASE_PROTOCOL.Communicate().
961 @param[in, out] FunctionData Pointer to SMMBASE_FUNCTION_DATA.
965 IN OUT SMMBASE_FUNCTION_DATA
*FunctionData
969 CALLBACK_INFO
*CallbackInfo
;
971 if (FunctionData
->Args
.Communicate
.CommunicationBuffer
== NULL
) {
972 FunctionData
->Status
= EFI_INVALID_PARAMETER
;
976 Node
= GetFirstNode (&mCallbackInfoListHead
);
977 while (!IsNull (&mCallbackInfoListHead
, Node
)) {
978 CallbackInfo
= (CALLBACK_INFO
*)Node
;
980 if (FunctionData
->Args
.Communicate
.ImageHandle
== CallbackInfo
->SmmImageHandle
) {
981 CallbackInfo
->CommunicationBuffer
= FunctionData
->Args
.Communicate
.CommunicationBuffer
;
982 CallbackInfo
->SourceSize
= FunctionData
->Args
.Communicate
.SourceSize
;
985 /// The message was successfully posted.
987 FunctionData
->Status
= EFI_SUCCESS
;
990 Node
= GetNextNode (&mCallbackInfoListHead
, Node
);
993 FunctionData
->Status
= EFI_INVALID_PARAMETER
;
997 Communication service SMI Handler entry.
999 This SMI handler provides services for the SMM Base Thunk driver.
1001 @param[in] DispatchHandle The unique handle assigned to this handler by SmiHandlerRegister().
1002 @param[in] RegisterContext Points to an optional handler context which was specified when the
1003 handler was registered.
1004 @param[in, out] CommBuffer A pointer to a collection of data in memory that will
1005 be conveyed from a non-SMM environment into an SMM environment.
1006 @param[in, out] CommBufferSize The size of the CommBuffer.
1008 @retval EFI_SUCCESS The interrupt was handled and quiesced. No other handlers
1009 should still be called.
1010 @retval EFI_WARN_INTERRUPT_SOURCE_QUIESCED The interrupt has been quiesced but other handlers should
1012 @retval EFI_WARN_INTERRUPT_SOURCE_PENDING The interrupt is still pending and other handlers should still
1014 @retval EFI_INTERRUPT_PENDING The interrupt could not be quiesced.
1019 IN EFI_HANDLE DispatchHandle
,
1020 IN CONST VOID
*RegisterContext
,
1021 IN OUT VOID
*CommBuffer
,
1022 IN OUT UINTN
*CommBufferSize
1025 SMMBASE_FUNCTION_DATA
*FunctionData
;
1027 ASSERT (CommBuffer
!= NULL
);
1028 ASSERT (*CommBufferSize
== sizeof (SMMBASE_FUNCTION_DATA
));
1030 FunctionData
= (SMMBASE_FUNCTION_DATA
*)CommBuffer
;
1032 switch (FunctionData
->Function
) {
1033 case SmmBaseFunctionRegister
:
1034 Register (FunctionData
);
1036 case SmmBaseFunctionUnregister
:
1037 UnRegister (FunctionData
);
1039 case SmmBaseFunctionRegisterCallback
:
1040 RegisterCallback (FunctionData
);
1042 case SmmBaseFunctionAllocatePool
:
1043 HelperAllocatePool (FunctionData
);
1045 case SmmBaseFunctionFreePool
:
1046 HelperFreePool (FunctionData
);
1048 case SmmBaseFunctionCommunicate
:
1049 HelperCommunicate (FunctionData
);
1053 FunctionData
->Status
= EFI_UNSUPPORTED
;
1059 Smm Ready To Lock event notification handler.
1061 It sets a flag indicating that SMRAM has been locked.
1063 @param[in] Protocol Points to the protocol's unique identifier.
1064 @param[in] Interface Points to the interface instance.
1065 @param[in] Handle The handle on which the interface was installed.
1067 @retval EFI_SUCCESS Notification handler runs successfully.
1071 SmmReadyToLockEventNotify (
1072 IN CONST EFI_GUID
*Protocol
,
1074 IN EFI_HANDLE Handle
1082 Entry point function of the SMM Base Helper SMM driver.
1084 @param[in] ImageHandle The firmware allocated handle for the EFI image.
1085 @param[in] SystemTable A pointer to the EFI System Table.
1087 @retval EFI_SUCCESS The entry point is executed successfully.
1088 @retval other Some error occurs when executing this entry point.
1093 IN EFI_HANDLE ImageHandle
,
1094 IN EFI_SYSTEM_TABLE
*SystemTable
1098 EFI_MP_SERVICES_PROTOCOL
*MpServices
;
1100 UINTN NumberOfEnabledProcessors
;
1105 /// Locate SMM CPU Protocol which is used later to retrieve/update CPU Save States
1107 Status
= gSmst
->SmmLocateProtocol (&gEfiSmmCpuProtocolGuid
, NULL
, (VOID
**) &mSmmCpu
);
1108 ASSERT_EFI_ERROR (Status
);
1111 /// Locate PE32 Image Protocol which is used later to load Framework SMM driver
1113 Status
= SystemTable
->BootServices
->LocateProtocol (&gEfiLoadPeImageProtocolGuid
, NULL
, (VOID
**) &mLoadPe32Image
);
1114 ASSERT_EFI_ERROR (Status
);
1117 // Get MP Services Protocol
1119 Status
= SystemTable
->BootServices
->LocateProtocol (&gEfiMpServiceProtocolGuid
, NULL
, (VOID
**)&MpServices
);
1120 ASSERT_EFI_ERROR (Status
);
1123 // Use MP Services Protocol to retrieve the number of processors and number of enabled processors
1125 Status
= MpServices
->GetNumberOfProcessors (MpServices
, &mNumberOfProcessors
, &NumberOfEnabledProcessors
);
1126 ASSERT_EFI_ERROR (Status
);
1129 /// Interface structure of SMM BASE Helper Ready Protocol is allocated from UEFI pool
1130 /// instead of SMM pool so that SMM Base Thunk driver can access it in Non-SMM mode.
1132 Status
= gBS
->AllocatePool (
1133 EfiBootServicesData
,
1134 sizeof (EFI_SMM_BASE_HELPER_READY_PROTOCOL
),
1135 (VOID
**)&mSmmBaseHelperReady
1137 ASSERT_EFI_ERROR (Status
);
1140 /// Construct Framework SMST from PI SMST
1142 mFrameworkSmst
= ConstructFrameworkSmst ();
1143 mSmmBaseHelperReady
->FrameworkSmst
= mFrameworkSmst
;
1144 mSmmBaseHelperReady
->ServiceEntry
= SmmHandlerEntry
;
1147 // Register SMM Ready To Lock Protocol notification
1149 Status
= gSmst
->SmmRegisterProtocolNotify (
1150 &gEfiSmmReadyToLockProtocolGuid
,
1151 SmmReadyToLockEventNotify
,
1154 ASSERT_EFI_ERROR (Status
);
1157 /// Register SMM Base Helper services for SMM Base Thunk driver
1159 Status
= gSmst
->SmiHandlerRegister (SmmHandlerEntry
, &gEfiSmmBaseThunkCommunicationGuid
, &mDispatchHandle
);
1160 ASSERT_EFI_ERROR (Status
);
1163 /// Install EFI SMM Base Helper Protocol in the UEFI handle database
1165 Status
= gBS
->InstallProtocolInterface (
1167 &gEfiSmmBaseHelperReadyProtocolGuid
,
1168 EFI_NATIVE_INTERFACE
,
1171 ASSERT_EFI_ERROR (Status
);