iPXE
efi_utils.c
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2011 Michael Brown <mbrown@fensystems.co.uk>.
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License as
6  * published by the Free Software Foundation; either version 2 of the
7  * License, or any later version.
8  *
9  * This program is distributed in the hope that it will be useful, but
10  * WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12  * General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
17  * 02110-1301, USA.
18  */
19 
20 FILE_LICENCE ( GPL2_OR_LATER );
21 FILE_SECBOOT ( PERMITTED );
22 
23 #include <stdio.h>
24 #include <string.h>
25 #include <errno.h>
26 #include <ipxe/efi/efi.h>
27 #include <ipxe/efi/efi_path.h>
28 #include <ipxe/efi/efi_pci.h>
29 #include <ipxe/efi/efi_utils.h>
30 
31 /** @file
32  *
33  * EFI utilities
34  *
35  */
36 
37 /**
38  * Locate parent device supporting a given protocol
39  *
40  * @v device EFI device handle
41  * @v protocol Protocol GUID
42  * @v parent Parent EFI device handle to fill in
43  * @v skip Number of protocol-supporting parent devices to skip
44  * @ret rc Return status code
45  */
47  EFI_HANDLE *parent, unsigned int skip ) {
49  EFI_DEVICE_PATH_PROTOCOL *devpath;
52  size_t len;
53  EFI_STATUS efirc;
54  int rc;
55 
56  /* Get device path */
58  &devpath ) ) != 0 ) {
59  DBGC ( device, "EFIDEV %s cannot open device path: %s\n",
60  efi_handle_name ( device ), strerror ( rc ) );
61  goto err_open_device_path;
62  }
63 
64  /* Create modifiable copy of device path */
65  len = ( efi_path_len ( devpath ) + sizeof ( *end ) );
66  path = malloc ( len );
67  if ( ! path ) {
68  rc = -ENOMEM;
69  goto err_alloc_path;
70  }
71  memcpy ( path, devpath, len );
72 
73  /* Locate parent device(s) */
74  while ( 1 ) {
75 
76  /* Check for presence of specified protocol */
77  end = path;
78  if ( ( efirc = bs->LocateDevicePath ( protocol, &end,
79  parent ) ) != 0 ) {
80  rc = -EEFI ( efirc );
81  DBGC ( device, "EFIDEV %s has no parent supporting "
82  "%s: %s\n", efi_devpath_text ( path ),
83  efi_guid_ntoa ( protocol ), strerror ( rc ) );
84  goto err_locate_protocol;
85  }
86 
87  /* Stop if we have skipped the requested number of devices */
88  if ( ! skip-- )
89  break;
90 
91  /* Trim device path */
93  end = efi_path_prev ( path, end );
95  }
96 
97  err_locate_protocol:
98  free ( path );
99  err_alloc_path:
100  err_open_device_path:
101  return rc;
102 }
103 
104 /**
105  * Add EFI device as child of another EFI device
106  *
107  * @v parent EFI parent device handle
108  * @v child EFI child device handle
109  * @ret rc Return status code
110  */
111 int efi_child_add ( EFI_HANDLE parent, EFI_HANDLE child ) {
112  EFI_DEVICE_PATH_PROTOCOL *devpath;
113  int rc;
114 
115  /* Re-open the device path protocol */
117  child, &devpath ) ) != 0 ) {
118  DBGC ( parent, "EFIDEV %s could not add child",
119  efi_handle_name ( parent ) );
120  DBGC ( parent, " %s: %s\n",
121  efi_handle_name ( child ), strerror ( rc ) );
122  DBGC_EFI_OPENERS ( parent, parent,
124  return rc;
125  }
126 
127  DBGC2 ( parent, "EFIDEV %s added child", efi_handle_name ( parent ) );
128  DBGC2 ( parent, " %s\n", efi_handle_name ( child ) );
129  return 0;
130 }
131 
132 /**
133  * Remove EFI device as child of another EFI device
134  *
135  * @v parent EFI parent device handle
136  * @v child EFI child device handle
137  */
138 void efi_child_del ( EFI_HANDLE parent, EFI_HANDLE child ) {
139 
141  DBGC2 ( parent, "EFIDEV %s removed child", efi_handle_name ( parent ) );
142  DBGC2 ( parent, " %s\n", efi_handle_name ( child ) );
143 }
144 
145 /**
146  * Get underlying PCI device information
147  *
148  * @v device EFI device handle
149  * @v prefix Device name prefix
150  * @v dev Generic device to fill in
151  * @ret rc Return status code
152  */
153 static int efi_device_info_pci ( EFI_HANDLE device, const char *prefix,
154  struct device *dev ) {
156  struct efi_pci_device efipci;
157  int rc;
158 
159  /* Find parent PCI device */
161  &pci_device, 0 ) ) != 0 ) {
162  DBGC ( device, "EFIDEV %s is not a PCI device: %s\n",
163  efi_handle_name ( device ), strerror ( rc ) );
164  return rc;
165  }
166 
167  /* Get PCI device information */
168  if ( ( rc = efipci_info ( pci_device, &efipci ) ) != 0 ) {
169  DBGC ( device, "EFIDEV %s could not get PCI information: %s\n",
170  efi_handle_name ( device ), strerror ( rc ) );
171  return rc;
172  }
173 
174  /* Populate device information */
175  memcpy ( &dev->desc, &efipci.pci.dev.desc, sizeof ( dev->desc ) );
176  snprintf ( dev->name, sizeof ( dev->name ), "%s-%s",
177  prefix, efipci.pci.dev.name );
178 
179  return 0;
180 }
181 
182 /**
183  * Get underlying device information
184  *
185  * @v device EFI device handle
186  * @v prefix Device name prefix
187  * @v dev Generic device to fill in
188  */
190  struct device *dev ) {
191  int rc;
192 
193  /* Try getting underlying PCI device information */
194  if ( ( rc = efi_device_info_pci ( device, prefix, dev ) ) == 0 )
195  return;
196 
197  /* If we cannot get any underlying device information, fall
198  * back to providing information about the EFI handle.
199  */
200  DBGC ( device, "EFIDEV %s could not get underlying device "
201  "information\n", efi_handle_name ( device ) );
202  dev->desc.bus_type = BUS_TYPE_EFI;
203  snprintf ( dev->name, sizeof ( dev->name ), "%s-%p", prefix, device );
204 }
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
int efipci_info(EFI_HANDLE device, struct efi_pci_device *efipci)
Get EFI PCI device information.
Definition: efi_pci.c:705
struct pci_device pci
PCI device.
Definition: efi_pci.h:24
128 bit buffer containing a unique identifier value.
Definition: Base.h:216
Error codes.
EFI_GUID efi_pci_io_protocol_guid
PCI I/O protocol GUID.
Definition: efi_guid.c:313
void efi_close_by_child(EFI_HANDLE handle, EFI_GUID *protocol, EFI_HANDLE child)
Close protocol opened for persistent use by a child controller.
Definition: efi_open.c:344
#define DBGC(...)
Definition: compiler.h:505
char name[40]
Name.
Definition: device.h:79
size_t efi_path_len(EFI_DEVICE_PATH_PROTOCOL *path)
Find length of device path (excluding terminator)
Definition: efi_path.c:174
char prefix[4]
Definition: vmconsole.c:53
#define DBGC_EFI_OPENERS(...)
Definition: efi.h:345
This protocol can be used on any device handle to obtain generic path/location information concerning...
Definition: DevicePath.h:46
int efi_child_add(EFI_HANDLE parent, EFI_HANDLE child)
Add EFI device as child of another EFI device.
Definition: efi_utils.c:111
struct device dev
Generic device.
Definition: pci.h:213
EFI utilities.
static void efi_path_terminate(EFI_DEVICE_PATH_PROTOCOL *end)
Terminate device path.
Definition: efi_path.h:31
EFI_DEVICE_PATH_PROTOCOL * efi_path_prev(EFI_DEVICE_PATH_PROTOCOL *path, EFI_DEVICE_PATH_PROTOCOL *curr)
Find previous element of device path.
Definition: efi_path.c:145
#define efi_open_by_child(handle, protocol, child, interface)
Open protocol for persistent use by a child controller.
Definition: efi.h:490
void efi_child_del(EFI_HANDLE parent, EFI_HANDLE child)
Remove EFI device as child of another EFI device.
Definition: efi_utils.c:138
FILE_LICENCE(GPL2_OR_LATER)
#define ENOMEM
Not enough space.
Definition: errno.h:535
A hardware device.
Definition: device.h:77
void * memcpy(void *dest, const void *src, size_t len) __nonnull
ring len
Length.
Definition: dwmac.h:231
const char * efi_devpath_text(EFI_DEVICE_PATH_PROTOCOL *path)
Get textual representation of device path.
Definition: efi_debug.c:247
const char * efi_handle_name(EFI_HANDLE handle)
Get name of an EFI handle.
Definition: efi_debug.c:652
char * strerror(int errno)
Retrieve string representation of error number.
Definition: strerror.c:79
static void(* free)(struct refcnt *refcnt))
Definition: refcnt.h:55
FILE_SECBOOT(PERMITTED)
EFI Boot Services Table.
Definition: UefiSpec.h:1931
A PCI device.
Definition: pci.h:211
#define efi_open(handle, protocol, interface)
Open protocol for ephemeral use.
Definition: efi.h:444
EFI device paths.
EFI_GUID efi_device_path_protocol_guid
Device path protocol GUID.
Definition: efi_guid.c:169
int efi_locate_device(EFI_HANDLE device, EFI_GUID *protocol, EFI_HANDLE *parent, unsigned int skip)
Locate parent device supporting a given protocol.
Definition: efi_utils.c:46
const char * efi_guid_ntoa(CONST EFI_GUID *guid)
Convert GUID to a printable string.
Definition: efi_guid.c:726
#define BUS_TYPE_EFI
EFI bus type.
Definition: device.h:62
void * malloc(size_t size)
Allocate memory.
Definition: malloc.c:621
EFI API.
An EFI PCI device.
Definition: efi_pci.h:22
unsigned int bus_type
Bus type.
Definition: device.h:25
#define DBGC2(...)
Definition: compiler.h:522
RETURN_STATUS EFI_STATUS
Function return status for EFI API.
Definition: UefiBaseType.h:32
EFI driver interface.
uint32_t end
Ending offset.
Definition: netvsc.h:18
struct device_description desc
Device description.
Definition: device.h:83
int snprintf(char *buf, size_t size, const char *fmt,...)
Write a formatted string to a buffer.
Definition: vsprintf.c:383
EFI_SYSTEM_TABLE * efi_systab
uint16_t protocol
Protocol ID.
Definition: stp.h:19
static int efi_device_info_pci(EFI_HANDLE device, const char *prefix, struct device *dev)
Get underlying PCI device information.
Definition: efi_utils.c:153
String functions.
Definition: efi.h:62
EFI_LOCATE_DEVICE_PATH LocateDevicePath
Definition: UefiSpec.h:1972
void efi_device_info(EFI_HANDLE device, const char *prefix, struct device *dev)
Get underlying device information.
Definition: efi_utils.c:189