]> git.proxmox.com Git - mirror_edk2.git/blame - EdkCompatibilityPkg/Compatibility/SmmBaseHelper/SmmBaseHelper.c
Add missing Type 35 support and correct SmbiosFldMiscType13 implementation.
[mirror_edk2.git] / EdkCompatibilityPkg / Compatibility / SmmBaseHelper / SmmBaseHelper.c
CommitLineData
9e620719 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
584d5652
HT
7 Copyright (c) 2009 - 2010, Intel Corporation. All rights reserved.<BR>\r
8 This program and the accompanying materials\r
9e620719 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
a7932d9a 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
27af6f9d 27#include <Library/MemoryAllocationLib.h>\r
ff443d3e 28#include <Library/SynchronizationLib.h>\r
29#include <Library/CpuLib.h>\r
a7932d9a 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
e906eae4 35#include <Protocol/MpService.h>\r
673c1498 36#include <Protocol/LoadPe32Image.h>\r
8edfbe02 37#include <Protocol/SmmReadyToLock.h>\r
a7932d9a 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
18e78927 48 VOID *CommunicationBuffer;\r
49 UINTN *SourceSize;\r
a7932d9a 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
9e620719 65\r
66EFI_HANDLE mDispatchHandle;\r
67EFI_SMM_CPU_PROTOCOL *mSmmCpu;\r
673c1498 68EFI_PE32_IMAGE_PROTOCOL *mLoadPe32Image;\r
9e620719 69EFI_GUID mEfiSmmCpuIoGuid = EFI_SMM_CPU_IO_GUID;\r
70EFI_SMM_BASE_HELPER_READY_PROTOCOL *mSmmBaseHelperReady;\r
71EFI_SMM_SYSTEM_TABLE *mFrameworkSmst;\r
e906eae4 72UINTN mNumberOfProcessors;\r
8edfbe02 73BOOLEAN mLocked = FALSE;\r
ff443d3e 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
9e620719 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
e9ba23c7
LG
109/**\r
110 Page fault handler.\r
111\r
112**/\r
ff443d3e 113VOID\r
114PageFaultHandlerHook (\r
115 VOID\r
116 );\r
117\r
097e25cb 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
ff443d3e 129VOID\r
130ReadCpuSaveState (\r
097e25cb 131 IN UINTN CpuIndex,\r
132 IN OUT EFI_SMM_CPU_SAVE_STATE *ToRead\r
ff443d3e 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
097e25cb 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
ff443d3e 185VOID\r
186WriteCpuSaveState (\r
097e25cb 187 IN UINTN CpuIndex,\r
188 IN EFI_SMM_CPU_SAVE_STATE *ToWrite\r
ff443d3e 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
097e25cb 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
ff443d3e 228VOID\r
229ReadWriteCpuStatePage (\r
097e25cb 230 IN UINT64 PageAddress,\r
231 IN BOOLEAN IsRead\r
ff443d3e 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
097e25cb 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
ff443d3e 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
097e25cb 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
ff443d3e 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
9af300fc
LG
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
ff443d3e 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
097e25cb 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
ff443d3e 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
097e25cb 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
ff443d3e 391UINT64 *\r
392InitCpuStatePageTable (\r
097e25cb 393 IN VOID *HookData\r
ff443d3e 394 )\r
395{\r
396 UINTN Index;\r
397 UINT64 *PageTable;\r
e9ba23c7 398 UINT64 *Pdpte;\r
ff443d3e 399 UINT64 HookAddress;\r
e9ba23c7 400 UINT64 Pde;\r
ff443d3e 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
e9ba23c7
LG
416 Pdpte = (UINT64 *)(UINTN)PageTable;\r
417 Pde = Pdpte[BitFieldRead64 (HookAddress, 21, 29)];\r
418 ASSERT ((Pde & BIT0) != 0); // Present and 2M Page\r
ff443d3e 419 \r
e9ba23c7
LG
420 if ((Pde & BIT7) == 0) { // 4KB Page Directory\r
421 PageTable = (UINT64 *)(UINTN)(Pde & mPhyMask);\r
ff443d3e 422 } else {\r
e9ba23c7 423 ASSERT ((Pde & mPhyMask) == (HookAddress & ~(SIZE_2MB-1))); // 2MB Page Point to HookAddress\r
ff443d3e 424 PageTable = AllocatePages (1);\r
983ae8ce 425 ASSERT (PageTable != NULL);\r
ff443d3e 426 Address = HookAddress & ~(SIZE_2MB-1);\r
427 for (Index = 0; Index < 512; Index++) {\r
428 PageTable[Index] = Address | BIT0 | BIT1; // Present and RW\r
429 Address += SIZE_4KB;\r
430 }\r
e9ba23c7 431 Pdpte[BitFieldRead64 (HookAddress, 21, 29)] = (UINT64)(UINTN)PageTable | BIT0 | BIT1; // Present and RW\r
ff443d3e 432 }\r
433 return PageTable;\r
434}\r
435\r
097e25cb 436/**\r
437 Mark all the CpuSaveStates as not present.\r
438 \r
439 The function marks all CpuSaveStates memory range as not present so that page fault can be triggered\r
440 on CpuSaveStates access. It is meant to be called on each SmmBaseHelper SMI callback before Framework\r
441 handler is called.\r
442\r
443 @param[in] CpuSaveState The base of CpuSaveStates.\r
444\r
445**/\r
ff443d3e 446VOID\r
447HookCpuStateMemory (\r
097e25cb 448 IN EFI_SMM_CPU_SAVE_STATE *CpuSaveState\r
ff443d3e 449 )\r
450{\r
451 UINT64 Index;\r
452 UINT64 PTStartIndex;\r
453 UINT64 PTEndIndex;\r
454\r
455 PTStartIndex = BitFieldRead64 ((UINTN)CpuSaveState, 12, 20);\r
456 PTEndIndex = BitFieldRead64 ((UINTN)CpuSaveState + mNumberOfProcessors * sizeof (EFI_SMM_CPU_SAVE_STATE) - 1, 12, 20);\r
457 for (Index = PTStartIndex; Index <= PTEndIndex; Index++) {\r
458 mCpuStatePageTable[Index] &= ~(BIT0|BIT5|BIT6); // not present nor accessed nor dirty\r
459 }\r
460} \r
461\r
9e620719 462/**\r
463 Framework SMST SmmInstallConfigurationTable() Thunk.\r
464\r
465 This thunk calls the PI SMM SmmInstallConfigurationTable() and then update the configuration\r
466 table related fields in the Framework SMST because the PI SMM SmmInstallConfigurationTable()\r
467 function may modify these fields.\r
468\r
469 @param[in] SystemTable A pointer to the SMM System Table.\r
470 @param[in] Guid A pointer to the GUID for the entry to add, update, or remove.\r
471 @param[in] Table A pointer to the buffer of the table to add.\r
472 @param[in] TableSize The size of the table to install.\r
473\r
474 @retval EFI_SUCCESS The (Guid, Table) pair was added, updated, or removed.\r
475 @retval EFI_INVALID_PARAMETER Guid is not valid.\r
476 @retval EFI_NOT_FOUND An attempt was made to delete a non-existent entry.\r
477 @retval EFI_OUT_OF_RESOURCES There is not enough memory available to complete the operation.\r
478**/\r
479EFI_STATUS\r
480EFIAPI\r
481SmmInstallConfigurationTable (\r
482 IN EFI_SMM_SYSTEM_TABLE *SystemTable,\r
483 IN EFI_GUID *Guid,\r
484 IN VOID *Table,\r
485 IN UINTN TableSize\r
486 )\r
487{\r
488 EFI_STATUS Status;\r
489 \r
490 Status = gSmst->SmmInstallConfigurationTable (gSmst, Guid, Table, TableSize);\r
491 if (!EFI_ERROR (Status)) {\r
492 mFrameworkSmst->NumberOfTableEntries = gSmst->NumberOfTableEntries;\r
493 mFrameworkSmst->SmmConfigurationTable = gSmst->SmmConfigurationTable;\r
494 }\r
495 return Status; \r
496}\r
497\r
097e25cb 498/**\r
499 Initialize all the stuff needed for on-demand paging hooks for PI<->Framework\r
500 CpuSaveStates marshalling.\r
501\r
502 @param[in] FrameworkSmst Framework SMM system table pointer.\r
503\r
504**/\r
ff443d3e 505VOID\r
506InitHook (\r
097e25cb 507 IN EFI_SMM_SYSTEM_TABLE *FrameworkSmst\r
ff443d3e 508 )\r
509{\r
510 UINTN NumCpuStatePages;\r
511 UINTN CpuStatePage;\r
512 UINTN Bottom2MPage;\r
513 UINTN Top2MPage;\r
514 \r
515 mPageTableHookEnabled = FALSE;\r
516 NumCpuStatePages = EFI_SIZE_TO_PAGES (mNumberOfProcessors * sizeof (EFI_SMM_CPU_SAVE_STATE));\r
517 //\r
518 // Only hook page table for X64 image and less than 2MB needed to hold all CPU Save States\r
519 //\r
520 if (EFI_IMAGE_MACHINE_TYPE_SUPPORTED(EFI_IMAGE_MACHINE_X64) && NumCpuStatePages <= EFI_SIZE_TO_PAGES (SIZE_2MB)) {\r
521 //\r
522 // Allocate double page size to make sure all CPU Save States are in one 2MB page.\r
523 //\r
524 CpuStatePage = (UINTN)AllocatePages (NumCpuStatePages * 2);\r
525 ASSERT (CpuStatePage != 0);\r
526 Bottom2MPage = CpuStatePage & ~(SIZE_2MB-1);\r
527 Top2MPage = (CpuStatePage + EFI_PAGES_TO_SIZE (NumCpuStatePages * 2) - 1) & ~(SIZE_2MB-1);\r
528 if (Bottom2MPage == Top2MPage ||\r
529 CpuStatePage + EFI_PAGES_TO_SIZE (NumCpuStatePages * 2) - Top2MPage >= EFI_PAGES_TO_SIZE (NumCpuStatePages)\r
530 ) {\r
531 //\r
532 // If the allocated 4KB pages are within the same 2MB page or higher portion is larger, use higher portion pages.\r
533 //\r
534 FrameworkSmst->CpuSaveState = (EFI_SMM_CPU_SAVE_STATE *)(CpuStatePage + EFI_PAGES_TO_SIZE (NumCpuStatePages));\r
535 FreePages ((VOID*)CpuStatePage, NumCpuStatePages);\r
536 } else {\r
537 FrameworkSmst->CpuSaveState = (EFI_SMM_CPU_SAVE_STATE *)CpuStatePage;\r
538 FreePages ((VOID*)(CpuStatePage + EFI_PAGES_TO_SIZE (NumCpuStatePages)), NumCpuStatePages);\r
539 }\r
540 //\r
541 // Add temporary working buffer for hooking\r
542 //\r
543 mShadowSaveState = (EFI_SMM_CPU_SAVE_STATE*) AllocatePool (sizeof (EFI_SMM_CPU_SAVE_STATE));\r
544 ASSERT (mShadowSaveState != NULL);\r
545 //\r
546 // Allocate and initialize 4KB Page Table for hooking CpuSaveState.\r
547 // Replace the original 2MB PDE with new 4KB page table.\r
548 //\r
549 mCpuStatePageTable = InitCpuStatePageTable (FrameworkSmst->CpuSaveState);\r
550 //\r
551 // Mark PTE for CpuSaveState as non-exist.\r
552 //\r
553 HookCpuStateMemory (FrameworkSmst->CpuSaveState);\r
554 HookPageFaultHandler ();\r
555 CpuFlushTlb ();\r
556 mPageTableHookEnabled = TRUE;\r
557 }\r
558 mHookInitialized = TRUE;\r
559}\r
560\r
9e620719 561/**\r
562 Construct a Framework SMST based on the PI SMM SMST.\r
563\r
564 @return Pointer to the constructed Framework SMST.\r
565**/\r
566EFI_SMM_SYSTEM_TABLE *\r
567ConstructFrameworkSmst (\r
568 VOID\r
569 )\r
570{\r
9e620719 571 EFI_SMM_SYSTEM_TABLE *FrameworkSmst;\r
572\r
27af6f9d 573 FrameworkSmst = (EFI_SMM_SYSTEM_TABLE *)AllocatePool (sizeof (EFI_SMM_SYSTEM_TABLE));\r
574 ASSERT (FrameworkSmst != NULL);\r
9e620719 575\r
576 ///\r
577 /// Copy same things from PI SMST to Framework SMST\r
578 ///\r
579 CopyMem (FrameworkSmst, gSmst, (UINTN)(&((EFI_SMM_SYSTEM_TABLE *)0)->SmmIo));\r
580 CopyMem (\r
581 &FrameworkSmst->SmmIo, \r
582 &gSmst->SmmIo,\r
583 sizeof (EFI_SMM_SYSTEM_TABLE) - (UINTN)(&((EFI_SMM_SYSTEM_TABLE *)0)->SmmIo)\r
584 );\r
585\r
586 ///\r
587 /// Update Framework SMST\r
588 ///\r
589 FrameworkSmst->Hdr.Revision = EFI_SMM_SYSTEM_TABLE_REVISION;\r
590 CopyGuid (&FrameworkSmst->EfiSmmCpuIoGuid, &mEfiSmmCpuIoGuid);\r
591\r
ff443d3e 592 mHookInitialized = FALSE;\r
e906eae4 593 FrameworkSmst->CpuSaveState = (EFI_SMM_CPU_SAVE_STATE *)AllocateZeroPool (mNumberOfProcessors * sizeof (EFI_SMM_CPU_SAVE_STATE));\r
27af6f9d 594 ASSERT (FrameworkSmst->CpuSaveState != NULL);\r
9e620719 595\r
596 ///\r
597 /// Do not support floating point state now\r
598 ///\r
599 FrameworkSmst->CpuOptionalFloatingPointState = NULL;\r
600\r
601 FrameworkSmst->SmmInstallConfigurationTable = SmmInstallConfigurationTable;\r
602\r
603 return FrameworkSmst;\r
604}\r
605\r
606/**\r
607 Load a given Framework SMM driver into SMRAM and invoke its entry point.\r
608\r
673c1498 609 @param[in] ParentImageHandle Parent Image Handle.\r
9e620719 610 @param[in] FilePath Location of the image to be installed as the handler.\r
611 @param[in] SourceBuffer Optional source buffer in case the image file\r
612 is in memory.\r
613 @param[in] SourceSize Size of the source image file, if in memory.\r
614 @param[out] ImageHandle The handle that the base driver uses to decode \r
615 the handler. Unique among SMM handlers only, \r
616 not unique across DXE/EFI.\r
617\r
618 @retval EFI_SUCCESS The operation was successful.\r
619 @retval EFI_OUT_OF_RESOURCES There were no additional SMRAM resources to load the handler\r
620 @retval EFI_UNSUPPORTED Can not find its copy in normal memory.\r
621 @retval EFI_INVALID_PARAMETER The handlers was not the correct image type\r
622**/\r
623EFI_STATUS\r
624LoadImage (\r
673c1498 625 IN EFI_HANDLE ParentImageHandle,\r
9e620719 626 IN EFI_DEVICE_PATH_PROTOCOL *FilePath,\r
627 IN VOID *SourceBuffer,\r
628 IN UINTN SourceSize,\r
629 OUT EFI_HANDLE *ImageHandle\r
630 )\r
631{\r
673c1498 632 EFI_STATUS Status;\r
633 UINTN PageCount;\r
634 UINTN OrgPageCount;\r
635 EFI_PHYSICAL_ADDRESS DstBuffer;\r
9e620719 636\r
637 if (FilePath == NULL || ImageHandle == NULL) { \r
638 return EFI_INVALID_PARAMETER;\r
639 }\r
640\r
673c1498 641 PageCount = 1;\r
642 do {\r
643 OrgPageCount = PageCount;\r
644 DstBuffer = (UINTN)-1;\r
645 Status = gSmst->SmmAllocatePages (\r
646 AllocateMaxAddress,\r
647 EfiRuntimeServicesCode,\r
648 PageCount,\r
649 &DstBuffer\r
9e620719 650 );\r
673c1498 651 if (EFI_ERROR (Status)) {\r
652 return Status;\r
9e620719 653 }\r
654\r
673c1498 655 Status = mLoadPe32Image->LoadPeImage (\r
656 mLoadPe32Image,\r
657 ParentImageHandle,\r
658 FilePath,\r
659 SourceBuffer,\r
660 SourceSize,\r
661 DstBuffer,\r
662 &PageCount,\r
663 ImageHandle,\r
664 NULL,\r
665 EFI_LOAD_PE_IMAGE_ATTRIBUTE_NONE\r
666 );\r
667 if (EFI_ERROR (Status)) {\r
668 FreePages ((VOID *)(UINTN)DstBuffer, OrgPageCount);\r
9e620719 669 }\r
673c1498 670 } while (Status == EFI_BUFFER_TOO_SMALL);\r
9e620719 671\r
9e620719 672 if (!EFI_ERROR (Status)) {\r
673c1498 673 ///\r
674 /// Update MP state in Framework SMST before transferring control to Framework SMM driver entry point\r
673c1498 675 ///\r
5b9fc2f0 676 mFrameworkSmst->SmmStartupThisAp = gSmst->SmmStartupThisAp;\r
677 mFrameworkSmst->NumberOfCpus = mNumberOfProcessors;\r
673c1498 678 mFrameworkSmst->CurrentlyExecutingCpu = gSmst->CurrentlyExecutingCpu;\r
679\r
680 Status = gBS->StartImage (*ImageHandle, NULL, NULL);\r
681 if (EFI_ERROR (Status)) {\r
682 mLoadPe32Image->UnLoadPeImage (mLoadPe32Image, *ImageHandle);\r
683 *ImageHandle = NULL;\r
684 FreePages ((VOID *)(UINTN)DstBuffer, PageCount);\r
685 }\r
9e620719 686 }\r
687\r
673c1498 688 return Status;\r
9e620719 689}\r
690\r
673c1498 691\r
9e620719 692/** \r
693 Thunk service of EFI_SMM_BASE_PROTOCOL.Register().\r
694\r
17d2c9a3 695 @param[in, out] FunctionData Pointer to SMMBASE_FUNCTION_DATA.\r
696**/\r
9e620719 697VOID\r
698Register (\r
699 IN OUT SMMBASE_FUNCTION_DATA *FunctionData\r
700 )\r
701{\r
702 EFI_STATUS Status;\r
703\r
8edfbe02 704 if (mLocked || FunctionData->Args.Register.LegacyIA32Binary) {\r
9e620719 705 Status = EFI_UNSUPPORTED;\r
706 } else {\r
707 Status = LoadImage (\r
673c1498 708 FunctionData->SmmBaseImageHandle,\r
9e620719 709 FunctionData->Args.Register.FilePath,\r
710 FunctionData->Args.Register.SourceBuffer,\r
711 FunctionData->Args.Register.SourceSize,\r
712 FunctionData->Args.Register.ImageHandle\r
713 );\r
714 }\r
715 FunctionData->Status = Status;\r
716}\r
717\r
718/** \r
719 Thunk service of EFI_SMM_BASE_PROTOCOL.UnRegister().\r
720\r
17d2c9a3 721 @param[in, out] FunctionData Pointer to SMMBASE_FUNCTION_DATA.\r
722**/\r
9e620719 723VOID\r
724UnRegister (\r
725 IN OUT SMMBASE_FUNCTION_DATA *FunctionData\r
726 )\r
727{\r
728 ///\r
729 /// Unregister not supported now\r
730 ///\r
731 FunctionData->Status = EFI_UNSUPPORTED;\r
732}\r
733\r
734/**\r
735 Search for Framework SMI handler information according to specific PI SMM dispatch handle.\r
736\r
737 @param[in] DispatchHandle The unique handle assigned by SmiHandlerRegister(). \r
738\r
17d2c9a3 739 @return Pointer to CALLBACK_INFO. If NULL, no callback info record is found.\r
9e620719 740**/\r
741CALLBACK_INFO *\r
742GetCallbackInfo (\r
743 IN EFI_HANDLE DispatchHandle\r
744 )\r
745{\r
746 LIST_ENTRY *Node;\r
747\r
748 Node = GetFirstNode (&mCallbackInfoListHead);\r
749 while (!IsNull (&mCallbackInfoListHead, Node)) {\r
750 if (((CALLBACK_INFO *)Node)->DispatchHandle == DispatchHandle) {\r
751 return (CALLBACK_INFO *)Node;\r
752 }\r
753 Node = GetNextNode (&mCallbackInfoListHead, Node);\r
754 }\r
755 return NULL;\r
756}\r
757\r
758/**\r
759 Callback thunk for Framework SMI handler.\r
760\r
761 This thunk functions calls the Framework SMI handler and converts the return value\r
762 defined from Framework SMI handlers to a correpsonding return value defined by PI SMM.\r
763\r
764 @param[in] DispatchHandle The unique handle assigned to this handler by SmiHandlerRegister().\r
765 @param[in] Context Points to an optional handler context which was specified when the\r
766 handler was registered.\r
26a76fbc 767 @param[in, out] CommBuffer A pointer to a collection of data in memory that will\r
9e620719 768 be conveyed from a non-SMM environment into an SMM environment.\r
26a76fbc 769 @param[in, out] CommBufferSize The size of the CommBuffer.\r
9e620719 770\r
771 @retval EFI_SUCCESS The interrupt was handled and quiesced. No other handlers \r
772 should still be called.\r
773 @retval EFI_WARN_INTERRUPT_SOURCE_QUIESCED The interrupt has been quiesced but other handlers should \r
774 still be called.\r
775 @retval EFI_WARN_INTERRUPT_SOURCE_PENDING The interrupt is still pending and other handlers should still \r
776 be called.\r
777 @retval EFI_INTERRUPT_PENDING The interrupt could not be quiesced.\r
778**/\r
779EFI_STATUS\r
780EFIAPI\r
781CallbackThunk (\r
782 IN EFI_HANDLE DispatchHandle,\r
783 IN CONST VOID *Context OPTIONAL,\r
784 IN OUT VOID *CommBuffer OPTIONAL,\r
785 IN OUT UINTN *CommBufferSize OPTIONAL\r
786 )\r
787{\r
788 EFI_STATUS Status;\r
789 CALLBACK_INFO *CallbackInfo;\r
9e620719 790 UINTN CpuIndex;\r
9e620719 791\r
792 ///\r
793 /// Before transferring the control into the Framework SMI handler, update CPU Save States\r
794 /// and MP states in the Framework SMST.\r
795 ///\r
796\r
ff443d3e 797 if (!mHookInitialized) {\r
798 InitHook (mFrameworkSmst);\r
799 }\r
800 if (mPageTableHookEnabled) {\r
801 HookCpuStateMemory (mFrameworkSmst->CpuSaveState);\r
802 CpuFlushTlb ();\r
803 } else {\r
804 for (CpuIndex = 0; CpuIndex < mNumberOfProcessors; CpuIndex++) {\r
805 ReadCpuSaveState (CpuIndex, NULL);\r
9e620719 806 }\r
807 }\r
808\r
33f30f1e 809 mFrameworkSmst->SmmStartupThisAp = gSmst->SmmStartupThisAp;\r
810 mFrameworkSmst->NumberOfCpus = mNumberOfProcessors;\r
9e620719 811 mFrameworkSmst->CurrentlyExecutingCpu = gSmst->CurrentlyExecutingCpu;\r
812\r
813 ///\r
814 /// Search for Framework SMI handler information\r
815 ///\r
816 CallbackInfo = GetCallbackInfo (DispatchHandle);\r
817 ASSERT (CallbackInfo != NULL);\r
818\r
819 ///\r
820 /// Thunk into original Framwork SMI handler\r
821 ///\r
822 Status = (CallbackInfo->CallbackAddress) (\r
823 CallbackInfo->SmmImageHandle,\r
18e78927 824 CallbackInfo->CommunicationBuffer,\r
825 CallbackInfo->SourceSize\r
9e620719 826 );\r
827 ///\r
828 /// Save CPU Save States in case any of them was modified\r
829 ///\r
ff443d3e 830 if (mPageTableHookEnabled) {\r
831 WriteBackDirtyPages ();\r
832 } else {\r
833 for (CpuIndex = 0; CpuIndex < mNumberOfProcessors; CpuIndex++) {\r
834 WriteCpuSaveState (CpuIndex, NULL);\r
9e620719 835 }\r
836 }\r
837\r
838 ///\r
839 /// Conversion of returned status code\r
840 ///\r
841 switch (Status) {\r
842 case EFI_HANDLER_SUCCESS:\r
843 Status = EFI_WARN_INTERRUPT_SOURCE_QUIESCED;\r
844 break;\r
845 case EFI_HANDLER_CRITICAL_EXIT:\r
846 case EFI_HANDLER_SOURCE_QUIESCED:\r
847 Status = EFI_SUCCESS;\r
848 break;\r
849 case EFI_HANDLER_SOURCE_PENDING:\r
850 Status = EFI_WARN_INTERRUPT_SOURCE_PENDING;\r
851 break;\r
852 }\r
853 return Status;\r
854}\r
855\r
856/** \r
857 Thunk service of EFI_SMM_BASE_PROTOCOL.RegisterCallback().\r
858\r
17d2c9a3 859 @param[in, out] FunctionData Pointer to SMMBASE_FUNCTION_DATA.\r
860**/\r
9e620719 861VOID\r
862RegisterCallback (\r
27af6f9d 863 IN OUT SMMBASE_FUNCTION_DATA *FunctionData\r
9e620719 864 )\r
865{\r
9e620719 866 CALLBACK_INFO *Buffer;\r
867\r
8edfbe02 868 if (mLocked) {\r
869 FunctionData->Status = EFI_UNSUPPORTED;\r
870 return;\r
871 }\r
872\r
9e620719 873 ///\r
874 /// Note that MakeLast and FloatingPointSave options are not supported in PI SMM\r
875 ///\r
876\r
877 ///\r
878 /// Allocate buffer for callback thunk information\r
879 ///\r
18e78927 880 Buffer = (CALLBACK_INFO *)AllocateZeroPool (sizeof (CALLBACK_INFO));\r
27af6f9d 881 if (Buffer == NULL) {\r
882 FunctionData->Status = EFI_OUT_OF_RESOURCES;\r
883 return;\r
9e620719 884 }\r
27af6f9d 885\r
886 ///\r
887 /// Fill SmmImageHandle and CallbackAddress into the thunk\r
888 ///\r
889 Buffer->SmmImageHandle = FunctionData->Args.RegisterCallback.SmmImageHandle;\r
890 Buffer->CallbackAddress = FunctionData->Args.RegisterCallback.CallbackAddress;\r
891\r
892 ///\r
893 /// Register the thunk code as a root SMI handler\r
894 ///\r
895 FunctionData->Status = gSmst->SmiHandlerRegister (\r
896 CallbackThunk,\r
897 NULL,\r
898 &Buffer->DispatchHandle\r
899 );\r
900 if (EFI_ERROR (FunctionData->Status)) {\r
901 FreePool (Buffer);\r
902 return;\r
903 }\r
904\r
905 ///\r
906 /// Save this callback info\r
907 ///\r
908 InsertTailList (&mCallbackInfoListHead, &Buffer->Link);\r
9e620719 909}\r
910\r
911\r
912/** \r
913 Thunk service of EFI_SMM_BASE_PROTOCOL.SmmAllocatePool().\r
914\r
17d2c9a3 915 @param[in, out] FunctionData Pointer to SMMBASE_FUNCTION_DATA.\r
916**/\r
9e620719 917VOID\r
918HelperAllocatePool (\r
919 IN OUT SMMBASE_FUNCTION_DATA *FunctionData\r
920 )\r
921{\r
8edfbe02 922 if (mLocked) {\r
923 FunctionData->Status = EFI_UNSUPPORTED;\r
924 } else {\r
925 FunctionData->Status = gSmst->SmmAllocatePool (\r
926 FunctionData->Args.AllocatePool.PoolType,\r
927 FunctionData->Args.AllocatePool.Size,\r
928 FunctionData->Args.AllocatePool.Buffer\r
929 );\r
930 }\r
9e620719 931}\r
932\r
933/** \r
934 Thunk service of EFI_SMM_BASE_PROTOCOL.SmmFreePool().\r
935\r
17d2c9a3 936 @param[in, out] FunctionData Pointer to SMMBASE_FUNCTION_DATA.\r
937**/\r
9e620719 938VOID\r
939HelperFreePool (\r
940 IN OUT SMMBASE_FUNCTION_DATA *FunctionData\r
941 )\r
942{\r
8edfbe02 943 if (mLocked) {\r
944 FunctionData->Status = EFI_UNSUPPORTED;\r
945 } else {\r
946 FreePool (FunctionData->Args.FreePool.Buffer);\r
947 FunctionData->Status = EFI_SUCCESS;\r
948 }\r
9e620719 949}\r
950\r
bade9bf5 951/** \r
952 Thunk service of EFI_SMM_BASE_PROTOCOL.Communicate().\r
953\r
954 @param[in, out] FunctionData Pointer to SMMBASE_FUNCTION_DATA.\r
955**/\r
956VOID\r
957HelperCommunicate (\r
958 IN OUT SMMBASE_FUNCTION_DATA *FunctionData\r
959 )\r
960{\r
961 LIST_ENTRY *Node;\r
962 CALLBACK_INFO *CallbackInfo;\r
963\r
964 if (FunctionData->Args.Communicate.CommunicationBuffer == NULL) {\r
965 FunctionData->Status = EFI_INVALID_PARAMETER;\r
966 return;\r
967 }\r
968\r
969 Node = GetFirstNode (&mCallbackInfoListHead);\r
970 while (!IsNull (&mCallbackInfoListHead, Node)) {\r
971 CallbackInfo = (CALLBACK_INFO *)Node;\r
972\r
973 if (FunctionData->Args.Communicate.ImageHandle == CallbackInfo->SmmImageHandle) {\r
18e78927 974 CallbackInfo->CommunicationBuffer = FunctionData->Args.Communicate.CommunicationBuffer;\r
975 CallbackInfo->SourceSize = FunctionData->Args.Communicate.SourceSize;\r
976\r
bade9bf5 977 ///\r
978 /// The message was successfully posted.\r
979 ///\r
980 FunctionData->Status = EFI_SUCCESS;\r
981 return;\r
982 }\r
983 Node = GetNextNode (&mCallbackInfoListHead, Node);\r
984 }\r
985\r
986 FunctionData->Status = EFI_INVALID_PARAMETER;\r
987}\r
988\r
9e620719 989/**\r
990 Communication service SMI Handler entry.\r
991\r
992 This SMI handler provides services for the SMM Base Thunk driver.\r
993\r
994 @param[in] DispatchHandle The unique handle assigned to this handler by SmiHandlerRegister().\r
26a76fbc 995 @param[in] RegisterContext Points to an optional handler context which was specified when the\r
9e620719 996 handler was registered.\r
26a76fbc 997 @param[in, out] CommBuffer A pointer to a collection of data in memory that will\r
9e620719 998 be conveyed from a non-SMM environment into an SMM environment.\r
26a76fbc 999 @param[in, out] CommBufferSize The size of the CommBuffer.\r
9e620719 1000\r
1001 @retval EFI_SUCCESS The interrupt was handled and quiesced. No other handlers \r
1002 should still be called.\r
1003 @retval EFI_WARN_INTERRUPT_SOURCE_QUIESCED The interrupt has been quiesced but other handlers should \r
1004 still be called.\r
1005 @retval EFI_WARN_INTERRUPT_SOURCE_PENDING The interrupt is still pending and other handlers should still \r
1006 be called.\r
1007 @retval EFI_INTERRUPT_PENDING The interrupt could not be quiesced.\r
1008**/\r
1009EFI_STATUS\r
1010EFIAPI\r
1011SmmHandlerEntry (\r
1012 IN EFI_HANDLE DispatchHandle,\r
1013 IN CONST VOID *RegisterContext,\r
1014 IN OUT VOID *CommBuffer,\r
1015 IN OUT UINTN *CommBufferSize\r
1016 )\r
1017{\r
1018 SMMBASE_FUNCTION_DATA *FunctionData;\r
1019\r
1020 ASSERT (CommBuffer != NULL);\r
1021 ASSERT (*CommBufferSize == sizeof (SMMBASE_FUNCTION_DATA));\r
1022\r
1023 FunctionData = (SMMBASE_FUNCTION_DATA *)CommBuffer;\r
1024\r
1025 switch (FunctionData->Function) {\r
26a76fbc 1026 case SmmBaseFunctionRegister:\r
9e620719 1027 Register (FunctionData);\r
1028 break;\r
26a76fbc 1029 case SmmBaseFunctionUnregister:\r
9e620719 1030 UnRegister (FunctionData);\r
1031 break;\r
26a76fbc 1032 case SmmBaseFunctionRegisterCallback:\r
9e620719 1033 RegisterCallback (FunctionData);\r
1034 break;\r
26a76fbc 1035 case SmmBaseFunctionAllocatePool:\r
9e620719 1036 HelperAllocatePool (FunctionData);\r
1037 break;\r
26a76fbc 1038 case SmmBaseFunctionFreePool:\r
9e620719 1039 HelperFreePool (FunctionData);\r
1040 break;\r
26a76fbc 1041 case SmmBaseFunctionCommunicate:\r
bade9bf5 1042 HelperCommunicate (FunctionData);\r
1043 break;\r
9e620719 1044 default:\r
1045 ASSERT (FALSE);\r
1046 FunctionData->Status = EFI_UNSUPPORTED;\r
1047 }\r
1048 return EFI_SUCCESS;\r
1049}\r
1050\r
8edfbe02 1051/**\r
1052 Smm Ready To Lock event notification handler.\r
1053\r
1054 It sets a flag indicating that SMRAM has been locked.\r
1055 \r
1056 @param[in] Protocol Points to the protocol's unique identifier.\r
1057 @param[in] Interface Points to the interface instance.\r
1058 @param[in] Handle The handle on which the interface was installed.\r
1059\r
1060 @retval EFI_SUCCESS Notification handler runs successfully.\r
1061 **/\r
1062EFI_STATUS\r
1063EFIAPI\r
1064SmmReadyToLockEventNotify (\r
1065 IN CONST EFI_GUID *Protocol,\r
1066 IN VOID *Interface,\r
1067 IN EFI_HANDLE Handle\r
1068 )\r
1069{\r
1070 mLocked = TRUE;\r
1071 return EFI_SUCCESS;\r
1072}\r
1073\r
9e620719 1074/**\r
1075 Entry point function of the SMM Base Helper SMM driver.\r
1076\r
1077 @param[in] ImageHandle The firmware allocated handle for the EFI image. \r
1078 @param[in] SystemTable A pointer to the EFI System Table.\r
1079 \r
1080 @retval EFI_SUCCESS The entry point is executed successfully.\r
1081 @retval other Some error occurs when executing this entry point.\r
1082**/\r
1083EFI_STATUS\r
1084EFIAPI\r
1085SmmBaseHelperMain (\r
1086 IN EFI_HANDLE ImageHandle,\r
1087 IN EFI_SYSTEM_TABLE *SystemTable\r
1088 )\r
1089{\r
1090 EFI_STATUS Status;\r
e906eae4 1091 EFI_MP_SERVICES_PROTOCOL *MpServices;\r
26a76fbc 1092 EFI_HANDLE Handle;\r
e906eae4 1093 UINTN NumberOfEnabledProcessors;\r
8edfbe02 1094 VOID *Registration;\r
26a76fbc
LG
1095 \r
1096 Handle = NULL;\r
9e620719 1097 ///\r
17d2c9a3 1098 /// Locate SMM CPU Protocol which is used later to retrieve/update CPU Save States\r
9e620719 1099 ///\r
1100 Status = gSmst->SmmLocateProtocol (&gEfiSmmCpuProtocolGuid, NULL, (VOID **) &mSmmCpu);\r
1101 ASSERT_EFI_ERROR (Status);\r
1102\r
673c1498 1103 ///\r
1104 /// Locate PE32 Image Protocol which is used later to load Framework SMM driver\r
1105 ///\r
1106 Status = SystemTable->BootServices->LocateProtocol (&gEfiLoadPeImageProtocolGuid, NULL, (VOID **) &mLoadPe32Image);\r
1107 ASSERT_EFI_ERROR (Status);\r
1108\r
e906eae4 1109 //\r
1110 // Get MP Services Protocol\r
1111 //\r
1112 Status = SystemTable->BootServices->LocateProtocol (&gEfiMpServiceProtocolGuid, NULL, (VOID **)&MpServices);\r
1113 ASSERT_EFI_ERROR (Status);\r
1114\r
1115 //\r
1116 // Use MP Services Protocol to retrieve the number of processors and number of enabled processors\r
1117 //\r
1118 Status = MpServices->GetNumberOfProcessors (MpServices, &mNumberOfProcessors, &NumberOfEnabledProcessors);\r
1119 ASSERT_EFI_ERROR (Status);\r
1120 \r
9e620719 1121 ///\r
1122 /// Interface structure of SMM BASE Helper Ready Protocol is allocated from UEFI pool\r
1123 /// instead of SMM pool so that SMM Base Thunk driver can access it in Non-SMM mode.\r
1124 ///\r
1125 Status = gBS->AllocatePool (\r
1126 EfiBootServicesData,\r
1127 sizeof (EFI_SMM_BASE_HELPER_READY_PROTOCOL),\r
1128 (VOID **)&mSmmBaseHelperReady\r
1129 );\r
1130 ASSERT_EFI_ERROR (Status);\r
1131\r
1132 ///\r
1133 /// Construct Framework SMST from PI SMST\r
1134 ///\r
1135 mFrameworkSmst = ConstructFrameworkSmst ();\r
1136 mSmmBaseHelperReady->FrameworkSmst = mFrameworkSmst;\r
1137 mSmmBaseHelperReady->ServiceEntry = SmmHandlerEntry;\r
1138\r
8edfbe02 1139 //\r
1140 // Register SMM Ready To Lock Protocol notification\r
1141 //\r
1142 Status = gSmst->SmmRegisterProtocolNotify (\r
1143 &gEfiSmmReadyToLockProtocolGuid,\r
1144 SmmReadyToLockEventNotify,\r
1145 &Registration\r
1146 );\r
1147 ASSERT_EFI_ERROR (Status);\r
1148\r
9e620719 1149 ///\r
1150 /// Register SMM Base Helper services for SMM Base Thunk driver\r
1151 ///\r
1152 Status = gSmst->SmiHandlerRegister (SmmHandlerEntry, &gEfiSmmBaseThunkCommunicationGuid, &mDispatchHandle);\r
1153 ASSERT_EFI_ERROR (Status);\r
1154\r
1155 ///\r
1156 /// Install EFI SMM Base Helper Protocol in the UEFI handle database\r
1157 ///\r
1158 Status = gBS->InstallProtocolInterface (\r
1159 &Handle,\r
1160 &gEfiSmmBaseHelperReadyProtocolGuid,\r
1161 EFI_NATIVE_INTERFACE,\r
1162 mSmmBaseHelperReady\r
1163 );\r
1164 ASSERT_EFI_ERROR (Status);\r
1165\r
1166 return Status;\r
1167}\r
1168\r