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