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
20FILE_LICENCE ( GPL2_OR_LATER );
21FILE_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 ) {
48 EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
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",
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 ),
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 */
111int efi_child_add ( EFI_HANDLE parent, EFI_HANDLE child ) {
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 */
138void 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 */
153static 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",
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",
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 ) );
203 snprintf ( dev->name, sizeof ( dev->name ), "%s-%p", prefix, device );
204}
RETURN_STATUS EFI_STATUS
Function return status for EFI API.
GUID EFI_GUID
128-bit buffer containing a unique identifier value.
struct arbelprm_rc_send_wqe rc
Definition arbel.h:3
#define BUS_TYPE_EFI
EFI bus type.
Definition device.h:62
ring len
Length.
Definition dwmac.h:226
const char * efi_handle_name(EFI_HANDLE handle)
Get name of an EFI handle.
Definition efi_debug.c:652
const char * efi_devpath_text(EFI_DEVICE_PATH_PROTOCOL *path)
Get textual representation of device path.
Definition efi_debug.c:247
const char * efi_guid_ntoa(CONST EFI_GUID *guid)
Convert GUID to a printable string.
Definition efi_guid.c:726
EFI_GUID efi_device_path_protocol_guid
Device path protocol GUID.
Definition efi_guid.c:169
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
size_t efi_path_len(EFI_DEVICE_PATH_PROTOCOL *path)
Find length of device path (excluding terminator)
Definition efi_path.c:174
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
EFI device paths.
static void efi_path_terminate(EFI_DEVICE_PATH_PROTOCOL *end)
Terminate device path.
Definition efi_path.h:31
int efipci_info(EFI_HANDLE device, struct efi_pci_device *efipci)
Get EFI PCI device information.
Definition efi_pci.c:711
EFI driver interface.
void efi_child_del(EFI_HANDLE parent, EFI_HANDLE child)
Remove EFI device as child of another EFI device.
Definition efi_utils.c:138
int efi_child_add(EFI_HANDLE parent, EFI_HANDLE child)
Add EFI device as child of another EFI device.
Definition efi_utils.c:111
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
void efi_device_info(EFI_HANDLE device, const char *prefix, struct device *dev)
Get underlying device information.
Definition efi_utils.c:189
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
EFI utilities.
Error codes.
#define DBGC2(...)
Definition compiler.h:522
#define DBGC(...)
Definition compiler.h:505
#define FILE_LICENCE(_licence)
Declare a particular licence as applying to a file.
Definition compiler.h:896
#define ENOMEM
Not enough space.
Definition errno.h:535
#define FILE_SECBOOT(_status)
Declare a file's UEFI Secure Boot permission status.
Definition compiler.h:926
EFI API.
#define efi_open(handle, protocol, interface)
Open protocol for ephemeral use.
Definition efi.h:444
#define EFI_HANDLE
Definition efi.h:53
#define EEFI(efirc)
Convert an EFI status code to an iPXE status code.
Definition efi.h:175
#define DBGC_EFI_OPENERS(...)
Definition efi.h:345
#define efi_open_by_child(handle, protocol, child, interface)
Open protocol for persistent use by a child controller.
Definition efi.h:490
EFI_SYSTEM_TABLE * efi_systab
String functions.
void * memcpy(void *dest, const void *src, size_t len) __nonnull
void * malloc(size_t size)
Allocate memory.
Definition malloc.c:621
uint32_t end
Ending offset.
Definition netvsc.h:7
static void(* free)(struct refcnt *refcnt))
Definition refcnt.h:55
uint16_t protocol
Protocol ID.
Definition stp.h:7
char * strerror(int errno)
Retrieve string representation of error number.
Definition strerror.c:79
EFI Boot Services Table.
Definition UefiSpec.h:1931
EFI_LOCATE_DEVICE_PATH LocateDevicePath
Definition UefiSpec.h:1972
This protocol can be used on any device handle to obtain generic path/location information concerning...
Definition DevicePath.h:46
unsigned int bus_type
Bus type.
Definition device.h:25
A hardware device.
Definition device.h:77
struct device_description desc
Device description.
Definition device.h:83
char name[40]
Name.
Definition device.h:79
An EFI PCI device.
Definition efi_pci.h:22
struct pci_device pci
PCI device.
Definition efi_pci.h:24
A PCI device.
Definition pci.h:211
struct device dev
Generic device.
Definition pci.h:213
char prefix[4]
Definition vmconsole.c:53
int snprintf(char *buf, size_t size, const char *fmt,...)
Write a formatted string to a buffer.
Definition vsprintf.c:383