]> git.proxmox.com Git - mirror_edk2.git/blame_incremental - MdeModulePkg/Core/PiSmmCore/Smi.c
MdeModulePkg/PiSmmCore: Add SmiHandlerProfile support.
[mirror_edk2.git] / MdeModulePkg / Core / PiSmmCore / Smi.c
... / ...
CommitLineData
1/** @file\r
2 SMI management.\r
3\r
4 Copyright (c) 2009 - 2017, Intel Corporation. All rights reserved.<BR>\r
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
17LIST_ENTRY mSmiEntryList = INITIALIZE_LIST_HEAD_VARIABLE (mSmiEntryList);\r
18\r
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
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
95 @retval EFI_WARN_INTERRUPT_SOURCE_PENDING Interrupt source was processed successfully but not quiesced.\r
96 @retval EFI_INTERRUPT_PENDING One or more SMI sources could not be quiesced.\r
97 @retval EFI_NOT_FOUND Interrupt source was not handled or quiesced.\r
98 @retval EFI_SUCCESS Interrupt source was handled and quiesced.\r
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
114 BOOLEAN SuccessReturn;\r
115 EFI_STATUS Status;\r
116 \r
117 Status = EFI_NOT_FOUND;\r
118 SuccessReturn = FALSE;\r
119 if (HandlerType == NULL) {\r
120 //\r
121 // Root SMI handler\r
122 //\r
123 SmiEntry = &mRootSmiEntry;\r
124 } else {\r
125 //\r
126 // Non-root SMI handler\r
127 //\r
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
135 }\r
136 Head = &SmiEntry->SmiHandlers;\r
137\r
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
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
153 //\r
154 if (HandlerType != NULL) {\r
155 return EFI_INTERRUPT_PENDING;\r
156 }\r
157 break;\r
158\r
159 case EFI_SUCCESS:\r
160 //\r
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
164 //\r
165 if (HandlerType != NULL) {\r
166 return EFI_SUCCESS;\r
167 }\r
168 SuccessReturn = TRUE;\r
169 break;\r
170\r
171 case EFI_WARN_INTERRUPT_SOURCE_QUIESCED:\r
172 //\r
173 // If at least one of the handlers returns EFI_WARN_INTERRUPT_SOURCE_QUIESCED\r
174 // then the function will return EFI_SUCCESS. \r
175 //\r
176 SuccessReturn = TRUE;\r
177 break;\r
178\r
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
186 default:\r
187 //\r
188 // Unexpected status code returned.\r
189 //\r
190 ASSERT (FALSE);\r
191 break;\r
192 }\r
193 }\r
194\r
195 if (SuccessReturn) {\r
196 Status = EFI_SUCCESS;\r
197 }\r
198\r
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
236 SmiHandler->CallerAddr = (UINTN)RETURN_ADDRESS (0);\r
237\r
238 if (HandlerType == NULL) {\r
239 //\r
240 // This is root SMI handler\r
241 //\r
242 SmiEntry = &mRootSmiEntry;\r
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
251 }\r
252 List = &SmiEntry->SmiHandlers;\r
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