TianoCore EDK2 master
Loading...
Searching...
No Matches
MmCommunicationDxe.c
Go to the documentation of this file.
1
10#include "MmCommunicationDxe.h"
11
12//
13// PI 1.7 MM Communication Protocol 2 instance
14//
15EFI_MM_COMMUNICATION2_PROTOCOL mMmCommunication2 = {
17};
18
19//
20// PI 1.7 MM Communication Protocol instance
21//
22EFI_MM_COMMUNICATION_PROTOCOL mMmCommunication = {
24};
25
26MM_COMM_BUFFER mMmCommonBuffer;
27EFI_SMM_CONTROL2_PROTOCOL *mSmmControl2;
28EFI_SMM_ACCESS2_PROTOCOL *mSmmAccess;
29BOOLEAN mSmmLocked = FALSE;
30BOOLEAN mEndOfDxe = FALSE;
31
32//
33// Table of Protocol notification and GUIDed Event notifications that the Standalone Mm requires
34//
35MM_EVENT_NOTIFICATION mMmEvents[] = {
36 //
37 // Declare protocol notification on DxeMmReadyToLock protocols. When this notification is established,
38 // the associated event is immediately signalled, so the notification function will be executed and the
39 // DXE Mm Ready To Lock Protocol will be found if it is already in the handle database.
40 //
41 { ProtocolNotify, TRUE, &gEfiDxeMmReadyToLockProtocolGuid, MmReadyToLockEventNotify, &gEfiDxeMmReadyToLockProtocolGuid, NULL },
42 //
43 // Declare event notification on Ready To Boot Event Group. This is an extra event notification that is
44 // used to make sure SMRAM is locked before any boot options are processed.
45 //
46 { EventNotify, TRUE, &gEfiEventReadyToBootGuid, MmReadyToLockEventNotify, &gEfiEventReadyToBootGuid, NULL },
47 //
48 // Declare event notification on Ready To Boot Event Group. This is used to inform the MM Core
49 // to notify MM driver that system enter ready to boot.
50 //
51 { EventNotify, FALSE, &gEfiEventReadyToBootGuid, MmGuidedEventNotify, &gEfiEventReadyToBootGuid, NULL },
52 //
53 // Declare event notification on EndOfDxe event. When this notification is established,
54 // the associated event is immediately signalled, so the notification function will be executed and the
55 // End Of Dxe Protocol will be found if it is already in the handle database.
56 //
57 { EventNotify, TRUE, &gEfiEndOfDxeEventGroupGuid, MmGuidedEventNotify, &gEfiEndOfDxeEventGroupGuid, NULL },
58 //
59 // Declare event notification on EndOfDxe event. This is used to set EndOfDxe event signaled flag.
60 //
61 { EventNotify, TRUE, &gEfiEndOfDxeEventGroupGuid, MmEndOfDxeEventNotify, &gEfiEndOfDxeEventGroupGuid, NULL },
62 //
63 // Declare event notification on Exit Boot Services Event Group. This is used to inform the MM Core
64 // to notify MM driver that system enter exit boot services.
65 //
66 { EventNotify, FALSE, &gEfiEventExitBootServicesGuid, MmGuidedEventNotify, &gEfiEventExitBootServicesGuid, NULL },
67 //
68 // Declare event notification on SetVirtualAddressMap() Event Group. This is used to convert fixed MM communication buffer
69 // and MM_COMM_BUFFER_STATUS in mMmCommonBuffer, mSmmControl2 from physical addresses to virtual addresses.
70 //
71 { EventNotify, FALSE, &gEfiEventVirtualAddressChangeGuid, MmVirtualAddressChangeEvent, NULL, NULL },
72 //
73 // Terminate the table of event notifications
74 //
75 { EndNotify, FALSE, NULL, NULL, NULL, NULL }
76};
77
85VOID
86EFIAPI
88 IN EFI_EVENT Event,
89 IN VOID *Context
90 )
91{
92 UINTN Size;
93 EFI_MM_COMMUNICATE_HEADER *CommunicateHeader;
94
95 CommunicateHeader = (EFI_MM_COMMUNICATE_HEADER *)(UINTN)mMmCommonBuffer.PhysicalStart;
96
97 //
98 // Use Guid to initialize EFI_MM_COMMUNICATE_HEADER structure
99 //
100 CopyGuid (&CommunicateHeader->HeaderGuid, (EFI_GUID *)Context);
101 CommunicateHeader->MessageLength = 1;
102 CommunicateHeader->Data[0] = 0;
103
104 //
105 // Generate the Software SMI and return the result
106 //
107 Size = sizeof (EFI_MM_COMMUNICATE_HEADER);
108 MmCommunicate2 (&mMmCommunication2, CommunicateHeader, CommunicateHeader, &Size);
109}
110
119VOID
120EFIAPI
122 IN EFI_EVENT Event,
123 IN VOID *Context
124 )
125{
126 EFI_STATUS Status;
127 VOID *Interface;
128 UINTN Index;
129
130 //
131 // See if we are already locked
132 //
133 if (mSmmLocked) {
134 return;
135 }
136
137 //
138 // Make sure this notification is for this handler
139 //
140 if (CompareGuid ((EFI_GUID *)Context, &gEfiDxeMmReadyToLockProtocolGuid)) {
141 Status = gBS->LocateProtocol (&gEfiDxeMmReadyToLockProtocolGuid, NULL, &Interface);
142 if (EFI_ERROR (Status)) {
143 return;
144 }
145 } else {
146 //
147 // If MM is not locked yet and we got here from gEfiEventReadyToBootGuid being
148 // signaled, then gEfiDxeMmReadyToLockProtocolGuid was not installed as expected.
149 // Print a warning on debug builds.
150 //
151 DEBUG ((DEBUG_WARN, "DXE Mm Ready To Lock Protocol not installed before Ready To Boot signal\n"));
152 }
153
154 if (!mEndOfDxe) {
155 DEBUG ((DEBUG_ERROR, "EndOfDxe Event must be signaled before DxeSmmReadyToLock Protocol installation!\n"));
157 EFI_ERROR_CODE | EFI_ERROR_UNRECOVERED,
158 (EFI_SOFTWARE_SMM_DRIVER | EFI_SW_EC_ILLEGAL_SOFTWARE_STATE)
159 );
160 ASSERT (FALSE);
161 }
162
163 //
164 // Lock the SMRAM (Note: Locking SMRAM may not be supported on all platforms)
165 //
166 mSmmAccess->Lock (mSmmAccess);
167
168 //
169 // Close protocol and event notification events that do not apply after the
170 // DXE MM Ready To Lock Protocol has been installed or the Ready To Boot
171 // event has been signalled.
172 //
173 for (Index = 0; mMmEvents[Index].NotifyFunction != NULL; Index++) {
174 if (mMmEvents[Index].CloseOnLock) {
175 gBS->CloseEvent (mMmEvents[Index].Event);
176 }
177 }
178
179 //
180 // Inform MM Core that the DxeSmmReadyToLock protocol was installed
181 //
182 MmGuidedEventNotify (Event, (VOID *)&gEfiDxeMmReadyToLockProtocolGuid);
183
184 //
185 // Print debug message that the SMRAM window is now locked.
186 //
187 DEBUG ((DEBUG_INFO, "MmCommunicationDxe locked SMRAM window\n"));
188
189 //
190 // Set flag so this operation will not be performed again
191 //
192 mSmmLocked = TRUE;
193}
194
202VOID
203EFIAPI
205 IN EFI_EVENT Event,
206 IN VOID *Context
207 )
208{
209 mEndOfDxe = TRUE;
210}
211
222VOID
223EFIAPI
225 IN EFI_EVENT Event,
226 IN VOID *Context
227 )
228{
229 EfiConvertPointer (0x0, (VOID **)&mMmCommonBuffer.Status);
230 EfiConvertPointer (0x0, (VOID **)&mMmCommonBuffer.PhysicalStart);
231 EfiConvertPointer (0x0, (VOID **)&mSmmControl2);
232}
233
257EFIAPI
259 IN OUT VOID *CommBuffer,
260 IN OUT UINTN *CommSize OPTIONAL
261 )
262{
263 EFI_STATUS Status;
264 EFI_MM_COMMUNICATE_HEADER *CommunicateHeader;
265 MM_COMM_BUFFER_STATUS *CommonBufferStatus;
266 UINTN BufferSize;
267
268 //
269 // Check parameters
270 //
271 if (CommBuffer == NULL) {
272 return EFI_INVALID_PARAMETER;
273 }
274
275 CommunicateHeader = (EFI_MM_COMMUNICATE_HEADER *)CommBuffer;
276 BufferSize = OFFSET_OF (EFI_MM_COMMUNICATE_HEADER, Data) + CommunicateHeader->MessageLength;
277
278 if (CommSize != NULL) {
279 ASSERT (*CommSize == BufferSize);
280 }
281
282 CommonBufferStatus = (MM_COMM_BUFFER_STATUS *)(UINTN)mMmCommonBuffer.Status;
283
284 //
285 // Copy the content at input CommBuffer to fixed MM communication buffer
286 // if CommBuffer is not equal to fixed MM communication buffer.
287 //
288 if ((UINTN)CommBuffer != mMmCommonBuffer.PhysicalStart) {
289 CopyMem ((VOID *)(UINTN)mMmCommonBuffer.PhysicalStart, CommBuffer, BufferSize);
290 }
291
292 CommonBufferStatus->IsCommBufferValid = TRUE;
293
294 //
295 // Generate Software SMI
296 //
297 Status = mSmmControl2->Trigger (mSmmControl2, NULL, NULL, FALSE, 0);
298 if (EFI_ERROR (Status)) {
299 return EFI_UNSUPPORTED;
300 }
301
302 //
303 // Copy the returned data to the non-mmram buffer (CommBuffer)
304 //
305 if ((UINTN)CommBuffer != mMmCommonBuffer.PhysicalStart) {
306 CopyMem (CommBuffer, (VOID *)(UINTN)mMmCommonBuffer.PhysicalStart, CommonBufferStatus->ReturnBufferSize);
307 }
308
309 //
310 // Retrieve BufferSize and return status from CommonBufferStatus
311 //
312 if (CommSize != NULL) {
313 *CommSize = CommonBufferStatus->ReturnBufferSize;
314 }
315
316 CommonBufferStatus->IsCommBufferValid = FALSE;
317
318 return CommonBufferStatus->ReturnStatus;
319}
320
346EFIAPI
349 IN OUT VOID *CommBufferPhysical,
350 IN OUT VOID *CommBufferVirtual,
351 IN OUT UINTN *CommSize OPTIONAL
352 )
353{
354 return ProcessCommunicationBuffer (CommBufferVirtual, CommSize);
355}
356
381EFIAPI
384 IN OUT VOID *CommBuffer,
385 IN OUT UINTN *CommSize OPTIONAL
386 )
387{
388 return ProcessCommunicationBuffer (CommBuffer, CommSize);
389}
390
402EFIAPI
404 IN EFI_HANDLE ImageHandle,
405 IN EFI_SYSTEM_TABLE *SystemTable
406 )
407{
408 EFI_STATUS Status;
409 EFI_HANDLE Handle;
410 EFI_HOB_GUID_TYPE *GuidHob;
411 MM_COMM_BUFFER *MmCommonBuffer;
412 UINTN Index;
413 VOID *Registration;
414
415 //
416 // Locate gMmCommBufferHobGuid and cache the content
417 //
418 GuidHob = GetFirstGuidHob (&gMmCommBufferHobGuid);
419 ASSERT (GuidHob != NULL);
420 MmCommonBuffer = GET_GUID_HOB_DATA (GuidHob);
421 CopyMem (&mMmCommonBuffer, MmCommonBuffer, sizeof (MM_COMM_BUFFER));
422
423 //
424 // Get SMM Control2 Protocol
425 //
426 Status = gBS->LocateProtocol (&gEfiSmmControl2ProtocolGuid, NULL, (VOID **)&mSmmControl2);
427 ASSERT_EFI_ERROR (Status);
428
429 //
430 // Get SMM Access Protocol
431 //
432 Status = gBS->LocateProtocol (&gEfiSmmAccess2ProtocolGuid, NULL, (VOID **)&mSmmAccess);
433 ASSERT_EFI_ERROR (Status);
434
435 Handle = NULL;
436 Status = gBS->InstallProtocolInterface (
437 &Handle,
438 &gEfiMmCommunication2ProtocolGuid,
440 &mMmCommunication2
441 );
442 ASSERT_EFI_ERROR (Status);
443
444 Status = gBS->InstallProtocolInterface (
445 &Handle,
446 &gEfiMmCommunicationProtocolGuid,
448 &mMmCommunication
449 );
450 ASSERT_EFI_ERROR (Status);
451
452 //
453 // Create the set of protocol and event notifications that the Standalone Mm requires
454 //
455 for (Index = 0; mMmEvents[Index].NotificationType != EndNotify; Index++) {
456 if (mMmEvents[Index].NotificationType == ProtocolNotify) {
457 mMmEvents[Index].Event = EfiCreateProtocolNotifyEvent (
458 mMmEvents[Index].Guid,
459 TPL_CALLBACK,
460 mMmEvents[Index].NotifyFunction,
461 mMmEvents[Index].NotifyContext,
462 &Registration
463 );
464 } else {
465 Status = gBS->CreateEventEx (
466 EVT_NOTIFY_SIGNAL,
467 TPL_CALLBACK,
468 mMmEvents[Index].NotifyFunction,
469 mMmEvents[Index].NotifyContext,
470 mMmEvents[Index].Guid,
471 &mMmEvents[Index].Event
472 );
473 ASSERT_EFI_ERROR (Status);
474 }
475 }
476
477 return EFI_SUCCESS;
478}
UINT64 UINTN
VOID *EFIAPI GetFirstGuidHob(IN CONST EFI_GUID *Guid)
Definition: HobLib.c:215
VOID *EFIAPI CopyMem(OUT VOID *DestinationBuffer, IN CONST VOID *SourceBuffer, IN UINTN Length)
BOOLEAN EFIAPI CompareGuid(IN CONST GUID *Guid1, IN CONST GUID *Guid2)
Definition: MemLibGuid.c:73
GUID *EFIAPI CopyGuid(OUT GUID *DestinationGuid, IN CONST GUID *SourceGuid)
Definition: MemLibGuid.c:39
#define NULL
Definition: Base.h:319
#define CONST
Definition: Base.h:259
#define TRUE
Definition: Base.h:301
#define FALSE
Definition: Base.h:307
#define IN
Definition: Base.h:279
#define OFFSET_OF(TYPE, Field)
Definition: Base.h:758
#define OUT
Definition: Base.h:284
#define ASSERT_EFI_ERROR(StatusParameter)
Definition: DebugLib.h:462
#define DEBUG(Expression)
Definition: DebugLib.h:434
#define REPORT_STATUS_CODE(Type, Value)
VOID EFIAPI MmGuidedEventNotify(IN EFI_EVENT Event, IN VOID *Context)
BOOLEAN mEndOfDxe
EFI_STATUS EFIAPI MmCommunicate2(IN CONST EFI_MM_COMMUNICATION2_PROTOCOL *This, IN OUT VOID *CommBufferPhysical, IN OUT VOID *CommBufferVirtual, IN OUT UINTN *CommSize OPTIONAL)
EFI_STATUS EFIAPI MmCommunicationEntryPoint(IN EFI_HANDLE ImageHandle, IN EFI_SYSTEM_TABLE *SystemTable)
EFI_STATUS EFIAPI MmCommunicate(IN CONST EFI_MM_COMMUNICATION_PROTOCOL *This, IN OUT VOID *CommBuffer, IN OUT UINTN *CommSize OPTIONAL)
EFI_STATUS EFIAPI ProcessCommunicationBuffer(IN OUT VOID *CommBuffer, IN OUT UINTN *CommSize OPTIONAL)
VOID EFIAPI MmReadyToLockEventNotify(IN EFI_EVENT Event, IN VOID *Context)
VOID EFIAPI MmEndOfDxeEventNotify(IN EFI_EVENT Event, IN VOID *Context)
VOID EFIAPI MmVirtualAddressChangeEvent(IN EFI_EVENT Event, IN VOID *Context)
VOID EFIAPI NotifyFunction(IN EFI_EVENT Event, IN VOID *Context)
Definition: ScsiBus.c:1492
RETURN_STATUS EFI_STATUS
Definition: UefiBaseType.h:29
VOID * EFI_EVENT
Definition: UefiBaseType.h:37
VOID * EFI_HANDLE
Definition: UefiBaseType.h:33
#define EFI_SUCCESS
Definition: UefiBaseType.h:112
EFI_BOOT_SERVICES * gBS
EFI_EVENT EFIAPI EfiCreateProtocolNotifyEvent(IN EFI_GUID *ProtocolGuid, IN EFI_TPL NotifyTpl, IN EFI_EVENT_NOTIFY NotifyFunction, IN VOID *NotifyContext OPTIONAL, OUT VOID **Registration)
Definition: UefiLib.c:134
EFI_STATUS EFIAPI EfiConvertPointer(IN UINTN DebugDisposition, IN OUT VOID **Address)
Definition: RuntimeLib.c:561
@ EFI_NATIVE_INTERFACE
Definition: UefiSpec.h:1193
Definition: Base.h:213
EFI_PHYSICAL_ADDRESS PhysicalStart
Definition: MmCommBuffer.h:31
EFI_PHYSICAL_ADDRESS Status
Definition: MmCommBuffer.h:41