1 /** @file
2 SMM handle & protocol handling.
3
4 Copyright (c) 2009 - 2010, 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 // mProtocolDatabase - A list of all protocols in the system. (simple list for now)
19 // gHandleList - A list of all the handles in the system
20 //
21 LIST_ENTRY mProtocolDatabase = INITIALIZE_LIST_HEAD_VARIABLE (mProtocolDatabase);
22 LIST_ENTRY gHandleList = INITIALIZE_LIST_HEAD_VARIABLE (gHandleList);
23
24 /**
25 Check whether a handle is a valid EFI_HANDLE
26
27 @param UserHandle The handle to check
28
29 @retval EFI_INVALID_PARAMETER The handle is NULL or not a valid EFI_HANDLE.
30 @retval EFI_SUCCESS The handle is valid EFI_HANDLE.
31
32 **/
33 EFI_STATUS
SmmValidateHandle(IN EFI_HANDLE UserHandle)34 SmmValidateHandle (
35 IN EFI_HANDLE UserHandle
36 )
37 {
38 IHANDLE *Handle;
39
40 Handle = (IHANDLE *)UserHandle;
41 if (Handle == NULL) {
42 return EFI_INVALID_PARAMETER;
43 }
44 if (Handle->Signature != EFI_HANDLE_SIGNATURE) {
45 return EFI_INVALID_PARAMETER;
46 }
47 return EFI_SUCCESS;
48 }
49
50 /**
51 Finds the protocol entry for the requested protocol.
52
53 @param Protocol The ID of the protocol
54 @param Create Create a new entry if not found
55
56 @return Protocol entry
57
58 **/
59 PROTOCOL_ENTRY *
SmmFindProtocolEntry(IN EFI_GUID * Protocol,IN BOOLEAN Create)60 SmmFindProtocolEntry (
61 IN EFI_GUID *Protocol,
62 IN BOOLEAN Create
63 )
64 {
65 LIST_ENTRY *Link;
66 PROTOCOL_ENTRY *Item;
67 PROTOCOL_ENTRY *ProtEntry;
68
69 //
70 // Search the database for the matching GUID
71 //
72
73 ProtEntry = NULL;
74 for (Link = mProtocolDatabase.ForwardLink;
75 Link != &mProtocolDatabase;
76 Link = Link->ForwardLink) {
77
78 Item = CR(Link, PROTOCOL_ENTRY, AllEntries, PROTOCOL_ENTRY_SIGNATURE);
79 if (CompareGuid (&Item->ProtocolID, Protocol)) {
80 //
81 // This is the protocol entry
82 //
83 ProtEntry = Item;
84 break;
85 }
86 }
87
88 //
89 // If the protocol entry was not found and Create is TRUE, then
90 // allocate a new entry
91 //
92 if ((ProtEntry == NULL) && Create) {
93 ProtEntry = AllocatePool (sizeof(PROTOCOL_ENTRY));
94 if (ProtEntry != NULL) {
95 //
96 // Initialize new protocol entry structure
97 //
98 ProtEntry->Signature = PROTOCOL_ENTRY_SIGNATURE;
99 CopyGuid ((VOID *)&ProtEntry->ProtocolID, Protocol);
100 InitializeListHead (&ProtEntry->Protocols);
101 InitializeListHead (&ProtEntry->Notify);
102
103 //
104 // Add it to protocol database
105 //
106 InsertTailList (&mProtocolDatabase, &ProtEntry->AllEntries);
107 }
108 }
109 return ProtEntry;
110 }
111
112 /**
113 Finds the protocol instance for the requested handle and protocol.
114 Note: This function doesn't do parameters checking, it's caller's responsibility
115 to pass in valid parameters.
116
117 @param Handle The handle to search the protocol on
118 @param Protocol GUID of the protocol
119 @param Interface The interface for the protocol being searched
120
121 @return Protocol instance (NULL: Not found)
122
123 **/
124 PROTOCOL_INTERFACE *
SmmFindProtocolInterface(IN IHANDLE * Handle,IN EFI_GUID * Protocol,IN VOID * Interface)125 SmmFindProtocolInterface (
126 IN IHANDLE *Handle,
127 IN EFI_GUID *Protocol,
128 IN VOID *Interface
129 )
130 {
131 PROTOCOL_INTERFACE *Prot;
132 PROTOCOL_ENTRY *ProtEntry;
133 LIST_ENTRY *Link;
134
135 Prot = NULL;
136
137 //
138 // Lookup the protocol entry for this protocol ID
139 //
140 ProtEntry = SmmFindProtocolEntry (Protocol, FALSE);
141 if (ProtEntry != NULL) {
142 //
143 // Look at each protocol interface for any matches
144 //
145 for (Link = Handle->Protocols.ForwardLink; Link != &Handle->Protocols; Link=Link->ForwardLink) {
146 //
147 // If this protocol interface matches, remove it
148 //
149 Prot = CR(Link, PROTOCOL_INTERFACE, Link, PROTOCOL_INTERFACE_SIGNATURE);
150 if (Prot->Interface == Interface && Prot->Protocol == ProtEntry) {
151 break;
152 }
153 Prot = NULL;
154 }
155 }
156 return Prot;
157 }
158
159 /**
160 Wrapper function to SmmInstallProtocolInterfaceNotify. This is the public API which
161 Calls the private one which contains a BOOLEAN parameter for notifications
162
163 @param UserHandle The handle to install the protocol handler on,
164 or NULL if a new handle is to be allocated
165 @param Protocol The protocol to add to the handle
166 @param InterfaceType Indicates whether Interface is supplied in
167 native form.
168 @param Interface The interface for the protocol being added
169
170 @return Status code
171
172 **/
173 EFI_STATUS
174 EFIAPI
SmmInstallProtocolInterface(IN OUT EFI_HANDLE * UserHandle,IN EFI_GUID * Protocol,IN EFI_INTERFACE_TYPE InterfaceType,IN VOID * Interface)175 SmmInstallProtocolInterface (
176 IN OUT EFI_HANDLE *UserHandle,
177 IN EFI_GUID *Protocol,
178 IN EFI_INTERFACE_TYPE InterfaceType,
179 IN VOID *Interface
180 )
181 {
182 return SmmInstallProtocolInterfaceNotify (
183 UserHandle,
184 Protocol,
185 InterfaceType,
186 Interface,
187 TRUE
188 );
189 }
190
191 /**
192 Installs a protocol interface into the boot services environment.
193
194 @param UserHandle The handle to install the protocol handler on,
195 or NULL if a new handle is to be allocated
196 @param Protocol The protocol to add to the handle
197 @param InterfaceType Indicates whether Interface is supplied in
198 native form.
199 @param Interface The interface for the protocol being added
200 @param Notify indicates whether notify the notification list
201 for this protocol
202
203 @retval EFI_INVALID_PARAMETER Invalid parameter
204 @retval EFI_OUT_OF_RESOURCES No enough buffer to allocate
205 @retval EFI_SUCCESS Protocol interface successfully installed
206
207 **/
208 EFI_STATUS
SmmInstallProtocolInterfaceNotify(IN OUT EFI_HANDLE * UserHandle,IN EFI_GUID * Protocol,IN EFI_INTERFACE_TYPE InterfaceType,IN VOID * Interface,IN BOOLEAN Notify)209 SmmInstallProtocolInterfaceNotify (
210 IN OUT EFI_HANDLE *UserHandle,
211 IN EFI_GUID *Protocol,
212 IN EFI_INTERFACE_TYPE InterfaceType,
213 IN VOID *Interface,
214 IN BOOLEAN Notify
215 )
216 {
217 PROTOCOL_INTERFACE *Prot;
218 PROTOCOL_ENTRY *ProtEntry;
219 IHANDLE *Handle;
220 EFI_STATUS Status;
221 VOID *ExistingInterface;
222
223 //
224 // returns EFI_INVALID_PARAMETER if InterfaceType is invalid.
225 // Also added check for invalid UserHandle and Protocol pointers.
226 //
227 if (UserHandle == NULL || Protocol == NULL) {
228 return EFI_INVALID_PARAMETER;
229 }
230
231 if (InterfaceType != EFI_NATIVE_INTERFACE) {
232 return EFI_INVALID_PARAMETER;
233 }
234
235 //
236 // Print debug message
237 //
238 DEBUG((DEBUG_LOAD | DEBUG_INFO, "SmmInstallProtocolInterface: %g %p\n", Protocol, Interface));
239
240 Status = EFI_OUT_OF_RESOURCES;
241 Prot = NULL;
242 Handle = NULL;
243
244 if (*UserHandle != NULL) {
245 Status = SmmHandleProtocol (*UserHandle, Protocol, (VOID **)&ExistingInterface);
246 if (!EFI_ERROR (Status)) {
247 return EFI_INVALID_PARAMETER;
248 }
249 }
250
251 //
252 // Lookup the Protocol Entry for the requested protocol
253 //
254 ProtEntry = SmmFindProtocolEntry (Protocol, TRUE);
255 if (ProtEntry == NULL) {
256 goto Done;
257 }
258
259 //
260 // Allocate a new protocol interface structure
261 //
262 Prot = AllocateZeroPool (sizeof(PROTOCOL_INTERFACE));
263 if (Prot == NULL) {
264 Status = EFI_OUT_OF_RESOURCES;
265 goto Done;
266 }
267
268 //
269 // If caller didn't supply a handle, allocate a new one
270 //
271 Handle = (IHANDLE *)*UserHandle;
272 if (Handle == NULL) {
273 Handle = AllocateZeroPool (sizeof(IHANDLE));
274 if (Handle == NULL) {
275 Status = EFI_OUT_OF_RESOURCES;
276 goto Done;
277 }
278
279 //
280 // Initialize new handler structure
281 //
282 Handle->Signature = EFI_HANDLE_SIGNATURE;
283 InitializeListHead (&Handle->Protocols);
284
285 //
286 // Add this handle to the list global list of all handles
287 // in the system
288 //
289 InsertTailList (&gHandleList, &Handle->AllHandles);
290 }
291
292 Status = SmmValidateHandle (Handle);
293 if (EFI_ERROR (Status)) {
294 goto Done;
295 }
296
297 //
298 // Each interface that is added must be unique
299 //
300 ASSERT (SmmFindProtocolInterface (Handle, Protocol, Interface) == NULL);
301
302 //
303 // Initialize the protocol interface structure
304 //
305 Prot->Signature = PROTOCOL_INTERFACE_SIGNATURE;
306 Prot->Handle = Handle;
307 Prot->Protocol = ProtEntry;
308 Prot->Interface = Interface;
309
310 //
311 // Add this protocol interface to the head of the supported
312 // protocol list for this handle
313 //
314 InsertHeadList (&Handle->Protocols, &Prot->Link);
315
316 //
317 // Add this protocol interface to the tail of the
318 // protocol entry
319 //
320 InsertTailList (&ProtEntry->Protocols, &Prot->ByProtocol);
321
322 //
323 // Notify the notification list for this protocol
324 //
325 if (Notify) {
326 SmmNotifyProtocol (Prot);
327 }
328 Status = EFI_SUCCESS;
329
330 Done:
331 if (!EFI_ERROR (Status)) {
332 //
333 // Return the new handle back to the caller
334 //
335 *UserHandle = Handle;
336 } else {
337 //
338 // There was an error, clean up
339 //
340 if (Prot != NULL) {
341 FreePool (Prot);
342 }
343 }
344 return Status;
345 }
346
347 /**
348 Uninstalls all instances of a protocol:interfacer from a handle.
349 If the last protocol interface is remove from the handle, the
350 handle is freed.
351
352 @param UserHandle The handle to remove the protocol handler from
353 @param Protocol The protocol, of protocol:interface, to remove
354 @param Interface The interface, of protocol:interface, to remove
355
356 @retval EFI_INVALID_PARAMETER Protocol is NULL.
357 @retval EFI_SUCCESS Protocol interface successfully uninstalled.
358
359 **/
360 EFI_STATUS
361 EFIAPI
SmmUninstallProtocolInterface(IN EFI_HANDLE UserHandle,IN EFI_GUID * Protocol,IN VOID * Interface)362 SmmUninstallProtocolInterface (
363 IN EFI_HANDLE UserHandle,
364 IN EFI_GUID *Protocol,
365 IN VOID *Interface
366 )
367 {
368 EFI_STATUS Status;
369 IHANDLE *Handle;
370 PROTOCOL_INTERFACE *Prot;
371
372 //
373 // Check that Protocol is valid
374 //
375 if (Protocol == NULL) {
376 return EFI_INVALID_PARAMETER;
377 }
378
379 //
380 // Check that UserHandle is a valid handle
381 //
382 Status = SmmValidateHandle (UserHandle);
383 if (EFI_ERROR (Status)) {
384 return Status;
385 }
386
387 //
388 // Check that Protocol exists on UserHandle, and Interface matches the interface in the database
389 //
390 Prot = SmmFindProtocolInterface (UserHandle, Protocol, Interface);
391 if (Prot == NULL) {
392 return EFI_NOT_FOUND;
393 }
394
395 //
396 // Remove the protocol interface from the protocol
397 //
398 Status = EFI_NOT_FOUND;
399 Handle = (IHANDLE *)UserHandle;
400 Prot = SmmRemoveInterfaceFromProtocol (Handle, Protocol, Interface);
401
402 if (Prot != NULL) {
403 //
404 // Remove the protocol interface from the handle
405 //
406 RemoveEntryList (&Prot->Link);
407
408 //
409 // Free the memory
410 //
411 Prot->Signature = 0;
412 FreePool (Prot);
413 Status = EFI_SUCCESS;
414 }
415
416 //
417 // If there are no more handlers for the handle, free the handle
418 //
419 if (IsListEmpty (&Handle->Protocols)) {
420 Handle->Signature = 0;
421 RemoveEntryList (&Handle->AllHandles);
422 FreePool (Handle);
423 }
424 return Status;
425 }
426
427 /**
428 Locate a certain GUID protocol interface in a Handle's protocols.
429
430 @param UserHandle The handle to obtain the protocol interface on
431 @param Protocol The GUID of the protocol
432
433 @return The requested protocol interface for the handle
434
435 **/
436 PROTOCOL_INTERFACE *
SmmGetProtocolInterface(IN EFI_HANDLE UserHandle,IN EFI_GUID * Protocol)437 SmmGetProtocolInterface (
438 IN EFI_HANDLE UserHandle,
439 IN EFI_GUID *Protocol
440 )
441 {
442 EFI_STATUS Status;
443 PROTOCOL_ENTRY *ProtEntry;
444 PROTOCOL_INTERFACE *Prot;
445 IHANDLE *Handle;
446 LIST_ENTRY *Link;
447
448 Status = SmmValidateHandle (UserHandle);
449 if (EFI_ERROR (Status)) {
450 return NULL;
451 }
452
453 Handle = (IHANDLE *)UserHandle;
454
455 //
456 // Look at each protocol interface for a match
457 //
458 for (Link = Handle->Protocols.ForwardLink; Link != &Handle->Protocols; Link = Link->ForwardLink) {
459 Prot = CR(Link, PROTOCOL_INTERFACE, Link, PROTOCOL_INTERFACE_SIGNATURE);
460 ProtEntry = Prot->Protocol;
461 if (CompareGuid (&ProtEntry->ProtocolID, Protocol)) {
462 return Prot;
463 }
464 }
465 return NULL;
466 }
467
468 /**
469 Queries a handle to determine if it supports a specified protocol.
470
471 @param UserHandle The handle being queried.
472 @param Protocol The published unique identifier of the protocol.
473 @param Interface Supplies the address where a pointer to the
474 corresponding Protocol Interface is returned.
475
476 @retval EFI_SUCCESS The interface information for the specified protocol was returned.
477 @retval EFI_UNSUPPORTED The device does not support the specified protocol.
478 @retval EFI_INVALID_PARAMETER Handle is not a valid EFI_HANDLE..
479 @retval EFI_INVALID_PARAMETER Protocol is NULL.
480 @retval EFI_INVALID_PARAMETER Interface is NULL.
481
482 **/
483 EFI_STATUS
484 EFIAPI
SmmHandleProtocol(IN EFI_HANDLE UserHandle,IN EFI_GUID * Protocol,OUT VOID ** Interface)485 SmmHandleProtocol (
486 IN EFI_HANDLE UserHandle,
487 IN EFI_GUID *Protocol,
488 OUT VOID **Interface
489 )
490 {
491 EFI_STATUS Status;
492 PROTOCOL_INTERFACE *Prot;
493
494 //
495 // Check for invalid Protocol
496 //
497 if (Protocol == NULL) {
498 return EFI_INVALID_PARAMETER;
499 }
500
501 //
502 // Check for invalid Interface
503 //
504 if (Interface == NULL) {
505 return EFI_INVALID_PARAMETER;
506 } else {
507 *Interface = NULL;
508 }
509
510 //
511 // Check for invalid UserHandle
512 //
513 Status = SmmValidateHandle (UserHandle);
514 if (EFI_ERROR (Status)) {
515 return Status;
516 }
517
518 //
519 // Look at each protocol interface for a match
520 //
521 Prot = SmmGetProtocolInterface (UserHandle, Protocol);
522 if (Prot == NULL) {
523 return EFI_UNSUPPORTED;
524 }
525
526 //
527 // This is the protocol interface entry for this protocol
528 //
529 *Interface = Prot->Interface;
530
531 return EFI_SUCCESS;
532 }
533