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