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