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)
 
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  )

◆ 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 96 of file efi_open.c.

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

181  {
185  unsigned int attributes;
186  EFI_STATUS efirc;
187  int rc;
188 
189  /* Sanity checks */
190  assert ( handle != NULL );
191  assert ( protocol != NULL );
192  assert ( interface != NULL );
193 
194  /* Open protocol
195  *
196  * We set ControllerHandle equal to AgentHandle to avoid
197  * collisions with other open types.
198  */
199  controller = agent;
200  attributes = EFI_OPEN_PROTOCOL_GET_PROTOCOL;
201  if ( ( efirc = bs->OpenProtocol ( handle, protocol, interface, agent,
202  controller, attributes ) ) != 0 ) {
203  rc = -EEFI ( efirc );
204  *interface = NULL;
205  return rc;
206  }
207 
208  return 0;
209 }
EFI_BOOT_SERVICES * BootServices
A pointer to the EFI Boot Services Table.
Definition: UefiSpec.h:2098
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:174
assert((readw(&hdr->flags) &(GTF_reading|GTF_writing))==0)
An object interface.
Definition: interface.h:124
#define EFI_OPEN_PROTOCOL_GET_PROTOCOL
Definition: UefiSpec.h:1354
EFI Boot Services Table.
Definition: UefiSpec.h:1930
EFI_HANDLE efi_image_handle
Image handle passed to entry point.
Definition: efi_init.c:35
uint8_t controller
CD-ROM controller number.
Definition: int13.h:18
RETURN_STATUS EFI_STATUS
Function return status for EFI API.
Definition: UefiBaseType.h:31
EFI_SYSTEM_TABLE * efi_systab
EFI_OPEN_PROTOCOL OpenProtocol
Definition: UefiSpec.h:1999
uint16_t protocol
Protocol ID.
Definition: stp.h:18
uint16_t handle
Handle.
Definition: smbios.h:16
#define NULL
NULL pointer (VOID *)
Definition: Base.h:321
Definition: efi.h:61

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 218 of file efi_open.c.

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

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 240 of file efi_open.c.

241  {
245  unsigned int attributes;
246  EFI_STATUS efirc;
247  int rc;
248 
249  /* Sanity checks */
250  assert ( handle != NULL );
251  assert ( protocol != NULL );
252  assert ( interface != NULL );
253 
254  /* Open protocol
255  *
256  * We set ControllerHandle equal to Handle to avoid collisions
257  * with other open types.
258  */
259  controller = handle;
260  attributes = ( EFI_OPEN_PROTOCOL_BY_DRIVER |
262  if ( ( efirc = bs->OpenProtocol ( handle, protocol, interface, agent,
263  controller, attributes ) ) != 0 ) {
264  rc = -EEFI ( efirc );
265  *interface = NULL;
266  return rc;
267  }
268 
269  return 0;
270 }
EFI_BOOT_SERVICES * BootServices
A pointer to the EFI Boot Services Table.
Definition: UefiSpec.h:2098
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:174
#define EFI_OPEN_PROTOCOL_BY_DRIVER
Definition: UefiSpec.h:1357
#define EFI_OPEN_PROTOCOL_EXCLUSIVE
Definition: UefiSpec.h:1358
assert((readw(&hdr->flags) &(GTF_reading|GTF_writing))==0)
An object interface.
Definition: interface.h:124
EFI Boot Services Table.
Definition: UefiSpec.h:1930
EFI_HANDLE efi_image_handle
Image handle passed to entry point.
Definition: efi_init.c:35
uint8_t controller
CD-ROM controller number.
Definition: int13.h:18
RETURN_STATUS EFI_STATUS
Function return status for EFI API.
Definition: UefiBaseType.h:31
EFI_SYSTEM_TABLE * efi_systab
EFI_OPEN_PROTOCOL OpenProtocol
Definition: UefiSpec.h:1999
uint16_t protocol
Protocol ID.
Definition: stp.h:18
uint16_t handle
Handle.
Definition: smbios.h:16
#define NULL
NULL pointer (VOID *)
Definition: Base.h:321
Definition: efi.h:61

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 278 of file efi_open.c.

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

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 301 of file efi_open.c.

302  {
306  unsigned int attributes;
307  EFI_STATUS efirc;
308  int rc;
309 
310  /* Sanity checks */
311  assert ( handle != NULL );
312  assert ( protocol != NULL );
313  assert ( child != NULL );
314  assert ( interface != NULL );
315 
316  /* Open protocol
317  *
318  * We set ControllerHandle to a non-NULL value distinct from
319  * both Handle and AgentHandle to avoid collisions with other
320  * open types.
321  */
322  controller = child;
323  assert ( controller != handle );
324  assert ( controller != agent );
326  if ( ( efirc = bs->OpenProtocol ( handle, protocol, interface, agent,
327  controller, attributes ) ) != 0 ) {
328  rc = -EEFI ( efirc );
329  *interface = NULL;
330  return rc;
331  }
332 
333  return 0;
334 }
EFI_BOOT_SERVICES * BootServices
A pointer to the EFI Boot Services Table.
Definition: UefiSpec.h:2098
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:174
#define EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
Definition: UefiSpec.h:1356
assert((readw(&hdr->flags) &(GTF_reading|GTF_writing))==0)
An object interface.
Definition: interface.h:124
EFI Boot Services Table.
Definition: UefiSpec.h:1930
EFI_HANDLE efi_image_handle
Image handle passed to entry point.
Definition: efi_init.c:35
uint8_t controller
CD-ROM controller number.
Definition: int13.h:18
RETURN_STATUS EFI_STATUS
Function return status for EFI API.
Definition: UefiBaseType.h:31
EFI_SYSTEM_TABLE * efi_systab
EFI_OPEN_PROTOCOL OpenProtocol
Definition: UefiSpec.h:1999
uint16_t protocol
Protocol ID.
Definition: stp.h:18
uint16_t handle
Handle.
Definition: smbios.h:16
#define NULL
NULL pointer (VOID *)
Definition: Base.h:321
Definition: efi.h:61

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 343 of file efi_open.c.

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

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().