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