TianoCore EDK2 master
Loading...
Searching...
No Matches
Mmi.c
Go to the documentation of this file.
1
10#include "StandaloneMmCore.h"
11
12//
13// MM_HANDLER_STATE_NOTIFIER
14//
15
16//
17// MM_HANDLER - used for each MM handler
18//
19
20#define MMI_ENTRY_SIGNATURE SIGNATURE_32('m','m','i','e')
21
22typedef struct {
23 UINTN Signature;
24 LIST_ENTRY AllEntries; // All entries
25
26 EFI_GUID HandlerType; // Type of interrupt
27 LIST_ENTRY MmiHandlers; // All handlers
28} MMI_ENTRY;
29
30#define MMI_HANDLER_SIGNATURE SIGNATURE_32('m','m','i','h')
31
32typedef struct {
33 UINTN Signature;
34 LIST_ENTRY Link; // Link on MMI_ENTRY.MmiHandlers
35 EFI_MM_HANDLER_ENTRY_POINT Handler; // The mm handler's entry point
36 MMI_ENTRY *MmiEntry;
37 BOOLEAN ToRemove; // To remove this MMI_HANDLER later
39
40//
41// mMmiManageCallingDepth is used to track the depth of recursive calls of MmiManage.
42//
43UINTN mMmiManageCallingDepth = 0;
44
45LIST_ENTRY mRootMmiHandlerList = INITIALIZE_LIST_HEAD_VARIABLE (mRootMmiHandlerList);
46LIST_ENTRY mMmiEntryList = INITIALIZE_LIST_HEAD_VARIABLE (mMmiEntryList);
47
58BOOLEAN
60 IN MMI_HANDLER *MmiHandler,
61 IN MMI_ENTRY *MmiEntry
62 )
63{
64 ASSERT (MmiHandler->ToRemove);
65 RemoveEntryList (&MmiHandler->Link);
66 FreePool (MmiHandler);
67
68 //
69 // Remove the MMI_ENTRY if all handlers have been removed.
70 //
71 if (MmiEntry != NULL) {
72 if (IsListEmpty (&MmiEntry->MmiHandlers)) {
73 RemoveEntryList (&MmiEntry->AllEntries);
74 FreePool (MmiEntry);
75 return TRUE;
76 }
77 }
78
79 return FALSE;
80}
81
92EFIAPI
94 IN EFI_GUID *HandlerType,
95 IN BOOLEAN Create
96 )
97{
98 LIST_ENTRY *Link;
99 MMI_ENTRY *Item;
100 MMI_ENTRY *MmiEntry;
101
102 //
103 // Search the MMI entry list for the matching GUID
104 //
105 MmiEntry = NULL;
106 for (Link = mMmiEntryList.ForwardLink;
107 Link != &mMmiEntryList;
108 Link = Link->ForwardLink)
109 {
110 Item = CR (Link, MMI_ENTRY, AllEntries, MMI_ENTRY_SIGNATURE);
111 if (CompareGuid (&Item->HandlerType, HandlerType)) {
112 //
113 // This is the MMI entry
114 //
115 MmiEntry = Item;
116 break;
117 }
118 }
119
120 //
121 // If the protocol entry was not found and Create is TRUE, then
122 // allocate a new entry
123 //
124 if ((MmiEntry == NULL) && Create) {
125 MmiEntry = AllocatePool (sizeof (MMI_ENTRY));
126 if (MmiEntry != NULL) {
127 //
128 // Initialize new MMI entry structure
129 //
130 MmiEntry->Signature = MMI_ENTRY_SIGNATURE;
131 CopyGuid ((VOID *)&MmiEntry->HandlerType, HandlerType);
132 InitializeListHead (&MmiEntry->MmiHandlers);
133
134 //
135 // Add it to MMI entry list
136 //
137 InsertTailList (&mMmiEntryList, &MmiEntry->AllEntries);
138 }
139 }
140
141 return MmiEntry;
142}
143
159EFIAPI
161 IN CONST EFI_GUID *HandlerType,
162 IN CONST VOID *Context OPTIONAL,
163 IN OUT VOID *CommBuffer OPTIONAL,
164 IN OUT UINTN *CommBufferSize OPTIONAL
165 )
166{
167 LIST_ENTRY *Link;
168 LIST_ENTRY *Head;
169 LIST_ENTRY *EntryLink;
170 MMI_ENTRY *MmiEntry;
171 MMI_HANDLER *MmiHandler;
172 EFI_STATUS ReturnStatus;
173 BOOLEAN WillReturn;
174 EFI_STATUS Status;
175
176 mMmiManageCallingDepth++;
177 WillReturn = FALSE;
178 Status = EFI_NOT_FOUND;
179 ReturnStatus = Status;
180 if (HandlerType == NULL) {
181 //
182 // Root MMI handler
183 //
184
185 Head = &mRootMmiHandlerList;
186 } else {
187 //
188 // Non-root MMI handler
189 //
190 MmiEntry = MmCoreFindMmiEntry ((EFI_GUID *)HandlerType, FALSE);
191 if (MmiEntry == NULL) {
192 //
193 // There is no handler registered for this interrupt source
194 //
195 return Status;
196 }
197
198 Head = &MmiEntry->MmiHandlers;
199 }
200
201 for (Link = Head->ForwardLink; Link != Head; Link = Link->ForwardLink) {
202 MmiHandler = CR (Link, MMI_HANDLER, Link, MMI_HANDLER_SIGNATURE);
203
204 Status = MmiHandler->Handler (
205 (EFI_HANDLE)MmiHandler,
206 Context,
207 CommBuffer,
208 CommBufferSize
209 );
210
211 switch (Status) {
213 //
214 // If a handler returns EFI_INTERRUPT_PENDING and HandlerType is not NULL then
215 // no additional handlers will be processed and EFI_INTERRUPT_PENDING will be returned.
216 //
217 if (HandlerType != NULL) {
218 ReturnStatus = EFI_INTERRUPT_PENDING;
219 WillReturn = TRUE;
220 } else {
221 //
222 // If any other handler's result sets ReturnStatus as EFI_SUCCESS, the return status
223 // will be EFI_SUCCESS.
224 //
225 if (ReturnStatus != EFI_SUCCESS) {
226 ReturnStatus = Status;
227 }
228 }
229
230 break;
231
232 case EFI_SUCCESS:
233 //
234 // If at least one of the handlers returns EFI_SUCCESS then the function will return
235 // EFI_SUCCESS. If a handler returns EFI_SUCCESS and HandlerType is not NULL then no
236 // additional handlers will be processed.
237 //
238 if (HandlerType != NULL) {
239 WillReturn = TRUE;
240 }
241
242 ReturnStatus = EFI_SUCCESS;
243 break;
244
245 case EFI_WARN_INTERRUPT_SOURCE_QUIESCED:
246 //
247 // If at least one of the handlers returns EFI_WARN_INTERRUPT_SOURCE_QUIESCED
248 // then the function will return EFI_SUCCESS.
249 //
250 ReturnStatus = EFI_SUCCESS;
251 break;
252
253 case EFI_WARN_INTERRUPT_SOURCE_PENDING:
254 //
255 // If all the handlers returned EFI_WARN_INTERRUPT_SOURCE_PENDING
256 // then EFI_WARN_INTERRUPT_SOURCE_PENDING will be returned.
257 //
258 if (ReturnStatus != EFI_SUCCESS) {
259 ReturnStatus = Status;
260 }
261
262 break;
263
264 default:
265 //
266 // Unexpected status code returned.
267 //
268 ASSERT_EFI_ERROR (Status);
269 break;
270 }
271
272 if (WillReturn) {
273 break;
274 }
275 }
276
277 ASSERT (mMmiManageCallingDepth > 0);
278 mMmiManageCallingDepth--;
279
280 //
281 // MmiHandlerUnRegister() calls from MMI handlers are deferred till this point.
282 // Before returned from MmiManage, delete the MmiHandler which is
283 // marked as ToRemove.
284 // Note that MmiManage can be called recursively.
285 //
286 if (mMmiManageCallingDepth == 0) {
287 //
288 // Go through all MmiHandler in root Mmi handlers
289 //
290 for ( Link = GetFirstNode (&mRootMmiHandlerList)
291 ; !IsNull (&mRootMmiHandlerList, Link);
292 )
293 {
294 //
295 // MmiHandler might be removed in below, so cache the next link in Link
296 //
297 MmiHandler = CR (Link, MMI_HANDLER, Link, MMI_HANDLER_SIGNATURE);
298 Link = GetNextNode (&mRootMmiHandlerList, Link);
299 if (MmiHandler->ToRemove) {
300 //
301 // Remove MmiHandler if the ToRemove is set.
302 //
303 RemoveMmiHandler (MmiHandler, NULL);
304 }
305 }
306
307 //
308 // Go through all MmiHandler in non-root MMI handlers
309 //
310 for ( EntryLink = GetFirstNode (&mMmiEntryList)
311 ; !IsNull (&mMmiEntryList, EntryLink);
312 )
313 {
314 //
315 // MmiEntry might be removed in below, so cache the next link in EntryLink
316 //
317 MmiEntry = CR (EntryLink, MMI_ENTRY, AllEntries, MMI_ENTRY_SIGNATURE);
318 EntryLink = GetNextNode (&mMmiEntryList, EntryLink);
319 for ( Link = GetFirstNode (&MmiEntry->MmiHandlers)
320 ; !IsNull (&MmiEntry->MmiHandlers, Link);
321 )
322 {
323 //
324 // MmiHandler might be removed in below, so cache the next link in Link
325 //
326 MmiHandler = CR (Link, MMI_HANDLER, Link, MMI_HANDLER_SIGNATURE);
327 Link = GetNextNode (&MmiEntry->MmiHandlers, Link);
328 if (MmiHandler->ToRemove) {
329 //
330 // Remove MmiHandler if the ToRemove is set.
331 //
332 if (RemoveMmiHandler (MmiHandler, MmiEntry)) {
333 break;
334 }
335 }
336 }
337 }
338 }
339
340 return ReturnStatus;
341}
342
355EFIAPI
358 IN CONST EFI_GUID *HandlerType OPTIONAL,
359 OUT EFI_HANDLE *DispatchHandle
360 )
361{
362 MMI_HANDLER *MmiHandler;
363 MMI_ENTRY *MmiEntry;
364 LIST_ENTRY *List;
365
366 if ((Handler == NULL) || (DispatchHandle == NULL)) {
367 return EFI_INVALID_PARAMETER;
368 }
369
370 MmiHandler = AllocateZeroPool (sizeof (MMI_HANDLER));
371 if (MmiHandler == NULL) {
372 return EFI_OUT_OF_RESOURCES;
373 }
374
375 MmiHandler->Signature = MMI_HANDLER_SIGNATURE;
376 MmiHandler->Handler = Handler;
377 MmiHandler->ToRemove = FALSE;
378
379 if (HandlerType == NULL) {
380 //
381 // This is root MMI handler
382 //
383 MmiEntry = NULL;
384 List = &mRootMmiHandlerList;
385 } else {
386 //
387 // None root MMI handler
388 //
389 MmiEntry = MmCoreFindMmiEntry ((EFI_GUID *)HandlerType, TRUE);
390 if (MmiEntry == NULL) {
391 return EFI_OUT_OF_RESOURCES;
392 }
393
394 List = &MmiEntry->MmiHandlers;
395 }
396
397 MmiHandler->MmiEntry = MmiEntry;
398 InsertTailList (List, &MmiHandler->Link);
399
400 *DispatchHandle = (EFI_HANDLE)MmiHandler;
401
402 return EFI_SUCCESS;
403}
404
415EFIAPI
417 IN EFI_HANDLE DispatchHandle
418 )
419{
420 MMI_HANDLER *MmiHandler;
421 MMI_ENTRY *MmiEntry;
422
423 MmiHandler = (MMI_HANDLER *)DispatchHandle;
424
425 if (MmiHandler == NULL) {
426 return EFI_INVALID_PARAMETER;
427 }
428
429 if (MmiHandler->Signature != MMI_HANDLER_SIGNATURE) {
430 return EFI_INVALID_PARAMETER;
431 }
432
433 MmiHandler->ToRemove = TRUE;
434 if (mMmiManageCallingDepth > 0) {
435 //
436 // This function is called from MmiManage()
437 // Do not delete or remove MmiHandler or MmiEntry now.
438 //
439 return EFI_SUCCESS;
440 }
441
442 MmiEntry = MmiHandler->MmiEntry;
443 RemoveMmiHandler (MmiHandler, MmiEntry);
444
445 return EFI_SUCCESS;
446}
UINT64 UINTN
BOOLEAN EFIAPI IsNull(IN CONST LIST_ENTRY *List, IN CONST LIST_ENTRY *Node)
Definition: LinkedList.c:443
BOOLEAN EFIAPI IsListEmpty(IN CONST LIST_ENTRY *ListHead)
Definition: LinkedList.c:403
LIST_ENTRY *EFIAPI GetNextNode(IN CONST LIST_ENTRY *List, IN CONST LIST_ENTRY *Node)
Definition: LinkedList.c:333
LIST_ENTRY *EFIAPI GetFirstNode(IN CONST LIST_ENTRY *List)
Definition: LinkedList.c:298
LIST_ENTRY *EFIAPI RemoveEntryList(IN CONST LIST_ENTRY *Entry)
Definition: LinkedList.c:590
LIST_ENTRY *EFIAPI InitializeListHead(IN OUT LIST_ENTRY *ListHead)
Definition: LinkedList.c:182
#define INITIALIZE_LIST_HEAD_VARIABLE(ListHead)
Definition: BaseLib.h:2904
LIST_ENTRY *EFIAPI InsertTailList(IN OUT LIST_ENTRY *ListHead, IN OUT LIST_ENTRY *Entry)
Definition: LinkedList.c:259
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
VOID *EFIAPI AllocateZeroPool(IN UINTN AllocationSize)
VOID EFIAPI FreePool(IN VOID *Buffer)
#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 OUT
Definition: Base.h:284
#define ASSERT_EFI_ERROR(StatusParameter)
Definition: DebugLib.h:462
#define CR(Record, TYPE, Field, TestSignature)
Definition: DebugLib.h:659
EFI_STATUS EFIAPI MmiHandlerRegister(IN EFI_MM_HANDLER_ENTRY_POINT Handler, IN CONST EFI_GUID *HandlerType OPTIONAL, OUT EFI_HANDLE *DispatchHandle)
Definition: Mmi.c:356
BOOLEAN RemoveMmiHandler(IN MMI_HANDLER *MmiHandler, IN MMI_ENTRY *MmiEntry)
Definition: Mmi.c:59
MMI_ENTRY *EFIAPI MmCoreFindMmiEntry(IN EFI_GUID *HandlerType, IN BOOLEAN Create)
Definition: Mmi.c:93
EFI_STATUS EFIAPI MmiManage(IN CONST EFI_GUID *HandlerType, IN CONST VOID *Context OPTIONAL, IN OUT VOID *CommBuffer OPTIONAL, IN OUT UINTN *CommBufferSize OPTIONAL)
Definition: Mmi.c:160
EFI_STATUS EFIAPI MmiHandlerUnRegister(IN EFI_HANDLE DispatchHandle)
Definition: Mmi.c:416
EFI_STATUS(EFIAPI * EFI_MM_HANDLER_ENTRY_POINT)(IN EFI_HANDLE DispatchHandle, IN CONST VOID *Context OPTIONAL, IN OUT VOID *CommBuffer OPTIONAL, IN OUT UINTN *CommBufferSize OPTIONAL)
Definition: PiMmCis.h:162
#define EFI_INTERRUPT_PENDING
Definition: PiMultiPhase.h:73
VOID *EFIAPI AllocatePool(IN UINTN AllocationSize)
RETURN_STATUS EFI_STATUS
Definition: UefiBaseType.h:29
VOID * EFI_HANDLE
Definition: UefiBaseType.h:33
#define EFI_SUCCESS
Definition: UefiBaseType.h:112
Definition: Base.h:213
Definition: Mmi.c:22