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