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