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