]> git.proxmox.com Git - mirror_edk2.git/blob - EdkCompatibilityPkg/Compatibility/SmmBaseHelper/SmmBaseHelper.c
Update the copyright notice format
[mirror_edk2.git] / EdkCompatibilityPkg / Compatibility / SmmBaseHelper / SmmBaseHelper.c
1 /** @file
2 SMM Base Helper SMM driver.
3
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.
6
7 Copyright (c) 2009 - 2010, 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
12
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.
15
16 **/
17
18 #include <PiSmm.h>
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>
38
39 ///
40 /// Structure for tracking paired information of registered Framework SMI handler
41 /// and correpsonding dispatch handle for SMI handler thunk.
42 ///
43 typedef struct {
44 LIST_ENTRY Link;
45 EFI_HANDLE DispatchHandle;
46 EFI_HANDLE SmmImageHandle;
47 EFI_SMM_CALLBACK_ENTRY_POINT CallbackAddress;
48 VOID *CommunicationBuffer;
49 UINTN *SourceSize;
50 } CALLBACK_INFO;
51
52 typedef struct {
53 ///
54 /// PI SMM CPU Save State register index
55 ///
56 EFI_SMM_SAVE_STATE_REGISTER Register;
57 ///
58 /// Offset in Framework SMST
59 ///
60 UINTN Offset;
61 } CPU_SAVE_STATE_CONVERSION;
62
63 #define CPU_SAVE_STATE_GET_OFFSET(Field) (UINTN)(&(((EFI_SMM_CPU_SAVE_STATE *) 0)->Ia32SaveState.Field))
64
65
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;
77 SPIN_LOCK mPFLock;
78 UINT64 mPhyMask;
79 VOID *mOriginalHandler;
80 EFI_SMM_CPU_SAVE_STATE *mShadowSaveState;
81
82 LIST_ENTRY mCallbackInfoListHead = INITIALIZE_LIST_HEAD_VARIABLE (mCallbackInfoListHead);
83
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)}
107 };
108
109 /**
110 Page fault handler.
111
112 **/
113 VOID
114 PageFaultHandlerHook (
115 VOID
116 );
117
118 /**
119 Read CpuSaveStates from PI for Framework use.
120
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].
124
125 @param[in] CpuIndex The zero-based CPU index.
126 @param[in, out] ToRead If not NULL, CpuSaveStates will be copied to it.
127
128 **/
129 VOID
130 ReadCpuSaveState (
131 IN UINTN CpuIndex,
132 IN OUT EFI_SMM_CPU_SAVE_STATE *ToRead
133 )
134 {
135 EFI_STATUS Status;
136 UINTN Index;
137 EFI_SMM_CPU_STATE *State;
138 EFI_SMI_CPU_SAVE_STATE *SaveState;
139
140 State = (EFI_SMM_CPU_STATE *)gSmst->CpuSaveState[CpuIndex];
141 if (ToRead != NULL) {
142 SaveState = &ToRead->Ia32SaveState;
143 } else {
144 SaveState = &mFrameworkSmst->CpuSaveState[CpuIndex].Ia32SaveState;
145 }
146
147 if (State->x86.SMMRevId < EFI_SMM_MIN_REV_ID_x64) {
148 SaveState->SMBASE = State->x86.SMBASE;
149 SaveState->SMMRevId = State->x86.SMMRevId;
150 SaveState->IORestart = State->x86.IORestart;
151 SaveState->AutoHALTRestart = State->x86.AutoHALTRestart;
152 } else {
153 SaveState->SMBASE = State->x64.SMBASE;
154 SaveState->SMMRevId = State->x64.SMMRevId;
155 SaveState->IORestart = State->x64.IORestart;
156 SaveState->AutoHALTRestart = State->x64.AutoHALTRestart;
157 }
158
159 for (Index = 0; Index < sizeof (mCpuSaveStateConvTable) / sizeof (CPU_SAVE_STATE_CONVERSION); Index++) {
160 ///
161 /// Try to use SMM CPU Protocol to access CPU save states if possible
162 ///
163 Status = mSmmCpu->ReadSaveState (
164 mSmmCpu,
165 (UINTN)sizeof (UINT32),
166 mCpuSaveStateConvTable[Index].Register,
167 CpuIndex,
168 ((UINT8 *)SaveState) + mCpuSaveStateConvTable[Index].Offset
169 );
170 ASSERT_EFI_ERROR (Status);
171 }
172 }
173
174 /**
175 Write CpuSaveStates from Framework into PI.
176
177 The function writes back CpuSaveStates of CpuIndex-th CPU from PI to Framework. If
178 ToWrite is specified, it contains the CpuSaveStates to write from, otherwise CpuSaveStates
179 to write from mFrameworkSmst->CpuSaveState[CpuIndex].
180
181 @param[in] CpuIndex The zero-based CPU index.
182 @param[in] ToWrite If not NULL, CpuSaveStates to write from.
183
184 **/
185 VOID
186 WriteCpuSaveState (
187 IN UINTN CpuIndex,
188 IN EFI_SMM_CPU_SAVE_STATE *ToWrite
189 )
190 {
191 EFI_STATUS Status;
192 UINTN Index;
193 EFI_SMI_CPU_SAVE_STATE *SaveState;
194
195 if (ToWrite != NULL) {
196 SaveState = &ToWrite->Ia32SaveState;
197 } else {
198 SaveState = &mFrameworkSmst->CpuSaveState[CpuIndex].Ia32SaveState;
199 }
200
201 for (Index = 0; Index < sizeof (mCpuSaveStateConvTable) / sizeof (CPU_SAVE_STATE_CONVERSION); Index++) {
202 Status = mSmmCpu->WriteSaveState (
203 mSmmCpu,
204 (UINTN)sizeof (UINT32),
205 mCpuSaveStateConvTable[Index].Register,
206 CpuIndex,
207 ((UINT8 *)SaveState) +
208 mCpuSaveStateConvTable[Index].Offset
209 );
210 }
211 }
212
213 /**
214 Read or write a page that contains CpuSaveStates. Read is from PI to Framework.
215 Write is from Framework to PI.
216
217 This function reads or writes a page that contains CpuSaveStates. The page contains Framework
218 CpuSaveStates. On read, it reads PI style CpuSaveStates and fill the page up. On write, it
219 writes back from the page content to PI CpuSaveStates struct.
220 The first Framework CpuSaveStates (for CPU 0) is from mFrameworkSmst->CpuSaveState which is
221 page aligned. Because Framework CpuSaveStates are continuous, we can know which CPUs' SaveStates
222 are in the page start from PageAddress.
223
224 @param[in] PageAddress The base address for a page.
225 @param[in] IsRead TRUE for Read, FALSE for Write.
226
227 **/
228 VOID
229 ReadWriteCpuStatePage (
230 IN UINT64 PageAddress,
231 IN BOOLEAN IsRead
232 )
233 {
234 UINTN FirstSSIndex; // Index of first CpuSaveState in the page
235 UINTN LastSSIndex; // Index of last CpuSaveState in the page
236 BOOLEAN FirstSSAligned; // Whether first CpuSaveState is page-aligned
237 BOOLEAN LastSSAligned; // Whether the end of last CpuSaveState is page-aligned
238 UINTN ClippedSize;
239 UINTN CpuIndex;
240
241 FirstSSIndex = ((UINTN)PageAddress - (UINTN)mFrameworkSmst->CpuSaveState) / sizeof (EFI_SMM_CPU_SAVE_STATE);
242 FirstSSAligned = TRUE;
243 if (((UINTN)PageAddress - (UINTN)mFrameworkSmst->CpuSaveState) % sizeof (EFI_SMM_CPU_SAVE_STATE) != 0) {
244 FirstSSIndex++;
245 FirstSSAligned = FALSE;
246 }
247 LastSSIndex = ((UINTN)PageAddress + SIZE_4KB - (UINTN)mFrameworkSmst->CpuSaveState - 1) / sizeof (EFI_SMM_CPU_SAVE_STATE);
248 LastSSAligned = TRUE;
249 if (((UINTN)PageAddress + SIZE_4KB - (UINTN)mFrameworkSmst->CpuSaveState) % sizeof (EFI_SMM_CPU_SAVE_STATE) != 0) {
250 LastSSIndex--;
251 LastSSAligned = FALSE;
252 }
253 for (CpuIndex = FirstSSIndex; CpuIndex <= LastSSIndex && CpuIndex < mNumberOfProcessors; CpuIndex++) {
254 if (IsRead) {
255 ReadCpuSaveState (CpuIndex, NULL);
256 } else {
257 WriteCpuSaveState (CpuIndex, NULL);
258 }
259 }
260 if (!FirstSSAligned) {
261 ReadCpuSaveState (FirstSSIndex - 1, mShadowSaveState);
262 ClippedSize = (UINTN)&mFrameworkSmst->CpuSaveState[FirstSSIndex] & (SIZE_4KB - 1);
263 if (IsRead) {
264 CopyMem ((VOID*)(UINTN)PageAddress, (VOID*)((UINTN)(mShadowSaveState + 1) - ClippedSize), ClippedSize);
265 } else {
266 CopyMem ((VOID*)((UINTN)(mShadowSaveState + 1) - ClippedSize), (VOID*)(UINTN)PageAddress, ClippedSize);
267 WriteCpuSaveState (FirstSSIndex - 1, mShadowSaveState);
268 }
269 }
270 if (!LastSSAligned && LastSSIndex + 1 < mNumberOfProcessors) {
271 ReadCpuSaveState (LastSSIndex + 1, mShadowSaveState);
272 ClippedSize = SIZE_4KB - ((UINTN)&mFrameworkSmst->CpuSaveState[LastSSIndex + 1] & (SIZE_4KB - 1));
273 if (IsRead) {
274 CopyMem (&mFrameworkSmst->CpuSaveState[LastSSIndex + 1], mShadowSaveState, ClippedSize);
275 } else {
276 CopyMem (mShadowSaveState, &mFrameworkSmst->CpuSaveState[LastSSIndex + 1], ClippedSize);
277 WriteCpuSaveState (LastSSIndex + 1, mShadowSaveState);
278 }
279 }
280 }
281
282 /**
283 The page fault handler that on-demand read PI CpuSaveStates for framework use. If the fault
284 is not targeted to mFrameworkSmst->CpuSaveState range, the function will return FALSE to let
285 PageFaultHandlerHook know it needs to pass the fault over to original page fault handler.
286
287 @retval TRUE The page fault is correctly handled.
288 @retval FALSE The page fault is not handled and is passed through to original handler.
289
290 **/
291 BOOLEAN
292 PageFaultHandler (
293 VOID
294 )
295 {
296 BOOLEAN IsHandled;
297 UINT64 *PageTable;
298 UINT64 PFAddress;
299 UINTN NumCpuStatePages;
300
301 ASSERT (mPageTableHookEnabled);
302 AcquireSpinLock (&mPFLock);
303
304 PageTable = (UINT64*)(UINTN)(AsmReadCr3 () & mPhyMask);
305 PFAddress = AsmReadCr2 ();
306 NumCpuStatePages = EFI_SIZE_TO_PAGES (mNumberOfProcessors * sizeof (EFI_SMM_CPU_SAVE_STATE));
307 IsHandled = FALSE;
308 if (((UINTN)mFrameworkSmst->CpuSaveState & ~(SIZE_2MB-1)) == (PFAddress & ~(SIZE_2MB-1))) {
309 if ((UINTN)mFrameworkSmst->CpuSaveState <= PFAddress &&
310 PFAddress < (UINTN)mFrameworkSmst->CpuSaveState + EFI_PAGES_TO_SIZE (NumCpuStatePages)
311 ) {
312 mCpuStatePageTable[BitFieldRead64 (PFAddress, 12, 20)] |= BIT0 | BIT1; // present and rw
313 CpuFlushTlb ();
314 ReadWriteCpuStatePage (PFAddress & ~(SIZE_4KB-1), TRUE);
315 IsHandled = TRUE;
316 } else {
317 ASSERT (FALSE);
318 }
319 }
320
321 ReleaseSpinLock (&mPFLock);
322 return IsHandled;
323 }
324
325 /**
326 Write back the dirty Framework CpuSaveStates to PI.
327
328 The function scans the page table for dirty pages in mFrameworkSmst->CpuSaveState
329 to write back to PI CpuSaveStates. It is meant to be called on each SmmBaseHelper SMI
330 callback after Framework handler is called.
331
332 **/
333 VOID
334 WriteBackDirtyPages (
335 VOID
336 )
337 {
338 UINTN NumCpuStatePages;
339 UINTN PTIndex;
340 UINTN PTStartIndex;
341 UINTN PTEndIndex;
342
343 NumCpuStatePages = EFI_SIZE_TO_PAGES (mNumberOfProcessors * sizeof (EFI_SMM_CPU_SAVE_STATE));
344 PTStartIndex = (UINTN)BitFieldRead64 ((UINT64) (UINTN) mFrameworkSmst->CpuSaveState, 12, 20);
345 PTEndIndex = (UINTN)BitFieldRead64 ((UINT64) (UINTN) mFrameworkSmst->CpuSaveState + EFI_PAGES_TO_SIZE(NumCpuStatePages) - 1, 12, 20);
346 for (PTIndex = PTStartIndex; PTIndex <= PTEndIndex; PTIndex++) {
347 if ((mCpuStatePageTable[PTIndex] & (BIT0|BIT6)) == (BIT0|BIT6)) { // present and dirty?
348 ReadWriteCpuStatePage (mCpuStatePageTable[PTIndex] & mPhyMask, FALSE);
349 }
350 }
351 }
352
353 /**
354 Hook IDT with our page fault handler so that the on-demand paging works on page fault.
355
356 The function hooks the IDT with PageFaultHandlerHook to get on-demand paging work for
357 PI<->Framework CpuSaveStates marshalling. It also saves original handler for pass-through
358 purpose.
359
360 **/
361 VOID
362 HookPageFaultHandler (
363 VOID
364 )
365 {
366 IA32_DESCRIPTOR Idtr;
367 IA32_IDT_GATE_DESCRIPTOR *IdtGateDesc;
368 UINT32 OffsetUpper;
369
370 InitializeSpinLock (&mPFLock);
371
372 AsmReadIdtr (&Idtr);
373 IdtGateDesc = (IA32_IDT_GATE_DESCRIPTOR *) Idtr.Base;
374 OffsetUpper = *(UINT32*)((UINT64*)IdtGateDesc + 1);
375 mOriginalHandler = (VOID *)(UINTN)(LShiftU64 (OffsetUpper, 32) + IdtGateDesc[14].Bits.OffsetLow + (IdtGateDesc[14].Bits.OffsetHigh << 16));
376 IdtGateDesc[14].Bits.OffsetLow = (UINT32)((UINTN)PageFaultHandlerHook & ((1 << 16) - 1));
377 IdtGateDesc[14].Bits.OffsetHigh = (UINT32)(((UINTN)PageFaultHandlerHook >> 16) & ((1 << 16) - 1));
378 }
379
380 /**
381 Initialize page table for pages contain HookData.
382
383 The function initialize PDE for 2MB range that contains HookData. If the related PDE points
384 to a 2MB page, a page table will be allocated and initialized for 4KB pages. Otherwise we juse
385 use the original page table.
386
387 @param[in] HookData Based on which to initialize page table.
388
389 @return The pointer to a Page Table that points to 4KB pages which contain HookData.
390 **/
391 UINT64 *
392 InitCpuStatePageTable (
393 IN VOID *HookData
394 )
395 {
396 UINTN Index;
397 UINT64 *PageTable;
398 UINT64 *Pdpte;
399 UINT64 HookAddress;
400 UINT64 Pde;
401 UINT64 Address;
402
403 //
404 // Initialize physical address mask
405 // NOTE: Physical memory above virtual address limit is not supported !!!
406 //
407 AsmCpuid (0x80000008, (UINT32*)&Index, NULL, NULL, NULL);
408 mPhyMask = LShiftU64 (1, (UINT8)Index) - 1;
409 mPhyMask &= (1ull << 48) - EFI_PAGE_SIZE;
410
411 HookAddress = (UINT64)(UINTN)HookData;
412 PageTable = (UINT64 *)(UINTN)(AsmReadCr3 () & mPhyMask);
413 PageTable = (UINT64 *)(UINTN)(PageTable[BitFieldRead64 (HookAddress, 39, 47)] & mPhyMask);
414 PageTable = (UINT64 *)(UINTN)(PageTable[BitFieldRead64 (HookAddress, 30, 38)] & mPhyMask);
415
416 Pdpte = (UINT64 *)(UINTN)PageTable;
417 Pde = Pdpte[BitFieldRead64 (HookAddress, 21, 29)];
418 ASSERT ((Pde & BIT0) != 0); // Present and 2M Page
419
420 if ((Pde & BIT7) == 0) { // 4KB Page Directory
421 PageTable = (UINT64 *)(UINTN)(Pde & mPhyMask);
422 } else {
423 ASSERT ((Pde & mPhyMask) == (HookAddress & ~(SIZE_2MB-1))); // 2MB Page Point to HookAddress
424 PageTable = AllocatePages (1);
425 ASSERT (PageTable != NULL);
426 Address = HookAddress & ~(SIZE_2MB-1);
427 for (Index = 0; Index < 512; Index++) {
428 PageTable[Index] = Address | BIT0 | BIT1; // Present and RW
429 Address += SIZE_4KB;
430 }
431 Pdpte[BitFieldRead64 (HookAddress, 21, 29)] = (UINT64)(UINTN)PageTable | BIT0 | BIT1; // Present and RW
432 }
433 return PageTable;
434 }
435
436 /**
437 Mark all the CpuSaveStates as not present.
438
439 The function marks all CpuSaveStates memory range as not present so that page fault can be triggered
440 on CpuSaveStates access. It is meant to be called on each SmmBaseHelper SMI callback before Framework
441 handler is called.
442
443 @param[in] CpuSaveState The base of CpuSaveStates.
444
445 **/
446 VOID
447 HookCpuStateMemory (
448 IN EFI_SMM_CPU_SAVE_STATE *CpuSaveState
449 )
450 {
451 UINT64 Index;
452 UINT64 PTStartIndex;
453 UINT64 PTEndIndex;
454
455 PTStartIndex = BitFieldRead64 ((UINTN)CpuSaveState, 12, 20);
456 PTEndIndex = BitFieldRead64 ((UINTN)CpuSaveState + mNumberOfProcessors * sizeof (EFI_SMM_CPU_SAVE_STATE) - 1, 12, 20);
457 for (Index = PTStartIndex; Index <= PTEndIndex; Index++) {
458 mCpuStatePageTable[Index] &= ~(BIT0|BIT5|BIT6); // not present nor accessed nor dirty
459 }
460 }
461
462 /**
463 Framework SMST SmmInstallConfigurationTable() Thunk.
464
465 This thunk calls the PI SMM SmmInstallConfigurationTable() and then update the configuration
466 table related fields in the Framework SMST because the PI SMM SmmInstallConfigurationTable()
467 function may modify these fields.
468
469 @param[in] SystemTable A pointer to the SMM System Table.
470 @param[in] Guid A pointer to the GUID for the entry to add, update, or remove.
471 @param[in] Table A pointer to the buffer of the table to add.
472 @param[in] TableSize The size of the table to install.
473
474 @retval EFI_SUCCESS The (Guid, Table) pair was added, updated, or removed.
475 @retval EFI_INVALID_PARAMETER Guid is not valid.
476 @retval EFI_NOT_FOUND An attempt was made to delete a non-existent entry.
477 @retval EFI_OUT_OF_RESOURCES There is not enough memory available to complete the operation.
478 **/
479 EFI_STATUS
480 EFIAPI
481 SmmInstallConfigurationTable (
482 IN EFI_SMM_SYSTEM_TABLE *SystemTable,
483 IN EFI_GUID *Guid,
484 IN VOID *Table,
485 IN UINTN TableSize
486 )
487 {
488 EFI_STATUS Status;
489
490 Status = gSmst->SmmInstallConfigurationTable (gSmst, Guid, Table, TableSize);
491 if (!EFI_ERROR (Status)) {
492 mFrameworkSmst->NumberOfTableEntries = gSmst->NumberOfTableEntries;
493 mFrameworkSmst->SmmConfigurationTable = gSmst->SmmConfigurationTable;
494 }
495 return Status;
496 }
497
498 /**
499 Initialize all the stuff needed for on-demand paging hooks for PI<->Framework
500 CpuSaveStates marshalling.
501
502 @param[in] FrameworkSmst Framework SMM system table pointer.
503
504 **/
505 VOID
506 InitHook (
507 IN EFI_SMM_SYSTEM_TABLE *FrameworkSmst
508 )
509 {
510 UINTN NumCpuStatePages;
511 UINTN CpuStatePage;
512 UINTN Bottom2MPage;
513 UINTN Top2MPage;
514
515 mPageTableHookEnabled = FALSE;
516 NumCpuStatePages = EFI_SIZE_TO_PAGES (mNumberOfProcessors * sizeof (EFI_SMM_CPU_SAVE_STATE));
517 //
518 // Only hook page table for X64 image and less than 2MB needed to hold all CPU Save States
519 //
520 if (EFI_IMAGE_MACHINE_TYPE_SUPPORTED(EFI_IMAGE_MACHINE_X64) && NumCpuStatePages <= EFI_SIZE_TO_PAGES (SIZE_2MB)) {
521 //
522 // Allocate double page size to make sure all CPU Save States are in one 2MB page.
523 //
524 CpuStatePage = (UINTN)AllocatePages (NumCpuStatePages * 2);
525 ASSERT (CpuStatePage != 0);
526 Bottom2MPage = CpuStatePage & ~(SIZE_2MB-1);
527 Top2MPage = (CpuStatePage + EFI_PAGES_TO_SIZE (NumCpuStatePages * 2) - 1) & ~(SIZE_2MB-1);
528 if (Bottom2MPage == Top2MPage ||
529 CpuStatePage + EFI_PAGES_TO_SIZE (NumCpuStatePages * 2) - Top2MPage >= EFI_PAGES_TO_SIZE (NumCpuStatePages)
530 ) {
531 //
532 // If the allocated 4KB pages are within the same 2MB page or higher portion is larger, use higher portion pages.
533 //
534 FrameworkSmst->CpuSaveState = (EFI_SMM_CPU_SAVE_STATE *)(CpuStatePage + EFI_PAGES_TO_SIZE (NumCpuStatePages));
535 FreePages ((VOID*)CpuStatePage, NumCpuStatePages);
536 } else {
537 FrameworkSmst->CpuSaveState = (EFI_SMM_CPU_SAVE_STATE *)CpuStatePage;
538 FreePages ((VOID*)(CpuStatePage + EFI_PAGES_TO_SIZE (NumCpuStatePages)), NumCpuStatePages);
539 }
540 //
541 // Add temporary working buffer for hooking
542 //
543 mShadowSaveState = (EFI_SMM_CPU_SAVE_STATE*) AllocatePool (sizeof (EFI_SMM_CPU_SAVE_STATE));
544 ASSERT (mShadowSaveState != NULL);
545 //
546 // Allocate and initialize 4KB Page Table for hooking CpuSaveState.
547 // Replace the original 2MB PDE with new 4KB page table.
548 //
549 mCpuStatePageTable = InitCpuStatePageTable (FrameworkSmst->CpuSaveState);
550 //
551 // Mark PTE for CpuSaveState as non-exist.
552 //
553 HookCpuStateMemory (FrameworkSmst->CpuSaveState);
554 HookPageFaultHandler ();
555 CpuFlushTlb ();
556 mPageTableHookEnabled = TRUE;
557 }
558 mHookInitialized = TRUE;
559 }
560
561 /**
562 Construct a Framework SMST based on the PI SMM SMST.
563
564 @return Pointer to the constructed Framework SMST.
565 **/
566 EFI_SMM_SYSTEM_TABLE *
567 ConstructFrameworkSmst (
568 VOID
569 )
570 {
571 EFI_SMM_SYSTEM_TABLE *FrameworkSmst;
572
573 FrameworkSmst = (EFI_SMM_SYSTEM_TABLE *)AllocatePool (sizeof (EFI_SMM_SYSTEM_TABLE));
574 ASSERT (FrameworkSmst != NULL);
575
576 ///
577 /// Copy same things from PI SMST to Framework SMST
578 ///
579 CopyMem (FrameworkSmst, gSmst, (UINTN)(&((EFI_SMM_SYSTEM_TABLE *)0)->SmmIo));
580 CopyMem (
581 &FrameworkSmst->SmmIo,
582 &gSmst->SmmIo,
583 sizeof (EFI_SMM_SYSTEM_TABLE) - (UINTN)(&((EFI_SMM_SYSTEM_TABLE *)0)->SmmIo)
584 );
585
586 ///
587 /// Update Framework SMST
588 ///
589 FrameworkSmst->Hdr.Revision = EFI_SMM_SYSTEM_TABLE_REVISION;
590 CopyGuid (&FrameworkSmst->EfiSmmCpuIoGuid, &mEfiSmmCpuIoGuid);
591
592 mHookInitialized = FALSE;
593 FrameworkSmst->CpuSaveState = (EFI_SMM_CPU_SAVE_STATE *)AllocateZeroPool (mNumberOfProcessors * sizeof (EFI_SMM_CPU_SAVE_STATE));
594 ASSERT (FrameworkSmst->CpuSaveState != NULL);
595
596 ///
597 /// Do not support floating point state now
598 ///
599 FrameworkSmst->CpuOptionalFloatingPointState = NULL;
600
601 FrameworkSmst->SmmInstallConfigurationTable = SmmInstallConfigurationTable;
602
603 return FrameworkSmst;
604 }
605
606 /**
607 Load a given Framework SMM driver into SMRAM and invoke its entry point.
608
609 @param[in] ParentImageHandle Parent Image Handle.
610 @param[in] FilePath Location of the image to be installed as the handler.
611 @param[in] SourceBuffer Optional source buffer in case the image file
612 is in memory.
613 @param[in] SourceSize Size of the source image file, if in memory.
614 @param[out] ImageHandle The handle that the base driver uses to decode
615 the handler. Unique among SMM handlers only,
616 not unique across DXE/EFI.
617
618 @retval EFI_SUCCESS The operation was successful.
619 @retval EFI_OUT_OF_RESOURCES There were no additional SMRAM resources to load the handler
620 @retval EFI_UNSUPPORTED Can not find its copy in normal memory.
621 @retval EFI_INVALID_PARAMETER The handlers was not the correct image type
622 **/
623 EFI_STATUS
624 LoadImage (
625 IN EFI_HANDLE ParentImageHandle,
626 IN EFI_DEVICE_PATH_PROTOCOL *FilePath,
627 IN VOID *SourceBuffer,
628 IN UINTN SourceSize,
629 OUT EFI_HANDLE *ImageHandle
630 )
631 {
632 EFI_STATUS Status;
633 UINTN PageCount;
634 UINTN OrgPageCount;
635 EFI_PHYSICAL_ADDRESS DstBuffer;
636
637 if (FilePath == NULL || ImageHandle == NULL) {
638 return EFI_INVALID_PARAMETER;
639 }
640
641 PageCount = 1;
642 do {
643 OrgPageCount = PageCount;
644 DstBuffer = (UINTN)-1;
645 Status = gSmst->SmmAllocatePages (
646 AllocateMaxAddress,
647 EfiRuntimeServicesCode,
648 PageCount,
649 &DstBuffer
650 );
651 if (EFI_ERROR (Status)) {
652 return Status;
653 }
654
655 Status = mLoadPe32Image->LoadPeImage (
656 mLoadPe32Image,
657 ParentImageHandle,
658 FilePath,
659 SourceBuffer,
660 SourceSize,
661 DstBuffer,
662 &PageCount,
663 ImageHandle,
664 NULL,
665 EFI_LOAD_PE_IMAGE_ATTRIBUTE_NONE
666 );
667 if (EFI_ERROR (Status)) {
668 FreePages ((VOID *)(UINTN)DstBuffer, OrgPageCount);
669 }
670 } while (Status == EFI_BUFFER_TOO_SMALL);
671
672 if (!EFI_ERROR (Status)) {
673 ///
674 /// Update MP state in Framework SMST before transferring control to Framework SMM driver entry point
675 /// in case it may invoke AP
676 ///
677 mFrameworkSmst->CurrentlyExecutingCpu = gSmst->CurrentlyExecutingCpu;
678
679 Status = gBS->StartImage (*ImageHandle, NULL, NULL);
680 if (EFI_ERROR (Status)) {
681 mLoadPe32Image->UnLoadPeImage (mLoadPe32Image, *ImageHandle);
682 *ImageHandle = NULL;
683 FreePages ((VOID *)(UINTN)DstBuffer, PageCount);
684 }
685 }
686
687 return Status;
688 }
689
690
691 /**
692 Thunk service of EFI_SMM_BASE_PROTOCOL.Register().
693
694 @param[in, out] FunctionData Pointer to SMMBASE_FUNCTION_DATA.
695 **/
696 VOID
697 Register (
698 IN OUT SMMBASE_FUNCTION_DATA *FunctionData
699 )
700 {
701 EFI_STATUS Status;
702
703 if (mLocked || FunctionData->Args.Register.LegacyIA32Binary) {
704 Status = EFI_UNSUPPORTED;
705 } else {
706 Status = LoadImage (
707 FunctionData->SmmBaseImageHandle,
708 FunctionData->Args.Register.FilePath,
709 FunctionData->Args.Register.SourceBuffer,
710 FunctionData->Args.Register.SourceSize,
711 FunctionData->Args.Register.ImageHandle
712 );
713 }
714 FunctionData->Status = Status;
715 }
716
717 /**
718 Thunk service of EFI_SMM_BASE_PROTOCOL.UnRegister().
719
720 @param[in, out] FunctionData Pointer to SMMBASE_FUNCTION_DATA.
721 **/
722 VOID
723 UnRegister (
724 IN OUT SMMBASE_FUNCTION_DATA *FunctionData
725 )
726 {
727 ///
728 /// Unregister not supported now
729 ///
730 FunctionData->Status = EFI_UNSUPPORTED;
731 }
732
733 /**
734 Search for Framework SMI handler information according to specific PI SMM dispatch handle.
735
736 @param[in] DispatchHandle The unique handle assigned by SmiHandlerRegister().
737
738 @return Pointer to CALLBACK_INFO. If NULL, no callback info record is found.
739 **/
740 CALLBACK_INFO *
741 GetCallbackInfo (
742 IN EFI_HANDLE DispatchHandle
743 )
744 {
745 LIST_ENTRY *Node;
746
747 Node = GetFirstNode (&mCallbackInfoListHead);
748 while (!IsNull (&mCallbackInfoListHead, Node)) {
749 if (((CALLBACK_INFO *)Node)->DispatchHandle == DispatchHandle) {
750 return (CALLBACK_INFO *)Node;
751 }
752 Node = GetNextNode (&mCallbackInfoListHead, Node);
753 }
754 return NULL;
755 }
756
757 /**
758 Callback thunk for Framework SMI handler.
759
760 This thunk functions calls the Framework SMI handler and converts the return value
761 defined from Framework SMI handlers to a correpsonding return value defined by PI SMM.
762
763 @param[in] DispatchHandle The unique handle assigned to this handler by SmiHandlerRegister().
764 @param[in] Context Points to an optional handler context which was specified when the
765 handler was registered.
766 @param[in, out] CommBuffer A pointer to a collection of data in memory that will
767 be conveyed from a non-SMM environment into an SMM environment.
768 @param[in, out] CommBufferSize The size of the CommBuffer.
769
770 @retval EFI_SUCCESS The interrupt was handled and quiesced. No other handlers
771 should still be called.
772 @retval EFI_WARN_INTERRUPT_SOURCE_QUIESCED The interrupt has been quiesced but other handlers should
773 still be called.
774 @retval EFI_WARN_INTERRUPT_SOURCE_PENDING The interrupt is still pending and other handlers should still
775 be called.
776 @retval EFI_INTERRUPT_PENDING The interrupt could not be quiesced.
777 **/
778 EFI_STATUS
779 EFIAPI
780 CallbackThunk (
781 IN EFI_HANDLE DispatchHandle,
782 IN CONST VOID *Context OPTIONAL,
783 IN OUT VOID *CommBuffer OPTIONAL,
784 IN OUT UINTN *CommBufferSize OPTIONAL
785 )
786 {
787 EFI_STATUS Status;
788 CALLBACK_INFO *CallbackInfo;
789 UINTN CpuIndex;
790
791 ///
792 /// Before transferring the control into the Framework SMI handler, update CPU Save States
793 /// and MP states in the Framework SMST.
794 ///
795
796 if (!mHookInitialized) {
797 InitHook (mFrameworkSmst);
798 }
799 if (mPageTableHookEnabled) {
800 HookCpuStateMemory (mFrameworkSmst->CpuSaveState);
801 CpuFlushTlb ();
802 } else {
803 for (CpuIndex = 0; CpuIndex < mNumberOfProcessors; CpuIndex++) {
804 ReadCpuSaveState (CpuIndex, NULL);
805 }
806 }
807
808 mFrameworkSmst->SmmStartupThisAp = gSmst->SmmStartupThisAp;
809 mFrameworkSmst->NumberOfCpus = mNumberOfProcessors;
810 mFrameworkSmst->CurrentlyExecutingCpu = gSmst->CurrentlyExecutingCpu;
811
812 ///
813 /// Search for Framework SMI handler information
814 ///
815 CallbackInfo = GetCallbackInfo (DispatchHandle);
816 ASSERT (CallbackInfo != NULL);
817
818 ///
819 /// Thunk into original Framwork SMI handler
820 ///
821 Status = (CallbackInfo->CallbackAddress) (
822 CallbackInfo->SmmImageHandle,
823 CallbackInfo->CommunicationBuffer,
824 CallbackInfo->SourceSize
825 );
826 ///
827 /// Save CPU Save States in case any of them was modified
828 ///
829 if (mPageTableHookEnabled) {
830 WriteBackDirtyPages ();
831 } else {
832 for (CpuIndex = 0; CpuIndex < mNumberOfProcessors; CpuIndex++) {
833 WriteCpuSaveState (CpuIndex, NULL);
834 }
835 }
836
837 ///
838 /// Conversion of returned status code
839 ///
840 switch (Status) {
841 case EFI_HANDLER_SUCCESS:
842 Status = EFI_WARN_INTERRUPT_SOURCE_QUIESCED;
843 break;
844 case EFI_HANDLER_CRITICAL_EXIT:
845 case EFI_HANDLER_SOURCE_QUIESCED:
846 Status = EFI_SUCCESS;
847 break;
848 case EFI_HANDLER_SOURCE_PENDING:
849 Status = EFI_WARN_INTERRUPT_SOURCE_PENDING;
850 break;
851 }
852 return Status;
853 }
854
855 /**
856 Thunk service of EFI_SMM_BASE_PROTOCOL.RegisterCallback().
857
858 @param[in, out] FunctionData Pointer to SMMBASE_FUNCTION_DATA.
859 **/
860 VOID
861 RegisterCallback (
862 IN OUT SMMBASE_FUNCTION_DATA *FunctionData
863 )
864 {
865 CALLBACK_INFO *Buffer;
866
867 if (mLocked) {
868 FunctionData->Status = EFI_UNSUPPORTED;
869 return;
870 }
871
872 ///
873 /// Note that MakeLast and FloatingPointSave options are not supported in PI SMM
874 ///
875
876 ///
877 /// Allocate buffer for callback thunk information
878 ///
879 Buffer = (CALLBACK_INFO *)AllocateZeroPool (sizeof (CALLBACK_INFO));
880 if (Buffer == NULL) {
881 FunctionData->Status = EFI_OUT_OF_RESOURCES;
882 return;
883 }
884
885 ///
886 /// Fill SmmImageHandle and CallbackAddress into the thunk
887 ///
888 Buffer->SmmImageHandle = FunctionData->Args.RegisterCallback.SmmImageHandle;
889 Buffer->CallbackAddress = FunctionData->Args.RegisterCallback.CallbackAddress;
890
891 ///
892 /// Register the thunk code as a root SMI handler
893 ///
894 FunctionData->Status = gSmst->SmiHandlerRegister (
895 CallbackThunk,
896 NULL,
897 &Buffer->DispatchHandle
898 );
899 if (EFI_ERROR (FunctionData->Status)) {
900 FreePool (Buffer);
901 return;
902 }
903
904 ///
905 /// Save this callback info
906 ///
907 InsertTailList (&mCallbackInfoListHead, &Buffer->Link);
908 }
909
910
911 /**
912 Thunk service of EFI_SMM_BASE_PROTOCOL.SmmAllocatePool().
913
914 @param[in, out] FunctionData Pointer to SMMBASE_FUNCTION_DATA.
915 **/
916 VOID
917 HelperAllocatePool (
918 IN OUT SMMBASE_FUNCTION_DATA *FunctionData
919 )
920 {
921 if (mLocked) {
922 FunctionData->Status = EFI_UNSUPPORTED;
923 } else {
924 FunctionData->Status = gSmst->SmmAllocatePool (
925 FunctionData->Args.AllocatePool.PoolType,
926 FunctionData->Args.AllocatePool.Size,
927 FunctionData->Args.AllocatePool.Buffer
928 );
929 }
930 }
931
932 /**
933 Thunk service of EFI_SMM_BASE_PROTOCOL.SmmFreePool().
934
935 @param[in, out] FunctionData Pointer to SMMBASE_FUNCTION_DATA.
936 **/
937 VOID
938 HelperFreePool (
939 IN OUT SMMBASE_FUNCTION_DATA *FunctionData
940 )
941 {
942 if (mLocked) {
943 FunctionData->Status = EFI_UNSUPPORTED;
944 } else {
945 FreePool (FunctionData->Args.FreePool.Buffer);
946 FunctionData->Status = EFI_SUCCESS;
947 }
948 }
949
950 /**
951 Thunk service of EFI_SMM_BASE_PROTOCOL.Communicate().
952
953 @param[in, out] FunctionData Pointer to SMMBASE_FUNCTION_DATA.
954 **/
955 VOID
956 HelperCommunicate (
957 IN OUT SMMBASE_FUNCTION_DATA *FunctionData
958 )
959 {
960 LIST_ENTRY *Node;
961 CALLBACK_INFO *CallbackInfo;
962
963 if (FunctionData->Args.Communicate.CommunicationBuffer == NULL) {
964 FunctionData->Status = EFI_INVALID_PARAMETER;
965 return;
966 }
967
968 Node = GetFirstNode (&mCallbackInfoListHead);
969 while (!IsNull (&mCallbackInfoListHead, Node)) {
970 CallbackInfo = (CALLBACK_INFO *)Node;
971
972 if (FunctionData->Args.Communicate.ImageHandle == CallbackInfo->SmmImageHandle) {
973 CallbackInfo->CommunicationBuffer = FunctionData->Args.Communicate.CommunicationBuffer;
974 CallbackInfo->SourceSize = FunctionData->Args.Communicate.SourceSize;
975
976 ///
977 /// The message was successfully posted.
978 ///
979 FunctionData->Status = EFI_SUCCESS;
980 return;
981 }
982 Node = GetNextNode (&mCallbackInfoListHead, Node);
983 }
984
985 FunctionData->Status = EFI_INVALID_PARAMETER;
986 }
987
988 /**
989 Communication service SMI Handler entry.
990
991 This SMI handler provides services for the SMM Base Thunk driver.
992
993 @param[in] DispatchHandle The unique handle assigned to this handler by SmiHandlerRegister().
994 @param[in] RegisterContext Points to an optional handler context which was specified when the
995 handler was registered.
996 @param[in, out] CommBuffer A pointer to a collection of data in memory that will
997 be conveyed from a non-SMM environment into an SMM environment.
998 @param[in, out] CommBufferSize The size of the CommBuffer.
999
1000 @retval EFI_SUCCESS The interrupt was handled and quiesced. No other handlers
1001 should still be called.
1002 @retval EFI_WARN_INTERRUPT_SOURCE_QUIESCED The interrupt has been quiesced but other handlers should
1003 still be called.
1004 @retval EFI_WARN_INTERRUPT_SOURCE_PENDING The interrupt is still pending and other handlers should still
1005 be called.
1006 @retval EFI_INTERRUPT_PENDING The interrupt could not be quiesced.
1007 **/
1008 EFI_STATUS
1009 EFIAPI
1010 SmmHandlerEntry (
1011 IN EFI_HANDLE DispatchHandle,
1012 IN CONST VOID *RegisterContext,
1013 IN OUT VOID *CommBuffer,
1014 IN OUT UINTN *CommBufferSize
1015 )
1016 {
1017 SMMBASE_FUNCTION_DATA *FunctionData;
1018
1019 ASSERT (CommBuffer != NULL);
1020 ASSERT (*CommBufferSize == sizeof (SMMBASE_FUNCTION_DATA));
1021
1022 FunctionData = (SMMBASE_FUNCTION_DATA *)CommBuffer;
1023
1024 switch (FunctionData->Function) {
1025 case SmmBaseFunctionRegister:
1026 Register (FunctionData);
1027 break;
1028 case SmmBaseFunctionUnregister:
1029 UnRegister (FunctionData);
1030 break;
1031 case SmmBaseFunctionRegisterCallback:
1032 RegisterCallback (FunctionData);
1033 break;
1034 case SmmBaseFunctionAllocatePool:
1035 HelperAllocatePool (FunctionData);
1036 break;
1037 case SmmBaseFunctionFreePool:
1038 HelperFreePool (FunctionData);
1039 break;
1040 case SmmBaseFunctionCommunicate:
1041 HelperCommunicate (FunctionData);
1042 break;
1043 default:
1044 ASSERT (FALSE);
1045 FunctionData->Status = EFI_UNSUPPORTED;
1046 }
1047 return EFI_SUCCESS;
1048 }
1049
1050 /**
1051 Smm Ready To Lock event notification handler.
1052
1053 It sets a flag indicating that SMRAM has been locked.
1054
1055 @param[in] Protocol Points to the protocol's unique identifier.
1056 @param[in] Interface Points to the interface instance.
1057 @param[in] Handle The handle on which the interface was installed.
1058
1059 @retval EFI_SUCCESS Notification handler runs successfully.
1060 **/
1061 EFI_STATUS
1062 EFIAPI
1063 SmmReadyToLockEventNotify (
1064 IN CONST EFI_GUID *Protocol,
1065 IN VOID *Interface,
1066 IN EFI_HANDLE Handle
1067 )
1068 {
1069 mLocked = TRUE;
1070 return EFI_SUCCESS;
1071 }
1072
1073 /**
1074 Entry point function of the SMM Base Helper SMM driver.
1075
1076 @param[in] ImageHandle The firmware allocated handle for the EFI image.
1077 @param[in] SystemTable A pointer to the EFI System Table.
1078
1079 @retval EFI_SUCCESS The entry point is executed successfully.
1080 @retval other Some error occurs when executing this entry point.
1081 **/
1082 EFI_STATUS
1083 EFIAPI
1084 SmmBaseHelperMain (
1085 IN EFI_HANDLE ImageHandle,
1086 IN EFI_SYSTEM_TABLE *SystemTable
1087 )
1088 {
1089 EFI_STATUS Status;
1090 EFI_MP_SERVICES_PROTOCOL *MpServices;
1091 EFI_HANDLE Handle;
1092 UINTN NumberOfEnabledProcessors;
1093 VOID *Registration;
1094
1095 Handle = NULL;
1096 ///
1097 /// Locate SMM CPU Protocol which is used later to retrieve/update CPU Save States
1098 ///
1099 Status = gSmst->SmmLocateProtocol (&gEfiSmmCpuProtocolGuid, NULL, (VOID **) &mSmmCpu);
1100 ASSERT_EFI_ERROR (Status);
1101
1102 ///
1103 /// Locate PE32 Image Protocol which is used later to load Framework SMM driver
1104 ///
1105 Status = SystemTable->BootServices->LocateProtocol (&gEfiLoadPeImageProtocolGuid, NULL, (VOID **) &mLoadPe32Image);
1106 ASSERT_EFI_ERROR (Status);
1107
1108 //
1109 // Get MP Services Protocol
1110 //
1111 Status = SystemTable->BootServices->LocateProtocol (&gEfiMpServiceProtocolGuid, NULL, (VOID **)&MpServices);
1112 ASSERT_EFI_ERROR (Status);
1113
1114 //
1115 // Use MP Services Protocol to retrieve the number of processors and number of enabled processors
1116 //
1117 Status = MpServices->GetNumberOfProcessors (MpServices, &mNumberOfProcessors, &NumberOfEnabledProcessors);
1118 ASSERT_EFI_ERROR (Status);
1119
1120 ///
1121 /// Interface structure of SMM BASE Helper Ready Protocol is allocated from UEFI pool
1122 /// instead of SMM pool so that SMM Base Thunk driver can access it in Non-SMM mode.
1123 ///
1124 Status = gBS->AllocatePool (
1125 EfiBootServicesData,
1126 sizeof (EFI_SMM_BASE_HELPER_READY_PROTOCOL),
1127 (VOID **)&mSmmBaseHelperReady
1128 );
1129 ASSERT_EFI_ERROR (Status);
1130
1131 ///
1132 /// Construct Framework SMST from PI SMST
1133 ///
1134 mFrameworkSmst = ConstructFrameworkSmst ();
1135 mSmmBaseHelperReady->FrameworkSmst = mFrameworkSmst;
1136 mSmmBaseHelperReady->ServiceEntry = SmmHandlerEntry;
1137
1138 //
1139 // Register SMM Ready To Lock Protocol notification
1140 //
1141 Status = gSmst->SmmRegisterProtocolNotify (
1142 &gEfiSmmReadyToLockProtocolGuid,
1143 SmmReadyToLockEventNotify,
1144 &Registration
1145 );
1146 ASSERT_EFI_ERROR (Status);
1147
1148 ///
1149 /// Register SMM Base Helper services for SMM Base Thunk driver
1150 ///
1151 Status = gSmst->SmiHandlerRegister (SmmHandlerEntry, &gEfiSmmBaseThunkCommunicationGuid, &mDispatchHandle);
1152 ASSERT_EFI_ERROR (Status);
1153
1154 ///
1155 /// Install EFI SMM Base Helper Protocol in the UEFI handle database
1156 ///
1157 Status = gBS->InstallProtocolInterface (
1158 &Handle,
1159 &gEfiSmmBaseHelperReadyProtocolGuid,
1160 EFI_NATIVE_INTERFACE,
1161 mSmmBaseHelperReady
1162 );
1163 ASSERT_EFI_ERROR (Status);
1164
1165 return Status;
1166 }
1167