|
|
1.1 ! root 1: /* ! 2: * Copyright (C) 2008 Michael Brown <[email protected]>. ! 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., 675 Mass Ave, Cambridge, MA 02139, USA. ! 17: */ ! 18: ! 19: FILE_LICENCE ( GPL2_OR_LATER ); ! 20: ! 21: #include <stdlib.h> ! 22: #include <string.h> ! 23: #include <errno.h> ! 24: #include <assert.h> ! 25: #include <byteswap.h> ! 26: #include <ipxe/netdevice.h> ! 27: #include <ipxe/iobuf.h> ! 28: #include <ipxe/in.h> ! 29: #include <ipxe/pci.h> ! 30: #include <ipxe/efi/efi.h> ! 31: #include <ipxe/efi/efi_pci.h> ! 32: #include <ipxe/efi/efi_driver.h> ! 33: #include <ipxe/efi/efi_strings.h> ! 34: #include <ipxe/efi/efi_hii.h> ! 35: #include <ipxe/efi/Protocol/SimpleNetwork.h> ! 36: #include <ipxe/efi/Protocol/NetworkInterfaceIdentifier.h> ! 37: #include <ipxe/efi/Protocol/DevicePath.h> ! 38: #include <ipxe/efi/Protocol/HiiConfigAccess.h> ! 39: #include <ipxe/efi/Protocol/HiiDatabase.h> ! 40: #include <config/general.h> ! 41: ! 42: /** @file ! 43: * ! 44: * iPXE EFI SNP interface ! 45: * ! 46: */ ! 47: ! 48: /** An SNP device */ ! 49: struct efi_snp_device { ! 50: /** List of SNP devices */ ! 51: struct list_head list; ! 52: /** The underlying iPXE network device */ ! 53: struct net_device *netdev; ! 54: /** The underlying EFI PCI device */ ! 55: struct efi_pci_device *efipci; ! 56: /** EFI device handle */ ! 57: EFI_HANDLE handle; ! 58: /** The SNP structure itself */ ! 59: EFI_SIMPLE_NETWORK_PROTOCOL snp; ! 60: /** The SNP "mode" (parameters) */ ! 61: EFI_SIMPLE_NETWORK_MODE mode; ! 62: /** Outstanding TX packet count (via "interrupt status") ! 63: * ! 64: * Used in order to generate TX completions. ! 65: */ ! 66: unsigned int tx_count_interrupts; ! 67: /** Outstanding TX packet count (via "recycled tx buffers") ! 68: * ! 69: * Used in order to generate TX completions. ! 70: */ ! 71: unsigned int tx_count_txbufs; ! 72: /** Outstanding RX packet count (via "interrupt status") */ ! 73: unsigned int rx_count_interrupts; ! 74: /** Outstanding RX packet count (via WaitForPacket event) */ ! 75: unsigned int rx_count_events; ! 76: /** The network interface identifier */ ! 77: EFI_NETWORK_INTERFACE_IDENTIFIER_PROTOCOL nii; ! 78: /** HII configuration access protocol */ ! 79: EFI_HII_CONFIG_ACCESS_PROTOCOL hii; ! 80: /** HII package list */ ! 81: EFI_HII_PACKAGE_LIST_HEADER *package_list; ! 82: /** HII handle */ ! 83: EFI_HII_HANDLE hii_handle; ! 84: /** Device name */ ! 85: wchar_t name[ sizeof ( ( ( struct net_device * ) NULL )->name ) ]; ! 86: /** The device path ! 87: * ! 88: * This field is variable in size and must appear at the end ! 89: * of the structure. ! 90: */ ! 91: EFI_DEVICE_PATH_PROTOCOL path; ! 92: }; ! 93: ! 94: /** EFI simple network protocol GUID */ ! 95: static EFI_GUID efi_simple_network_protocol_guid ! 96: = EFI_SIMPLE_NETWORK_PROTOCOL_GUID; ! 97: ! 98: /** EFI device path protocol GUID */ ! 99: static EFI_GUID efi_device_path_protocol_guid ! 100: = EFI_DEVICE_PATH_PROTOCOL_GUID; ! 101: ! 102: /** EFI network interface identifier GUID */ ! 103: static EFI_GUID efi_nii_protocol_guid ! 104: = EFI_NETWORK_INTERFACE_IDENTIFIER_PROTOCOL_GUID; ! 105: ! 106: /** EFI network interface identifier GUID (extra special version) */ ! 107: static EFI_GUID efi_nii31_protocol_guid = { ! 108: /* At some point, it seems that someone decided to change the ! 109: * GUID. Current EFI builds ignore the older GUID, older EFI ! 110: * builds ignore the newer GUID, so we have to expose both. ! 111: */ ! 112: 0x1ACED566, 0x76ED, 0x4218, ! 113: { 0xBC, 0x81, 0x76, 0x7F, 0x1F, 0x97, 0x7A, 0x89 } ! 114: }; ! 115: ! 116: /** List of SNP devices */ ! 117: static LIST_HEAD ( efi_snp_devices ); ! 118: ! 119: /** ! 120: * Set EFI SNP mode based on iPXE net device parameters ! 121: * ! 122: * @v snp SNP interface ! 123: */ ! 124: static void efi_snp_set_mode ( struct efi_snp_device *snpdev ) { ! 125: struct net_device *netdev = snpdev->netdev; ! 126: EFI_SIMPLE_NETWORK_MODE *mode = &snpdev->mode; ! 127: struct ll_protocol *ll_protocol = netdev->ll_protocol; ! 128: unsigned int ll_addr_len = ll_protocol->ll_addr_len; ! 129: ! 130: mode->HwAddressSize = ll_addr_len; ! 131: mode->MediaHeaderSize = ll_protocol->ll_header_len; ! 132: mode->MaxPacketSize = netdev->max_pkt_len; ! 133: mode->ReceiveFilterMask = ( EFI_SIMPLE_NETWORK_RECEIVE_UNICAST | ! 134: EFI_SIMPLE_NETWORK_RECEIVE_MULTICAST | ! 135: EFI_SIMPLE_NETWORK_RECEIVE_BROADCAST ); ! 136: assert ( ll_addr_len <= sizeof ( mode->CurrentAddress ) ); ! 137: memcpy ( &mode->CurrentAddress, netdev->ll_addr, ll_addr_len ); ! 138: memcpy ( &mode->BroadcastAddress, netdev->ll_broadcast, ll_addr_len ); ! 139: ll_protocol->init_addr ( netdev->hw_addr, &mode->PermanentAddress ); ! 140: mode->IfType = ntohs ( ll_protocol->ll_proto ); ! 141: mode->MacAddressChangeable = TRUE; ! 142: mode->MediaPresentSupported = TRUE; ! 143: mode->MediaPresent = ( netdev_link_ok ( netdev ) ? TRUE : FALSE ); ! 144: } ! 145: ! 146: /** ! 147: * Poll net device and count received packets ! 148: * ! 149: * @v snpdev SNP device ! 150: */ ! 151: static void efi_snp_poll ( struct efi_snp_device *snpdev ) { ! 152: struct io_buffer *iobuf; ! 153: unsigned int before = 0; ! 154: unsigned int after = 0; ! 155: unsigned int arrived; ! 156: ! 157: /* We have to report packet arrivals, and this is the easiest ! 158: * way to fake it. ! 159: */ ! 160: list_for_each_entry ( iobuf, &snpdev->netdev->rx_queue, list ) ! 161: before++; ! 162: netdev_poll ( snpdev->netdev ); ! 163: list_for_each_entry ( iobuf, &snpdev->netdev->rx_queue, list ) ! 164: after++; ! 165: arrived = ( after - before ); ! 166: ! 167: snpdev->rx_count_interrupts += arrived; ! 168: snpdev->rx_count_events += arrived; ! 169: } ! 170: ! 171: /** ! 172: * Change SNP state from "stopped" to "started" ! 173: * ! 174: * @v snp SNP interface ! 175: * @ret efirc EFI status code ! 176: */ ! 177: static EFI_STATUS EFIAPI ! 178: efi_snp_start ( EFI_SIMPLE_NETWORK_PROTOCOL *snp ) { ! 179: struct efi_snp_device *snpdev = ! 180: container_of ( snp, struct efi_snp_device, snp ); ! 181: ! 182: DBGC2 ( snpdev, "SNPDEV %p START\n", snpdev ); ! 183: ! 184: snpdev->mode.State = EfiSimpleNetworkStarted; ! 185: return 0; ! 186: } ! 187: ! 188: /** ! 189: * Change SNP state from "started" to "stopped" ! 190: * ! 191: * @v snp SNP interface ! 192: * @ret efirc EFI status code ! 193: */ ! 194: static EFI_STATUS EFIAPI ! 195: efi_snp_stop ( EFI_SIMPLE_NETWORK_PROTOCOL *snp ) { ! 196: struct efi_snp_device *snpdev = ! 197: container_of ( snp, struct efi_snp_device, snp ); ! 198: ! 199: DBGC2 ( snpdev, "SNPDEV %p STOP\n", snpdev ); ! 200: ! 201: snpdev->mode.State = EfiSimpleNetworkStopped; ! 202: return 0; ! 203: } ! 204: ! 205: /** ! 206: * Open the network device ! 207: * ! 208: * @v snp SNP interface ! 209: * @v extra_rx_bufsize Extra RX buffer size, in bytes ! 210: * @v extra_tx_bufsize Extra TX buffer size, in bytes ! 211: * @ret efirc EFI status code ! 212: */ ! 213: static EFI_STATUS EFIAPI ! 214: efi_snp_initialize ( EFI_SIMPLE_NETWORK_PROTOCOL *snp, ! 215: UINTN extra_rx_bufsize, UINTN extra_tx_bufsize ) { ! 216: struct efi_snp_device *snpdev = ! 217: container_of ( snp, struct efi_snp_device, snp ); ! 218: int rc; ! 219: ! 220: DBGC2 ( snpdev, "SNPDEV %p INITIALIZE (%ld extra RX, %ld extra TX)\n", ! 221: snpdev, ( ( unsigned long ) extra_rx_bufsize ), ! 222: ( ( unsigned long ) extra_tx_bufsize ) ); ! 223: ! 224: if ( ( rc = netdev_open ( snpdev->netdev ) ) != 0 ) { ! 225: DBGC ( snpdev, "SNPDEV %p could not open %s: %s\n", ! 226: snpdev, snpdev->netdev->name, strerror ( rc ) ); ! 227: return RC_TO_EFIRC ( rc ); ! 228: } ! 229: ! 230: snpdev->mode.State = EfiSimpleNetworkInitialized; ! 231: return 0; ! 232: } ! 233: ! 234: /** ! 235: * Reset the network device ! 236: * ! 237: * @v snp SNP interface ! 238: * @v ext_verify Extended verification required ! 239: * @ret efirc EFI status code ! 240: */ ! 241: static EFI_STATUS EFIAPI ! 242: efi_snp_reset ( EFI_SIMPLE_NETWORK_PROTOCOL *snp, BOOLEAN ext_verify ) { ! 243: struct efi_snp_device *snpdev = ! 244: container_of ( snp, struct efi_snp_device, snp ); ! 245: int rc; ! 246: ! 247: DBGC2 ( snpdev, "SNPDEV %p RESET (%s extended verification)\n", ! 248: snpdev, ( ext_verify ? "with" : "without" ) ); ! 249: ! 250: netdev_close ( snpdev->netdev ); ! 251: snpdev->mode.State = EfiSimpleNetworkStarted; ! 252: ! 253: if ( ( rc = netdev_open ( snpdev->netdev ) ) != 0 ) { ! 254: DBGC ( snpdev, "SNPDEV %p could not reopen %s: %s\n", ! 255: snpdev, snpdev->netdev->name, strerror ( rc ) ); ! 256: return RC_TO_EFIRC ( rc ); ! 257: } ! 258: ! 259: snpdev->mode.State = EfiSimpleNetworkInitialized; ! 260: return 0; ! 261: } ! 262: ! 263: /** ! 264: * Shut down the network device ! 265: * ! 266: * @v snp SNP interface ! 267: * @ret efirc EFI status code ! 268: */ ! 269: static EFI_STATUS EFIAPI ! 270: efi_snp_shutdown ( EFI_SIMPLE_NETWORK_PROTOCOL *snp ) { ! 271: struct efi_snp_device *snpdev = ! 272: container_of ( snp, struct efi_snp_device, snp ); ! 273: ! 274: DBGC2 ( snpdev, "SNPDEV %p SHUTDOWN\n", snpdev ); ! 275: ! 276: netdev_close ( snpdev->netdev ); ! 277: snpdev->mode.State = EfiSimpleNetworkStarted; ! 278: return 0; ! 279: } ! 280: ! 281: /** ! 282: * Manage receive filters ! 283: * ! 284: * @v snp SNP interface ! 285: * @v enable Receive filters to enable ! 286: * @v disable Receive filters to disable ! 287: * @v mcast_reset Reset multicast filters ! 288: * @v mcast_count Number of multicast filters ! 289: * @v mcast Multicast filters ! 290: * @ret efirc EFI status code ! 291: */ ! 292: static EFI_STATUS EFIAPI ! 293: efi_snp_receive_filters ( EFI_SIMPLE_NETWORK_PROTOCOL *snp, UINT32 enable, ! 294: UINT32 disable, BOOLEAN mcast_reset, ! 295: UINTN mcast_count, EFI_MAC_ADDRESS *mcast ) { ! 296: struct efi_snp_device *snpdev = ! 297: container_of ( snp, struct efi_snp_device, snp ); ! 298: unsigned int i; ! 299: ! 300: DBGC2 ( snpdev, "SNPDEV %p RECEIVE_FILTERS %08x&~%08x%s %ld mcast\n", ! 301: snpdev, enable, disable, ( mcast_reset ? " reset" : "" ), ! 302: ( ( unsigned long ) mcast_count ) ); ! 303: for ( i = 0 ; i < mcast_count ; i++ ) { ! 304: DBGC2_HDA ( snpdev, i, &mcast[i], ! 305: snpdev->netdev->ll_protocol->ll_addr_len ); ! 306: } ! 307: ! 308: /* Lie through our teeth, otherwise MNP refuses to accept us */ ! 309: return 0; ! 310: } ! 311: ! 312: /** ! 313: * Set station address ! 314: * ! 315: * @v snp SNP interface ! 316: * @v reset Reset to permanent address ! 317: * @v new New station address ! 318: * @ret efirc EFI status code ! 319: */ ! 320: static EFI_STATUS EFIAPI ! 321: efi_snp_station_address ( EFI_SIMPLE_NETWORK_PROTOCOL *snp, BOOLEAN reset, ! 322: EFI_MAC_ADDRESS *new ) { ! 323: struct efi_snp_device *snpdev = ! 324: container_of ( snp, struct efi_snp_device, snp ); ! 325: struct ll_protocol *ll_protocol = snpdev->netdev->ll_protocol; ! 326: ! 327: DBGC2 ( snpdev, "SNPDEV %p STATION_ADDRESS %s\n", snpdev, ! 328: ( reset ? "reset" : ll_protocol->ntoa ( new ) ) ); ! 329: ! 330: /* Set the MAC address */ ! 331: if ( reset ) ! 332: new = &snpdev->mode.PermanentAddress; ! 333: memcpy ( snpdev->netdev->ll_addr, new, ll_protocol->ll_addr_len ); ! 334: ! 335: /* MAC address changes take effect only on netdev_open() */ ! 336: if ( netdev_is_open ( snpdev->netdev ) ) { ! 337: DBGC ( snpdev, "SNPDEV %p MAC address changed while net " ! 338: "devive open\n", snpdev ); ! 339: } ! 340: ! 341: return 0; ! 342: } ! 343: ! 344: /** ! 345: * Get (or reset) statistics ! 346: * ! 347: * @v snp SNP interface ! 348: * @v reset Reset statistics ! 349: * @v stats_len Size of statistics table ! 350: * @v stats Statistics table ! 351: * @ret efirc EFI status code ! 352: */ ! 353: static EFI_STATUS EFIAPI ! 354: efi_snp_statistics ( EFI_SIMPLE_NETWORK_PROTOCOL *snp, BOOLEAN reset, ! 355: UINTN *stats_len, EFI_NETWORK_STATISTICS *stats ) { ! 356: struct efi_snp_device *snpdev = ! 357: container_of ( snp, struct efi_snp_device, snp ); ! 358: EFI_NETWORK_STATISTICS stats_buf; ! 359: ! 360: DBGC2 ( snpdev, "SNPDEV %p STATISTICS%s", snpdev, ! 361: ( reset ? " reset" : "" ) ); ! 362: ! 363: /* Gather statistics */ ! 364: memset ( &stats_buf, 0, sizeof ( stats_buf ) ); ! 365: stats_buf.TxGoodFrames = snpdev->netdev->tx_stats.good; ! 366: stats_buf.TxDroppedFrames = snpdev->netdev->tx_stats.bad; ! 367: stats_buf.TxTotalFrames = ( snpdev->netdev->tx_stats.good + ! 368: snpdev->netdev->tx_stats.bad ); ! 369: stats_buf.RxGoodFrames = snpdev->netdev->rx_stats.good; ! 370: stats_buf.RxDroppedFrames = snpdev->netdev->rx_stats.bad; ! 371: stats_buf.RxTotalFrames = ( snpdev->netdev->rx_stats.good + ! 372: snpdev->netdev->rx_stats.bad ); ! 373: if ( *stats_len > sizeof ( stats_buf ) ) ! 374: *stats_len = sizeof ( stats_buf ); ! 375: if ( stats ) ! 376: memcpy ( stats, &stats_buf, *stats_len ); ! 377: ! 378: /* Reset statistics if requested to do so */ ! 379: if ( reset ) { ! 380: memset ( &snpdev->netdev->tx_stats, 0, ! 381: sizeof ( snpdev->netdev->tx_stats ) ); ! 382: memset ( &snpdev->netdev->rx_stats, 0, ! 383: sizeof ( snpdev->netdev->rx_stats ) ); ! 384: } ! 385: ! 386: return 0; ! 387: } ! 388: ! 389: /** ! 390: * Convert multicast IP address to MAC address ! 391: * ! 392: * @v snp SNP interface ! 393: * @v ipv6 Address is IPv6 ! 394: * @v ip IP address ! 395: * @v mac MAC address ! 396: * @ret efirc EFI status code ! 397: */ ! 398: static EFI_STATUS EFIAPI ! 399: efi_snp_mcast_ip_to_mac ( EFI_SIMPLE_NETWORK_PROTOCOL *snp, BOOLEAN ipv6, ! 400: EFI_IP_ADDRESS *ip, EFI_MAC_ADDRESS *mac ) { ! 401: struct efi_snp_device *snpdev = ! 402: container_of ( snp, struct efi_snp_device, snp ); ! 403: struct ll_protocol *ll_protocol = snpdev->netdev->ll_protocol; ! 404: const char *ip_str; ! 405: int rc; ! 406: ! 407: ip_str = ( ipv6 ? "(IPv6)" /* FIXME when we have inet6_ntoa() */ : ! 408: inet_ntoa ( *( ( struct in_addr * ) ip ) ) ); ! 409: DBGC2 ( snpdev, "SNPDEV %p MCAST_IP_TO_MAC %s\n", snpdev, ip_str ); ! 410: ! 411: /* Try to hash the address */ ! 412: if ( ( rc = ll_protocol->mc_hash ( ( ipv6 ? AF_INET6 : AF_INET ), ! 413: ip, mac ) ) != 0 ) { ! 414: DBGC ( snpdev, "SNPDEV %p could not hash %s: %s\n", ! 415: snpdev, ip_str, strerror ( rc ) ); ! 416: return RC_TO_EFIRC ( rc ); ! 417: } ! 418: ! 419: return 0; ! 420: } ! 421: ! 422: /** ! 423: * Read or write non-volatile storage ! 424: * ! 425: * @v snp SNP interface ! 426: * @v read Operation is a read ! 427: * @v offset Starting offset within NVRAM ! 428: * @v len Length of data buffer ! 429: * @v data Data buffer ! 430: * @ret efirc EFI status code ! 431: */ ! 432: static EFI_STATUS EFIAPI ! 433: efi_snp_nvdata ( EFI_SIMPLE_NETWORK_PROTOCOL *snp, BOOLEAN read, ! 434: UINTN offset, UINTN len, VOID *data ) { ! 435: struct efi_snp_device *snpdev = ! 436: container_of ( snp, struct efi_snp_device, snp ); ! 437: ! 438: DBGC2 ( snpdev, "SNPDEV %p NVDATA %s %lx+%lx\n", snpdev, ! 439: ( read ? "read" : "write" ), ( ( unsigned long ) offset ), ! 440: ( ( unsigned long ) len ) ); ! 441: if ( ! read ) ! 442: DBGC2_HDA ( snpdev, offset, data, len ); ! 443: ! 444: return EFI_UNSUPPORTED; ! 445: } ! 446: ! 447: /** ! 448: * Read interrupt status and TX recycled buffer status ! 449: * ! 450: * @v snp SNP interface ! 451: * @v interrupts Interrupt status, or NULL ! 452: * @v txbufs Recycled transmit buffer address, or NULL ! 453: * @ret efirc EFI status code ! 454: */ ! 455: static EFI_STATUS EFIAPI ! 456: efi_snp_get_status ( EFI_SIMPLE_NETWORK_PROTOCOL *snp, ! 457: UINT32 *interrupts, VOID **txbufs ) { ! 458: struct efi_snp_device *snpdev = ! 459: container_of ( snp, struct efi_snp_device, snp ); ! 460: ! 461: DBGC2 ( snpdev, "SNPDEV %p GET_STATUS", snpdev ); ! 462: ! 463: /* Poll the network device */ ! 464: efi_snp_poll ( snpdev ); ! 465: ! 466: /* Interrupt status. In practice, this seems to be used only ! 467: * to detect TX completions. ! 468: */ ! 469: if ( interrupts ) { ! 470: *interrupts = 0; ! 471: /* Report TX completions once queue is empty; this ! 472: * avoids having to add hooks in the net device layer. ! 473: */ ! 474: if ( snpdev->tx_count_interrupts && ! 475: list_empty ( &snpdev->netdev->tx_queue ) ) { ! 476: *interrupts |= EFI_SIMPLE_NETWORK_TRANSMIT_INTERRUPT; ! 477: snpdev->tx_count_interrupts--; ! 478: } ! 479: /* Report RX */ ! 480: if ( snpdev->rx_count_interrupts ) { ! 481: *interrupts |= EFI_SIMPLE_NETWORK_RECEIVE_INTERRUPT; ! 482: snpdev->rx_count_interrupts--; ! 483: } ! 484: DBGC2 ( snpdev, " INTS:%02x", *interrupts ); ! 485: } ! 486: ! 487: /* TX completions. It would be possible to design a more ! 488: * idiotic scheme for this, but it would be a challenge. ! 489: * According to the UEFI header file, txbufs will be filled in ! 490: * with a list of "recycled transmit buffers" (i.e. completed ! 491: * TX buffers). Observant readers may care to note that ! 492: * *txbufs is a void pointer. Precisely how a list of ! 493: * completed transmit buffers is meant to be represented as an ! 494: * array of voids is left as an exercise for the reader. ! 495: * ! 496: * The only users of this interface (MnpDxe/MnpIo.c and ! 497: * PxeBcDxe/Bc.c within the EFI dev kit) both just poll until ! 498: * seeing a non-NULL result return in txbufs. This is valid ! 499: * provided that they do not ever attempt to transmit more ! 500: * than one packet concurrently (and that TX never times out). ! 501: */ ! 502: if ( txbufs ) { ! 503: if ( snpdev->tx_count_txbufs && ! 504: list_empty ( &snpdev->netdev->tx_queue ) ) { ! 505: *txbufs = "Which idiot designed this API?"; ! 506: snpdev->tx_count_txbufs--; ! 507: } else { ! 508: *txbufs = NULL; ! 509: } ! 510: DBGC2 ( snpdev, " TX:%s", ( *txbufs ? "some" : "none" ) ); ! 511: } ! 512: ! 513: DBGC2 ( snpdev, "\n" ); ! 514: return 0; ! 515: } ! 516: ! 517: /** ! 518: * Start packet transmission ! 519: * ! 520: * @v snp SNP interface ! 521: * @v ll_header_len Link-layer header length, if to be filled in ! 522: * @v len Length of data buffer ! 523: * @v data Data buffer ! 524: * @v ll_src Link-layer source address, if specified ! 525: * @v ll_dest Link-layer destination address, if specified ! 526: * @v net_proto Network-layer protocol (in host order) ! 527: * @ret efirc EFI status code ! 528: */ ! 529: static EFI_STATUS EFIAPI ! 530: efi_snp_transmit ( EFI_SIMPLE_NETWORK_PROTOCOL *snp, ! 531: UINTN ll_header_len, UINTN len, VOID *data, ! 532: EFI_MAC_ADDRESS *ll_src, EFI_MAC_ADDRESS *ll_dest, ! 533: UINT16 *net_proto ) { ! 534: struct efi_snp_device *snpdev = ! 535: container_of ( snp, struct efi_snp_device, snp ); ! 536: struct ll_protocol *ll_protocol = snpdev->netdev->ll_protocol; ! 537: struct io_buffer *iobuf; ! 538: size_t ll_headroom; ! 539: int rc; ! 540: EFI_STATUS efirc; ! 541: ! 542: DBGC2 ( snpdev, "SNPDEV %p TRANSMIT %p+%lx", snpdev, data, ! 543: ( ( unsigned long ) len ) ); ! 544: if ( ll_header_len ) { ! 545: if ( ll_src ) { ! 546: DBGC2 ( snpdev, " src %s", ! 547: ll_protocol->ntoa ( ll_src ) ); ! 548: } ! 549: if ( ll_dest ) { ! 550: DBGC2 ( snpdev, " dest %s", ! 551: ll_protocol->ntoa ( ll_dest ) ); ! 552: } ! 553: if ( net_proto ) { ! 554: DBGC2 ( snpdev, " proto %04x", *net_proto ); ! 555: } ! 556: } ! 557: DBGC2 ( snpdev, "\n" ); ! 558: ! 559: /* Sanity checks */ ! 560: if ( ll_header_len ) { ! 561: if ( ll_header_len != ll_protocol->ll_header_len ) { ! 562: DBGC ( snpdev, "SNPDEV %p TX invalid header length " ! 563: "%ld\n", snpdev, ! 564: ( ( unsigned long ) ll_header_len ) ); ! 565: efirc = EFI_INVALID_PARAMETER; ! 566: goto err_sanity; ! 567: } ! 568: if ( len < ll_header_len ) { ! 569: DBGC ( snpdev, "SNPDEV %p invalid packet length %ld\n", ! 570: snpdev, ( ( unsigned long ) len ) ); ! 571: efirc = EFI_BUFFER_TOO_SMALL; ! 572: goto err_sanity; ! 573: } ! 574: if ( ! ll_dest ) { ! 575: DBGC ( snpdev, "SNPDEV %p TX missing destination " ! 576: "address\n", snpdev ); ! 577: efirc = EFI_INVALID_PARAMETER; ! 578: goto err_sanity; ! 579: } ! 580: if ( ! net_proto ) { ! 581: DBGC ( snpdev, "SNPDEV %p TX missing network " ! 582: "protocol\n", snpdev ); ! 583: efirc = EFI_INVALID_PARAMETER; ! 584: goto err_sanity; ! 585: } ! 586: if ( ! ll_src ) ! 587: ll_src = &snpdev->mode.CurrentAddress; ! 588: } ! 589: ! 590: /* Allocate buffer */ ! 591: ll_headroom = ( MAX_LL_HEADER_LEN - ll_header_len ); ! 592: iobuf = alloc_iob ( ll_headroom + len ); ! 593: if ( ! iobuf ) { ! 594: DBGC ( snpdev, "SNPDEV %p TX could not allocate %ld-byte " ! 595: "buffer\n", snpdev, ( ( unsigned long ) len ) ); ! 596: efirc = EFI_DEVICE_ERROR; ! 597: goto err_alloc_iob; ! 598: } ! 599: iob_reserve ( iobuf, ll_headroom ); ! 600: memcpy ( iob_put ( iobuf, len ), data, len ); ! 601: ! 602: /* Create link-layer header, if specified */ ! 603: if ( ll_header_len ) { ! 604: iob_pull ( iobuf, ll_header_len ); ! 605: if ( ( rc = ll_protocol->push ( snpdev->netdev, ! 606: iobuf, ll_dest, ll_src, ! 607: htons ( *net_proto ) )) != 0 ){ ! 608: DBGC ( snpdev, "SNPDEV %p TX could not construct " ! 609: "header: %s\n", snpdev, strerror ( rc ) ); ! 610: efirc = RC_TO_EFIRC ( rc ); ! 611: goto err_ll_push; ! 612: } ! 613: } ! 614: ! 615: /* Transmit packet */ ! 616: if ( ( rc = netdev_tx ( snpdev->netdev, iob_disown ( iobuf ) ) ) != 0){ ! 617: DBGC ( snpdev, "SNPDEV %p TX could not transmit: %s\n", ! 618: snpdev, strerror ( rc ) ); ! 619: efirc = RC_TO_EFIRC ( rc ); ! 620: goto err_tx; ! 621: } ! 622: ! 623: /* Record transmission as outstanding */ ! 624: snpdev->tx_count_interrupts++; ! 625: snpdev->tx_count_txbufs++; ! 626: ! 627: return 0; ! 628: ! 629: err_tx: ! 630: err_ll_push: ! 631: free_iob ( iobuf ); ! 632: err_alloc_iob: ! 633: err_sanity: ! 634: return efirc; ! 635: } ! 636: ! 637: /** ! 638: * Receive packet ! 639: * ! 640: * @v snp SNP interface ! 641: * @v ll_header_len Link-layer header length, if to be filled in ! 642: * @v len Length of data buffer ! 643: * @v data Data buffer ! 644: * @v ll_src Link-layer source address, if specified ! 645: * @v ll_dest Link-layer destination address, if specified ! 646: * @v net_proto Network-layer protocol (in host order) ! 647: * @ret efirc EFI status code ! 648: */ ! 649: static EFI_STATUS EFIAPI ! 650: efi_snp_receive ( EFI_SIMPLE_NETWORK_PROTOCOL *snp, ! 651: UINTN *ll_header_len, UINTN *len, VOID *data, ! 652: EFI_MAC_ADDRESS *ll_src, EFI_MAC_ADDRESS *ll_dest, ! 653: UINT16 *net_proto ) { ! 654: struct efi_snp_device *snpdev = ! 655: container_of ( snp, struct efi_snp_device, snp ); ! 656: struct ll_protocol *ll_protocol = snpdev->netdev->ll_protocol; ! 657: struct io_buffer *iobuf; ! 658: const void *iob_ll_dest; ! 659: const void *iob_ll_src; ! 660: uint16_t iob_net_proto; ! 661: int rc; ! 662: EFI_STATUS efirc; ! 663: ! 664: DBGC2 ( snpdev, "SNPDEV %p RECEIVE %p(+%lx)", snpdev, data, ! 665: ( ( unsigned long ) *len ) ); ! 666: ! 667: /* Poll the network device */ ! 668: efi_snp_poll ( snpdev ); ! 669: ! 670: /* Dequeue a packet, if one is available */ ! 671: iobuf = netdev_rx_dequeue ( snpdev->netdev ); ! 672: if ( ! iobuf ) { ! 673: DBGC2 ( snpdev, "\n" ); ! 674: efirc = EFI_NOT_READY; ! 675: goto out_no_packet; ! 676: } ! 677: DBGC2 ( snpdev, "+%zx\n", iob_len ( iobuf ) ); ! 678: ! 679: /* Return packet to caller */ ! 680: memcpy ( data, iobuf->data, iob_len ( iobuf ) ); ! 681: *len = iob_len ( iobuf ); ! 682: ! 683: /* Attempt to decode link-layer header */ ! 684: if ( ( rc = ll_protocol->pull ( snpdev->netdev, iobuf, &iob_ll_dest, ! 685: &iob_ll_src, &iob_net_proto ) ) != 0 ){ ! 686: DBGC ( snpdev, "SNPDEV %p could not parse header: %s\n", ! 687: snpdev, strerror ( rc ) ); ! 688: efirc = RC_TO_EFIRC ( rc ); ! 689: goto out_bad_ll_header; ! 690: } ! 691: ! 692: /* Return link-layer header parameters to caller, if required */ ! 693: if ( ll_header_len ) ! 694: *ll_header_len = ll_protocol->ll_header_len; ! 695: if ( ll_src ) ! 696: memcpy ( ll_src, iob_ll_src, ll_protocol->ll_addr_len ); ! 697: if ( ll_dest ) ! 698: memcpy ( ll_dest, iob_ll_dest, ll_protocol->ll_addr_len ); ! 699: if ( net_proto ) ! 700: *net_proto = ntohs ( iob_net_proto ); ! 701: ! 702: efirc = 0; ! 703: ! 704: out_bad_ll_header: ! 705: free_iob ( iobuf ); ! 706: out_no_packet: ! 707: return efirc; ! 708: } ! 709: ! 710: /** ! 711: * Poll event ! 712: * ! 713: * @v event Event ! 714: * @v context Event context ! 715: */ ! 716: static VOID EFIAPI efi_snp_wait_for_packet ( EFI_EVENT event, ! 717: VOID *context ) { ! 718: EFI_BOOT_SERVICES *bs = efi_systab->BootServices; ! 719: struct efi_snp_device *snpdev = context; ! 720: ! 721: DBGCP ( snpdev, "SNPDEV %p WAIT_FOR_PACKET\n", snpdev ); ! 722: ! 723: /* Do nothing unless the net device is open */ ! 724: if ( ! netdev_is_open ( snpdev->netdev ) ) ! 725: return; ! 726: ! 727: /* Poll the network device */ ! 728: efi_snp_poll ( snpdev ); ! 729: ! 730: /* Fire event if packets have been received */ ! 731: if ( snpdev->rx_count_events != 0 ) { ! 732: DBGC2 ( snpdev, "SNPDEV %p firing WaitForPacket event\n", ! 733: snpdev ); ! 734: bs->SignalEvent ( event ); ! 735: snpdev->rx_count_events--; ! 736: } ! 737: } ! 738: ! 739: /** SNP interface */ ! 740: static EFI_SIMPLE_NETWORK_PROTOCOL efi_snp_device_snp = { ! 741: .Revision = EFI_SIMPLE_NETWORK_PROTOCOL_REVISION, ! 742: .Start = efi_snp_start, ! 743: .Stop = efi_snp_stop, ! 744: .Initialize = efi_snp_initialize, ! 745: .Reset = efi_snp_reset, ! 746: .Shutdown = efi_snp_shutdown, ! 747: .ReceiveFilters = efi_snp_receive_filters, ! 748: .StationAddress = efi_snp_station_address, ! 749: .Statistics = efi_snp_statistics, ! 750: .MCastIpToMac = efi_snp_mcast_ip_to_mac, ! 751: .NvData = efi_snp_nvdata, ! 752: .GetStatus = efi_snp_get_status, ! 753: .Transmit = efi_snp_transmit, ! 754: .Receive = efi_snp_receive, ! 755: }; ! 756: ! 757: /****************************************************************************** ! 758: * ! 759: * Human Interface Infrastructure ! 760: * ! 761: ****************************************************************************** ! 762: */ ! 763: ! 764: /** EFI configuration access protocol GUID */ ! 765: static EFI_GUID efi_hii_config_access_protocol_guid ! 766: = EFI_HII_CONFIG_ACCESS_PROTOCOL_GUID; ! 767: ! 768: /** EFI HII database protocol */ ! 769: static EFI_HII_DATABASE_PROTOCOL *efihii; ! 770: EFI_REQUIRE_PROTOCOL ( EFI_HII_DATABASE_PROTOCOL, &efihii ); ! 771: ! 772: /** Local GUID used for our EFI SNP formset */ ! 773: #define EFI_SNP_FORMSET_GUID \ ! 774: { 0xc4f84019, 0x6dfd, 0x4a27, \ ! 775: { 0x9b, 0x94, 0xb7, 0x2e, 0x1f, 0xbc, 0xad, 0xca } } ! 776: ! 777: /** Form identifiers used for our EFI SNP HII */ ! 778: enum efi_snp_hii_form_id { ! 779: EFI_SNP_FORM = 0x0001, /**< The only form */ ! 780: }; ! 781: ! 782: /** String identifiers used for our EFI SNP HII */ ! 783: enum efi_snp_hii_string_id { ! 784: /* Language name */ ! 785: EFI_SNP_LANGUAGE_NAME = 0x0001, ! 786: /* Formset */ ! 787: EFI_SNP_FORMSET_TITLE, EFI_SNP_FORMSET_HELP, ! 788: /* Product name */ ! 789: EFI_SNP_PRODUCT_PROMPT, EFI_SNP_PRODUCT_HELP, EFI_SNP_PRODUCT_TEXT, ! 790: /* Version */ ! 791: EFI_SNP_VERSION_PROMPT, EFI_SNP_VERSION_HELP, EFI_SNP_VERSION_TEXT, ! 792: /* Driver */ ! 793: EFI_SNP_DRIVER_PROMPT, EFI_SNP_DRIVER_HELP, EFI_SNP_DRIVER_TEXT, ! 794: /* Device */ ! 795: EFI_SNP_DEVICE_PROMPT, EFI_SNP_DEVICE_HELP, EFI_SNP_DEVICE_TEXT, ! 796: /* End of list */ ! 797: EFI_SNP_MAX_STRING_ID ! 798: }; ! 799: ! 800: /** EFI SNP formset */ ! 801: struct efi_snp_formset { ! 802: EFI_HII_PACKAGE_HEADER Header; ! 803: EFI_IFR_FORM_SET_TYPE(1) FormSet; ! 804: EFI_IFR_GUID_CLASS Class; ! 805: EFI_IFR_GUID_SUBCLASS SubClass; ! 806: EFI_IFR_FORM Form; ! 807: EFI_IFR_TEXT ProductText; ! 808: EFI_IFR_TEXT VersionText; ! 809: EFI_IFR_TEXT DriverText; ! 810: EFI_IFR_TEXT DeviceText; ! 811: EFI_IFR_END EndForm; ! 812: EFI_IFR_END EndFormSet; ! 813: } __attribute__ (( packed )) efi_snp_formset = { ! 814: .Header = { ! 815: .Length = sizeof ( efi_snp_formset ), ! 816: .Type = EFI_HII_PACKAGE_FORMS, ! 817: }, ! 818: .FormSet = EFI_IFR_FORM_SET ( EFI_SNP_FORMSET_GUID, ! 819: EFI_SNP_FORMSET_TITLE, ! 820: EFI_SNP_FORMSET_HELP, ! 821: typeof ( efi_snp_formset.FormSet ), ! 822: EFI_HII_PLATFORM_SETUP_FORMSET_GUID ), ! 823: .Class = EFI_IFR_GUID_CLASS ( EFI_NETWORK_DEVICE_CLASS ), ! 824: .SubClass = EFI_IFR_GUID_SUBCLASS ( 0x03 ), ! 825: .Form = EFI_IFR_FORM ( EFI_SNP_FORM, EFI_SNP_FORMSET_TITLE ), ! 826: .ProductText = EFI_IFR_TEXT ( EFI_SNP_PRODUCT_PROMPT, ! 827: EFI_SNP_PRODUCT_HELP, ! 828: EFI_SNP_PRODUCT_TEXT ), ! 829: .VersionText = EFI_IFR_TEXT ( EFI_SNP_VERSION_PROMPT, ! 830: EFI_SNP_VERSION_HELP, ! 831: EFI_SNP_VERSION_TEXT ), ! 832: .DriverText = EFI_IFR_TEXT ( EFI_SNP_DRIVER_PROMPT, ! 833: EFI_SNP_DRIVER_HELP, ! 834: EFI_SNP_DRIVER_TEXT ), ! 835: .DeviceText = EFI_IFR_TEXT ( EFI_SNP_DEVICE_PROMPT, ! 836: EFI_SNP_DEVICE_HELP, ! 837: EFI_SNP_DEVICE_TEXT ), ! 838: .EndForm = EFI_IFR_END(), ! 839: .EndFormSet = EFI_IFR_END(), ! 840: }; ! 841: ! 842: /** ! 843: * Generate EFI SNP string ! 844: * ! 845: * @v wbuf Buffer ! 846: * @v swlen Size of buffer (in wide characters) ! 847: * @v snpdev SNP device ! 848: * @ret wlen Length of string (in wide characters) ! 849: */ ! 850: static int efi_snp_string ( wchar_t *wbuf, ssize_t swlen, ! 851: enum efi_snp_hii_string_id id, ! 852: struct efi_snp_device *snpdev ) { ! 853: struct net_device *netdev = snpdev->netdev; ! 854: struct device *dev = netdev->dev; ! 855: ! 856: switch ( id ) { ! 857: case EFI_SNP_LANGUAGE_NAME: ! 858: return efi_ssnprintf ( wbuf, swlen, "English" ); ! 859: case EFI_SNP_FORMSET_TITLE: ! 860: return efi_ssnprintf ( wbuf, swlen, "%s (%s)", ! 861: ( PRODUCT_NAME[0] ? ! 862: PRODUCT_NAME : PRODUCT_SHORT_NAME ), ! 863: netdev_addr ( netdev ) ); ! 864: case EFI_SNP_FORMSET_HELP: ! 865: return efi_ssnprintf ( wbuf, swlen, ! 866: "Configure " PRODUCT_SHORT_NAME ); ! 867: case EFI_SNP_PRODUCT_PROMPT: ! 868: return efi_ssnprintf ( wbuf, swlen, "Name" ); ! 869: case EFI_SNP_PRODUCT_HELP: ! 870: return efi_ssnprintf ( wbuf, swlen, "Firmware product name" ); ! 871: case EFI_SNP_PRODUCT_TEXT: ! 872: return efi_ssnprintf ( wbuf, swlen, "%s", ! 873: ( PRODUCT_NAME[0] ? ! 874: PRODUCT_NAME : PRODUCT_SHORT_NAME ) ); ! 875: case EFI_SNP_VERSION_PROMPT: ! 876: return efi_ssnprintf ( wbuf, swlen, "Version" ); ! 877: case EFI_SNP_VERSION_HELP: ! 878: return efi_ssnprintf ( wbuf, swlen, "Firmware version" ); ! 879: case EFI_SNP_VERSION_TEXT: ! 880: return efi_ssnprintf ( wbuf, swlen, VERSION ); ! 881: case EFI_SNP_DRIVER_PROMPT: ! 882: return efi_ssnprintf ( wbuf, swlen, "Driver" ); ! 883: case EFI_SNP_DRIVER_HELP: ! 884: return efi_ssnprintf ( wbuf, swlen, "Firmware driver" ); ! 885: case EFI_SNP_DRIVER_TEXT: ! 886: return efi_ssnprintf ( wbuf, swlen, "%s", dev->driver_name ); ! 887: case EFI_SNP_DEVICE_PROMPT: ! 888: return efi_ssnprintf ( wbuf, swlen, "Device" ); ! 889: case EFI_SNP_DEVICE_HELP: ! 890: return efi_ssnprintf ( wbuf, swlen, "Hardware device" ); ! 891: case EFI_SNP_DEVICE_TEXT: ! 892: return efi_ssnprintf ( wbuf, swlen, "%s", dev->name ); ! 893: default: ! 894: assert ( 0 ); ! 895: return 0; ! 896: } ! 897: } ! 898: ! 899: /** ! 900: * Generate EFI SNP string package ! 901: * ! 902: * @v strings String package header buffer ! 903: * @v max_len Buffer length ! 904: * @v snpdev SNP device ! 905: * @ret len Length of string package ! 906: */ ! 907: static int efi_snp_strings ( EFI_HII_STRING_PACKAGE_HDR *strings, ! 908: size_t max_len, struct efi_snp_device *snpdev ) { ! 909: static const char language[] = "en-us"; ! 910: void *buf = strings; ! 911: ssize_t remaining = max_len; ! 912: size_t hdrsize; ! 913: EFI_HII_SIBT_STRING_UCS2_BLOCK *string; ! 914: ssize_t wremaining; ! 915: size_t string_wlen; ! 916: unsigned int id; ! 917: EFI_HII_STRING_BLOCK *end; ! 918: size_t len; ! 919: ! 920: /* Calculate header size */ ! 921: hdrsize = ( offsetof ( typeof ( *strings ), Language ) + ! 922: sizeof ( language ) ); ! 923: buf += hdrsize; ! 924: remaining -= hdrsize; ! 925: ! 926: /* Fill in strings */ ! 927: for ( id = 1 ; id < EFI_SNP_MAX_STRING_ID ; id++ ) { ! 928: string = buf; ! 929: if ( remaining >= ( ( ssize_t ) sizeof ( string->Header ) ) ) ! 930: string->Header.BlockType = EFI_HII_SIBT_STRING_UCS2; ! 931: buf += offsetof ( typeof ( *string ), StringText ); ! 932: remaining -= offsetof ( typeof ( *string ), StringText ); ! 933: wremaining = ( remaining / ! 934: ( ( ssize_t ) sizeof ( string->StringText[0] ))); ! 935: assert ( ! ( ( remaining <= 0 ) && ( wremaining > 0 ) ) ); ! 936: string_wlen = efi_snp_string ( string->StringText, wremaining, ! 937: id, snpdev ); ! 938: buf += ( ( string_wlen + 1 /* wNUL */ ) * ! 939: sizeof ( string->StringText[0] ) ); ! 940: remaining -= ( ( string_wlen + 1 /* wNUL */ ) * ! 941: sizeof ( string->StringText[0] ) ); ! 942: } ! 943: ! 944: /* Fill in end marker */ ! 945: end = buf; ! 946: if ( remaining >= ( ( ssize_t ) sizeof ( *end ) ) ) ! 947: end->BlockType = EFI_HII_SIBT_END; ! 948: buf += sizeof ( *end ); ! 949: remaining -= sizeof ( *end ); ! 950: ! 951: /* Calculate overall length */ ! 952: len = ( max_len - remaining ); ! 953: ! 954: /* Fill in string package header */ ! 955: if ( strings ) { ! 956: memset ( strings, 0, sizeof ( *strings ) ); ! 957: strings->Header.Length = len; ! 958: strings->Header.Type = EFI_HII_PACKAGE_STRINGS; ! 959: strings->HdrSize = hdrsize; ! 960: strings->StringInfoOffset = hdrsize; ! 961: strings->LanguageName = EFI_SNP_LANGUAGE_NAME; ! 962: memcpy ( strings->Language, language, sizeof ( language ) ); ! 963: } ! 964: ! 965: return len; ! 966: } ! 967: ! 968: /** ! 969: * Generate EFI SNP package list ! 970: * ! 971: * @v snpdev SNP device ! 972: * @ret package_list Package list, or NULL on error ! 973: * ! 974: * The package list is allocated using malloc(), and must eventually ! 975: * be freed by the caller. ! 976: */ ! 977: static EFI_HII_PACKAGE_LIST_HEADER * ! 978: efi_snp_package_list ( struct efi_snp_device *snpdev ) { ! 979: size_t strings_len = efi_snp_strings ( NULL, 0, snpdev ); ! 980: struct { ! 981: EFI_HII_PACKAGE_LIST_HEADER header; ! 982: struct efi_snp_formset formset; ! 983: union { ! 984: EFI_HII_STRING_PACKAGE_HDR strings; ! 985: uint8_t pad[strings_len]; ! 986: } __attribute__ (( packed )) strings; ! 987: EFI_HII_PACKAGE_HEADER end; ! 988: } __attribute__ (( packed )) *package_list; ! 989: ! 990: /* Allocate package list */ ! 991: package_list = zalloc ( sizeof ( *package_list ) ); ! 992: if ( ! package_list ) ! 993: return NULL; ! 994: ! 995: /* Populate package list */ ! 996: memcpy ( &package_list->header.PackageListGuid, ! 997: &efi_snp_formset.FormSet.FormSet.Guid, ! 998: sizeof ( package_list->header.PackageListGuid ) ); ! 999: package_list->header.PackageLength = sizeof ( *package_list ); ! 1000: memcpy ( &package_list->formset, &efi_snp_formset, ! 1001: sizeof ( package_list->formset ) ); ! 1002: efi_snp_strings ( &package_list->strings.strings, ! 1003: sizeof ( package_list->strings ), snpdev ); ! 1004: package_list->end.Length = sizeof ( package_list->end ); ! 1005: package_list->end.Type = EFI_HII_PACKAGE_END; ! 1006: ! 1007: return &package_list->header; ! 1008: } ! 1009: ! 1010: /** ! 1011: * Fetch configuration ! 1012: * ! 1013: * @v hii HII configuration access protocol ! 1014: * @v request Configuration to fetch ! 1015: * @ret progress Progress made through configuration to fetch ! 1016: * @ret results Query results ! 1017: * @ret efirc EFI status code ! 1018: */ ! 1019: static EFI_STATUS EFIAPI ! 1020: efi_snp_hii_extract_config ( const EFI_HII_CONFIG_ACCESS_PROTOCOL *hii, ! 1021: EFI_STRING request, EFI_STRING *progress, ! 1022: EFI_STRING *results __unused ) { ! 1023: struct efi_snp_device *snpdev = ! 1024: container_of ( hii, struct efi_snp_device, hii ); ! 1025: ! 1026: DBGC ( snpdev, "SNPDEV %p ExtractConfig\n", snpdev ); ! 1027: ! 1028: *progress = request; ! 1029: return EFI_INVALID_PARAMETER; ! 1030: } ! 1031: ! 1032: /** ! 1033: * Store configuration ! 1034: * ! 1035: * @v hii HII configuration access protocol ! 1036: * @v config Configuration to store ! 1037: * @ret progress Progress made through configuration to store ! 1038: * @ret efirc EFI status code ! 1039: */ ! 1040: static EFI_STATUS EFIAPI ! 1041: efi_snp_hii_route_config ( const EFI_HII_CONFIG_ACCESS_PROTOCOL *hii, ! 1042: EFI_STRING config, EFI_STRING *progress ) { ! 1043: struct efi_snp_device *snpdev = ! 1044: container_of ( hii, struct efi_snp_device, hii ); ! 1045: ! 1046: DBGC ( snpdev, "SNPDEV %p RouteConfig\n", snpdev ); ! 1047: ! 1048: *progress = config; ! 1049: return EFI_INVALID_PARAMETER; ! 1050: } ! 1051: ! 1052: /** ! 1053: * Handle form actions ! 1054: * ! 1055: * @v hii HII configuration access protocol ! 1056: * @v action Form browser action ! 1057: * @v question_id Question ID ! 1058: * @v type Type of value ! 1059: * @v value Value ! 1060: * @ret action_request Action requested by driver ! 1061: * @ret efirc EFI status code ! 1062: */ ! 1063: static EFI_STATUS EFIAPI ! 1064: efi_snp_hii_callback ( const EFI_HII_CONFIG_ACCESS_PROTOCOL *hii, ! 1065: EFI_BROWSER_ACTION action __unused, ! 1066: EFI_QUESTION_ID question_id __unused, ! 1067: UINT8 type __unused, EFI_IFR_TYPE_VALUE *value __unused, ! 1068: EFI_BROWSER_ACTION_REQUEST *action_request __unused ) { ! 1069: struct efi_snp_device *snpdev = ! 1070: container_of ( hii, struct efi_snp_device, hii ); ! 1071: ! 1072: DBGC ( snpdev, "SNPDEV %p Callback\n", snpdev ); ! 1073: return EFI_UNSUPPORTED; ! 1074: } ! 1075: ! 1076: /** HII configuration access protocol */ ! 1077: static EFI_HII_CONFIG_ACCESS_PROTOCOL efi_snp_device_hii = { ! 1078: .ExtractConfig = efi_snp_hii_extract_config, ! 1079: .RouteConfig = efi_snp_hii_route_config, ! 1080: .Callback = efi_snp_hii_callback, ! 1081: }; ! 1082: ! 1083: /****************************************************************************** ! 1084: * ! 1085: * iPXE network driver ! 1086: * ! 1087: ****************************************************************************** ! 1088: */ ! 1089: ! 1090: /** ! 1091: * Locate SNP device corresponding to network device ! 1092: * ! 1093: * @v netdev Network device ! 1094: * @ret snp SNP device, or NULL if not found ! 1095: */ ! 1096: static struct efi_snp_device * efi_snp_demux ( struct net_device *netdev ) { ! 1097: struct efi_snp_device *snpdev; ! 1098: ! 1099: list_for_each_entry ( snpdev, &efi_snp_devices, list ) { ! 1100: if ( snpdev->netdev == netdev ) ! 1101: return snpdev; ! 1102: } ! 1103: return NULL; ! 1104: } ! 1105: ! 1106: /** ! 1107: * Create SNP device ! 1108: * ! 1109: * @v netdev Network device ! 1110: * @ret rc Return status code ! 1111: */ ! 1112: static int efi_snp_probe ( struct net_device *netdev ) { ! 1113: EFI_BOOT_SERVICES *bs = efi_systab->BootServices; ! 1114: struct efi_pci_device *efipci; ! 1115: struct efi_snp_device *snpdev; ! 1116: EFI_DEVICE_PATH_PROTOCOL *path_end; ! 1117: MAC_ADDR_DEVICE_PATH *macpath; ! 1118: size_t path_prefix_len = 0; ! 1119: EFI_STATUS efirc; ! 1120: int rc; ! 1121: ! 1122: /* Find EFI PCI device */ ! 1123: efipci = efipci_find ( netdev->dev ); ! 1124: if ( ! efipci ) { ! 1125: DBG ( "SNP skipping non-PCI device %s\n", netdev->name ); ! 1126: rc = 0; ! 1127: goto err_no_pci; ! 1128: } ! 1129: ! 1130: /* Calculate device path prefix length */ ! 1131: path_end = efi_devpath_end ( efipci->path ); ! 1132: path_prefix_len = ( ( ( void * ) path_end ) - ! 1133: ( ( void * ) efipci->path ) ); ! 1134: ! 1135: /* Allocate the SNP device */ ! 1136: snpdev = zalloc ( sizeof ( *snpdev ) + path_prefix_len + ! 1137: sizeof ( *macpath ) ); ! 1138: if ( ! snpdev ) { ! 1139: rc = -ENOMEM; ! 1140: goto err_alloc_snp; ! 1141: } ! 1142: snpdev->netdev = netdev_get ( netdev ); ! 1143: snpdev->efipci = efipci; ! 1144: ! 1145: /* Sanity check */ ! 1146: if ( netdev->ll_protocol->ll_addr_len > sizeof ( EFI_MAC_ADDRESS ) ) { ! 1147: DBGC ( snpdev, "SNPDEV %p cannot support link-layer address " ! 1148: "length %d for %s\n", snpdev, ! 1149: netdev->ll_protocol->ll_addr_len, netdev->name ); ! 1150: rc = -ENOTSUP; ! 1151: goto err_ll_addr_len; ! 1152: } ! 1153: ! 1154: /* Populate the SNP structure */ ! 1155: memcpy ( &snpdev->snp, &efi_snp_device_snp, sizeof ( snpdev->snp ) ); ! 1156: snpdev->snp.Mode = &snpdev->mode; ! 1157: if ( ( efirc = bs->CreateEvent ( EVT_NOTIFY_WAIT, TPL_NOTIFY, ! 1158: efi_snp_wait_for_packet, snpdev, ! 1159: &snpdev->snp.WaitForPacket ) ) != 0 ){ ! 1160: DBGC ( snpdev, "SNPDEV %p could not create event: %s\n", ! 1161: snpdev, efi_strerror ( efirc ) ); ! 1162: rc = EFIRC_TO_RC ( efirc ); ! 1163: goto err_create_event; ! 1164: } ! 1165: ! 1166: /* Populate the SNP mode structure */ ! 1167: snpdev->mode.State = EfiSimpleNetworkStopped; ! 1168: efi_snp_set_mode ( snpdev ); ! 1169: ! 1170: /* Populate the NII structure */ ! 1171: snpdev->nii.Revision = ! 1172: EFI_NETWORK_INTERFACE_IDENTIFIER_PROTOCOL_REVISION; ! 1173: strncpy ( snpdev->nii.StringId, "iPXE", ! 1174: sizeof ( snpdev->nii.StringId ) ); ! 1175: ! 1176: /* Populate the HII configuration access structure */ ! 1177: memcpy ( &snpdev->hii, &efi_snp_device_hii, sizeof ( snpdev->hii ) ); ! 1178: ! 1179: /* Populate the device name */ ! 1180: efi_snprintf ( snpdev->name, ( sizeof ( snpdev->name ) / ! 1181: sizeof ( snpdev->name[0] ) ), ! 1182: "%s", netdev->name ); ! 1183: ! 1184: /* Populate the device path */ ! 1185: memcpy ( &snpdev->path, efipci->path, path_prefix_len ); ! 1186: macpath = ( ( ( void * ) &snpdev->path ) + path_prefix_len ); ! 1187: path_end = ( ( void * ) ( macpath + 1 ) ); ! 1188: memset ( macpath, 0, sizeof ( *macpath ) ); ! 1189: macpath->Header.Type = MESSAGING_DEVICE_PATH; ! 1190: macpath->Header.SubType = MSG_MAC_ADDR_DP; ! 1191: macpath->Header.Length[0] = sizeof ( *macpath ); ! 1192: memcpy ( &macpath->MacAddress, netdev->ll_addr, ! 1193: sizeof ( macpath->MacAddress ) ); ! 1194: macpath->IfType = ntohs ( netdev->ll_protocol->ll_proto ); ! 1195: memset ( path_end, 0, sizeof ( *path_end ) ); ! 1196: path_end->Type = END_DEVICE_PATH_TYPE; ! 1197: path_end->SubType = END_ENTIRE_DEVICE_PATH_SUBTYPE; ! 1198: path_end->Length[0] = sizeof ( *path_end ); ! 1199: ! 1200: /* Install the SNP */ ! 1201: if ( ( efirc = bs->InstallMultipleProtocolInterfaces ( ! 1202: &snpdev->handle, ! 1203: &efi_simple_network_protocol_guid, &snpdev->snp, ! 1204: &efi_device_path_protocol_guid, &snpdev->path, ! 1205: &efi_nii_protocol_guid, &snpdev->nii, ! 1206: &efi_nii31_protocol_guid, &snpdev->nii, ! 1207: &efi_hii_config_access_protocol_guid, &snpdev->hii, ! 1208: NULL ) ) != 0 ) { ! 1209: DBGC ( snpdev, "SNPDEV %p could not install protocols: " ! 1210: "%s\n", snpdev, efi_strerror ( efirc ) ); ! 1211: rc = EFIRC_TO_RC ( efirc ); ! 1212: goto err_install_protocol_interface; ! 1213: } ! 1214: ! 1215: /* Add as child of PCI device */ ! 1216: if ( ( efirc = efipci_child_add ( efipci, snpdev->handle ) ) != 0 ) { ! 1217: DBGC ( snpdev, "SNPDEV %p could not become child of " PCI_FMT ! 1218: ": %s\n", snpdev, PCI_ARGS ( &efipci->pci ), ! 1219: efi_strerror ( efirc ) ); ! 1220: rc = EFIRC_TO_RC ( efirc ); ! 1221: goto err_efipci_child_add; ! 1222: } ! 1223: ! 1224: /* Create HII package list */ ! 1225: snpdev->package_list = efi_snp_package_list ( snpdev ); ! 1226: if ( ! snpdev->package_list ) { ! 1227: DBGC ( snpdev, "SNPDEV %p could not create HII package list\n", ! 1228: snpdev ); ! 1229: rc = -ENOMEM; ! 1230: goto err_create_hii; ! 1231: } ! 1232: ! 1233: /* Add HII packages */ ! 1234: if ( ( efirc = efihii->NewPackageList ( efihii, snpdev->package_list, ! 1235: snpdev->handle, ! 1236: &snpdev->hii_handle ) ) != 0 ) { ! 1237: DBGC ( snpdev, "SNPDEV %p could not add HII packages: %s\n", ! 1238: snpdev, efi_strerror ( efirc ) ); ! 1239: rc = EFIRC_TO_RC ( efirc ); ! 1240: goto err_register_hii; ! 1241: } ! 1242: ! 1243: /* Add to list of SNP devices */ ! 1244: list_add ( &snpdev->list, &efi_snp_devices ); ! 1245: ! 1246: DBGC ( snpdev, "SNPDEV %p installed for %s as device %p\n", ! 1247: snpdev, netdev->name, snpdev->handle ); ! 1248: return 0; ! 1249: ! 1250: efihii->RemovePackageList ( efihii, snpdev->hii_handle ); ! 1251: err_register_hii: ! 1252: free ( snpdev->package_list ); ! 1253: err_create_hii: ! 1254: efipci_child_del ( efipci, snpdev->handle ); ! 1255: err_efipci_child_add: ! 1256: bs->UninstallMultipleProtocolInterfaces ( ! 1257: snpdev->handle, ! 1258: &efi_simple_network_protocol_guid, &snpdev->snp, ! 1259: &efi_device_path_protocol_guid, &snpdev->path, ! 1260: &efi_nii_protocol_guid, &snpdev->nii, ! 1261: &efi_nii31_protocol_guid, &snpdev->nii, ! 1262: &efi_hii_config_access_protocol_guid, &snpdev->hii, ! 1263: NULL ); ! 1264: err_install_protocol_interface: ! 1265: bs->CloseEvent ( snpdev->snp.WaitForPacket ); ! 1266: err_create_event: ! 1267: err_ll_addr_len: ! 1268: netdev_put ( netdev ); ! 1269: free ( snpdev ); ! 1270: err_alloc_snp: ! 1271: err_no_pci: ! 1272: return rc; ! 1273: } ! 1274: ! 1275: /** ! 1276: * Handle SNP device or link state change ! 1277: * ! 1278: * @v netdev Network device ! 1279: */ ! 1280: static void efi_snp_notify ( struct net_device *netdev __unused ) { ! 1281: /* Nothing to do */ ! 1282: } ! 1283: ! 1284: /** ! 1285: * Destroy SNP device ! 1286: * ! 1287: * @v netdev Network device ! 1288: */ ! 1289: static void efi_snp_remove ( struct net_device *netdev ) { ! 1290: EFI_BOOT_SERVICES *bs = efi_systab->BootServices; ! 1291: struct efi_snp_device *snpdev; ! 1292: ! 1293: /* Locate SNP device */ ! 1294: snpdev = efi_snp_demux ( netdev ); ! 1295: if ( ! snpdev ) { ! 1296: DBG ( "SNP skipping non-SNP device %s\n", netdev->name ); ! 1297: return; ! 1298: } ! 1299: ! 1300: /* Uninstall the SNP */ ! 1301: efihii->RemovePackageList ( efihii, snpdev->hii_handle ); ! 1302: free ( snpdev->package_list ); ! 1303: efipci_child_del ( snpdev->efipci, snpdev->handle ); ! 1304: list_del ( &snpdev->list ); ! 1305: bs->UninstallMultipleProtocolInterfaces ( ! 1306: snpdev->handle, ! 1307: &efi_simple_network_protocol_guid, &snpdev->snp, ! 1308: &efi_device_path_protocol_guid, &snpdev->path, ! 1309: &efi_nii_protocol_guid, &snpdev->nii, ! 1310: &efi_nii31_protocol_guid, &snpdev->nii, ! 1311: &efi_hii_config_access_protocol_guid, &snpdev->hii, ! 1312: NULL ); ! 1313: bs->CloseEvent ( snpdev->snp.WaitForPacket ); ! 1314: netdev_put ( snpdev->netdev ); ! 1315: free ( snpdev ); ! 1316: } ! 1317: ! 1318: /** SNP driver */ ! 1319: struct net_driver efi_snp_driver __net_driver = { ! 1320: .name = "SNP", ! 1321: .probe = efi_snp_probe, ! 1322: .notify = efi_snp_notify, ! 1323: .remove = efi_snp_remove, ! 1324: };
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.