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