1 /*
2 * Copyright (C) 2020 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 #include <stdlib.h>
21 #include <stdarg.h>
22 #include <string.h>
23 #include <byteswap.h>
24 #include <ipxe/netdevice.h>
25 #include <ipxe/vlan.h>
26 #include <ipxe/tcpip.h>
27 #include <ipxe/uri.h>
28 #include <ipxe/iscsi.h>
29 #include <ipxe/aoe.h>
30 #include <ipxe/fcp.h>
31 #include <ipxe/ib_srp.h>
32 #include <ipxe/usb.h>
33 #include <ipxe/efi/efi.h>
34 #include <ipxe/efi/efi_driver.h>
35 #include <ipxe/efi/efi_path.h>
36
37 /** @file
38 *
39 * EFI device paths
40 *
41 */
42
43 /**
44 * Find end of device path
45 *
46 * @v path Path to device
47 * @ret path_end End of device path
48 */
efi_path_end(EFI_DEVICE_PATH_PROTOCOL * path)49 EFI_DEVICE_PATH_PROTOCOL * efi_path_end ( EFI_DEVICE_PATH_PROTOCOL *path ) {
50
51 while ( path->Type != END_DEVICE_PATH_TYPE ) {
52 path = ( ( ( void * ) path ) +
53 /* There's this amazing new-fangled thing known as
54 * a UINT16, but who wants to use one of those? */
55 ( ( path->Length[1] << 8 ) | path->Length[0] ) );
56 }
57
58 return path;
59 }
60
61 /**
62 * Find length of device path (excluding terminator)
63 *
64 * @v path Path to device
65 * @ret path_len Length of device path
66 */
efi_path_len(EFI_DEVICE_PATH_PROTOCOL * path)67 size_t efi_path_len ( EFI_DEVICE_PATH_PROTOCOL *path ) {
68 EFI_DEVICE_PATH_PROTOCOL *end = efi_path_end ( path );
69
70 return ( ( ( void * ) end ) - ( ( void * ) path ) );
71 }
72
73 /**
74 * Concatenate EFI device paths
75 *
76 * @v ... List of device paths (NULL terminated)
77 * @ret path Concatenated device path, or NULL on error
78 *
79 * The caller is responsible for eventually calling free() on the
80 * allocated device path.
81 */
efi_paths(EFI_DEVICE_PATH_PROTOCOL * first,...)82 EFI_DEVICE_PATH_PROTOCOL * efi_paths ( EFI_DEVICE_PATH_PROTOCOL *first, ... ) {
83 EFI_DEVICE_PATH_PROTOCOL *path;
84 EFI_DEVICE_PATH_PROTOCOL *src;
85 EFI_DEVICE_PATH_PROTOCOL *dst;
86 EFI_DEVICE_PATH_PROTOCOL *end;
87 va_list args;
88 size_t len;
89
90 /* Calculate device path length */
91 va_start ( args, first );
92 len = 0;
93 src = first;
94 while ( src ) {
95 len += efi_path_len ( src );
96 src = va_arg ( args, EFI_DEVICE_PATH_PROTOCOL * );
97 }
98 va_end ( args );
99
100 /* Allocate device path */
101 path = zalloc ( len + sizeof ( *end ) );
102 if ( ! path )
103 return NULL;
104
105 /* Populate device path */
106 va_start ( args, first );
107 dst = path;
108 src = first;
109 while ( src ) {
110 len = efi_path_len ( src );
111 memcpy ( dst, src, len );
112 dst = ( ( ( void * ) dst ) + len );
113 src = va_arg ( args, EFI_DEVICE_PATH_PROTOCOL * );
114 }
115 va_end ( args );
116 end = dst;
117 end->Type = END_DEVICE_PATH_TYPE;
118 end->SubType = END_ENTIRE_DEVICE_PATH_SUBTYPE;
119 end->Length[0] = sizeof ( *end );
120
121 return path;
122 }
123
124 /**
125 * Construct EFI device path for network device
126 *
127 * @v netdev Network device
128 * @ret path EFI device path, or NULL on error
129 *
130 * The caller is responsible for eventually calling free() on the
131 * allocated device path.
132 */
efi_netdev_path(struct net_device * netdev)133 EFI_DEVICE_PATH_PROTOCOL * efi_netdev_path ( struct net_device *netdev ) {
134 struct efi_device *efidev;
135 EFI_DEVICE_PATH_PROTOCOL *path;
136 MAC_ADDR_DEVICE_PATH *macpath;
137 VLAN_DEVICE_PATH *vlanpath;
138 EFI_DEVICE_PATH_PROTOCOL *end;
139 unsigned int tag;
140 size_t prefix_len;
141 size_t len;
142
143 /* Find parent EFI device */
144 efidev = efidev_parent ( netdev->dev );
145 if ( ! efidev )
146 return NULL;
147
148 /* Calculate device path length */
149 prefix_len = efi_path_len ( efidev->path );
150 len = ( prefix_len + sizeof ( *macpath ) + sizeof ( *vlanpath ) +
151 sizeof ( *end ) );
152
153 /* Allocate device path */
154 path = zalloc ( len );
155 if ( ! path )
156 return NULL;
157
158 /* Construct device path */
159 memcpy ( path, efidev->path, prefix_len );
160 macpath = ( ( ( void * ) path ) + prefix_len );
161 macpath->Header.Type = MESSAGING_DEVICE_PATH;
162 macpath->Header.SubType = MSG_MAC_ADDR_DP;
163 macpath->Header.Length[0] = sizeof ( *macpath );
164 assert ( netdev->ll_protocol->ll_addr_len <
165 sizeof ( macpath->MacAddress ) );
166 memcpy ( &macpath->MacAddress, netdev->ll_addr,
167 netdev->ll_protocol->ll_addr_len );
168 macpath->IfType = ntohs ( netdev->ll_protocol->ll_proto );
169 if ( ( tag = vlan_tag ( netdev ) ) ) {
170 vlanpath = ( ( ( void * ) macpath ) + sizeof ( *macpath ) );
171 vlanpath->Header.Type = MESSAGING_DEVICE_PATH;
172 vlanpath->Header.SubType = MSG_VLAN_DP;
173 vlanpath->Header.Length[0] = sizeof ( *vlanpath );
174 vlanpath->VlanId = tag;
175 end = ( ( ( void * ) vlanpath ) + sizeof ( *vlanpath ) );
176 } else {
177 end = ( ( ( void * ) macpath ) + sizeof ( *macpath ) );
178 }
179 end->Type = END_DEVICE_PATH_TYPE;
180 end->SubType = END_ENTIRE_DEVICE_PATH_SUBTYPE;
181 end->Length[0] = sizeof ( *end );
182
183 return path;
184 }
185
186 /**
187 * Construct EFI device path for URI
188 *
189 * @v uri URI
190 * @ret path EFI device path, or NULL on error
191 *
192 * The caller is responsible for eventually calling free() on the
193 * allocated device path.
194 */
efi_uri_path(struct uri * uri)195 EFI_DEVICE_PATH_PROTOCOL * efi_uri_path ( struct uri *uri ) {
196 EFI_DEVICE_PATH_PROTOCOL *path;
197 EFI_DEVICE_PATH_PROTOCOL *end;
198 URI_DEVICE_PATH *uripath;
199 size_t uri_len;
200 size_t uripath_len;
201 size_t len;
202
203 /* Calculate device path length */
204 uri_len = ( format_uri ( uri, NULL, 0 ) + 1 /* NUL */ );
205 uripath_len = ( sizeof ( *uripath ) + uri_len );
206 len = ( uripath_len + sizeof ( *end ) );
207
208 /* Allocate device path */
209 path = zalloc ( len );
210 if ( ! path )
211 return NULL;
212
213 /* Construct device path */
214 uripath = ( ( void * ) path );
215 uripath->Header.Type = MESSAGING_DEVICE_PATH;
216 uripath->Header.SubType = MSG_URI_DP;
217 uripath->Header.Length[0] = ( uripath_len & 0xff );
218 uripath->Header.Length[1] = ( uripath_len >> 8 );
219 format_uri ( uri, uripath->Uri, uri_len );
220 end = ( ( ( void * ) path ) + uripath_len );
221 end->Type = END_DEVICE_PATH_TYPE;
222 end->SubType = END_ENTIRE_DEVICE_PATH_SUBTYPE;
223 end->Length[0] = sizeof ( *end );
224
225 return path;
226 }
227
228 /**
229 * Construct EFI device path for iSCSI device
230 *
231 * @v iscsi iSCSI session
232 * @ret path EFI device path, or NULL on error
233 */
efi_iscsi_path(struct iscsi_session * iscsi)234 EFI_DEVICE_PATH_PROTOCOL * efi_iscsi_path ( struct iscsi_session *iscsi ) {
235 struct sockaddr_tcpip *st_target;
236 struct net_device *netdev;
237 EFI_DEVICE_PATH_PROTOCOL *netpath;
238 EFI_DEVICE_PATH_PROTOCOL *path;
239 EFI_DEVICE_PATH_PROTOCOL *end;
240 ISCSI_DEVICE_PATH *iscsipath;
241 char *name;
242 size_t prefix_len;
243 size_t name_len;
244 size_t iscsi_len;
245 size_t len;
246
247 /* Get network device associated with target address */
248 st_target = ( ( struct sockaddr_tcpip * ) &iscsi->target_sockaddr );
249 netdev = tcpip_netdev ( st_target );
250 if ( ! netdev )
251 goto err_netdev;
252
253 /* Get network device path */
254 netpath = efi_netdev_path ( netdev );
255 if ( ! netpath )
256 goto err_netpath;
257
258 /* Calculate device path length */
259 prefix_len = efi_path_len ( netpath );
260 name_len = ( strlen ( iscsi->target_iqn ) + 1 /* NUL */ );
261 iscsi_len = ( sizeof ( *iscsipath ) + name_len );
262 len = ( prefix_len + iscsi_len + sizeof ( *end ) );
263
264 /* Allocate device path */
265 path = zalloc ( len );
266 if ( ! path )
267 goto err_alloc;
268
269 /* Construct device path */
270 memcpy ( path, netpath, prefix_len );
271 iscsipath = ( ( ( void * ) path ) + prefix_len );
272 iscsipath->Header.Type = MESSAGING_DEVICE_PATH;
273 iscsipath->Header.SubType = MSG_ISCSI_DP;
274 iscsipath->Header.Length[0] = iscsi_len;
275 iscsipath->LoginOption = ISCSI_LOGIN_OPTION_AUTHMETHOD_NON;
276 memcpy ( &iscsipath->Lun, &iscsi->lun, sizeof ( iscsipath->Lun ) );
277 name = ( ( ( void * ) iscsipath ) + sizeof ( *iscsipath ) );
278 memcpy ( name, iscsi->target_iqn, name_len );
279 end = ( ( ( void * ) name ) + name_len );
280 end->Type = END_DEVICE_PATH_TYPE;
281 end->SubType = END_ENTIRE_DEVICE_PATH_SUBTYPE;
282 end->Length[0] = sizeof ( *end );
283
284 /* Free temporary paths */
285 free ( netpath );
286
287 return path;
288
289 err_alloc:
290 free ( netpath );
291 err_netpath:
292 err_netdev:
293 return NULL;
294 }
295
296 /**
297 * Construct EFI device path for AoE device
298 *
299 * @v aoedev AoE device
300 * @ret path EFI device path, or NULL on error
301 */
efi_aoe_path(struct aoe_device * aoedev)302 EFI_DEVICE_PATH_PROTOCOL * efi_aoe_path ( struct aoe_device *aoedev ) {
303 struct {
304 SATA_DEVICE_PATH sata;
305 EFI_DEVICE_PATH_PROTOCOL end;
306 } satapath;
307 EFI_DEVICE_PATH_PROTOCOL *netpath;
308 EFI_DEVICE_PATH_PROTOCOL *path;
309
310 /* Get network device path */
311 netpath = efi_netdev_path ( aoedev->netdev );
312 if ( ! netpath )
313 goto err_netdev;
314
315 /* Construct SATA path */
316 memset ( &satapath, 0, sizeof ( satapath ) );
317 satapath.sata.Header.Type = MESSAGING_DEVICE_PATH;
318 satapath.sata.Header.SubType = MSG_SATA_DP;
319 satapath.sata.Header.Length[0] = sizeof ( satapath.sata );
320 satapath.sata.HBAPortNumber = aoedev->major;
321 satapath.sata.PortMultiplierPortNumber = aoedev->minor;
322 satapath.end.Type = END_DEVICE_PATH_TYPE;
323 satapath.end.SubType = END_ENTIRE_DEVICE_PATH_SUBTYPE;
324 satapath.end.Length[0] = sizeof ( satapath.end );
325
326 /* Construct overall device path */
327 path = efi_paths ( netpath, &satapath, NULL );
328 if ( ! path )
329 goto err_paths;
330
331 /* Free temporary paths */
332 free ( netpath );
333
334 return path;
335
336 err_paths:
337 free ( netpath );
338 err_netdev:
339 return NULL;
340 }
341
342 /**
343 * Construct EFI device path for Fibre Channel device
344 *
345 * @v desc FCP device description
346 * @ret path EFI device path, or NULL on error
347 */
efi_fcp_path(struct fcp_description * desc)348 EFI_DEVICE_PATH_PROTOCOL * efi_fcp_path ( struct fcp_description *desc ) {
349 struct {
350 FIBRECHANNELEX_DEVICE_PATH fc;
351 EFI_DEVICE_PATH_PROTOCOL end;
352 } __attribute__ (( packed )) *path;
353
354 /* Allocate device path */
355 path = zalloc ( sizeof ( *path ) );
356 if ( ! path )
357 return NULL;
358
359 /* Construct device path */
360 path->fc.Header.Type = MESSAGING_DEVICE_PATH;
361 path->fc.Header.SubType = MSG_FIBRECHANNELEX_DP;
362 path->fc.Header.Length[0] = sizeof ( path->fc );
363 memcpy ( path->fc.WWN, &desc->wwn, sizeof ( path->fc.WWN ) );
364 memcpy ( path->fc.Lun, &desc->lun, sizeof ( path->fc.Lun ) );
365 path->end.Type = END_DEVICE_PATH_TYPE;
366 path->end.SubType = END_ENTIRE_DEVICE_PATH_SUBTYPE;
367 path->end.Length[0] = sizeof ( path->end );
368
369 return &path->fc.Header;
370 }
371
372 /**
373 * Construct EFI device path for Infiniband SRP device
374 *
375 * @v ib_srp Infiniband SRP device
376 * @ret path EFI device path, or NULL on error
377 */
efi_ib_srp_path(struct ib_srp_device * ib_srp)378 EFI_DEVICE_PATH_PROTOCOL * efi_ib_srp_path ( struct ib_srp_device *ib_srp ) {
379 const struct ipxe_ib_sbft *sbft = &ib_srp->sbft;
380 union ib_srp_target_port_id *id =
381 container_of ( &sbft->srp.target, union ib_srp_target_port_id,
382 srp );
383 struct efi_device *efidev;
384 EFI_DEVICE_PATH_PROTOCOL *path;
385 INFINIBAND_DEVICE_PATH *ibpath;
386 EFI_DEVICE_PATH_PROTOCOL *end;
387 size_t prefix_len;
388 size_t len;
389
390 /* Find parent EFI device */
391 efidev = efidev_parent ( ib_srp->ibdev->dev );
392 if ( ! efidev )
393 return NULL;
394
395 /* Calculate device path length */
396 prefix_len = efi_path_len ( efidev->path );
397 len = ( prefix_len + sizeof ( *ibpath ) + sizeof ( *end ) );
398
399 /* Allocate device path */
400 path = zalloc ( len );
401 if ( ! path )
402 return NULL;
403
404 /* Construct device path */
405 memcpy ( path, efidev->path, prefix_len );
406 ibpath = ( ( ( void * ) path ) + prefix_len );
407 ibpath->Header.Type = MESSAGING_DEVICE_PATH;
408 ibpath->Header.SubType = MSG_INFINIBAND_DP;
409 ibpath->Header.Length[0] = sizeof ( *ibpath );
410 ibpath->ResourceFlags = INFINIBAND_RESOURCE_FLAG_STORAGE_PROTOCOL;
411 memcpy ( ibpath->PortGid, &sbft->ib.dgid, sizeof ( ibpath->PortGid ) );
412 memcpy ( &ibpath->ServiceId, &sbft->ib.service_id,
413 sizeof ( ibpath->ServiceId ) );
414 memcpy ( &ibpath->TargetPortId, &id->ib.ioc_guid,
415 sizeof ( ibpath->TargetPortId ) );
416 memcpy ( &ibpath->DeviceId, &id->ib.id_ext,
417 sizeof ( ibpath->DeviceId ) );
418 end = ( ( ( void * ) ibpath ) + sizeof ( *ibpath ) );
419 end->Type = END_DEVICE_PATH_TYPE;
420 end->SubType = END_ENTIRE_DEVICE_PATH_SUBTYPE;
421 end->Length[0] = sizeof ( *end );
422
423 return path;
424 }
425
426 /**
427 * Construct EFI device path for USB function
428 *
429 * @v func USB function
430 * @ret path EFI device path, or NULL on error
431 *
432 * The caller is responsible for eventually calling free() on the
433 * allocated device path.
434 */
efi_usb_path(struct usb_function * func)435 EFI_DEVICE_PATH_PROTOCOL * efi_usb_path ( struct usb_function *func ) {
436 struct usb_device *usb = func->usb;
437 struct efi_device *efidev;
438 EFI_DEVICE_PATH_PROTOCOL *path;
439 EFI_DEVICE_PATH_PROTOCOL *end;
440 USB_DEVICE_PATH *usbpath;
441 unsigned int count;
442 size_t prefix_len;
443 size_t len;
444
445 /* Sanity check */
446 assert ( func->desc.count >= 1 );
447
448 /* Find parent EFI device */
449 efidev = efidev_parent ( &func->dev );
450 if ( ! efidev )
451 return NULL;
452
453 /* Calculate device path length */
454 count = ( usb_depth ( usb ) + 1 );
455 prefix_len = efi_path_len ( efidev->path );
456 len = ( prefix_len + ( count * sizeof ( *usbpath ) ) +
457 sizeof ( *end ) );
458
459 /* Allocate device path */
460 path = zalloc ( len );
461 if ( ! path )
462 return NULL;
463
464 /* Construct device path */
465 memcpy ( path, efidev->path, prefix_len );
466 end = ( ( ( void * ) path ) + len - sizeof ( *end ) );
467 end->Type = END_DEVICE_PATH_TYPE;
468 end->SubType = END_ENTIRE_DEVICE_PATH_SUBTYPE;
469 end->Length[0] = sizeof ( *end );
470 usbpath = ( ( ( void * ) end ) - sizeof ( *usbpath ) );
471 usbpath->InterfaceNumber = func->interface[0];
472 for ( ; usb ; usbpath--, usb = usb->port->hub->usb ) {
473 usbpath->Header.Type = MESSAGING_DEVICE_PATH;
474 usbpath->Header.SubType = MSG_USB_DP;
475 usbpath->Header.Length[0] = sizeof ( *usbpath );
476 usbpath->ParentPortNumber = ( usb->port->address - 1 );
477 }
478
479 return path;
480 }
481
482 /**
483 * Describe object as an EFI device path
484 *
485 * @v intf Interface
486 * @ret path EFI device path, or NULL
487 *
488 * The caller is responsible for eventually calling free() on the
489 * allocated device path.
490 */
efi_describe(struct interface * intf)491 EFI_DEVICE_PATH_PROTOCOL * efi_describe ( struct interface *intf ) {
492 struct interface *dest;
493 efi_describe_TYPE ( void * ) *op =
494 intf_get_dest_op ( intf, efi_describe, &dest );
495 void *object = intf_object ( dest );
496 EFI_DEVICE_PATH_PROTOCOL *path;
497
498 if ( op ) {
499 path = op ( object );
500 } else {
501 path = NULL;
502 }
503
504 intf_put ( dest );
505 return path;
506 }
507