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