• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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