]> git.proxmox.com Git - mirror_edk2.git/blame - EdkCompatibilityPkg/Compatibility/SmmBaseHelper/SmmBaseHelper.c
Security enhancement to SMM Base thunk drivers: Framework SMM drivers can't be loaded...
[mirror_edk2.git] / EdkCompatibilityPkg / Compatibility / SmmBaseHelper / SmmBaseHelper.c
CommitLineData
9e620719 1/** @file\r
2 SMM Base Helper SMM driver.\r
3\r
4 This driver is the counterpart of the SMM Base On SMM Base2 Thunk driver. It\r
5 provides helping services in SMM to the SMM Base On SMM Base2 Thunk driver.\r
6\r
a7932d9a 7 Copyright (c) 2009 - 2010, Intel Corporation\r
9e620719 8 All rights reserved. This program and the accompanying materials\r
9 are licensed and made available under the terms and conditions of the BSD License\r
10 which accompanies this distribution. The full text of the license may be found at\r
11 http://opensource.org/licenses/bsd-license.php\r
12\r
13 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
14 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
15\r
16**/\r
17\r
a7932d9a 18#include <PiSmm.h>\r
19#include <Library/DebugLib.h>\r
20#include <Library/UefiBootServicesTableLib.h>\r
21#include <Library/SmmServicesTableLib.h>\r
22#include <Library/BaseLib.h>\r
23#include <Library/BaseMemoryLib.h>\r
24#include <Library/PeCoffLib.h>\r
25#include <Library/DevicePathLib.h>\r
26#include <Library/CacheMaintenanceLib.h>\r
27af6f9d 27#include <Library/MemoryAllocationLib.h>\r
a7932d9a 28#include <Guid/SmmBaseThunkCommunication.h>\r
29#include <Protocol/SmmBaseHelperReady.h>\r
30#include <Protocol/SmmCpu.h>\r
31#include <Protocol/LoadedImage.h>\r
32#include <Protocol/SmmCpuSaveState.h>\r
e906eae4 33#include <Protocol/MpService.h>\r
673c1498 34#include <Protocol/LoadPe32Image.h>\r
8edfbe02 35#include <Protocol/SmmReadyToLock.h>\r
a7932d9a 36\r
37///\r
38/// Structure for tracking paired information of registered Framework SMI handler\r
39/// and correpsonding dispatch handle for SMI handler thunk.\r
40///\r
41typedef struct {\r
42 LIST_ENTRY Link;\r
43 EFI_HANDLE DispatchHandle;\r
44 EFI_HANDLE SmmImageHandle;\r
45 EFI_SMM_CALLBACK_ENTRY_POINT CallbackAddress;\r
18e78927 46 VOID *CommunicationBuffer;\r
47 UINTN *SourceSize;\r
a7932d9a 48} CALLBACK_INFO;\r
49\r
50typedef struct {\r
51 ///\r
52 /// PI SMM CPU Save State register index\r
53 ///\r
54 EFI_SMM_SAVE_STATE_REGISTER Register;\r
55 ///\r
56 /// Offset in Framework SMST\r
57 ///\r
58 UINTN Offset;\r
59} CPU_SAVE_STATE_CONVERSION;\r
60\r
61#define CPU_SAVE_STATE_GET_OFFSET(Field) (UINTN)(&(((EFI_SMM_CPU_SAVE_STATE *) 0)->Ia32SaveState.Field))\r
62\r
9e620719 63\r
64EFI_HANDLE mDispatchHandle;\r
65EFI_SMM_CPU_PROTOCOL *mSmmCpu;\r
673c1498 66EFI_PE32_IMAGE_PROTOCOL *mLoadPe32Image;\r
9e620719 67EFI_GUID mEfiSmmCpuIoGuid = EFI_SMM_CPU_IO_GUID;\r
68EFI_SMM_BASE_HELPER_READY_PROTOCOL *mSmmBaseHelperReady;\r
69EFI_SMM_SYSTEM_TABLE *mFrameworkSmst;\r
e906eae4 70UINTN mNumberOfProcessors;\r
8edfbe02 71BOOLEAN mLocked = FALSE;\r
9e620719 72\r
73LIST_ENTRY mCallbackInfoListHead = INITIALIZE_LIST_HEAD_VARIABLE (mCallbackInfoListHead);\r
74\r
75CPU_SAVE_STATE_CONVERSION mCpuSaveStateConvTable[] = {\r
76 {EFI_SMM_SAVE_STATE_REGISTER_LDTBASE , CPU_SAVE_STATE_GET_OFFSET(LDTBase)},\r
77 {EFI_SMM_SAVE_STATE_REGISTER_ES , CPU_SAVE_STATE_GET_OFFSET(ES)},\r
78 {EFI_SMM_SAVE_STATE_REGISTER_CS , CPU_SAVE_STATE_GET_OFFSET(CS)},\r
79 {EFI_SMM_SAVE_STATE_REGISTER_SS , CPU_SAVE_STATE_GET_OFFSET(SS)},\r
80 {EFI_SMM_SAVE_STATE_REGISTER_DS , CPU_SAVE_STATE_GET_OFFSET(DS)},\r
81 {EFI_SMM_SAVE_STATE_REGISTER_FS , CPU_SAVE_STATE_GET_OFFSET(FS)},\r
82 {EFI_SMM_SAVE_STATE_REGISTER_GS , CPU_SAVE_STATE_GET_OFFSET(GS)},\r
83 {EFI_SMM_SAVE_STATE_REGISTER_TR_SEL , CPU_SAVE_STATE_GET_OFFSET(TR)},\r
84 {EFI_SMM_SAVE_STATE_REGISTER_DR7 , CPU_SAVE_STATE_GET_OFFSET(DR7)},\r
85 {EFI_SMM_SAVE_STATE_REGISTER_DR6 , CPU_SAVE_STATE_GET_OFFSET(DR6)},\r
86 {EFI_SMM_SAVE_STATE_REGISTER_RAX , CPU_SAVE_STATE_GET_OFFSET(EAX)},\r
87 {EFI_SMM_SAVE_STATE_REGISTER_RBX , CPU_SAVE_STATE_GET_OFFSET(EBX)},\r
88 {EFI_SMM_SAVE_STATE_REGISTER_RCX , CPU_SAVE_STATE_GET_OFFSET(ECX)},\r
89 {EFI_SMM_SAVE_STATE_REGISTER_RDX , CPU_SAVE_STATE_GET_OFFSET(EDX)},\r
90 {EFI_SMM_SAVE_STATE_REGISTER_RSP , CPU_SAVE_STATE_GET_OFFSET(ESP)},\r
91 {EFI_SMM_SAVE_STATE_REGISTER_RBP , CPU_SAVE_STATE_GET_OFFSET(EBP)},\r
92 {EFI_SMM_SAVE_STATE_REGISTER_RSI , CPU_SAVE_STATE_GET_OFFSET(ESI)},\r
93 {EFI_SMM_SAVE_STATE_REGISTER_RDI , CPU_SAVE_STATE_GET_OFFSET(EDI)},\r
94 {EFI_SMM_SAVE_STATE_REGISTER_RIP , CPU_SAVE_STATE_GET_OFFSET(EIP)},\r
95 {EFI_SMM_SAVE_STATE_REGISTER_RFLAGS , CPU_SAVE_STATE_GET_OFFSET(EFLAGS)},\r
96 {EFI_SMM_SAVE_STATE_REGISTER_CR0 , CPU_SAVE_STATE_GET_OFFSET(CR0)},\r
97 {EFI_SMM_SAVE_STATE_REGISTER_CR3 , CPU_SAVE_STATE_GET_OFFSET(CR3)}\r
98};\r
99\r
100/**\r
101 Framework SMST SmmInstallConfigurationTable() Thunk.\r
102\r
103 This thunk calls the PI SMM SmmInstallConfigurationTable() and then update the configuration\r
104 table related fields in the Framework SMST because the PI SMM SmmInstallConfigurationTable()\r
105 function may modify these fields.\r
106\r
107 @param[in] SystemTable A pointer to the SMM System Table.\r
108 @param[in] Guid A pointer to the GUID for the entry to add, update, or remove.\r
109 @param[in] Table A pointer to the buffer of the table to add.\r
110 @param[in] TableSize The size of the table to install.\r
111\r
112 @retval EFI_SUCCESS The (Guid, Table) pair was added, updated, or removed.\r
113 @retval EFI_INVALID_PARAMETER Guid is not valid.\r
114 @retval EFI_NOT_FOUND An attempt was made to delete a non-existent entry.\r
115 @retval EFI_OUT_OF_RESOURCES There is not enough memory available to complete the operation.\r
116**/\r
117EFI_STATUS\r
118EFIAPI\r
119SmmInstallConfigurationTable (\r
120 IN EFI_SMM_SYSTEM_TABLE *SystemTable,\r
121 IN EFI_GUID *Guid,\r
122 IN VOID *Table,\r
123 IN UINTN TableSize\r
124 )\r
125{\r
126 EFI_STATUS Status;\r
127 \r
128 Status = gSmst->SmmInstallConfigurationTable (gSmst, Guid, Table, TableSize);\r
129 if (!EFI_ERROR (Status)) {\r
130 mFrameworkSmst->NumberOfTableEntries = gSmst->NumberOfTableEntries;\r
131 mFrameworkSmst->SmmConfigurationTable = gSmst->SmmConfigurationTable;\r
132 }\r
133 return Status; \r
134}\r
135\r
136/**\r
137 Construct a Framework SMST based on the PI SMM SMST.\r
138\r
139 @return Pointer to the constructed Framework SMST.\r
140**/\r
141EFI_SMM_SYSTEM_TABLE *\r
142ConstructFrameworkSmst (\r
143 VOID\r
144 )\r
145{\r
9e620719 146 EFI_SMM_SYSTEM_TABLE *FrameworkSmst;\r
147\r
27af6f9d 148 FrameworkSmst = (EFI_SMM_SYSTEM_TABLE *)AllocatePool (sizeof (EFI_SMM_SYSTEM_TABLE));\r
149 ASSERT (FrameworkSmst != NULL);\r
9e620719 150\r
151 ///\r
152 /// Copy same things from PI SMST to Framework SMST\r
153 ///\r
154 CopyMem (FrameworkSmst, gSmst, (UINTN)(&((EFI_SMM_SYSTEM_TABLE *)0)->SmmIo));\r
155 CopyMem (\r
156 &FrameworkSmst->SmmIo, \r
157 &gSmst->SmmIo,\r
158 sizeof (EFI_SMM_SYSTEM_TABLE) - (UINTN)(&((EFI_SMM_SYSTEM_TABLE *)0)->SmmIo)\r
159 );\r
160\r
161 ///\r
162 /// Update Framework SMST\r
163 ///\r
164 FrameworkSmst->Hdr.Revision = EFI_SMM_SYSTEM_TABLE_REVISION;\r
165 CopyGuid (&FrameworkSmst->EfiSmmCpuIoGuid, &mEfiSmmCpuIoGuid);\r
166\r
e906eae4 167 FrameworkSmst->CpuSaveState = (EFI_SMM_CPU_SAVE_STATE *)AllocateZeroPool (mNumberOfProcessors * sizeof (EFI_SMM_CPU_SAVE_STATE));\r
27af6f9d 168 ASSERT (FrameworkSmst->CpuSaveState != NULL);\r
9e620719 169\r
170 ///\r
171 /// Do not support floating point state now\r
172 ///\r
173 FrameworkSmst->CpuOptionalFloatingPointState = NULL;\r
174\r
175 FrameworkSmst->SmmInstallConfigurationTable = SmmInstallConfigurationTable;\r
176\r
177 return FrameworkSmst;\r
178}\r
179\r
180/**\r
181 Load a given Framework SMM driver into SMRAM and invoke its entry point.\r
182\r
673c1498 183 @param[in] ParentImageHandle Parent Image Handle.\r
9e620719 184 @param[in] FilePath Location of the image to be installed as the handler.\r
185 @param[in] SourceBuffer Optional source buffer in case the image file\r
186 is in memory.\r
187 @param[in] SourceSize Size of the source image file, if in memory.\r
188 @param[out] ImageHandle The handle that the base driver uses to decode \r
189 the handler. Unique among SMM handlers only, \r
190 not unique across DXE/EFI.\r
191\r
192 @retval EFI_SUCCESS The operation was successful.\r
193 @retval EFI_OUT_OF_RESOURCES There were no additional SMRAM resources to load the handler\r
194 @retval EFI_UNSUPPORTED Can not find its copy in normal memory.\r
195 @retval EFI_INVALID_PARAMETER The handlers was not the correct image type\r
196**/\r
197EFI_STATUS\r
198LoadImage (\r
673c1498 199 IN EFI_HANDLE ParentImageHandle,\r
9e620719 200 IN EFI_DEVICE_PATH_PROTOCOL *FilePath,\r
201 IN VOID *SourceBuffer,\r
202 IN UINTN SourceSize,\r
203 OUT EFI_HANDLE *ImageHandle\r
204 )\r
205{\r
673c1498 206 EFI_STATUS Status;\r
207 UINTN PageCount;\r
208 UINTN OrgPageCount;\r
209 EFI_PHYSICAL_ADDRESS DstBuffer;\r
9e620719 210\r
211 if (FilePath == NULL || ImageHandle == NULL) { \r
212 return EFI_INVALID_PARAMETER;\r
213 }\r
214\r
673c1498 215 PageCount = 1;\r
216 do {\r
217 OrgPageCount = PageCount;\r
218 DstBuffer = (UINTN)-1;\r
219 Status = gSmst->SmmAllocatePages (\r
220 AllocateMaxAddress,\r
221 EfiRuntimeServicesCode,\r
222 PageCount,\r
223 &DstBuffer\r
9e620719 224 );\r
673c1498 225 if (EFI_ERROR (Status)) {\r
226 return Status;\r
9e620719 227 }\r
228\r
673c1498 229 Status = mLoadPe32Image->LoadPeImage (\r
230 mLoadPe32Image,\r
231 ParentImageHandle,\r
232 FilePath,\r
233 SourceBuffer,\r
234 SourceSize,\r
235 DstBuffer,\r
236 &PageCount,\r
237 ImageHandle,\r
238 NULL,\r
239 EFI_LOAD_PE_IMAGE_ATTRIBUTE_NONE\r
240 );\r
241 if (EFI_ERROR (Status)) {\r
242 FreePages ((VOID *)(UINTN)DstBuffer, OrgPageCount);\r
9e620719 243 }\r
673c1498 244 } while (Status == EFI_BUFFER_TOO_SMALL);\r
9e620719 245\r
9e620719 246 if (!EFI_ERROR (Status)) {\r
673c1498 247 ///\r
248 /// Update MP state in Framework SMST before transferring control to Framework SMM driver entry point\r
249 /// in case it may invoke AP\r
250 ///\r
251 mFrameworkSmst->CurrentlyExecutingCpu = gSmst->CurrentlyExecutingCpu;\r
252\r
253 Status = gBS->StartImage (*ImageHandle, NULL, NULL);\r
254 if (EFI_ERROR (Status)) {\r
255 mLoadPe32Image->UnLoadPeImage (mLoadPe32Image, *ImageHandle);\r
256 *ImageHandle = NULL;\r
257 FreePages ((VOID *)(UINTN)DstBuffer, PageCount);\r
258 }\r
9e620719 259 }\r
260\r
673c1498 261 return Status;\r
9e620719 262}\r
263\r
673c1498 264\r
9e620719 265/** \r
266 Thunk service of EFI_SMM_BASE_PROTOCOL.Register().\r
267\r
17d2c9a3 268 @param[in, out] FunctionData Pointer to SMMBASE_FUNCTION_DATA.\r
269**/\r
9e620719 270VOID\r
271Register (\r
272 IN OUT SMMBASE_FUNCTION_DATA *FunctionData\r
273 )\r
274{\r
275 EFI_STATUS Status;\r
276\r
8edfbe02 277 if (mLocked || FunctionData->Args.Register.LegacyIA32Binary) {\r
9e620719 278 Status = EFI_UNSUPPORTED;\r
279 } else {\r
280 Status = LoadImage (\r
673c1498 281 FunctionData->SmmBaseImageHandle,\r
9e620719 282 FunctionData->Args.Register.FilePath,\r
283 FunctionData->Args.Register.SourceBuffer,\r
284 FunctionData->Args.Register.SourceSize,\r
285 FunctionData->Args.Register.ImageHandle\r
286 );\r
287 }\r
288 FunctionData->Status = Status;\r
289}\r
290\r
291/** \r
292 Thunk service of EFI_SMM_BASE_PROTOCOL.UnRegister().\r
293\r
17d2c9a3 294 @param[in, out] FunctionData Pointer to SMMBASE_FUNCTION_DATA.\r
295**/\r
9e620719 296VOID\r
297UnRegister (\r
298 IN OUT SMMBASE_FUNCTION_DATA *FunctionData\r
299 )\r
300{\r
301 ///\r
302 /// Unregister not supported now\r
303 ///\r
304 FunctionData->Status = EFI_UNSUPPORTED;\r
305}\r
306\r
307/**\r
308 Search for Framework SMI handler information according to specific PI SMM dispatch handle.\r
309\r
310 @param[in] DispatchHandle The unique handle assigned by SmiHandlerRegister(). \r
311\r
17d2c9a3 312 @return Pointer to CALLBACK_INFO. If NULL, no callback info record is found.\r
9e620719 313**/\r
314CALLBACK_INFO *\r
315GetCallbackInfo (\r
316 IN EFI_HANDLE DispatchHandle\r
317 )\r
318{\r
319 LIST_ENTRY *Node;\r
320\r
321 Node = GetFirstNode (&mCallbackInfoListHead);\r
322 while (!IsNull (&mCallbackInfoListHead, Node)) {\r
323 if (((CALLBACK_INFO *)Node)->DispatchHandle == DispatchHandle) {\r
324 return (CALLBACK_INFO *)Node;\r
325 }\r
326 Node = GetNextNode (&mCallbackInfoListHead, Node);\r
327 }\r
328 return NULL;\r
329}\r
330\r
331/**\r
332 Callback thunk for Framework SMI handler.\r
333\r
334 This thunk functions calls the Framework SMI handler and converts the return value\r
335 defined from Framework SMI handlers to a correpsonding return value defined by PI SMM.\r
336\r
337 @param[in] DispatchHandle The unique handle assigned to this handler by SmiHandlerRegister().\r
338 @param[in] Context Points to an optional handler context which was specified when the\r
339 handler was registered.\r
26a76fbc 340 @param[in, out] CommBuffer A pointer to a collection of data in memory that will\r
9e620719 341 be conveyed from a non-SMM environment into an SMM environment.\r
26a76fbc 342 @param[in, out] CommBufferSize The size of the CommBuffer.\r
9e620719 343\r
344 @retval EFI_SUCCESS The interrupt was handled and quiesced. No other handlers \r
345 should still be called.\r
346 @retval EFI_WARN_INTERRUPT_SOURCE_QUIESCED The interrupt has been quiesced but other handlers should \r
347 still be called.\r
348 @retval EFI_WARN_INTERRUPT_SOURCE_PENDING The interrupt is still pending and other handlers should still \r
349 be called.\r
350 @retval EFI_INTERRUPT_PENDING The interrupt could not be quiesced.\r
351**/\r
352EFI_STATUS\r
353EFIAPI\r
354CallbackThunk (\r
355 IN EFI_HANDLE DispatchHandle,\r
356 IN CONST VOID *Context OPTIONAL,\r
357 IN OUT VOID *CommBuffer OPTIONAL,\r
358 IN OUT UINTN *CommBufferSize OPTIONAL\r
359 )\r
360{\r
361 EFI_STATUS Status;\r
362 CALLBACK_INFO *CallbackInfo;\r
363 UINTN Index;\r
364 UINTN CpuIndex;\r
365 EFI_SMM_CPU_STATE *State;\r
366 EFI_SMI_CPU_SAVE_STATE *SaveState;\r
367\r
368 ///\r
369 /// Before transferring the control into the Framework SMI handler, update CPU Save States\r
370 /// and MP states in the Framework SMST.\r
371 ///\r
372\r
e906eae4 373 for (CpuIndex = 0; CpuIndex < mNumberOfProcessors; CpuIndex++) {\r
9e620719 374 State = (EFI_SMM_CPU_STATE *)gSmst->CpuSaveState[CpuIndex];\r
375 SaveState = &mFrameworkSmst->CpuSaveState[CpuIndex].Ia32SaveState;\r
376\r
377 if (State->x86.SMMRevId < EFI_SMM_MIN_REV_ID_x64) {\r
378 SaveState->SMBASE = State->x86.SMBASE;\r
379 SaveState->SMMRevId = State->x86.SMMRevId;\r
380 SaveState->IORestart = State->x86.IORestart;\r
381 SaveState->AutoHALTRestart = State->x86.AutoHALTRestart;\r
382 } else {\r
383 SaveState->SMBASE = State->x64.SMBASE;\r
384 SaveState->SMMRevId = State->x64.SMMRevId;\r
385 SaveState->IORestart = State->x64.IORestart;\r
386 SaveState->AutoHALTRestart = State->x64.AutoHALTRestart;\r
387 }\r
388\r
389 for (Index = 0; Index < sizeof (mCpuSaveStateConvTable) / sizeof (CPU_SAVE_STATE_CONVERSION); Index++) {\r
390 ///\r
391 /// Try to use SMM CPU Protocol to access CPU save states if possible\r
392 ///\r
393 Status = mSmmCpu->ReadSaveState (\r
394 mSmmCpu,\r
f76edcfd 395 (UINTN)sizeof (UINT32),\r
9e620719 396 mCpuSaveStateConvTable[Index].Register,\r
397 CpuIndex,\r
398 ((UINT8 *)SaveState) + mCpuSaveStateConvTable[Index].Offset\r
399 );\r
400 ASSERT_EFI_ERROR (Status);\r
401 }\r
402 }\r
403\r
33f30f1e 404 mFrameworkSmst->SmmStartupThisAp = gSmst->SmmStartupThisAp;\r
405 mFrameworkSmst->NumberOfCpus = mNumberOfProcessors;\r
9e620719 406 mFrameworkSmst->CurrentlyExecutingCpu = gSmst->CurrentlyExecutingCpu;\r
407\r
408 ///\r
409 /// Search for Framework SMI handler information\r
410 ///\r
411 CallbackInfo = GetCallbackInfo (DispatchHandle);\r
412 ASSERT (CallbackInfo != NULL);\r
413\r
414 ///\r
415 /// Thunk into original Framwork SMI handler\r
416 ///\r
417 Status = (CallbackInfo->CallbackAddress) (\r
418 CallbackInfo->SmmImageHandle,\r
18e78927 419 CallbackInfo->CommunicationBuffer,\r
420 CallbackInfo->SourceSize\r
9e620719 421 );\r
422 ///\r
423 /// Save CPU Save States in case any of them was modified\r
424 ///\r
e906eae4 425 for (CpuIndex = 0; CpuIndex < mNumberOfProcessors; CpuIndex++) {\r
9e620719 426 for (Index = 0; Index < sizeof (mCpuSaveStateConvTable) / sizeof (CPU_SAVE_STATE_CONVERSION); Index++) {\r
427 Status = mSmmCpu->WriteSaveState (\r
428 mSmmCpu,\r
f76edcfd 429 (UINTN)sizeof (UINT32),\r
9e620719 430 mCpuSaveStateConvTable[Index].Register,\r
431 CpuIndex,\r
432 ((UINT8 *)&mFrameworkSmst->CpuSaveState[CpuIndex].Ia32SaveState) + \r
433 mCpuSaveStateConvTable[Index].Offset\r
434 );\r
435 }\r
436 }\r
437\r
438 ///\r
439 /// Conversion of returned status code\r
440 ///\r
441 switch (Status) {\r
442 case EFI_HANDLER_SUCCESS:\r
443 Status = EFI_WARN_INTERRUPT_SOURCE_QUIESCED;\r
444 break;\r
445 case EFI_HANDLER_CRITICAL_EXIT:\r
446 case EFI_HANDLER_SOURCE_QUIESCED:\r
447 Status = EFI_SUCCESS;\r
448 break;\r
449 case EFI_HANDLER_SOURCE_PENDING:\r
450 Status = EFI_WARN_INTERRUPT_SOURCE_PENDING;\r
451 break;\r
452 }\r
453 return Status;\r
454}\r
455\r
456/** \r
457 Thunk service of EFI_SMM_BASE_PROTOCOL.RegisterCallback().\r
458\r
17d2c9a3 459 @param[in, out] FunctionData Pointer to SMMBASE_FUNCTION_DATA.\r
460**/\r
9e620719 461VOID\r
462RegisterCallback (\r
27af6f9d 463 IN OUT SMMBASE_FUNCTION_DATA *FunctionData\r
9e620719 464 )\r
465{\r
9e620719 466 CALLBACK_INFO *Buffer;\r
467\r
8edfbe02 468 if (mLocked) {\r
469 FunctionData->Status = EFI_UNSUPPORTED;\r
470 return;\r
471 }\r
472\r
9e620719 473 ///\r
474 /// Note that MakeLast and FloatingPointSave options are not supported in PI SMM\r
475 ///\r
476\r
477 ///\r
478 /// Allocate buffer for callback thunk information\r
479 ///\r
18e78927 480 Buffer = (CALLBACK_INFO *)AllocateZeroPool (sizeof (CALLBACK_INFO));\r
27af6f9d 481 if (Buffer == NULL) {\r
482 FunctionData->Status = EFI_OUT_OF_RESOURCES;\r
483 return;\r
9e620719 484 }\r
27af6f9d 485\r
486 ///\r
487 /// Fill SmmImageHandle and CallbackAddress into the thunk\r
488 ///\r
489 Buffer->SmmImageHandle = FunctionData->Args.RegisterCallback.SmmImageHandle;\r
490 Buffer->CallbackAddress = FunctionData->Args.RegisterCallback.CallbackAddress;\r
491\r
492 ///\r
493 /// Register the thunk code as a root SMI handler\r
494 ///\r
495 FunctionData->Status = gSmst->SmiHandlerRegister (\r
496 CallbackThunk,\r
497 NULL,\r
498 &Buffer->DispatchHandle\r
499 );\r
500 if (EFI_ERROR (FunctionData->Status)) {\r
501 FreePool (Buffer);\r
502 return;\r
503 }\r
504\r
505 ///\r
506 /// Save this callback info\r
507 ///\r
508 InsertTailList (&mCallbackInfoListHead, &Buffer->Link);\r
9e620719 509}\r
510\r
511\r
512/** \r
513 Thunk service of EFI_SMM_BASE_PROTOCOL.SmmAllocatePool().\r
514\r
17d2c9a3 515 @param[in, out] FunctionData Pointer to SMMBASE_FUNCTION_DATA.\r
516**/\r
9e620719 517VOID\r
518HelperAllocatePool (\r
519 IN OUT SMMBASE_FUNCTION_DATA *FunctionData\r
520 )\r
521{\r
8edfbe02 522 if (mLocked) {\r
523 FunctionData->Status = EFI_UNSUPPORTED;\r
524 } else {\r
525 FunctionData->Status = gSmst->SmmAllocatePool (\r
526 FunctionData->Args.AllocatePool.PoolType,\r
527 FunctionData->Args.AllocatePool.Size,\r
528 FunctionData->Args.AllocatePool.Buffer\r
529 );\r
530 }\r
9e620719 531}\r
532\r
533/** \r
534 Thunk service of EFI_SMM_BASE_PROTOCOL.SmmFreePool().\r
535\r
17d2c9a3 536 @param[in, out] FunctionData Pointer to SMMBASE_FUNCTION_DATA.\r
537**/\r
9e620719 538VOID\r
539HelperFreePool (\r
540 IN OUT SMMBASE_FUNCTION_DATA *FunctionData\r
541 )\r
542{\r
8edfbe02 543 if (mLocked) {\r
544 FunctionData->Status = EFI_UNSUPPORTED;\r
545 } else {\r
546 FreePool (FunctionData->Args.FreePool.Buffer);\r
547 FunctionData->Status = EFI_SUCCESS;\r
548 }\r
9e620719 549}\r
550\r
bade9bf5 551/** \r
552 Thunk service of EFI_SMM_BASE_PROTOCOL.Communicate().\r
553\r
554 @param[in, out] FunctionData Pointer to SMMBASE_FUNCTION_DATA.\r
555**/\r
556VOID\r
557HelperCommunicate (\r
558 IN OUT SMMBASE_FUNCTION_DATA *FunctionData\r
559 )\r
560{\r
561 LIST_ENTRY *Node;\r
562 CALLBACK_INFO *CallbackInfo;\r
563\r
564 if (FunctionData->Args.Communicate.CommunicationBuffer == NULL) {\r
565 FunctionData->Status = EFI_INVALID_PARAMETER;\r
566 return;\r
567 }\r
568\r
569 Node = GetFirstNode (&mCallbackInfoListHead);\r
570 while (!IsNull (&mCallbackInfoListHead, Node)) {\r
571 CallbackInfo = (CALLBACK_INFO *)Node;\r
572\r
573 if (FunctionData->Args.Communicate.ImageHandle == CallbackInfo->SmmImageHandle) {\r
18e78927 574 CallbackInfo->CommunicationBuffer = FunctionData->Args.Communicate.CommunicationBuffer;\r
575 CallbackInfo->SourceSize = FunctionData->Args.Communicate.SourceSize;\r
576\r
bade9bf5 577 ///\r
578 /// The message was successfully posted.\r
579 ///\r
580 FunctionData->Status = EFI_SUCCESS;\r
581 return;\r
582 }\r
583 Node = GetNextNode (&mCallbackInfoListHead, Node);\r
584 }\r
585\r
586 FunctionData->Status = EFI_INVALID_PARAMETER;\r
587}\r
588\r
9e620719 589/**\r
590 Communication service SMI Handler entry.\r
591\r
592 This SMI handler provides services for the SMM Base Thunk driver.\r
593\r
594 @param[in] DispatchHandle The unique handle assigned to this handler by SmiHandlerRegister().\r
26a76fbc 595 @param[in] RegisterContext Points to an optional handler context which was specified when the\r
9e620719 596 handler was registered.\r
26a76fbc 597 @param[in, out] CommBuffer A pointer to a collection of data in memory that will\r
9e620719 598 be conveyed from a non-SMM environment into an SMM environment.\r
26a76fbc 599 @param[in, out] CommBufferSize The size of the CommBuffer.\r
9e620719 600\r
601 @retval EFI_SUCCESS The interrupt was handled and quiesced. No other handlers \r
602 should still be called.\r
603 @retval EFI_WARN_INTERRUPT_SOURCE_QUIESCED The interrupt has been quiesced but other handlers should \r
604 still be called.\r
605 @retval EFI_WARN_INTERRUPT_SOURCE_PENDING The interrupt is still pending and other handlers should still \r
606 be called.\r
607 @retval EFI_INTERRUPT_PENDING The interrupt could not be quiesced.\r
608**/\r
609EFI_STATUS\r
610EFIAPI\r
611SmmHandlerEntry (\r
612 IN EFI_HANDLE DispatchHandle,\r
613 IN CONST VOID *RegisterContext,\r
614 IN OUT VOID *CommBuffer,\r
615 IN OUT UINTN *CommBufferSize\r
616 )\r
617{\r
618 SMMBASE_FUNCTION_DATA *FunctionData;\r
619\r
620 ASSERT (CommBuffer != NULL);\r
621 ASSERT (*CommBufferSize == sizeof (SMMBASE_FUNCTION_DATA));\r
622\r
623 FunctionData = (SMMBASE_FUNCTION_DATA *)CommBuffer;\r
624\r
625 switch (FunctionData->Function) {\r
26a76fbc 626 case SmmBaseFunctionRegister:\r
9e620719 627 Register (FunctionData);\r
628 break;\r
26a76fbc 629 case SmmBaseFunctionUnregister:\r
9e620719 630 UnRegister (FunctionData);\r
631 break;\r
26a76fbc 632 case SmmBaseFunctionRegisterCallback:\r
9e620719 633 RegisterCallback (FunctionData);\r
634 break;\r
26a76fbc 635 case SmmBaseFunctionAllocatePool:\r
9e620719 636 HelperAllocatePool (FunctionData);\r
637 break;\r
26a76fbc 638 case SmmBaseFunctionFreePool:\r
9e620719 639 HelperFreePool (FunctionData);\r
640 break;\r
26a76fbc 641 case SmmBaseFunctionCommunicate:\r
bade9bf5 642 HelperCommunicate (FunctionData);\r
643 break;\r
9e620719 644 default:\r
645 ASSERT (FALSE);\r
646 FunctionData->Status = EFI_UNSUPPORTED;\r
647 }\r
648 return EFI_SUCCESS;\r
649}\r
650\r
8edfbe02 651/**\r
652 Smm Ready To Lock event notification handler.\r
653\r
654 It sets a flag indicating that SMRAM has been locked.\r
655 \r
656 @param[in] Protocol Points to the protocol's unique identifier.\r
657 @param[in] Interface Points to the interface instance.\r
658 @param[in] Handle The handle on which the interface was installed.\r
659\r
660 @retval EFI_SUCCESS Notification handler runs successfully.\r
661 **/\r
662EFI_STATUS\r
663EFIAPI\r
664SmmReadyToLockEventNotify (\r
665 IN CONST EFI_GUID *Protocol,\r
666 IN VOID *Interface,\r
667 IN EFI_HANDLE Handle\r
668 )\r
669{\r
670 mLocked = TRUE;\r
671 return EFI_SUCCESS;\r
672}\r
673\r
9e620719 674/**\r
675 Entry point function of the SMM Base Helper SMM driver.\r
676\r
677 @param[in] ImageHandle The firmware allocated handle for the EFI image. \r
678 @param[in] SystemTable A pointer to the EFI System Table.\r
679 \r
680 @retval EFI_SUCCESS The entry point is executed successfully.\r
681 @retval other Some error occurs when executing this entry point.\r
682**/\r
683EFI_STATUS\r
684EFIAPI\r
685SmmBaseHelperMain (\r
686 IN EFI_HANDLE ImageHandle,\r
687 IN EFI_SYSTEM_TABLE *SystemTable\r
688 )\r
689{\r
690 EFI_STATUS Status;\r
e906eae4 691 EFI_MP_SERVICES_PROTOCOL *MpServices;\r
26a76fbc 692 EFI_HANDLE Handle;\r
e906eae4 693 UINTN NumberOfEnabledProcessors;\r
8edfbe02 694 VOID *Registration;\r
26a76fbc
LG
695 \r
696 Handle = NULL;\r
9e620719 697 ///\r
17d2c9a3 698 /// Locate SMM CPU Protocol which is used later to retrieve/update CPU Save States\r
9e620719 699 ///\r
700 Status = gSmst->SmmLocateProtocol (&gEfiSmmCpuProtocolGuid, NULL, (VOID **) &mSmmCpu);\r
701 ASSERT_EFI_ERROR (Status);\r
702\r
673c1498 703 ///\r
704 /// Locate PE32 Image Protocol which is used later to load Framework SMM driver\r
705 ///\r
706 Status = SystemTable->BootServices->LocateProtocol (&gEfiLoadPeImageProtocolGuid, NULL, (VOID **) &mLoadPe32Image);\r
707 ASSERT_EFI_ERROR (Status);\r
708\r
e906eae4 709 //\r
710 // Get MP Services Protocol\r
711 //\r
712 Status = SystemTable->BootServices->LocateProtocol (&gEfiMpServiceProtocolGuid, NULL, (VOID **)&MpServices);\r
713 ASSERT_EFI_ERROR (Status);\r
714\r
715 //\r
716 // Use MP Services Protocol to retrieve the number of processors and number of enabled processors\r
717 //\r
718 Status = MpServices->GetNumberOfProcessors (MpServices, &mNumberOfProcessors, &NumberOfEnabledProcessors);\r
719 ASSERT_EFI_ERROR (Status);\r
720 \r
9e620719 721 ///\r
722 /// Interface structure of SMM BASE Helper Ready Protocol is allocated from UEFI pool\r
723 /// instead of SMM pool so that SMM Base Thunk driver can access it in Non-SMM mode.\r
724 ///\r
725 Status = gBS->AllocatePool (\r
726 EfiBootServicesData,\r
727 sizeof (EFI_SMM_BASE_HELPER_READY_PROTOCOL),\r
728 (VOID **)&mSmmBaseHelperReady\r
729 );\r
730 ASSERT_EFI_ERROR (Status);\r
731\r
732 ///\r
733 /// Construct Framework SMST from PI SMST\r
734 ///\r
735 mFrameworkSmst = ConstructFrameworkSmst ();\r
736 mSmmBaseHelperReady->FrameworkSmst = mFrameworkSmst;\r
737 mSmmBaseHelperReady->ServiceEntry = SmmHandlerEntry;\r
738\r
8edfbe02 739 //\r
740 // Register SMM Ready To Lock Protocol notification\r
741 //\r
742 Status = gSmst->SmmRegisterProtocolNotify (\r
743 &gEfiSmmReadyToLockProtocolGuid,\r
744 SmmReadyToLockEventNotify,\r
745 &Registration\r
746 );\r
747 ASSERT_EFI_ERROR (Status);\r
748\r
9e620719 749 ///\r
750 /// Register SMM Base Helper services for SMM Base Thunk driver\r
751 ///\r
752 Status = gSmst->SmiHandlerRegister (SmmHandlerEntry, &gEfiSmmBaseThunkCommunicationGuid, &mDispatchHandle);\r
753 ASSERT_EFI_ERROR (Status);\r
754\r
755 ///\r
756 /// Install EFI SMM Base Helper Protocol in the UEFI handle database\r
757 ///\r
758 Status = gBS->InstallProtocolInterface (\r
759 &Handle,\r
760 &gEfiSmmBaseHelperReadyProtocolGuid,\r
761 EFI_NATIVE_INTERFACE,\r
762 mSmmBaseHelperReady\r
763 );\r
764 ASSERT_EFI_ERROR (Status);\r
765\r
766 return Status;\r
767}\r
768\r