]> git.proxmox.com Git - mirror_edk2.git/blob - StandaloneMmPkg/Core/Mmi.c
StandaloneMmPkg: Replace BSD License with BSD+Patent License
[mirror_edk2.git] / StandaloneMmPkg / Core / Mmi.c
1 /** @file
2 MMI management.
3
4 Copyright (c) 2009 - 2013, Intel Corporation. All rights reserved.<BR>
5 Copyright (c) 2016 - 2018, ARM Limited. All rights reserved.<BR>
6 SPDX-License-Identifier: BSD-2-Clause-Patent
7
8 **/
9
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
22 typedef 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
32 typedef 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 } MMI_HANDLER;
38
39 LIST_ENTRY mRootMmiHandlerList = INITIALIZE_LIST_HEAD_VARIABLE (mRootMmiHandlerList);
40 LIST_ENTRY mMmiEntryList = INITIALIZE_LIST_HEAD_VARIABLE (mMmiEntryList);
41
42 /**
43 Finds the MMI entry for the requested handler type.
44
45 @param HandlerType The type of the interrupt
46 @param Create Create a new entry if not found
47
48 @return MMI entry
49
50 **/
51 MMI_ENTRY *
52 EFIAPI
53 MmCoreFindMmiEntry (
54 IN EFI_GUID *HandlerType,
55 IN BOOLEAN Create
56 )
57 {
58 LIST_ENTRY *Link;
59 MMI_ENTRY *Item;
60 MMI_ENTRY *MmiEntry;
61
62 //
63 // Search the MMI entry list for the matching GUID
64 //
65 MmiEntry = NULL;
66 for (Link = mMmiEntryList.ForwardLink;
67 Link != &mMmiEntryList;
68 Link = Link->ForwardLink) {
69
70 Item = CR (Link, MMI_ENTRY, AllEntries, MMI_ENTRY_SIGNATURE);
71 if (CompareGuid (&Item->HandlerType, HandlerType)) {
72 //
73 // This is the MMI entry
74 //
75 MmiEntry = Item;
76 break;
77 }
78 }
79
80 //
81 // If the protocol entry was not found and Create is TRUE, then
82 // allocate a new entry
83 //
84 if ((MmiEntry == NULL) && Create) {
85 MmiEntry = AllocatePool (sizeof (MMI_ENTRY));
86 if (MmiEntry != NULL) {
87 //
88 // Initialize new MMI entry structure
89 //
90 MmiEntry->Signature = MMI_ENTRY_SIGNATURE;
91 CopyGuid ((VOID *)&MmiEntry->HandlerType, HandlerType);
92 InitializeListHead (&MmiEntry->MmiHandlers);
93
94 //
95 // Add it to MMI entry list
96 //
97 InsertTailList (&mMmiEntryList, &MmiEntry->AllEntries);
98 }
99 }
100 return MmiEntry;
101 }
102
103 /**
104 Manage MMI of a particular type.
105
106 @param HandlerType Points to the handler type or NULL for root MMI handlers.
107 @param Context Points to an optional context buffer.
108 @param CommBuffer Points to the optional communication buffer.
109 @param CommBufferSize Points to the size of the optional communication buffer.
110
111 @retval EFI_WARN_INTERRUPT_SOURCE_PENDING Interrupt source was processed successfully but not quiesced.
112 @retval EFI_INTERRUPT_PENDING One or more MMI sources could not be quiesced.
113 @retval EFI_NOT_FOUND Interrupt source was not handled or quiesced.
114 @retval EFI_SUCCESS Interrupt source was handled and quiesced.
115
116 **/
117 EFI_STATUS
118 EFIAPI
119 MmiManage (
120 IN CONST EFI_GUID *HandlerType,
121 IN CONST VOID *Context OPTIONAL,
122 IN OUT VOID *CommBuffer OPTIONAL,
123 IN OUT UINTN *CommBufferSize OPTIONAL
124 )
125 {
126 LIST_ENTRY *Link;
127 LIST_ENTRY *Head;
128 MMI_ENTRY *MmiEntry;
129 MMI_HANDLER *MmiHandler;
130 BOOLEAN SuccessReturn;
131 EFI_STATUS Status;
132
133 Status = EFI_NOT_FOUND;
134 SuccessReturn = FALSE;
135 if (HandlerType == NULL) {
136 //
137 // Root MMI handler
138 //
139
140 Head = &mRootMmiHandlerList;
141 } else {
142 //
143 // Non-root MMI handler
144 //
145 MmiEntry = MmCoreFindMmiEntry ((EFI_GUID *) HandlerType, FALSE);
146 if (MmiEntry == NULL) {
147 //
148 // There is no handler registered for this interrupt source
149 //
150 return Status;
151 }
152
153 Head = &MmiEntry->MmiHandlers;
154 }
155
156 for (Link = Head->ForwardLink; Link != Head; Link = Link->ForwardLink) {
157 MmiHandler = CR (Link, MMI_HANDLER, Link, MMI_HANDLER_SIGNATURE);
158
159 Status = MmiHandler->Handler (
160 (EFI_HANDLE) MmiHandler,
161 Context,
162 CommBuffer,
163 CommBufferSize
164 );
165
166 switch (Status) {
167 case EFI_INTERRUPT_PENDING:
168 //
169 // If a handler returns EFI_INTERRUPT_PENDING and HandlerType is not NULL then
170 // no additional handlers will be processed and EFI_INTERRUPT_PENDING will be returned.
171 //
172 if (HandlerType != NULL) {
173 return EFI_INTERRUPT_PENDING;
174 }
175 break;
176
177 case EFI_SUCCESS:
178 //
179 // If at least one of the handlers returns EFI_SUCCESS then the function will return
180 // EFI_SUCCESS. If a handler returns EFI_SUCCESS and HandlerType is not NULL then no
181 // additional handlers will be processed.
182 //
183 if (HandlerType != NULL) {
184 return EFI_SUCCESS;
185 }
186 SuccessReturn = TRUE;
187 break;
188
189 case EFI_WARN_INTERRUPT_SOURCE_QUIESCED:
190 //
191 // If at least one of the handlers returns EFI_WARN_INTERRUPT_SOURCE_QUIESCED
192 // then the function will return EFI_SUCCESS.
193 //
194 SuccessReturn = TRUE;
195 break;
196
197 case EFI_WARN_INTERRUPT_SOURCE_PENDING:
198 //
199 // If all the handlers returned EFI_WARN_INTERRUPT_SOURCE_PENDING
200 // then EFI_WARN_INTERRUPT_SOURCE_PENDING will be returned.
201 //
202 break;
203
204 default:
205 //
206 // Unexpected status code returned.
207 //
208 ASSERT (FALSE);
209 break;
210 }
211 }
212
213 if (SuccessReturn) {
214 Status = EFI_SUCCESS;
215 }
216
217 return Status;
218 }
219
220 /**
221 Registers a handler to execute within MM.
222
223 @param Handler Handler service funtion pointer.
224 @param HandlerType Points to the handler type or NULL for root MMI handlers.
225 @param DispatchHandle On return, contains a unique handle which can be used to later unregister the handler function.
226
227 @retval EFI_SUCCESS Handler register success.
228 @retval EFI_INVALID_PARAMETER Handler or DispatchHandle is NULL.
229
230 **/
231 EFI_STATUS
232 EFIAPI
233 MmiHandlerRegister (
234 IN EFI_MM_HANDLER_ENTRY_POINT Handler,
235 IN CONST EFI_GUID *HandlerType OPTIONAL,
236 OUT EFI_HANDLE *DispatchHandle
237 )
238 {
239 MMI_HANDLER *MmiHandler;
240 MMI_ENTRY *MmiEntry;
241 LIST_ENTRY *List;
242
243 if (Handler == NULL || DispatchHandle == NULL) {
244 return EFI_INVALID_PARAMETER;
245 }
246
247 MmiHandler = AllocateZeroPool (sizeof (MMI_HANDLER));
248 if (MmiHandler == NULL) {
249 return EFI_OUT_OF_RESOURCES;
250 }
251
252 MmiHandler->Signature = MMI_HANDLER_SIGNATURE;
253 MmiHandler->Handler = Handler;
254
255 if (HandlerType == NULL) {
256 //
257 // This is root MMI handler
258 //
259 MmiEntry = NULL;
260 List = &mRootMmiHandlerList;
261 } else {
262 //
263 // None root MMI handler
264 //
265 MmiEntry = MmCoreFindMmiEntry ((EFI_GUID *) HandlerType, TRUE);
266 if (MmiEntry == NULL) {
267 return EFI_OUT_OF_RESOURCES;
268 }
269
270 List = &MmiEntry->MmiHandlers;
271 }
272
273 MmiHandler->MmiEntry = MmiEntry;
274 InsertTailList (List, &MmiHandler->Link);
275
276 *DispatchHandle = (EFI_HANDLE) MmiHandler;
277
278 return EFI_SUCCESS;
279 }
280
281 /**
282 Unregister a handler in MM.
283
284 @param DispatchHandle The handle that was specified when the handler was registered.
285
286 @retval EFI_SUCCESS Handler function was successfully unregistered.
287 @retval EFI_INVALID_PARAMETER DispatchHandle does not refer to a valid handle.
288
289 **/
290 EFI_STATUS
291 EFIAPI
292 MmiHandlerUnRegister (
293 IN EFI_HANDLE DispatchHandle
294 )
295 {
296 MMI_HANDLER *MmiHandler;
297 MMI_ENTRY *MmiEntry;
298
299 MmiHandler = (MMI_HANDLER *) DispatchHandle;
300
301 if (MmiHandler == NULL) {
302 return EFI_INVALID_PARAMETER;
303 }
304
305 if (MmiHandler->Signature != MMI_HANDLER_SIGNATURE) {
306 return EFI_INVALID_PARAMETER;
307 }
308
309 MmiEntry = MmiHandler->MmiEntry;
310
311 RemoveEntryList (&MmiHandler->Link);
312 FreePool (MmiHandler);
313
314 if (MmiEntry == NULL) {
315 //
316 // This is root MMI handler
317 //
318 return EFI_SUCCESS;
319 }
320
321 if (IsListEmpty (&MmiEntry->MmiHandlers)) {
322 //
323 // No handler registered for this interrupt now, remove the MMI_ENTRY
324 //
325 RemoveEntryList (&MmiEntry->AllEntries);
326
327 FreePool (MmiEntry);
328 }
329
330 return EFI_SUCCESS;
331 }