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