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