iPXE
Functions
efi_open.c File Reference

EFI protocol opening and closing. More...

#include <assert.h>
#include <errno.h>
#include <ipxe/efi/efi.h>

Go to the source code of this file.

Functions

 FILE_LICENCE (GPL2_OR_LATER_OR_UBDL)
 
 FILE_SECBOOT (PERMITTED)
 
int efi_open_untyped (EFI_HANDLE handle, EFI_GUID *protocol, void **interface)
 Open (or test) protocol for ephemeral use. More...
 
int efi_open_unsafe_untyped (EFI_HANDLE handle, EFI_GUID *protocol, void **interface)
 Open protocol for unsafe persistent use. More...
 
void efi_close_unsafe (EFI_HANDLE handle, EFI_GUID *protocol)
 Close protocol opened for unsafe persistent use. More...
 
int efi_open_by_driver_untyped (EFI_HANDLE handle, EFI_GUID *protocol, void **interface)
 Open protocol for persistent use by a driver. More...
 
void efi_close_by_driver (EFI_HANDLE handle, EFI_GUID *protocol)
 Close protocol opened for persistent use by a driver. More...
 
int efi_open_by_child_untyped (EFI_HANDLE handle, EFI_GUID *protocol, EFI_HANDLE child, void **interface)
 Open protocol for persistent use by a child controller. More...
 
void efi_close_by_child (EFI_HANDLE handle, EFI_GUID *protocol, EFI_HANDLE child)
 Close protocol opened for persistent use by a child controller. More...
 

Detailed Description

EFI protocol opening and closing.

The UEFI model for opening and closing protocols is broken by design and cannot be repaired.

Calling OpenProtocol() to obtain a protocol interface pointer does not, in general, provide any guarantees about the lifetime of that pointer. It is theoretically possible that the pointer has already become invalid by the time that OpenProtocol() returns the pointer to its caller. (This can happen when a USB device is physically removed, for example.)

Various UEFI design flaws make it occasionally necessary to hold on to a protocol interface pointer despite the total lack of guarantees that the pointer will remain valid.

The UEFI driver model overloads the semantics of OpenProtocol() to accommodate the use cases of recording a driver attachment (which is modelled as opening a protocol with EFI_OPEN_PROTOCOL_BY_DRIVER attributes) and recording the existence of a related child controller (which is modelled as opening a protocol with EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER attributes).

The parameters defined for CloseProtocol() are not sufficient to allow the implementation to precisely identify the matching call to OpenProtocol(). While the UEFI model appears to allow for matched open and close pairs, this is merely an illusion. Calling CloseProtocol() will delete all matching records in the protocol open information tables.

Since the parameters defined for CloseProtocol() do not include the attributes passed to OpenProtocol(), this means that a matched open/close pair using EFI_OPEN_PROTOCOL_GET_PROTOCOL can inadvertently end up deleting the record that defines a driver attachment or the existence of a child controller. This in turn can cause some very unexpected side effects, such as allowing other UEFI drivers to start controlling hardware to which iPXE believes it has exclusive access. This rarely ends well.

To prevent this kind of inadvertent deletion, we establish a convention for four different types of protocol opening:

This convention ensures that the four types of open never overlap within the set of parameters defined for CloseProtocol(), and so a close of one type cannot inadvertently delete the record corresponding to a different type.

Definition in file efi_open.c.

Function Documentation

◆ FILE_LICENCE()

FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL  )

◆ FILE_SECBOOT()

FILE_SECBOOT ( PERMITTED  )

◆ efi_open_untyped()

int efi_open_untyped ( EFI_HANDLE  handle,
EFI_GUID protocol,
void **  interface 
)

Open (or test) protocol for ephemeral use.

Parameters
handleEFI handle
protocolProtocol GUID
interfaceProtocol interface pointer to fill in (or NULL to test)
Return values
rcReturn status code

Definition at line 97 of file efi_open.c.

