]> git.proxmox.com Git - mirror_edk2.git/blob - StandaloneMmPkg/Core/Mmi.c
UefiCpuPkg: Move AsmRelocateApLoopStart from Mpfuncs.nasm to AmdSev.nasm
[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 - 2021, 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
101 return MmiEntry;
102 }
103
104 /**
105 Manage MMI of a particular type.
106
107 @param HandlerType Points to the handler type or NULL for root MMI handlers.
108 @param Context Points to an optional context buffer.
109 @param CommBuffer Points to the optional communication buffer.
110 @param CommBufferSize Points to the size of the optional communication buffer.
111
112 @retval EFI_WARN_INTERRUPT_SOURCE_PENDING Interrupt source was processed successfully but not quiesced.
113 @retval EFI_INTERRUPT_PENDING One or more MMI sources could not be quiesced.
114 @retval EFI_NOT_FOUND Interrupt source was not handled or quiesced.
115 @retval EFI_SUCCESS Interrupt source was handled and quiesced.
116
117 **/
118 EFI_STATUS
119 EFIAPI
120 MmiManage (
121 IN CONST EFI_GUID *HandlerType,
122 IN CONST VOID *Context OPTIONAL,
123 IN OUT VOID *CommBuffer OPTIONAL,
124 IN OUT UINTN *CommBufferSize OPTIONAL
125 )
126 {
127 LIST_ENTRY *Link;
128 LIST_ENTRY *Head;
129 MMI_ENTRY *MmiEntry;
130 MMI_HANDLER *MmiHandler;
131 BOOLEAN SuccessReturn;
132 EFI_STATUS Status;
133
134 Status = EFI_NOT_FOUND;
135 SuccessReturn = FALSE;
136 if (HandlerType == NULL) {
137 //
138 // Root MMI handler
139 //
140
141 Head = &mRootMmiHandlerList;
142 } else {
143 //
144 // Non-root MMI handler
145 //
146 MmiEntry = MmCoreFindMmiEntry ((EFI_GUID *)HandlerType, FALSE);
147 if (MmiEntry == NULL) {
148 //
149 // There is no handler registered for this interrupt source
150 //
151 return Status;
152 }
153
154 Head = &MmiEntry->MmiHandlers;
155 }
156
157 for (Link = Head->ForwardLink; Link != Head; Link = Link->ForwardLink) {
158 MmiHandler = CR (Link, MMI_HANDLER, Link, MMI_HANDLER_SIGNATURE);
159
160 Status = MmiHandler->Handler (
161 (EFI_HANDLE)MmiHandler,
162 Context,
163 CommBuffer,
164 CommBufferSize
165 );
166
167 switch (Status) {
168 case EFI_INTERRUPT_PENDING:
169 //
170 // If a handler returns EFI_INTERRUPT_PENDING and HandlerType is not NULL then
171 // no additional handlers will be processed and EFI_INTERRUPT_PENDING will be returned.
172 //
173 if (HandlerType != NULL) {
174 return EFI_INTERRUPT_PENDING;
175 }
176
177 break;
178
179 case EFI_SUCCESS:
180 //
181 // If at least one of the handlers returns EFI_SUCCESS then the function will return
182 // EFI_SUCCESS. If a handler returns EFI_SUCCESS and HandlerType is not NULL then no
183 // additional handlers will be processed.
184 //
185 if (HandlerType != NULL) {
186 return EFI_SUCCESS;
187 }
188
189 SuccessReturn = TRUE;
190 break;
191
192 case EFI_WARN_INTERRUPT_SOURCE_QUIESCED:
193 //
194 // If at least one of the handlers returns EFI_WARN_INTERRUPT_SOURCE_QUIESCED
195 // then the function will return EFI_SUCCESS.
196 //
197 SuccessReturn = TRUE;
198 break;
199
200 case EFI_WARN_INTERRUPT_SOURCE_PENDING:
201 //
202 // If all the handlers returned EFI_WARN_INTERRUPT_SOURCE_PENDING
203 // then EFI_WARN_INTERRUPT_SOURCE_PENDING will be returned.
204 //
205 break;
206
207 default:
208 //
209 // Unexpected status code returned.
210 //
211 ASSERT (FALSE);
212 break;
213 }
214 }
215
216 if (SuccessReturn) {
217 Status = EFI_SUCCESS;
218 }
219
220 return Status;
221 }
222
223 /**
224 Registers a handler to execute within MM.
225
226 @param Handler Handler service function pointer.
227 @param HandlerType Points to the handler type or NULL for root MMI handlers.
228 @param DispatchHandle On return, contains a unique handle which can be used to later unregister the handler function.
229
230 @retval EFI_SUCCESS Handler register success.
231 @retval EFI_INVALID_PARAMETER Handler or DispatchHandle is NULL.
232
233 **/
234 EFI_STATUS
235 EFIAPI
236 MmiHandlerRegister (
237 IN EFI_MM_HANDLER_ENTRY_POINT Handler,
238 IN CONST EFI_GUID *HandlerType OPTIONAL,
239 OUT EFI_HANDLE *DispatchHandle
240 )
241 {
242 MMI_HANDLER *MmiHandler;
243 MMI_ENTRY *MmiEntry;
244 LIST_ENTRY *List;
245
246 if ((Handler == NULL) || (DispatchHandle == NULL)) {
247 return EFI_INVALID_PARAMETER;
248 }
249
250 MmiHandler = AllocateZeroPool (sizeof (MMI_HANDLER));
251 if (MmiHandler == NULL) {
252 return EFI_OUT_OF_RESOURCES;
253 }
254
255 MmiHandler->Signature = MMI_HANDLER_SIGNATURE;
256 MmiHandler->Handler = Handler;
257
258 if (HandlerType == NULL) {
259 //
260 // This is root MMI handler
261 //
262 MmiEntry = NULL;
263 List = &mRootMmiHandlerList;
264 } else {
265 //
266 // None root MMI handler
267 //
268 MmiEntry = MmCoreFindMmiEntry ((EFI_GUID *)HandlerType, TRUE);
269 if (MmiEntry == NULL) {
270 return EFI_OUT_OF_RESOURCES;
271 }
272
273 List = &MmiEntry->MmiHandlers;
274 }
275
276 MmiHandler->MmiEntry = MmiEntry;
277 InsertTailList (List, &MmiHandler->Link);
278
279 *DispatchHandle = (EFI_HANDLE)MmiHandler;
280
281 return EFI_SUCCESS;
282 }
283
284 /**
285 Unregister a handler in MM.
286
287 @param DispatchHandle The handle that was specified when the handler was registered.
288
289 @retval EFI_SUCCESS Handler function was successfully unregistered.
290 @retval EFI_INVALID_PARAMETER DispatchHandle does not refer to a valid handle.
291
292 **/
293 EFI_STATUS
294 EFIAPI
295 MmiHandlerUnRegister (
296 IN EFI_HANDLE DispatchHandle
297 )
298 {
299 MMI_HANDLER *MmiHandler;
300 MMI_ENTRY *MmiEntry;
301
302 MmiHandler = (MMI_HANDLER *)DispatchHandle;
303
304 if (MmiHandler == NULL) {
305 return EFI_INVALID_PARAMETER;
306 }
307
308 if (MmiHandler->Signature != MMI_HANDLER_SIGNATURE) {
309 return EFI_INVALID_PARAMETER;
310 }
311
312 MmiEntry = MmiHandler->MmiEntry;
313
314 RemoveEntryList (&MmiHandler->Link);
315 FreePool (MmiHandler);
316
317 if (MmiEntry == NULL) {
318 //
319 // This is root MMI handler
320 //
321 return EFI_SUCCESS;
322 }
323
324 if (IsListEmpty (&MmiEntry->MmiHandlers)) {
325 //
326 // No handler registered for this interrupt now, remove the MMI_ENTRY
327 //
328 RemoveEntryList (&MmiEntry->AllEntries);
329
330 FreePool (MmiEntry);
331 }
332
333 return EFI_SUCCESS;
334 }