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