Annotation of qemu/roms/ipxe/src/interface/efi/efi_snp.c, revision 1.1.1.1

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: };

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.