98  {
102  unsigned int attributes;
103  EFI_STATUS efirc;
104  int rc;
105 
106  /* Sanity checks */
107  assert ( handle != NULL );
108  assert ( protocol != NULL );
109 
110  /* Open protocol
111  *
112  * We set ControllerHandle to NULL to avoid collisions with
113  * other open types.
114  */
115  controller = NULL;
116  attributes = ( interface ? EFI_OPEN_PROTOCOL_GET_PROTOCOL :
118  if ( ( efirc = bs->OpenProtocol ( handle, protocol, interface, agent,
119  controller, attributes ) ) != 0 ) {
120  rc = -EEFI ( efirc );
121  if ( interface )
122  *interface = NULL;
123  return rc;
124  }
125 
126  /* Close protocol immediately
127  *
128  * While it may seem prima facie unsafe to use a protocol
129  * after closing it, UEFI doesn't actually give us any safety
130  * even while the protocol is nominally open. Opening a
131  * protocol with EFI_OPEN_PROTOCOL_GET_PROTOCOL attributes
132  * does not in any way ensure that the interface pointer
133  * remains valid: there are no locks or notifications
134  * associated with these "opens".
135  *
136  * The only way to obtain a (partially) guaranteed persistent
137  * interface pointer is to open the protocol with the
138  * EFI_OPEN_PROTOCOL_BY_DRIVER attributes. This is not
139  * possible in the general case, since UEFI permits only a
140  * single image at a time to have the protocol opened with
141  * these attributes.
142  *
143  * We can therefore obtain at best an ephemeral interface
144  * pointer: one that is guaranteed to remain valid only for as
145  * long as we do not relinquish the thread of control.
146  *
147  * (Since UEFI permits calls to UninstallProtocolInterface()
148  * at levels up to and including TPL_NOTIFY, this means that
149  * we technically cannot rely on the pointer remaining valid
150  * unless the caller is itself running at TPL_NOTIFY. This is
151  * clearly impractical, and large portions of the EDK2
152  * codebase presume that using EFI_OPEN_PROTOCOL_GET_PROTOCOL
153  * is safe at lower TPLs.)
154  *
155  * Closing is not strictly necessary for protocols opened
156  * ephemerally (i.e. using EFI_OPEN_PROTOCOL_GET_PROTOCOL or
157  * EFI_OPEN_PROTOCOL_TEST_PROTOCOL), but avoids polluting the
158  * protocol open information tables with stale data.
159  *
160  * Closing immediately also simplifies the callers' code
161  * paths, since they do not need to worry about closing the
162  * protocol.
163  *
164  * The overall effect is equivalent to using HandleProtocol(),
165  * but without the associated pollution of the protocol open
166  * information tables, and with improved traceability.
167  */
168  bs->CloseProtocol ( handle, protocol, agent, controller );
169 
170  return 0;
171 }
EFI_BOOT_SERVICES * BootServices
A pointer to the EFI Boot Services Table.
Definition: UefiSpec.h:2099
struct arbelprm_rc_send_wqe rc
Definition: arbel.h:14
#define EEFI(efirc)
Convert an EFI status code to an iPXE status code.
Definition: efi.h:175
EFI_CLOSE_PROTOCOL CloseProtocol
Definition: UefiSpec.h:2001
#define EFI_OPEN_PROTOCOL_TEST_PROTOCOL
Definition: UefiSpec.h:1356
assert((readw(&hdr->flags) &(GTF_reading|GTF_writing))==0)
An object interface.
Definition: interface.h:125
#define EFI_OPEN_PROTOCOL_GET_PROTOCOL
Definition: UefiSpec.h:1355
EFI Boot Services Table.
Definition: UefiSpec.h:1931
EFI_HANDLE efi_image_handle
Image handle passed to entry point.
Definition: efi_init.c:36
uint8_t controller
CD-ROM controller number.
Definition: int13.h:18
RETURN_STATUS EFI_STATUS
Function return status for EFI API.
Definition: UefiBaseType.h:32
EFI_SYSTEM_TABLE * efi_systab
uint16_t protocol
Protocol ID.
Definition: stp.h:19
uint16_t handle
Handle.
Definition: smbios.h:17
#define NULL
NULL pointer (VOID *)
Definition: Base.h:322
Definition: efi.h:62
if(natsemi->flags &NATSEMI_64BIT) return 1

References assert(), EFI_SYSTEM_TABLE::BootServices, EFI_BOOT_SERVICES::CloseProtocol, controller, EEFI, efi_image_handle, EFI_OPEN_PROTOCOL_GET_PROTOCOL, EFI_OPEN_PROTOCOL_TEST_PROTOCOL, efi_systab, handle, if(), NULL, protocol, and rc.

◆ efi_open_unsafe_untyped()

int efi_open_unsafe_untyped ( EFI_HANDLE  handle,
EFI_GUID protocol,
void **  interface 
)

Open protocol for unsafe persistent use.

Parameters
handleEFI handle
protocolProtocol GUID
interfaceProtocol interface pointer to fill in
Return values
rcReturn status code

Definition at line 181 of file efi_open.c.

182  {
186  unsigned int attributes;
187  EFI_STATUS efirc;
188  int rc;
189 
190  /* Sanity checks */
191  assert ( handle != NULL );
192  assert ( protocol != NULL );
193  assert ( interface != NULL );
194 
195  /* Open protocol
196  *
197  * We set ControllerHandle equal to AgentHandle to avoid
198  * collisions with other open types.
199  */
200  controller = agent;
201  attributes = EFI_OPEN_PROTOCOL_GET_PROTOCOL;
202  if ( ( efirc = bs->OpenProtocol ( handle, protocol, interface, agent,
203  controller, attributes ) ) != 0 ) {
204  rc = -EEFI ( efirc );
205  *interface = NULL;
206  return rc;
207  }
208 
209  return 0;
210 }
EFI_BOOT_SERVICES * BootServices
A pointer to the EFI Boot Services Table.
Definition: UefiSpec.h:2099
struct arbelprm_rc_send_wqe rc
Definition: arbel.h:14
#define EEFI(efirc)
Convert an EFI status code to an iPXE status code.
Definition: efi.h:175
assert((readw(&hdr->flags) &(GTF_reading|GTF_writing))==0)
An object interface.
Definition: interface.h:125
#define EFI_OPEN_PROTOCOL_GET_PROTOCOL
Definition: UefiSpec.h:1355
EFI Boot Services Table.
Definition: UefiSpec.h:1931
EFI_HANDLE efi_image_handle
Image handle passed to entry point.
Definition: efi_init.c:36
uint8_t controller
CD-ROM controller number.
Definition: int13.h:18
RETURN_STATUS EFI_STATUS
Function return status for EFI API.
Definition: UefiBaseType.h:32
EFI_SYSTEM_TABLE * efi_systab
EFI_OPEN_PROTOCOL OpenProtocol
Definition: UefiSpec.h:2000
uint16_t protocol
Protocol ID.
Definition: stp.h:19
uint16_t handle
Handle.
Definition: smbios.h:17
#define NULL
NULL pointer (VOID *)
Definition: Base.h:322
Definition: efi.h:62

References assert(), EFI_SYSTEM_TABLE::BootServices, controller, EEFI, efi_image_handle, EFI_OPEN_PROTOCOL_GET_PROTOCOL, efi_systab, handle, NULL, EFI_BOOT_SERVICES::OpenProtocol, protocol, and rc.

◆ efi_close_unsafe()

void efi_close_unsafe ( EFI_HANDLE  handle,
EFI_GUID protocol 
)

Close protocol opened for unsafe persistent use.

Parameters
handleEFI handle
protocolProtocol GUID
childChild controller handle

Definition at line 219 of file efi_open.c.

219  {
223 
224  /* Sanity checks */
225  assert ( handle != NULL );
226  assert ( protocol != NULL );
227 
228  /* Close protocol */
229  controller = agent;
230  bs->CloseProtocol ( handle, protocol, agent, controller );
231 }
EFI_BOOT_SERVICES * BootServices
A pointer to the EFI Boot Services Table.
Definition: UefiSpec.h:2099
EFI_CLOSE_PROTOCOL CloseProtocol
Definition: UefiSpec.h:2001
assert((readw(&hdr->flags) &(GTF_reading|GTF_writing))==0)
EFI Boot Services Table.
Definition: UefiSpec.h:1931
EFI_HANDLE efi_image_handle
Image handle passed to entry point.
Definition: efi_init.c:36
uint8_t controller
CD-ROM controller number.
Definition: int13.h:18
EFI_SYSTEM_TABLE * efi_systab
uint16_t protocol
Protocol ID.
Definition: stp.h:19
uint16_t handle
Handle.
Definition: smbios.h:17
#define NULL
NULL pointer (VOID *)
Definition: Base.h:322
Definition: efi.h:62

References assert(), EFI_SYSTEM_TABLE::BootServices, EFI_BOOT_SERVICES::CloseProtocol, controller, efi_image_handle, efi_systab, handle, NULL, and protocol.

Referenced by efi_bofm_start(), nii_pci_close(), and nii_pci_open().

◆ efi_open_by_driver_untyped()

int efi_open_by_driver_untyped ( EFI_HANDLE  handle,
EFI_GUID protocol,
void **  interface 
)

Open protocol for persistent use by a driver.

Parameters
handleEFI handle
protocolProtocol GUID
interfaceProtocol interface pointer to fill in
Return values
rcReturn status code

Definition at line 241 of file efi_open.c.

242  {
246  unsigned int attributes;
247  EFI_STATUS efirc;
248  int rc;
249 
250  /* Sanity checks */
251  assert ( handle != NULL );
252  assert ( protocol != NULL );
253  assert ( interface != NULL );
254 
255  /* Open protocol
256  *
257  * We set ControllerHandle equal to Handle to avoid collisions
258  * with other open types.
259  */
260  controller = handle;
261  attributes = ( EFI_OPEN_PROTOCOL_BY_DRIVER |
263  if ( ( efirc = bs->OpenProtocol ( handle, protocol, interface, agent,
264  controller, attributes ) ) != 0 ) {
265  rc = -EEFI ( efirc );
266  *interface = NULL;
267  return rc;
268  }
269 
270  return 0;
271 }
EFI_BOOT_SERVICES * BootServices
A pointer to the EFI Boot Services Table.
Definition: UefiSpec.h:2099
struct arbelprm_rc_send_wqe rc
Definition: arbel.h:14
#define EEFI(efirc)
Convert an EFI status code to an iPXE status code.
Definition: efi.h:175
#define EFI_OPEN_PROTOCOL_BY_DRIVER
Definition: UefiSpec.h:1358
#define EFI_OPEN_PROTOCOL_EXCLUSIVE
Definition: UefiSpec.h:1359
assert((readw(&hdr->flags) &(GTF_reading|GTF_writing))==0)
An object interface.
Definition: interface.h:125
EFI Boot Services Table.
Definition: UefiSpec.h:1931
EFI_HANDLE efi_image_handle
Image handle passed to entry point.
Definition: efi_init.c:36
uint8_t controller
CD-ROM controller number.
Definition: int13.h:18
RETURN_STATUS EFI_STATUS
Function return status for EFI API.
Definition: UefiBaseType.h:32
EFI_SYSTEM_TABLE * efi_systab
EFI_OPEN_PROTOCOL OpenProtocol
Definition: UefiSpec.h:2000
uint16_t protocol
Protocol ID.
Definition: stp.h:19
uint16_t handle
Handle.
Definition: smbios.h:17
#define NULL
NULL pointer (VOID *)
Definition: Base.h:322
Definition: efi.h:62

References assert(), EFI_SYSTEM_TABLE::BootServices, controller, EEFI, efi_image_handle, EFI_OPEN_PROTOCOL_BY_DRIVER, EFI_OPEN_PROTOCOL_EXCLUSIVE, efi_systab, handle, NULL, EFI_BOOT_SERVICES::OpenProtocol, protocol, and rc.

◆ efi_close_by_driver()

void efi_close_by_driver ( EFI_HANDLE  handle,
EFI_GUID protocol 
)

Close protocol opened for persistent use by a driver.

Parameters
handleEFI handle
protocolProtocol GUID

Definition at line 279 of file efi_open.c.

279  {
283 
284  /* Sanity checks */
285  assert ( handle != NULL );
286  assert ( protocol != NULL );
287 
288  /* Close protocol */
289  controller = handle;
290  bs->CloseProtocol ( handle, protocol, agent, controller );
291 }
EFI_BOOT_SERVICES * BootServices
A pointer to the EFI Boot Services Table.
Definition: UefiSpec.h:2099
EFI_CLOSE_PROTOCOL CloseProtocol
Definition: UefiSpec.h:2001
assert((readw(&hdr->flags) &(GTF_reading|GTF_writing))==0)
EFI Boot Services Table.
Definition: UefiSpec.h:1931
EFI_HANDLE efi_image_handle
Image handle passed to entry point.
Definition: efi_init.c:36
uint8_t controller
CD-ROM controller number.
Definition: int13.h:18
EFI_SYSTEM_TABLE * efi_systab
uint16_t protocol
Protocol ID.
Definition: stp.h:19
uint16_t handle
Handle.
Definition: smbios.h:17
#define NULL
NULL pointer (VOID *)
Definition: Base.h:322
Definition: efi.h:62

References assert(), EFI_SYSTEM_TABLE::BootServices, EFI_BOOT_SERVICES::CloseProtocol, controller, efi_image_handle, efi_systab, handle, NULL, and protocol.

Referenced by efi_file_install(), efi_file_uninstall(), efi_snp_probe(), efi_snp_remove(), efipci_start(), efipci_stop(), mnpnet_start(), mnpnet_stop(), nii_start(), nii_stop(), snpnet_start(), snpnet_stop(), usbio_close(), usbio_start(), and usbio_stop().

◆ efi_open_by_child_untyped()

int efi_open_by_child_untyped ( EFI_HANDLE  handle,
EFI_GUID protocol,
EFI_HANDLE  child,
void **  interface 
)

Open protocol for persistent use by a child controller.

Parameters
handleEFI handle
protocolProtocol GUID
childChild controller handle
interfaceProtocol interface pointer to fill in
Return values
rcReturn status code

Definition at line 302 of file efi_open.c.

303  {
307  unsigned int attributes;
308  EFI_STATUS efirc;
309  int rc;
310 
311  /* Sanity checks */
312  assert ( handle != NULL );
313  assert ( protocol != NULL );
314  assert ( child != NULL );
315  assert ( interface != NULL );
316 
317  /* Open protocol
318  *
319  * We set ControllerHandle to a non-NULL value distinct from
320  * both Handle and AgentHandle to avoid collisions with other
321  * open types.
322  */
323  controller = child;
324  assert ( controller != handle );
325  assert ( controller != agent );
327  if ( ( efirc = bs->OpenProtocol ( handle, protocol, interface, agent,
328  controller, attributes ) ) != 0 ) {
329  rc = -EEFI ( efirc );
330  *interface = NULL;
331  return rc;
332  }
333 
334  return 0;
335 }
EFI_BOOT_SERVICES * BootServices
A pointer to the EFI Boot Services Table.
Definition: UefiSpec.h:2099
struct arbelprm_rc_send_wqe rc
Definition: arbel.h:14
#define EEFI(efirc)
Convert an EFI status code to an iPXE status code.
Definition: efi.h:175
#define EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
Definition: UefiSpec.h:1357
assert((readw(&hdr->flags) &(GTF_reading|GTF_writing))==0)
An object interface.
Definition: interface.h:125
EFI Boot Services Table.
Definition: UefiSpec.h:1931
EFI_HANDLE efi_image_handle
Image handle passed to entry point.
Definition: efi_init.c:36
uint8_t controller
CD-ROM controller number.
Definition: int13.h:18
RETURN_STATUS EFI_STATUS
Function return status for EFI API.
Definition: UefiBaseType.h:32
EFI_SYSTEM_TABLE * efi_systab
EFI_OPEN_PROTOCOL OpenProtocol
Definition: UefiSpec.h:2000
uint16_t protocol
Protocol ID.
Definition: stp.h:19
uint16_t handle
Handle.
Definition: smbios.h:17
#define NULL
NULL pointer (VOID *)
Definition: Base.h:322
Definition: efi.h:62

References assert(), EFI_SYSTEM_TABLE::BootServices, controller, EEFI, efi_image_handle, EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER, efi_systab, handle, NULL, EFI_BOOT_SERVICES::OpenProtocol, protocol, and rc.

◆ efi_close_by_child()

void efi_close_by_child ( EFI_HANDLE  handle,
EFI_GUID protocol,
EFI_HANDLE  child 
)

Close protocol opened for persistent use by a child controller.

Parameters
handleEFI handle
protocolProtocol GUID
childChild controller handle

Definition at line 344 of file efi_open.c.

345  {
349 
350  /* Sanity checks */
351  assert ( handle != NULL );
352  assert ( protocol != NULL );
353  assert ( child != NULL );
354 
355  /* Close protocol */
356  controller = child;
357  assert ( controller != handle );
358  assert ( controller != agent );
359  bs->CloseProtocol ( handle, protocol, agent, controller );
360 }
EFI_BOOT_SERVICES * BootServices
A pointer to the EFI Boot Services Table.
Definition: UefiSpec.h:2099
EFI_CLOSE_PROTOCOL CloseProtocol
Definition: UefiSpec.h:2001
assert((readw(&hdr->flags) &(GTF_reading|GTF_writing))==0)
EFI Boot Services Table.
Definition: UefiSpec.h:1931
EFI_HANDLE efi_image_handle
Image handle passed to entry point.
Definition: efi_init.c:36
uint8_t controller
CD-ROM controller number.
Definition: int13.h:18
EFI_SYSTEM_TABLE * efi_systab
uint16_t protocol
Protocol ID.
Definition: stp.h:19
uint16_t handle
Handle.
Definition: smbios.h:17
#define NULL
NULL pointer (VOID *)
Definition: Base.h:322
Definition: efi.h:62

References assert(), EFI_SYSTEM_TABLE::BootServices, EFI_BOOT_SERVICES::CloseProtocol, controller, efi_image_handle, efi_systab, handle, NULL, and protocol.

Referenced by efi_child_del().