Annotation of qemu/roms/ipxe/src/interface/efi/efi_snp.c, revision 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.