Add qemu 2.4.0
[kvmfornfv.git] / qemu / roms / ipxe / src / drivers / net / efi / snponly.c
1 /*
2  * Copyright (C) 2014 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 <string.h>
23 #include <errno.h>
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>
30 #include "snpnet.h"
31 #include "nii.h"
32
33 /** @file
34  *
35  * EFI chainloaded-device-only driver
36  *
37  */
38
39 /** A chainloaded protocol */
40 struct chained_protocol {
41         /** Protocol GUID */
42         EFI_GUID *protocol;
43         /**
44          * Protocol instance installed on the loaded image's device handle
45          *
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.
50          */
51         void *interface;
52 };
53
54 /** Chainloaded SNP protocol */
55 static struct chained_protocol chained_snp = {
56         .protocol = &efi_simple_network_protocol_guid,
57 };
58
59 /** Chainloaded NII protocol */
60 static struct chained_protocol chained_nii = {
61         .protocol = &efi_nii31_protocol_guid,
62 };
63
64 /**
65  * Locate chainloaded protocol instance
66  *
67  * @v chained           Chainloaded protocol
68  * @ret rc              Return status code
69  */
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;
73         EFI_HANDLE parent;
74         EFI_STATUS efirc;
75         int rc;
76
77         /* Locate handle supporting this protocol */
78         if ( ( rc = efi_locate_device ( device, chained->protocol,
79                                         &parent ) ) != 0 ) {
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;
84         }
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 ) );
88
89         /* Get protocol instance */
90         if ( ( efirc = bs->OpenProtocol ( parent, chained->protocol,
91                                           &chained->interface, efi_image_handle,
92                                           device,
93                                           EFI_OPEN_PROTOCOL_GET_PROTOCOL ))!=0){
94                 rc = -EEFI ( efirc );
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;
101         }
102
103  err_locate_device:
104         bs->CloseProtocol ( parent, chained->protocol, efi_image_handle,
105                             device );
106  err_open_protocol:
107         return rc;
108 }
109
110 /**
111  * Check to see if driver supports a device
112  *
113  * @v device            EFI device handle
114  * @v chained           Chainloaded protocol
115  * @ret rc              Return status code
116  */
117 static int chained_supported ( EFI_HANDLE device,
118                                struct chained_protocol *chained ) {
119         EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
120         EFI_STATUS efirc;
121         void *interface;
122         int rc;
123
124         /* Get protocol */
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;
133         }
134
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 ) );
140                 rc = -ENOTTY;
141                 goto err_no_match;
142         }
143
144         /* Success */
145         rc = 0;
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 ) );
149
150  err_no_match:
151         bs->CloseProtocol ( device, chained->protocol, efi_image_handle,
152                             device );
153  err_open_protocol:
154         return rc;
155 }
156
157 /**
158  * Check to see if driver supports a device
159  *
160  * @v device            EFI device handle
161  * @ret rc              Return status code
162  */
163 static int snponly_supported ( EFI_HANDLE device ) {
164
165         return chained_supported ( device, &chained_snp );
166 }
167
168 /**
169  * Check to see if driver supports a device
170  *
171  * @v device            EFI device handle
172  * @ret rc              Return status code
173  */
174 static int niionly_supported ( EFI_HANDLE device ) {
175
176         return chained_supported ( device, &chained_nii );
177 }
178
179 /** EFI SNP chainloading-device-only driver */
180 struct efi_driver snponly_driver __efi_driver ( EFI_DRIVER_NORMAL ) = {
181         .name = "SNPONLY",
182         .supported = snponly_supported,
183         .start = snpnet_start,
184         .stop = snpnet_stop,
185 };
186
187 /** EFI NII chainloading-device-only driver */
188 struct efi_driver niionly_driver __efi_driver ( EFI_DRIVER_NORMAL ) = {
189         .name = "NIIONLY",
190         .supported = niionly_supported,
191         .start = nii_start,
192         .stop = nii_stop,
193 };
194
195 /**
196  * Initialise EFI chainloaded-device-only driver
197  *
198  */
199 static void chained_init ( void ) {
200
201         chained_locate ( &chained_snp );
202         chained_locate ( &chained_nii );
203 }
204
205 /** EFI chainloaded-device-only initialisation function */
206 struct init_fn chained_init_fn __init_fn ( INIT_LATE ) = {
207         .initialise = chained_init,
208 };