]> git.proxmox.com Git - mirror_edk2.git/blob - EdkCompatibilityPkg/Compatibility/SmmBaseHelper/SmmBaseHelper.c
Enhance the SmmBaseHelper driver to support changing SMBASE/IORestart/AutoHALTRestart...
[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 - 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
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 //
148 // Note that SMBASE/SMMRevId/IORestart/AutoHALTRestart are in same location in IA32 and X64 CPU Save State Map.
149 //
150 SaveState->SMBASE = State->x86.SMBASE;
151 SaveState->SMMRevId = State->x86.SMMRevId;
152 SaveState->IORestart = State->x86.IORestart;
153 SaveState->AutoHALTRestart = State->x86.AutoHALTRestart;
154
155 for (Index = 0; Index < sizeof (mCpuSaveStateConvTable) / sizeof (CPU_SAVE_STATE_CONVERSION); Index++) {
156 ///
157 /// Try to use SMM CPU Protocol to access CPU save states if possible
158 ///
159 Status = mSmmCpu->ReadSaveState (
160 mSmmCpu,
161 (UINTN)sizeof (UINT32),
162 mCpuSaveStateConvTable[Index].Register,
163 CpuIndex,
164 ((UINT8 *)SaveState) + mCpuSaveStateConvTable[Index].Offset
165 );
166 ASSERT_EFI_ERROR (Status);
167 }
168 }
169
170 /**
171 Write CpuSaveStates from Framework into PI.
172
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].
176
177 @param[in] CpuIndex The zero-based CPU index.
178 @param[in] ToWrite If not NULL, CpuSaveStates to write from.
179
180 **/
181 VOID
182 WriteCpuSaveState (
183 IN UINTN CpuIndex,
184 IN EFI_SMM_CPU_SAVE_STATE *ToWrite
185 )
186 {
187 EFI_STATUS Status;
188 UINTN Index;
189 EFI_SMM_CPU_STATE *State;
190 EFI_SMI_CPU_SAVE_STATE *SaveState;
191
192 State = (EFI_SMM_CPU_STATE *)gSmst->CpuSaveState[CpuIndex];
193
194 if (ToWrite != NULL) {
195 SaveState = &ToWrite->Ia32SaveState;
196 } else {
197 SaveState = &mFrameworkSmst->CpuSaveState[CpuIndex].Ia32SaveState;
198 }
199
200 //
201 // SMMRevId is read-only.
202 // Note that SMBASE/IORestart/AutoHALTRestart are in same location in IA32 and X64 CPU Save State Map.
203 //
204 State->x86.SMBASE = SaveState->SMBASE;
205 State->x86.IORestart = SaveState->IORestart;
206 State->x86.AutoHALTRestart = SaveState->AutoHALTRestart;
207
208 for (Index = 0; Index < sizeof (mCpuSaveStateConvTable) / sizeof (CPU_SAVE_STATE_CONVERSION); Index++) {
209 Status = mSmmCpu->WriteSaveState (
210 mSmmCpu,
211 (UINTN)sizeof (UINT32),
212 mCpuSaveStateConvTable[Index].Register,
213 CpuIndex,
214 ((UINT8 *)SaveState) +
215 mCpuSaveStateConvTable[Index].Offset
216 );
217 }
218 }
219
220 /**
221 Read or write a page that contains CpuSaveStates. Read is from PI to Framework.
222 Write is from Framework to PI.
223
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.
230
231 @param[in] PageAddress The base address for a page.
232 @param[in] IsRead TRUE for Read, FALSE for Write.
233
234 **/
235 VOID
236 ReadWriteCpuStatePage (
237 IN UINT64 PageAddress,
238 IN BOOLEAN IsRead
239 )
240 {
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
245 UINTN ClippedSize;
246 UINTN CpuIndex;
247
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) {
251 FirstSSIndex++;
252 FirstSSAligned = FALSE;
253 }
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) {
257 LastSSIndex--;
258 LastSSAligned = FALSE;
259 }
260 for (CpuIndex = FirstSSIndex; CpuIndex <= LastSSIndex && CpuIndex < mNumberOfProcessors; CpuIndex++) {
261 if (IsRead) {
262 ReadCpuSaveState (CpuIndex, NULL);
263 } else {
264 WriteCpuSaveState (CpuIndex, NULL);
265 }
266 }
267 if (!FirstSSAligned) {
268 ReadCpuSaveState (FirstSSIndex - 1, mShadowSaveState);
269 ClippedSize = (UINTN)&mFrameworkSmst->CpuSaveState[FirstSSIndex] & (SIZE_4KB - 1);
270 if (IsRead) {
271 CopyMem ((VOID*)(UINTN)PageAddress, (VOID*)((UINTN)(mShadowSaveState + 1) - ClippedSize), ClippedSize);
272 } else {
273 CopyMem ((VOID*)((UINTN)(mShadowSaveState + 1) - ClippedSize), (VOID*)(UINTN)PageAddress, ClippedSize);
274 WriteCpuSaveState (FirstSSIndex - 1, mShadowSaveState);
275 }
276 }
277 if (!LastSSAligned && LastSSIndex + 1 < mNumberOfProcessors) {
278 ReadCpuSaveState (LastSSIndex + 1, mShadowSaveState);
279 ClippedSize = SIZE_4KB - ((UINTN)&mFrameworkSmst->CpuSaveState[LastSSIndex + 1] & (SIZE_4KB - 1));
280 if (IsRead) {
281 CopyMem (&mFrameworkSmst->CpuSaveState[LastSSIndex + 1], mShadowSaveState, ClippedSize);
282 } else {
283 CopyMem (mShadowSaveState, &mFrameworkSmst->CpuSaveState[LastSSIndex + 1], ClippedSize);
284 WriteCpuSaveState (LastSSIndex + 1, mShadowSaveState);
285 }
286 }
287 }
288
289 /**
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.
293
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.
296
297 **/
298 BOOLEAN
299 PageFaultHandler (
300 VOID
301 )
302 {
303 BOOLEAN IsHandled;
304 UINT64 *PageTable;
305 UINT64 PFAddress;
306 UINTN NumCpuStatePages;
307
308 ASSERT (mPageTableHookEnabled);
309 AcquireSpinLock (&mPFLock);
310
311 PageTable = (UINT64*)(UINTN)(AsmReadCr3 () & mPhyMask);
312 PFAddress = AsmReadCr2 ();
313 NumCpuStatePages = EFI_SIZE_TO_PAGES (mNumberOfProcessors * sizeof (EFI_SMM_CPU_SAVE_STATE));
314 IsHandled = FALSE;
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)
318 ) {
319 mCpuStatePageTable[BitFieldRead64 (PFAddress, 12, 20)] |= BIT0 | BIT1; // present and rw
320 CpuFlushTlb ();
321 ReadWriteCpuStatePage (PFAddress & ~(SIZE_4KB-1), TRUE);
322 IsHandled = TRUE;
323 } else {
324 ASSERT (FALSE);
325 }
326 }
327
328 ReleaseSpinLock (&mPFLock);
329 return IsHandled;
330 }
331
332 /**
333 Write back the dirty Framework CpuSaveStates to PI.
334
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.
338
339 **/
340 VOID
341 WriteBackDirtyPages (
342 VOID
343 )
344 {
345 UINTN NumCpuStatePages;
346 UINTN PTIndex;
347 UINTN PTStartIndex;
348 UINTN PTEndIndex;
349
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);
356 }
357 }
358 }
359
360 /**
361 Hook IDT with our page fault handler so that the on-demand paging works on page fault.
362
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
365 purpose.
366
367 **/
368 VOID
369 HookPageFaultHandler (
370 VOID
371 )
372 {
373 IA32_DESCRIPTOR Idtr;
374 IA32_IDT_GATE_DESCRIPTOR *IdtGateDesc;
375 UINT32 OffsetUpper;
376
377 InitializeSpinLock (&mPFLock);
378
379 AsmReadIdtr (&Idtr);
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));
385 }
386
387 /**
388 Initialize page table for pages contain HookData.
389
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.
393
394 @param[in] HookData Based on which to initialize page table.
395
396 @return The pointer to a Page Table that points to 4KB pages which contain HookData.
397 **/
398 UINT64 *
399 InitCpuStatePageTable (
400 IN VOID *HookData
401 )
402 {
403 UINTN Index;
404 UINT64 *PageTable;
405 UINT64 *Pdpte;
406 UINT64 HookAddress;
407 UINT64 Pde;
408 UINT64 Address;
409
410 //
411 // Initialize physical address mask
412 // NOTE: Physical memory above virtual address limit is not supported !!!
413 //
414 AsmCpuid (0x80000008, (UINT32*)&Index, NULL, NULL, NULL);
415 mPhyMask = LShiftU64 (1, (UINT8)Index) - 1;
416 mPhyMask &= (1ull << 48) - EFI_PAGE_SIZE;
417
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);
422
423 Pdpte = (UINT64 *)(UINTN)PageTable;
424 Pde = Pdpte[BitFieldRead64 (HookAddress, 21, 29)];
425 ASSERT ((Pde & BIT0) != 0); // Present and 2M Page
426
427 if ((Pde & BIT7) == 0) { // 4KB Page Directory
428 PageTable = (UINT64 *)(UINTN)(Pde & mPhyMask);
429 } else {
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
436 Address += SIZE_4KB;
437 }
438 Pdpte[BitFieldRead64 (HookAddress, 21, 29)] = (UINT64)(UINTN)PageTable | BIT0 | BIT1; // Present and RW
439 }
440 return PageTable;
441 }
442
443 /**
444 Mark all the CpuSaveStates as not present.
445
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
448 handler is called.
449
450 @param[in] CpuSaveState The base of CpuSaveStates.
451
452 **/
453 VOID
454 HookCpuStateMemory (
455 IN EFI_SMM_CPU_SAVE_STATE *CpuSaveState
456 )
457 {
458 UINT64 Index;
459 UINT64 PTStartIndex;
460 UINT64 PTEndIndex;
461
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
466 }
467 }
468
469 /**
470 Framework SMST SmmInstallConfigurationTable() Thunk.
471
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.
475
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.
480
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.
485 **/
486 EFI_STATUS
487 EFIAPI
488 SmmInstallConfigurationTable (
489 IN EFI_SMM_SYSTEM_TABLE *SystemTable,
490 IN EFI_GUID *Guid,
491 IN VOID *Table,
492 IN UINTN TableSize
493 )
494 {
495 EFI_STATUS Status;
496
497 Status = gSmst->SmmInstallConfigurationTable (gSmst, Guid, Table, TableSize);
498 if (!EFI_ERROR (Status)) {
499 mFrameworkSmst->NumberOfTableEntries = gSmst->NumberOfTableEntries;
500 mFrameworkSmst->SmmConfigurationTable = gSmst->SmmConfigurationTable;
501 }
502 return Status;
503 }
504
505 /**
506 Initialize all the stuff needed for on-demand paging hooks for PI<->Framework
507 CpuSaveStates marshalling.
508
509 @param[in] FrameworkSmst Framework SMM system table pointer.
510
511 **/
512 VOID
513 InitHook (
514 IN EFI_SMM_SYSTEM_TABLE *FrameworkSmst
515 )
516 {
517 UINTN NumCpuStatePages;
518 UINTN CpuStatePage;
519 UINTN Bottom2MPage;
520 UINTN Top2MPage;
521
522 mPageTableHookEnabled = FALSE;
523 NumCpuStatePages = EFI_SIZE_TO_PAGES (mNumberOfProcessors * sizeof (EFI_SMM_CPU_SAVE_STATE));
524 //
525 // Only hook page table for X64 image and less than 2MB needed to hold all CPU Save States
526 //
527 if (EFI_IMAGE_MACHINE_TYPE_SUPPORTED(EFI_IMAGE_MACHINE_X64) && NumCpuStatePages <= EFI_SIZE_TO_PAGES (SIZE_2MB)) {
528 //
529 // Allocate double page size to make sure all CPU Save States are in one 2MB page.
530 //
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)
537 ) {
538 //
539 // If the allocated 4KB pages are within the same 2MB page or higher portion is larger, use higher portion pages.
540 //
541 FrameworkSmst->CpuSaveState = (EFI_SMM_CPU_SAVE_STATE *)(CpuStatePage + EFI_PAGES_TO_SIZE (NumCpuStatePages));
542 FreePages ((VOID*)CpuStatePage, NumCpuStatePages);
543 } else {
544 FrameworkSmst->CpuSaveState = (EFI_SMM_CPU_SAVE_STATE *)CpuStatePage;
545 FreePages ((VOID*)(CpuStatePage + EFI_PAGES_TO_SIZE (NumCpuStatePages)), NumCpuStatePages);
546 }
547 //
548 // Add temporary working buffer for hooking
549 //
550 mShadowSaveState = (EFI_SMM_CPU_SAVE_STATE*) AllocatePool (sizeof (EFI_SMM_CPU_SAVE_STATE));
551 ASSERT (mShadowSaveState != NULL);
552 //
553 // Allocate and initialize 4KB Page Table for hooking CpuSaveState.
554 // Replace the original 2MB PDE with new 4KB page table.
555 //
556 mCpuStatePageTable = InitCpuStatePageTable (FrameworkSmst->CpuSaveState);
557 //
558 // Mark PTE for CpuSaveState as non-exist.
559 //
560 HookCpuStateMemory (FrameworkSmst->CpuSaveState);
561 HookPageFaultHandler ();
562 CpuFlushTlb ();
563 mPageTableHookEnabled = TRUE;
564 }
565 mHookInitialized = TRUE;
566 }
567
568 /**
569 Construct a Framework SMST based on the PI SMM SMST.
570
571 @return Pointer to the constructed Framework SMST.
572 **/
573 EFI_SMM_SYSTEM_TABLE *
574 ConstructFrameworkSmst (
575 VOID
576 )
577 {
578 EFI_SMM_SYSTEM_TABLE *FrameworkSmst;
579
580 FrameworkSmst = (EFI_SMM_SYSTEM_TABLE *)AllocatePool (sizeof (EFI_SMM_SYSTEM_TABLE));
581 ASSERT (FrameworkSmst != NULL);
582
583 ///
584 /// Copy same things from PI SMST to Framework SMST
585 ///
586 CopyMem (FrameworkSmst, gSmst, (UINTN)(&((EFI_SMM_SYSTEM_TABLE *)0)->SmmIo));
587 CopyMem (
588 &FrameworkSmst->SmmIo,
589 &gSmst->SmmIo,
590 sizeof (EFI_SMM_SYSTEM_TABLE) - (UINTN)(&((EFI_SMM_SYSTEM_TABLE *)0)->SmmIo)
591 );
592
593 ///
594 /// Update Framework SMST
595 ///
596 FrameworkSmst->Hdr.Revision = EFI_SMM_SYSTEM_TABLE_REVISION;
597 CopyGuid (&FrameworkSmst->EfiSmmCpuIoGuid, &mEfiSmmCpuIoGuid);
598
599 mHookInitialized = FALSE;
600 FrameworkSmst->CpuSaveState = (EFI_SMM_CPU_SAVE_STATE *)AllocateZeroPool (mNumberOfProcessors * sizeof (EFI_SMM_CPU_SAVE_STATE));
601 ASSERT (FrameworkSmst->CpuSaveState != NULL);
602
603 ///
604 /// Do not support floating point state now
605 ///
606 FrameworkSmst->CpuOptionalFloatingPointState = NULL;
607
608 FrameworkSmst->SmmInstallConfigurationTable = SmmInstallConfigurationTable;
609
610 return FrameworkSmst;
611 }
612
613 /**
614 Load a given Framework SMM driver into SMRAM and invoke its entry point.
615
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
619 is in memory.
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.
624
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
629 **/
630 EFI_STATUS
631 LoadImage (
632 IN EFI_HANDLE ParentImageHandle,
633 IN EFI_DEVICE_PATH_PROTOCOL *FilePath,
634 IN VOID *SourceBuffer,
635 IN UINTN SourceSize,
636 OUT EFI_HANDLE *ImageHandle
637 )
638 {
639 EFI_STATUS Status;
640 UINTN PageCount;
641 UINTN OrgPageCount;
642 EFI_PHYSICAL_ADDRESS DstBuffer;
643
644 if (FilePath == NULL || ImageHandle == NULL) {
645 return EFI_INVALID_PARAMETER;
646 }
647
648 PageCount = 1;
649 do {
650 OrgPageCount = PageCount;
651 DstBuffer = (UINTN)-1;
652 Status = gSmst->SmmAllocatePages (
653 AllocateMaxAddress,
654 EfiRuntimeServicesCode,
655 PageCount,
656 &DstBuffer
657 );
658 if (EFI_ERROR (Status)) {
659 return Status;
660 }
661
662 Status = mLoadPe32Image->LoadPeImage (
663 mLoadPe32Image,
664 ParentImageHandle,
665 FilePath,
666 SourceBuffer,
667 SourceSize,
668 DstBuffer,
669 &PageCount,
670 ImageHandle,
671 NULL,
672 EFI_LOAD_PE_IMAGE_ATTRIBUTE_NONE
673 );
674 if (EFI_ERROR (Status)) {
675 FreePages ((VOID *)(UINTN)DstBuffer, OrgPageCount);
676 }
677 } while (Status == EFI_BUFFER_TOO_SMALL);
678
679 if (!EFI_ERROR (Status)) {
680 ///
681 /// Update MP state in Framework SMST before transferring control to Framework SMM driver entry point
682 ///
683 mFrameworkSmst->SmmStartupThisAp = gSmst->SmmStartupThisAp;
684 mFrameworkSmst->NumberOfCpus = mNumberOfProcessors;
685 mFrameworkSmst->CurrentlyExecutingCpu = gSmst->CurrentlyExecutingCpu;
686
687 Status = gBS->StartImage (*ImageHandle, NULL, NULL);
688 if (EFI_ERROR (Status)) {
689 mLoadPe32Image->UnLoadPeImage (mLoadPe32Image, *ImageHandle);
690 *ImageHandle = NULL;
691 FreePages ((VOID *)(UINTN)DstBuffer, PageCount);
692 }
693 }
694
695 return Status;
696 }
697
698
699 /**
700 Thunk service of EFI_SMM_BASE_PROTOCOL.Register().
701
702 @param[in, out] FunctionData Pointer to SMMBASE_FUNCTION_DATA.
703 **/
704 VOID
705 Register (
706 IN OUT SMMBASE_FUNCTION_DATA *FunctionData
707 )
708 {
709 EFI_STATUS Status;
710
711 if (mLocked || FunctionData->Args.Register.LegacyIA32Binary) {
712 Status = EFI_UNSUPPORTED;
713 } else {
714 Status = LoadImage (
715 FunctionData->SmmBaseImageHandle,
716 FunctionData->Args.Register.FilePath,
717 FunctionData->Args.Register.SourceBuffer,
718 FunctionData->Args.Register.SourceSize,
719 FunctionData->Args.Register.ImageHandle
720 );
721 }
722 FunctionData->Status = Status;
723 }
724
725 /**
726 Thunk service of EFI_SMM_BASE_PROTOCOL.UnRegister().
727
728 @param[in, out] FunctionData Pointer to SMMBASE_FUNCTION_DATA.
729 **/
730 VOID
731 UnRegister (
732 IN OUT SMMBASE_FUNCTION_DATA *FunctionData
733 )
734 {
735 ///
736 /// Unregister not supported now
737 ///
738 FunctionData->Status = EFI_UNSUPPORTED;
739 }
740
741 /**
742 Search for Framework SMI handler information according to specific PI SMM dispatch handle.
743
744 @param[in] DispatchHandle The unique handle assigned by SmiHandlerRegister().
745
746 @return Pointer to CALLBACK_INFO. If NULL, no callback info record is found.
747 **/
748 CALLBACK_INFO *
749 GetCallbackInfo (
750 IN EFI_HANDLE DispatchHandle
751 )
752 {
753 LIST_ENTRY *Node;
754
755 Node = GetFirstNode (&mCallbackInfoListHead);
756 while (!IsNull (&mCallbackInfoListHead, Node)) {
757 if (((CALLBACK_INFO *)Node)->DispatchHandle == DispatchHandle) {
758 return (CALLBACK_INFO *)Node;
759 }
760 Node = GetNextNode (&mCallbackInfoListHead, Node);
761 }
762 return NULL;
763 }
764
765 /**
766 Callback thunk for Framework SMI handler.
767
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.
770
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.
777
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
781 still be called.
782 @retval EFI_WARN_INTERRUPT_SOURCE_PENDING The interrupt is still pending and other handlers should still
783 be called.
784 @retval EFI_INTERRUPT_PENDING The interrupt could not be quiesced.
785 **/
786 EFI_STATUS
787 EFIAPI
788 CallbackThunk (
789 IN EFI_HANDLE DispatchHandle,
790 IN CONST VOID *Context OPTIONAL,
791 IN OUT VOID *CommBuffer OPTIONAL,
792 IN OUT UINTN *CommBufferSize OPTIONAL
793 )
794 {
795 EFI_STATUS Status;
796 CALLBACK_INFO *CallbackInfo;
797 UINTN CpuIndex;
798
799 ///
800 /// Before transferring the control into the Framework SMI handler, update CPU Save States
801 /// and MP states in the Framework SMST.
802 ///
803
804 if (!mHookInitialized) {
805 InitHook (mFrameworkSmst);
806 }
807 if (mPageTableHookEnabled) {
808 HookCpuStateMemory (mFrameworkSmst->CpuSaveState);
809 CpuFlushTlb ();
810 } else {
811 for (CpuIndex = 0; CpuIndex < mNumberOfProcessors; CpuIndex++) {
812 ReadCpuSaveState (CpuIndex, NULL);
813 }
814 }
815
816 mFrameworkSmst->SmmStartupThisAp = gSmst->SmmStartupThisAp;
817 mFrameworkSmst->NumberOfCpus = mNumberOfProcessors;
818 mFrameworkSmst->CurrentlyExecutingCpu = gSmst->CurrentlyExecutingCpu;
819
820 ///
821 /// Search for Framework SMI handler information
822 ///
823 CallbackInfo = GetCallbackInfo (DispatchHandle);
824 ASSERT (CallbackInfo != NULL);
825
826 ///
827 /// Thunk into original Framwork SMI handler
828 ///
829 Status = (CallbackInfo->CallbackAddress) (
830 CallbackInfo->SmmImageHandle,
831 CallbackInfo->CommunicationBuffer,
832 CallbackInfo->SourceSize
833 );
834 ///
835 /// Save CPU Save States in case any of them was modified
836 ///
837 if (mPageTableHookEnabled) {
838 WriteBackDirtyPages ();
839 } else {
840 for (CpuIndex = 0; CpuIndex < mNumberOfProcessors; CpuIndex++) {
841 WriteCpuSaveState (CpuIndex, NULL);
842 }
843 }
844
845 ///
846 /// Conversion of returned status code
847 ///
848 switch (Status) {
849 case EFI_HANDLER_SUCCESS:
850 Status = EFI_WARN_INTERRUPT_SOURCE_QUIESCED;
851 break;
852 case EFI_HANDLER_CRITICAL_EXIT:
853 case EFI_HANDLER_SOURCE_QUIESCED:
854 Status = EFI_SUCCESS;
855 break;
856 case EFI_HANDLER_SOURCE_PENDING:
857 Status = EFI_WARN_INTERRUPT_SOURCE_PENDING;
858 break;
859 }
860 return Status;
861 }
862
863 /**
864 Thunk service of EFI_SMM_BASE_PROTOCOL.RegisterCallback().
865
866 @param[in, out] FunctionData Pointer to SMMBASE_FUNCTION_DATA.
867 **/
868 VOID
869 RegisterCallback (
870 IN OUT SMMBASE_FUNCTION_DATA *FunctionData
871 )
872 {
873 CALLBACK_INFO *Buffer;
874
875 if (mLocked) {
876 FunctionData->Status = EFI_UNSUPPORTED;
877 return;
878 }
879
880 ///
881 /// Note that MakeLast and FloatingPointSave options are not supported in PI SMM
882 ///
883
884 ///
885 /// Allocate buffer for callback thunk information
886 ///
887 Buffer = (CALLBACK_INFO *)AllocateZeroPool (sizeof (CALLBACK_INFO));
888 if (Buffer == NULL) {
889 FunctionData->Status = EFI_OUT_OF_RESOURCES;
890 return;
891 }
892
893 ///
894 /// Fill SmmImageHandle and CallbackAddress into the thunk
895 ///
896 Buffer->SmmImageHandle = FunctionData->Args.RegisterCallback.SmmImageHandle;
897 Buffer->CallbackAddress = FunctionData->Args.RegisterCallback.CallbackAddress;
898
899 ///
900 /// Register the thunk code as a root SMI handler
901 ///
902 FunctionData->Status = gSmst->SmiHandlerRegister (
903 CallbackThunk,
904 NULL,
905 &Buffer->DispatchHandle
906 );
907 if (EFI_ERROR (FunctionData->Status)) {
908 FreePool (Buffer);
909 return;
910 }
911
912 ///
913 /// Save this callback info
914 ///
915 InsertTailList (&mCallbackInfoListHead, &Buffer->Link);
916 }
917
918
919 /**
920 Thunk service of EFI_SMM_BASE_PROTOCOL.SmmAllocatePool().
921
922 @param[in, out] FunctionData Pointer to SMMBASE_FUNCTION_DATA.
923 **/
924 VOID
925 HelperAllocatePool (
926 IN OUT SMMBASE_FUNCTION_DATA *FunctionData
927 )
928 {
929 if (mLocked) {
930 FunctionData->Status = EFI_UNSUPPORTED;
931 } else {
932 FunctionData->Status = gSmst->SmmAllocatePool (
933 FunctionData->Args.AllocatePool.PoolType,
934 FunctionData->Args.AllocatePool.Size,
935 FunctionData->Args.AllocatePool.Buffer
936 );
937 }
938 }
939
940 /**
941 Thunk service of EFI_SMM_BASE_PROTOCOL.SmmFreePool().
942
943 @param[in, out] FunctionData Pointer to SMMBASE_FUNCTION_DATA.
944 **/
945 VOID
946 HelperFreePool (
947 IN OUT SMMBASE_FUNCTION_DATA *FunctionData
948 )
949 {
950 if (mLocked) {
951 FunctionData->Status = EFI_UNSUPPORTED;
952 } else {
953 FreePool (FunctionData->Args.FreePool.Buffer);
954 FunctionData->Status = EFI_SUCCESS;
955 }
956 }
957
958 /**
959 Thunk service of EFI_SMM_BASE_PROTOCOL.Communicate().
960
961 @param[in, out] FunctionData Pointer to SMMBASE_FUNCTION_DATA.
962 **/
963 VOID
964 HelperCommunicate (
965 IN OUT SMMBASE_FUNCTION_DATA *FunctionData
966 )
967 {
968 LIST_ENTRY *Node;
969 CALLBACK_INFO *CallbackInfo;
970
971 if (FunctionData->Args.Communicate.CommunicationBuffer == NULL) {
972 FunctionData->Status = EFI_INVALID_PARAMETER;
973 return;
974 }
975
976 Node = GetFirstNode (&mCallbackInfoListHead);
977 while (!IsNull (&mCallbackInfoListHead, Node)) {
978 CallbackInfo = (CALLBACK_INFO *)Node;
979
980 if (FunctionData->Args.Communicate.ImageHandle == CallbackInfo->SmmImageHandle) {
981 CallbackInfo->CommunicationBuffer = FunctionData->Args.Communicate.CommunicationBuffer;
982 CallbackInfo->SourceSize = FunctionData->Args.Communicate.SourceSize;
983
984 ///
985 /// The message was successfully posted.
986 ///
987 FunctionData->Status = EFI_SUCCESS;
988 return;
989 }
990 Node = GetNextNode (&mCallbackInfoListHead, Node);
991 }
992
993 FunctionData->Status = EFI_INVALID_PARAMETER;
994 }
995
996 /**
997 Communication service SMI Handler entry.
998
999 This SMI handler provides services for the SMM Base Thunk driver.
1000
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.
1007
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
1011 still be called.
1012 @retval EFI_WARN_INTERRUPT_SOURCE_PENDING The interrupt is still pending and other handlers should still
1013 be called.
1014 @retval EFI_INTERRUPT_PENDING The interrupt could not be quiesced.
1015 **/
1016 EFI_STATUS
1017 EFIAPI
1018 SmmHandlerEntry (
1019 IN EFI_HANDLE DispatchHandle,
1020 IN CONST VOID *RegisterContext,
1021 IN OUT VOID *CommBuffer,
1022 IN OUT UINTN *CommBufferSize
1023 )
1024 {
1025 SMMBASE_FUNCTION_DATA *FunctionData;
1026
1027 ASSERT (CommBuffer != NULL);
1028 ASSERT (*CommBufferSize == sizeof (SMMBASE_FUNCTION_DATA));
1029
1030 FunctionData = (SMMBASE_FUNCTION_DATA *)CommBuffer;
1031
1032 switch (FunctionData->Function) {
1033 case SmmBaseFunctionRegister:
1034 Register (FunctionData);
1035 break;
1036 case SmmBaseFunctionUnregister:
1037 UnRegister (FunctionData);
1038 break;
1039 case SmmBaseFunctionRegisterCallback:
1040 RegisterCallback (FunctionData);
1041 break;
1042 case SmmBaseFunctionAllocatePool:
1043 HelperAllocatePool (FunctionData);
1044 break;
1045 case SmmBaseFunctionFreePool:
1046 HelperFreePool (FunctionData);
1047 break;
1048 case SmmBaseFunctionCommunicate:
1049 HelperCommunicate (FunctionData);
1050 break;
1051 default:
1052 ASSERT (FALSE);
1053 FunctionData->Status = EFI_UNSUPPORTED;
1054 }
1055 return EFI_SUCCESS;
1056 }
1057
1058 /**
1059 Smm Ready To Lock event notification handler.
1060
1061 It sets a flag indicating that SMRAM has been locked.
1062
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.
1066
1067 @retval EFI_SUCCESS Notification handler runs successfully.
1068 **/
1069 EFI_STATUS
1070 EFIAPI
1071 SmmReadyToLockEventNotify (
1072 IN CONST EFI_GUID *Protocol,
1073 IN VOID *Interface,
1074 IN EFI_HANDLE Handle
1075 )
1076 {
1077 mLocked = TRUE;
1078 return EFI_SUCCESS;
1079 }
1080
1081 /**
1082 Entry point function of the SMM Base Helper SMM driver.
1083
1084 @param[in] ImageHandle The firmware allocated handle for the EFI image.
1085 @param[in] SystemTable A pointer to the EFI System Table.
1086
1087 @retval EFI_SUCCESS The entry point is executed successfully.
1088 @retval other Some error occurs when executing this entry point.
1089 **/
1090 EFI_STATUS
1091 EFIAPI
1092 SmmBaseHelperMain (
1093 IN EFI_HANDLE ImageHandle,
1094 IN EFI_SYSTEM_TABLE *SystemTable
1095 )
1096 {
1097 EFI_STATUS Status;
1098 EFI_MP_SERVICES_PROTOCOL *MpServices;
1099 EFI_HANDLE Handle;
1100 UINTN NumberOfEnabledProcessors;
1101 VOID *Registration;
1102
1103 Handle = NULL;
1104 ///
1105 /// Locate SMM CPU Protocol which is used later to retrieve/update CPU Save States
1106 ///
1107 Status = gSmst->SmmLocateProtocol (&gEfiSmmCpuProtocolGuid, NULL, (VOID **) &mSmmCpu);
1108 ASSERT_EFI_ERROR (Status);
1109
1110 ///
1111 /// Locate PE32 Image Protocol which is used later to load Framework SMM driver
1112 ///
1113 Status = SystemTable->BootServices->LocateProtocol (&gEfiLoadPeImageProtocolGuid, NULL, (VOID **) &mLoadPe32Image);
1114 ASSERT_EFI_ERROR (Status);
1115
1116 //
1117 // Get MP Services Protocol
1118 //
1119 Status = SystemTable->BootServices->LocateProtocol (&gEfiMpServiceProtocolGuid, NULL, (VOID **)&MpServices);
1120 ASSERT_EFI_ERROR (Status);
1121
1122 //
1123 // Use MP Services Protocol to retrieve the number of processors and number of enabled processors
1124 //
1125 Status = MpServices->GetNumberOfProcessors (MpServices, &mNumberOfProcessors, &NumberOfEnabledProcessors);
1126 ASSERT_EFI_ERROR (Status);
1127
1128 ///
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.
1131 ///
1132 Status = gBS->AllocatePool (
1133 EfiBootServicesData,
1134 sizeof (EFI_SMM_BASE_HELPER_READY_PROTOCOL),
1135 (VOID **)&mSmmBaseHelperReady
1136 );
1137 ASSERT_EFI_ERROR (Status);
1138
1139 ///
1140 /// Construct Framework SMST from PI SMST
1141 ///
1142 mFrameworkSmst = ConstructFrameworkSmst ();
1143 mSmmBaseHelperReady->FrameworkSmst = mFrameworkSmst;
1144 mSmmBaseHelperReady->ServiceEntry = SmmHandlerEntry;
1145
1146 //
1147 // Register SMM Ready To Lock Protocol notification
1148 //
1149 Status = gSmst->SmmRegisterProtocolNotify (
1150 &gEfiSmmReadyToLockProtocolGuid,
1151 SmmReadyToLockEventNotify,
1152 &Registration
1153 );
1154 ASSERT_EFI_ERROR (Status);
1155
1156 ///
1157 /// Register SMM Base Helper services for SMM Base Thunk driver
1158 ///
1159 Status = gSmst->SmiHandlerRegister (SmmHandlerEntry, &gEfiSmmBaseThunkCommunicationGuid, &mDispatchHandle);
1160 ASSERT_EFI_ERROR (Status);
1161
1162 ///
1163 /// Install EFI SMM Base Helper Protocol in the UEFI handle database
1164 ///
1165 Status = gBS->InstallProtocolInterface (
1166 &Handle,
1167 &gEfiSmmBaseHelperReadyProtocolGuid,
1168 EFI_NATIVE_INTERFACE,
1169 mSmmBaseHelperReady
1170 );
1171 ASSERT_EFI_ERROR (Status);
1172
1173 return Status;
1174 }
1175