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 
22 #include <stdio.h>
23 #include <string.h>
24 #include <errno.h>
25 #include <ipxe/efi/efi.h>
26 #include <ipxe/efi/efi_path.h>
27 #include <ipxe/efi/efi_pci.h>
28 #include <ipxe/efi/efi_utils.h>
29 
30 /** @file
31  *
32  * EFI utilities
33  *
34  */
35 
36 /**
37  * Locate parent device supporting a given protocol
38  *
39  * @v device EFI device handle
40  * @v protocol Protocol GUID
41  * @v parent Parent EFI device handle to fill in
42  * @v skip Number of protocol-supporting parent devices to skip
43  * @ret rc Return status code
44  */
46  EFI_HANDLE *parent, unsigned int skip ) {
48  EFI_DEVICE_PATH_PROTOCOL *devpath;
51  size_t len;
52  EFI_STATUS efirc;
53  int rc;
54 
55  /* Get device path */
57  &devpath ) ) != 0 ) {
58  DBGC ( device, "EFIDEV %s cannot open device path: %s\n",
59  efi_handle_name ( device ), strerror ( rc ) );
60  goto err_open_device_path;
61  }
62 
63  /* Create modifiable copy of device path */
64  len = ( efi_path_len ( devpath ) + sizeof ( *end ) );
65  path = malloc ( len );
66  if ( ! path ) {
67  rc = -ENOMEM;
68  goto err_alloc_path;
69  }
70  memcpy ( path, devpath, len );
71 
72  /* Locate parent device(s) */
73  while ( 1 ) {
74 
75  /* Check for presence of specified protocol */
76  end = path;
77  if ( ( efirc = bs->LocateDevicePath ( protocol, &end,
78  parent ) ) != 0 ) {
79  rc = -EEFI ( efirc );
80  DBGC ( device, "EFIDEV %s has no parent supporting "
81  "%s: %s\n", efi_devpath_text ( path ),
82  efi_guid_ntoa ( protocol ), strerror ( rc ) );
83  goto err_locate_protocol;
84  }
85 
86  /* Stop if we have skipped the requested number of devices */
87  if ( ! skip-- )
88  break;
89 
90  /* Trim device path */
92  end = efi_path_prev ( path, end );
94  }
95 
96  err_locate_protocol:
97  free ( path );
98  err_alloc_path:
99  err_open_device_path:
100  return rc;
101 }
102 
103 /**
104  * Add EFI device as child of another EFI device
105  *
106  * @v parent EFI parent device handle
107  * @v child EFI child device handle
108  * @ret rc Return status code
109  */
110 int efi_child_add ( EFI_HANDLE parent, EFI_HANDLE child ) {
111  EFI_DEVICE_PATH_PROTOCOL *devpath;
112  int rc;
113 
114  /* Re-open the device path protocol */
116  child, &devpath ) ) != 0 ) {
117  DBGC ( parent, "EFIDEV %s could not add child",
118  efi_handle_name ( parent ) );
119  DBGC ( parent, " %s: %s\n",
120  efi_handle_name ( child ), strerror ( rc ) );
121  DBGC_EFI_OPENERS ( parent, parent,
123  return rc;
124  }
125 
126  DBGC2 ( parent, "EFIDEV %s added child", efi_handle_name ( parent ) );
127  DBGC2 ( parent, " %s\n", efi_handle_name ( child ) );
128  return 0;
129 }
130 
131 /**
132  * Remove EFI device as child of another EFI device
133  *
134  * @v parent EFI parent device handle
135  * @v child EFI child device handle
136  */
137 void efi_child_del ( EFI_HANDLE parent, EFI_HANDLE child ) {
138 
140  DBGC2 ( parent, "EFIDEV %s removed child", efi_handle_name ( parent ) );
141  DBGC2 ( parent, " %s\n", efi_handle_name ( child ) );
142 }
143 
144 /**
145  * Get underlying PCI device information
146  *
147  * @v device EFI device handle
148  * @v prefix Device name prefix
149  * @v dev Generic device to fill in
150  * @ret rc Return status code
151  */
152 static int efi_device_info_pci ( EFI_HANDLE device, const char *prefix,
153  struct device *dev ) {
155  struct efi_pci_device efipci;
156  int rc;
157 
158  /* Find parent PCI device */
160  &pci_device, 0 ) ) != 0 ) {
161  DBGC ( device, "EFIDEV %s is not a PCI device: %s\n",
162  efi_handle_name ( device ), strerror ( rc ) );
163  return rc;
164  }
165 
166  /* Get PCI device information */
167  if ( ( rc = efipci_info ( pci_device, &efipci ) ) != 0 ) {
168  DBGC ( device, "EFIDEV %s could not get PCI information: %s\n",
169  efi_handle_name ( device ), strerror ( rc ) );
170  return rc;
171  }
172 
173  /* Populate device information */
174  memcpy ( &dev->desc, &efipci.pci.dev.desc, sizeof ( dev->desc ) );
175  snprintf ( dev->name, sizeof ( dev->name ), "%s-%s",
176  prefix, efipci.pci.dev.name );
177 
178  return 0;
179 }
180 
181 /**
182  * Get underlying device information
183  *
184  * @v device EFI device handle
185  * @v prefix Device name prefix
186  * @v dev Generic device to fill in
187  */
189  struct device *dev ) {
190  int rc;
191 
192  /* Try getting underlying PCI device information */
193  if ( ( rc = efi_device_info_pci ( device, prefix, dev ) ) == 0 )
194  return;
195 
196  /* If we cannot get any underlying device information, fall
197  * back to providing information about the EFI handle.
198  */
199  DBGC ( device, "EFIDEV %s could not get underlying device "
200  "information\n", efi_handle_name ( device ) );
201  dev->desc.bus_type = BUS_TYPE_EFI;
202  snprintf ( dev->name, sizeof ( dev->name ), "%s-%p", prefix, device );
203 }
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
int efipci_info(EFI_HANDLE device, struct efi_pci_device *efipci)
Get EFI PCI device information.
Definition: efi_pci.c:704
struct pci_device pci
PCI device.
Definition: efi_pci.h:23
128 bit buffer containing a unique identifier value.
Definition: Base.h:215
Error codes.
EFI_GUID efi_pci_io_protocol_guid
PCI I/O protocol GUID.
Definition: efi_guid.c:312
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:343
#define DBGC(...)
Definition: compiler.h:505
char name[40]
Name.
Definition: device.h:78
size_t efi_path_len(EFI_DEVICE_PATH_PROTOCOL *path)
Find length of device path (excluding terminator)
Definition: efi_path.c:173
char prefix[4]
Definition: vmconsole.c:53
#define DBGC_EFI_OPENERS(...)
Definition: efi.h:344
This protocol can be used on any device handle to obtain generic path/location information concerning...
Definition: DevicePath.h:45
int efi_child_add(EFI_HANDLE parent, EFI_HANDLE child)
Add EFI device as child of another EFI device.
Definition: efi_utils.c:110
struct device dev
Generic device.
Definition: pci.h:212
EFI utilities.
static void efi_path_terminate(EFI_DEVICE_PATH_PROTOCOL *end)
Terminate device path.
Definition: efi_path.h:30
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:144
#define efi_open_by_child(handle, protocol, child, interface)
Open protocol for persistent use by a child controller.
Definition: efi.h:489
void efi_child_del(EFI_HANDLE parent, EFI_HANDLE child)
Remove EFI device as child of another EFI device.
Definition: efi_utils.c:137
FILE_LICENCE(GPL2_OR_LATER)
#define ENOMEM
Not enough space.
Definition: errno.h:534
A hardware device.
Definition: device.h:76
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:78
static void(* free)(struct refcnt *refcnt))
Definition: refcnt.h:54
EFI Boot Services Table.
Definition: UefiSpec.h:1930
A PCI device.
Definition: pci.h:210
#define efi_open(handle, protocol, interface)
Open protocol for ephemeral use.
Definition: efi.h:443
EFI device paths.
EFI_GUID efi_device_path_protocol_guid
Device path protocol GUID.
Definition: efi_guid.c:168
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:45
const char * efi_guid_ntoa(CONST EFI_GUID *guid)
Convert GUID to a printable string.
Definition: efi_guid.c:725
#define BUS_TYPE_EFI
EFI bus type.
Definition: device.h:61
void * malloc(size_t size)
Allocate memory.
Definition: malloc.c:620
EFI API.
An EFI PCI device.
Definition: efi_pci.h:21
unsigned int bus_type
Bus type.
Definition: device.h:24
#define DBGC2(...)
Definition: compiler.h:522
RETURN_STATUS EFI_STATUS
Function return status for EFI API.
Definition: UefiBaseType.h:31
EFI driver interface.
uint32_t end
Ending offset.
Definition: netvsc.h:18
struct device_description desc
Device description.
Definition: device.h:82
int snprintf(char *buf, size_t size, const char *fmt,...)
Write a formatted string to a buffer.
Definition: vsprintf.c:382
EFI_SYSTEM_TABLE * efi_systab
uint16_t protocol
Protocol ID.
Definition: stp.h:18
static int efi_device_info_pci(EFI_HANDLE device, const char *prefix, struct device *dev)
Get underlying PCI device information.
Definition: efi_utils.c:152
String functions.
Definition: efi.h:61
EFI_LOCATE_DEVICE_PATH LocateDevicePath
Definition: UefiSpec.h:1971
void efi_device_info(EFI_HANDLE device, const char *prefix, struct device *dev)
Get underlying device information.
Definition: efi_utils.c:188