diff options
| author | Simon Rettberg | 2021-04-15 11:29:11 +0200 |
|---|---|---|
| committer | Simon Rettberg | 2021-04-15 11:29:11 +0200 |
| commit | e6589858be226fa86b109a7737b0780bf5640697 (patch) | |
| tree | ca95febb1511ad0b206fd20eb912639f3c3db14a | |
| parent | Merge branch 'master' into openslx (diff) | |
| parent | [xen] Support scatter-gather to allow for jumbo frames (diff) | |
| download | ipxe-e6589858be226fa86b109a7737b0780bf5640697.tar.gz ipxe-e6589858be226fa86b109a7737b0780bf5640697.tar.xz ipxe-e6589858be226fa86b109a7737b0780bf5640697.zip | |
Merge branch 'master' into openslx
| -rw-r--r-- | src/arch/x86/include/ipxe/pcidirect.h | 4 | ||||
| -rw-r--r-- | src/arch/x86/interface/pcbios/int13.c | 4 | ||||
| -rw-r--r-- | src/config/cloud/general.h | 5 | ||||
| -rw-r--r-- | src/drivers/bus/pci.c | 27 | ||||
| -rw-r--r-- | src/drivers/net/intelxvf.c | 1 | ||||
| -rw-r--r-- | src/drivers/net/netfront.c | 188 | ||||
| -rw-r--r-- | src/drivers/net/netfront.h | 16 | ||||
| -rw-r--r-- | src/include/ipxe/netdevice.h | 6 | ||||
| -rw-r--r-- | src/include/ipxe/pci.h | 3 | ||||
| -rw-r--r-- | src/include/ipxe/xengrant.h | 7 | ||||
| -rw-r--r-- | src/interface/linux/linux_api.c | 32 | ||||
| -rw-r--r-- | src/net/netdevice.c | 39 | ||||
| -rw-r--r-- | src/net/udp/dhcp.c | 40 | ||||
| -rw-r--r-- | src/scripts/efi.lds | 19 | ||||
| -rw-r--r-- | src/util/elf2efi.c | 37 |
15 files changed, 300 insertions, 128 deletions
diff --git a/src/arch/x86/include/ipxe/pcidirect.h b/src/arch/x86/include/ipxe/pcidirect.h index 9570fd7d6..decdc8100 100644 --- a/src/arch/x86/include/ipxe/pcidirect.h +++ b/src/arch/x86/include/ipxe/pcidirect.h @@ -32,8 +32,8 @@ extern void pcidirect_prepare ( struct pci_device *pci, int where ); */ static inline __always_inline int PCIAPI_INLINE ( direct, pci_num_bus ) ( void ) { - /* No way to work this out via Type 1 accesses */ - return 0x100; + /* Scan first bus and rely on bridge detection to find higher buses */ + return 1; } /** diff --git a/src/arch/x86/interface/pcbios/int13.c b/src/arch/x86/interface/pcbios/int13.c index 30530e197..d6c4d7ebf 100644 --- a/src/arch/x86/interface/pcbios/int13.c +++ b/src/arch/x86/interface/pcbios/int13.c @@ -678,10 +678,10 @@ static int int13_get_disk_type ( struct san_device *sandev, * @ret cx Extensions API support bitmap * @ret status Status code / API version */ -static int int13_extension_check ( struct san_device *sandev __unused, +static int int13_extension_check ( struct san_device *sandev, struct i386_all_regs *ix86 ) { - if ( ix86->regs.bx == 0x55aa ) { + if ( ( ix86->regs.bx == 0x55aa ) && ! int13_is_fdd ( sandev ) ) { DBGC2 ( sandev, "INT13 extensions installation check\n" ); ix86->regs.bx = 0xaa55; ix86->regs.cx = ( INT13_EXTENSION_LINEAR | diff --git a/src/config/cloud/general.h b/src/config/cloud/general.h index 38799fd8e..fc881163a 100644 --- a/src/config/cloud/general.h +++ b/src/config/cloud/general.h @@ -6,3 +6,8 @@ * Google Compute Engine metadata server. */ #define HTTP_HACK_GCE + +/* Allow scripts to handle errors by powering down the VM to avoid + * incurring unnecessary costs. + */ +#define POWEROFF_CMD diff --git a/src/drivers/bus/pci.c b/src/drivers/bus/pci.c index 06b36a770..1b7350c8b 100644 --- a/src/drivers/bus/pci.c +++ b/src/drivers/bus/pci.c @@ -228,6 +228,9 @@ int pci_read_config ( struct pci_device *pci ) { */ int pci_find_next ( struct pci_device *pci, unsigned int busdevfn ) { static unsigned int end; + unsigned int sub_end; + uint8_t hdrtype; + uint8_t sub; int rc; /* Determine number of PCI buses */ @@ -236,10 +239,30 @@ int pci_find_next ( struct pci_device *pci, unsigned int busdevfn ) { /* Find next PCI device, if any */ for ( ; busdevfn < end ; busdevfn++ ) { + + /* Check for PCI device existence */ memset ( pci, 0, sizeof ( *pci ) ); pci_init ( pci, busdevfn ); - if ( ( rc = pci_read_config ( pci ) ) == 0 ) - return busdevfn; + if ( ( rc = pci_read_config ( pci ) ) != 0 ) + continue; + + /* If device is a bridge, expand the number of PCI + * buses as needed. + */ + pci_read_config_byte ( pci, PCI_HEADER_TYPE, &hdrtype ); + hdrtype &= PCI_HEADER_TYPE_MASK; + if ( hdrtype == PCI_HEADER_TYPE_BRIDGE ) { + pci_read_config_byte ( pci, PCI_SUBORDINATE, &sub ); + sub_end = PCI_BUSDEVFN ( 0, ( sub + 1 ), 0, 0 ); + if ( end < sub_end ) { + DBGC ( pci, PCI_FMT " found subordinate bus " + "%#02x\n", PCI_ARGS ( pci ), sub ); + end = sub_end; + } + } + + /* Return this device */ + return busdevfn; } return -ENODEV; diff --git a/src/drivers/net/intelxvf.c b/src/drivers/net/intelxvf.c index f0ba091d5..d50bac698 100644 --- a/src/drivers/net/intelxvf.c +++ b/src/drivers/net/intelxvf.c @@ -530,6 +530,7 @@ static struct pci_device_id intelxvf_nics[] = { PCI_ROM ( 0x8086, 0x1515, "x540-vf", "X540 VF", 0 ), PCI_ROM ( 0x8086, 0x1565, "x550-vf", "X550 VF", 0 ), PCI_ROM ( 0x8086, 0x15a8, "x552-vf", "X552 VF", 0 ), + PCI_ROM ( 0x8086, 0x15c5, "x557-vf", "X557-AT2 VF", 0 ), }; /** PCI driver */ diff --git a/src/drivers/net/netfront.c b/src/drivers/net/netfront.c index be210850a..1203e585c 100644 --- a/src/drivers/net/netfront.c +++ b/src/drivers/net/netfront.c @@ -56,7 +56,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); __einfo_uniqify ( EINFO_EIO, -NETIF_RSP_DROPPED, \ "Packet dropped" ) #define EIO_NETIF_RSP( status ) \ - EUNIQ ( EINFO_EIO, -(status), \ + EUNIQ ( EINFO_EIO, ( -(status) & 0x1f ), \ EIO_NETIF_RSP_ERROR, EIO_NETIF_RSP_DROPPED ) /****************************************************************************** @@ -326,6 +326,7 @@ static int netfront_create_ring ( struct netfront_nic *netfront, struct netfront_ring *ring ) { struct xen_device *xendev = netfront->xendev; struct xen_hypervisor *xen = xendev->xen; + physaddr_t addr; unsigned int i; int rc; @@ -345,11 +346,11 @@ static int netfront_create_ring ( struct netfront_nic *netfront, } /* Grant access to shared ring */ + addr = virt_to_phys ( ring->sring.raw ); if ( ( rc = xengrant_permit_access ( xen, ring->ref, xendev->backend_id, - 0, ring->sring.raw ) ) != 0 ) { + 0, addr ) ) != 0 ) { DBGC ( netfront, "NETFRONT %s could not permit access to " - "%#08lx: %s\n", xendev->key, - virt_to_phys ( ring->sring.raw ), strerror ( rc ) ); + "%#08lx: %s\n", xendev->key, addr, strerror ( rc ) ); goto err_permit_access; } @@ -358,10 +359,8 @@ static int netfront_create_ring ( struct netfront_nic *netfront, ring->ref ) ) != 0 ) goto err_write_num; - DBGC ( netfront, "NETFRONT %s %s=\"%d\" [%08lx,%08lx)\n", - xendev->key, ring->ref_key, ring->ref, - virt_to_phys ( ring->sring.raw ), - ( virt_to_phys ( ring->sring.raw ) + PAGE_SIZE ) ); + DBGC ( netfront, "NETFRONT %s %s=\"%d\" [%08lx,%08lx)\n", xendev->key, + ring->ref_key, ring->ref, addr, ( addr + PAGE_SIZE ) ); return 0; netfront_rm ( netfront, ring->ref_key ); @@ -378,7 +377,8 @@ static int netfront_create_ring ( struct netfront_nic *netfront, * * @v netfront Netfront device * @v ring Descriptor ring - * @v iobuf I/O buffer + * @v addr Physical address + * @v iobuf Associated I/O buffer, or NULL * @v id Buffer ID to fill in * @v ref Grant reference to fill in * @ret rc Return status code @@ -387,8 +387,9 @@ static int netfront_create_ring ( struct netfront_nic *netfront, * ring. */ static int netfront_push ( struct netfront_nic *netfront, - struct netfront_ring *ring, struct io_buffer *iobuf, - uint16_t *id, grant_ref_t *ref ) { + struct netfront_ring *ring, physaddr_t addr, + struct io_buffer *iobuf, uint16_t *id, + grant_ref_t *ref ) { struct xen_device *xendev = netfront->xendev; struct xen_hypervisor *xen = xendev->xen; unsigned int next_id; @@ -402,19 +403,15 @@ static int netfront_push ( struct netfront_nic *netfront, next_id = ring->ids[ ring->id_prod & ( ring->count - 1 ) ]; next_ref = ring->refs[next_id]; - /* Grant access to I/O buffer page. I/O buffers are naturally - * aligned, so we never need to worry about crossing a page - * boundary. - */ + /* Grant access to page containing address */ if ( ( rc = xengrant_permit_access ( xen, next_ref, xendev->backend_id, - 0, iobuf->data ) ) != 0 ) { + 0, addr ) ) != 0 ) { DBGC ( netfront, "NETFRONT %s could not permit access to " - "%#08lx: %s\n", xendev->key, - virt_to_phys ( iobuf->data ), strerror ( rc ) ); + "%#08lx: %s\n", xendev->key, addr, strerror ( rc ) ); return rc; } - /* Store I/O buffer */ + /* Store associated I/O buffer, if any */ assert ( ring->iobufs[next_id] == NULL ); ring->iobufs[next_id] = iobuf; @@ -434,7 +431,7 @@ static int netfront_push ( struct netfront_nic *netfront, * @v netfront Netfront device * @v ring Descriptor ring * @v id Buffer ID - * @ret iobuf I/O buffer + * @ret iobuf Associated I/O buffer, if any */ static struct io_buffer * netfront_pull ( struct netfront_nic *netfront, struct netfront_ring *ring, @@ -451,7 +448,6 @@ static struct io_buffer * netfront_pull ( struct netfront_nic *netfront, /* Retrieve I/O buffer */ iobuf = ring->iobufs[id]; - assert ( iobuf != NULL ); ring->iobufs[id] = NULL; /* Free buffer ID */ @@ -494,6 +490,22 @@ static void netfront_destroy_ring ( struct netfront_nic *netfront, ring->sring.raw = NULL; } +/** + * Discard partially received I/O buffers + * + * @v netfront Netfront device + */ +static void netfront_discard ( struct netfront_nic *netfront ) { + struct io_buffer *iobuf; + struct io_buffer *tmp; + + /* Discard all buffers in the list */ + list_for_each_entry_safe ( iobuf, tmp, &netfront->rx_partial, list ) { + list_del ( &iobuf->list ); + free_iob ( iobuf ); + } +} + /****************************************************************************** * * Network device interface @@ -512,6 +524,7 @@ static void netfront_refill_rx ( struct net_device *netdev ) { struct io_buffer *iobuf; struct netif_rx_request *request; unsigned int refilled = 0; + physaddr_t addr; int notify; int rc; @@ -524,24 +537,24 @@ static void netfront_refill_rx ( struct net_device *netdev ) { /* Wait for next refill */ break; } + addr = virt_to_phys ( iobuf->data ); /* Add to descriptor ring */ request = RING_GET_REQUEST ( &netfront->rx_fring, netfront->rx_fring.req_prod_pvt ); - if ( ( rc = netfront_push ( netfront, &netfront->rx, + if ( ( rc = netfront_push ( netfront, &netfront->rx, addr, iobuf, &request->id, &request->gref ) ) != 0 ) { netdev_rx_err ( netdev, iobuf, rc ); break; } DBGC2 ( netfront, "NETFRONT %s RX id %d ref %d is %#08lx+%zx\n", - xendev->key, request->id, request->gref, - virt_to_phys ( iobuf->data ), iob_tailroom ( iobuf ) ); + xendev->key, request->id, request->gref, addr, + iob_tailroom ( iobuf ) ); /* Move to next descriptor */ netfront->rx_fring.req_prod_pvt++; refilled++; - } /* Push new descriptors and notify backend if applicable */ @@ -593,6 +606,10 @@ static int netfront_open ( struct net_device *netdev ) { if ( ( rc = netfront_write_flag ( netfront, "request-rx-copy" ) ) != 0 ) goto err_request_rx_copy; + /* Inform backend that we can support scatter-gather */ + if ( ( rc = netfront_write_flag ( netfront, "feature-sg" ) ) != 0 ) + goto err_feature_sg; + /* Disable checksum offload, since we will always do the work anyway */ if ( ( rc = netfront_write_flag ( netfront, "feature-no-csum-offload" ) ) != 0 ) @@ -632,6 +649,8 @@ static int netfront_open ( struct net_device *netdev ) { err_feature_rx_notify: netfront_rm ( netfront, "feature-no-csum-offload" ); err_feature_no_csum_offload: + netfront_rm ( netfront, "feature-sg" ); + err_feature_sg: netfront_rm ( netfront, "request-rx-copy" ); err_request_rx_copy: netfront_destroy_event ( netfront ); @@ -675,11 +694,15 @@ static void netfront_close ( struct net_device *netdev ) { /* Delete flags */ netfront_rm ( netfront, "feature-rx-notify" ); netfront_rm ( netfront, "feature-no-csum-offload" ); + netfront_rm ( netfront, "feature-sg" ); netfront_rm ( netfront, "request-rx-copy" ); /* Destroy event channel */ netfront_destroy_event ( netfront ); + /* Discard any partially received I/O buffers */ + netfront_discard ( netfront ); + /* Destroy receive descriptor ring, freeing any outstanding * I/O buffers. */ @@ -703,34 +726,66 @@ static int netfront_transmit ( struct net_device *netdev, struct netfront_nic *netfront = netdev->priv; struct xen_device *xendev = netfront->xendev; struct netif_tx_request *request; + physaddr_t addr; + size_t len; + size_t remaining; + size_t frag_len; + unsigned int offset; + unsigned int count; + unsigned int more; int notify; int rc; + /* Calculate number of page buffers required */ + addr = virt_to_phys ( iobuf->data ); + len = iob_len ( iobuf ); + offset = ( addr & ( PAGE_SIZE - 1 ) ); + count = ( ( offset + len + PAGE_SIZE - 1 ) / PAGE_SIZE ); + /* Check that we have space in the ring */ - if ( netfront_ring_is_full ( &netfront->tx ) ) { + if ( netfront_ring_space ( &netfront->tx ) < count ) { DBGC ( netfront, "NETFRONT %s out of transmit descriptors\n", xendev->key ); return -ENOBUFS; } /* Add to descriptor ring */ - request = RING_GET_REQUEST ( &netfront->tx_fring, - netfront->tx_fring.req_prod_pvt ); - if ( ( rc = netfront_push ( netfront, &netfront->tx, iobuf, - &request->id, &request->gref ) ) != 0 ) { - return rc; - } - request->offset = ( virt_to_phys ( iobuf->data ) & ( PAGE_SIZE - 1 ) ); - request->flags = NETTXF_data_validated; - request->size = iob_len ( iobuf ); - DBGC2 ( netfront, "NETFRONT %s TX id %d ref %d is %#08lx+%zx\n", - xendev->key, request->id, request->gref, - virt_to_phys ( iobuf->data ), iob_len ( iobuf ) ); + remaining = len; + while ( remaining ) { + + /* Calculate length of this fragment */ + frag_len = ( PAGE_SIZE - offset ); + if ( frag_len >= remaining ) { + frag_len = remaining; + more = 0; + } else { + more = NETTXF_more_data; + } - /* Consume descriptor */ - netfront->tx_fring.req_prod_pvt++; + /* Populate request */ + request = RING_GET_REQUEST ( &netfront->tx_fring, + netfront->tx_fring.req_prod_pvt ); + if ( ( rc = netfront_push ( netfront, &netfront->tx, addr, + ( more ? NULL : iobuf ), + &request->id, + &request->gref ) ) != 0 ) { + return rc; + } + request->flags = ( NETTXF_data_validated | more ); + request->offset = offset; + request->size = ( ( remaining == len ) ? len : frag_len ); + DBGC2 ( netfront, "NETFRONT %s TX id %d ref %d is " + "%#08lx+%zx%s\n", xendev->key, request->id, + request->gref, addr, frag_len, ( more ? "..." : "" ) ); + + /* Move to next descriptor */ + netfront->tx_fring.req_prod_pvt++; + addr += frag_len; + remaining -= frag_len; + offset = 0; + } - /* Push new descriptor and notify backend if applicable */ + /* Push new descriptors and notify backend if applicable */ RING_PUSH_REQUESTS_AND_CHECK_NOTIFY ( &netfront->tx_fring, notify ); if ( notify ) netfront_send_event ( netfront ); @@ -748,7 +803,7 @@ static void netfront_poll_tx ( struct net_device *netdev ) { struct xen_device *xendev = netfront->xendev; struct netif_tx_response *response; struct io_buffer *iobuf; - unsigned int status; + int status; int rc; /* Consume any unconsumed responses */ @@ -761,10 +816,11 @@ static void netfront_poll_tx ( struct net_device *netdev ) { /* Retrieve from descriptor ring */ iobuf = netfront_pull ( netfront, &netfront->tx, response->id ); status = response->status; - if ( status == NETIF_RSP_OKAY ) { + if ( status >= NETIF_RSP_OKAY ) { DBGC2 ( netfront, "NETFRONT %s TX id %d complete\n", xendev->key, response->id ); - netdev_tx_complete ( netdev, iobuf ); + if ( iobuf ) + netdev_tx_complete ( netdev, iobuf ); } else { rc = -EIO_NETIF_RSP ( status ); DBGC2 ( netfront, "NETFRONT %s TX id %d error %d: %s\n", @@ -786,6 +842,7 @@ static void netfront_poll_rx ( struct net_device *netdev ) { struct netif_rx_response *response; struct io_buffer *iobuf; int status; + int more; size_t len; int rc; @@ -799,21 +856,45 @@ static void netfront_poll_rx ( struct net_device *netdev ) { /* Retrieve from descriptor ring */ iobuf = netfront_pull ( netfront, &netfront->rx, response->id ); status = response->status; - if ( status >= 0 ) { - len = status; - iob_reserve ( iobuf, response->offset ); - iob_put ( iobuf, len ); - DBGC2 ( netfront, "NETFRONT %s RX id %d complete " - "%#08lx+%zx\n", xendev->key, response->id, - virt_to_phys ( iobuf->data ), len ); - netdev_rx ( netdev, iobuf ); - } else { + more = ( response->flags & NETRXF_more_data ); + + /* Report errors */ + if ( status < 0 ) { rc = -EIO_NETIF_RSP ( status ); DBGC2 ( netfront, "NETFRONT %s RX id %d error %d: %s\n", xendev->key, response->id, status, strerror ( rc ) ); + netfront_discard ( netfront ); netdev_rx_err ( netdev, iobuf, rc ); + continue; } + + /* Add to partial receive list */ + len = status; + iob_reserve ( iobuf, response->offset ); + iob_put ( iobuf, len ); + DBGC2 ( netfront, "NETFRONT %s RX id %d complete " + "%#08lx+%zx%s\n", xendev->key, response->id, + virt_to_phys ( iobuf->data ), len, + ( more ? "..." : "" ) ); + list_add_tail ( &iobuf->list, &netfront->rx_partial ); + + /* Wait until complete packet has been received */ + if ( more ) + continue; + + /* Reassemble complete packet */ + iobuf = iob_concatenate ( &netfront->rx_partial ); + if ( ! iobuf ) { + DBGC2 ( netfront, "NETFRONT %s RX reassembly failed\n", + xendev->key ); + netfront_discard ( netfront ); + netdev_rx_err ( netdev, NULL, -ENOMEM ); + continue; + } + + /* Hand off to network stack */ + netdev_rx ( netdev, iobuf ); } } @@ -871,6 +952,7 @@ static int netfront_probe ( struct xen_device *xendev ) { netdev->dev = &xendev->dev; netfront = netdev->priv; netfront->xendev = xendev; + INIT_LIST_HEAD ( &netfront->rx_partial ); DBGC ( netfront, "NETFRONT %s backend=\"%s\" in domain %ld\n", xendev->key, xendev->backend, xendev->backend_id ); diff --git a/src/drivers/net/netfront.h b/src/drivers/net/netfront.h index c95ed2645..dca3ff1c5 100644 --- a/src/drivers/net/netfront.h +++ b/src/drivers/net/netfront.h @@ -65,7 +65,7 @@ struct netfront_ring { size_t count; /** I/O buffers, indexed by buffer ID */ struct io_buffer **iobufs; - /** I/O buffer grant references, indexed by buffer ID */ + /** Grant references, indexed by buffer ID */ grant_ref_t *refs; /** Buffer ID ring */ @@ -117,6 +117,18 @@ netfront_ring_fill ( struct netfront_ring *ring ) { } /** + * Calculate descriptor ring remaining space + * + * @v ring Descriptor ring + * @v space Number of unused entries + */ +static inline __attribute__ (( always_inline )) unsigned int +netfront_ring_space ( struct netfront_ring *ring ) { + + return ( ring->count - netfront_ring_fill ( ring ) ); +} + +/** * Check whether or not descriptor ring is full * * @v ring Descriptor ring @@ -164,6 +176,8 @@ struct netfront_nic { struct io_buffer *rx_iobufs[NETFRONT_NUM_RX_DESC]; /** Receive I/O buffer IDs */ uint8_t rx_ids[NETFRONT_NUM_RX_DESC]; + /** Partial receive I/O buffer list */ + struct list_head rx_partial; /** Event channel */ struct evtchn_send event; diff --git a/src/include/ipxe/netdevice.h b/src/include/ipxe/netdevice.h index b9c651c71..294f7b367 100644 --- a/src/include/ipxe/netdevice.h +++ b/src/include/ipxe/netdevice.h @@ -451,6 +451,12 @@ struct net_device { */ #define NETDEV_IRQ_UNSUPPORTED 0x0008 +/** Network device transmission is in progress */ +#define NETDEV_TX_IN_PROGRESS 0x0010 + +/** Network device poll is in progress */ +#define NETDEV_POLL_IN_PROGRESS 0x0020 + /** Link-layer protocol table */ #define LL_PROTOCOLS __table ( struct ll_protocol, "ll_protocols" ) diff --git a/src/include/ipxe/pci.h b/src/include/ipxe/pci.h index 6632c574d..933f48530 100644 --- a/src/include/ipxe/pci.h +++ b/src/include/ipxe/pci.h @@ -135,6 +135,9 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #define PCI_CLASS_SERIAL_USB_EHCI 0x20 /**< ECHI USB controller */ #define PCI_CLASS_SERIAL_USB_XHCI 0x30 /**< xHCI USB controller */ +/** Subordinate bus number */ +#define PCI_SUBORDINATE 0x1a + /** Construct PCI class * * @v base Base class (or PCI_ANY_ID) diff --git a/src/include/ipxe/xengrant.h b/src/include/ipxe/xengrant.h index 451a3ceee..fcb7a7157 100644 --- a/src/include/ipxe/xengrant.h +++ b/src/include/ipxe/xengrant.h @@ -166,16 +166,17 @@ xengrant_invalidate ( struct xen_hypervisor *xen, grant_ref_t ref ) { * @v ref Grant reference * @v domid Domain ID * @v subflags Additional flags - * @v page Page start + * @v addr Physical address within page * @ret rc Return status code */ static inline __attribute__ (( always_inline )) int xengrant_permit_access ( struct xen_hypervisor *xen, grant_ref_t ref, - domid_t domid, unsigned int subflags, void *page ) { + domid_t domid, unsigned int subflags, + physaddr_t addr ) { struct grant_entry_header *hdr = xengrant_header ( xen, ref ); struct grant_entry_v1 *v1 = xengrant_v1 ( hdr ); union grant_entry_v2 *v2 = xengrant_v2 ( hdr ); - unsigned long frame = ( virt_to_phys ( page ) / PAGE_SIZE ); + unsigned long frame = ( addr / PAGE_SIZE ); /* Fail (for test purposes) if applicable */ if ( ( XENGRANT_FAIL_RATE > 0 ) && diff --git a/src/interface/linux/linux_api.c b/src/interface/linux/linux_api.c index d1f969aa7..21024ede1 100644 --- a/src/interface/linux/linux_api.c +++ b/src/interface/linux/linux_api.c @@ -486,35 +486,6 @@ linux_slirp_pollfds_poll ( struct Slirp *slirp, int select_error, slirp_pollfds_poll ( slirp, select_error, get_revents, opaque ); } -#else /* HAVE_LIBSLIRP */ - -struct Slirp * __asmcall -linux_slirp_new ( const struct slirp_config *config, - const struct slirp_callbacks *callbacks, void *opaque ) { - return NULL; -} - -void __asmcall linux_slirp_cleanup ( struct Slirp *slirp ) { -} - -void __asmcall linux_slirp_input ( struct Slirp *slirp, const uint8_t *pkt, - int pkt_len ) { -} - -void __asmcall -linux_slirp_pollfds_fill ( struct Slirp *slirp, uint32_t *timeout, - int ( __asmcall * add_poll ) ( int fd, int events, - void *opaque ), - void *opaque ) { -} - -void __asmcall -linux_slirp_pollfds_poll ( struct Slirp *slirp, int select_error, - int ( __asmcall * get_revents ) ( int idx, - void *opaque ), - void *opaque ) { -} - #endif /* HAVE_LIBSLIRP */ /****************************************************************************** @@ -544,8 +515,11 @@ PROVIDE_IPXE_SYM ( linux_socket ); PROVIDE_IPXE_SYM ( linux_bind ); PROVIDE_IPXE_SYM ( linux_sendto ); PROVIDE_IPXE_SYM ( linux_strerror ); + +#ifdef HAVE_LIBSLIRP PROVIDE_IPXE_SYM ( linux_slirp_new ); PROVIDE_IPXE_SYM ( linux_slirp_cleanup ); PROVIDE_IPXE_SYM ( linux_slirp_input ); PROVIDE_IPXE_SYM ( linux_slirp_pollfds_fill ); PROVIDE_IPXE_SYM ( linux_slirp_pollfds_poll ); +#endif /* HAVE_LIBSLIRP */ diff --git a/src/net/netdevice.c b/src/net/netdevice.c index 6e685630c..5df306e8d 100644 --- a/src/net/netdevice.c +++ b/src/net/netdevice.c @@ -297,30 +297,45 @@ int netdev_tx ( struct net_device *netdev, struct io_buffer *iobuf ) { /* Enqueue packet */ list_add_tail ( &iobuf->list, &netdev->tx_queue ); + /* Guard against re-entry */ + if ( netdev->state & NETDEV_TX_IN_PROGRESS ) { + rc = -EBUSY; + goto err_busy; + } + netdev->state |= NETDEV_TX_IN_PROGRESS; + /* Avoid calling transmit() on unopened network devices */ if ( ! netdev_is_open ( netdev ) ) { rc = -ENETUNREACH; - goto err; + goto err_closed; } /* Discard packet (for test purposes) if applicable */ if ( ( rc = inject_fault ( NETDEV_DISCARD_RATE ) ) != 0 ) - goto err; + goto err_fault; /* Map for DMA, if required */ if ( netdev->dma && ( ! dma_mapped ( &iobuf->map ) ) ) { if ( ( rc = iob_map_tx ( iobuf, netdev->dma ) ) != 0 ) - goto err; + goto err_map; } /* Transmit packet */ if ( ( rc = netdev->op->transmit ( netdev, iobuf ) ) != 0 ) - goto err; + goto err_transmit; + + /* Clear in-progress flag */ + netdev->state &= ~NETDEV_TX_IN_PROGRESS; profile_stop ( &net_tx_profiler ); return 0; - err: + err_transmit: + err_map: + err_fault: + err_closed: + netdev->state &= ~NETDEV_TX_IN_PROGRESS; + err_busy: netdev_tx_complete_err ( netdev, iobuf, rc ); return rc; } @@ -552,8 +567,18 @@ void netdev_rx_err ( struct net_device *netdev, */ void netdev_poll ( struct net_device *netdev ) { - if ( netdev_is_open ( netdev ) ) - netdev->op->poll ( netdev ); + /* Avoid calling poll() on unopened network devices */ + if ( ! netdev_is_open ( netdev ) ) + return; + + /* Guard against re-entry */ + if ( netdev->state & NETDEV_POLL_IN_PROGRESS ) + return; + + /* Poll device */ + netdev->state |= NETDEV_POLL_IN_PROGRESS; + netdev->op->poll ( netdev ); + netdev->state &= ~NETDEV_POLL_IN_PROGRESS; } /** diff --git a/src/net/udp/dhcp.c b/src/net/udp/dhcp.c index 4ebd38bbb..a335a778a 100644 --- a/src/net/udp/dhcp.c +++ b/src/net/udp/dhcp.c @@ -444,6 +444,26 @@ static void dhcp_discovery_rx ( struct dhcp_session *dhcp, } /** + * Defer DHCP discovery + * + * @v dhcp DHCP session + */ +static void dhcp_defer ( struct dhcp_session *dhcp ) { + + /* Do nothing if we have reached the deferral limit */ + if ( dhcp->count > DHCP_DISC_MAX_DEFERRALS ) + return; + + /* Return to discovery state */ + DBGC ( dhcp, "DHCP %p deferring discovery\n", dhcp ); + dhcp_set_state ( dhcp, &dhcp_state_discover ); + + /* Delay first DHCPDISCOVER */ + start_timer_fixed ( &dhcp->timer, + ( DHCP_DISC_START_TIMEOUT_SEC * TICKS_PER_SEC ) ); +} + +/** * Handle timer expiry during DHCP discovery * * @v dhcp DHCP session @@ -462,14 +482,8 @@ static void dhcp_discovery_expired ( struct dhcp_session *dhcp ) { dhcp_tx ( dhcp ); /* If link is blocked, defer DHCP discovery timeout */ - if ( netdev_link_blocked ( dhcp->netdev ) && - ( dhcp->count <= DHCP_DISC_MAX_DEFERRALS ) ) { - DBGC ( dhcp, "DHCP %p deferring discovery timeout\n", dhcp ); - dhcp->start = currticks(); - start_timer_fixed ( &dhcp->timer, - ( DHCP_DISC_START_TIMEOUT_SEC * - TICKS_PER_SEC ) ); - } + if ( netdev_link_blocked ( dhcp->netdev ) ) + dhcp_defer ( dhcp ); } /** DHCP discovery state operations */ @@ -553,9 +567,17 @@ static void dhcp_request_rx ( struct dhcp_session *dhcp, DBGC ( dhcp, " for %s", inet_ntoa ( ip ) ); DBGC ( dhcp, "\n" ); - /* Filter out unacceptable responses */ + /* Filter out invalid port */ if ( peer->sin_port != htons ( BOOTPS_PORT ) ) return; + + /* Handle DHCPNAK */ + if ( msgtype == DHCPNAK ) { + dhcp_defer ( dhcp ); + return; + } + + /* Filter out unacceptable responses */ if ( msgtype /* BOOTP */ && ( msgtype != DHCPACK ) ) return; if ( server_id.s_addr != dhcp->server.s_addr ) diff --git a/src/scripts/efi.lds b/src/scripts/efi.lds index f1049f24b..dd7b3f019 100644 --- a/src/scripts/efi.lds +++ b/src/scripts/efi.lds @@ -8,22 +8,22 @@ SECTIONS { /* The file starts at a virtual address of zero, and sections are - * contiguous. Each section is aligned to at least _max_align, - * which defaults to 32. Load addresses are equal to virtual + * contiguous. Each section is aligned to at least _page_align, + * which defaults to 4096. Load addresses are equal to virtual * addresses. */ - _max_align = 32; + _page_align = 4096; - /* Allow plenty of space for file headers */ - . = 0x1000; + /* Allow one page of space for file headers, common PE/COFF layout */ + . = _page_align; /* * The text section * */ - . = ALIGN ( _max_align ); + . = ALIGN ( _page_align ); .text : { _text = .; *(.text) @@ -36,7 +36,7 @@ SECTIONS { * */ - . = ALIGN ( _max_align ); + . = ALIGN ( _page_align ); .rodata : { _rodata = .; *(.rodata) @@ -49,7 +49,7 @@ SECTIONS { * */ - . = ALIGN ( _max_align ); + . = ALIGN ( _page_align ); .data : { _data = .; *(.data) @@ -65,7 +65,7 @@ SECTIONS { * */ - . = ALIGN ( _max_align ); + . = ALIGN ( _page_align ); .bss : { _bss = .; *(.bss) @@ -106,5 +106,6 @@ SECTIONS { *(.einfo.*) *(.discard) *(.discard.*) + *(.pci_devlist.*) } } diff --git a/src/util/elf2efi.c b/src/util/elf2efi.c index 38eb29964..5542b99f8 100644 --- a/src/util/elf2efi.c +++ b/src/util/elf2efi.c @@ -125,7 +125,8 @@ #define R_ARM_V4BX 40 #endif -#define EFI_FILE_ALIGN 0x20 +#define EFI_FILE_ALIGN 0x20 +#define EFI_IMAGE_ALIGN 0x1000 struct elf_file { void *data; @@ -173,9 +174,9 @@ static struct pe_header efi_pe_header = { .Magic = EFI_IMAGE_NT_OPTIONAL_HDR_MAGIC, .MajorLinkerVersion = 42, .MinorLinkerVersion = 42, - .SectionAlignment = EFI_FILE_ALIGN, + .SectionAlignment = EFI_IMAGE_ALIGN, .FileAlignment = EFI_FILE_ALIGN, - .SizeOfImage = sizeof ( efi_pe_header ), + .SizeOfImage = EFI_IMAGE_ALIGN, .SizeOfHeaders = sizeof ( efi_pe_header ), .NumberOfRvaAndSizes = EFI_IMAGE_NUMBER_OF_DIRECTORY_ENTRIES, @@ -217,6 +218,16 @@ static unsigned long efi_file_align ( unsigned long offset ) { } /** + * Align section within PE image + * + * @v offset Unaligned offset + * @ret aligned_offset Aligned offset + */ +static unsigned long efi_image_align ( unsigned long offset ) { + return ( ( offset + EFI_IMAGE_ALIGN - 1 ) & ~( EFI_IMAGE_ALIGN - 1 ) ); +} + +/** * Generate entry in PE relocation table * * @v pe_reltab PE relocation table @@ -605,7 +616,7 @@ static struct pe_section * process_section ( struct elf_file *elf, pe_header->nt.FileHeader.NumberOfSections++; pe_header->nt.OptionalHeader.SizeOfHeaders += sizeof ( new->hdr ); pe_header->nt.OptionalHeader.SizeOfImage = - efi_file_align ( data_end ); + efi_image_align ( data_end ); return new; } @@ -728,13 +739,15 @@ static struct pe_section * create_reloc_section ( struct pe_header *pe_header, struct pe_relocs *pe_reltab ) { struct pe_section *reloc; + size_t section_rawsz; size_t section_memsz; size_t section_filesz; EFI_IMAGE_DATA_DIRECTORY *relocdir; /* Allocate PE section */ - section_memsz = output_pe_reltab ( pe_reltab, NULL ); - section_filesz = efi_file_align ( section_memsz ); + section_rawsz = output_pe_reltab ( pe_reltab, NULL ); + section_filesz = efi_file_align ( section_rawsz ); + section_memsz = efi_image_align ( section_rawsz ); reloc = xmalloc ( sizeof ( *reloc ) + section_filesz ); memset ( reloc, 0, sizeof ( *reloc ) + section_filesz ); @@ -745,6 +758,7 @@ create_reloc_section ( struct pe_header *pe_header, reloc->hdr.VirtualAddress = pe_header->nt.OptionalHeader.SizeOfImage; reloc->hdr.SizeOfRawData = section_filesz; reloc->hdr.Characteristics = ( EFI_IMAGE_SCN_CNT_INITIALIZED_DATA | + EFI_IMAGE_SCN_MEM_DISCARDABLE | EFI_IMAGE_SCN_MEM_NOT_PAGED | EFI_IMAGE_SCN_MEM_READ ); @@ -754,11 +768,11 @@ create_reloc_section ( struct pe_header *pe_header, /* Update file header details */ pe_header->nt.FileHeader.NumberOfSections++; pe_header->nt.OptionalHeader.SizeOfHeaders += sizeof ( reloc->hdr ); - pe_header->nt.OptionalHeader.SizeOfImage += section_filesz; + pe_header->nt.OptionalHeader.SizeOfImage += section_memsz; relocdir = &(pe_header->nt.OptionalHeader.DataDirectory [EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC]); relocdir->VirtualAddress = reloc->hdr.VirtualAddress; - relocdir->Size = reloc->hdr.Misc.VirtualSize; + relocdir->Size = section_rawsz; return reloc; } @@ -796,8 +810,8 @@ create_debug_section ( struct pe_header *pe_header, const char *filename ) { } *contents; /* Allocate PE section */ - section_memsz = sizeof ( *contents ); - section_filesz = efi_file_align ( section_memsz ); + section_memsz = efi_image_align ( sizeof ( *contents ) ); + section_filesz = efi_file_align ( sizeof ( *contents ) ); debug = xmalloc ( sizeof ( *debug ) + section_filesz ); memset ( debug, 0, sizeof ( *debug ) + section_filesz ); contents = ( void * ) debug->contents; @@ -809,6 +823,7 @@ create_debug_section ( struct pe_header *pe_header, const char *filename ) { debug->hdr.VirtualAddress = pe_header->nt.OptionalHeader.SizeOfImage; debug->hdr.SizeOfRawData = section_filesz; debug->hdr.Characteristics = ( EFI_IMAGE_SCN_CNT_INITIALIZED_DATA | + EFI_IMAGE_SCN_MEM_DISCARDABLE | EFI_IMAGE_SCN_MEM_NOT_PAGED | EFI_IMAGE_SCN_MEM_READ ); debug->fixup = fixup_debug_section; @@ -828,7 +843,7 @@ create_debug_section ( struct pe_header *pe_header, const char *filename ) { /* Update file header details */ pe_header->nt.FileHeader.NumberOfSections++; pe_header->nt.OptionalHeader.SizeOfHeaders += sizeof ( debug->hdr ); - pe_header->nt.OptionalHeader.SizeOfImage += section_filesz; + pe_header->nt.OptionalHeader.SizeOfImage += section_memsz; debugdir = &(pe_header->nt.OptionalHeader.DataDirectory [EFI_IMAGE_DIRECTORY_ENTRY_DEBUG]); debugdir->VirtualAddress = debug->hdr.VirtualAddress; |
