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