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