]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Core/PiSmmCore/Smi.c
MdeModulePkg: Replace BSD License with BSD+Patent License
[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
e42e9404 11LIST_ENTRY mSmiEntryList = INITIALIZE_LIST_HEAD_VARIABLE (mSmiEntryList);\r
12\r
ca41f3f4
JY
13SMI_ENTRY mRootSmiEntry = {\r
14 SMI_ENTRY_SIGNATURE,\r
15 INITIALIZE_LIST_HEAD_VARIABLE (mRootSmiEntry.AllEntries),\r
16 {0},\r
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
46 Link = Link->ForwardLink) {\r
47\r
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
63 SmiEntry = AllocatePool (sizeof(SMI_ENTRY));\r
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
78 return SmiEntry;\r
79}\r
80\r
81/**\r
82 Manage SMI of a particular type.\r
83\r
84 @param HandlerType Points to the handler type or NULL for root SMI handlers.\r
85 @param Context Points to an optional context buffer.\r
86 @param CommBuffer Points to the optional communication buffer.\r
87 @param CommBufferSize Points to the size of the optional communication buffer.\r
88\r
d5b339a9 89 @retval EFI_WARN_INTERRUPT_SOURCE_PENDING Interrupt source was processed successfully but not quiesced.\r
e42e9404 90 @retval EFI_INTERRUPT_PENDING One or more SMI sources could not be quiesced.\r
d5b339a9 91 @retval EFI_NOT_FOUND Interrupt source was not handled or quiesced.\r
92 @retval EFI_SUCCESS Interrupt source was handled and quiesced.\r
e42e9404 93\r
94**/\r
95EFI_STATUS\r
96EFIAPI\r
97SmiManage (\r
98 IN CONST EFI_GUID *HandlerType,\r
99 IN CONST VOID *Context OPTIONAL,\r
100 IN OUT VOID *CommBuffer OPTIONAL,\r
101 IN OUT UINTN *CommBufferSize OPTIONAL\r
102 )\r
103{\r
104 LIST_ENTRY *Link;\r
105 LIST_ENTRY *Head;\r
106 SMI_ENTRY *SmiEntry;\r
107 SMI_HANDLER *SmiHandler;\r
510ed431 108 BOOLEAN SuccessReturn;\r
e42e9404 109 EFI_STATUS Status;\r
d1102dba 110\r
d5b339a9 111 Status = EFI_NOT_FOUND;\r
510ed431 112 SuccessReturn = FALSE;\r
e42e9404 113 if (HandlerType == NULL) {\r
114 //\r
115 // Root SMI handler\r
116 //\r
ca41f3f4 117 SmiEntry = &mRootSmiEntry;\r
d5b339a9 118 } else {\r
e42e9404 119 //\r
d5b339a9 120 // Non-root SMI handler\r
e42e9404 121 //\r
d5b339a9 122 SmiEntry = SmmCoreFindSmiEntry ((EFI_GUID *) HandlerType, FALSE);\r
123 if (SmiEntry == NULL) {\r
124 //\r
125 // There is no handler registered for this interrupt source\r
126 //\r
127 return Status;\r
128 }\r
e42e9404 129 }\r
ca41f3f4 130 Head = &SmiEntry->SmiHandlers;\r
e42e9404 131\r
e42e9404 132 for (Link = Head->ForwardLink; Link != Head; Link = Link->ForwardLink) {\r
133 SmiHandler = CR (Link, SMI_HANDLER, Link, SMI_HANDLER_SIGNATURE);\r
134\r
135 Status = SmiHandler->Handler (\r
136 (EFI_HANDLE) SmiHandler,\r
137 Context,\r
138 CommBuffer,\r
139 CommBufferSize\r
140 );\r
141\r
142 switch (Status) {\r
143 case EFI_INTERRUPT_PENDING:\r
144 //\r
510ed431 145 // If a handler returns EFI_INTERRUPT_PENDING and HandlerType is not NULL then\r
146 // no additional handlers will be processed and EFI_INTERRUPT_PENDING will be returned.\r
e42e9404 147 //\r
6b52b72f 148 if (HandlerType != NULL) {\r
149 return EFI_INTERRUPT_PENDING;\r
150 }\r
151 break;\r
e42e9404 152\r
153 case EFI_SUCCESS:\r
154 //\r
510ed431 155 // If at least one of the handlers returns EFI_SUCCESS then the function will return\r
156 // EFI_SUCCESS. If a handler returns EFI_SUCCESS and HandlerType is not NULL then no\r
157 // additional handlers will be processed.\r
e42e9404 158 //\r
6b52b72f 159 if (HandlerType != NULL) {\r
160 return EFI_SUCCESS;\r
161 }\r
510ed431 162 SuccessReturn = TRUE;\r
6b52b72f 163 break;\r
e42e9404 164\r
165 case EFI_WARN_INTERRUPT_SOURCE_QUIESCED:\r
166 //\r
d5b339a9 167 // If at least one of the handlers returns EFI_WARN_INTERRUPT_SOURCE_QUIESCED\r
d1102dba 168 // then the function will return EFI_SUCCESS.\r
e42e9404 169 //\r
510ed431 170 SuccessReturn = TRUE;\r
e42e9404 171 break;\r
172\r
d5b339a9 173 case EFI_WARN_INTERRUPT_SOURCE_PENDING:\r
174 //\r
175 // If all the handlers returned EFI_WARN_INTERRUPT_SOURCE_PENDING\r
176 // then EFI_WARN_INTERRUPT_SOURCE_PENDING will be returned.\r
177 //\r
178 break;\r
179\r
e42e9404 180 default:\r
d5b339a9 181 //\r
182 // Unexpected status code returned.\r
183 //\r
184 ASSERT (FALSE);\r
e42e9404 185 break;\r
186 }\r
187 }\r
188\r
510ed431 189 if (SuccessReturn) {\r
d5b339a9 190 Status = EFI_SUCCESS;\r
e42e9404 191 }\r
d5b339a9 192\r
e42e9404 193 return Status;\r
194}\r
195\r
196/**\r
197 Registers a handler to execute within SMM.\r
198\r
199 @param Handler Handler service funtion pointer.\r
200 @param HandlerType Points to the handler type or NULL for root SMI handlers.\r
201 @param DispatchHandle On return, contains a unique handle which can be used to later unregister the handler function.\r
202\r
203 @retval EFI_SUCCESS Handler register success.\r
204 @retval EFI_INVALID_PARAMETER Handler or DispatchHandle is NULL.\r
205\r
206**/\r
207EFI_STATUS\r
208EFIAPI\r
209SmiHandlerRegister (\r
210 IN EFI_SMM_HANDLER_ENTRY_POINT2 Handler,\r
211 IN CONST EFI_GUID *HandlerType OPTIONAL,\r
212 OUT EFI_HANDLE *DispatchHandle\r
213 )\r
214{\r
215 SMI_HANDLER *SmiHandler;\r
216 SMI_ENTRY *SmiEntry;\r
217 LIST_ENTRY *List;\r
218\r
219 if (Handler == NULL || DispatchHandle == NULL) {\r
220 return EFI_INVALID_PARAMETER;\r
221 }\r
222\r
223 SmiHandler = AllocateZeroPool (sizeof (SMI_HANDLER));\r
224 if (SmiHandler == NULL) {\r
225 return EFI_OUT_OF_RESOURCES;\r
226 }\r
227\r
228 SmiHandler->Signature = SMI_HANDLER_SIGNATURE;\r
229 SmiHandler->Handler = Handler;\r
ca41f3f4 230 SmiHandler->CallerAddr = (UINTN)RETURN_ADDRESS (0);\r
e42e9404 231\r
232 if (HandlerType == NULL) {\r
233 //\r
234 // This is root SMI handler\r
235 //\r
ca41f3f4 236 SmiEntry = &mRootSmiEntry;\r
e42e9404 237 } else {\r
238 //\r
239 // None root SMI handler\r
240 //\r
241 SmiEntry = SmmCoreFindSmiEntry ((EFI_GUID *) HandlerType, TRUE);\r
242 if (SmiEntry == NULL) {\r
243 return EFI_OUT_OF_RESOURCES;\r
244 }\r
e42e9404 245 }\r
ca41f3f4 246 List = &SmiEntry->SmiHandlers;\r
e42e9404 247\r
248 SmiHandler->SmiEntry = SmiEntry;\r
249 InsertTailList (List, &SmiHandler->Link);\r
250\r
251 *DispatchHandle = (EFI_HANDLE) SmiHandler;\r
252\r
253 return EFI_SUCCESS;\r
254}\r
255\r
256/**\r
257 Unregister a handler in SMM.\r
258\r
259 @param DispatchHandle The handle that was specified when the handler was registered.\r
260\r
261 @retval EFI_SUCCESS Handler function was successfully unregistered.\r
262 @retval EFI_INVALID_PARAMETER DispatchHandle does not refer to a valid handle.\r
263\r
264**/\r
265EFI_STATUS\r
266EFIAPI\r
267SmiHandlerUnRegister (\r
268 IN EFI_HANDLE DispatchHandle\r
269 )\r
270{\r
271 SMI_HANDLER *SmiHandler;\r
272 SMI_ENTRY *SmiEntry;\r
8a641d2b
RN
273 LIST_ENTRY *EntryLink;\r
274 LIST_ENTRY *HandlerLink;\r
e42e9404 275\r
8a641d2b 276 if (DispatchHandle == NULL) {\r
e42e9404 277 return EFI_INVALID_PARAMETER;\r
278 }\r
279\r
8a641d2b
RN
280 //\r
281 // Look for it in root SMI handlers\r
282 //\r
283 SmiHandler = NULL;\r
284 for ( HandlerLink = GetFirstNode (&mRootSmiEntry.SmiHandlers)\r
285 ; !IsNull (&mRootSmiEntry.SmiHandlers, HandlerLink) && (SmiHandler != DispatchHandle)\r
286 ; HandlerLink = GetNextNode (&mRootSmiEntry.SmiHandlers, HandlerLink)\r
287 ) {\r
288 SmiHandler = CR (HandlerLink, SMI_HANDLER, Link, SMI_HANDLER_SIGNATURE);\r
289 }\r
290\r
291 //\r
292 // Look for it in non-root SMI handlers\r
293 //\r
294 for ( EntryLink = GetFirstNode (&mSmiEntryList)\r
295 ; !IsNull (&mSmiEntryList, EntryLink) && (SmiHandler != DispatchHandle)\r
296 ; EntryLink = GetNextNode (&mSmiEntryList, EntryLink)\r
297 ) {\r
298 SmiEntry = CR (EntryLink, SMI_ENTRY, AllEntries, SMI_ENTRY_SIGNATURE);\r
299 for ( HandlerLink = GetFirstNode (&SmiEntry->SmiHandlers)\r
300 ; !IsNull (&SmiEntry->SmiHandlers, HandlerLink) && (SmiHandler != DispatchHandle)\r
301 ; HandlerLink = GetNextNode (&SmiEntry->SmiHandlers, HandlerLink)\r
302 ) {\r
303 SmiHandler = CR (HandlerLink, SMI_HANDLER, Link, SMI_HANDLER_SIGNATURE);\r
304 }\r
305 }\r
306\r
307 if (SmiHandler != DispatchHandle) {\r
e42e9404 308 return EFI_INVALID_PARAMETER;\r
309 }\r
310\r
311 SmiEntry = SmiHandler->SmiEntry;\r
312\r
313 RemoveEntryList (&SmiHandler->Link);\r
314 FreePool (SmiHandler);\r
315\r
316 if (SmiEntry == NULL) {\r
317 //\r
318 // This is root SMI handler\r
319 //\r
320 return EFI_SUCCESS;\r
321 }\r
322\r
323 if (IsListEmpty (&SmiEntry->SmiHandlers)) {\r
324 //\r
325 // No handler registered for this interrupt now, remove the SMI_ENTRY\r
326 //\r
327 RemoveEntryList (&SmiEntry->AllEntries);\r
328\r
329 FreePool (SmiEntry);\r
330 }\r
331\r
332 return EFI_SUCCESS;\r
333}\r