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