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