Add qemu 2.4.0
[kvmfornfv.git] / qemu / roms / ipxe / src / interface / efi / efi_utils.c
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_pci.h>
27 #include <ipxe/efi/efi_utils.h>
28
29 /** @file
30  *
31  * EFI utilities
32  *
33  */
34
35 /**
36  * Find end of device path
37  *
38  * @v path              Path to device
39  * @ret path_end        End of device path
40  */
41 EFI_DEVICE_PATH_PROTOCOL * efi_devpath_end ( EFI_DEVICE_PATH_PROTOCOL *path ) {
42
43         while ( path->Type != END_DEVICE_PATH_TYPE ) {
44                 path = ( ( ( void * ) path ) +
45                          /* There's this amazing new-fangled thing known as
46                           * a UINT16, but who wants to use one of those? */
47                          ( ( path->Length[1] << 8 ) | path->Length[0] ) );
48         }
49
50         return path;
51 }
52
53 /**
54  * Locate parent device supporting a given protocol
55  *
56  * @v device            EFI device handle
57  * @v protocol          Protocol GUID
58  * @v parent            Parent EFI device handle to fill in
59  * @ret rc              Return status code
60  */
61 int efi_locate_device ( EFI_HANDLE device, EFI_GUID *protocol,
62                         EFI_HANDLE *parent ) {
63         EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
64         union {
65                 EFI_DEVICE_PATH_PROTOCOL *path;
66                 void *interface;
67         } path;
68         EFI_DEVICE_PATH_PROTOCOL *devpath;
69         EFI_STATUS efirc;
70         int rc;
71
72         /* Get device path */
73         if ( ( efirc = bs->OpenProtocol ( device,
74                                           &efi_device_path_protocol_guid,
75                                           &path.interface,
76                                           efi_image_handle, device,
77                                           EFI_OPEN_PROTOCOL_GET_PROTOCOL ))!=0){
78                 rc = -EEFI ( efirc );
79                 DBGC ( device, "EFIDEV %p %s cannot open device path: %s\n",
80                        device, efi_handle_name ( device ), strerror ( rc ) );
81                 goto err_open_device_path;
82         }
83         devpath = path.path;
84
85         /* Check for presence of specified protocol */
86         if ( ( efirc = bs->LocateDevicePath ( protocol, &devpath,
87                                               parent ) ) != 0 ) {
88                 rc = -EEFI ( efirc );
89                 DBGC ( device, "EFIDEV %p %s has no parent supporting %s: %s\n",
90                        device, efi_handle_name ( device ),
91                        efi_guid_ntoa ( protocol ), strerror ( rc ) );
92                 goto err_locate_protocol;
93         }
94
95         /* Success */
96         rc = 0;
97
98  err_locate_protocol:
99         bs->CloseProtocol ( device, &efi_device_path_protocol_guid,
100                             efi_image_handle, device );
101  err_open_device_path:
102         return rc;
103 }
104
105 /**
106  * Add EFI device as child of another EFI device
107  *
108  * @v parent            EFI parent device handle
109  * @v child             EFI child device handle
110  * @ret rc              Return status code
111  */
112 int efi_child_add ( EFI_HANDLE parent, EFI_HANDLE child ) {
113         EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
114         void *devpath;
115         EFI_STATUS efirc;
116         int rc;
117
118         /* Re-open the device path protocol */
119         if ( ( efirc = bs->OpenProtocol ( parent,
120                                           &efi_device_path_protocol_guid,
121                                           &devpath,
122                                           efi_image_handle, child,
123                                           EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
124                                           ) ) != 0 ) {
125                 rc = -EEFI ( efirc );
126                 DBGC ( parent, "EFIDEV %p %s could not add child",
127                        parent, efi_handle_name ( parent ) );
128                 DBGC ( parent, " %p %s: %s\n", child,
129                        efi_handle_name ( child ), strerror ( rc ) );
130                 DBGC_EFI_OPENERS ( parent, parent,
131                                    &efi_device_path_protocol_guid );
132                 return rc;
133         }
134
135         DBGC2 ( parent, "EFIDEV %p %s added child",
136                 parent, efi_handle_name ( parent ) );
137         DBGC2 ( parent, " %p %s\n", child, efi_handle_name ( child ) );
138         return 0;
139 }
140
141 /**
142  * Remove EFI device as child of another EFI device
143  *
144  * @v parent            EFI parent device handle
145  * @v child             EFI child device handle
146  */
147 void efi_child_del ( EFI_HANDLE parent, EFI_HANDLE child ) {
148         EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
149
150         bs->CloseProtocol ( parent, &efi_device_path_protocol_guid,
151                             efi_image_handle, child );
152         DBGC2 ( parent, "EFIDEV %p %s removed child",
153                 parent, efi_handle_name ( parent ) );
154         DBGC2 ( parent, " %p %s\n",
155                 child, efi_handle_name ( child ) );
156 }
157
158 /**
159  * Get underlying PCI device information
160  *
161  * @v device            EFI device handle
162  * @v prefix            Device name prefix
163  * @v dev               Generic device to fill in
164  * @ret rc              Return status code
165  */
166 static int efi_pci_info ( EFI_HANDLE device, const char *prefix,
167                           struct device *dev ) {
168         EFI_HANDLE pci_device;
169         struct pci_device pci;
170         int rc;
171
172         /* Find parent PCI device */
173         if ( ( rc = efi_locate_device ( device, &efi_pci_io_protocol_guid,
174                                         &pci_device ) ) != 0 ) {
175                 DBGC ( device, "EFIDEV %p %s is not a PCI device: %s\n",
176                        device, efi_handle_name ( device ), strerror ( rc ) );
177                 return rc;
178         }
179
180         /* Get PCI device information */
181         if ( ( rc = efipci_info ( pci_device, &pci ) ) != 0 ) {
182                 DBGC ( device, "EFIDEV %p %s could not get PCI information: "
183                        "%s\n", device, efi_handle_name ( device ),
184                        strerror ( rc ) );
185                 return rc;
186         }
187
188         /* Populate device information */
189         memcpy ( &dev->desc, &pci.dev.desc, sizeof ( dev->desc ) );
190         snprintf ( dev->name, sizeof ( dev->name ), "%s-%s",
191                    prefix, pci.dev.name );
192
193         return 0;
194 }
195
196 /**
197  * Get underlying device information
198  *
199  * @v device            EFI device handle
200  * @v prefix            Device name prefix
201  * @v dev               Generic device to fill in
202  */
203 void efi_device_info ( EFI_HANDLE device, const char *prefix,
204                        struct device *dev ) {
205         int rc;
206
207         /* Try getting underlying PCI device information */
208         if ( ( rc = efi_pci_info ( device, prefix, dev ) ) == 0 )
209                 return;
210
211         /* If we cannot get any underlying device information, fall
212          * back to providing information about the EFI handle.
213          */
214         DBGC ( device, "EFIDEV %p %s could not get underlying device "
215                "information\n", device, efi_handle_name ( device ) );
216         dev->desc.bus_type = BUS_TYPE_EFI;
217         snprintf ( dev->name, sizeof ( dev->name ), "%s-%p", prefix, device );
218 }