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