2 * Copyright (C) 2014 Michael Brown <mbrown@fensystems.co.uk>.
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.
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.
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
20 FILE_LICENCE ( GPL2_OR_LATER );
24 #include <ipxe/init.h>
25 #include <ipxe/efi/efi.h>
26 #include <ipxe/efi/efi_driver.h>
27 #include <ipxe/efi/efi_utils.h>
28 #include <ipxe/efi/Protocol/SimpleNetwork.h>
29 #include <ipxe/efi/Protocol/NetworkInterfaceIdentifier.h>
35 * EFI chainloaded-device-only driver
39 /** A chainloaded protocol */
40 struct chained_protocol {
44 * Protocol instance installed on the loaded image's device handle
46 * We match against the protocol instance (rather than simply
47 * matching against the device handle itself) because some
48 * systems load us via a child of the underlying device, with
49 * a duplicate protocol installed on the child handle.
54 /** Chainloaded SNP protocol */
55 static struct chained_protocol chained_snp = {
56 .protocol = &efi_simple_network_protocol_guid,
59 /** Chainloaded NII protocol */
60 static struct chained_protocol chained_nii = {
61 .protocol = &efi_nii31_protocol_guid,
65 * Locate chainloaded protocol instance
67 * @v chained Chainloaded protocol
68 * @ret rc Return status code
70 static int chained_locate ( struct chained_protocol *chained ) {
71 EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
72 EFI_HANDLE device = efi_loaded_image->DeviceHandle;
77 /* Locate handle supporting this protocol */
78 if ( ( rc = efi_locate_device ( device, chained->protocol,
80 DBGC ( device, "CHAINED %p %s does not support %s: %s\n",
81 device, efi_handle_name ( device ),
82 efi_guid_ntoa ( chained->protocol ), strerror ( rc ) );
83 goto err_locate_device;
85 DBGC ( device, "CHAINED %p %s found %s on ", device,
86 efi_handle_name ( device ), efi_guid_ntoa ( chained->protocol ));
87 DBGC ( device, "%p %s\n", parent, efi_handle_name ( parent ) );
89 /* Get protocol instance */
90 if ( ( efirc = bs->OpenProtocol ( parent, chained->protocol,
91 &chained->interface, efi_image_handle,
93 EFI_OPEN_PROTOCOL_GET_PROTOCOL ))!=0){
95 DBGC ( device, "CHAINED %p %s could not open %s on ",
96 device, efi_handle_name ( device ),
97 efi_guid_ntoa ( chained->protocol ) );
98 DBGC ( device, "%p %s: %s\n",
99 parent, efi_handle_name ( parent ), strerror ( rc ) );
100 goto err_open_protocol;
104 bs->CloseProtocol ( parent, chained->protocol, efi_image_handle,
111 * Check to see if driver supports a device
113 * @v device EFI device handle
114 * @v chained Chainloaded protocol
115 * @ret rc Return status code
117 static int chained_supported ( EFI_HANDLE device,
118 struct chained_protocol *chained ) {
119 EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
125 if ( ( efirc = bs->OpenProtocol ( device, chained->protocol, &interface,
126 efi_image_handle, device,
127 EFI_OPEN_PROTOCOL_GET_PROTOCOL ))!=0){
128 rc = -EEFI ( efirc );
129 DBGCP ( device, "CHAINED %p %s is not a %s device\n",
130 device, efi_handle_name ( device ),
131 efi_guid_ntoa ( chained->protocol ) );
132 goto err_open_protocol;
135 /* Test for a match against the chainloading device */
136 if ( interface != chained->interface ) {
137 DBGC ( device, "CHAINED %p %s %p is not the chainloaded "
138 "%s\n", device, efi_handle_name ( device ),
139 interface, efi_guid_ntoa ( chained->protocol ) );
146 DBGC ( device, "CHAINED %p %s %p is the chainloaded %s\n",
147 device, efi_handle_name ( device ), interface,
148 efi_guid_ntoa ( chained->protocol ) );
151 bs->CloseProtocol ( device, chained->protocol, efi_image_handle,
158 * Check to see if driver supports a device
160 * @v device EFI device handle
161 * @ret rc Return status code
163 static int snponly_supported ( EFI_HANDLE device ) {
165 return chained_supported ( device, &chained_snp );
169 * Check to see if driver supports a device
171 * @v device EFI device handle
172 * @ret rc Return status code
174 static int niionly_supported ( EFI_HANDLE device ) {
176 return chained_supported ( device, &chained_nii );
179 /** EFI SNP chainloading-device-only driver */
180 struct efi_driver snponly_driver __efi_driver ( EFI_DRIVER_NORMAL ) = {
182 .supported = snponly_supported,
183 .start = snpnet_start,
187 /** EFI NII chainloading-device-only driver */
188 struct efi_driver niionly_driver __efi_driver ( EFI_DRIVER_NORMAL ) = {
190 .supported = niionly_supported,
196 * Initialise EFI chainloaded-device-only driver
199 static void chained_init ( void ) {
201 chained_locate ( &chained_snp );
202 chained_locate ( &chained_nii );
205 /** EFI chainloaded-device-only initialisation function */
206 struct init_fn chained_init_fn __init_fn ( INIT_LATE ) = {
207 .initialise = chained_init,