VirtualBox

source: vbox/trunk/src/VBox/Devices/EFI/FirmwareNew/StandaloneMmPkg/Drivers/MmCommunicationDxe/MmCommunicationDxe.c@ 108794

Last change on this file since 108794 was 108794, checked in by vboxsync, 2 weeks ago

Devices/EFI/FirmwareNew: Merge edk2-stable202502 from the vendor branch and make it build for the important platforms, bugref:4643

  • Property svn:eol-style set to native
File size: 16.9 KB
Line 
1/** @file
2 MmCommunicationDxe driver produces MmCommunication protocol and
3 create the notifications of some protocols and event.
4
5 Copyright (c) 2024, Intel Corporation. All rights reserved.<BR>
6 SPDX-License-Identifier: BSD-2-Clause-Patent
7
8**/
9
10#include "MmCommunicationDxe.h"
11
12//
13// PI 1.7 MM Communication Protocol 2 instance
14//
15EFI_MM_COMMUNICATION2_PROTOCOL mMmCommunication2 = {
16 MmCommunicate2
17};
18
19//
20// PI 1.7 MM Communication Protocol instance
21//
22EFI_MM_COMMUNICATION_PROTOCOL mMmCommunication = {
23 MmCommunicate
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
78/**
79 Event notification that is fired when GUIDed Event Group is signaled.
80
81 @param Event The Event that is being processed, not used.
82 @param Context Event Context, not used.
83
84**/
85VOID
86EFIAPI
87MmGuidedEventNotify (
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
111/**
112 Event notification that is fired every time a DxeSmmReadyToLock protocol is added
113 or if gEfiEventReadyToBootGuid is signaled.
114
115 @param Event The Event that is being processed, not used.
116 @param Context Event Context, not used.
117
118**/
119VOID
120EFIAPI
121MmReadyToLockEventNotify (
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"));
156 REPORT_STATUS_CODE (
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
195/**
196 Event notification that is fired when EndOfDxe Event Group is signaled.
197
198 @param Event The Event that is being processed, not used.
199 @param Context Event Context, not used.
200
201**/
202VOID
203EFIAPI
204MmEndOfDxeEventNotify (
205 IN EFI_EVENT Event,
206 IN VOID *Context
207 )
208{
209 mEndOfDxe = TRUE;
210}
211
212/**
213 Notification function of EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE.
214
215 This is a notification function registered on EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE event.
216 It convers pointer to new virtual address.
217
218 @param[in] Event Event whose notification function is being invoked.
219 @param[in] Context Pointer to the notification function's context.
220
221**/
222VOID
223EFIAPI
224MmVirtualAddressChangeEvent (
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
234/**
235 Processes the communication buffer for Mm communication protocols.
236
237 This function encapsulates the common logic for handling communication buffers
238 used by MmCommunicate2 and MmCommunicate functions.
239
240 @param[in, out] CommBuffer Pointer to the MM communication buffer
241 @param[in, out] CommSize The size of the data buffer being passed in. On exit, the size of data
242 being returned. Zero if the handler does not wish to reply with any data.
243 This parameter is optional and may be NULL.
244
245 @retval EFI_SUCCESS The message was successfully posted.
246 @retval EFI_INVALID_PARAMETER The CommBuffer was NULL.
247 @retval EFI_BAD_BUFFER_SIZE The buffer is too large for the MM implementation.
248 If this error is returned, the MessageLength field
249 in the CommBuffer header or the integer pointed by
250 CommSize, are updated to reflect the maximum payload
251 size the implementation can accommodate.
252 @retval EFI_ACCESS_DENIED The CommunicateBuffer parameter or CommSize parameter,
253 if not omitted, are in address range that cannot be
254 accessed by the MM environment.
255**/
256EFI_STATUS
257EFIAPI
258ProcessCommunicationBuffer (
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
321/**
322 Communicates with a registered handler.
323
324 This function provides a service to send and receive messages from a registered UEFI service.
325
326 @param[in] This The EFI_MM_COMMUNICATION_PROTOCOL instance.
327 @param[in, out] CommBufferPhysical Physical address of the MM communication buffer.
328 @param[in, out] CommBufferVirtual Virtual address of the MM communication buffer.
329 @param[in, out] CommSize The size of the data buffer being passed in. On exit, the size of data
330 being returned. Zero if the handler does not wish to reply with any data.
331 This parameter is optional and may be NULL.
332
333 @retval EFI_SUCCESS The message was successfully posted.
334 @retval EFI_INVALID_PARAMETER The CommBuffer was NULL.
335 @retval EFI_BAD_BUFFER_SIZE The buffer is too large for the MM implementation.
336 If this error is returned, the MessageLength field
337 in the CommBuffer header or the integer pointed by
338 CommSize, are updated to reflect the maximum payload
339 size the implementation can accommodate.
340 @retval EFI_ACCESS_DENIED The CommunicateBuffer parameter or CommSize parameter,
341 if not omitted, are in address range that cannot be
342 accessed by the MM environment.
343
344**/
345EFI_STATUS
346EFIAPI
347MmCommunicate2 (
348 IN CONST EFI_MM_COMMUNICATION2_PROTOCOL *This,
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
357/**
358 Communicates with a registered handler.
359
360 This function provides a service to send and receive messages from a registered UEFI service.
361
362 @param[in] This The EFI_MM_COMMUNICATION_PROTOCOL instance.
363 @param[in, out] CommBuffer Pointer to the MM communication buffer
364 @param[in, out] CommSize The size of the data buffer being passed in. On exit, the size of data
365 being returned. Zero if the handler does not wish to reply with any data.
366 This parameter is optional and may be NULL.
367
368 @retval EFI_SUCCESS The message was successfully posted.
369 @retval EFI_INVALID_PARAMETER The CommBuffer was NULL.
370 @retval EFI_BAD_BUFFER_SIZE The buffer is too large for the MM implementation.
371 If this error is returned, the MessageLength field
372 in the CommBuffer header or the integer pointed by
373 CommSize, are updated to reflect the maximum payload
374 size the implementation can accommodate.
375 @retval EFI_ACCESS_DENIED The CommunicateBuffer parameter or CommSize parameter,
376 if not omitted, are in address range that cannot be
377 accessed by the MM environment.
378
379**/
380EFI_STATUS
381EFIAPI
382MmCommunicate (
383 IN CONST EFI_MM_COMMUNICATION_PROTOCOL *This,
384 IN OUT VOID *CommBuffer,
385 IN OUT UINTN *CommSize OPTIONAL
386 )
387{
388 return ProcessCommunicationBuffer (CommBuffer, CommSize);
389}
390
391/**
392 The Entry Point for MmCommunicateDxe driver.
393
394 @param ImageHandle The firmware allocated handle for the EFI image.
395 @param SystemTable A pointer to the EFI System Table.
396
397 @retval EFI_SUCCESS The entry point is executed successfully.
398 @retval Other Some error occurred when executing this entry point.
399
400**/
401EFI_STATUS
402EFIAPI
403MmCommunicationEntryPoint (
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,
439 EFI_NATIVE_INTERFACE,
440 &mMmCommunication2
441 );
442 ASSERT_EFI_ERROR (Status);
443
444 Status = gBS->InstallProtocolInterface (
445 &Handle,
446 &gEfiMmCommunicationProtocolGuid,
447 EFI_NATIVE_INTERFACE,
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}
Note: See TracBrowser for help on using the repository browser.

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette