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