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