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