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