From 9d866c240d5168a02f12cfe9fd7dacba4abd2896 Mon Sep 17 00:00:00 2001 From: Animesh Bhatt Date: Mon, 3 Jul 2023 02:43:14 -0700 Subject: support for aqc113 --- src/Makefile | 1 + src/drivers/net/marvell/aqc1xx.c | 643 ++++++++++++++++++++++++++++++++++++++ src/drivers/net/marvell/aqc1xx.h | 270 ++++++++++++++++ src/drivers/net/marvell/atl2_hw.c | 235 ++++++++++++++ src/drivers/net/marvell/atl2_hw.h | 94 ++++++ src/drivers/net/marvell/atl_hw.c | 321 +++++++++++++++++++ src/drivers/net/marvell/atl_hw.h | 83 +++++ src/include/ipxe/errfile.h | 4 + 8 files changed, 1651 insertions(+) create mode 100644 src/drivers/net/marvell/aqc1xx.c create mode 100644 src/drivers/net/marvell/aqc1xx.h create mode 100644 src/drivers/net/marvell/atl2_hw.c create mode 100644 src/drivers/net/marvell/atl2_hw.h create mode 100644 src/drivers/net/marvell/atl_hw.c create mode 100644 src/drivers/net/marvell/atl_hw.h diff --git a/src/Makefile b/src/Makefile index bc82cc6f..95719628 100644 --- a/src/Makefile +++ b/src/Makefile @@ -77,6 +77,7 @@ SRCDIRS += drivers/net/efi SRCDIRS += drivers/net/tg3 SRCDIRS += drivers/net/bnxt SRCDIRS += drivers/net/sfc +SRCDIRS += drivers/net/marvell SRCDIRS += drivers/block SRCDIRS += drivers/nvs SRCDIRS += drivers/bitbash diff --git a/src/drivers/net/marvell/aqc1xx.c b/src/drivers/net/marvell/aqc1xx.c new file mode 100644 index 00000000..42b8164a --- /dev/null +++ b/src/drivers/net/marvell/aqc1xx.c @@ -0,0 +1,643 @@ +/** @file + * + * Marvell AQtion family network card driver. + * + * Copyright(C) 2017-2021 Marvell + * + * SPDX-License-Identifier: BSD-2-Clause + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO,THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ +FILE_LICENCE ( BSD2 ); + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "aqc1xx.h" + +extern struct atl_hw_ops atl_hw; +extern struct atl_hw_ops atl2_hw; + +/** @file +* +* Marvell AQC network card driver +* +*/ + +static int atl_ring_alloc ( const struct atl_nic *nic, struct atl_ring *ring, + uint32_t desc_size, uint32_t reg_base ) +{ + physaddr_t phy_addr; + + /* Allocate ring buffer.*/ + ring->length = ATL_RING_SIZE * desc_size; + ring->ring = dma_alloc ( nic->dma, &ring->map, ring->length, + ring->length ); + + if ( !ring->ring ) + return -ENOMEM; + + /* Initialize the descriptor ring */ + memset ( ring->ring, 0, ring->length ); + + /* Program ring address */ + phy_addr = dma ( &ring->map, ring->ring ); + + /* Write ring address (hi & low parts).*/ + ATL_WRITE_REG ( (uint32_t)phy_addr, reg_base ); + ATL_WRITE_REG ( (uint32_t)(((uint64_t)phy_addr) >> 32), reg_base + 4 ); + + /* Write ring length.*/ + ATL_WRITE_REG ( ATL_RING_SIZE, reg_base + 8 ); + + ring->sw_head = ring->sw_tail = 0; + + DBGC ( nic, "AQUANTIA: %p ring is at [%08llx,%08llx), reg base %#x\n", + nic, ((unsigned long long)phy_addr), + ((unsigned long long) phy_addr + ring->length), reg_base ); + + return 0; +} + +static void atl_ring_free ( struct atl_ring *ring ) +{ + dma_free ( &ring->map, ring->ring, ring->length ); + ring->ring = NULL; + ring->length = 0; +} + +static void atl_ring_next_dx ( unsigned int *val ) +{ + ++( *val ); + if ( *val == ATL_RING_SIZE ) + *val = 0; +} + +int atl_ring_full ( const struct atl_ring *ring ) +{ + unsigned int tail = ring->sw_tail; + atl_ring_next_dx ( &tail ); + return tail == ring->sw_head; +} + +void atl_rx_ring_fill ( struct atl_nic *nic ) +{ + struct atl_desc_rx *rx; + struct io_buffer *iobuf; + physaddr_t address; + unsigned int refilled = 0; + + /* Refill ring */ + while ( !atl_ring_full ( &nic->rx_ring ) ) { + + /* Allocate I/O buffer */ + iobuf = alloc_rx_iob ( ATL_RX_MAX_LEN, nic->dma ); + if ( !iobuf ) { + /* Wait for next refill */ + break; + } + + /* Get next receive descriptor */ + rx = ( struct atl_desc_rx * )nic->rx_ring.ring + + nic->rx_ring.sw_tail; + + /* Populate receive descriptor */ + address = iob_dma ( iobuf ); + rx->data_addr = address; + rx->hdr_addr = 0; + + /* Record I/O buffer */ + assert ( nic->iobufs[nic->rx_ring.sw_tail] == NULL ); + nic->iobufs[nic->rx_ring.sw_tail] = iobuf; + + DBGC( nic, "AQUANTIA: RX[%d] is [%llx,%llx)\n", + nic->rx_ring.sw_tail, + ( (unsigned long long)address), + ( (unsigned long long)address + ATL_RX_MAX_LEN) ); + + atl_ring_next_dx ( &nic->rx_ring.sw_tail ); + refilled++; + } + + /* Push descriptors to card, if applicable */ + if ( refilled ) { + wmb(); + ATL_WRITE_REG ( nic->rx_ring.sw_tail, ATL_RING_TAIL_PTR ); + } +} + +/** +* Open network device +* +* @v netdev Network device +* @ret rc Return status code +*/ +static int atl_open ( struct net_device *netdev ) +{ + struct atl_nic *nic = netdev->priv; + uint32_t ctrl = 0; + + /* Tx ring */ + if ( atl_ring_alloc ( nic, &nic->tx_ring, sizeof(struct atl_desc_tx), + ATL_TX_DMA_DESC_ADDR ) != 0 ) + goto err_tx_alloc; + + /* Rx ring */ + if ( atl_ring_alloc ( nic, &nic->rx_ring, sizeof(struct atl_desc_rx), + ATL_RX_DMA_DESC_ADDR ) != 0 ) + goto err_rx_alloc; + + /* Allocate interrupt vectors */ + ATL_WRITE_REG ( (ATL_IRQ_CTRL_COR_EN | ATL_IRQ_CTRL_REG_RST_DIS), + ATL_IRQ_CTRL ); + + /*TX & RX Interruprt Mapping*/ + ctrl = ATL_IRQ_MAP_REG1_RX0 | ATL_IRQ_MAP_REG1_RX0_EN | + ATL_IRQ_MAP_REG1_TX0 | ATL_IRQ_MAP_REG1_TX0_EN; + ATL_WRITE_REG ( ctrl, ATL_IRQ_MAP_REG1 ); + + /*TX interrupt ctrl reg*/ + ATL_WRITE_REG ( ATL_TX_IRQ_CTRL_WB_EN, ATL_TX_IRQ_CTRL ); + + /*RX interrupt ctrl reg*/ + ATL_WRITE_REG ( ATL_RX_IRQ_CTRL_WB_EN, ATL_RX_IRQ_CTRL ); + + /*RX data path*/ + ctrl = ATL_IRQ_TX | ATL_IRQ_RX; + /* itr mask */ + ATL_WRITE_REG ( ctrl, ATL_ITR_MSKS ); + ATL_WRITE_REG ( (uint32_t)ATL_RX_MAX_LEN / 1024U, + ATL_RX_DMA_DESC_BUF_SIZE ); + + /*filter global ctrl */ + ctrl = ATL_RPF_CTRL1_BRC_EN | ATL_RPF_CTRL1_L2_PROMISC | + ATL_RPF_CTRL1_ACTION | ATL_RPF_CTRL1_BRC_TSH; + ATL_WRITE_REG ( ctrl, ATL_RPF_CTRL1 ); + + /* vlan promisc */ + ATL_WRITE_REG ( ATL_RPF_CTRL2_VLAN_PROMISC, ATL_RPF_CTRL2 ); + /* enable rpf2 */ + ATL_WRITE_REG ( ATL_RPF2_CTRL_EN, ATL_RPF2_CTRL ); + + /* RX Packet Buffer 0 Register 1 */ + ATL_WRITE_REG ( ATL_RPB0_CTRL1_SIZE, ATL_RPB0_CTRL1 ); + + /*RX Packet Buffer 0 Register 2 */ + ctrl = ATL_RPB0_CTRL2_LOW_TSH | ATL_RPB0_CTRL2_HIGH_TSH | + ATL_RPB0_CTRL2_FC_EN; + ATL_WRITE_REG ( ctrl, ATL_RPB0_CTRL2 ); + + /*RPB global ctrl*/ + ctrl = ATL_READ_REG(ATL_RPB_CTRL); + ctrl |= (ATL_RPB_CTRL_EN | ATL_RPB_CTRL_FC); + ATL_WRITE_REG ( ctrl, ATL_RPB_CTRL ); + + /*TX data path*/ + /* enable tpo2 */ + ATL_WRITE_REG ( ATL_TPO2_EN, ATL_TPO2_CTRL ); + /* tpb global ctrl *** */ + ATL_WRITE_REG ( ATL_TPB0_CTRL1_SIZE, ATL_TPB0_CTRL1 ); + + ctrl = ATL_TPB0_CTRL2_LOW_TSH | ATL_TPB0_CTRL2_HIGH_TSH; + /* tpb global ctrl *** */ + ATL_WRITE_REG ( ctrl, ATL_TPB0_CTRL2 ); + + ctrl = ATL_READ_REG ( ATL_TPB_CTRL ); + ctrl |= ( ATL_TPB_CTRL_EN | ATL_TPB_CTRL_PAD_EN ); + /* tpb global ctrl */ + ATL_WRITE_REG ( ctrl, ATL_TPB_CTRL ); + + /*Enable rings*/ + ATL_WRITE_REG ( ATL_READ_REG ( ATL_RING_TX_CTRL ) | ATL_RING_TX_CTRL_EN, + ATL_RING_TX_CTRL ); + ATL_WRITE_REG ( ATL_READ_REG ( ATL_RING_RX_CTRL ) | ATL_RING_RX_CTRL_EN, + ATL_RING_RX_CTRL ); + + if ( nic->flags == ATL_FLAG_A2 ) { + ATL_WRITE_REG ( ATL2_RPF_NEW_EN_ADR_EN, ATL2_RPF_NEW_EN_ADR ); + } + + atl_rx_ring_fill ( nic ); + + nic->hw_ops->start ( nic ); + + return 0; + +err_rx_alloc: + atl_ring_free ( &nic->tx_ring ); + +err_tx_alloc: + return -ENOMEM; +} + +/** +* Close network device +* +* @v netdev Network device +*/ +static void atl_close ( struct net_device *netdev ) +{ + struct atl_nic *nic = netdev->priv; + + nic->hw_ops->stop ( nic ); + /* rpb global ctrl */ + ATL_WRITE_REG ( ATL_RPB_CTRL_DIS, ATL_RPB_CTRL ); + /* tgb global ctrl */ + ATL_WRITE_REG ( ATL_TPB_CTRL_DIS, ATL_TPB_CTRL); + + ATL_WRITE_REG ( ATL_READ_REG(ATL_RING_TX_CTRL) | (~ATL_RING_TX_CTRL_EN), + ATL_RING_TX_CTRL ); + ATL_WRITE_REG ( ATL_READ_REG(ATL_RING_RX_CTRL) | (~ATL_RING_RX_CTRL_EN), + ATL_RING_RX_CTRL ); + + /* clear itr mask */ + ATL_WRITE_REG ( ATL_ITR_MSKS_DIS, ATL_ITR_MSKS ); + + /* Reset the NIC */ + nic->hw_ops->reset ( nic ); + + atl_ring_free ( &nic->tx_ring ); + atl_ring_free ( &nic->rx_ring ); +} + +/** +* Transmit packet +* +* @v netdev Network device +* @v iobuf I/O buffer +* @ret rc Return status code +*/ +int atl_transmit ( struct net_device *netdev, struct io_buffer *iobuf ) +{ + struct atl_nic *nic = netdev->priv; + struct atl_desc_tx *tx; + physaddr_t address; + uint32_t len; + + /* Get next transmit descriptor */ + if ( atl_ring_full ( &nic->tx_ring ) ) { + DBGC ( nic, "AQUANTIA: %p out of transmit descriptors\n", nic ); + return -ENOBUFS; + } + + tx = (struct atl_desc_tx *)nic->tx_ring.ring + nic->tx_ring.sw_tail; + + /* Populate transmit descriptor */ + memset ( tx, 0, sizeof ( *tx ) ); + address = iob_dma ( iobuf ); + tx->address = address; + len = iob_len ( iobuf ); + + tx->status = 0x1; + tx->status = ( (tx->status) & ~ATL_DESC_TX_BUF_LEN_MASK) | + ((len << ATL_DESC_TX_BUF_LEN_OFFSET) & + ATL_DESC_TX_BUF_LEN_MASK ); + tx->status = ((tx->status) & ~ATL_DESC_TX_EOP_MASK) | + ( (ATL_DESC_TX_DX_EOP_VALUE << ATL_DESC_TX_EOP_OFFSET) & + ATL_DESC_TX_EOP_MASK ); + tx->status = ( (tx->status) & ~ATL_DESC_TX_CMD_MASK) | + ((ATL_DESC_TX_CMD_VALUE << ATL_DESC_TX_CMD_OFFSET) & + ATL_DESC_TX_CMD_MASK ); + tx->flag = ( (tx->flag) & ~ATL_DESC_TX_PAY_LEN_MASK) | + ((len << ATL_DESC_TX_PAY_LEN_OFFSET) & + ATL_DESC_TX_PAY_LEN_MASK ); + wmb(); + + DBGC2 ( nic, "AQUANTIA: %p TX[%d] is [%llx, %llx]\n", + nic, nic->tx_ring.sw_tail, + ( ( unsigned long long ) address ), + ( ( unsigned long long ) address + len ) ); + + atl_ring_next_dx ( &nic->tx_ring.sw_tail ); + ATL_WRITE_REG ( nic->tx_ring.sw_tail, ATL_RING_TAIL ); + + return 0; +} + +void atl_check_link ( struct net_device *netdev ) +{ + struct atl_nic *nic = netdev->priv; + uint32_t link_state; + + /* Read link status */ + link_state = nic->hw_ops->get_link ( nic ); + + DBGC ( nic, "AQUANTIA: %p link status is %08x\n", nic, link_state ); + + if ( link_state != nic->link_state ) { + if ( link_state ) { + DBGC ( nic, "AQUANTIA: link up\n"); + netdev_link_up ( netdev ); + } else { + DBGC ( nic, "AQUANTIA: link lost\n"); + netdev_link_down ( netdev ); + } + nic->link_state = link_state; + } +} + +/** +* Poll for completed packets +* +* @v netdev Network device +*/ +void atl_poll_tx ( struct net_device *netdev ) +{ + struct atl_nic *nic = netdev->priv; + struct atl_desc_tx_wb *tx; + + /* Check for completed packets */ + while ( nic->tx_ring.sw_head != nic->tx_ring.sw_tail ) { + + /* Get next transmit descriptor */ + tx = ( struct atl_desc_tx_wb * )nic->tx_ring.ring + + nic->tx_ring.sw_head; + + /* Stop if descriptor is still in use */ + if ( !(tx->status & cpu_to_le32 ( ATL_TX_DESC_STATUS_DD ) ) ) + return; + + DBGC2 ( nic, "AQUANTIA: %p TX[%d] complete\n", + nic, nic->tx_ring.sw_head ); + + /* Complete TX descriptor */ + atl_ring_next_dx ( &nic->tx_ring.sw_head ); + netdev_tx_complete_next ( netdev ); + } +} + +/** +* Poll for received packets +* +* @v netdev Network device +*/ +void atl_poll_rx ( struct net_device *netdev ) +{ + struct atl_nic *nic = netdev->priv; + struct atl_desc_rx_wb *rx; + struct io_buffer *iobuf; + size_t len; + + /* Check for received packets */ + while ( nic->rx_ring.sw_head != nic->rx_ring.sw_tail ) { + + /* Get next receive descriptor */ + rx = (struct atl_desc_rx_wb *)nic->rx_ring.ring + + nic->rx_ring.sw_head; + + /* Stop if descriptor is still in use */ + if ( !(rx->status & cpu_to_le16(ATL_RX_DESC_STATUS_DD)) ) + return; + + /* Populate I/O buffer */ + iobuf = nic->iobufs[nic->rx_ring.sw_head]; + nic->iobufs[nic->rx_ring.sw_head] = NULL; + len = le16_to_cpu ( rx->pkt_len ); + iob_put ( iobuf, len ); + + /* Hand off to network stack */ + DBGC ( nic, "AQUANTIA: %p RX[%d] complete (length %zd)\n", + nic, nic->rx_ring.sw_head, len ); + + netdev_rx ( netdev, iobuf ); + + atl_ring_next_dx ( &nic->rx_ring.sw_head ); + } +} + +/** +* Poll for completed and received packets +* +* @v netdev Network device +*/ +static void atl_poll ( struct net_device *netdev ) +{ + struct atl_nic *nic = netdev->priv; + + /* Check link state */ + atl_check_link ( netdev ); + + /* Poll for TX completions */ + atl_poll_tx ( netdev ); + + /* Poll for RX completions */ + atl_poll_rx ( netdev ); + + /* Refill RX ring */ + atl_rx_ring_fill ( nic ); +} + +/** +* Enable or disable interrupts +* +* @v netdev Network device +* @v enable Interrupts should be enabled +*/ +static void atl_irq ( struct net_device *netdev, int enable ) +{ + struct atl_nic *nic = netdev->priv; + uint32_t mask; + + mask = ( ATL_IRQ_TX | ATL_IRQ_RX ); + if ( enable ) + ATL_WRITE_REG ( mask, ATL_ITR_MSKS ); + else + ATL_WRITE_REG ( mask, ATL_ITR_MSKC ); +} + +/** Marvell network device operations */ +static struct net_device_operations atl_operations = { + .open = atl_open, + .close = atl_close, + .transmit = atl_transmit, + .poll = atl_poll, + .irq = atl_irq, +}; + +/****************************************************************************** +* +* PCI interface +* +******************************************************************************* +*/ + +/** +* Probe PCI device +* +* @v pci PCI device +* @ret rc Return status code +*/ +static int atl_probe ( struct pci_device *pci ) +{ + struct net_device *netdev; + struct atl_nic *nic; + int rc = ENOERR; + uint32_t io_size = 0; + + /* Allocate and initialise net device */ + netdev = alloc_etherdev ( sizeof( *nic ) ); + if ( !netdev ) { + rc = -ENOMEM; + goto err_alloc; + } + netdev_init ( netdev, &atl_operations ); + nic = netdev->priv; + pci_set_drvdata ( pci, netdev ); + netdev->dev = &pci->dev; + memset( nic, 0, sizeof( *nic ) ); + nic->flags = pci->id->driver_data; + + /* Fix up PCI device */ + adjust_pci_device ( pci ); + + switch ( nic->flags ) { + case ATL_FLAG_A1: + nic->hw_ops = &atl_hw; + io_size = ATL_BAR_SIZE; + break; + case ATL_FLAG_A2: + nic->hw_ops = &atl2_hw; + io_size = ATL2_BAR_SIZE; + break; + default: + goto err_unsupported; + break; + } + + /* Map registers */ + nic->regs = pci_ioremap ( pci, pci->membase, io_size ); + if ( !nic->regs ) { + rc = -ENODEV; + goto err_ioremap; + } + + /* Configure DMA */ + nic->dma = &pci->dma; + + /* Reset the NIC */ + if ( ( rc = nic->hw_ops->reset ( nic ) ) != 0 ) + goto err_reset; + + /* Get MAC Address */ + if ( ( rc = nic->hw_ops->get_mac ( nic, netdev->hw_addr ) ) != 0 ) + goto err_mac; + + /* Register network device */ + if ( ( rc = register_netdev ( netdev ) ) != 0 ) + goto err_register_netdev; + + /* Set initial link state */ + netdev_link_down ( netdev ); + + return 0; + +err_register_netdev: +err_mac: + nic->hw_ops->reset ( nic ); +err_reset: + iounmap ( nic->regs ); +err_ioremap: + netdev_nullify ( netdev ); + netdev_put ( netdev ); +err_unsupported: +err_alloc: + return rc; +} + +/** +* Remove PCI device +* +* @v pci PCI device +*/ +static void atl_remove ( struct pci_device *pci ) +{ + struct net_device *netdev = pci_get_drvdata ( pci ); + struct atl_nic *nic = netdev->priv; + + /* Unregister network device */ + unregister_netdev ( netdev ); + + /* Reset the NIC */ + nic->hw_ops->reset ( nic ); + + /* Free network device */ + iounmap ( nic->regs ); + netdev_nullify ( netdev ); + netdev_put ( netdev ); +} + +/** Marvell PCI device IDs */ +static struct pci_device_id atl_nics[] = { + /* Atlantic 1 */ + /* 10G */ + PCI_ROM(0x1D6A, 0x0001, "AQC07", "Marvell AQtion 10Gbit Network Adapter", ATL_FLAG_A1), + PCI_ROM(0x1D6A, 0xD107, "AQC07", "Marvell AQtion 10Gbit Network Adapter", ATL_FLAG_A1), + PCI_ROM(0x1D6A, 0x07B1, "AQC07", "Marvell AQtion 10Gbit Network Adapter", ATL_FLAG_A1), + PCI_ROM(0x1D6A, 0x87B1, "AQC07", "Marvell AQtion 10Gbit Network Adapter", ATL_FLAG_A1), + + /* SFP */ + PCI_ROM(0x1D6A, 0xD100, "AQC00", "Felicity Network Adapter", ATL_FLAG_A1), + PCI_ROM(0x1D6A, 0x00B1, "AQC00", "Felicity Network Adapter", ATL_FLAG_A1), + PCI_ROM(0x1D6A, 0x80B1, "AQC00", "Felicity Network Adapter", ATL_FLAG_A1), + + /* 5G */ + PCI_ROM(0x1D6A, 0xD108, "AQC08", "Marvell AQtion 5Gbit Network Adapter", ATL_FLAG_A1), + PCI_ROM(0x1D6A, 0x08B1, "AQC08", "Marvell AQtion 5Gbit Network Adapter", ATL_FLAG_A1), + PCI_ROM(0x1D6A, 0x88B1, "AQC08", "Marvell AQtion 5Gbit Network Adapter", ATL_FLAG_A1), + PCI_ROM(0x1D6A, 0x11B1, "AQC11", "Marvell AQtion 5Gbit Network Adapter", ATL_FLAG_A1), + PCI_ROM(0x1D6A, 0x91B1, "AQC11", "Marvell AQtion 5Gbit Network Adapter", ATL_FLAG_A1), + + /* 2.5G */ + PCI_ROM(0x1D6A, 0xD109, "AQC09", "Marvell AQtion 2.5Gbit Network Adapter", ATL_FLAG_A1), + PCI_ROM(0x1D6A, 0x09B1, "AQC09", "Marvell AQtion 2.5Gbit Network Adapter", ATL_FLAG_A1), + PCI_ROM(0x1D6A, 0x89B1, "AQC09", "Marvell AQtion 2.5Gbit Network Adapter", ATL_FLAG_A1), + PCI_ROM(0x1D6A, 0x12B1, "AQC12", "Marvell AQtion 2.5Gbit Network Adapter", ATL_FLAG_A1), + PCI_ROM(0x1D6A, 0x92B1, "AQC12", "Marvell AQtion 2.5Gbit Network Adapter", ATL_FLAG_A1), + + /* Atlantic 2 */ + PCI_ROM(0x1D6A, 0x00C0, "AQC13", "Marvell AQtion 10Gbit Network Adapter", ATL_FLAG_A2), + PCI_ROM(0x1D6A, 0x94C0, "AQC13", "Marvell AQtion 10Gbit Network Adapter", ATL_FLAG_A2), + PCI_ROM(0x1D6A, 0x93C0, "AQC13", "Marvell AQtion 10Gbit Network Adapter", ATL_FLAG_A2), + PCI_ROM(0x1D6A, 0x04C0, "AQC13", "Marvell AQtion 10Gbit Network Adapter", ATL_FLAG_A2), + PCI_ROM(0x1D6A, 0x14C0, "AQC13", "Marvell AQtion 10Gbit Network Adapter", ATL_FLAG_A2), + PCI_ROM(0x1D6A, 0x12C0, "AQC13", "Marvell AQtion 10Gbit Network Adapter", ATL_FLAG_A2), +}; + +/** Marvell PCI driver */ +struct pci_driver atl_driver __pci_driver = { + .ids = atl_nics, + .id_count = (sizeof(atl_nics) / sizeof(atl_nics[0])), + .probe = atl_probe, + .remove = atl_remove, +}; \ No newline at end of file diff --git a/src/drivers/net/marvell/aqc1xx.h b/src/drivers/net/marvell/aqc1xx.h new file mode 100644 index 00000000..c3e34e1e --- /dev/null +++ b/src/drivers/net/marvell/aqc1xx.h @@ -0,0 +1,270 @@ +/** @file + * + * Marvell AQtion family network card driver definitions. + * + * Copyright(C) 2017-2021 Marvell + * + * SPDX-License-Identifier: BSD-2-Clause + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ +#ifndef _ATLANTIC_H +#define _ATLANTIC_H + +FILE_LICENCE ( BSD2 ); + +#include +#include +#include + +#define ATL_BAR_SIZE 0x10000 +#define ATL2_BAR_SIZE 0x40000 +#define ATL_RING_SIZE 64 +#define ATL_RING_ALIGN 128 +#define ATL_RX_MAX_LEN 2048 + +#define ATL_IRQ_TX 0x00000001U +#define ATL_IRQ_RX 0x00000002U + +/*IRQ Status Register*/ +#define ATL_IRQ_STAT_REG 0x00002000U + +/* Interrupt Vector Allocation Register */ +#define ATL_IRQ_CTRL 0x00002300U +#define ATL_IRQ_CTRL_COR_EN 0x00000080U /*IRQ clear on read */ +#define ATL_IRQ_CTRL_REG_RST_DIS 0x20000000U /*Register reset disable */ + +/*TX/RX Interruprt Mapping*/ +#define ATL_IRQ_MAP_REG1 0x00002100U /*IRQ mapping register */ + +#define ATL_IRQ_MAP_REG1_RX0_EN 0x00008000U /*IRQ RX0 enable*/ +#define ATL_IRQ_MAP_REG1_RX0 0x00000100U /*IRQ RX0*/ + +#define ATL_IRQ_MAP_REG1_TX0_EN 0x80000000U /*IRQ TX0 enable*/ +#define ATL_IRQ_MAP_REG1_TX0 0x00000000U /*IRQ TX0*/ + +/*TX interrupt ctrl reg*/ +#define ATL_TX_IRQ_CTRL 0x00007B40U +#define ATL_TX_IRQ_CTRL_WB_EN 0x00000002U + +/*RX interrupt ctrl reg*/ +#define ATL_RX_IRQ_CTRL 0x00005A30U +#define ATL_RX_IRQ_CTRL_WB_EN 0x00000004U + +#define ATL_GLB_CTRL 0x00000000U + +#define ATL_PCI_CTRL 0x00001000U +#define ATL_PCI_CTRL_RST_DIS 0x20000000U + +#define ATL_RX_CTRL 0x00005000U +#define ATL_RX_CTRL_RST_DIS 0x20000000U /*RPB reset disable */ +#define ATL_TX_CTRL 0x00007000U +#define ATL_TX_CTRL_RST_DIS 0x20000000U /*TPB reset disable */ + +/*RX data path control registers*/ +#define ATL_RPF2_CTRL 0x00005040U +#define ATL_RPF2_CTRL_EN 0x000F0000U /* RPF2 enable*/ +#define ATL2_RPF_NEW_EN_ADR_EN 0x00000001U /*enable*/ +#define ATL2_RPF_NEW_EN_ADR 0x5104 + +#define ATL_RPF_CTRL1 0x00005100U +#define ATL_RPF_CTRL1_BRC_EN 0x00000001U /*Allow broadcast receive*/ +#define ATL_RPF_CTRL1_L2_PROMISC 0x00000008U /*L2 promiscious*/ +#define ATL_RPF_CTRL1_ACTION 0x00001000U /*Action to host*/ +#define ATL_RPF_CTRL1_BRC_TSH 0x00010000U /*Brc threshold 256 units per sec*/ + +#define ATL_RPF_CTRL2 0x00005280U +#define ATL_RPF_CTRL2_VLAN_PROMISC 0x00000002U /*VLAN promisc*/ + +#define ATL_RPB_CTRL_DIS 0x0 +#define ATL_RPB_CTRL 0x00005700U +#define ATL_RPB_CTRL_EN 0x00000001U /*RPB Enable*/ +#define ATL_RPB_CTRL_FC 0x00000010U /*RPB Enable*/ +#define ATL_RPB_CTRL_TC_MODE 0x00000100U /*RPB Traffic Class Mode*/ + +#define ATL_RPB0_CTRL1 0x00005710U +#define ATL_RPB0_CTRL1_SIZE 0x00000140U /*RPB size (in unit 1KB) \*/ + +#define ATL_RPB0_CTRL2 0x00005714U + +/*Buffer Low Threshold (70% of RPB size in unit 32B)*/ +#define ATL_RPB0_CTRL2_LOW_TSH 0x00000C00U +/*Buffer High Threshold(30% of RPB size in unit 32B)*/ +#define ATL_RPB0_CTRL2_HIGH_TSH 0x1C000000U +#define ATL_RPB0_CTRL2_FC_EN 0x80000000U /*Flow control Enable*/ + +#define ATL_RX_DMA_DESC_BUF_SIZE 0x00005b18U +#define ATL_RX_DMA_DESC_ADDR 0x00005b00U + +/*TX data path control registers*/ +#define ATL_TPO2_CTRL 0x00007040U +#define ATL_TPO2_EN 0x00010000U /*TPO2 Enable*/ + +#define ATL_TPB_CTRL_DIS 0x0 +#define ATL_TPB_CTRL 0x00007900U +#define ATL_TPB_CTRL_EN 0x00000001U /*TPB enable*/ +#define ATL_TPB_CTRL_PAD_EN 0x00000004U /*Tx pad insert enable*/ +#define ATL_TPB_CTRL_TC_MODE 0x00000100U /*Tx traffic Class Mode*/ + +#define ATL_TPB0_CTRL1 0x00007910U +#define ATL_TPB0_CTRL1_SIZE 0x000000A0U /*TPB Size (in unit 1KB)*/ + +#define ATL_TPB0_CTRL2 0x00007914U +/*Buffer Low Threshold(30% of RPB size in unit 32B)*/ +#define ATL_TPB0_CTRL2_LOW_TSH 0x00000600U +/*Buffer High Threshold(30% of RPB size in unit 32B)*/ +#define ATL_TPB0_CTRL2_HIGH_TSH 0x0E000000U + +#define ATL_TX_DMA_DESC_ADDR 0x00007c00U + +/*Rings control registers*/ +#define ATL_RING_TX_CTRL 0x00007c08U +#define ATL_RING_TX_CTRL_EN 0x80000000U /*Tx descriptor Enable*/ + +#define ATL_RING_RX_CTRL 0x00005b08U +#define ATL_RING_RX_CTRL_EN 0x80000000U /*Rx descriptor Enable*/ + +#define ATL_RING_TAIL 0x00007c10U +#define ATL_RING_TAIL_PTR 0x00005b10U + +/*IRQ control registers*/ +#define ATL_ITR_MSKS_DIS 0x0 +#define ATL_ITR_MSKS 0x00002060U +#define ATL_ITR_MSKS_LSW 0x0000000CU +#define ATL_ITR_MSKC 0x00002070U +#define ATL_ITR_MSKC_LSW 0x0000000CU + +/*Link advertising*/ +#define ATL_LINK_ADV 0x00000368U +#define ATL_SHUT_LINK 0x0 +#define ATL_LINK_ADV_AUTONEG 0xF20U + +#define ATL_LINK_ST 0x00000370U + +/*Semaphores*/ +#define ATL_SEM_RAM 0x000003a8U +#define ATL_SEM_RAM_RESET 0X1 + +/*Mailbox*/ +#define ATL_MBOX_ADDR 0x00000360U +#define ATL_MBOX_CTRL1 0x00000200U +#define ATL_MBOX_CTRL1_START_MBOX_OPT 0x8000 + +#define ATL_MBOX_CTRL3 0x00000208U +#define ATL_MBOX_CTRL5 0x0000020cU + +#define ATL_FLAG_A1 0x1 +#define ATL_FLAG_A2 0x2 + +/*write register*/ +#define ATL_WRITE_REG(VAL, REG) writel(VAL, nic->regs + (REG)) +#define ATL_READ_REG(REG) readl(nic->regs + (REG)) /*read register*/ + +struct atl_desc_tx { + uint64_t address; + uint32_t status; + uint32_t flag; +} __attribute__((packed)); + +#define ATL_DESC_TX_DX_TYPE_VALUE 0x1 + +#define ATL_DESC_TX_DX_EOP_VALUE 0x1 +#define ATL_DESC_TX_EOP_MASK 0x00200000 +#define ATL_DESC_TX_EOP_OFFSET 21 + +#define ATL_DESC_TX_CMD_MASK 0x3FC00000UL +#define ATL_DESC_TX_CMD_OFFSET 22 +#define ATL_DESC_TX_CMD_VALUE 0x22 + +#define ATL_DESC_TX_BUF_LEN_MASK 0x000FFFF0 +#define ATL_DESC_TX_BUF_LEN_OFFSET 5 + +#define ATL_DESC_TX_PAY_LEN_MASK 0xFFFFC000 +#define ATL_DESC_TX_PAY_LEN_OFFSET 14 + +struct atl_desc_tx_wb { + uint64_t rsvd1; + uint32_t status; + uint32_t rsvd4; +} __attribute__((packed)); + +#define ATL_TX_DESC_STATUS_DD 0x00100000UL + +struct atl_desc_rx { + uint64_t data_addr; + uint64_t hdr_addr; + +} __attribute__((packed)); + +struct atl_desc_rx_wb { + uint64_t rsvd2; + uint16_t status; + uint16_t pkt_len; + uint32_t rsvd4; +} __attribute__((packed)); + +#define ATL_RX_DESC_STATUS_DD 0x0001UL +#define ATL_RX_DESC_STATUS_EOP 0x0002UL +struct atl_ring { + unsigned int sw_tail; + unsigned int sw_head; + void *ring; + /** Descriptor ring DMA mapping */ + struct dma_mapping map; + unsigned int length; +}; + +struct atl_nic; + +struct atl_hw_ops { + int (*reset) (struct atl_nic *nic); + int (*start) (struct atl_nic *nic); + int (*stop) (struct atl_nic *nic); + int (*get_link) (struct atl_nic *nic); + int (*get_mac) (struct atl_nic *, uint8_t *mac); +}; + +/** An aQuanita network card */ +struct atl_nic { + /** Registers */ + void *regs; + /** Port number (for multi-port devices) */ + unsigned int port; + /** DMA device */ + struct dma_device *dma; + /** Flags */ + unsigned int flags; + struct atl_ring tx_ring; + struct atl_ring rx_ring; + struct io_buffer *iobufs[ATL_RING_SIZE]; + uint32_t link_state; + uint32_t mbox_addr; + struct atl_hw_ops *hw_ops; +}; + +struct atl_hw_stats { + uint32_t version; + uint32_t tid; +}; + +#endif /* _AQUANTIA_H */ diff --git a/src/drivers/net/marvell/atl2_hw.c b/src/drivers/net/marvell/atl2_hw.c new file mode 100644 index 00000000..0c57a12f --- /dev/null +++ b/src/drivers/net/marvell/atl2_hw.c @@ -0,0 +1,235 @@ +/** @file + * + * Marvell AQtion family network card driver, hardware-specific functions. + * + * Copyright(C) 2017-2021 Marvell + * + * SPDX-License-Identifier: BSD-2-Clause + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO,THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +FILE_LICENCE ( BSD2 ); + +#include +#include +#include +#include +#include +#include "aqc1xx.h" +#include "atl2_hw.h" + +static int atl2_hw_boot_completed_ ( struct atl_nic *nic ) +{ + uint32_t reset_status = ATL_READ_REG ( ATL2_GLB_RST_CTRL2 ); + + return ( reset_status & ATL2_RESET_STATUS_BOOT_COMPLETED_MASK ) || + ( ATL_READ_REG ( ATL2_HOST_ITR_REQ ) + & ATL2_FW_HOST_INTERRUPT_REQUEST_READY ); +} + +void atl2_hw_read_shared_in_ ( struct atl_nic *nic, uint32_t offset, + uint32_t *data, uint32_t len ) +{ + uint32_t i; + + for (i = 0; i < len; ++i ) + { + data[i] = ATL_READ_REG ( ATL2_MIF_SHARED_BUF_IN + offset + i * 4 ); + } +} + +void atl2_hw_write_shared_in_ ( struct atl_nic *nic, uint32_t offset, + uint32_t *data, uint32_t len ) +{ + uint32_t i; + + for ( i = 0; i < len; ++i ) + { + ATL_WRITE_REG ( data[i], ATL2_MIF_SHARED_BUF_IN + offset + i * 4 ); + } +} + +int atl2_hw_finish_ack_ ( struct atl_nic *nic, uint32_t ms ) +{ + uint32_t i; + int err = 0; + + ATL_WRITE_REG ( ATL_READ_REG(ATL2_HOST_FINISHED_WRITE ) + | 1, ATL2_HOST_FINISHED_WRITE ); + + for ( i = 0; i < (ms / 100); ++i ) + { + if ( ( ATL_READ_REG(ATL2_MCP_BUSY_WRITE ) & 1 ) == 0 ) + { + break; + } + udelay ( ATL2_DELAY_100 ); + } + if (i == ( ms / 100 ) ) + err = -ETIME; + + return err; +} + +int atl2_hw_fw_init_ ( struct atl_nic *nic ) +{ + uint32_t val; + int err = 0; + + atl2_hw_read_shared_in_ ( nic, ATL2_LINK_CTRL_IN_OFF, &val, 1 ); + val |= ( ATL2_HOST_MODE_ACTIVE | ( 1U << 13 ) ); + atl2_hw_write_shared_in_ ( nic, ATL2_LINK_CTRL_IN_OFF, &val, 1 ); + + atl2_hw_read_shared_in_ ( nic, ATL2_MTU_IN_OFF, &val, 1 ); + val = 16352; + atl2_hw_write_shared_in_ ( nic, ATL2_MTU_IN_OFF, &val, 1 ); + + atl2_hw_read_shared_in_ ( nic, ATL2_LINK_OPTS_IN_OFF, &val, 1 ); + val = 0; + atl2_hw_write_shared_in_( nic, ATL2_LINK_OPTS_IN_OFF, &val, 1 ); + err = atl2_hw_finish_ack_ ( nic, 50000000 ); + + return err; +} + +int atl2_hw_reset ( struct atl_nic *nic ) +{ + int completed = 0; + uint32_t status = 0; + uint32_t request; + int err = 0; + int i; + + request = ATL2_RESET_STATUS_REQ_GSR; + + ATL_WRITE_REG ( request, ATL2_GLB_RST_CTRL2 ); + + /* Wait for boot code started every 10us, 200 ms */ + for ( i = 0; i < 20000; ++i ) + { + status = ATL_READ_REG ( ATL2_GLB_RST_CTRL2 ); + + if ( ( ( status & ATL2_RESET_STATUS_BC_STARTED ) && + (status != 0xFFFFFFFFu ) ) ) + break; + + udelay ( ATL2_DELAY_10 ); + } + if ( i == 20000 ) + { + DBGC ( nic, "Boot code hanged" ); + err = -EIO; + goto err_exit; + } + + /* Wait for boot succeed, failed or host request every 10us, 480ms */ + for ( i = 0; i < 48000; ++i ) + { + completed = atl2_hw_boot_completed_ ( nic ); + if ( completed ) + break; + + udelay ( ATL2_DELAY_10 ); + } + + if ( !completed ) + { + DBGC ( nic, "FW Restart timed out" ); + err = -ETIME; + goto err_exit; + } + + status = ATL_READ_REG ( ATL2_GLB_RST_CTRL2 ); + + if ( status & ATL2_RESET_STATUS_BOOT_FAILED_MASK ) + { + err = -EIO; + DBGC ( nic, "FW Restart failed" ); + DBGC ( nic, "status = 0x%x", status ); + goto err_exit; + } + + if ( ATL_READ_REG ( ATL2_HOST_ITR_REQ ) + & ATL2_FW_HOST_INTERRUPT_REQUEST_READY ) + { + err = -ENOTSUP; + DBGC ( nic, "Dynamic FW load not implemented" ); + goto err_exit; + } + + err = atl2_hw_fw_init_ ( nic ); + +err_exit: + return err; +} + +int atl2_hw_start ( struct atl_nic *nic ) +{ + uint32_t val; + + atl2_hw_read_shared_in_ ( nic, ATL2_LINK_OPTS_IN_OFF, &val, 1 ); + val = 0x4B00FFE1; + atl2_hw_write_shared_in_ ( nic, ATL2_LINK_OPTS_IN_OFF, &val, 1 ); + + return atl2_hw_finish_ack_ ( nic, 100000); +} + +int atl2_hw_stop ( struct atl_nic *nic ) +{ + uint32_t val; + + atl2_hw_read_shared_in_ ( nic, ATL2_LINK_OPTS_IN_OFF, &val, 1 ); + val = 0; + atl2_hw_write_shared_in_ ( nic, ATL2_LINK_OPTS_IN_OFF, &val, 1 ); + + return atl2_hw_finish_ack_ ( nic, 100000 ); +} + +int atl2_hw_get_link ( struct atl_nic *nic ) +{ + uint32_t val; + + val = ATL_READ_REG ( ATL2_MIF_SHARED_BUF_OUT + ATL2_LINK_STS_OUT_OFF ); + + return ( (val & 0xf) != 0) && ((val & 0xF0) != 0 ); +} + +int atl2_hw_get_mac ( struct atl_nic *nic, uint8_t *mac ) +{ + uint32_t mac_addr[2] = {0}; + + atl2_hw_read_shared_in_ ( nic, ATL2_MAC_ADDR_IN_OFF, mac_addr, 2 ); + + memcpy ( mac, (uint8_t *)mac_addr, 6 ); + + return 0; +} + +struct atl_hw_ops atl2_hw = { + .reset = atl2_hw_reset, + .start = atl2_hw_start, + .stop = atl2_hw_stop, + .get_link = atl2_hw_get_link, + .get_mac = atl2_hw_get_mac, +}; \ No newline at end of file diff --git a/src/drivers/net/marvell/atl2_hw.h b/src/drivers/net/marvell/atl2_hw.h new file mode 100644 index 00000000..ebd5466e --- /dev/null +++ b/src/drivers/net/marvell/atl2_hw.h @@ -0,0 +1,94 @@ +/* + * Copyright(C) 2017-2021 Marvell + * + * SPDX-License-Identifier: BSD-2-Clause + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO,THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#ifndef __ATL2_HW_H +#define __ATL2_HW_H + +FILE_LICENCE ( BSD2 ); + +#define ATL2_GLB_RST_CTRL2 0x3040 +#define ATL2_HOST_FINISHED_WRITE 0xE00 +#define ATL2_MCP_BUSY_WRITE 0xE04 +#define ATL2_HOST_ITR_REQ 0xF00 + + +#define ATL2_RESET_STATUS_REQ_GSR (1U << 0x0) +#define ATL2_RESET_STATUS_REQ_HOST_BOOT (1U << 0x8) +#define ATL2_RESET_STATUS_REQ_MAC_FAST_BOOT (1U << 0xA) +#define ATL2_RESET_STATUS_REQ_PHY_FAST_BOOT (1U << 0xB) + +#define ATL2_RESET_STATUS_HOST_LOAD_COMPLETED (1U << 0x10) +#define ATL2_RESET_STATUS_REQUIRE_HOST_LOAD (1U << 0x11) +#define ATL2_RESET_STATUS_BC_STARTED (1U << 0x18) +#define ATL2_RESET_STATUS_CRASH_DURING_INIT (1U << 0x1B) +#define ATL2_RESET_STATUS_BC_FAILED (1U << 0x1C) +#define ATL2_RESET_STATUS_FW_FAILED (1U << 0x1D) +#define ATL2_RESET_STATUS_FW_SUCCEED (1U << 0x1F) + +#define ATL2_RESET_STATUS_BOOT_FAILED_MASK (ATL2_RESET_STATUS_CRASH_DURING_INIT | ATL2_RESET_STATUS_BC_FAILED | ATL2_RESET_STATUS_FW_FAILED) +#define ATL2_RESET_STATUS_BOOT_COMPLETED_MASK (ATL2_RESET_STATUS_BOOT_FAILED_MASK | ATL2_RESET_STATUS_FW_SUCCEED) + +#define ATL2_FW_HOST_INTERRUPT_REQUEST_READY 0x0001 +#define ATL2_FW_HOST_INTERRUPT_MAC_READY 0x0004 +#define ATL2_FW_HOST_INTERRUPT_DATA_HANDLED 0x0100 +#define ATL2_FW_HOST_INTERRUPT_LINK_UP 0x0200 +#define ATL2_FW_HOST_INTERRUPT_LINK_DOWN 0x0400 +#define ATL2_FW_HOST_INTERRUPT_PHY_FAULT 0x0800 +#define ATL2_FW_HOST_INTERRUPT_MAC_FAULT 0x1000 +#define ATL2_FW_HOST_INTERRUPT_TEMPERATURE_WARNING 0x2000 +#define ATL2_FW_HOST_INTERRUPT_HEARTBEAT 0x4000 + +#define ATL2_FW_LINK_RATE_INVALID 0 +#define ATL2_FW_LINK_RATE_10M 1 +#define ATL2_FW_LINK_RATE_100M 2 +#define ATL2_FW_LINK_RATE_1G 3 +#define ATL2_FW_LINK_RATE_2G5 4 +#define ATL2_FW_LINK_RATE_5G 5 +#define ATL2_FW_LINK_RATE_10G 6 + +#define ATL2_HOST_MODE_INVALID 0U +#define ATL2_HOST_MODE_ACTIVE 1U +#define ATL2_HOST_MODE_SLEEP_PROXY 2U +#define ATL2_HOST_MODE_LOW_POWER 3U +#define ATL2_HOST_MODE_SHUTDOWN 4U + +#define ATL2_MIF_SHARED_BUF_IN 0x12000 +#define ATL2_MIF_SHARED_BUF_OUT 0x13000 + +#define ATL2_MTU_IN_OFF 0x0 +#define ATL2_MAC_ADDR_IN_OFF 0x8 +#define ATL2_LINK_CTRL_IN_OFF 0x10 +#define ATL2_LINK_OPTS_IN_OFF 0x18 + +#define ATL2_FW_OUT_OFF 0x8 +#define ATL2_LINK_STS_OUT_OFF 0x14 + +#define ATL2_DELAY_10 10 +#define ATL2_DELAY_100 100 + +#endif \ No newline at end of file diff --git a/src/drivers/net/marvell/atl_hw.c b/src/drivers/net/marvell/atl_hw.c new file mode 100644 index 00000000..2dddb718 --- /dev/null +++ b/src/drivers/net/marvell/atl_hw.c @@ -0,0 +1,321 @@ +/** @file + * + * Marvell AQtion family network card driver, hardware-specific functions. + * + * Copyright(C) 2017-2021 Marvell + * + * SPDX-License-Identifier: BSD-2-Clause + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO,THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +FILE_LICENCE ( BSD2 ); + +#include +#include +#include +#include +#include +#include "aqc1xx.h" +#include "atl_hw.h" +#include + + +int atl_hw_reset_flb_ ( struct atl_nic *nic ) +{ + uint32_t val; + int k = 0; + + ATL_WRITE_REG ( ATL_GLB_CTRL2_MBOX_ERR_UP_RUN_STALL, ATL_GLB_CTRL2 ); + mdelay ( ATL_DELAY_50_MNS ); + + /* Cleanup SPI */ + val = ATL_READ_REG ( ATL_GLB_NVR_PROV4 ); + ATL_WRITE_REG ( val | ATL_GBL_NVR_PROV4_RESET, ATL_GLB_NVR_PROV4 ); + + ATL_WRITE_REG( (ATL_READ_REG(ATL_GLB_STD_CTRL) & + ~ATL_GLB_CTRL_RST_DIS) | ATL_GLB_STD_CTRL_RESET, + ATL_GLB_STD_CTRL ); + + /* Kickstart MAC */ + ATL_WRITE_REG ( ATL_GLB_CTRL2_FW_RESET, ATL_GLB_CTRL2 ); + ATL_WRITE_REG ( ATL_MIF_PWR_GATING_EN_CTRL_RESET, + ATL_MIF_PWR_GATING_EN_CTRL ); + + ATL_WRITE_REG ( ATL_GEN_PROV9_ENABLE, ATL_GEN_PROV9 ); + + /* Reset SPI again because of possible interrupted SPI burst */ + val = ATL_READ_REG ( ATL_GLB_NVR_PROV4 ); + ATL_WRITE_REG ( val | ATL_GBL_NVR_PROV4_RESET, ATL_GLB_NVR_PROV4 ); + mdelay ( ATL_DELAY_10_MNS ); + /* Clear SPI reset state */ + ATL_WRITE_REG ( val & ~ATL_GBL_NVR_PROV4_RESET, ATL_GLB_NVR_PROV4 ); + + /* MAC Kickstart */ + ATL_WRITE_REG ( ATL_GLB_CTRL2_MAC_KICK_START, ATL_GLB_CTRL2 ); + + for (k = 0; k < 1000; k++) { + uint32_t flb_status = ATL_READ_REG ( ATL_MPI_DAISY_CHAIN_STS ); + + flb_status = flb_status & FLB_LOAD_STS; + if ( flb_status ) + break; + mdelay ( ATL_DELAY_10_MNS ); + } + if ( k == 1000 ) { + DBGC (nic, "MAC kickstart failed\n" ); + return -EIO; + } + + /* FW reset */ + ATL_WRITE_REG ( ATL_GLB_CTRL2_FW_RESET, ATL_GLB_CTRL2 ); + mdelay ( ATL_DELAY_50_MNS ); + + ATL_WRITE_REG ( ATL_GBL_MCP_SEM1_RELEASE, ATL_GLB_MCP_SEM1 ); + + /* Global software reset*/ + ATL_WRITE_REG ( ATL_READ_REG ( ATL_RX_CTRL ) & + ~ATL_RX_CTRL_RST_DIS, ATL_RX_CTRL ); + ATL_WRITE_REG ( ATL_READ_REG ( ATL_TX_CTRL ) & + ~ATL_TX_CTRL_RST_DIS, ATL_TX_CTRL ); + + ATL_WRITE_REG ( ATL_READ_REG ( ATL_MAC_PHY_CTRL ) & + ~ATL_MAC_PHY_CTRL_RST_DIS, ATL_MAC_PHY_CTRL ); + + ATL_WRITE_REG ( ( ATL_READ_REG ( ATL_GLB_STD_CTRL ) & + ~ATL_GLB_CTRL_RST_DIS) | ATL_GLB_STD_CTRL_RESET, + ATL_GLB_STD_CTRL ); + + for (k = 0; k < 1000; k++) { + u32 fw_state = ATL_READ_REG ( ATL_FW_VER ); + + if ( fw_state ) + break; + mdelay ( ATL_DELAY_10_MNS ); + } + if ( k == 1000 ) { + DBGC ( nic, "FW kickstart failed\n" ); + return -EIO; + } + /* Old FW requires fixed delay after init */ + mdelay ( ATL_DELAY_15_MNS ); + + return 0; +} + +int atl_hw_reset_rbl_ ( struct atl_nic *nic ) +{ + uint32_t val, rbl_status; + int k; + + ATL_WRITE_REG ( ATL_GLB_CTRL2_MBOX_ERR_UP_RUN_STALL, ATL_GLB_CTRL2 ); + ATL_WRITE_REG ( ATL_GBL_MCP_SEM1_RELEASE, ATL_GLB_MCP_SEM1 ); + ATL_WRITE_REG ( ATL_MIF_PWR_GATING_EN_CTRL_RESET, + ATL_MIF_PWR_GATING_EN_CTRL ); + + /* Alter RBL status */ + ATL_WRITE_REG ( POISON_SIGN, ATL_MPI_BOOT_EXIT_CODE ); + + /* Cleanup SPI */ + val = ATL_READ_REG ( ATL_GLB_NVR_PROV4 ); + ATL_WRITE_REG ( val | ATL_GBL_NVR_PROV4_RESET, ATL_GLB_NVR_PROV4 ); + + /* Global software reset*/ + ATL_WRITE_REG ( ATL_READ_REG(ATL_RX_CTRL) & ~ATL_RX_CTRL_RST_DIS, + ATL_RX_CTRL ); + ATL_WRITE_REG ( ATL_READ_REG(ATL_TX_CTRL) & ~ATL_TX_CTRL_RST_DIS, + ATL_TX_CTRL ); + ATL_WRITE_REG ( ATL_READ_REG(ATL_MAC_PHY_CTRL) & + ~ATL_MAC_PHY_CTRL_RST_DIS, ATL_MAC_PHY_CTRL ); + + ATL_WRITE_REG ( (ATL_READ_REG(ATL_GLB_STD_CTRL) & + ~ATL_GLB_CTRL_RST_DIS) | ATL_GLB_STD_CTRL_RESET, + ATL_GLB_STD_CTRL ); + + ATL_WRITE_REG ( ATL_GLB_CTRL2_MBOX_ERR_UP_RUN_NORMAL, ATL_GLB_CTRL2 ); + + /* Wait for RBL boot */ + for ( k = 0; k < 1000; k++ ) { + rbl_status = ATL_READ_REG ( ATL_MPI_BOOT_EXIT_CODE ) & 0xFFFF; + if ( rbl_status && rbl_status != POISON_SIGN ) + break; + mdelay ( ATL_DELAY_10_MNS ); + } + if ( !rbl_status || rbl_status == POISON_SIGN ) { + DBGC ( nic, "RBL Restart failed\n" ); + return -EIO; + } + + if ( rbl_status == FW_NOT_SUPPORT ) + return -ENOTSUP; + + for ( k = 0; k < 1000; k++ ) { + u32 fw_state = ATL_READ_REG ( ATL_FW_VER ); + + if ( fw_state ) + break; + mdelay ( ATL_DELAY_10_MNS ); + } + if ( k == 1000 ) { + DBGC ( nic, "FW kickstart failed\n" ); + return -EIO; + } + /* Old FW requires fixed delay after init */ + mdelay ( ATL_DELAY_15_MNS ); + + return 0; +} + +int atl_hw_reset ( struct atl_nic *nic ) +{ + uint32_t boot_exit_code = 0; + uint32_t k; + int rbl_enabled; + uint32_t fw_ver; + uint32_t sem_timeout; + + for ( k = 0; k < 1000; ++k ) { + uint32_t flb_status = ATL_READ_REG ( ATL_MPI_DAISY_CHAIN_STS ); + boot_exit_code = ATL_READ_REG ( ATL_MPI_BOOT_EXIT_CODE ); + if ( flb_status != ATL_MPI_DAISY_CHAIN_STS_ERROR_STATUS || + boot_exit_code != 0 ) + break; + } + + if ( k == 1000 ) { + DBGC ( nic, "Neither RBL nor FLB firmware started\n" ); + return -ENOTSUP; + } + + rbl_enabled = (boot_exit_code != 0); + + fw_ver = ATL_READ_REG ( ATL_FW_VER ); + if ( ((fw_ver >> 24) & 0xFF) >= 4 ) { + sem_timeout = ATL_READ_REG ( ATL_SEM_TIMEOUT ); + if ( sem_timeout > ATL_SEM_MAX_TIMEOUT ) + sem_timeout = ATL_SEM_MAX_TIMEOUT; + + for ( k = 0; k < sem_timeout; ++k ) { + if ( ATL_READ_REG ( ATL_GLB_MCP_SEM4) ) + break; + + mdelay (ATL_DELAY_1_MNS); + } + for ( k = 0; k < sem_timeout; ++k ) { + if (ATL_READ_REG ( ATL_GLB_MCP_SEM5) ) + break; + + mdelay ( ATL_DELAY_1_MNS ); + } + } + + + if ( rbl_enabled ) + return atl_hw_reset_rbl_ ( nic ); + else + return atl_hw_reset_flb_ ( nic ); +} + +int atl_hw_start ( struct atl_nic *nic ) +{ + ATL_WRITE_REG ( ATL_LINK_ADV_AUTONEG, ATL_LINK_ADV ); + return 0; +} + +int atl_hw_stop ( struct atl_nic *nic ) +{ + ATL_WRITE_REG ( ATL_SHUT_LINK, ATL_LINK_ADV ); + return 0; +} + +int atl_hw_get_link ( struct atl_nic *nic ) +{ + return ( ATL_READ_REG ( ATL_LINK_ST) & ATL_LINK_ADV_AUTONEG ) != 0; +} + +int atl_hw_read_mem ( struct atl_nic *nic, uint32_t addr, uint32_t *buffer, + uint32_t size ) +{ + uint32_t i; + + for ( i = 0; i < 100; ++i ) { + if ( ATL_READ_REG( ATL_SEM_RAM) ) + break; + mdelay ( ATL_DELAY_1_MNS ); + } + if ( i == 100 ) { + DBGC (nic, "Semaphore Register not set\n" ); + return -EIO; + } + + ATL_WRITE_REG ( addr, ATL_MBOX_CTRL3 ); + + for ( i = 0; i < size; ++i, addr += 4 ) { + uint32_t j; + + ATL_WRITE_REG ( ATL_MBOX_CTRL1_START_MBOX_OPT, ATL_MBOX_CTRL1 ); + for ( j = 0; j < 10000; ++j ) { + if ( ATL_READ_REG (ATL_MBOX_CTRL3 ) != addr ) + break; + udelay ( ATL_DELAY_10_MNS ); + } + if ( j == 10000 ) { + DBGC (nic, "Reading from CTRL3 Register Failed\n" ); + return -EIO; + } + + buffer[i] = ATL_READ_REG ( ATL_MBOX_CTRL5 ); + } + + ATL_WRITE_REG( ATL_SEM_RAM_RESET, ATL_SEM_RAM ); + + return 0; +} + +int atl_hw_get_mac ( struct atl_nic *nic, uint8_t *mac ) +{ + uint32_t mac_addr[2] = {0}; + int err = 0; + uint32_t efuse_addr = ATL_READ_REG ( ATL_GLB_MCP_SP26 ); + + if ( efuse_addr != 0) { + uint32_t mac_efuse_addr = efuse_addr + 40 * sizeof(uint32_t); + err = atl_hw_read_mem ( nic, mac_efuse_addr, mac_addr, 2 ); + if ( err != 0 ) + return err; + + mac_addr[0] = cpu_to_be32 ( mac_addr[0] ); + mac_addr[1] = cpu_to_be32 ( mac_addr[1] ); + + memcpy ( mac, (uint8_t *)mac_addr, ATL_MAC_ADDRESS_SIZE ); + } + return 0; +} + +struct atl_hw_ops atl_hw = { + .reset = atl_hw_reset, + .start = atl_hw_start, + .stop = atl_hw_stop, + .get_link = atl_hw_get_link, + .get_mac = atl_hw_get_mac, +}; \ No newline at end of file diff --git a/src/drivers/net/marvell/atl_hw.h b/src/drivers/net/marvell/atl_hw.h new file mode 100644 index 00000000..0a20fbfc --- /dev/null +++ b/src/drivers/net/marvell/atl_hw.h @@ -0,0 +1,83 @@ +/* + * Copyright(C) 2017-2021 Marvell + * + * SPDX-License-Identifier: BSD-2-Clause + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO,THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ +#ifndef __ATL_HW_H +#define __ATL_HW_H + +FILE_LICENCE ( BSD2 ); + +#define ATL_GLB_STD_CTRL 0x0 +#define ATL_GLB_CTRL_RST_DIS 0x4000 +#define ATL_FW_VER 0x18 + +#define ATL_MPI_DAISY_CHAIN_STS 0x704 +#define ATL_MPI_RX_DAISY_CHAIN_DATA 0x04000000 +#define ATL_MPI_RX_DAISY_CHAIN_SOF 0x02000000 +#define FLB_LOAD_STS 0x10 + +#define ATL_MPI_BOOT_EXIT_CODE 0x388 + +#define ATL_SEM_TIMEOUT 0x348 +#define ATL_SEM_MAX_TIMEOUT 3000 + +#define ATL_GLB_CTRL2 0x404 +#define ATL_GLB_MCP_SEM1 0x3A0 +#define ATL_GBL_MCP_SEM1_RELEASE 0x1 + +#define ATL_GLB_MCP_SEM4 0x3AC +#define ATL_GLB_MCP_SEM5 0x3B0 +#define ATL_GLB_MCP_SP26 0x364 +#define ATL_MIF_PWR_GATING_EN_CTRL 0x32A8 + +#define ATL_GLB_NVR_PROV4 0x53C +#define ATL_GBL_NVR_PROV4_RESET 0x10 + + +#define ATL_GEN_PROV9 0x520 + +#define ATL_MAC_PHY_CTRL 0x00004000U +#define ATL_MAC_PHY_CTRL_RST_DIS 0x20000000U + +#define ATL_MIF_PWR_GATING_EN_CTRL_RESET 0x0 +#define ATL_GEN_PROV9_ENABLE 0x1 +#define ATL_GLB_CTRL2_MAC_KICK_START 0x180e0 +#define ATL_GLB_CTRL2_FW_RESET 0x80e0 +#define ATL_GLB_CTRL2_MBOX_ERR_UP_RUN_STALL 0x40e1 +#define ATL_GLB_CTRL2_MBOX_ERR_UP_RUN_NORMAL 0x40e0 +#define ATL_GLB_STD_CTRL_RESET 0x8000 +#define ATL_MPI_DAISY_CHAIN_STS_ERROR_STATUS 0x06000000 + +#define ATL_DELAY_1_MNS 1 +#define ATL_DELAY_10_MNS 10 +#define ATL_DELAY_15_MNS 15 +#define ATL_DELAY_50_MNS 50 + +#define ATL_MAC_ADDRESS_SIZE 6 +#define POISON_SIGN 0xDEAD +#define FW_NOT_SUPPORT 0xF1A7 + +#endif diff --git a/src/include/ipxe/errfile.h b/src/include/ipxe/errfile.h index 320835a3..9df99d91 100644 --- a/src/include/ipxe/errfile.h +++ b/src/include/ipxe/errfile.h @@ -219,6 +219,10 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #define ERRFILE_ice ( ERRFILE_DRIVER | 0x00d20000 ) #define ERRFILE_ecam ( ERRFILE_DRIVER | 0x00d30000 ) #define ERRFILE_pcibridge ( ERRFILE_DRIVER | 0x00d40000 ) +#define ERRFILE_aqc1xx ( ERRFILE_DRIVER | 0x00d50000 ) +#define ERRFILE_atl_hw ( ERRFILE_DRIVER | 0x00d60000 ) +#define ERRFILE_atl2_hw ( ERRFILE_DRIVER | 0x00d70000 ) + #define ERRFILE_aoe ( ERRFILE_NET | 0x00000000 ) #define ERRFILE_arp ( ERRFILE_NET | 0x00010000 ) -- cgit v1.2.3-55-g7522 From 115707c0edebad65f87525fed583fef73880016d Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Tue, 24 Oct 2023 11:43:56 +0100 Subject: [iphone] Add missing va_start()/va_end() around reused argument list The ipair_tx() function uses a va_list twice (first to calculate the formatted string length before allocation, then to construct the string in the allocated buffer) but is missing the va_start() and va_end() around the second usage. This is undefined behaviour that happens to work on some build platforms. Fix by adding the missing va_start() and va_end() around the second usage of the variadic argument list. Reported-by: Andreas Hammarskjöld Signed-off-by: Michael Brown --- src/drivers/net/iphone.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/drivers/net/iphone.c b/src/drivers/net/iphone.c index 7d0eb4b6..bbac527b 100644 --- a/src/drivers/net/iphone.c +++ b/src/drivers/net/iphone.c @@ -1304,7 +1304,9 @@ ipair_tx ( struct ipair *ipair, const char *fmt, ... ) { memset ( hdr, 0, sizeof ( *hdr ) ); hdr->len = htonl ( len ); msg = iob_put ( iobuf, len ); + va_start ( args, fmt ); vsnprintf ( msg, len, fmt, args ); + va_end ( args ); DBGC2 ( ipair, "IPAIR %p transmitting:\n%s\n", ipair, msg ); /* Transmit message */ -- cgit v1.2.3-55-g7522 From f883203132b3d06ffb354f1b11d1f65a0c70ff42 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Wed, 1 Nov 2023 22:03:34 +0000 Subject: [pci] Force completion of ECAM configuration space writes The PCIe specification requires that "processor and host bridge implementations must ensure that a method exists for the software to determine when the write using the ECAM is completed by the completer" but does not specify any particular method to be used. Some platforms might treat writes to the ECAM region as non-posted, others might require reading back from a dedicated (and implementation-specific) completion register to determine when the configuration space write has completed. Since PCI configuration space writes will never be used for any performance-critical datapath operations (on any sane hardware), a simple and platform-independent solution is to always read back from the written register in order to guarantee that the write must have completed. This is safe to do, since the PCIe specification defines a limited set of configuration register types, none of which have read side effects. Signed-off-by: Michael Brown --- src/drivers/bus/ecam.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/drivers/bus/ecam.c b/src/drivers/bus/ecam.c index 1d57bd2a..376f3495 100644 --- a/src/drivers/bus/ecam.c +++ b/src/drivers/bus/ecam.c @@ -235,7 +235,7 @@ int ecam_write ( struct pci_device *pci, unsigned int location, if ( ( rc = ecam_access ( pci ) ) != 0 ) return rc; - /* Read from address */ + /* Write to address */ index = ( pci->busdevfn - ecam.range.start ); addr = ( ecam.regs + ( index * ECAM_SIZE ) + where ); switch ( len ) { @@ -252,6 +252,15 @@ int ecam_write ( struct pci_device *pci, unsigned int location, assert ( 0 ); } + /* Read from address, to guarantee completion of the write + * + * PCIe configuration space registers may not have read side + * effects. Reading back is therefore always safe to do, and + * guarantees that the write has reached the device. + */ + mb(); + ecam_read ( pci, location, &value ); + return 0; } -- cgit v1.2.3-55-g7522 From 74ec00a9f336152fccf8df9cc9c5a46ab1a649b4 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Thu, 2 Nov 2023 15:05:15 +0000 Subject: [pci] Handle non-zero starting bus in ECAM allocations The base address provided in the PCI ECAM allocation within the ACPI MCFG table is the base address for the segment as a whole, not for the starting bus within that allocation. On machines that provide ECAM allocations with a non-zero starting bus number (observed with an AWS EC2 m7a.large instance), this will result in iPXE accessing the wrong memory addresses within the ECAM region. Fix by adding the appropriate starting bus offset to the base address. Signed-off-by: Michael Brown --- src/drivers/bus/ecam.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/drivers/bus/ecam.c b/src/drivers/bus/ecam.c index 376f3495..dd3e1e51 100644 --- a/src/drivers/bus/ecam.c +++ b/src/drivers/bus/ecam.c @@ -150,6 +150,7 @@ static int ecam_access ( struct pci_device *pci ) { /* Map configuration space for this allocation */ base = le64_to_cpu ( ecam.alloc.base ); + base += ( ecam.alloc.start * ECAM_SIZE * PCI_BUSDEVFN ( 0, 1, 0, 0 ) ); len = ( ecam.range.count * ECAM_SIZE ); ecam.regs = ioremap ( base, len ); if ( ! ecam.regs ) { -- cgit v1.2.3-55-g7522 From 1f3a37e342ff110a451afcdf15c75a90e643208d Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Thu, 2 Nov 2023 15:16:19 +0000 Subject: [pci] Cache ECAM mapping errors When an error occurs during ECAM configuration space mapping, preserve the error within the existing cached mapping (instead of invalidating the cached mapping) in order to avoid flooding the debug log with repeated identical mapping errors. Signed-off-by: Michael Brown --- src/drivers/bus/ecam.c | 6 ++++-- src/include/ipxe/ecam.h | 2 ++ 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/drivers/bus/ecam.c b/src/drivers/bus/ecam.c index dd3e1e51..62baebee 100644 --- a/src/drivers/bus/ecam.c +++ b/src/drivers/bus/ecam.c @@ -127,7 +127,7 @@ static int ecam_access ( struct pci_device *pci ) { /* Reuse mapping if possible */ if ( ( pci->busdevfn - ecam.range.start ) < ecam.range.count ) - return 0; + return ecam.rc; /* Clear any existing mapping */ if ( ecam.regs ) { @@ -145,6 +145,7 @@ static int ecam_access ( struct pci_device *pci ) { if ( ecam.range.start > pci->busdevfn ) { DBGC ( &ecam, "ECAM found no allocation for " PCI_FMT "\n", PCI_ARGS ( pci ) ); + rc = -ENOENT; goto err_find; } @@ -165,12 +166,13 @@ static int ecam_access ( struct pci_device *pci ) { DBGC ( &ecam, "ECAM %04x:[%02x-%02x] mapped [%08llx,%08llx) -> %p\n", le16_to_cpu ( ecam.alloc.segment ), ecam.alloc.start, ecam.alloc.end, base, ( base + len ), ecam.regs ); + ecam.rc = 0; return 0; iounmap ( ecam.regs ); err_ioremap: err_find: - ecam.range.count = 0; + ecam.rc = rc; return rc; } diff --git a/src/include/ipxe/ecam.h b/src/include/ipxe/ecam.h index 683d613a..ff08aee5 100644 --- a/src/include/ipxe/ecam.h +++ b/src/include/ipxe/ecam.h @@ -50,6 +50,8 @@ struct ecam_mapping { struct pci_range range; /** MMIO base address */ void *regs; + /** Mapping result */ + int rc; }; extern struct pci_api ecam_api; -- cgit v1.2.3-55-g7522 From 36e1a559a28ea9d62eb1f6cde4df8fda3999525e Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Thu, 2 Nov 2023 15:38:08 +0000 Subject: [pci] Check that ECAM configuration space is within reachable memory Some machines (observed with an AWS EC2 m7a.large instance) will place the ECAM configuration space window above 4GB, thereby making it unreachable from non-paged 32-bit code. This problem is currently ignored by iPXE, since the address is silently truncated in the call to ioremap(). (Note that other uses of ioremap() are not affected since the PCI core will already have checked for unreachable 64-bit BARs when retrieving the physical address to be mapped.) Fix by adding an explicit check that the region to be mapped starts within the reachable memory address space. (Assume that no machines will be sufficiently peverse to provide a region that straddles the 4GB boundary.) Signed-off-by: Michael Brown --- src/drivers/bus/ecam.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/drivers/bus/ecam.c b/src/drivers/bus/ecam.c index 62baebee..5e3debdd 100644 --- a/src/drivers/bus/ecam.c +++ b/src/drivers/bus/ecam.c @@ -153,6 +153,14 @@ static int ecam_access ( struct pci_device *pci ) { base = le64_to_cpu ( ecam.alloc.base ); base += ( ecam.alloc.start * ECAM_SIZE * PCI_BUSDEVFN ( 0, 1, 0, 0 ) ); len = ( ecam.range.count * ECAM_SIZE ); + if ( base != ( ( unsigned long ) base ) ) { + DBGC ( &ecam, "ECAM %04x:[%02x-%02x] could not map " + "[%08llx,%08llx) outside CPU range\n", + le16_to_cpu ( ecam.alloc.segment ), ecam.alloc.start, + ecam.alloc.end, base, ( base + len ) ); + rc = -ERANGE; + goto err_range; + } ecam.regs = ioremap ( base, len ); if ( ! ecam.regs ) { DBGC ( &ecam, "ECAM %04x:[%02x-%02x] could not map " @@ -171,6 +179,7 @@ static int ecam_access ( struct pci_device *pci ) { iounmap ( ecam.regs ); err_ioremap: + err_range: err_find: ecam.rc = rc; return rc; -- cgit v1.2.3-55-g7522 From 5524bb98328dd1b16037916498b0f91e0200a87c Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Thu, 2 Nov 2023 16:11:38 +0000 Subject: [pci] Require discovery of a PCI device when determining usable PCI APIs The PCI cloud API (PCIAPI_CLOUD) currently selects the first PCI API that successfully discovers a PCI device address range. The ECAM API may discover an address range but subsequently be unable to map the configuration space region, which would result in the selected PCI API being unusable. Fix by instead selecting the first PCI API that can be successfully used to discover a PCI device. Signed-off-by: Michael Brown --- src/arch/x86/interface/pcbios/pcicloud.c | 25 ++++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/src/arch/x86/interface/pcbios/pcicloud.c b/src/arch/x86/interface/pcbios/pcicloud.c index 97d7cac1..98ba38b3 100644 --- a/src/arch/x86/interface/pcbios/pcicloud.c +++ b/src/arch/x86/interface/pcbios/pcicloud.c @@ -165,24 +165,27 @@ static void pcicloud_init ( void ) { static struct pci_api *apis[] = { &ecam_api, &pcibios_api, &pcidirect_api }; - struct pci_range range; + struct pci_device pci; + uint32_t busdevfn; unsigned int i; + int rc; - /* Select first API that successfully discovers an address range */ + /* Select first API that successfully discovers a PCI device */ for ( i = 0 ; i < ( sizeof ( apis ) / sizeof ( apis[0] ) ) ; i++ ) { pcicloud = apis[i]; - pcicloud_discover ( 0, &range ); - if ( range.count != 0 ) { - DBGC ( pcicloud, "PCICLOUD selected %s API\n", - pcicloud->name ); - break; + busdevfn = 0; + if ( ( rc = pci_find_next ( &pci, &busdevfn ) ) == 0 ) { + DBGC ( pcicloud, "PCICLOUD selected %s API (found " + PCI_FMT ")\n", pcicloud->name, + PCI_ARGS ( &pci ) ); + return; } } - /* The PCI direct API can never fail discovery since the range - * is hardcoded. - */ - assert ( range.count != 0 ); + /* Fall back to using final attempted API if no devices found */ + pcicloud = apis[ i - 1 ]; + DBGC ( pcicloud, "PCICLOUD selected %s API (nothing detected)\n", + pcicloud->name ); } /** Cloud VM PCI configuration space access initialisation function */ -- cgit v1.2.3-55-g7522 From 1bd01b761f1f33723f0b07d277863b3284dfe232 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Tue, 7 Nov 2023 11:08:33 +0000 Subject: [eapol] Delay EAPoL-Start while waiting for EAP to complete EAP exchanges may take a long time to reach a final status, especially when relying upon MAC Authentication Bypass (MAB). Our current behaviour of sending EAPoL-Start every few seconds until a final status is obtained can prevent these exchanges from ever completing. Fix by redefining the EAP supplicant state to allow EAPoL-Start to be suppressed: either temporarily (while waiting for a full EAP exchange to complete, in which case we need to eventually resend EAPoL-Start if the final Success or Failure packet is lost), or permanently (while waiting for the potentially very long MAC Authentication Bypass timeout period). Signed-off-by: Michael Brown --- src/include/ipxe/eap.h | 41 +++++++++++++++++++++++++--- src/net/eap.c | 15 +++++++---- src/net/eapol.c | 72 +++++++++++++++++++++++++------------------------- 3 files changed, 84 insertions(+), 44 deletions(-) diff --git a/src/include/ipxe/eap.h b/src/include/ipxe/eap.h index e5f60655..818862a9 100644 --- a/src/include/ipxe/eap.h +++ b/src/include/ipxe/eap.h @@ -51,7 +51,7 @@ union eap_packet { struct eap_request req; }; -/** Link block timeout +/** EAP link block timeout * * We mark the link as blocked upon receiving a Request-Identity, on * the basis that this most likely indicates that the switch will not @@ -64,12 +64,30 @@ union eap_packet { */ #define EAP_BLOCK_TIMEOUT ( 45 * TICKS_PER_SEC ) +/** EAP protocol wait timeout + * + * In the EAP model, the supplicant is a pure responder. The model + * also defines no acknowledgement response for the final Success or + * Failure "requests". This leaves open the possibility that the + * final Success or Failure packet is lost, with the supplicant having + * no way to determine the final authentication status. + * + * Sideband mechanisms such as EAPoL-Start may be used to restart the + * entire EAP process, as a (crude) workaround for this protocol flaw. + * When expecting to receive a further EAP request (e.g. an + * authentication challenge), we may wait for some length of time + * before triggering this restart. Choose a duration that is shorter + * than the link block timeout, so that there is no period during + * which we erroneously leave the link marked as not blocked. + */ +#define EAP_WAIT_TIMEOUT ( EAP_BLOCK_TIMEOUT * 7 / 8 ) + /** An EAP supplicant */ struct eap_supplicant { /** Network device */ struct net_device *netdev; - /** Authentication outcome is final */ - int done; + /** Flags */ + unsigned int flags; /** * Transmit EAP response * @@ -82,6 +100,23 @@ struct eap_supplicant { const void *data, size_t len ); }; +/** EAP authentication is in progress + * + * This indicates that we have received an EAP Request-Identity, but + * have not yet received a final EAP Success or EAP Failure. + */ +#define EAP_FL_ONGOING 0x0001 + +/** EAP supplicant is passive + * + * This indicates that the supplicant should not transmit any futher + * unsolicited packets (e.g. EAPoL-Start for a supplicant running over + * EAPoL). This could be because authentication has already + * completed, or because we are relying upon MAC Authentication Bypass + * (MAB) which may have a very long timeout. + */ +#define EAP_FL_PASSIVE 0x0002 + extern int eap_rx ( struct eap_supplicant *supplicant, const void *data, size_t len ); diff --git a/src/net/eap.c b/src/net/eap.c index beaeb61d..2c68b75d 100644 --- a/src/net/eap.c +++ b/src/net/eap.c @@ -47,6 +47,14 @@ static int eap_rx_request_identity ( struct eap_supplicant *supplicant ) { netdev->name ); netdev_link_block ( netdev, EAP_BLOCK_TIMEOUT ); + /* Mark EAP as in progress */ + supplicant->flags |= EAP_FL_ONGOING; + + /* We have no identity to offer, so wait until the switch + * times out and switches to MAC Authentication Bypass (MAB). + */ + supplicant->flags |= EAP_FL_PASSIVE; + return 0; } @@ -69,9 +77,6 @@ static int eap_rx_request ( struct eap_supplicant *supplicant, return -EINVAL; } - /* Mark authentication as incomplete */ - supplicant->done = 0; - /* Handle according to type */ switch ( req->type ) { case EAP_TYPE_IDENTITY: @@ -94,7 +99,7 @@ static int eap_rx_success ( struct eap_supplicant *supplicant ) { struct net_device *netdev = supplicant->netdev; /* Mark authentication as complete */ - supplicant->done = 1; + supplicant->flags = EAP_FL_PASSIVE; /* Mark link as unblocked */ DBGC ( netdev, "EAP %s Success\n", netdev->name ); @@ -113,7 +118,7 @@ static int eap_rx_failure ( struct eap_supplicant *supplicant ) { struct net_device *netdev = supplicant->netdev; /* Mark authentication as complete */ - supplicant->done = 1; + supplicant->flags = EAP_FL_PASSIVE; /* Record error */ DBGC ( netdev, "EAP %s Failure\n", netdev->name ); diff --git a/src/net/eapol.c b/src/net/eapol.c index 1b843e89..ce7be55d 100644 --- a/src/net/eapol.c +++ b/src/net/eapol.c @@ -48,37 +48,6 @@ static const uint8_t eapol_mac[ETH_ALEN] = { 0x01, 0x80, 0xc2, 0x00, 0x00, 0x03 }; -/** - * Update EAPoL supplicant state - * - * @v supplicant EAPoL supplicant - * @v timeout Timer ticks until next EAPoL-Start (if applicable) - */ -static void eapol_update ( struct eapol_supplicant *supplicant, - unsigned long timeout ) { - struct net_device *netdev = supplicant->eap.netdev; - - /* Check device and EAP state */ - if ( netdev_is_open ( netdev ) && netdev_link_ok ( netdev ) ) { - if ( supplicant->eap.done ) { - - /* EAP has completed: stop sending EAPoL-Start */ - stop_timer ( &supplicant->timer ); - - } else if ( ! timer_running ( &supplicant->timer ) ) { - - /* EAP has not yet begun: start sending EAPoL-Start */ - start_timer_fixed ( &supplicant->timer, timeout ); - } - - } else { - - /* Not ready: clear completion and stop sending EAPoL-Start */ - supplicant->eap.done = 0; - stop_timer ( &supplicant->timer ); - } -} - /** * Process EAPoL packet * @@ -186,8 +155,19 @@ static int eapol_eap_rx ( struct eapol_supplicant *supplicant, goto drop; } - /* Update supplicant state */ - eapol_update ( supplicant, EAPOL_START_INTERVAL ); + /* Update EAPoL-Start transmission timer */ + if ( supplicant->eap.flags & EAP_FL_PASSIVE ) { + /* Stop sending EAPoL-Start */ + if ( timer_running ( &supplicant->timer ) ) { + DBGC ( netdev, "EAPOL %s becoming passive\n", + netdev->name ); + } + stop_timer ( &supplicant->timer ); + } else if ( supplicant->eap.flags & EAP_FL_ONGOING ) { + /* Delay EAPoL-Start until after next expected packet */ + DBGC ( netdev, "EAPOL %s deferring Start\n", netdev->name ); + start_timer_fixed ( &supplicant->timer, EAP_WAIT_TIMEOUT ); + } drop: free_iob ( iobuf ); @@ -309,15 +289,35 @@ static int eapol_probe ( struct net_device *netdev, void *priv ) { * @v netdev Network device * @v priv Private data */ -static void eapol_notify ( struct net_device *netdev __unused, void *priv ) { +static void eapol_notify ( struct net_device *netdev, void *priv ) { struct eapol_supplicant *supplicant = priv; /* Ignore non-EAPoL devices */ if ( ! supplicant->eap.netdev ) return; - /* Update supplicant state */ - eapol_update ( supplicant, 0 ); + /* Terminate and reset EAP when link goes down */ + if ( ! ( netdev_is_open ( netdev ) && netdev_link_ok ( netdev ) ) ) { + if ( timer_running ( &supplicant->timer ) ) { + DBGC ( netdev, "EAPOL %s shutting down\n", + netdev->name ); + } + supplicant->eap.flags = 0; + stop_timer ( &supplicant->timer ); + return; + } + + /* Do nothing if EAP is already in progress */ + if ( timer_running ( &supplicant->timer ) ) + return; + + /* Do nothing if EAP has already finished transmitting */ + if ( supplicant->eap.flags & EAP_FL_PASSIVE ) + return; + + /* Otherwise, start sending EAPoL-Start */ + start_timer_nodelay ( &supplicant->timer ); + DBGC ( netdev, "EAPOL %s starting up\n", netdev->name ); } /** EAPoL driver */ -- cgit v1.2.3-55-g7522 From 595b1796f6dc980cf27ca3883cde3baa23655528 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Tue, 7 Nov 2023 13:50:15 +0000 Subject: [eapol] Limit number of EAPoL-Start packets transmitted per attempt Signed-off-by: Michael Brown --- src/include/ipxe/eapol.h | 5 +++++ src/net/eapol.c | 8 ++++++++ 2 files changed, 13 insertions(+) diff --git a/src/include/ipxe/eapol.h b/src/include/ipxe/eapol.h index d4ea3920..dcf39294 100644 --- a/src/include/ipxe/eapol.h +++ b/src/include/ipxe/eapol.h @@ -42,11 +42,16 @@ struct eapol_supplicant { struct eap_supplicant eap; /** EAPoL-Start retransmission timer */ struct retry_timer timer; + /** EAPoL-Start transmission count */ + unsigned int count; }; /** Delay between EAPoL-Start packets */ #define EAPOL_START_INTERVAL ( 2 * TICKS_PER_SEC ) +/** Maximum number of EAPoL-Start packets to transmit */ +#define EAPOL_START_COUNT 3 + /** An EAPoL handler */ struct eapol_handler { /** Type */ diff --git a/src/net/eapol.c b/src/net/eapol.c index ce7be55d..8b09ca23 100644 --- a/src/net/eapol.c +++ b/src/net/eapol.c @@ -167,6 +167,7 @@ static int eapol_eap_rx ( struct eapol_supplicant *supplicant, /* Delay EAPoL-Start until after next expected packet */ DBGC ( netdev, "EAPOL %s deferring Start\n", netdev->name ); start_timer_fixed ( &supplicant->timer, EAP_WAIT_TIMEOUT ); + supplicant->count = 0; } drop: @@ -250,6 +251,12 @@ static void eapol_expired ( struct retry_timer *timer, int fail __unused ) { container_of ( timer, struct eapol_supplicant, timer ); struct net_device *netdev = supplicant->eap.netdev; + /* Stop transmitting after maximum number of attempts */ + if ( supplicant->count++ >= EAPOL_START_COUNT ) { + DBGC ( netdev, "EAPOL %s giving up\n", netdev->name ); + return; + } + /* Schedule next transmission */ start_timer_fixed ( timer, EAPOL_START_INTERVAL ); @@ -317,6 +324,7 @@ static void eapol_notify ( struct net_device *netdev, void *priv ) { /* Otherwise, start sending EAPoL-Start */ start_timer_nodelay ( &supplicant->timer ); + supplicant->count = 0; DBGC ( netdev, "EAPOL %s starting up\n", netdev->name ); } -- cgit v1.2.3-55-g7522 From d8f9c221ede6d67a251134989a30bb850f8709e6 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Tue, 7 Nov 2023 15:54:59 +0000 Subject: [cloud] Add ability to overwrite existing AMI images AMI names must be unique within a region. Add a --overwrite option that allows an existing AMI of the same name to be deregistered (and its underlying snapshot deleted). Signed-off-by: Michael Brown --- contrib/cloud/aws-import | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/contrib/cloud/aws-import b/contrib/cloud/aws-import index b9a350f6..ace00587 100755 --- a/contrib/cloud/aws-import +++ b/contrib/cloud/aws-import @@ -46,11 +46,19 @@ def create_snapshot(region, description, image): return snapshot_id -def import_image(region, name, architecture, image, public): +def import_image(region, name, architecture, image, public, overwrite): """Import an AMI image""" client = boto3.client('ec2', region_name=region) resource = boto3.resource('ec2', region_name=region) description = '%s (%s)' % (name, architecture) + images = client.describe_images(Filters=[{'Name': 'name', + 'Values': [description]}]) + if overwrite and images['Images']: + images = images['Images'][0] + image_id = images['ImageId'] + snapshot_id = images['BlockDeviceMappings'][0]['Ebs']['SnapshotId'] + resource.Image(image_id).deregister() + resource.Snapshot(snapshot_id).delete() snapshot_id = create_snapshot(region=region, description=description, image=image) client.get_waiter('snapshot_completed').wait(SnapshotIds=[snapshot_id]) @@ -88,6 +96,8 @@ parser.add_argument('--name', '-n', help="Image name") parser.add_argument('--public', '-p', action='store_true', help="Make image public") +parser.add_argument('--overwrite', action='store_true', + help="Overwrite any existing image with same name") parser.add_argument('--region', '-r', action='append', help="AWS region(s)") parser.add_argument('--wiki', '-w', metavar='FILE', @@ -115,7 +125,8 @@ with ThreadPoolExecutor(max_workers=len(imports)) as executor: name=args.name, architecture=architectures[image], image=image, - public=args.public): (region, image) + public=args.public, + overwrite=args.overwrite): (region, image) for region, image in imports} results = {futures[future]: future.result() for future in as_completed(futures)} -- cgit v1.2.3-55-g7522 From 77b07ea4fdc259d7253c6f9df2beda6e6c7a9d85 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Tue, 7 Nov 2023 18:05:45 +0000 Subject: [cloud] Add utility script to read iPXE output from INT13CON partition Some AWS instance types still do not support serial console output or screenshots. For these instance types, the only viable way to extract debugging information is to use the INT13 console (which is already enabled via CONFIG=cloud for all AWS images). Obtaining the INT13 console output can be very cumbersome, since there is no direct way to read from an AWS volume. The simplest current approach is to stop the instance under test, detach its root volume, and reattach the volume to a Linux instance in the same region. Add a utility script aws-int13con to retrieve the INT13 console output by creating a temporary snapshot, reading the first block from the snapshot, and extracting the INT13 console partition content. Signed-off-by: Michael Brown --- contrib/cloud/aws-int13con | 68 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 68 insertions(+) create mode 100755 contrib/cloud/aws-int13con diff --git a/contrib/cloud/aws-int13con b/contrib/cloud/aws-int13con new file mode 100755 index 00000000..b79b4065 --- /dev/null +++ b/contrib/cloud/aws-int13con @@ -0,0 +1,68 @@ +#!/usr/bin/env python3 + +import argparse + +import boto3 + +BLOCKSIZE = 512 * 1024 + +IPXELOG_OFFSET = 16 * 1024 + +IPXELOG_MAGIC = b'iPXE LOG' + + +def create_snapshot(region, instance_id): + """Create root volume snapshot""" + client = boto3.client('ec2', region_name=region) + resource = boto3.resource('ec2', region_name=region) + instance = resource.Instance(instance_id) + volumes = list(instance.volumes.all()) + snapshot = volumes[0].create_snapshot() + snapshot.wait_until_completed() + return snapshot.id + + +def get_snapshot_block(region, snapshot_id, index): + """Get block content from snapshot""" + client = boto3.client('ebs', region_name=region) + blocks = client.list_snapshot_blocks(SnapshotId=snapshot_id, + StartingBlockIndex=index) + token = blocks['Blocks'][0]['BlockToken'] + block = client.get_snapshot_block(SnapshotId=snapshot_id, + BlockIndex=index, + BlockToken=token) + return block['BlockData'].read() + + +def get_block0_content(region, instance_id): + """Get content of root volume block zero from instance""" + client = boto3.client('ec2', region_name=region) + resource = boto3.resource('ec2', region_name=region) + snapshot_id = create_snapshot(region, instance_id) + block = get_snapshot_block(region, snapshot_id, 0) + resource.Snapshot(snapshot_id).delete() + return block + + +def get_int13con_output(region, instance_id): + """Get INT13 console output""" + block = get_block0_content(region, instance_id) + logpart = block[IPXELOG_OFFSET:] + magic = logpart[:len(IPXELOG_MAGIC)] + if magic != IPXELOG_MAGIC: + raise ValueError("Invalid log magic signature") + log = logpart[len(IPXELOG_MAGIC):].split(b'\0')[0] + return log.decode() + + +# Parse command-line arguments +parser = argparse.ArgumentParser(description="Get AWS INT13 console output") +parser.add_argument('--region', '-r', help="AWS region") +parser.add_argument('id', help="Instance ID") +args = parser.parse_args() + +# Get console output from INT13CON partition +output = get_int13con_output(args.region, args.id) + +# Print console output +print(output) -- cgit v1.2.3-55-g7522 From 8c8ead25305bbe9521b488144257c131abbbcd23 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Wed, 22 Nov 2023 23:30:56 +0000 Subject: [efi] Update to current EDK2 headers Signed-off-by: Michael Brown --- src/include/ipxe/efi/Base.h | 10 ++++++ src/include/ipxe/efi/IndustryStandard/PeImage.h | 22 +++++++++---- src/include/ipxe/efi/Library/BaseLib.h | 5 +++ src/include/ipxe/efi/Pi/PiStatusCode.h | 42 +++++++++++++------------ src/include/ipxe/efi/Protocol/Rng.h | 10 ++++++ src/include/ipxe/efi/Uefi/UefiBaseType.h | 2 ++ 6 files changed, 65 insertions(+), 26 deletions(-) diff --git a/src/include/ipxe/efi/Base.h b/src/include/ipxe/efi/Base.h index e76013c1..46c31a3b 100644 --- a/src/include/ipxe/efi/Base.h +++ b/src/include/ipxe/efi/Base.h @@ -1231,6 +1231,11 @@ typedef UINTN RETURN_STATUS; /// #define RETURN_COMPROMISED_DATA ENCODE_ERROR (33) +/// +/// There is an address conflict address allocation. +/// +#define RETURN_IP_ADDRESS_CONFLICT ENCODE_ERROR (34) + /// /// A HTTP error occurred during the network operation. /// @@ -1270,6 +1275,11 @@ typedef UINTN RETURN_STATUS; /// #define RETURN_WARN_FILE_SYSTEM ENCODE_WARNING (6) +/// +/// The operation will be processed across a system reset. +/// +#define RETURN_WARN_RESET_REQUIRED ENCODE_WARNING (7) + /** Returns a 16-bit signature built from 2 ASCII characters. diff --git a/src/include/ipxe/efi/IndustryStandard/PeImage.h b/src/include/ipxe/efi/IndustryStandard/PeImage.h index 401e961c..c1f1a09c 100644 --- a/src/include/ipxe/efi/IndustryStandard/PeImage.h +++ b/src/include/ipxe/efi/IndustryStandard/PeImage.h @@ -4,7 +4,7 @@ EFI_IMAGE_NT_HEADERS64 is for PE32+. This file is coded to the Visual Studio, Microsoft Portable Executable and - Common Object File Format Specification, Revision 8.3 - February 6, 2013. + Common Object File Format Specification, Revision 9.3 - December 29, 2015. This file also includes some definitions in PI Specification, Revision 1.0. Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.
@@ -271,6 +271,21 @@ typedef struct { #define EFI_IMAGE_SUBSYSTEM_OS2_CUI 5 #define EFI_IMAGE_SUBSYSTEM_POSIX_CUI 7 +// +// DLL Characteristics +// +#define IMAGE_DLLCHARACTERISTICS_HIGH_ENTROPY_VA 0x0020 +#define IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE 0x0040 +#define IMAGE_DLLCHARACTERISTICS_FORCE_INTEGRITY 0x0080 +#define IMAGE_DLLCHARACTERISTICS_NX_COMPAT 0x0100 +#define IMAGE_DLLCHARACTERISTICS_NO_ISOLATION 0x0200 +#define IMAGE_DLLCHARACTERISTICS_NO_SEH 0x0400 +#define IMAGE_DLLCHARACTERISTICS_NO_BIND 0x0800 +#define IMAGE_DLLCHARACTERISTICS_APPCONTAINER 0x1000 +#define IMAGE_DLLCHARACTERISTICS_WDM_DRIVER 0x2000 +#define IMAGE_DLLCHARACTERISTICS_GUARD_CF 0x4000 +#define IMAGE_DLLCHARACTERISTICS_TERMINAL_SERVER_AWARE 0x8000 + /// /// Length of ShortName. /// @@ -680,9 +695,6 @@ typedef struct { // } EFI_IMAGE_DEBUG_CODEVIEW_MTOC_ENTRY; -// avoid conflict with windows header files -#ifndef RUNTIME_FUNCTION_INDIRECT - // // .pdata entries for X64 // @@ -692,8 +704,6 @@ typedef struct { UINT32 UnwindInfoAddress; } RUNTIME_FUNCTION; -#endif - typedef struct { UINT8 Version : 3; UINT8 Flags : 5; diff --git a/src/include/ipxe/efi/Library/BaseLib.h b/src/include/ipxe/efi/Library/BaseLib.h index e17f3da2..6d236595 100644 --- a/src/include/ipxe/efi/Library/BaseLib.h +++ b/src/include/ipxe/efi/Library/BaseLib.h @@ -183,6 +183,11 @@ RiscVSetSupervisorAddressTranslationRegister ( IN UINT64 ); +UINT64 +RiscVGetSupervisorAddressTranslationRegister ( + VOID + ); + UINT64 RiscVReadTimer ( VOID diff --git a/src/include/ipxe/efi/Pi/PiStatusCode.h b/src/include/ipxe/efi/Pi/PiStatusCode.h index 4375f704..427e5061 100644 --- a/src/include/ipxe/efi/Pi/PiStatusCode.h +++ b/src/include/ipxe/efi/Pi/PiStatusCode.h @@ -365,6 +365,7 @@ typedef struct { #define EFI_PERIPHERAL_LCD_DEVICE (EFI_PERIPHERAL | 0x000B0000) #define EFI_PERIPHERAL_NETWORK (EFI_PERIPHERAL | 0x000C0000) #define EFI_PERIPHERAL_DOCKING (EFI_PERIPHERAL | 0x000D0000) +#define EFI_PERIPHERAL_TPM (EFI_PERIPHERAL | 0x000E0000) ///@} /// @@ -967,26 +968,27 @@ typedef struct { /// These are shared by all subclasses. /// ///@{ -#define EFI_SW_EC_NON_SPECIFIC 0x00000000 -#define EFI_SW_EC_LOAD_ERROR 0x00000001 -#define EFI_SW_EC_INVALID_PARAMETER 0x00000002 -#define EFI_SW_EC_UNSUPPORTED 0x00000003 -#define EFI_SW_EC_INVALID_BUFFER 0x00000004 -#define EFI_SW_EC_OUT_OF_RESOURCES 0x00000005 -#define EFI_SW_EC_ABORTED 0x00000006 -#define EFI_SW_EC_ILLEGAL_SOFTWARE_STATE 0x00000007 -#define EFI_SW_EC_ILLEGAL_HARDWARE_STATE 0x00000008 -#define EFI_SW_EC_START_ERROR 0x00000009 -#define EFI_SW_EC_BAD_DATE_TIME 0x0000000A -#define EFI_SW_EC_CFG_INVALID 0x0000000B -#define EFI_SW_EC_CFG_CLR_REQUEST 0x0000000C -#define EFI_SW_EC_CFG_DEFAULT 0x0000000D -#define EFI_SW_EC_PWD_INVALID 0x0000000E -#define EFI_SW_EC_PWD_CLR_REQUEST 0x0000000F -#define EFI_SW_EC_PWD_CLEARED 0x00000010 -#define EFI_SW_EC_EVENT_LOG_FULL 0x00000011 -#define EFI_SW_EC_WRITE_PROTECTED 0x00000012 -#define EFI_SW_EC_FV_CORRUPTED 0x00000013 +#define EFI_SW_EC_NON_SPECIFIC 0x00000000 +#define EFI_SW_EC_LOAD_ERROR 0x00000001 +#define EFI_SW_EC_INVALID_PARAMETER 0x00000002 +#define EFI_SW_EC_UNSUPPORTED 0x00000003 +#define EFI_SW_EC_INVALID_BUFFER 0x00000004 +#define EFI_SW_EC_OUT_OF_RESOURCES 0x00000005 +#define EFI_SW_EC_ABORTED 0x00000006 +#define EFI_SW_EC_ILLEGAL_SOFTWARE_STATE 0x00000007 +#define EFI_SW_EC_ILLEGAL_HARDWARE_STATE 0x00000008 +#define EFI_SW_EC_START_ERROR 0x00000009 +#define EFI_SW_EC_BAD_DATE_TIME 0x0000000A +#define EFI_SW_EC_CFG_INVALID 0x0000000B +#define EFI_SW_EC_CFG_CLR_REQUEST 0x0000000C +#define EFI_SW_EC_CFG_DEFAULT 0x0000000D +#define EFI_SW_EC_PWD_INVALID 0x0000000E +#define EFI_SW_EC_PWD_CLR_REQUEST 0x0000000F +#define EFI_SW_EC_PWD_CLEARED 0x00000010 +#define EFI_SW_EC_EVENT_LOG_FULL 0x00000011 +#define EFI_SW_EC_WRITE_PROTECTED 0x00000012 +#define EFI_SW_EC_FV_CORRUPTED 0x00000013 +#define EFI_SW_EC_INCONSISTENT_MEMORY_MAP 0x00000014 ///@} // diff --git a/src/include/ipxe/efi/Protocol/Rng.h b/src/include/ipxe/efi/Protocol/Rng.h index 87c5c0ed..92d648be 100644 --- a/src/include/ipxe/efi/Protocol/Rng.h +++ b/src/include/ipxe/efi/Protocol/Rng.h @@ -69,6 +69,15 @@ typedef EFI_GUID EFI_RNG_ALGORITHM; { \ 0xe43176d7, 0xb6e8, 0x4827, {0xb7, 0x84, 0x7f, 0xfd, 0xc4, 0xb6, 0x85, 0x61 } \ } +/// +/// The Arm Architecture states the RNDR that the DRBG algorithm should be compliant +/// with NIST SP800-90A, while not mandating a particular algorithm, so as to be +/// inclusive of different geographies. +/// +#define EFI_RNG_ALGORITHM_ARM_RNDR \ + { \ + 0x43d2fde3, 0x9d4e, 0x4d79, {0x02, 0x96, 0xa8, 0x9b, 0xca, 0x78, 0x08, 0x41} \ + } /** Returns information about the random number generation implementation. @@ -148,5 +157,6 @@ extern EFI_GUID gEfiRngAlgorithmSp80090Ctr256Guid; extern EFI_GUID gEfiRngAlgorithmX9313DesGuid; extern EFI_GUID gEfiRngAlgorithmX931AesGuid; extern EFI_GUID gEfiRngAlgorithmRaw; +extern EFI_GUID gEfiRngAlgorithmArmRndr; #endif diff --git a/src/include/ipxe/efi/Uefi/UefiBaseType.h b/src/include/ipxe/efi/Uefi/UefiBaseType.h index 04927599..bf3aa9bb 100644 --- a/src/include/ipxe/efi/Uefi/UefiBaseType.h +++ b/src/include/ipxe/efi/Uefi/UefiBaseType.h @@ -143,6 +143,7 @@ typedef union { #define EFI_END_OF_FILE RETURN_END_OF_FILE #define EFI_INVALID_LANGUAGE RETURN_INVALID_LANGUAGE #define EFI_COMPROMISED_DATA RETURN_COMPROMISED_DATA +#define EFI_IP_ADDRESS_CONFLICT RETURN_IP_ADDRESS_CONFLICT #define EFI_HTTP_ERROR RETURN_HTTP_ERROR #define EFI_WARN_UNKNOWN_GLYPH RETURN_WARN_UNKNOWN_GLYPH @@ -151,6 +152,7 @@ typedef union { #define EFI_WARN_BUFFER_TOO_SMALL RETURN_WARN_BUFFER_TOO_SMALL #define EFI_WARN_STALE_DATA RETURN_WARN_STALE_DATA #define EFI_WARN_FILE_SYSTEM RETURN_WARN_FILE_SYSTEM +#define EFI_WARN_RESET_REQUIRED RETURN_WARN_RESET_REQUIRED ///@} /// -- cgit v1.2.3-55-g7522 From 678a60f61d76b6fce2d9e3b323db1892f69800d3 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Wed, 22 Nov 2023 23:14:38 +0000 Subject: [efi] Treat writable sections as data sections Hybrid bzImage and UEFI binaries (such as wimboot) may include 16-bit executable code that is opaque data from the perspective of a UEFI PE binary, as described in wimboot commit fe456ca ("[efi] Use separate .text and .data PE sections"). The ELF section will be marked as containing both executable code and writable data. Choose to treat such a section as a data section rather than a code section, since that matches the expected semantics for ELF files that we expect to process. Signed-off-by: Michael Brown --- src/util/elf2efi.c | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/src/util/elf2efi.c b/src/util/elf2efi.c index 5b3e785f..4ed016c0 100644 --- a/src/util/elf2efi.c +++ b/src/util/elf2efi.c @@ -591,17 +591,7 @@ static struct pe_section * process_section ( struct elf_file *elf, /* Fill in section characteristics and update RVA limits */ if ( ( shdr->sh_type == SHT_PROGBITS ) && - ( shdr->sh_flags & SHF_EXECINSTR ) ) { - /* .text-type section */ - new->hdr.Characteristics = - ( EFI_IMAGE_SCN_CNT_CODE | - EFI_IMAGE_SCN_MEM_NOT_PAGED | - EFI_IMAGE_SCN_MEM_EXECUTE | - EFI_IMAGE_SCN_MEM_READ ); - applicable_start = &code_start; - applicable_end = &code_end; - } else if ( ( shdr->sh_type == SHT_PROGBITS ) && - ( shdr->sh_flags & SHF_WRITE ) ) { + ( shdr->sh_flags & SHF_WRITE ) ) { /* .data-type section */ new->hdr.Characteristics = ( EFI_IMAGE_SCN_CNT_INITIALIZED_DATA | @@ -610,6 +600,16 @@ static struct pe_section * process_section ( struct elf_file *elf, EFI_IMAGE_SCN_MEM_WRITE ); applicable_start = &data_start; applicable_end = &data_mid; + } else if ( ( shdr->sh_type == SHT_PROGBITS ) && + ( shdr->sh_flags & SHF_EXECINSTR ) ) { + /* .text-type section */ + new->hdr.Characteristics = + ( EFI_IMAGE_SCN_CNT_CODE | + EFI_IMAGE_SCN_MEM_NOT_PAGED | + EFI_IMAGE_SCN_MEM_EXECUTE | + EFI_IMAGE_SCN_MEM_READ ); + applicable_start = &code_start; + applicable_end = &code_end; } else if ( shdr->sh_type == SHT_PROGBITS ) { /* .rodata-type section */ new->hdr.Characteristics = -- cgit v1.2.3-55-g7522 From a9e89787d08df46daee85a871ba256daf84c6f34 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Wed, 22 Nov 2023 23:36:35 +0000 Subject: [efi] Set NXCOMPAT bit in PE header Indicate that the binary is compatible with W^X protections by setting the NXCOMPAT bit in the DllCharacteristics field of the PE header. Signed-off-by: Michael Brown --- src/util/elf2efi.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/util/elf2efi.c b/src/util/elf2efi.c index 4ed016c0..f4d591d1 100644 --- a/src/util/elf2efi.c +++ b/src/util/elf2efi.c @@ -225,6 +225,8 @@ static struct pe_header efi_pe_header = { .FileAlignment = EFI_FILE_ALIGN, .SizeOfImage = EFI_IMAGE_ALIGN, .SizeOfHeaders = sizeof ( efi_pe_header ), + .DllCharacteristics = + IMAGE_DLLCHARACTERISTICS_NX_COMPAT, .NumberOfRvaAndSizes = NUMBER_OF_DIRECTORY_ENTRIES, }, }, -- cgit v1.2.3-55-g7522 From 3d8a614657e68fb6cb7241397bc14cb5b9a7c0b8 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Wed, 22 Nov 2023 23:05:39 +0000 Subject: [efi] Mark PE images as large address aware The images generated by elf2efi can be loaded anywhere in the address space, and are not limited to the low 2GB. Indicate this by setting the "large address aware" flag within the PE header, for compatibility with EFI images generated by the EDK2 build process. (The EDK2 PE loader does not ever check this flag, and it is unlikely that any other EFI PE loader ever does so, but we may as well report it accurately.) Signed-off-by: Michael Brown --- src/util/elf2efi.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/util/elf2efi.c b/src/util/elf2efi.c index f4d591d1..b13ff43e 100644 --- a/src/util/elf2efi.c +++ b/src/util/elf2efi.c @@ -215,6 +215,7 @@ static struct pe_header efi_pe_header = { DataDirectory[0] ) ) ), .Characteristics = ( EFI_IMAGE_FILE_DLL | EFI_IMAGE_FILE_MACHINE | + EFI_IMAGE_FILE_LARGE_ADDRESS_AWARE| EFI_IMAGE_FILE_EXECUTABLE_IMAGE ), }, .OptionalHeader = { -- cgit v1.2.3-55-g7522 From b30a0987e239baf4689adbf79035b7f737eef873 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Wed, 22 Nov 2023 14:57:05 +0000 Subject: [efi] Use load memory address as file offset for hybrid binaries Hybrid bzImage and UEFI binaries (such as wimboot) may be loaded as a single contiguous blob without reference to the PE headers, and the placement of sections within the PE file must therefore be known at link time. Use the load memory address (extracted from the ELF program headers) to determine the physical placement of the section within the PE file when generating a hybrid binary. Signed-off-by: Michael Brown --- src/util/elf2efi.c | 84 +++++++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 77 insertions(+), 7 deletions(-) diff --git a/src/util/elf2efi.c b/src/util/elf2efi.c index b13ff43e..682580f4 100644 --- a/src/util/elf2efi.c +++ b/src/util/elf2efi.c @@ -50,6 +50,7 @@ #define EFI_IMAGE_FILE_MACHINE EFI_IMAGE_FILE_32BIT_MACHINE #define ELFCLASS ELFCLASS32 #define Elf_Ehdr Elf32_Ehdr +#define Elf_Phdr Elf32_Phdr #define Elf_Shdr Elf32_Shdr #define Elf_Sym Elf32_Sym #define Elf_Addr Elf32_Addr @@ -65,6 +66,7 @@ #define EFI_IMAGE_FILE_MACHINE 0 #define ELFCLASS ELFCLASS64 #define Elf_Ehdr Elf64_Ehdr +#define Elf_Phdr Elf64_Phdr #define Elf_Shdr Elf64_Shdr #define Elf_Sym Elf64_Sym #define Elf_Addr Elf64_Addr @@ -168,6 +170,9 @@ */ #define EFI_IMAGE_ALIGN 0x1000 +/** Set PointerToRawData automatically */ +#define PTRD_AUTO 0xffffffffUL + /** Number of data directory entries */ #define NUMBER_OF_DIRECTORY_ENTRIES 8 @@ -429,6 +434,14 @@ static void read_elf_file ( const char *name, struct elf_file *elf ) { } elf->ehdr = ehdr; + /* Check program headers */ + if ( ( elf->len < ehdr->e_phoff ) || + ( ( elf->len - ehdr->e_phoff ) < ( ehdr->e_phnum * + ehdr->e_phentsize ) ) ) { + eprintf ( "ELF program headers outside file in %s\n", name ); + exit ( 1 ); + } + /* Check section headers */ for ( i = 0 ; i < ehdr->e_shnum ; i++ ) { offset = ( ehdr->e_shoff + ( i * ehdr->e_shentsize ) ); @@ -498,6 +511,39 @@ static const char * elf_string ( struct elf_file *elf, unsigned int section, return string; } +/** + * Get section load memory address + * + * @v elf ELF file + * @v shdr ELF section header + * @v name ELF section name + * @ret lma Load memory address + */ +static unsigned long elf_lma ( struct elf_file *elf, const Elf_Shdr *shdr, + const char *name ) { + const Elf_Ehdr *ehdr = elf->ehdr; + const Elf_Phdr *phdr; + size_t offset; + unsigned int i; + + /* Find containing segment */ + for ( i = 0 ; i < ehdr->e_phnum ; i++ ) { + offset = ( ehdr->e_phoff + ( i * ehdr->e_phentsize ) ); + phdr = ( elf->data + offset ); + if ( ( phdr->p_type == PT_LOAD ) && + ( phdr->p_vaddr <= shdr->sh_addr ) && + ( ( shdr->sh_addr - phdr->p_vaddr + shdr->sh_size ) <= + phdr->p_memsz ) ) { + /* Found matching segment */ + return ( phdr->p_paddr + + ( shdr->sh_addr - phdr->p_vaddr ) ); + } + } + + eprintf ( "No containing segment for section %s\n", name ); + exit ( 1 ); +} + /** * Set machine architecture * @@ -540,11 +586,13 @@ static void set_machine ( struct elf_file *elf, struct pe_header *pe_header ) { * @v elf ELF file * @v shdr ELF section header * @v pe_header PE file header + * @v opts Options * @ret new New PE section */ static struct pe_section * process_section ( struct elf_file *elf, const Elf_Shdr *shdr, - struct pe_header *pe_header ) { + struct pe_header *pe_header, + struct options *opts ) { struct pe_section *new; const char *name; size_t name_len; @@ -591,6 +639,13 @@ static struct pe_section * process_section ( struct elf_file *elf, new->hdr.Misc.VirtualSize = section_memsz; new->hdr.VirtualAddress = shdr->sh_addr; new->hdr.SizeOfRawData = section_filesz; + if ( shdr->sh_type == SHT_PROGBITS ) { + if ( opts->hybrid ) { + new->hdr.PointerToRawData = elf_lma ( elf, shdr, name ); + } else { + new->hdr.PointerToRawData = PTRD_AUTO; + } + } /* Fill in section characteristics and update RVA limits */ if ( ( shdr->sh_type == SHT_PROGBITS ) && @@ -835,6 +890,7 @@ create_reloc_section ( struct pe_header *pe_header, reloc->hdr.Misc.VirtualSize = section_memsz; reloc->hdr.VirtualAddress = pe_header->nt.OptionalHeader.SizeOfImage; reloc->hdr.SizeOfRawData = section_filesz; + reloc->hdr.PointerToRawData = PTRD_AUTO; reloc->hdr.Characteristics = ( EFI_IMAGE_SCN_CNT_INITIALIZED_DATA | EFI_IMAGE_SCN_MEM_DISCARDABLE | EFI_IMAGE_SCN_MEM_NOT_PAGED | @@ -901,6 +957,7 @@ create_debug_section ( struct pe_header *pe_header, const char *filename ) { debug->hdr.Misc.VirtualSize = section_memsz; debug->hdr.VirtualAddress = pe_header->nt.OptionalHeader.SizeOfImage; debug->hdr.SizeOfRawData = section_filesz; + debug->hdr.PointerToRawData = PTRD_AUTO; debug->hdr.Characteristics = ( EFI_IMAGE_SCN_CNT_INITIALIZED_DATA | EFI_IMAGE_SCN_MEM_DISCARDABLE | EFI_IMAGE_SCN_MEM_NOT_PAGED | @@ -944,19 +1001,25 @@ static void write_pe_file ( struct pe_header *pe_header, FILE *pe ) { struct pe_section *section; unsigned long fpos = 0; + unsigned long fposmax = 0; unsigned int count = 0; /* Align length of headers */ - fpos = pe_header->nt.OptionalHeader.SizeOfHeaders = + fpos = fposmax = pe_header->nt.OptionalHeader.SizeOfHeaders = efi_file_align ( pe_header->nt.OptionalHeader.SizeOfHeaders ); /* Assign raw data pointers */ for ( section = pe_sections ; section ; section = section->next ) { - if ( section->hdr.SizeOfRawData ) { - section->hdr.PointerToRawData = fpos; - fpos += section->hdr.SizeOfRawData; - fpos = efi_file_align ( fpos ); + if ( section->hdr.PointerToRawData == PTRD_AUTO ) { + fpos = fposmax; + } else { + fpos = section->hdr.PointerToRawData; } + section->hdr.PointerToRawData = fpos; + fpos += section->hdr.SizeOfRawData; + fpos = efi_file_align ( fpos ); + if ( fpos > fposmax ) + fposmax = fpos; if ( section->fixup ) section->fixup ( section ); } @@ -985,6 +1048,12 @@ static void write_pe_file ( struct pe_header *pe_header, /* Write sections */ for ( section = pe_sections ; section ; section = section->next ) { + if ( section->hdr.PointerToRawData & ( EFI_FILE_ALIGN - 1 ) ) { + eprintf ( "Section %.8s file offset %x is " + "misaligned\n", section->hdr.Name, + section->hdr.PointerToRawData ); + exit ( 1 ); + } if ( fseek ( pe, section->hdr.PointerToRawData, SEEK_SET ) != 0 ) { eprintf ( "Could not seek to %x: %s\n", @@ -1044,7 +1113,8 @@ static void elf2pe ( const char *elf_name, const char *pe_name, /* Create output section */ *(next_pe_section) = process_section ( &elf, shdr, - &pe_header ); + &pe_header, + opts ); next_pe_section = &(*next_pe_section)->next; } else if ( shdr->sh_type == SHT_REL ) { -- cgit v1.2.3-55-g7522 From cc858acd3205b18934ffff19ac55f8987e9c6135 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Wed, 22 Nov 2023 15:38:22 +0000 Subject: [efi] Write out PE header only after writing sections Hybrid bzImage and UEFI binaries (such as wimboot) include a bzImage header within a section starting at offset zero, with the PE header effectively occupying unused space within this section. Allow for this by treating a section placed at offset zero as hidden, and by deferring the writing of the PE header until after the output sections have been written. Signed-off-by: Michael Brown --- src/util/elf2efi.c | 50 ++++++++++++++++++++++++++++---------------------- 1 file changed, 28 insertions(+), 22 deletions(-) diff --git a/src/util/elf2efi.c b/src/util/elf2efi.c index 682580f4..a8074915 100644 --- a/src/util/elf2efi.c +++ b/src/util/elf2efi.c @@ -642,6 +642,8 @@ static struct pe_section * process_section ( struct elf_file *elf, if ( shdr->sh_type == SHT_PROGBITS ) { if ( opts->hybrid ) { new->hdr.PointerToRawData = elf_lma ( elf, shdr, name ); + if ( new->hdr.PointerToRawData == 0 ) + new->hidden = 1; } else { new->hdr.PointerToRawData = PTRD_AUTO; } @@ -1024,28 +1026,6 @@ static void write_pe_file ( struct pe_header *pe_header, section->fixup ( section ); } - /* Write file header */ - if ( fwrite ( pe_header, - ( offsetof ( typeof ( *pe_header ), nt.OptionalHeader ) + - pe_header->nt.FileHeader.SizeOfOptionalHeader ), - 1, pe ) != 1 ) { - perror ( "Could not write PE header" ); - exit ( 1 ); - } - - /* Write section headers */ - for ( section = pe_sections ; section ; section = section->next ) { - if ( section->hidden ) - continue; - if ( fwrite ( §ion->hdr, sizeof ( section->hdr ), - 1, pe ) != 1 ) { - perror ( "Could not write section header" ); - exit ( 1 ); - } - count++; - } - assert ( count == pe_header->nt.FileHeader.NumberOfSections ); - /* Write sections */ for ( section = pe_sections ; section ; section = section->next ) { if ( section->hdr.PointerToRawData & ( EFI_FILE_ALIGN - 1 ) ) { @@ -1069,6 +1049,32 @@ static void write_pe_file ( struct pe_header *pe_header, exit ( 1 ); } } + + /* Write file header */ + if ( fseek ( pe, 0, SEEK_SET ) != 0 ) { + eprintf ( "Could not rewind: %s\n", strerror ( errno ) ); + exit ( 1 ); + } + if ( fwrite ( pe_header, + ( offsetof ( typeof ( *pe_header ), nt.OptionalHeader ) + + pe_header->nt.FileHeader.SizeOfOptionalHeader ), + 1, pe ) != 1 ) { + perror ( "Could not write PE header" ); + exit ( 1 ); + } + + /* Write section headers */ + for ( section = pe_sections ; section ; section = section->next ) { + if ( section->hidden ) + continue; + if ( fwrite ( §ion->hdr, sizeof ( section->hdr ), + 1, pe ) != 1 ) { + perror ( "Could not write section header" ); + exit ( 1 ); + } + count++; + } + assert ( count == pe_header->nt.FileHeader.NumberOfSections ); } /** -- cgit v1.2.3-55-g7522 From b37d89db90566cc1dcab9fe5713bde142fbc8f63 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Thu, 23 Nov 2023 14:54:12 +0000 Subject: [efi] Fix recorded overall size of headers in NT optional header Commit 1e4c378 ("[efi] Shrink size of data directory in PE header") reduced the number of entries used in the data directory and reduced the recorded size of the NT "optional" header, but did not also adjust the recorded overall size of the PE headers, resulting in unused space between the PE headers and the first section. Fix by reducing the initial recorded size of the PE headers by the size of the omitted data directory entries. Signed-off-by: Michael Brown --- src/util/elf2efi.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/util/elf2efi.c b/src/util/elf2efi.c index a8074915..76d02f24 100644 --- a/src/util/elf2efi.c +++ b/src/util/elf2efi.c @@ -230,7 +230,12 @@ static struct pe_header efi_pe_header = { .SectionAlignment = EFI_IMAGE_ALIGN, .FileAlignment = EFI_FILE_ALIGN, .SizeOfImage = EFI_IMAGE_ALIGN, - .SizeOfHeaders = sizeof ( efi_pe_header ), + .SizeOfHeaders = + ( sizeof ( efi_pe_header ) - + ( ( EFI_IMAGE_NUMBER_OF_DIRECTORY_ENTRIES - + NUMBER_OF_DIRECTORY_ENTRIES ) * + sizeof ( efi_pe_header.nt.OptionalHeader. + DataDirectory[0] ) ) ), .DllCharacteristics = IMAGE_DLLCHARACTERISTICS_NX_COMPAT, .NumberOfRvaAndSizes = NUMBER_OF_DIRECTORY_ENTRIES, -- cgit v1.2.3-55-g7522 From 6714b20ea20af5046cdb36b58ab777b55a3c003c Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Thu, 23 Nov 2023 14:17:36 +0000 Subject: [efi] Place PE debug information in a hidden section The PE debug information generated by elf2efi is used only to hold the image filename, and the debug information is located via the relevant data directory entry rather than via the section table. Make the .debug section a hidden section in order to save one entry in the PE section list. Choose to place the debug information in the unused space at the end of the PE headers, since it no longer needs to satisfy the general section alignment constraints. Signed-off-by: Michael Brown --- src/util/elf2efi.c | 46 +++++++++++++++------------------------------- 1 file changed, 15 insertions(+), 31 deletions(-) diff --git a/src/util/elf2efi.c b/src/util/elf2efi.c index 76d02f24..c98c4d4a 100644 --- a/src/util/elf2efi.c +++ b/src/util/elf2efi.c @@ -185,7 +185,6 @@ struct elf_file { struct pe_section { struct pe_section *next; EFI_IMAGE_SECTION_HEADER hdr; - void ( * fixup ) ( struct pe_section *section ); int hidden; uint8_t contents[0]; }; @@ -919,20 +918,6 @@ create_reloc_section ( struct pe_header *pe_header, return reloc; } -/** - * Fix up debug section - * - * @v debug Debug section - */ -static void fixup_debug_section ( struct pe_section *debug ) { - EFI_IMAGE_DEBUG_DIRECTORY_ENTRY *contents; - - /* Fix up FileOffset */ - contents = ( ( void * ) debug->contents ); - contents->FileOffset += ( debug->hdr.PointerToRawData - - debug->hdr.VirtualAddress ); -} - /** * Create debug section * @@ -952,24 +937,27 @@ 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_filesz = section_memsz = sizeof ( *contents ); debug = xmalloc ( sizeof ( *debug ) + section_filesz ); memset ( debug, 0, sizeof ( *debug ) + section_filesz ); contents = ( void * ) debug->contents; + /* Place at end of headers */ + pe_header->nt.OptionalHeader.SizeOfHeaders += sizeof ( *contents ); + pe_header->nt.OptionalHeader.SizeOfHeaders = + efi_file_align ( pe_header->nt.OptionalHeader.SizeOfHeaders ); + pe_header->nt.OptionalHeader.SizeOfHeaders -= sizeof ( *contents ); + /* Fill in section header details */ strncpy ( ( char * ) debug->hdr.Name, ".debug", sizeof ( debug->hdr.Name ) ); debug->hdr.Misc.VirtualSize = section_memsz; - debug->hdr.VirtualAddress = pe_header->nt.OptionalHeader.SizeOfImage; + debug->hdr.VirtualAddress = + pe_header->nt.OptionalHeader.SizeOfHeaders; debug->hdr.SizeOfRawData = section_filesz; - debug->hdr.PointerToRawData = PTRD_AUTO; - 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; + debug->hdr.PointerToRawData = + pe_header->nt.OptionalHeader.SizeOfHeaders; + debug->hidden = 1; /* Create section contents */ contents->debug.TimeDateStamp = 0x10d1a884; @@ -984,10 +972,7 @@ create_debug_section ( struct pe_header *pe_header, const char *filename ) { filename ); /* Update file header details */ - pe_header->nt.FileHeader.NumberOfSections++; - pe_header->nt.OptionalHeader.SizeOfHeaders += sizeof ( debug->hdr ); - pe_header->nt.OptionalHeader.SizeOfImage += - efi_image_align ( section_memsz ); + pe_header->nt.OptionalHeader.SizeOfHeaders += sizeof ( *contents ); debugdir = &(pe_header->nt.OptionalHeader.DataDirectory [EFI_IMAGE_DIRECTORY_ENTRY_DEBUG]); debugdir->VirtualAddress = debug->hdr.VirtualAddress; @@ -1027,13 +1012,12 @@ static void write_pe_file ( struct pe_header *pe_header, fpos = efi_file_align ( fpos ); if ( fpos > fposmax ) fposmax = fpos; - if ( section->fixup ) - section->fixup ( section ); } /* Write sections */ for ( section = pe_sections ; section ; section = section->next ) { - if ( section->hdr.PointerToRawData & ( EFI_FILE_ALIGN - 1 ) ) { + if ( ( section->hdr.PointerToRawData & ( EFI_FILE_ALIGN - 1 ) ) + && ( ! section->hidden ) ) { eprintf ( "Section %.8s file offset %x is " "misaligned\n", section->hdr.Name, section->hdr.PointerToRawData ); -- cgit v1.2.3-55-g7522 From 18582a05fc65fc8835220c27528ef8902f5da60e Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Fri, 24 Nov 2023 12:16:49 +0000 Subject: [efi] Treat 16-bit sections as hidden in hybrid binaries Hybrid bzImage and UEFI binaries (such as wimboot) may include 16-bit sections such as .bss16 that do not need to consume an entry in the PE section list. Treat any such sections as hidden. Signed-off-by: Michael Brown --- src/util/elf2efi.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/util/elf2efi.c b/src/util/elf2efi.c index c98c4d4a..171e2b58 100644 --- a/src/util/elf2efi.c +++ b/src/util/elf2efi.c @@ -653,6 +653,12 @@ static struct pe_section * process_section ( struct elf_file *elf, } } + /* Treat 16-bit sections as hidden in hybrid binaries */ + if ( opts->hybrid && ( strlen ( name ) > 2 ) && + ( strcmp ( &name[ strlen ( name ) - 2 ], "16" ) == 0 ) ) { + new->hidden = 1; + } + /* Fill in section characteristics and update RVA limits */ if ( ( shdr->sh_type == SHT_PROGBITS ) && ( shdr->sh_flags & SHF_WRITE ) ) { -- cgit v1.2.3-55-g7522 From 03ff1bb99a28230397fb583853ab2160ff227e77 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Fri, 24 Nov 2023 15:55:41 +0000 Subject: [efi] Do not assume canonical PE section ordering The BaseOfCode (and, in PE32, BaseOfData) fields imply an assumption that binaries are laid out as code followed by initialised data followed by uninitialised data. This assumption may not be valid for complex binaries such as wimboot. Remove this implicit assumption, and use arguably justifiable values for the assorted summary start and size fields within the PE headers. Signed-off-by: Michael Brown --- src/util/elf2efi.c | 93 ++++++++++++++++++++++-------------------------------- 1 file changed, 37 insertions(+), 56 deletions(-) diff --git a/src/util/elf2efi.c b/src/util/elf2efi.c index 171e2b58..72d50d38 100644 --- a/src/util/elf2efi.c +++ b/src/util/elf2efi.c @@ -602,31 +602,29 @@ static struct pe_section * process_section ( struct elf_file *elf, size_t name_len; size_t section_memsz; size_t section_filesz; - unsigned long code_start; - unsigned long code_end; - unsigned long data_start; - unsigned long data_mid; - unsigned long data_end; - unsigned long start; - unsigned long end; - unsigned long *applicable_start; - unsigned long *applicable_end; + uint32_t start; + uint32_t end; + uint32_t *code_start; + uint32_t *data_start; + uint32_t *code_size; + uint32_t *data_size; + uint32_t *bss_size; + uint32_t *applicable_start; + uint32_t *applicable_size; /* Get section name */ name = elf_string ( elf, elf->ehdr->e_shstrndx, shdr->sh_name ); - /* Extract current RVA limits from file header */ - code_start = pe_header->nt.OptionalHeader.BaseOfCode; - code_end = ( code_start + pe_header->nt.OptionalHeader.SizeOfCode ); + /* Identify start and size limit fields from file header */ + code_start = &pe_header->nt.OptionalHeader.BaseOfCode; + code_size = &pe_header->nt.OptionalHeader.SizeOfCode; #if defined(EFI_TARGET32) - data_start = pe_header->nt.OptionalHeader.BaseOfData; + data_start = &pe_header->nt.OptionalHeader.BaseOfData; #elif defined(EFI_TARGET64) - data_start = code_end; + data_start = NULL; #endif - data_mid = ( data_start + - pe_header->nt.OptionalHeader.SizeOfInitializedData ); - data_end = ( data_mid + - pe_header->nt.OptionalHeader.SizeOfUninitializedData ); + data_size = &pe_header->nt.OptionalHeader.SizeOfInitializedData; + bss_size = &pe_header->nt.OptionalHeader.SizeOfUninitializedData; /* Allocate PE section */ section_memsz = shdr->sh_size; @@ -659,7 +657,7 @@ static struct pe_section * process_section ( struct elf_file *elf, new->hidden = 1; } - /* Fill in section characteristics and update RVA limits */ + /* Fill in section characteristics and identify applicable limits */ if ( ( shdr->sh_type == SHT_PROGBITS ) && ( shdr->sh_flags & SHF_WRITE ) ) { /* .data-type section */ @@ -668,8 +666,8 @@ static struct pe_section * process_section ( struct elf_file *elf, EFI_IMAGE_SCN_MEM_NOT_PAGED | EFI_IMAGE_SCN_MEM_READ | EFI_IMAGE_SCN_MEM_WRITE ); - applicable_start = &data_start; - applicable_end = &data_mid; + applicable_start = data_start; + applicable_size = data_size; } else if ( ( shdr->sh_type == SHT_PROGBITS ) && ( shdr->sh_flags & SHF_EXECINSTR ) ) { /* .text-type section */ @@ -678,16 +676,16 @@ static struct pe_section * process_section ( struct elf_file *elf, EFI_IMAGE_SCN_MEM_NOT_PAGED | EFI_IMAGE_SCN_MEM_EXECUTE | EFI_IMAGE_SCN_MEM_READ ); - applicable_start = &code_start; - applicable_end = &code_end; + applicable_start = code_start; + applicable_size = code_size; } else if ( shdr->sh_type == SHT_PROGBITS ) { /* .rodata-type section */ new->hdr.Characteristics = ( EFI_IMAGE_SCN_CNT_INITIALIZED_DATA | EFI_IMAGE_SCN_MEM_NOT_PAGED | EFI_IMAGE_SCN_MEM_READ ); - applicable_start = &data_start; - applicable_end = &data_mid; + applicable_start = data_start; + applicable_size = data_size; } else if ( shdr->sh_type == SHT_NOBITS ) { /* .bss-type section */ new->hdr.Characteristics = @@ -695,8 +693,8 @@ static struct pe_section * process_section ( struct elf_file *elf, EFI_IMAGE_SCN_MEM_NOT_PAGED | EFI_IMAGE_SCN_MEM_READ | EFI_IMAGE_SCN_MEM_WRITE ); - applicable_start = &data_mid; - applicable_end = &data_end; + applicable_start = data_start; + applicable_size = bss_size; } else { eprintf ( "Unrecognised characteristics for section %s\n", name ); @@ -709,41 +707,24 @@ static struct pe_section * process_section ( struct elf_file *elf, shdr->sh_size ); } - /* Update RVA limits */ + /* Update file header fields */ start = new->hdr.VirtualAddress; - end = ( start + new->hdr.Misc.VirtualSize ); - if ( ! new->hidden ) { - if ( ( ! *applicable_start ) || ( *applicable_start >= start ) ) - *applicable_start = start; - if ( *applicable_end < end ) - *applicable_end = end; - } - if ( data_start < code_end ) - data_start = code_end; - if ( data_mid < data_start ) - data_mid = data_start; - if ( data_end < data_mid ) - data_end = data_mid; - - /* Write RVA limits back to file header */ - pe_header->nt.OptionalHeader.BaseOfCode = code_start; - pe_header->nt.OptionalHeader.SizeOfCode = ( code_end - code_start ); -#if defined(EFI_TARGET32) - pe_header->nt.OptionalHeader.BaseOfData = data_start; -#endif - pe_header->nt.OptionalHeader.SizeOfInitializedData = - ( data_mid - data_start ); - pe_header->nt.OptionalHeader.SizeOfUninitializedData = - ( data_end - data_mid ); - - /* Update remaining file header fields */ if ( ! new->hidden ) { pe_header->nt.FileHeader.NumberOfSections++; pe_header->nt.OptionalHeader.SizeOfHeaders += sizeof ( new->hdr ); + if ( applicable_start && ( ( *applicable_start == 0 ) || + ( start < *applicable_start ) ) ) { + *applicable_start = start; + } + if ( applicable_size ) { + *applicable_size += section_memsz; + } + } + end = efi_image_align ( start + section_memsz ); + if ( end > pe_header->nt.OptionalHeader.SizeOfImage ) { + pe_header->nt.OptionalHeader.SizeOfImage = end; } - pe_header->nt.OptionalHeader.SizeOfImage = - efi_image_align ( data_end ); return new; } -- cgit v1.2.3-55-g7522 From b829b1750de041f7d4fd0f4f86fbf968bdccda6a Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Fri, 24 Nov 2023 12:26:43 +0000 Subject: [efi] Maximise image base address iPXE images are linked with a starting virtual address of zero. Other images (such as wimboot) may use a non-zero starting virtual address. There is no direct equivalent of the PE ImageBase address field within ELF object files. Choose to use the highest possible address that accommodates all sections and the PE header itself, since this will minimise the memory allocated to hold the loaded image. Signed-off-by: Michael Brown --- src/util/elf2efi.c | 44 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) diff --git a/src/util/elf2efi.c b/src/util/elf2efi.c index 72d50d38..e9760139 100644 --- a/src/util/elf2efi.c +++ b/src/util/elf2efi.c @@ -729,6 +729,47 @@ static struct pe_section * process_section ( struct elf_file *elf, return new; } +/** + * Update image base address + * + * @v pe_header PE file header + * @v pe_sections List of PE sections + * @v pe_reltab PE relocation table + */ +static void update_image_base ( struct pe_header *pe_header, + struct pe_section *pe_sections, + struct pe_relocs *pe_reltab ) { + struct pe_section *section; + struct pe_relocs *pe_rel; + unsigned long base = -1UL; + + /* Set ImageBase to the highest possible value, leaving space + * for the PE header itself. + */ + for ( section = pe_sections ; section ; section = section->next ) { + if ( ! section->hidden ) { + if ( base > section->hdr.VirtualAddress ) + base = section->hdr.VirtualAddress; + } + } + base -= EFI_IMAGE_ALIGN; + pe_header->nt.OptionalHeader.ImageBase = base; + + /* Adjust RVAs to match ImageBase */ + pe_header->nt.OptionalHeader.AddressOfEntryPoint -= base; + pe_header->nt.OptionalHeader.BaseOfCode -= base; +#if defined(EFI_TARGET32) + pe_header->nt.OptionalHeader.BaseOfData -= base; +#endif + pe_header->nt.OptionalHeader.SizeOfImage -= base; + for ( section = pe_sections ; section ; section = section->next ) { + section->hdr.VirtualAddress -= base; + } + for ( pe_rel = pe_reltab ; pe_rel ; pe_rel = pe_rel->next ) { + pe_rel->start_rva -= base; + } +} + /** * Process relocation record * @@ -1113,6 +1154,9 @@ static void elf2pe ( const char *elf_name, const char *pe_name, } } + /* Update image base address */ + update_image_base ( &pe_header, pe_sections, pe_reltab ); + /* Create the .reloc section */ *(next_pe_section) = create_reloc_section ( &pe_header, pe_reltab ); next_pe_section = &(*next_pe_section)->next; -- cgit v1.2.3-55-g7522 From c3dd3168c916f624af1b843515c1305387060611 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Fri, 24 Nov 2023 22:26:50 +0000 Subject: [efi] Fix dependency list construction in EDK2 header import script Signed-off-by: Michael Brown --- src/include/ipxe/efi/import.pl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/include/ipxe/efi/import.pl b/src/include/ipxe/efi/import.pl index 34aed9a2..0a7669f4 100755 --- a/src/include/ipxe/efi/import.pl +++ b/src/include/ipxe/efi/import.pl @@ -68,7 +68,7 @@ sub try_import_file { chomp; # Update include lines, and record included files if ( s/^(\s*\#include\s+)[<\"](\S+)[>\"]/$1/ ) { - push @dependencies, $1; + push @dependencies, $2; } # Check for BSD licence statement if ( /^\s*SPDX-License-Identifier: BSD-2-Clause-Patent$/ ) { -- cgit v1.2.3-55-g7522 From a147245f1a2f92a85a75226ea921acb22322ab4d Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Mon, 27 Nov 2023 12:08:19 +0000 Subject: [efi] Extend PE header size to cover space up to first section Hybrid bzImage and UEFI binaries (such as wimboot) may place sections at explicit offsets within the PE file, as described in commit b30a098 ("[efi] Use load memory address as file offset for hybrid binaries"). This can leave a gap after the PE headers that is not covered by any section. It is not entirely clear whether or not such gaps are permitted in binaries submitted for Secure Boot signing. To minimise potential problems, extend the PE header size to cover any space before the first explicitly placed section. Signed-off-by: Michael Brown --- src/util/elf2efi.c | 25 +++++++++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) diff --git a/src/util/elf2efi.c b/src/util/elf2efi.c index e9760139..a3aff8f1 100644 --- a/src/util/elf2efi.c +++ b/src/util/elf2efi.c @@ -1020,13 +1020,34 @@ static void write_pe_file ( struct pe_header *pe_header, struct pe_section *pe_sections, FILE *pe ) { struct pe_section *section; - unsigned long fpos = 0; - unsigned long fposmax = 0; + unsigned long hdrmax; + unsigned long fpos; + unsigned long fposmax; unsigned int count = 0; + /* Extend header length to reach first explicitly placed section */ + hdrmax = -1UL; + for ( section = pe_sections ; section ; section = section->next ) { + if ( ( section->hdr.PointerToRawData != PTRD_AUTO ) && + ( section->hdr.SizeOfRawData > 0 ) && + ( ! section->hidden ) && + ( hdrmax > section->hdr.PointerToRawData ) ) { + hdrmax = section->hdr.PointerToRawData; + } + } + if ( ( hdrmax != -1UL ) && + ( pe_header->nt.OptionalHeader.SizeOfHeaders < hdrmax ) ) { + pe_header->nt.OptionalHeader.SizeOfHeaders = hdrmax; + } + /* Align length of headers */ fpos = fposmax = pe_header->nt.OptionalHeader.SizeOfHeaders = efi_file_align ( pe_header->nt.OptionalHeader.SizeOfHeaders ); + if ( fpos > hdrmax ) { + eprintf ( "Cannot fit %lx bytes of headers before section at " + "file offset %lx\n", fpos, hdrmax ); + exit ( 1 ); + } /* Assign raw data pointers */ for ( section = pe_sections ; section ; section = section->next ) { -- cgit v1.2.3-55-g7522 From 98dd25a3bb2d3aafa71f088cbabf89418a783132 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Wed, 29 Nov 2023 12:49:06 +0000 Subject: [efi] Avoid modifying PE/COFF debug filename The function efi_pecoff_debug_name() (called by efi_handle_name()) is used to extract a filename from the debug data directory entry located within a PE/COFF image. The name is copied into a temporary static buffer to allow for modifications, but the code currently erroneously modifies the original name within the loaded PE/COFF image. Fix by performing the modification on the copy in the temporary buffer, as originally intended. Signed-off-by: Michael Brown --- src/interface/efi/efi_debug.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/interface/efi/efi_debug.c b/src/interface/efi/efi_debug.c index 1372776f..ad79f0d3 100644 --- a/src/interface/efi/efi_debug.c +++ b/src/interface/efi/efi_debug.c @@ -665,10 +665,10 @@ efi_pecoff_debug_name ( EFI_LOADED_IMAGE_PROTOCOL *loaded ) { snprintf ( buf, sizeof ( buf ), "%s", name ); /* Strip file suffix, if present */ - if ( ( tmp = strrchr ( name, '.' ) ) != NULL ) + if ( ( tmp = strrchr ( buf, '.' ) ) != NULL ) *tmp = '\0'; - return name; + return buf; } /** -- cgit v1.2.3-55-g7522 From f22879ca994aedd2667bb0c73ebce505bf5f8cef Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Tue, 5 Dec 2023 15:49:17 +0000 Subject: [efi] Allow compiling elf2efi with clang The clang compiler does not (and apparently will not ever) allow for variable-length arrays within structs. Work around this limitation by using a fixed-length array to hold the PDB filename in the debug section. This mirrors wimboot commit f52c3ff ("[efi] Allow compiling elf2efi with clang"). Signed-off-by: Michael Brown --- src/util/elf2efi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/util/elf2efi.c b/src/util/elf2efi.c index a3aff8f1..acde75c0 100644 --- a/src/util/elf2efi.c +++ b/src/util/elf2efi.c @@ -961,7 +961,7 @@ create_debug_section ( struct pe_header *pe_header, const char *filename ) { struct { EFI_IMAGE_DEBUG_DIRECTORY_ENTRY debug; EFI_IMAGE_DEBUG_CODEVIEW_RSDS_ENTRY rsds; - char name[ strlen ( filename ) + 1 ]; + char name[32]; } *contents; /* Allocate PE section */ -- cgit v1.2.3-55-g7522 From 337880deaa7ea5d86e5c7de63faa1c976d6114cf Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Tue, 19 Dec 2023 14:39:36 +0000 Subject: [build] Use SOURCE_DATE_EPOCH for FAT serial number if it exists Reported-by: Bernhard M. Wiedemann Signed-off-by: Michael Brown --- src/util/genfsimg | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/util/genfsimg b/src/util/genfsimg index 0c069279..a981a62d 100755 --- a/src/util/genfsimg +++ b/src/util/genfsimg @@ -269,6 +269,10 @@ if [ -n "${FATIMG}" ] ; then FATSIZE=$(( FATCYLS * 504 )) FATARGS="-s 63 -h 16 -t ${FATCYLS}" fi + if [ -n "${SOURCE_DATE_EPOCH:-}" ] ; then + FATSERIAL=$(( SOURCE_DATE_EPOCH % 100000000 )) + FATARGS="${FATARGS} -N ${FATSERIAL}" + fi truncate -s "${FATSIZE}K" "${FATIMG}" mformat -v iPXE -i "${FATIMG}" ${FATARGS} :: mcopy -i "${FATIMG}" -s "${FATDIR}"/* :: -- cgit v1.2.3-55-g7522 From 0958e01463f7ad6a532939e77712ed31b4a12dbc Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Tue, 19 Dec 2023 16:29:42 +0000 Subject: [efi] Add relocation types generated by clang Add additional PC-relative relocation types that may be encountered when converting binaries compiled with clang. This mirrors the relevant elf2efi portions of wimboot commit 7910830 ("[build] Support building with the clang compiler"). Signed-off-by: Michael Brown --- src/util/elf2efi.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/util/elf2efi.c b/src/util/elf2efi.c index acde75c0..3bf6cbf9 100644 --- a/src/util/elf2efi.c +++ b/src/util/elf2efi.c @@ -828,6 +828,8 @@ static void process_reloc ( struct elf_file *elf, const Elf_Shdr *shdr, case ELF_MREL ( EM_ARM, R_ARM_V4BX ): case ELF_MREL ( EM_X86_64, R_X86_64_PC32 ) : case ELF_MREL ( EM_X86_64, R_X86_64_PLT32 ) : + case ELF_MREL ( EM_X86_64, R_X86_64_GOTPCRELX ) : + case ELF_MREL ( EM_X86_64, R_X86_64_REX_GOTPCRELX ) : case ELF_MREL ( EM_AARCH64, R_AARCH64_CALL26 ) : case ELF_MREL ( EM_AARCH64, R_AARCH64_JUMP26 ) : case ELF_MREL ( EM_AARCH64, R_AARCH64_ADR_PREL_LO21 ) : @@ -837,6 +839,7 @@ static void process_reloc ( struct elf_file *elf, const Elf_Shdr *shdr, case ELF_MREL ( EM_AARCH64, R_AARCH64_LDST16_ABS_LO12_NC ) : case ELF_MREL ( EM_AARCH64, R_AARCH64_LDST32_ABS_LO12_NC ) : case ELF_MREL ( EM_AARCH64, R_AARCH64_LDST64_ABS_LO12_NC ) : + case ELF_MREL ( EM_AARCH64, R_AARCH64_LDST128_ABS_LO12_NC ) : case ELF_MREL ( EM_LOONGARCH, R_LARCH_B26): case ELF_MREL ( EM_LOONGARCH, R_LARCH_PCALA_HI20 ): case ELF_MREL ( EM_LOONGARCH, R_LARCH_PCALA_LO12 ): -- cgit v1.2.3-55-g7522 From 3fc1b407d204e950a41c567e84f4c4f079cc052e Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Tue, 19 Dec 2023 16:56:34 +0000 Subject: [efi] Fix Coverity warning about unintended sign extension The result of multiplying a uint16_t by another uint16_t will be a signed int. Comparing this against a size_t will perform an unwanted sign extension. Fix by explicitly casting e_phnum to an unsigned int, thereby matching the data type used for the loop index variable (and avoiding the unwanted sign extension). This mirrors wimboot commit 15f6162 ("[efi] Fix Coverity warning about unintended sign extension"). Signed-off-by: Michael Brown --- src/util/elf2efi.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/util/elf2efi.c b/src/util/elf2efi.c index 3bf6cbf9..29e4f24a 100644 --- a/src/util/elf2efi.c +++ b/src/util/elf2efi.c @@ -440,8 +440,8 @@ static void read_elf_file ( const char *name, struct elf_file *elf ) { /* Check program headers */ if ( ( elf->len < ehdr->e_phoff ) || - ( ( elf->len - ehdr->e_phoff ) < ( ehdr->e_phnum * - ehdr->e_phentsize ) ) ) { + ( ( elf->len - ehdr->e_phoff ) < + ( ( ( unsigned int ) ehdr->e_phnum ) * ehdr->e_phentsize ) ) ) { eprintf ( "ELF program headers outside file in %s\n", name ); exit ( 1 ); } -- cgit v1.2.3-55-g7522 From 9e92c39894610c825a4cd6ccb40229fdeaa7223f Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Thu, 21 Dec 2023 12:29:03 +0000 Subject: [efi] Add potentially missing relocation types Add definitions for relocation types that may be missing on older versions of the host system's elf.h. This mirrors wimboot commit 47f6298 ("[efi] Add potentially missing relocation types"). Signed-off-by: Michael Brown --- src/util/elf2efi.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/util/elf2efi.c b/src/util/elf2efi.c index 29e4f24a..88713b66 100644 --- a/src/util/elf2efi.c +++ b/src/util/elf2efi.c @@ -122,6 +122,9 @@ #ifndef R_AARCH64_LDST64_ABS_LO12_NC #define R_AARCH64_LDST64_ABS_LO12_NC 286 #endif +#ifndef R_AARCH64_LDST128_ABS_LO12_NC +#define R_AARCH64_LDST128_ABS_LO12_NC 299 +#endif #ifndef R_ARM_CALL #define R_ARM_CALL 28 #endif @@ -152,6 +155,12 @@ #ifndef R_LARCH_GOT_PC_LO12 #define R_LARCH_GOT_PC_LO12 76 #endif +#ifndef R_X86_64_GOTPCRELX +#define R_X86_64_GOTPCRELX 41 +#endif +#ifndef R_X86_64_REX_GOTPCRELX +#define R_X86_64_REX_GOTPCRELX 42 +#endif /** * Alignment of raw data of sections in the image file -- cgit v1.2.3-55-g7522 From 119c415ee47aaef2717104fea493377aa9a65874 Mon Sep 17 00:00:00 2001 From: Christian Helmuth Date: Thu, 21 Dec 2023 13:51:26 +0100 Subject: [intel] Add PCI ID for I219-LM (23) Successfully tested on FUJITSU LIFEBOOK U7413. Signed-off-by: Christian Helmuth --- src/drivers/net/intel.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/drivers/net/intel.c b/src/drivers/net/intel.c index 46527bdb..7879714f 100644 --- a/src/drivers/net/intel.c +++ b/src/drivers/net/intel.c @@ -1043,6 +1043,7 @@ static struct pci_device_id intel_nics[] = { PCI_ROM ( 0x8086, 0x0d4f, "i219v-10", "I219-V (10)", INTEL_I219 ), PCI_ROM ( 0x8086, 0x0d53, "i219lm-12", "I219-LM (12)", INTEL_I219 ), PCI_ROM ( 0x8086, 0x0d55, "i219v-12", "I219-V (12)", INTEL_I219 ), + PCI_ROM ( 0x8086, 0x0dc5, "i219lm-23", "I219-LM (23)", INTEL_I219 ), PCI_ROM ( 0x8086, 0x1000, "82542-f", "82542 (Fiber)", 0 ), PCI_ROM ( 0x8086, 0x1001, "82543gc-f", "82543GC (Fiber)", 0 ), PCI_ROM ( 0x8086, 0x1004, "82543gc", "82543GC (Copper)", 0 ), -- cgit v1.2.3-55-g7522 From fa62213231a882eb6bbcefa7ad1106bdb9aaeae2 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Fri, 29 Dec 2023 19:38:12 +0000 Subject: [smbios] Support scanning for the 64-bit SMBIOS3 entry point Support scanning for the 64-bit SMBIOS3 entry point in addition to the 32-bit SMBIOS2 entry point. Prefer use of the 32-bit entry point if present, since this is guaranteed to be within accessible memory. Signed-off-by: Michael Brown --- src/arch/x86/interface/pcbios/bios_smbios.c | 55 +++++++++++++++++++- src/include/ipxe/smbios.h | 2 + src/interface/smbios/smbios.c | 78 ++++++++++++++++++++++++----- 3 files changed, 120 insertions(+), 15 deletions(-) diff --git a/src/arch/x86/interface/pcbios/bios_smbios.c b/src/arch/x86/interface/pcbios/bios_smbios.c index a8c0fc32..366679d3 100644 --- a/src/arch/x86/interface/pcbios/bios_smbios.c +++ b/src/arch/x86/interface/pcbios/bios_smbios.c @@ -44,11 +44,11 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); * @v smbios SMBIOS entry point descriptor structure to fill in * @ret rc Return status code */ -static int bios_find_smbios ( struct smbios *smbios ) { +static int bios_find_smbios2 ( struct smbios *smbios ) { struct smbios_entry entry; int rc; - /* Scan through BIOS segment to find SMBIOS entry point */ + /* Scan through BIOS segment to find SMBIOS 32-bit entry point */ if ( ( rc = find_smbios_entry ( real_to_user ( BIOS_SEG, 0 ), 0x10000, &entry ) ) != 0 ) return rc; @@ -62,4 +62,55 @@ static int bios_find_smbios ( struct smbios *smbios ) { return 0; } +/** + * Find SMBIOS + * + * @v smbios SMBIOS entry point descriptor structure to fill in + * @ret rc Return status code + */ +static int bios_find_smbios3 ( struct smbios *smbios ) { + struct smbios3_entry entry; + int rc; + + /* Scan through BIOS segment to find SMBIOS 64-bit entry point */ + if ( ( rc = find_smbios3_entry ( real_to_user ( BIOS_SEG, 0 ), 0x10000, + &entry ) ) != 0 ) + return rc; + + /* Check that address is accessible */ + if ( entry.smbios_address > ~( ( physaddr_t ) 0 ) ) { + DBG ( "SMBIOS3 at %08llx is inaccessible\n", + ( ( unsigned long long ) entry.smbios_address ) ); + return -ENOTSUP; + } + + /* Fill in entry point descriptor structure */ + smbios->address = phys_to_user ( entry.smbios_address ); + smbios->len = entry.smbios_len; + smbios->count = 0; + smbios->version = SMBIOS_VERSION ( entry.major, entry.minor ); + + return 0; +} + +/** + * Find SMBIOS + * + * @v smbios SMBIOS entry point descriptor structure to fill in + * @ret rc Return status code + */ +static int bios_find_smbios ( struct smbios *smbios ) { + int rc; + + /* Use 32-bit table if present */ + if ( ( rc = bios_find_smbios2 ( smbios ) ) == 0 ) + return 0; + + /* Otherwise, use 64-bit table if present and accessible */ + if ( ( rc = bios_find_smbios3 ( smbios ) ) == 0 ) + return 0; + + return rc; +} + PROVIDE_SMBIOS ( pcbios, find_smbios, bios_find_smbios ); diff --git a/src/include/ipxe/smbios.h b/src/include/ipxe/smbios.h index 42278fb2..077a67a8 100644 --- a/src/include/ipxe/smbios.h +++ b/src/include/ipxe/smbios.h @@ -227,6 +227,8 @@ struct smbios { extern int find_smbios ( struct smbios *smbios ); extern int find_smbios_entry ( userptr_t start, size_t len, struct smbios_entry *entry ); +extern int find_smbios3_entry ( userptr_t start, size_t len, + struct smbios3_entry *entry ); extern int find_smbios_structure ( unsigned int type, unsigned int instance, struct smbios_structure *structure ); extern int read_smbios_structure ( struct smbios_structure *structure, diff --git a/src/interface/smbios/smbios.c b/src/interface/smbios/smbios.c index 12a080da..fdd14499 100644 --- a/src/interface/smbios/smbios.c +++ b/src/interface/smbios/smbios.c @@ -42,7 +42,27 @@ static struct smbios smbios = { }; /** - * Scan for SMBIOS entry point structure + * Calculate SMBIOS entry point structure checksum + * + * @v start Start address of region + * @v offset Offset of SMBIOS entry point structure + * @v len Length of entry point structure + * @ret sum Byte checksum + */ +static uint8_t smbios_checksum ( userptr_t start, size_t offset, size_t len ) { + size_t end = ( offset + len ); + uint8_t sum; + uint8_t byte; + + for ( sum = 0 ; offset < end ; offset++ ) { + copy_from_user ( &byte, start, offset, sizeof ( byte ) ); + sum += byte; + } + return sum; +} + +/** + * Scan for SMBIOS 32-bit entry point structure * * @v start Start address of region to scan * @v len Length of region to scan @@ -51,28 +71,20 @@ static struct smbios smbios = { */ int find_smbios_entry ( userptr_t start, size_t len, struct smbios_entry *entry ) { - uint8_t buf[256]; /* 256 is maximum length possible */ static size_t offset = 0; /* Avoid repeated attempts to locate SMBIOS */ - size_t entry_len; - unsigned int i; uint8_t sum; /* Try to find SMBIOS */ - for ( ; offset < len ; offset += 0x10 ) { + for ( ; ( offset + sizeof ( *entry ) ) <= len ; offset += 0x10 ) { /* Read start of header and verify signature */ copy_from_user ( entry, start, offset, sizeof ( *entry ) ); if ( entry->signature != SMBIOS_SIGNATURE ) continue; - /* Read whole header and verify checksum */ - entry_len = entry->len; - assert ( entry_len <= sizeof ( buf ) ); - copy_from_user ( buf, start, offset, entry_len ); - for ( i = 0, sum = 0 ; i < entry_len ; i++ ) { - sum += buf[i]; - } - if ( sum != 0 ) { + /* Verify checksum */ + if ( ( sum = smbios_checksum ( start, offset, + entry->len ) ) != 0 ) { DBG ( "SMBIOS at %08lx has bad checksum %02x\n", user_to_phys ( start, offset ), sum ); continue; @@ -89,6 +101,46 @@ int find_smbios_entry ( userptr_t start, size_t len, return -ENODEV; } +/** + * Scan for SMBIOS 64-bit entry point structure + * + * @v start Start address of region to scan + * @v len Length of region to scan + * @v entry SMBIOS entry point structure to fill in + * @ret rc Return status code + */ +int find_smbios3_entry ( userptr_t start, size_t len, + struct smbios3_entry *entry ) { + static size_t offset = 0; /* Avoid repeated attempts to locate SMBIOS */ + uint8_t sum; + + /* Try to find SMBIOS */ + for ( ; ( offset + sizeof ( *entry ) ) <= len ; offset += 0x10 ) { + + /* Read start of header and verify signature */ + copy_from_user ( entry, start, offset, sizeof ( *entry ) ); + if ( entry->signature != SMBIOS3_SIGNATURE ) + continue; + + /* Verify checksum */ + if ( ( sum = smbios_checksum ( start, offset, + entry->len ) ) != 0 ) { + DBG ( "SMBIOS3 at %08lx has bad checksum %02x\n", + user_to_phys ( start, offset ), sum ); + continue; + } + + /* Fill result structure */ + DBG ( "Found SMBIOS3 v%d.%d entry point at %08lx\n", + entry->major, entry->minor, + user_to_phys ( start, offset ) ); + return 0; + } + + DBG ( "No SMBIOS3 found\n" ); + return -ENODEV; +} + /** * Find SMBIOS strings terminator * -- cgit v1.2.3-55-g7522 From 4ed7a5718f29e59c19d6bef51dc3430861c9da87 Mon Sep 17 00:00:00 2001 From: Mark Rogalski Date: Mon, 8 Jan 2024 10:03:12 -0600 Subject: [build] Reduce scope of wildcard .gitignore rules Ensure that .gitignore rules do not cover any files that do exist within the repository. Modified-by: Michael Brown Signed-off-by: Michael Brown --- src/.gitignore | 2 +- src/bin/.gitignore | 1 + src/config/local/.gitignore | 1 + 3 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/.gitignore b/src/.gitignore index cc8e33e2..4e4f00c8 100644 --- a/src/.gitignore +++ b/src/.gitignore @@ -1,4 +1,4 @@ .toolcheck .echocheck TAGS* -bin* +bin-* diff --git a/src/bin/.gitignore b/src/bin/.gitignore index 72e8ffc0..d6b7ef32 100644 --- a/src/bin/.gitignore +++ b/src/bin/.gitignore @@ -1 +1,2 @@ * +!.gitignore diff --git a/src/config/local/.gitignore b/src/config/local/.gitignore index 72e8ffc0..d6b7ef32 100644 --- a/src/config/local/.gitignore +++ b/src/config/local/.gitignore @@ -1 +1,2 @@ * +!.gitignore -- cgit v1.2.3-55-g7522 From 0abb3e85e518c4d9366d4555093c0aff0c060858 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Wed, 10 Jan 2024 15:28:59 +0000 Subject: [eap] Ignore any received EAP responses EAP responses (including our own) may be broadcast by switches but are not of interest to us and can be safely ignored if received. Signed-off-by: Michael Brown --- src/include/ipxe/eap.h | 3 +++ src/net/eap.c | 3 +++ 2 files changed, 6 insertions(+) diff --git a/src/include/ipxe/eap.h b/src/include/ipxe/eap.h index 818862a9..4b689cc2 100644 --- a/src/include/ipxe/eap.h +++ b/src/include/ipxe/eap.h @@ -26,6 +26,9 @@ struct eap_header { /** EAP request */ #define EAP_CODE_REQUEST 1 +/** EAP response */ +#define EAP_CODE_RESPONSE 2 + /** EAP request */ struct eap_request { /** Header */ diff --git a/src/net/eap.c b/src/net/eap.c index 2c68b75d..8ba87e29 100644 --- a/src/net/eap.c +++ b/src/net/eap.c @@ -149,6 +149,9 @@ int eap_rx ( struct eap_supplicant *supplicant, const void *data, switch ( eap->hdr.code ) { case EAP_CODE_REQUEST: return eap_rx_request ( supplicant, &eap->req, len ); + case EAP_CODE_RESPONSE: + DBGC2 ( netdev, "EAP %s ignoring response\n", netdev->name ); + return 0; case EAP_CODE_SUCCESS: return eap_rx_success ( supplicant ); case EAP_CODE_FAILURE: -- cgit v1.2.3-55-g7522 From c6226f104e22db7d19b4c983e962d84b5665c04b Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Wed, 10 Jan 2024 15:30:36 +0000 Subject: [eap] Add support for sending an EAP identity Allow the ${netX/username} setting to be used to specify an EAP identity to be returned in response to a Request-Identity, and provide a mechanism for responding with a NAK to indicate which authentication types we support. If no identity is specified then fall back to the current behaviour of not sending any Request-Identity response, so that switches will time out and switch to MAC Authentication Bypass (MAB) if applicable. Signed-off-by: Michael Brown --- src/include/ipxe/eap.h | 45 ++++++++++++-- src/net/eap.c | 157 ++++++++++++++++++++++++++++++++++++++++++------- 2 files changed, 177 insertions(+), 25 deletions(-) diff --git a/src/include/ipxe/eap.h b/src/include/ipxe/eap.h index 4b689cc2..bbae517d 100644 --- a/src/include/ipxe/eap.h +++ b/src/include/ipxe/eap.h @@ -12,6 +12,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #include #include #include +#include /** EAP header */ struct eap_header { @@ -29,17 +30,25 @@ struct eap_header { /** EAP response */ #define EAP_CODE_RESPONSE 2 -/** EAP request */ -struct eap_request { +/** EAP request/response message */ +struct eap_message { /** Header */ struct eap_header hdr; /** Type */ uint8_t type; + /** Type data */ + uint8_t data[0]; } __attribute__ (( packed )); +/** EAP "no available types" marker */ +#define EAP_TYPE_NONE 0 + /** EAP identity */ #define EAP_TYPE_IDENTITY 1 +/** EAP NAK */ +#define EAP_TYPE_NAK 3 + /** EAP success */ #define EAP_CODE_SUCCESS 3 @@ -50,8 +59,8 @@ struct eap_request { union eap_packet { /** Header */ struct eap_header hdr; - /** Request */ - struct eap_request req; + /** Request/response message */ + struct eap_message msg; }; /** EAP link block timeout @@ -90,7 +99,11 @@ struct eap_supplicant { /** Network device */ struct net_device *netdev; /** Flags */ - unsigned int flags; + uint16_t flags; + /** ID for current request/response */ + uint8_t id; + /** Type for current request/response */ + uint8_t type; /** * Transmit EAP response * @@ -120,6 +133,28 @@ struct eap_supplicant { */ #define EAP_FL_PASSIVE 0x0002 +/** An EAP method */ +struct eap_method { + /** Type */ + uint8_t type; + /** + * Handle EAP request + * + * @v supplicant EAP supplicant + * @v req Request type data + * @v req_len Length of request type data + * @ret rc Return status code + */ + int ( * rx ) ( struct eap_supplicant *supplicant, + const void *req, size_t req_len ); +}; + +/** EAP method table */ +#define EAP_METHODS __table ( struct eap_method, "eap_methods" ) + +/** Declare an EAP method */ +#define __eap_method __table_entry ( EAP_METHODS, 01 ) + extern int eap_rx ( struct eap_supplicant *supplicant, const void *data, size_t len ); diff --git a/src/net/eap.c b/src/net/eap.c index 8ba87e29..fe01f136 100644 --- a/src/net/eap.c +++ b/src/net/eap.c @@ -23,7 +23,10 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); +#include #include +#include +#include #include #include @@ -33,60 +36,174 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); * */ +/** + * Transmit EAP response + * + * @v supplicant EAP supplicant + * @v rsp Response type data + * @v rsp_len Length of response type data + * @ret rc Return status code + */ +static int eap_tx_response ( struct eap_supplicant *supplicant, + const void *rsp, size_t rsp_len ) { + struct net_device *netdev = supplicant->netdev; + struct eap_message *msg; + size_t len; + int rc; + + /* Allocate and populate response */ + len = ( sizeof ( *msg ) + rsp_len ); + msg = malloc ( len ); + if ( ! msg ) { + rc = -ENOMEM; + goto err_alloc; + } + msg->hdr.code = EAP_CODE_RESPONSE; + msg->hdr.id = supplicant->id; + msg->hdr.len = htons ( len ); + msg->type = supplicant->type; + memcpy ( msg->data, rsp, rsp_len ); + + /* Transmit response */ + if ( ( rc = supplicant->tx ( supplicant, msg, len ) ) != 0 ) { + DBGC ( netdev, "EAP %s could not transmit: %s\n", + netdev->name, strerror ( rc ) ); + goto err_tx; + } + + err_tx: + free ( msg ); + err_alloc: + return rc; +} + +/** + * Transmit EAP NAK + * + * @v supplicant EAP supplicant + * @ret rc Return status code + */ +static int eap_tx_nak ( struct eap_supplicant *supplicant ) { + unsigned int max = table_num_entries ( EAP_METHODS ); + uint8_t methods[ max + 1 /* potential EAP_TYPE_NONE */ ]; + unsigned int count = 0; + struct eap_method *method; + + /* Populate methods list */ + for_each_table_entry ( method, EAP_METHODS ) { + if ( method->type > EAP_TYPE_NAK ) + methods[count++] = method->type; + } + if ( ! count ) + methods[count++] = EAP_TYPE_NONE; + assert ( count <= max ); + + /* Transmit response */ + supplicant->type = EAP_TYPE_NAK; + return eap_tx_response ( supplicant, methods, count ); +} + /** * Handle EAP Request-Identity * * @v supplicant EAP supplicant + * @v req Request type data + * @v req_len Length of request type data * @ret rc Return status code */ -static int eap_rx_request_identity ( struct eap_supplicant *supplicant ) { +static int eap_rx_identity ( struct eap_supplicant *supplicant, + const void *req, size_t req_len ) { struct net_device *netdev = supplicant->netdev; + void *rsp; + int rsp_len; + int rc; /* Treat Request-Identity as blocking the link */ DBGC ( netdev, "EAP %s Request-Identity blocking link\n", netdev->name ); + DBGC_HDA ( netdev, 0, req, req_len ); netdev_link_block ( netdev, EAP_BLOCK_TIMEOUT ); /* Mark EAP as in progress */ supplicant->flags |= EAP_FL_ONGOING; - /* We have no identity to offer, so wait until the switch - * times out and switches to MAC Authentication Bypass (MAB). - */ - supplicant->flags |= EAP_FL_PASSIVE; + /* Construct response, if applicable */ + rsp_len = fetch_raw_setting_copy ( netdev_settings ( netdev ), + &username_setting, &rsp ); + if ( rsp_len < 0 ) { + /* We have no identity to offer, so wait until the + * switch times out and switches to MAC Authentication + * Bypass (MAB). + */ + DBGC2 ( netdev, "EAP %s has no identity\n", netdev->name ); + supplicant->flags |= EAP_FL_PASSIVE; + rc = 0; + goto no_response; + } - return 0; + /* Transmit response */ + if ( ( rc = eap_tx_response ( supplicant, rsp, rsp_len ) ) != 0 ) + goto err_tx; + + err_tx: + free ( rsp ); + no_response: + return rc; } +/** EAP Request-Identity method */ +struct eap_method eap_identity_method __eap_method = { + .type = EAP_TYPE_IDENTITY, + .rx = eap_rx_identity, +}; + /** * Handle EAP Request * * @v supplicant EAP supplicant - * @v req EAP request + * @v msg EAP request * @v len Length of EAP request * @ret rc Return status code */ static int eap_rx_request ( struct eap_supplicant *supplicant, - const struct eap_request *req, size_t len ) { + const struct eap_message *msg, size_t len ) { struct net_device *netdev = supplicant->netdev; + struct eap_method *method; + const void *req; + size_t req_len; - /* Sanity check */ - if ( len < sizeof ( *req ) ) { + /* Sanity checks */ + if ( len < sizeof ( *msg ) ) { DBGC ( netdev, "EAP %s underlength request:\n", netdev->name ); - DBGC_HDA ( netdev, 0, req, len ); + DBGC_HDA ( netdev, 0, msg, len ); + return -EINVAL; + } + if ( len < ntohs ( msg->hdr.len ) ) { + DBGC ( netdev, "EAP %s truncated request:\n", netdev->name ); + DBGC_HDA ( netdev, 0, msg, len ); return -EINVAL; } + req = msg->data; + req_len = ( ntohs ( msg->hdr.len ) - sizeof ( *msg ) ); + + /* Record request details */ + supplicant->id = msg->hdr.id; + supplicant->type = msg->type; /* Handle according to type */ - switch ( req->type ) { - case EAP_TYPE_IDENTITY: - return eap_rx_request_identity ( supplicant ); - default: - DBGC ( netdev, "EAP %s requested type %d unknown:\n", - netdev->name, req->type ); - DBGC_HDA ( netdev, 0, req, len ); - return -ENOTSUP; + for_each_table_entry ( method, EAP_METHODS ) { + if ( msg->type == method->type ) + return method->rx ( supplicant, req, req_len ); } + DBGC ( netdev, "EAP %s requested type %d unknown:\n", + netdev->name, msg->type ); + DBGC_HDA ( netdev, 0, msg, len ); + + /* Send NAK if applicable */ + if ( msg->type > EAP_TYPE_NAK ) + return eap_tx_nak ( supplicant ); + + return -ENOTSUP; } /** @@ -148,7 +265,7 @@ int eap_rx ( struct eap_supplicant *supplicant, const void *data, /* Handle according to code */ switch ( eap->hdr.code ) { case EAP_CODE_REQUEST: - return eap_rx_request ( supplicant, &eap->req, len ); + return eap_rx_request ( supplicant, &eap->msg, len ); case EAP_CODE_RESPONSE: DBGC2 ( netdev, "EAP %s ignoring response\n", netdev->name ); return 0; -- cgit v1.2.3-55-g7522 From 08fcb0e8fba4ef1dc770253bfbb330fa0c02e096 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Wed, 10 Jan 2024 15:23:07 +0000 Subject: [eap] Add support for the MD5-Challenge authentication type RFC 3748 states that support for MD5-Challenge is mandatory for EAP implementations. The MD5 and CHAP code is already included in the default build since it is required by iSCSI, and so this does not substantially increase the binary size. Signed-off-by: Michael Brown --- src/include/ipxe/eap.h | 11 +++++++ src/net/eap.c | 80 ++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 91 insertions(+) diff --git a/src/include/ipxe/eap.h b/src/include/ipxe/eap.h index bbae517d..cf1c7c00 100644 --- a/src/include/ipxe/eap.h +++ b/src/include/ipxe/eap.h @@ -49,6 +49,17 @@ struct eap_message { /** EAP NAK */ #define EAP_TYPE_NAK 3 +/** EAP MD5 challenge request/response */ +#define EAP_TYPE_MD5 4 + +/** EAP MD5 challenge request/response type data */ +struct eap_md5 { + /** Value length */ + uint8_t len; + /** Value */ + uint8_t value[0]; +} __attribute__ (( packed )); + /** EAP success */ #define EAP_CODE_SUCCESS 3 diff --git a/src/net/eap.c b/src/net/eap.c index fe01f136..79b060aa 100644 --- a/src/net/eap.c +++ b/src/net/eap.c @@ -28,6 +28,8 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #include #include #include +#include +#include #include /** @file @@ -157,6 +159,84 @@ struct eap_method eap_identity_method __eap_method = { .rx = eap_rx_identity, }; +/** + * Handle EAP MD5-Challenge + * + * @v req Request type data + * @v req_len Length of request type data + * @ret rc Return status code + */ +static int eap_rx_md5 ( struct eap_supplicant *supplicant, + const void *req, size_t req_len ) { + struct net_device *netdev = supplicant->netdev; + const struct eap_md5 *md5req = req; + struct { + uint8_t len; + uint8_t value[MD5_DIGEST_SIZE]; + } __attribute__ (( packed )) md5rsp; + struct chap_response chap; + void *secret; + int secret_len; + int rc; + + /* Sanity checks */ + if ( req_len < sizeof ( *md5req ) ) { + DBGC ( netdev, "EAP %s underlength MD5-Challenge:\n", + netdev->name ); + DBGC_HDA ( netdev, 0, req, req_len ); + rc = -EINVAL; + goto err_sanity; + } + if ( ( req_len - sizeof ( *md5req ) ) < md5req->len ) { + DBGC ( netdev, "EAP %s truncated MD5-Challenge:\n", + netdev->name ); + DBGC_HDA ( netdev, 0, req, req_len ); + rc = -EINVAL; + goto err_sanity; + } + + /* Construct response */ + if ( ( rc = chap_init ( &chap, &md5_algorithm ) ) != 0 ) { + DBGC ( netdev, "EAP %s could not initialise CHAP: %s\n", + netdev->name, strerror ( rc ) ); + goto err_chap; + } + chap_set_identifier ( &chap, supplicant->id ); + secret_len = fetch_raw_setting_copy ( netdev_settings ( netdev ), + &password_setting, &secret ); + if ( secret_len < 0 ) { + rc = secret_len; + DBGC ( netdev, "EAP %s has no secret: %s\n", + netdev->name, strerror ( rc ) ); + goto err_secret; + } + chap_update ( &chap, secret, secret_len ); + chap_update ( &chap, md5req->value, md5req->len ); + chap_respond ( &chap ); + assert ( chap.response_len == sizeof ( md5rsp.value ) ); + md5rsp.len = sizeof ( md5rsp.value ); + memcpy ( md5rsp.value, chap.response, sizeof ( md5rsp.value ) ); + + /* Transmit response */ + if ( ( rc = eap_tx_response ( supplicant, &md5rsp, + sizeof ( md5rsp ) ) ) != 0 ) + goto err_tx; + + err_tx: + free ( secret ); + err_secret: + chap_finish ( &chap ); + err_chap: + err_sanity: + return rc; +} + +/** EAP MD5-Challenge method */ +struct eap_method eap_md5_method __eap_method = { + .type = EAP_TYPE_MD5, + .rx = eap_rx_md5, +}; + /** * Handle EAP Request * -- cgit v1.2.3-55-g7522 From e66552eeede19a91b1a52468a550b58fd031777b Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Sun, 14 Jan 2024 11:51:16 +0000 Subject: [build] Remove unnecessary ".text" directives The .text directive is entirely redundant when followed by a .section directive giving an explicit section name and attributes. Remove these unnecessary directives to simplify the code. Signed-off-by: Michael Brown --- src/arch/arm32/libgcc/lldivmod.S | 1 - src/arch/arm32/libgcc/llshift.S | 1 - src/arch/x86/core/patch_cf.S | 1 - src/arch/x86/drivers/net/undiisr.S | 1 - src/arch/x86/interface/pcbios/e820mangler.S | 1 - src/arch/x86/prefix/bootpart.S | 1 - src/arch/x86/prefix/dskprefix.S | 1 - src/arch/x86/prefix/exeprefix.S | 1 - src/arch/x86/prefix/hdprefix.S | 1 - src/arch/x86/prefix/lkrnprefix.S | 1 - src/arch/x86/prefix/mbr.S | 1 - src/arch/x86/prefix/mromprefix.S | 1 - src/arch/x86/prefix/nbiprefix.S | 1 - src/arch/x86/prefix/nullprefix.S | 1 - src/arch/x86/prefix/pxeprefix.S | 1 - src/arch/x86/prefix/rawprefix.S | 1 - src/arch/x86/prefix/romprefix.S | 1 - src/arch/x86/prefix/undiloader.S | 1 - src/arch/x86/prefix/unlzma.S | 1 - src/arch/x86/prefix/usbdisk.S | 1 - src/arch/x86/transitions/libkir.S | 1 - 21 files changed, 21 deletions(-) diff --git a/src/arch/arm32/libgcc/lldivmod.S b/src/arch/arm32/libgcc/lldivmod.S index 746fa8fd..c9c22450 100644 --- a/src/arch/arm32/libgcc/lldivmod.S +++ b/src/arch/arm32/libgcc/lldivmod.S @@ -1,7 +1,6 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ) .section ".note.GNU-stack", "", %progbits - .text .thumb /** diff --git a/src/arch/arm32/libgcc/llshift.S b/src/arch/arm32/libgcc/llshift.S index c1b51e77..592e28e6 100644 --- a/src/arch/arm32/libgcc/llshift.S +++ b/src/arch/arm32/libgcc/llshift.S @@ -1,7 +1,6 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ) .section ".note.GNU-stack", "", %progbits - .text .arm /** diff --git a/src/arch/x86/core/patch_cf.S b/src/arch/x86/core/patch_cf.S index 63730c3f..ebf62876 100644 --- a/src/arch/x86/core/patch_cf.S +++ b/src/arch/x86/core/patch_cf.S @@ -23,7 +23,6 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ) .section ".note.GNU-stack", "", @progbits - .text .arch i386 .code16 diff --git a/src/arch/x86/drivers/net/undiisr.S b/src/arch/x86/drivers/net/undiisr.S index a1098b83..aa8991d7 100644 --- a/src/arch/x86/drivers/net/undiisr.S +++ b/src/arch/x86/drivers/net/undiisr.S @@ -11,7 +11,6 @@ FILE_LICENCE ( GPL2_OR_LATER ) #define PIC2_ICR 0xa0 .section ".note.GNU-stack", "", @progbits - .text .arch i386 .code16 diff --git a/src/arch/x86/interface/pcbios/e820mangler.S b/src/arch/x86/interface/pcbios/e820mangler.S index 46e1cab4..40f84c70 100644 --- a/src/arch/x86/interface/pcbios/e820mangler.S +++ b/src/arch/x86/interface/pcbios/e820mangler.S @@ -24,7 +24,6 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ) .section ".note.GNU-stack", "", @progbits - .text .arch i386 .code16 diff --git a/src/arch/x86/prefix/bootpart.S b/src/arch/x86/prefix/bootpart.S index 575cb1c0..cf75ff79 100644 --- a/src/arch/x86/prefix/bootpart.S +++ b/src/arch/x86/prefix/bootpart.S @@ -6,7 +6,6 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ) #define STACK_SIZE 0x2000 .section ".note.GNU-stack", "", @progbits - .text .arch i386 .section ".prefix", "awx", @progbits .code16 diff --git a/src/arch/x86/prefix/dskprefix.S b/src/arch/x86/prefix/dskprefix.S index bc194887..f9d30195 100644 --- a/src/arch/x86/prefix/dskprefix.S +++ b/src/arch/x86/prefix/dskprefix.S @@ -27,7 +27,6 @@ FILE_LICENCE ( GPL2_ONLY ) .section ".note.GNU-stack", "", @progbits .org 0 .arch i386 - .text .section ".prefix", "ax", @progbits .code16 .globl _dsk_start diff --git a/src/arch/x86/prefix/exeprefix.S b/src/arch/x86/prefix/exeprefix.S index 5b2605e8..86333489 100644 --- a/src/arch/x86/prefix/exeprefix.S +++ b/src/arch/x86/prefix/exeprefix.S @@ -37,7 +37,6 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ) #define PSP_CMDLINE_START 0x81 .section ".note.GNU-stack", "", @progbits - .text .arch i386 .org 0 .code16 diff --git a/src/arch/x86/prefix/hdprefix.S b/src/arch/x86/prefix/hdprefix.S index fbf8d2e4..1bbf72dd 100644 --- a/src/arch/x86/prefix/hdprefix.S +++ b/src/arch/x86/prefix/hdprefix.S @@ -3,7 +3,6 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ) #include .section ".note.GNU-stack", "", @progbits - .text .arch i386 .section ".prefix", "awx", @progbits .code16 diff --git a/src/arch/x86/prefix/lkrnprefix.S b/src/arch/x86/prefix/lkrnprefix.S index 2c17f79d..9f1a2f09 100644 --- a/src/arch/x86/prefix/lkrnprefix.S +++ b/src/arch/x86/prefix/lkrnprefix.S @@ -5,7 +5,6 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ) #define BZI_LOAD_HIGH_ADDR 0x100000 .section ".note.GNU-stack", "", @progbits - .text .arch i386 .code16 .section ".prefix", "ax", @progbits diff --git a/src/arch/x86/prefix/mbr.S b/src/arch/x86/prefix/mbr.S index 928bb338..b37eed71 100644 --- a/src/arch/x86/prefix/mbr.S +++ b/src/arch/x86/prefix/mbr.S @@ -1,7 +1,6 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ) .section ".note.GNU-stack", "", @progbits - .text .arch i386 .section ".prefix", "awx", @progbits .code16 diff --git a/src/arch/x86/prefix/mromprefix.S b/src/arch/x86/prefix/mromprefix.S index 5f3496b2..543fd006 100644 --- a/src/arch/x86/prefix/mromprefix.S +++ b/src/arch/x86/prefix/mromprefix.S @@ -42,7 +42,6 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ) #include "pciromprefix.S" .section ".note.GNU-stack", "", @progbits - .text .arch i386 .code16 diff --git a/src/arch/x86/prefix/nbiprefix.S b/src/arch/x86/prefix/nbiprefix.S index cae1009b..0a74ca71 100644 --- a/src/arch/x86/prefix/nbiprefix.S +++ b/src/arch/x86/prefix/nbiprefix.S @@ -3,7 +3,6 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ) #include .section ".note.GNU-stack", "", @progbits - .text .arch i386 .code16 .section ".prefix", "ax", @progbits diff --git a/src/arch/x86/prefix/nullprefix.S b/src/arch/x86/prefix/nullprefix.S index 1568188d..bbc697fd 100644 --- a/src/arch/x86/prefix/nullprefix.S +++ b/src/arch/x86/prefix/nullprefix.S @@ -2,7 +2,6 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ) .section ".note.GNU-stack", "", @progbits .org 0 - .text .arch i386 .section ".prefix", "ax", @progbits diff --git a/src/arch/x86/prefix/pxeprefix.S b/src/arch/x86/prefix/pxeprefix.S index 494fbc13..c62a5011 100644 --- a/src/arch/x86/prefix/pxeprefix.S +++ b/src/arch/x86/prefix/pxeprefix.S @@ -12,7 +12,6 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ) #define PXE_HACK_EB54 0x0001 .section ".note.GNU-stack", "", @progbits - .text .arch i386 .org 0 .code16 diff --git a/src/arch/x86/prefix/rawprefix.S b/src/arch/x86/prefix/rawprefix.S index 4a3d3504..d97b3b51 100644 --- a/src/arch/x86/prefix/rawprefix.S +++ b/src/arch/x86/prefix/rawprefix.S @@ -9,7 +9,6 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ) .section ".note.GNU-stack", "", @progbits - .text .arch i386 .org 0 .code16 diff --git a/src/arch/x86/prefix/romprefix.S b/src/arch/x86/prefix/romprefix.S index 79fed2a3..09837cee 100644 --- a/src/arch/x86/prefix/romprefix.S +++ b/src/arch/x86/prefix/romprefix.S @@ -55,7 +55,6 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ) #endif .section ".note.GNU-stack", "", @progbits - .text .code16 .arch i386 .section ".prefix", "ax", @progbits diff --git a/src/arch/x86/prefix/undiloader.S b/src/arch/x86/prefix/undiloader.S index e544d504..33573230 100644 --- a/src/arch/x86/prefix/undiloader.S +++ b/src/arch/x86/prefix/undiloader.S @@ -3,7 +3,6 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ) #include .section ".note.GNU-stack", "", @progbits - .text .code16 .arch i386 .section ".prefix", "ax", @progbits diff --git a/src/arch/x86/prefix/unlzma.S b/src/arch/x86/prefix/unlzma.S index f4bd81bd..4059090b 100644 --- a/src/arch/x86/prefix/unlzma.S +++ b/src/arch/x86/prefix/unlzma.S @@ -44,7 +44,6 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); */ .section ".note.GNU-stack", "", @progbits - .text .arch i486 .section ".prefix.lib", "ax", @progbits diff --git a/src/arch/x86/prefix/usbdisk.S b/src/arch/x86/prefix/usbdisk.S index 461a0837..b8fc5e95 100644 --- a/src/arch/x86/prefix/usbdisk.S +++ b/src/arch/x86/prefix/usbdisk.S @@ -3,7 +3,6 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ) #include .section ".note.GNU-stack", "", @progbits - .text .arch i386 .section ".prefix", "awx", @progbits .code16 diff --git a/src/arch/x86/transitions/libkir.S b/src/arch/x86/transitions/libkir.S index af090b26..5909654c 100644 --- a/src/arch/x86/transitions/libkir.S +++ b/src/arch/x86/transitions/libkir.S @@ -32,7 +32,6 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ) #define BOCHSBP xchgw %bx, %bx .section ".note.GNU-stack", "", @progbits - .text .arch i386 .section ".text16", "awx", @progbits .code16 -- cgit v1.2.3-55-g7522 From 6ca597eee9f95b846a3c2dc1231e63cfc02272c1 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Sun, 14 Jan 2024 12:12:18 +0000 Subject: [build] Fix building with newer binutils Newer versions of the GNU assembler (observed with binutils 2.41) will complain about the ".arch i386" in files assembled with "as --64", with the message "Error: 64bit mode not supported on 'i386'". In files such as stack.S that contain no instructions to be assembled, the ".arch i386" is redundant and may be removed entirely. In the remaining files, fix by moving ".arch i386" below the relevant ".code16" or ".code32" directive, so that the assembler is no longer expecting 64-bit instructions to be used by the time that the ".arch i386" directive is encountered. Reported-by: Ali Mustakim Signed-off-by: Michael Brown --- src/arch/i386/core/setjmp.S | 2 +- src/arch/i386/tests/gdbstub_test.S | 1 + src/arch/x86/core/patch_cf.S | 2 +- src/arch/x86/core/stack.S | 1 - src/arch/x86/core/stack16.S | 1 - src/arch/x86/drivers/net/undiisr.S | 2 +- src/arch/x86/interface/pcbios/e820mangler.S | 2 +- src/arch/x86/interface/pxe/pxe_entry.S | 1 + src/arch/x86/prefix/bootpart.S | 2 +- src/arch/x86/prefix/dskprefix.S | 2 +- src/arch/x86/prefix/exeprefix.S | 2 +- src/arch/x86/prefix/hdprefix.S | 2 +- src/arch/x86/prefix/libprefix.S | 1 + src/arch/x86/prefix/lkrnprefix.S | 2 +- src/arch/x86/prefix/mbr.S | 2 +- src/arch/x86/prefix/mromprefix.S | 2 +- src/arch/x86/prefix/nbiprefix.S | 2 +- src/arch/x86/prefix/nullprefix.S | 2 +- src/arch/x86/prefix/pxeprefix.S | 2 +- src/arch/x86/prefix/rawprefix.S | 2 +- src/arch/x86/prefix/unlzma.S | 1 + src/arch/x86/prefix/usbdisk.S | 2 +- src/arch/x86/transitions/liba20.S | 1 + src/arch/x86/transitions/libkir.S | 2 +- 24 files changed, 22 insertions(+), 19 deletions(-) diff --git a/src/arch/i386/core/setjmp.S b/src/arch/i386/core/setjmp.S index e0bbb7ef..cbb5e713 100644 --- a/src/arch/i386/core/setjmp.S +++ b/src/arch/i386/core/setjmp.S @@ -2,8 +2,8 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ) .section ".note.GNU-stack", "", @progbits .text - .arch i386 .code32 + .arch i386 /* Must match jmp_buf structure layout */ .struct 0 diff --git a/src/arch/i386/tests/gdbstub_test.S b/src/arch/i386/tests/gdbstub_test.S index e0c9e6c9..e44c13c2 100644 --- a/src/arch/i386/tests/gdbstub_test.S +++ b/src/arch/i386/tests/gdbstub_test.S @@ -1,4 +1,5 @@ .section ".note.GNU-stack", "", @progbits + .code32 .arch i386 .section ".data", "aw", @progbits diff --git a/src/arch/x86/core/patch_cf.S b/src/arch/x86/core/patch_cf.S index ebf62876..62f19e45 100644 --- a/src/arch/x86/core/patch_cf.S +++ b/src/arch/x86/core/patch_cf.S @@ -23,8 +23,8 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ) .section ".note.GNU-stack", "", @progbits - .arch i386 .code16 + .arch i386 /**************************************************************************** * Set/clear CF on the stack as appropriate, assumes stack is as it should diff --git a/src/arch/x86/core/stack.S b/src/arch/x86/core/stack.S index 49345347..1bcaf18f 100644 --- a/src/arch/x86/core/stack.S +++ b/src/arch/x86/core/stack.S @@ -1,7 +1,6 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ) .section ".note.GNU-stack", "", @progbits - .arch i386 #ifdef __x86_64__ #define STACK_SIZE 8192 diff --git a/src/arch/x86/core/stack16.S b/src/arch/x86/core/stack16.S index d3949a55..622887ea 100644 --- a/src/arch/x86/core/stack16.S +++ b/src/arch/x86/core/stack16.S @@ -1,7 +1,6 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ) .section ".note.GNU-stack", "", @progbits - .arch i386 /**************************************************************************** * Internal stack diff --git a/src/arch/x86/drivers/net/undiisr.S b/src/arch/x86/drivers/net/undiisr.S index aa8991d7..8ba5c535 100644 --- a/src/arch/x86/drivers/net/undiisr.S +++ b/src/arch/x86/drivers/net/undiisr.S @@ -11,8 +11,8 @@ FILE_LICENCE ( GPL2_OR_LATER ) #define PIC2_ICR 0xa0 .section ".note.GNU-stack", "", @progbits - .arch i386 .code16 + .arch i386 .section ".text16", "ax", @progbits .globl undiisr diff --git a/src/arch/x86/interface/pcbios/e820mangler.S b/src/arch/x86/interface/pcbios/e820mangler.S index 40f84c70..ef5dc275 100644 --- a/src/arch/x86/interface/pcbios/e820mangler.S +++ b/src/arch/x86/interface/pcbios/e820mangler.S @@ -24,8 +24,8 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ) .section ".note.GNU-stack", "", @progbits - .arch i386 .code16 + .arch i386 #define SMAP 0x534d4150 diff --git a/src/arch/x86/interface/pxe/pxe_entry.S b/src/arch/x86/interface/pxe/pxe_entry.S index 354dd1b3..3899e1bc 100644 --- a/src/arch/x86/interface/pxe/pxe_entry.S +++ b/src/arch/x86/interface/pxe/pxe_entry.S @@ -27,6 +27,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ) #include .section ".note.GNU-stack", "", @progbits + .code16 .arch i386 /**************************************************************************** diff --git a/src/arch/x86/prefix/bootpart.S b/src/arch/x86/prefix/bootpart.S index cf75ff79..7b9920fd 100644 --- a/src/arch/x86/prefix/bootpart.S +++ b/src/arch/x86/prefix/bootpart.S @@ -6,9 +6,9 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ) #define STACK_SIZE 0x2000 .section ".note.GNU-stack", "", @progbits + .code16 .arch i386 .section ".prefix", "awx", @progbits - .code16 /* * Find active partition diff --git a/src/arch/x86/prefix/dskprefix.S b/src/arch/x86/prefix/dskprefix.S index f9d30195..e8e55ef1 100644 --- a/src/arch/x86/prefix/dskprefix.S +++ b/src/arch/x86/prefix/dskprefix.S @@ -26,9 +26,9 @@ FILE_LICENCE ( GPL2_ONLY ) .section ".note.GNU-stack", "", @progbits .org 0 + .code16 .arch i386 .section ".prefix", "ax", @progbits - .code16 .globl _dsk_start _dsk_start: diff --git a/src/arch/x86/prefix/exeprefix.S b/src/arch/x86/prefix/exeprefix.S index 86333489..98ed6c5f 100644 --- a/src/arch/x86/prefix/exeprefix.S +++ b/src/arch/x86/prefix/exeprefix.S @@ -37,9 +37,9 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ) #define PSP_CMDLINE_START 0x81 .section ".note.GNU-stack", "", @progbits + .code16 .arch i386 .org 0 - .code16 .section ".prefix", "awx", @progbits signature: diff --git a/src/arch/x86/prefix/hdprefix.S b/src/arch/x86/prefix/hdprefix.S index 1bbf72dd..3133dec6 100644 --- a/src/arch/x86/prefix/hdprefix.S +++ b/src/arch/x86/prefix/hdprefix.S @@ -3,9 +3,9 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ) #include .section ".note.GNU-stack", "", @progbits + .code16 .arch i386 .section ".prefix", "awx", @progbits - .code16 .org 0 .globl _hd_start _hd_start: diff --git a/src/arch/x86/prefix/libprefix.S b/src/arch/x86/prefix/libprefix.S index 380e471d..b08a5782 100644 --- a/src/arch/x86/prefix/libprefix.S +++ b/src/arch/x86/prefix/libprefix.S @@ -27,6 +27,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ) #include .section ".note.GNU-stack", "", @progbits + .code16 .arch i386 /* Image compression enabled */ diff --git a/src/arch/x86/prefix/lkrnprefix.S b/src/arch/x86/prefix/lkrnprefix.S index 9f1a2f09..c8a04c9d 100644 --- a/src/arch/x86/prefix/lkrnprefix.S +++ b/src/arch/x86/prefix/lkrnprefix.S @@ -5,8 +5,8 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ) #define BZI_LOAD_HIGH_ADDR 0x100000 .section ".note.GNU-stack", "", @progbits - .arch i386 .code16 + .arch i386 .section ".prefix", "ax", @progbits .globl _lkrn_start _lkrn_start: diff --git a/src/arch/x86/prefix/mbr.S b/src/arch/x86/prefix/mbr.S index b37eed71..5e0ed5dd 100644 --- a/src/arch/x86/prefix/mbr.S +++ b/src/arch/x86/prefix/mbr.S @@ -1,9 +1,9 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ) .section ".note.GNU-stack", "", @progbits + .code16 .arch i386 .section ".prefix", "awx", @progbits - .code16 .org 0 .globl mbr diff --git a/src/arch/x86/prefix/mromprefix.S b/src/arch/x86/prefix/mromprefix.S index 543fd006..d05278e6 100644 --- a/src/arch/x86/prefix/mromprefix.S +++ b/src/arch/x86/prefix/mromprefix.S @@ -42,8 +42,8 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ) #include "pciromprefix.S" .section ".note.GNU-stack", "", @progbits - .arch i386 .code16 + .arch i386 /* Obtain access to payload by exposing the expansion ROM BAR at the * address currently used by a suitably large memory BAR on the same diff --git a/src/arch/x86/prefix/nbiprefix.S b/src/arch/x86/prefix/nbiprefix.S index 0a74ca71..bbacd4b7 100644 --- a/src/arch/x86/prefix/nbiprefix.S +++ b/src/arch/x86/prefix/nbiprefix.S @@ -3,8 +3,8 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ) #include .section ".note.GNU-stack", "", @progbits - .arch i386 .code16 + .arch i386 .section ".prefix", "ax", @progbits .org 0 diff --git a/src/arch/x86/prefix/nullprefix.S b/src/arch/x86/prefix/nullprefix.S index bbc697fd..426f1f2c 100644 --- a/src/arch/x86/prefix/nullprefix.S +++ b/src/arch/x86/prefix/nullprefix.S @@ -2,10 +2,10 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ) .section ".note.GNU-stack", "", @progbits .org 0 + .code16 .arch i386 .section ".prefix", "ax", @progbits - .code16 _prefix: .section ".text16", "ax", @progbits diff --git a/src/arch/x86/prefix/pxeprefix.S b/src/arch/x86/prefix/pxeprefix.S index c62a5011..5181ef61 100644 --- a/src/arch/x86/prefix/pxeprefix.S +++ b/src/arch/x86/prefix/pxeprefix.S @@ -12,9 +12,9 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ) #define PXE_HACK_EB54 0x0001 .section ".note.GNU-stack", "", @progbits + .code16 .arch i386 .org 0 - .code16 #include #include diff --git a/src/arch/x86/prefix/rawprefix.S b/src/arch/x86/prefix/rawprefix.S index d97b3b51..962c9718 100644 --- a/src/arch/x86/prefix/rawprefix.S +++ b/src/arch/x86/prefix/rawprefix.S @@ -9,9 +9,9 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ) .section ".note.GNU-stack", "", @progbits + .code16 .arch i386 .org 0 - .code16 #include diff --git a/src/arch/x86/prefix/unlzma.S b/src/arch/x86/prefix/unlzma.S index 4059090b..e4d1e190 100644 --- a/src/arch/x86/prefix/unlzma.S +++ b/src/arch/x86/prefix/unlzma.S @@ -44,6 +44,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); */ .section ".note.GNU-stack", "", @progbits + .code32 .arch i486 .section ".prefix.lib", "ax", @progbits diff --git a/src/arch/x86/prefix/usbdisk.S b/src/arch/x86/prefix/usbdisk.S index b8fc5e95..11ab6a46 100644 --- a/src/arch/x86/prefix/usbdisk.S +++ b/src/arch/x86/prefix/usbdisk.S @@ -3,9 +3,9 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ) #include .section ".note.GNU-stack", "", @progbits + .code16 .arch i386 .section ".prefix", "awx", @progbits - .code16 .org 0 #include "mbr.S" diff --git a/src/arch/x86/transitions/liba20.S b/src/arch/x86/transitions/liba20.S index 6c1bac67..971cff22 100644 --- a/src/arch/x86/transitions/liba20.S +++ b/src/arch/x86/transitions/liba20.S @@ -25,6 +25,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ) .section ".note.GNU-stack", "", @progbits + .code16 .arch i386 /**************************************************************************** diff --git a/src/arch/x86/transitions/libkir.S b/src/arch/x86/transitions/libkir.S index 5909654c..2c4dc948 100644 --- a/src/arch/x86/transitions/libkir.S +++ b/src/arch/x86/transitions/libkir.S @@ -32,9 +32,9 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ) #define BOCHSBP xchgw %bx, %bx .section ".note.GNU-stack", "", @progbits + .code16 .arch i386 .section ".text16", "awx", @progbits - .code16 /**************************************************************************** * init_libkir (real-mode or 16:xx protected-mode far call) -- cgit v1.2.3-55-g7522 From 6d29415c89d607b988381bc367c9c521694fa728 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Tue, 16 Jan 2024 12:23:02 +0000 Subject: [libc] Make static_assert() available via assert.h Expose static_assert() via assert.h and migrate link-time assertions to build-time assertions where possible. Signed-off-by: Michael Brown --- src/drivers/infiniband/arbel.c | 4 ++-- src/drivers/infiniband/hermon.c | 4 ++-- src/image/script.c | 3 +-- src/include/assert.h | 9 +++++++++ src/net/aoe.c | 2 +- 5 files changed, 15 insertions(+), 7 deletions(-) diff --git a/src/drivers/infiniband/arbel.c b/src/drivers/infiniband/arbel.c index 293c1b64..24c0b53b 100644 --- a/src/drivers/infiniband/arbel.c +++ b/src/drivers/infiniband/arbel.c @@ -545,8 +545,8 @@ static int arbel_mad ( struct ib_device *ibdev, union ib_mad *mad ) { union arbelprm_mad mad_ifc; int rc; - linker_assert ( sizeof ( *mad ) == sizeof ( mad_ifc.mad ), - mad_size_mismatch ); + /* Sanity check */ + static_assert ( sizeof ( *mad ) == sizeof ( mad_ifc.mad ) ); /* Copy in request packet */ memcpy ( &mad_ifc.mad, mad, sizeof ( mad_ifc.mad ) ); diff --git a/src/drivers/infiniband/hermon.c b/src/drivers/infiniband/hermon.c index c09baf7a..6fc7d8bd 100644 --- a/src/drivers/infiniband/hermon.c +++ b/src/drivers/infiniband/hermon.c @@ -779,8 +779,8 @@ static int hermon_mad ( struct ib_device *ibdev, union ib_mad *mad ) { union hermonprm_mad mad_ifc; int rc; - linker_assert ( sizeof ( *mad ) == sizeof ( mad_ifc.mad ), - mad_size_mismatch ); + /* Sanity check */ + static_assert ( sizeof ( *mad ) == sizeof ( mad_ifc.mad ) ); /* Copy in request packet */ memcpy ( &mad_ifc.mad, mad, sizeof ( mad_ifc.mad ) ); diff --git a/src/image/script.c b/src/image/script.c index 49b35640..9e8566bc 100644 --- a/src/image/script.c +++ b/src/image/script.c @@ -219,8 +219,7 @@ static int script_exec ( struct image *image ) { static int script_probe ( struct image *image ) { static const char ipxe_magic[] = "#!ipxe"; static const char gpxe_magic[] = "#!gpxe"; - linker_assert ( sizeof ( ipxe_magic ) == sizeof ( gpxe_magic ), - magic_size_mismatch ); + static_assert ( sizeof ( ipxe_magic ) == sizeof ( gpxe_magic ) ); char test[ sizeof ( ipxe_magic ) - 1 /* NUL */ + 1 /* terminating space */]; diff --git a/src/include/assert.h b/src/include/assert.h index dd71fa71..6d053180 100644 --- a/src/include/assert.h +++ b/src/include/assert.h @@ -55,6 +55,15 @@ assert_printf ( const char *fmt, ... ) asm ( "printf" ); } \ } while ( 0 ) +/** + * Assert a condition at build time + * + * If the compiler cannot prove that the condition is true, the build + * will fail with an error message. + */ +#undef static_assert +#define static_assert(x) _Static_assert( x, #x ) + /** * Assert a condition at link-time. * diff --git a/src/net/aoe.c b/src/net/aoe.c index e785e897..dba4f51b 100644 --- a/src/net/aoe.c +++ b/src/net/aoe.c @@ -374,7 +374,7 @@ static void aoecmd_ata_cmd ( struct aoe_command *aoecmd, struct aoeata *aoeata = &aoehdr->payload[0].ata; /* Sanity check */ - linker_assert ( AOE_FL_DEV_HEAD == ATA_DEV_SLAVE, __fix_ata_h__ ); + static_assert ( AOE_FL_DEV_HEAD == ATA_DEV_SLAVE ); assert ( len == ( sizeof ( *aoehdr ) + sizeof ( *aoeata ) + command->data_out_len ) ); -- cgit v1.2.3-55-g7522 From 4b7d9a6af08cb704ce77eadba2a7bb1b06c1554c Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Tue, 16 Jan 2024 13:24:29 +0000 Subject: [libc] Replace linker_assert() with build_assert() We currently implement build-time assertions via a mechanism that generates a call to an undefined external function that will cause the link to fail unless the compiler can prove that the asserted condition is true (and thereby eliminate the undefined function call). This assertion mechanism can be used for conditions that are not amenable to the use of static_assert(), since static_assert() will not allow for proofs via dead code elimination. Add __attribute__((error(...))) to the undefined external function, so that the error is raised at compile time rather than at link time. This allows us to provide a more meaningful error message (which will include the file name and line number, as with any other compile-time error), and avoids the need for the caller to specify a unique symbol name for the external function. Change the name from linker_assert() to build_assert(), since the assertion now takes place at compile time rather than at link time. Signed-off-by: Michael Brown --- src/crypto/gcm.c | 8 ++++---- src/crypto/md4.c | 10 +++++----- src/crypto/md5.c | 10 +++++----- src/crypto/sha1.c | 12 ++++++------ src/crypto/sha256.c | 18 ++++++++--------- src/crypto/sha512.c | 18 ++++++++--------- src/drivers/infiniband/linda.c | 4 ++-- src/drivers/infiniband/qib7322.c | 4 ++-- src/include/assert.h | 21 +++++++++++--------- src/include/ipxe/asn1.h | 7 +++---- src/include/ipxe/entropy.h | 42 ++++++++++++++++------------------------ src/include/ipxe/gcm.h | 11 ++++------- 12 files changed, 78 insertions(+), 87 deletions(-) diff --git a/src/crypto/gcm.c b/src/crypto/gcm.c index 9d8bae82..c21aad14 100644 --- a/src/crypto/gcm.c +++ b/src/crypto/gcm.c @@ -472,10 +472,10 @@ void gcm_setiv ( struct gcm_context *context, const void *iv, size_t ivlen ) { union gcm_block *check = ( ( void * ) context ); /* Sanity checks */ - linker_assert ( &context->hash == check, gcm_bad_layout ); - linker_assert ( &context->len == check + 1, gcm_bad_layout ); - linker_assert ( &context->ctr == check + 2, gcm_bad_layout ); - linker_assert ( &context->key == check + 3, gcm_bad_layout ); + build_assert ( &context->hash == check ); + build_assert ( &context->len == check + 1 ); + build_assert ( &context->ctr == check + 2 ); + build_assert ( &context->key == check + 3 ); /* Reset non-key state */ memset ( context, 0, offsetof ( typeof ( *context ), key ) ); diff --git a/src/crypto/md4.c b/src/crypto/md4.c index ca5dcc21..dcd86a42 100644 --- a/src/crypto/md4.c +++ b/src/crypto/md4.c @@ -155,11 +155,11 @@ static void md4_digest ( struct md4_context *context ) { /* Sanity checks */ assert ( ( context->len % sizeof ( context->ddd.dd.data ) ) == 0 ); - linker_assert ( &u.ddd.dd.digest.h[0] == a, md4_bad_layout ); - linker_assert ( &u.ddd.dd.digest.h[1] == b, md4_bad_layout ); - linker_assert ( &u.ddd.dd.digest.h[2] == c, md4_bad_layout ); - linker_assert ( &u.ddd.dd.digest.h[3] == d, md4_bad_layout ); - linker_assert ( &u.ddd.dd.data.dword[0] == w, md4_bad_layout ); + build_assert ( &u.ddd.dd.digest.h[0] == a ); + build_assert ( &u.ddd.dd.digest.h[1] == b ); + build_assert ( &u.ddd.dd.digest.h[2] == c ); + build_assert ( &u.ddd.dd.digest.h[3] == d ); + build_assert ( &u.ddd.dd.data.dword[0] == w ); DBGC ( context, "MD4 digesting:\n" ); DBGC_HDA ( context, 0, &context->ddd.dd.digest, diff --git a/src/crypto/md5.c b/src/crypto/md5.c index bee382e9..5c62513e 100644 --- a/src/crypto/md5.c +++ b/src/crypto/md5.c @@ -178,11 +178,11 @@ static void md5_digest ( struct md5_context *context ) { /* Sanity checks */ assert ( ( context->len % sizeof ( context->ddd.dd.data ) ) == 0 ); - linker_assert ( &u.ddd.dd.digest.h[0] == a, md5_bad_layout ); - linker_assert ( &u.ddd.dd.digest.h[1] == b, md5_bad_layout ); - linker_assert ( &u.ddd.dd.digest.h[2] == c, md5_bad_layout ); - linker_assert ( &u.ddd.dd.digest.h[3] == d, md5_bad_layout ); - linker_assert ( &u.ddd.dd.data.dword[0] == w, md5_bad_layout ); + build_assert ( &u.ddd.dd.digest.h[0] == a ); + build_assert ( &u.ddd.dd.digest.h[1] == b ); + build_assert ( &u.ddd.dd.digest.h[2] == c ); + build_assert ( &u.ddd.dd.digest.h[3] == d ); + build_assert ( &u.ddd.dd.data.dword[0] == w ); DBGC ( context, "MD5 digesting:\n" ); DBGC_HDA ( context, 0, &context->ddd.dd.digest, diff --git a/src/crypto/sha1.c b/src/crypto/sha1.c index 94fce002..8eecc75b 100644 --- a/src/crypto/sha1.c +++ b/src/crypto/sha1.c @@ -145,12 +145,12 @@ static void sha1_digest ( struct sha1_context *context ) { /* Sanity checks */ assert ( ( context->len % sizeof ( context->ddd.dd.data ) ) == 0 ); - linker_assert ( &u.ddd.dd.digest.h[0] == a, sha1_bad_layout ); - linker_assert ( &u.ddd.dd.digest.h[1] == b, sha1_bad_layout ); - linker_assert ( &u.ddd.dd.digest.h[2] == c, sha1_bad_layout ); - linker_assert ( &u.ddd.dd.digest.h[3] == d, sha1_bad_layout ); - linker_assert ( &u.ddd.dd.digest.h[4] == e, sha1_bad_layout ); - linker_assert ( &u.ddd.dd.data.dword[0] == w, sha1_bad_layout ); + build_assert ( &u.ddd.dd.digest.h[0] == a ); + build_assert ( &u.ddd.dd.digest.h[1] == b ); + build_assert ( &u.ddd.dd.digest.h[2] == c ); + build_assert ( &u.ddd.dd.digest.h[3] == d ); + build_assert ( &u.ddd.dd.digest.h[4] == e ); + build_assert ( &u.ddd.dd.data.dword[0] == w ); DBGC ( context, "SHA1 digesting:\n" ); DBGC_HDA ( context, 0, &context->ddd.dd.digest, diff --git a/src/crypto/sha256.c b/src/crypto/sha256.c index 6bd72771..c30300eb 100644 --- a/src/crypto/sha256.c +++ b/src/crypto/sha256.c @@ -140,15 +140,15 @@ static void sha256_digest ( struct sha256_context *context ) { /* Sanity checks */ assert ( ( context->len % sizeof ( context->ddd.dd.data ) ) == 0 ); - linker_assert ( &u.ddd.dd.digest.h[0] == a, sha256_bad_layout ); - linker_assert ( &u.ddd.dd.digest.h[1] == b, sha256_bad_layout ); - linker_assert ( &u.ddd.dd.digest.h[2] == c, sha256_bad_layout ); - linker_assert ( &u.ddd.dd.digest.h[3] == d, sha256_bad_layout ); - linker_assert ( &u.ddd.dd.digest.h[4] == e, sha256_bad_layout ); - linker_assert ( &u.ddd.dd.digest.h[5] == f, sha256_bad_layout ); - linker_assert ( &u.ddd.dd.digest.h[6] == g, sha256_bad_layout ); - linker_assert ( &u.ddd.dd.digest.h[7] == h, sha256_bad_layout ); - linker_assert ( &u.ddd.dd.data.dword[0] == w, sha256_bad_layout ); + build_assert ( &u.ddd.dd.digest.h[0] == a ); + build_assert ( &u.ddd.dd.digest.h[1] == b ); + build_assert ( &u.ddd.dd.digest.h[2] == c ); + build_assert ( &u.ddd.dd.digest.h[3] == d ); + build_assert ( &u.ddd.dd.digest.h[4] == e ); + build_assert ( &u.ddd.dd.digest.h[5] == f ); + build_assert ( &u.ddd.dd.digest.h[6] == g ); + build_assert ( &u.ddd.dd.digest.h[7] == h ); + build_assert ( &u.ddd.dd.data.dword[0] == w ); DBGC ( context, "SHA256 digesting:\n" ); DBGC_HDA ( context, 0, &context->ddd.dd.digest, diff --git a/src/crypto/sha512.c b/src/crypto/sha512.c index e8489501..d7d44b28 100644 --- a/src/crypto/sha512.c +++ b/src/crypto/sha512.c @@ -156,15 +156,15 @@ static void sha512_digest ( struct sha512_context *context ) { /* Sanity checks */ assert ( ( context->len % sizeof ( context->ddq.dd.data ) ) == 0 ); - linker_assert ( &u.ddq.dd.digest.h[0] == a, sha512_bad_layout ); - linker_assert ( &u.ddq.dd.digest.h[1] == b, sha512_bad_layout ); - linker_assert ( &u.ddq.dd.digest.h[2] == c, sha512_bad_layout ); - linker_assert ( &u.ddq.dd.digest.h[3] == d, sha512_bad_layout ); - linker_assert ( &u.ddq.dd.digest.h[4] == e, sha512_bad_layout ); - linker_assert ( &u.ddq.dd.digest.h[5] == f, sha512_bad_layout ); - linker_assert ( &u.ddq.dd.digest.h[6] == g, sha512_bad_layout ); - linker_assert ( &u.ddq.dd.digest.h[7] == h, sha512_bad_layout ); - linker_assert ( &u.ddq.dd.data.qword[0] == w, sha512_bad_layout ); + build_assert ( &u.ddq.dd.digest.h[0] == a ); + build_assert ( &u.ddq.dd.digest.h[1] == b ); + build_assert ( &u.ddq.dd.digest.h[2] == c ); + build_assert ( &u.ddq.dd.digest.h[3] == d ); + build_assert ( &u.ddq.dd.digest.h[4] == e ); + build_assert ( &u.ddq.dd.digest.h[5] == f ); + build_assert ( &u.ddq.dd.digest.h[6] == g ); + build_assert ( &u.ddq.dd.digest.h[7] == h ); + build_assert ( &u.ddq.dd.data.qword[0] == w ); DBGC ( context, "SHA512 digesting:\n" ); DBGC_HDA ( context, 0, &context->ddq.dd.digest, diff --git a/src/drivers/infiniband/linda.c b/src/drivers/infiniband/linda.c index 8c591266..0c8a043a 100644 --- a/src/drivers/infiniband/linda.c +++ b/src/drivers/infiniband/linda.c @@ -721,7 +721,7 @@ static int linda_init_recv ( struct linda *linda ) { eager_array_size_other = LINDA_EAGER_ARRAY_SIZE_17CTX_OTHER; break; default: - linker_assert ( 0, invalid_LINDA_NUM_CONTEXTS ); + build_assert ( 0 ); return -EINVAL; } @@ -1108,7 +1108,7 @@ static int linda_post_recv ( struct ib_device *ibdev, case 16384: bufsize = LINDA_EAGER_BUFFER_16K; break; case 32768: bufsize = LINDA_EAGER_BUFFER_32K; break; case 65536: bufsize = LINDA_EAGER_BUFFER_64K; break; - default: linker_assert ( 0, invalid_rx_payload_size ); + default: build_assert ( 0 ); bufsize = LINDA_EAGER_BUFFER_NONE; } diff --git a/src/drivers/infiniband/qib7322.c b/src/drivers/infiniband/qib7322.c index da055b74..a011dafc 100644 --- a/src/drivers/infiniband/qib7322.c +++ b/src/drivers/infiniband/qib7322.c @@ -893,7 +893,7 @@ static int qib7322_init_recv ( struct qib7322 *qib7322 ) { eager_array_size_user = QIB7322_EAGER_ARRAY_SIZE_18CTX_USER; break; default: - linker_assert ( 0, invalid_QIB7322_NUM_CONTEXTS ); + build_assert ( 0 ); return -EINVAL; } @@ -1351,7 +1351,7 @@ static int qib7322_post_recv ( struct ib_device *ibdev, case 16384: bufsize = QIB7322_EAGER_BUFFER_16K; break; case 32768: bufsize = QIB7322_EAGER_BUFFER_32K; break; case 65536: bufsize = QIB7322_EAGER_BUFFER_64K; break; - default: linker_assert ( 0, invalid_rx_payload_size ); + default: build_assert ( 0 ); bufsize = QIB7322_EAGER_BUFFER_NONE; } diff --git a/src/include/assert.h b/src/include/assert.h index 6d053180..b3a9b1fe 100644 --- a/src/include/assert.h +++ b/src/include/assert.h @@ -65,19 +65,22 @@ assert_printf ( const char *fmt, ... ) asm ( "printf" ); #define static_assert(x) _Static_assert( x, #x ) /** - * Assert a condition at link-time. + * Assert a condition at build time (after dead code elimination) * - * If the condition is not true, the link will fail with an unresolved - * symbol (error_symbol). + * If the compiler cannot prove that the condition is true, the build + * will fail with an error message. * * This macro is iPXE-specific. Do not use this macro in code * intended to be portable. - * */ -#define linker_assert( condition, error_symbol ) \ - if ( ! (condition) ) { \ - extern void error_symbol ( void ); \ - error_symbol(); \ - } +#define build_assert( condition ) \ + do { \ + if ( ! (condition) ) { \ + extern void __attribute__ (( error ( \ + "build_assert(" #condition ") failed" \ + ) )) _C2 ( build_assert_, __LINE__ ) ( void ); \ + _C2 ( build_assert_, __LINE__ ) (); \ + } \ + } while ( 0 ) #endif /* _ASSERT_H */ diff --git a/src/include/ipxe/asn1.h b/src/include/ipxe/asn1.h index 77429f3a..452fcef0 100644 --- a/src/include/ipxe/asn1.h +++ b/src/include/ipxe/asn1.h @@ -390,10 +390,9 @@ asn1_built ( struct asn1_builder *builder ) { } *u = container_of ( builder, typeof ( *u ), builder ); /* Sanity check */ - linker_assert ( ( ( const void * ) &u->builder.data ) == - &u->cursor.data, asn1_builder_cursor_data_mismatch ); - linker_assert ( &u->builder.len == &u->cursor.len, - asn1_builder_cursor_len_mismatch ); + build_assert ( ( ( const void * ) &u->builder.data ) == + &u->cursor.data ); + build_assert ( &u->builder.len == &u->cursor.len ); return &u->cursor; } diff --git a/src/include/ipxe/entropy.h b/src/include/ipxe/entropy.h index 240feace..82bb1182 100644 --- a/src/include/ipxe/entropy.h +++ b/src/include/ipxe/entropy.h @@ -237,8 +237,7 @@ get_entropy_input ( unsigned int min_entropy_bits, void *data, size_t min_len, int rc; /* Sanity check */ - linker_assert ( ( min_entropy_bits <= ( 8 * max_len ) ), - entropy_buffer_too_small ); + build_assert ( min_entropy_bits <= ( 8 * max_len ) ); /* Round up minimum entropy to an integral number of bytes */ min_entropy_bits = ( ( min_entropy_bits + 7 ) & ~7 ); @@ -247,11 +246,11 @@ get_entropy_input ( unsigned int min_entropy_bits, void *data, size_t min_len, * meet or exceed the security strength indicated by the * min_entropy parameter. */ - linker_assert ( ( ( 8 * ENTROPY_HASH_DF_OUTLEN_BYTES ) >= - min_entropy_bits ), hash_df_algorithm_too_weak ); + build_assert ( ( 8 * ENTROPY_HASH_DF_OUTLEN_BYTES ) >= + min_entropy_bits ); /* 1. If ( min_length > max_length ), then return ( FAILURE, Null ) */ - linker_assert ( ( min_len <= max_len ), min_len_greater_than_max_len ); + build_assert ( min_len <= max_len ); /* 2. n = 2 * min_entropy */ n = ( 2 * min_entropy_bits ); @@ -269,9 +268,8 @@ get_entropy_input ( unsigned int min_entropy_bits, void *data, size_t min_len, * (The implementation of these steps is inside the function * get_entropy_input_tmp().) */ - linker_assert ( __builtin_constant_p ( tmp_len ), - tmp_len_not_constant ); - linker_assert ( ( n == ( 8 * tmp_len ) ), tmp_len_mismatch ); + build_assert ( __builtin_constant_p ( tmp_len ) ); + build_assert ( n == ( 8 * tmp_len ) ); if ( ( rc = get_entropy_input_tmp ( MIN_ENTROPY ( min_entropy_bits ), tmp, tmp_len ) ) != 0 ) { return rc; @@ -283,17 +281,17 @@ get_entropy_input ( unsigned int min_entropy_bits, void *data, size_t min_len, */ if ( tmp_len < min_len ) { /* (Data is already in-place.) */ - linker_assert ( ( data == tmp ), data_not_inplace ); + build_assert ( data == tmp ); memset ( ( data + tmp_len ), 0, ( min_len - tmp_len ) ); return min_len; } else if ( tmp_len > max_len ) { - linker_assert ( ( tmp == tmp_buf ), data_inplace ); + build_assert ( tmp == tmp_buf ); hash_df ( &entropy_hash_df_algorithm, tmp, tmp_len, data, max_len ); return max_len; } else { /* (Data is already in-place.) */ - linker_assert ( ( data == tmp ), data_not_inplace ); + build_assert ( data == tmp ); return tmp_len; } } @@ -328,15 +326,14 @@ entropy_repetition_count_cutoff ( min_entropy_t min_entropy_per_sample ) { cutoff = max_repetitions; if ( cutoff < max_repetitions ) cutoff++; - linker_assert ( ( cutoff >= max_repetitions ), rounding_error ); + build_assert ( cutoff >= max_repetitions ); /* Floating-point operations are not allowed in iPXE since we * never set up a suitable environment. Abort the build * unless the calculated number of repetitions is a * compile-time constant. */ - linker_assert ( __builtin_constant_p ( cutoff ), - repetition_count_cutoff_not_constant ); + build_assert ( __builtin_constant_p ( cutoff ) ); return cutoff; } @@ -443,12 +440,10 @@ entropy_adaptive_proportion_cutoff ( min_entropy_t min_entropy_per_sample ) { cutoff = entropy_adaptive_proportion_cutoff_lookup ( n, h ); /* Fail unless cutoff value is a compile-time constant */ - linker_assert ( __builtin_constant_p ( cutoff ), - adaptive_proportion_cutoff_not_constant ); + build_assert ( __builtin_constant_p ( cutoff ) ); /* Fail if cutoff value is N/A */ - linker_assert ( ( cutoff != APC_NA ), - adaptive_proportion_cutoff_not_applicable ); + build_assert ( cutoff != APC_NA ); return cutoff; } @@ -475,8 +470,7 @@ entropy_startup_test_count ( unsigned int repetition_count_cutoff, num_samples = repetition_count_cutoff; if ( num_samples < adaptive_proportion_cutoff ) num_samples = adaptive_proportion_cutoff; - linker_assert ( __builtin_constant_p ( num_samples ), - startup_test_count_not_constant ); + build_assert ( __builtin_constant_p ( num_samples ) ); return num_samples; } @@ -499,11 +493,9 @@ entropy_init ( struct entropy_source *source, unsigned int startup_test_count; /* Sanity check */ - linker_assert ( min_entropy_per_sample > MIN_ENTROPY ( 0 ), - min_entropy_per_sample_is_zero ); - linker_assert ( ( min_entropy_per_sample <= - MIN_ENTROPY ( 8 * sizeof ( noise_sample_t ) ) ), - min_entropy_per_sample_is_impossibly_high ); + build_assert ( min_entropy_per_sample > MIN_ENTROPY ( 0 ) ); + build_assert ( min_entropy_per_sample <= + MIN_ENTROPY ( 8 * sizeof ( noise_sample_t ) ) ); /* Calculate test cutoff values */ repetition_count_cutoff = diff --git a/src/include/ipxe/gcm.h b/src/include/ipxe/gcm.h index 90ef0b52..9653a0a1 100644 --- a/src/include/ipxe/gcm.h +++ b/src/include/ipxe/gcm.h @@ -88,13 +88,10 @@ struct _gcm_name ## _context { \ static int _gcm_name ## _setkey ( void *ctx, const void *key, \ size_t keylen ) { \ struct _gcm_name ## _context *context = ctx; \ - linker_assert ( _blocksize == sizeof ( context->gcm.key ), \ - _gcm_name ## _unsupported_blocksize ); \ - linker_assert ( ( ( void * ) &context->gcm ) == ctx, \ - _gcm_name ## _context_layout_error ); \ - linker_assert ( ( ( void * ) &context->raw ) == \ - ( ( void * ) context->gcm.raw_ctx ), \ - _gcm_name ## _context_layout_error ); \ + build_assert ( _blocksize == sizeof ( context->gcm.key ) ); \ + build_assert ( ( ( void * ) &context->gcm ) == ctx ); \ + build_assert ( ( ( void * ) &context->raw ) == \ + ( ( void * ) context->gcm.raw_ctx ) ); \ return gcm_setkey ( &context->gcm, key, keylen, &_raw_cipher ); \ } \ static void _gcm_name ## _setiv ( void *ctx, const void *iv, \ -- cgit v1.2.3-55-g7522 From 26d3ef062b33e43e076b7ecef20c4ec3f9441860 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Tue, 16 Jan 2024 16:09:16 +0000 Subject: [crypto] Allow multiplicand and multiplier to differ in size Big integer multiplication is currently used only as part of modular exponentiation, where both multiplicand and multiplier will be the same size. Relax this requirement to allow for the use of big integer multiplication in other contexts. Signed-off-by: Michael Brown --- src/arch/arm32/core/arm32_bigint.c | 26 +++++++++++++---------- src/arch/arm32/include/bits/bigint.h | 4 +++- src/arch/arm64/core/arm64_bigint.c | 26 +++++++++++++---------- src/arch/arm64/include/bits/bigint.h | 4 +++- src/arch/loong64/core/loong64_bigint.c | 26 +++++++++++++---------- src/arch/loong64/include/bits/bigint.h | 4 +++- src/arch/x86/core/x86_bigint.c | 26 +++++++++++++---------- src/arch/x86/include/bits/bigint.h | 4 +++- src/include/ipxe/bigint.h | 12 ++++++----- src/tests/bigint_test.c | 39 +++++++++++++++++++++------------- 10 files changed, 103 insertions(+), 68 deletions(-) diff --git a/src/arch/arm32/core/arm32_bigint.c b/src/arch/arm32/core/arm32_bigint.c index 839bead1..29fb40a7 100644 --- a/src/arch/arm32/core/arm32_bigint.c +++ b/src/arch/arm32/core/arm32_bigint.c @@ -36,19 +36,23 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); * Multiply big integers * * @v multiplicand0 Element 0 of big integer to be multiplied + * @v multiplicand_size Number of elements in multiplicand * @v multiplier0 Element 0 of big integer to be multiplied + * @v multiplier_size Number of elements in multiplier * @v result0 Element 0 of big integer to hold result - * @v size Number of elements */ void bigint_multiply_raw ( const uint32_t *multiplicand0, + unsigned int multiplicand_size, const uint32_t *multiplier0, - uint32_t *result0, unsigned int size ) { - const bigint_t ( size ) __attribute__ (( may_alias )) *multiplicand = - ( ( const void * ) multiplicand0 ); - const bigint_t ( size ) __attribute__ (( may_alias )) *multiplier = - ( ( const void * ) multiplier0 ); - bigint_t ( size * 2 ) __attribute__ (( may_alias )) *result = - ( ( void * ) result0 ); + unsigned int multiplier_size, + uint32_t *result0 ) { + unsigned int result_size = ( multiplicand_size + multiplier_size ); + const bigint_t ( multiplicand_size ) __attribute__ (( may_alias )) + *multiplicand = ( ( const void * ) multiplicand0 ); + const bigint_t ( multiplier_size ) __attribute__ (( may_alias )) + *multiplier = ( ( const void * ) multiplier0 ); + bigint_t ( result_size ) __attribute__ (( may_alias )) + *result = ( ( void * ) result0 ); unsigned int i; unsigned int j; uint32_t multiplicand_element; @@ -62,9 +66,9 @@ void bigint_multiply_raw ( const uint32_t *multiplicand0, memset ( result, 0, sizeof ( *result ) ); /* Multiply integers one element at a time */ - for ( i = 0 ; i < size ; i++ ) { + for ( i = 0 ; i < multiplicand_size ; i++ ) { multiplicand_element = multiplicand->element[i]; - for ( j = 0 ; j < size ; j++ ) { + for ( j = 0 ; j < multiplier_size ; j++ ) { multiplier_element = multiplier->element[j]; result_elements = &result->element[ i + j ]; /* Perform a single multiply, and add the @@ -73,7 +77,7 @@ void bigint_multiply_raw ( const uint32_t *multiplicand0, * never overflow beyond the end of the * result, since: * - * a < 2^{n}, b < 2^{n} => ab < 2^{2n} + * a < 2^{n}, b < 2^{m} => ab < 2^{n+m} */ __asm__ __volatile__ ( "umull %1, %2, %5, %6\n\t" "ldr %3, [%0]\n\t" diff --git a/src/arch/arm32/include/bits/bigint.h b/src/arch/arm32/include/bits/bigint.h index 103c6c48..e4b511da 100644 --- a/src/arch/arm32/include/bits/bigint.h +++ b/src/arch/arm32/include/bits/bigint.h @@ -310,7 +310,9 @@ bigint_done_raw ( const uint32_t *value0, unsigned int size __unused, } extern void bigint_multiply_raw ( const uint32_t *multiplicand0, + unsigned int multiplicand_size, const uint32_t *multiplier0, - uint32_t *value0, unsigned int size ); + unsigned int multiplier_size, + uint32_t *value0 ); #endif /* _BITS_BIGINT_H */ diff --git a/src/arch/arm64/core/arm64_bigint.c b/src/arch/arm64/core/arm64_bigint.c index bc4ee9a0..7740f1ae 100644 --- a/src/arch/arm64/core/arm64_bigint.c +++ b/src/arch/arm64/core/arm64_bigint.c @@ -36,19 +36,23 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); * Multiply big integers * * @v multiplicand0 Element 0 of big integer to be multiplied + * @v multiplicand_size Number of elements in multiplicand * @v multiplier0 Element 0 of big integer to be multiplied + * @v multiplier_size Number of elements in multiplier * @v result0 Element 0 of big integer to hold result - * @v size Number of elements */ void bigint_multiply_raw ( const uint64_t *multiplicand0, + unsigned int multiplicand_size, const uint64_t *multiplier0, - uint64_t *result0, unsigned int size ) { - const bigint_t ( size ) __attribute__ (( may_alias )) *multiplicand = - ( ( const void * ) multiplicand0 ); - const bigint_t ( size ) __attribute__ (( may_alias )) *multiplier = - ( ( const void * ) multiplier0 ); - bigint_t ( size * 2 ) __attribute__ (( may_alias )) *result = - ( ( void * ) result0 ); + unsigned int multiplier_size, + uint64_t *result0 ) { + unsigned int result_size = ( multiplicand_size + multiplier_size ); + const bigint_t ( multiplicand_size ) __attribute__ (( may_alias )) + *multiplicand = ( ( const void * ) multiplicand0 ); + const bigint_t ( multiplier_size ) __attribute__ (( may_alias )) + *multiplier = ( ( const void * ) multiplier0 ); + bigint_t ( result_size ) __attribute__ (( may_alias )) + *result = ( ( void * ) result0 ); unsigned int i; unsigned int j; uint64_t multiplicand_element; @@ -63,9 +67,9 @@ void bigint_multiply_raw ( const uint64_t *multiplicand0, memset ( result, 0, sizeof ( *result ) ); /* Multiply integers one element at a time */ - for ( i = 0 ; i < size ; i++ ) { + for ( i = 0 ; i < multiplicand_size ; i++ ) { multiplicand_element = multiplicand->element[i]; - for ( j = 0 ; j < size ; j++ ) { + for ( j = 0 ; j < multiplier_size ; j++ ) { multiplier_element = multiplier->element[j]; result_elements = &result->element[ i + j ]; /* Perform a single multiply, and add the @@ -74,7 +78,7 @@ void bigint_multiply_raw ( const uint64_t *multiplicand0, * never overflow beyond the end of the * result, since: * - * a < 2^{n}, b < 2^{n} => ab < 2^{2n} + * a < 2^{n}, b < 2^{m} => ab < 2^{n+m} */ __asm__ __volatile__ ( "mul %1, %6, %7\n\t" "umulh %2, %6, %7\n\t" diff --git a/src/arch/arm64/include/bits/bigint.h b/src/arch/arm64/include/bits/bigint.h index 79983b41..0d08bbd6 100644 --- a/src/arch/arm64/include/bits/bigint.h +++ b/src/arch/arm64/include/bits/bigint.h @@ -311,7 +311,9 @@ bigint_done_raw ( const uint64_t *value0, unsigned int size __unused, } extern void bigint_multiply_raw ( const uint64_t *multiplicand0, + unsigned int multiplicand_size, const uint64_t *multiplier0, - uint64_t *value0, unsigned int size ); + unsigned int multiplier_size, + uint64_t *value0 ); #endif /* _BITS_BIGINT_H */ diff --git a/src/arch/loong64/core/loong64_bigint.c b/src/arch/loong64/core/loong64_bigint.c index f42b8611..b428e22c 100644 --- a/src/arch/loong64/core/loong64_bigint.c +++ b/src/arch/loong64/core/loong64_bigint.c @@ -37,19 +37,23 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); * Multiply big integers * * @v multiplicand0 Element 0 of big integer to be multiplied + * @v multiplicand_size Number of elements in multiplicand * @v multiplier0 Element 0 of big integer to be multiplied + * @v multiplier_size Number of elements in multiplier * @v result0 Element 0 of big integer to hold result - * @v size Number of elements */ void bigint_multiply_raw ( const uint64_t *multiplicand0, + unsigned int multiplicand_size, const uint64_t *multiplier0, - uint64_t *result0, unsigned int size ) { - const bigint_t ( size ) __attribute__ (( may_alias )) *multiplicand = - ( ( const void * ) multiplicand0 ); - const bigint_t ( size ) __attribute__ (( may_alias )) *multiplier = - ( ( const void * ) multiplier0 ); - bigint_t ( size * 2 ) __attribute__ (( may_alias )) *result = - ( ( void * ) result0 ); + unsigned int multiplier_size, + uint64_t *result0 ) { + unsigned int result_size = ( multiplicand_size + multiplier_size ); + const bigint_t ( multiplicand_size ) __attribute__ (( may_alias )) + *multiplicand = ( ( const void * ) multiplicand0 ); + const bigint_t ( multiplier_size ) __attribute__ (( may_alias )) + *multiplier = ( ( const void * ) multiplier0 ); + bigint_t ( result_size ) __attribute__ (( may_alias )) + *result = ( ( void * ) result0 ); unsigned int i; unsigned int j; uint64_t multiplicand_element; @@ -64,9 +68,9 @@ void bigint_multiply_raw ( const uint64_t *multiplicand0, memset ( result, 0, sizeof ( *result ) ); /* Multiply integers one element at a time */ - for ( i = 0 ; i < size ; i++ ) { + for ( i = 0 ; i < multiplicand_size ; i++ ) { multiplicand_element = multiplicand->element[i]; - for ( j = 0 ; j < size ; j++ ) { + for ( j = 0 ; j < multiplier_size ; j++ ) { multiplier_element = multiplier->element[j]; result_elements = &result->element[ i + j ]; /* Perform a single multiply, and add the @@ -75,7 +79,7 @@ void bigint_multiply_raw ( const uint64_t *multiplicand0, * never overflow beyond the end of the * result, since: * - * a < 2^{n}, b < 2^{n} => ab < 2^{2n} + * a < 2^{n}, b < 2^{m} => ab < 2^{n+m} */ __asm__ __volatile__ ( "mul.d %1, %6, %7\n\t" "mulh.du %2, %6, %7\n\t" diff --git a/src/arch/loong64/include/bits/bigint.h b/src/arch/loong64/include/bits/bigint.h index 89e0b867..a37ac73c 100644 --- a/src/arch/loong64/include/bits/bigint.h +++ b/src/arch/loong64/include/bits/bigint.h @@ -330,7 +330,9 @@ bigint_done_raw ( const uint64_t *value0, unsigned int size __unused, } extern void bigint_multiply_raw ( const uint64_t *multiplicand0, + unsigned int multiplicand_size, const uint64_t *multiplier0, - uint64_t *value0, unsigned int size ); + unsigned int multiplier_size, + uint64_t *value0 ); #endif /* _BITS_BIGINT_H */ diff --git a/src/arch/x86/core/x86_bigint.c b/src/arch/x86/core/x86_bigint.c index 9a25bdad..74e5da9a 100644 --- a/src/arch/x86/core/x86_bigint.c +++ b/src/arch/x86/core/x86_bigint.c @@ -36,19 +36,23 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); * Multiply big integers * * @v multiplicand0 Element 0 of big integer to be multiplied + * @v multiplicand_size Number of elements in multiplicand * @v multiplier0 Element 0 of big integer to be multiplied + * @v multiplier_size Number of elements in multiplier * @v result0 Element 0 of big integer to hold result - * @v size Number of elements */ void bigint_multiply_raw ( const uint32_t *multiplicand0, + unsigned int multiplicand_size, const uint32_t *multiplier0, - uint32_t *result0, unsigned int size ) { - const bigint_t ( size ) __attribute__ (( may_alias )) *multiplicand = - ( ( const void * ) multiplicand0 ); - const bigint_t ( size ) __attribute__ (( may_alias )) *multiplier = - ( ( const void * ) multiplier0 ); - bigint_t ( size * 2 ) __attribute__ (( may_alias )) *result = - ( ( void * ) result0 ); + unsigned int multiplier_size, + uint32_t *result0 ) { + unsigned int result_size = ( multiplicand_size + multiplier_size ); + const bigint_t ( multiplicand_size ) __attribute__ (( may_alias )) + *multiplicand = ( ( const void * ) multiplicand0 ); + const bigint_t ( multiplier_size ) __attribute__ (( may_alias )) + *multiplier = ( ( const void * ) multiplier0 ); + bigint_t ( result_size ) __attribute__ (( may_alias )) + *result = ( ( void * ) result0 ); unsigned int i; unsigned int j; uint32_t multiplicand_element; @@ -62,9 +66,9 @@ void bigint_multiply_raw ( const uint32_t *multiplicand0, memset ( result, 0, sizeof ( *result ) ); /* Multiply integers one element at a time */ - for ( i = 0 ; i < size ; i++ ) { + for ( i = 0 ; i < multiplicand_size ; i++ ) { multiplicand_element = multiplicand->element[i]; - for ( j = 0 ; j < size ; j++ ) { + for ( j = 0 ; j < multiplier_size ; j++ ) { multiplier_element = multiplier->element[j]; result_elements = &result->element[ i + j ]; /* Perform a single multiply, and add the @@ -73,7 +77,7 @@ void bigint_multiply_raw ( const uint32_t *multiplicand0, * never overflow beyond the end of the * result, since: * - * a < 2^{n}, b < 2^{n} => ab < 2^{2n} + * a < 2^{n}, b < 2^{m} => ab < 2^{n+m} */ __asm__ __volatile__ ( "mull %5\n\t" "addl %%eax, (%6,%2,4)\n\t" diff --git a/src/arch/x86/include/bits/bigint.h b/src/arch/x86/include/bits/bigint.h index 7443d6fd..a6bc2ca1 100644 --- a/src/arch/x86/include/bits/bigint.h +++ b/src/arch/x86/include/bits/bigint.h @@ -323,7 +323,9 @@ bigint_done_raw ( const uint32_t *value0, unsigned int size __unused, } extern void bigint_multiply_raw ( const uint32_t *multiplicand0, + unsigned int multiplicand_size, const uint32_t *multiplier0, - uint32_t *value0, unsigned int size ); + unsigned int multiplier_size, + uint32_t *value0 ); #endif /* _BITS_BIGINT_H */ diff --git a/src/include/ipxe/bigint.h b/src/include/ipxe/bigint.h index 2f99f844..36138dd6 100644 --- a/src/include/ipxe/bigint.h +++ b/src/include/ipxe/bigint.h @@ -184,10 +184,11 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); * @v result Big integer to hold result */ #define bigint_multiply( multiplicand, multiplier, result ) do { \ - unsigned int size = bigint_size (multiplicand); \ + unsigned int multiplicand_size = bigint_size (multiplicand); \ + unsigned int multiplier_size = bigint_size (multiplier); \ bigint_multiply_raw ( (multiplicand)->element, \ - (multiplier)->element, (result)->element, \ - size ); \ + multiplicand_size, (multiplier)->element, \ + multiplier_size, (result)->element ); \ } while ( 0 ) /** @@ -283,9 +284,10 @@ void bigint_shrink_raw ( const bigint_element_t *source0, unsigned int source_size, bigint_element_t *dest0, unsigned int dest_size ); void bigint_multiply_raw ( const bigint_element_t *multiplicand0, + unsigned int multiplicand_size, const bigint_element_t *multiplier0, - bigint_element_t *result0, - unsigned int size ); + unsigned int multiplier_size, + bigint_element_t *result0 ); void bigint_mod_multiply_raw ( const bigint_element_t *multiplicand0, const bigint_element_t *multiplier0, const bigint_element_t *modulus0, diff --git a/src/tests/bigint_test.c b/src/tests/bigint_test.c index 8d40c318..02568dff 100644 --- a/src/tests/bigint_test.c +++ b/src/tests/bigint_test.c @@ -150,15 +150,17 @@ void bigint_shrink_sample ( const bigint_element_t *source0, } void bigint_multiply_sample ( const bigint_element_t *multiplicand0, + unsigned int multiplicand_size, const bigint_element_t *multiplier0, - bigint_element_t *result0, - unsigned int size ) { - const bigint_t ( size ) *multiplicand __attribute__ (( may_alias )) - = ( ( const void * ) multiplicand0 ); - const bigint_t ( size ) *multiplier __attribute__ (( may_alias )) - = ( ( const void * ) multiplier0 ); - bigint_t ( size * 2 ) *result __attribute__ (( may_alias )) - = ( ( void * ) result0 ); + unsigned int multiplier_size, + bigint_element_t *result0 ) { + unsigned int result_size = ( multiplicand_size + multiplier_size ); + const bigint_t ( multiplicand_size ) __attribute__ (( may_alias )) + *multiplicand = ( ( const void * ) multiplicand0 ); + const bigint_t ( multiplier_size ) __attribute__ (( may_alias )) + *multiplier = ( ( const void * ) multiplier0 ); + bigint_t ( result_size ) __attribute__ (( may_alias )) + *result = ( ( void * ) result0 ); bigint_multiply ( multiplicand, multiplier, result ); } @@ -430,17 +432,18 @@ void bigint_mod_exp_sample ( const bigint_element_t *base0, static const uint8_t multiplier_raw[] = multiplier; \ static const uint8_t expected_raw[] = expected; \ uint8_t result_raw[ sizeof ( expected_raw ) ]; \ - unsigned int size = \ + unsigned int multiplicand_size = \ bigint_required_size ( sizeof ( multiplicand_raw ) ); \ - bigint_t ( size ) multiplicand_temp; \ - bigint_t ( size ) multiplier_temp; \ - bigint_t ( size * 2 ) result_temp; \ + unsigned int multiplier_size = \ + bigint_required_size ( sizeof ( multiplier_raw ) ); \ + bigint_t ( multiplicand_size ) multiplicand_temp; \ + bigint_t ( multiplier_size ) multiplier_temp; \ + bigint_t ( multiplicand_size + multiplier_size ) result_temp; \ {} /* Fix emacs alignment */ \ \ - assert ( bigint_size ( &multiplier_temp ) == \ - bigint_size ( &multiplicand_temp ) ); \ assert ( bigint_size ( &result_temp ) == \ - ( 2 * bigint_size ( &multiplicand_temp ) ) ); \ + ( bigint_size ( &multiplicand_temp ) + \ + bigint_size ( &multiplier_temp ) ) ); \ bigint_init ( &multiplicand_temp, multiplicand_raw, \ sizeof ( multiplicand_raw ) ); \ bigint_init ( &multiplier_temp, multiplier_raw, \ @@ -1373,6 +1376,12 @@ static void bigint_test_exec ( void ) { BIGINT ( 0x67, 0x3c, 0x5a, 0x16 ), BIGINT ( 0x3c, 0xdb, 0x7f, 0xae, 0x12, 0x7e, 0xef, 0x16 ) ); + bigint_multiply_ok ( BIGINT ( 0x39, 0x1f, 0xc8, 0x6a ), + BIGINT ( 0xba, 0x39, 0x4a, 0xb8, 0xac, 0xb3, + 0x4f, 0x64, 0x28, 0x46, 0xa6, 0x99 ), + BIGINT ( 0x29, 0x8d, 0xe0, 0x5d, 0x08, 0xea, + 0x0d, 0xc7, 0x82, 0x5d, 0xba, 0x96, + 0x1c, 0xef, 0x83, 0x5a ) ); bigint_multiply_ok ( BIGINT ( 0xe8, 0x08, 0x0b, 0xe9, 0x29, 0x36, 0xea, 0x51, 0x1d, 0x75, 0x1a, 0xd5, 0xba, 0xc6, 0xa0, 0xf3, 0x48, 0x5c, -- cgit v1.2.3-55-g7522 From 13e390d54edde17c8e22b0f6d8897c273a91c5d0 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Fri, 19 Jan 2024 12:29:29 +0000 Subject: [crypto] Add bigint_copy() as a convenient wrapper macro Big integers may be efficiently copied using bigint_shrink() (which will always copy only the size of the destination integer), but this is potentially confusing to a reader of the code. Provide bigint_copy() as an alias for bigint_shrink() so that the intention of the calling code may be more obvious. Signed-off-by: Michael Brown --- src/include/ipxe/bigint.h | 13 +++++++++++++ src/tests/bigint_test.c | 10 ++++++++++ 2 files changed, 23 insertions(+) diff --git a/src/include/ipxe/bigint.h b/src/include/ipxe/bigint.h index 36138dd6..820d306b 100644 --- a/src/include/ipxe/bigint.h +++ b/src/include/ipxe/bigint.h @@ -8,6 +8,8 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); +#include + /** * Define a big-integer type * @@ -176,6 +178,17 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); (dest)->element, dest_size ); \ } while ( 0 ) +/** + * Copy big integer + * + * @v source Source big integer + * @v dest Destination big integer + */ +#define bigint_copy( source, dest ) do { \ + build_assert ( sizeof ( *(source) ) == sizeof ( *(dest) ) ); \ + bigint_shrink ( (source), (dest) ); \ + } while ( 0 ) + /** * Multiply big integers * diff --git a/src/tests/bigint_test.c b/src/tests/bigint_test.c index 02568dff..484c5913 100644 --- a/src/tests/bigint_test.c +++ b/src/tests/bigint_test.c @@ -149,6 +149,16 @@ void bigint_shrink_sample ( const bigint_element_t *source0, bigint_shrink ( source, dest ); } +void bigint_copy_sample ( const bigint_element_t *source0, + bigint_element_t *dest0, unsigned int size ) { + const bigint_t ( size ) *source __attribute__ (( may_alias )) + = ( ( const void * ) source0 ); + bigint_t ( size ) *dest __attribute__ (( may_alias )) + = ( ( void * ) dest0 ); + + bigint_copy ( source, dest ); +} + void bigint_multiply_sample ( const bigint_element_t *multiplicand0, unsigned int multiplicand_size, const bigint_element_t *multiplier0, -- cgit v1.2.3-55-g7522 From bac13ba1f658a1e742b9ceb958e670086affebe7 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Fri, 19 Jan 2024 12:34:02 +0000 Subject: [crypto] Add bigint_swap() to conditionally swap big integers Add a helper function bigint_swap() that can be used to conditionally swap a pair of big integers in constant time. Signed-off-by: Michael Brown --- src/crypto/bigint.c | 25 ++++++++++++++++++++++ src/include/ipxe/bigint.h | 15 +++++++++++++ src/tests/bigint_test.c | 54 +++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 94 insertions(+) diff --git a/src/crypto/bigint.c b/src/crypto/bigint.c index ac9670ef..656f979e 100644 --- a/src/crypto/bigint.c +++ b/src/crypto/bigint.c @@ -50,6 +50,31 @@ static struct profiler bigint_mod_multiply_rescale_profiler __profiler = static struct profiler bigint_mod_multiply_subtract_profiler __profiler = { .name = "bigint_mod_multiply.subtract" }; +/** + * Conditionally swap big integers (in constant time) + * + * @v first0 Element 0 of big integer to be conditionally swapped + * @v second0 Element 0 of big integer to be conditionally swapped + * @v size Number of elements in big integers + * @v swap Swap first and second big integers + */ +void bigint_swap_raw ( bigint_element_t *first0, bigint_element_t *second0, + unsigned int size, int swap ) { + bigint_element_t mask; + bigint_element_t xor; + unsigned int i; + + /* Construct mask */ + mask = ( ( bigint_element_t ) ( ! swap ) - 1 ); + + /* Conditionally swap elements */ + for ( i = 0 ; i < size ; i++ ) { + xor = ( mask & ( first0[i] ^ second0[i] ) ); + first0[i] ^= xor; + second0[i] ^= xor; + } +} + /** * Perform modular multiplication of big integers * diff --git a/src/include/ipxe/bigint.h b/src/include/ipxe/bigint.h index 820d306b..3dc344df 100644 --- a/src/include/ipxe/bigint.h +++ b/src/include/ipxe/bigint.h @@ -189,6 +189,19 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); bigint_shrink ( (source), (dest) ); \ } while ( 0 ) +/** + * Conditionally swap big integers (in constant time) + * + * @v first Big integer to be conditionally swapped + * @v second Big integer to be conditionally swapped + * @v swap Swap first and second big integers + */ +#define bigint_swap( first, second, swap ) do { \ + unsigned int size = bigint_size (first); \ + bigint_swap_raw ( (first)->element, (second)->element, size, \ + (swap) ); \ + } while ( 0 ) + /** * Multiply big integers * @@ -296,6 +309,8 @@ void bigint_grow_raw ( const bigint_element_t *source0, void bigint_shrink_raw ( const bigint_element_t *source0, unsigned int source_size, bigint_element_t *dest0, unsigned int dest_size ); +void bigint_swap_raw ( bigint_element_t *first0, bigint_element_t *second0, + unsigned int size, int swap ); void bigint_multiply_raw ( const bigint_element_t *multiplicand0, unsigned int multiplicand_size, const bigint_element_t *multiplier0, diff --git a/src/tests/bigint_test.c b/src/tests/bigint_test.c index 484c5913..f09d7c76 100644 --- a/src/tests/bigint_test.c +++ b/src/tests/bigint_test.c @@ -159,6 +159,16 @@ void bigint_copy_sample ( const bigint_element_t *source0, bigint_copy ( source, dest ); } +void bigint_swap_sample ( bigint_element_t *first0, bigint_element_t *second0, + unsigned int size, int swap ) { + bigint_t ( size ) *first __attribute__ (( may_alias )) + = ( ( void * ) first0 ); + bigint_t ( size ) *second __attribute__ (( may_alias )) + = ( ( void * ) second0 ); + + bigint_swap ( first, second, swap ); +} + void bigint_multiply_sample ( const bigint_element_t *multiplicand0, unsigned int multiplicand_size, const bigint_element_t *multiplier0, @@ -430,6 +440,42 @@ void bigint_mod_exp_sample ( const bigint_element_t *base0, ok ( max_set_bit == (expected) ); \ } while ( 0 ) +/** + * Report result of big integer swap test + * + * @v first Big integer to be conditionally swapped + * @v second Big integer to be conditionally swapped + */ +#define bigint_swap_ok( first, second ) do { \ + static const uint8_t first_raw[] = first; \ + static const uint8_t second_raw[] = second; \ + uint8_t temp[ sizeof ( first_raw ) ]; \ + unsigned int size = bigint_required_size ( sizeof ( temp) ); \ + bigint_t ( size ) first_temp; \ + bigint_t ( size ) second_temp; \ + {} /* Fix emacs alignment */ \ + \ + assert ( sizeof ( first_raw ) == sizeof ( temp ) ); \ + assert ( sizeof ( second_raw ) == sizeof ( temp ) ); \ + bigint_init ( &first_temp, first_raw, sizeof ( first_raw ) ); \ + bigint_init ( &second_temp, second_raw, sizeof ( second_raw ) );\ + bigint_swap ( &first_temp, &second_temp, 0 ); \ + bigint_done ( &first_temp, temp, sizeof ( temp ) ); \ + ok ( memcmp ( temp, first_raw, sizeof ( temp ) ) == 0 ); \ + bigint_done ( &second_temp, temp, sizeof ( temp ) ); \ + ok ( memcmp ( temp, second_raw, sizeof ( temp ) ) == 0 ); \ + bigint_swap ( &first_temp, &second_temp, 1 ); \ + bigint_done ( &first_temp, temp, sizeof ( temp ) ); \ + ok ( memcmp ( temp, second_raw, sizeof ( temp ) ) == 0 ); \ + bigint_done ( &second_temp, temp, sizeof ( temp ) ); \ + ok ( memcmp ( temp, first_raw, sizeof ( temp ) ) == 0 ); \ + bigint_swap ( &first_temp, &second_temp, 1 ); \ + bigint_done ( &first_temp, temp, sizeof ( temp ) ); \ + ok ( memcmp ( temp, first_raw, sizeof ( temp ) ) == 0 ); \ + bigint_done ( &second_temp, temp, sizeof ( temp ) ); \ + ok ( memcmp ( temp, second_raw, sizeof ( temp ) ) == 0 ); \ + } while ( 0 ) + /** * Report result of big integer multiplication test * @@ -1373,6 +1419,14 @@ static void bigint_test_exec ( void ) { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff ), 1024 ); + bigint_swap_ok ( BIGINT ( 0x68, 0x65, 0x6c, 0x6c, 0x6f ), + BIGINT ( 0x77, 0x6f, 0x72, 0x6c, 0x64 ) ); + bigint_swap_ok ( BIGINT ( 0xc8, 0x1c, 0x31, 0xd7, 0x13, 0x69, 0x47, + 0x32, 0xb0, 0x0a, 0xf7, 0x2d, 0xb9, 0xc3, + 0x35, 0x96 ), + BIGINT ( 0x8b, 0x1d, 0x8f, 0x21, 0x76, 0x16, 0x4c, + 0xf8, 0xb2, 0x63, 0xed, 0x89, 0x5e, 0x6b, + 0x35, 0x7c ) ); bigint_multiply_ok ( BIGINT ( 0xf0 ), BIGINT ( 0xeb ), BIGINT ( 0xdc, 0x50 ) ); -- cgit v1.2.3-55-g7522 From 908174ec7e49d845c8b52a07a3db32534eade37d Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Fri, 19 Jan 2024 16:35:02 +0000 Subject: [loong64] Replace broken big integer arithmetic implementations The slightly incomprehensible LoongArch64 implementation for bigint_subtract() is observed to produce incorrect results for some input values. Replace the suspicious LoongArch64 implementations of bigint_add(), bigint_subtract(), bigint_rol() and bigint_ror(), and add a test case for a subtraction that was producing an incorrect result with the previous implementation. Signed-off-by: Michael Brown --- src/arch/loong64/include/bits/bigint.h | 184 +++++++++++++++++++-------------- src/tests/bigint_test.c | 9 ++ 2 files changed, 115 insertions(+), 78 deletions(-) diff --git a/src/arch/loong64/include/bits/bigint.h b/src/arch/loong64/include/bits/bigint.h index a37ac73c..bec748be 100644 --- a/src/arch/loong64/include/bits/bigint.h +++ b/src/arch/loong64/include/bits/bigint.h @@ -53,34 +53,37 @@ bigint_add_raw ( const uint64_t *addend0, uint64_t *value0, uint64_t *discard_value; uint64_t discard_addend_i; uint64_t discard_value_i; + uint64_t discard_carry; + uint64_t discard_temp; unsigned int discard_size; - __asm__ __volatile__ ( "move $t0, $zero\n" - "1:\n\t" - "ld.d %3, %0, 0\n\t" - "addi.d %0, %0, 8\n\t" - "ld.d %4, %1, 0\n\t" - - "add.d %4, %4, $t0\n\t" - "sltu $t0, %4, $t0\n\t" - - "add.d %4, %4, %3\n\t" - "sltu $t1, %4, %3\n\t" - "or $t0, $t0, $t1\n\t" - "st.d %4, %1, 0\n\t" + __asm__ __volatile__ ( "\n1:\n\t" + /* Load addend[i] and value[i] */ + "ld.d %3, %0, 0\n\t" + "ld.d %4, %1, 0\n\t" + /* Add carry flag and addend */ + "add.d %4, %4, %5\n\t" + "sltu %6, %4, %5\n\t" + "add.d %4, %4, %3\n\t" + "sltu %5, %4, %3\n\t" + "or %5, %5, %6\n\t" + /* Store value[i] */ + "st.d %4, %1, 0\n\t" + /* Loop */ + "addi.d %0, %0, 8\n\t" "addi.d %1, %1, 8\n\t" "addi.w %2, %2, -1\n\t" - "bnez %2, 1b" + "bnez %2, 1b\n\t" : "=r" ( discard_addend ), "=r" ( discard_value ), "=r" ( discard_size ), "=r" ( discard_addend_i ), "=r" ( discard_value_i ), + "=r" ( discard_carry ), + "=r" ( discard_temp ), "+m" ( *value ) - : "0" ( addend0 ), - "1" ( value0 ), - "2" ( size ) - : "t0", "t1" ); + : "0" ( addend0 ), "1" ( value0 ), + "2" ( size ), "5" ( 0 ) ); } /** @@ -93,35 +96,43 @@ bigint_add_raw ( const uint64_t *addend0, uint64_t *value0, static inline __attribute__ (( always_inline )) void bigint_subtract_raw ( const uint64_t *subtrahend0, uint64_t *value0, unsigned int size ) { + bigint_t ( size ) __attribute__ (( may_alias )) *value = + ( ( void * ) value0 ); uint64_t *discard_subtrahend; uint64_t *discard_value; uint64_t discard_subtrahend_i; uint64_t discard_value_i; + uint64_t discard_carry; + uint64_t discard_temp; unsigned int discard_size; - unsigned int flag = 0; - - discard_subtrahend = (uint64_t*) subtrahend0; - discard_value = value0; - discard_size = size; - - do { - discard_subtrahend_i = *discard_subtrahend; - discard_subtrahend++; - discard_value_i = *discard_value; - - discard_value_i = discard_value_i - discard_subtrahend_i - flag; - - if ( *discard_value < (discard_subtrahend_i + flag)) { - flag = 1; - } else { - flag = 0; - } - *discard_value = discard_value_i; - - discard_value++; - discard_size -= 1; - } while (discard_size != 0); + __asm__ __volatile__ ( "\n1:\n\t" + /* Load subtrahend[i] and value[i] */ + "ld.d %3, %0, 0\n\t" + "ld.d %4, %1, 0\n\t" + /* Subtract carry flag and subtrahend */ + "sltu %6, %4, %5\n\t" + "sub.d %4, %4, %5\n\t" + "sltu %5, %4, %3\n\t" + "sub.d %4, %4, %3\n\t" + "or %5, %5, %6\n\t" + /* Store value[i] */ + "st.d %4, %1, 0\n\t" + /* Loop */ + "addi.d %0, %0, 8\n\t" + "addi.d %1, %1, 8\n\t" + "addi.w %2, %2, -1\n\t" + "bnez %2, 1b\n\t" + : "=r" ( discard_subtrahend ), + "=r" ( discard_value ), + "=r" ( discard_size ), + "=r" ( discard_subtrahend_i ), + "=r" ( discard_value_i ), + "=r" ( discard_carry ), + "=r" ( discard_temp ), + "+m" ( *value ) + : "0" ( subtrahend0 ), "1" ( value0 ), + "2" ( size ), "5" ( 0 ) ); } /** @@ -132,30 +143,37 @@ bigint_subtract_raw ( const uint64_t *subtrahend0, uint64_t *value0, */ static inline __attribute__ (( always_inline )) void bigint_rol_raw ( uint64_t *value0, unsigned int size ) { + bigint_t ( size ) __attribute__ (( may_alias )) *value = + ( ( void * ) value0 ); uint64_t *discard_value; uint64_t discard_value_i; + uint64_t discard_carry; + uint64_t discard_temp; unsigned int discard_size; - uint64_t current_value_i; - unsigned int flag = 0; - discard_value = value0; - discard_size = size; - do { - discard_value_i = *discard_value; - current_value_i = discard_value_i; - - discard_value_i += discard_value_i + flag; - - if (discard_value_i < current_value_i) { - flag = 1; - } else { - flag = 0; - } - - *discard_value = discard_value_i; - discard_value++; - discard_size -= 1; - } while ( discard_size != 0 ); + __asm__ __volatile__ ( "\n1:\n\t" + /* Load value[i] */ + "ld.d %2, %0, 0\n\t" + /* Shift left */ + "rotri.d %2, %2, 63\n\t" + "andi %4, %2, 1\n\t" + "xor %2, %2, %4\n\t" + "or %2, %2, %3\n\t" + "move %3, %4\n\t" + /* Store value[i] */ + "st.d %2, %0, 0\n\t" + /* Loop */ + "addi.d %0, %0, 8\n\t" + "addi.w %1, %1, -1\n\t" + "bnez %1, 1b\n\t" + : "=r" ( discard_value ), + "=r" ( discard_size ), + "=r" ( discard_value_i ), + "=r" ( discard_carry ), + "=r" ( discard_temp ), + "+m" ( *value ) + : "0" ( value0 ), "1" ( size ), "3" ( 0 ) + : "cc" ); } /** @@ -166,27 +184,37 @@ bigint_rol_raw ( uint64_t *value0, unsigned int size ) { */ static inline __attribute__ (( always_inline )) void bigint_ror_raw ( uint64_t *value0, unsigned int size ) { + bigint_t ( size ) __attribute__ (( may_alias )) *value = + ( ( void * ) value0 ); uint64_t *discard_value; uint64_t discard_value_i; - uint64_t discard_value_j; + uint64_t discard_carry; + uint64_t discard_temp; unsigned int discard_size; - discard_value = value0; - discard_size = size; - - discard_value_j = 0; - - do { - discard_size -= 1; - - discard_value_i = *(discard_value + discard_size); - - discard_value_j = (discard_value_j << 63) | (discard_value_i >> 1); - - *(discard_value + discard_size) = discard_value_j; - - discard_value_j = discard_value_i; - } while ( discard_size > 0 ); + __asm__ __volatile__ ( "\n1:\n\t" + /* Load value[i] */ + "ld.d %2, %0, -8\n\t" + /* Shift right */ + "andi %4, %2, 1\n\t" + "xor %2, %2, %4\n\t" + "or %2, %2, %3\n\t" + "move %3, %4\n\t" + "rotri.d %2, %2, 1\n\t" + /* Store value[i] */ + "st.d %2, %0, -8\n\t" + /* Loop */ + "addi.d %0, %0, -8\n\t" + "addi.w %1, %1, -1\n\t" + "bnez %1, 1b\n\t" + : "=r" ( discard_value ), + "=r" ( discard_size ), + "=r" ( discard_value_i ), + "=r" ( discard_carry ), + "=r" ( discard_temp ), + "+m" ( *value ) + : "0" ( value0 + size ), "1" ( size ), "3" ( 0 ) + : "cc" ); } /** diff --git a/src/tests/bigint_test.c b/src/tests/bigint_test.c index f09d7c76..76aca105 100644 --- a/src/tests/bigint_test.c +++ b/src/tests/bigint_test.c @@ -714,6 +714,15 @@ static void bigint_test_exec ( void ) { bigint_subtract_ok ( BIGINT ( 0xbb, 0x77, 0x32, 0x5a ), BIGINT ( 0x5a, 0xd5, 0xfe, 0x28 ), BIGINT ( 0x9f, 0x5e, 0xcb, 0xce ) ); + bigint_subtract_ok ( BIGINT ( 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff ), + BIGINT ( 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x2a ), + BIGINT ( 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x2b ) ); bigint_subtract_ok ( BIGINT ( 0x7b, 0xaa, 0x16, 0xcf, 0x15, 0x87, 0xe0, 0x4f, 0x2c, 0xa3, 0xec, 0x2f, 0x46, 0xfb, 0x83, 0xc6, 0xe0, 0xee, -- cgit v1.2.3-55-g7522 From 2eea04c02ca902f8068b6ad0dd522e6e9a81691c Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Fri, 19 Jan 2024 12:36:11 +0000 Subject: [crypto] Add X25519 key exchange algorithm Add an implementation of the X25519 key exchange algorithm as defined in RFC7748. This implementation is inspired by and partially based upon the paper "Implementing Curve25519/X25519: A Tutorial on Elliptic Curve Cryptography" by Martin Kleppmann, available for download from https://www.cl.cam.ac.uk/teaching/2122/Crypto/curve25519.pdf The underlying modular addition, subtraction, and multiplication operations are completely redesigned for substantially improved efficiency compared to the TweetNaCl implementation studied in that paper (approximately 5x-10x faster and with 70% less memory usage). Signed-off-by: Michael Brown --- src/crypto/x25519.c | 808 ++++++++++++++++++++++++++++++++++++++++++++++ src/include/ipxe/x25519.h | 91 ++++++ src/tests/tests.c | 1 + src/tests/x25519_test.c | 571 ++++++++++++++++++++++++++++++++ 4 files changed, 1471 insertions(+) create mode 100644 src/crypto/x25519.c create mode 100644 src/include/ipxe/x25519.h create mode 100644 src/tests/x25519_test.c diff --git a/src/crypto/x25519.c b/src/crypto/x25519.c new file mode 100644 index 00000000..750a2a71 --- /dev/null +++ b/src/crypto/x25519.c @@ -0,0 +1,808 @@ +/* + * Copyright (C) 2024 Michael Brown . + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + * + * You can also choose to distribute this program under the terms of + * the Unmodified Binary Distribution Licence (as given in the file + * COPYING.UBDL), provided that you have satisfied its requirements. + */ + +FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); + +/** @file + * + * X25519 key exchange + * + * This implementation is inspired by and partially based upon the + * paper "Implementing Curve25519/X25519: A Tutorial on Elliptic Curve + * Cryptography" by Martin Kleppmann, available for download from + * https://www.cl.cam.ac.uk/teaching/2122/Crypto/curve25519.pdf + * + * The underlying modular addition, subtraction, and multiplication + * operations are completely redesigned for substantially improved + * efficiency compared to the TweetNaCl implementation studied in that + * paper. + * + * TweetNaCl iPXE + * --------- ---- + * + * Storage size of each big integer 128 40 + * (in bytes) + * + * Stack usage for key exchange 1144 360 + * (in bytes, large objects only) + * + * Cost of big integer addition 16 5 + * (in number of 64-bit additions) + * + * Cost of big integer multiplication 273 31 + * (in number of 64-bit multiplications) + * + * The implementation is constant-time (provided that the underlying + * big integer operations are also constant-time). + */ + +#include +#include +#include +#include +#include + +/** X25519 reduction constant + * + * The X25519 field prime is p=2^255-19. This gives us: + * + * p = 2^255 - 19 + * 2^255 = p + 19 + * 2^255 = 19 (mod p) + * k * 2^255 = k * 19 (mod p) + * + * We can therefore reduce a value modulo p by taking the high-order + * bits of the value from bit 255 and above, multiplying by 19, and + * adding this to the low-order 255 bits of the value. + * + * This would be cumbersome to do in practice since it would require + * partitioning the value at a 255-bit boundary (and hence would + * require some shifting and masking operations). However, we can + * note that: + * + * k * 2^255 = k * 19 (mod p) + * k * 2 * 2^255 = k * 2 * 19 (mod p) + * k * 2^256 = k * 38 (mod p) + * + * We can therefore simplify the reduction to taking the high order + * bits of the value from bit 256 and above, multiplying by 38, and + * adding this to the low-order 256 bits of the value. + * + * Since 256 will inevitably be a multiple of the big integer element + * size (typically 32 or 64 bits), this avoids the need to perform any + * shifting or masking operations. + */ +#define X25519_REDUCE_256 38 + +/** X25519 multiplication step 1 result + * + * Step 1 of X25519 multiplication is to compute the product of two + * X25519 unsigned 258-bit integers. + * + * Both multiplication inputs are limited to 258 bits, and so the + * product will have at most 516 bits. + */ +union x25519_multiply_step1 { + /** Raw product + * + * Big integer multiplication produces a result with a number + * of elements equal to the sum of the number of elements in + * each input. + */ + bigint_t ( X25519_SIZE + X25519_SIZE ) product; + /** Partition into low-order and high-order bits + * + * Reduction modulo p requires separating the low-order 256 + * bits from the remaining high-order bits. + * + * Since the value will never exceed 516 bits (see above), + * there will be at most 260 high-order bits. + */ + struct { + /** Low-order 256 bits */ + bigint_t ( bigint_required_size ( ( 256 /* bits */ + 7 ) / 8 ) ) + low_256bit; + /** High-order 260 bits */ + bigint_t ( bigint_required_size ( ( 260 /* bits */ + 7 ) / 8 ) ) + high_260bit; + } __attribute__ (( packed )) parts; +}; + +/** X25519 multiplication step 2 result + * + * Step 2 of X25519 multiplication is to multiply the high-order 260 + * bits from step 1 with the 6-bit reduction constant 38, and to add + * this to the low-order 256 bits from step 1. + * + * The multiplication inputs are limited to 260 and 6 bits + * respectively, and so the product will have at most 266 bits. After + * adding the low-order 256 bits from step 1, the result will have at + * most 267 bits. + */ +union x25519_multiply_step2 { + /** Raw product + * + * Big integer multiplication produces a result with a number + * of elements equal to the sum of the number of elements in + * each input. + */ + bigint_t ( bigint_required_size ( ( 260 /* bits */ + 7 ) / 8 ) + + bigint_required_size ( ( 6 /* bits */ + 7 ) / 8 ) ) product; + /** Big integer value + * + * The value will never exceed 267 bits (see above), and so + * may be consumed as a normal X25519 big integer. + */ + x25519_t value; + /** Partition into low-order and high-order bits + * + * Reduction modulo p requires separating the low-order 256 + * bits from the remaining high-order bits. + * + * Since the value will never exceed 267 bits (see above), + * there will be at most 11 high-order bits. + */ + struct { + /** Low-order 256 bits */ + bigint_t ( bigint_required_size ( ( 256 /* bits */ + 7 ) / 8 ) ) + low_256bit; + /** High-order 11 bits */ + bigint_t ( bigint_required_size ( ( 11 /* bits */ + 7 ) / 8 ) ) + high_11bit; + } __attribute__ (( packed )) parts; +}; + +/** X25519 multiplication step 3 result + * + * Step 3 of X25519 multiplication is to multiply the high-order 11 + * bits from step 2 with the 6-bit reduction constant 38, and to add + * this to the low-order 256 bits from step 2. + * + * The multiplication inputs are limited to 11 and 6 bits + * respectively, and so the product will have at most 17 bits. After + * adding the low-order 256 bits from step 2, the result will have at + * most 257 bits. + */ +union x25519_multiply_step3 { + /** Raw product + * + * Big integer multiplication produces a result with a number + * of elements equal to the sum of the number of elements in + * each input. + */ + bigint_t ( bigint_required_size ( ( 11 /* bits */ + 7 ) / 8 ) + + bigint_required_size ( ( 6 /* bits */ + 7 ) / 8 ) ) product; + /** Big integer value + * + * The value will never exceed 267 bits (see above), and so + * may be consumed as a normal X25519 big integer. + */ + x25519_t value; +}; + +/** X25519 multiplication temporary working space + * + * We overlap the buffers used by each step of the multiplication + * calculation to reduce the total stack space required: + * + * |--------------------------------------------------------| + * | <- pad -> | <------------ step 1 result -------------> | + * | | <- low 256 bits -> | <-- high 260 bits --> | + * | <------- step 2 result ------> | <-- step 3 result --> | + * |--------------------------------------------------------| + */ +union x25519_multiply_workspace { + /** Step 1 result */ + struct { + /** Padding to avoid collision between steps 1 and 2 + * + * The step 2 multiplication consumes the high 260 + * bits of step 1, and so the step 2 multiplication + * result must not overlap this portion of the step 1 + * result. + */ + uint8_t pad[ sizeof ( union x25519_multiply_step2 ) - + offsetof ( union x25519_multiply_step1, + parts.high_260bit ) ]; + /** Step 1 result */ + union x25519_multiply_step1 step1; + } __attribute__ (( packed )); + /** Steps 2 and 3 results */ + struct { + /** Step 2 result */ + union x25519_multiply_step2 step2; + /** Step 3 result */ + union x25519_multiply_step3 step3; + } __attribute__ (( packed )); +}; + +/** An X25519 elliptic curve point in projective coordinates + * + * A point (x,y) on the Montgomery curve used in X25519 is represented + * using projective coordinates (X/Z,Y/Z) so that intermediate + * calculations may be performed on both numerator and denominator + * separately, with the division step performed only once at the end + * of the calculation. + * + * The group operation calculation is performed using a Montgomery + * ladder as: + * + * X[2i] = ( X[i]^2 - Z[i]^2 )^2 + * X[2i+1] = ( X[i] * X[i+1] - Z[i] * Z[i+1] )^2 + * Z[2i] = 4 * X[i] * Z[i] * ( X[i]^2 + A * X[i] * Z[i] + Z[i]^2 ) + * Z[2i+1] = X[0] * ( X[i] * Z[i+1] - X[i+1] * Z[i] ) ^ 2 + * + * It is therefore not necessary to store (or use) the value of Y. + */ +struct x25519_projective { + /** X coordinate */ + union x25519_quad257 X; + /** Z coordinate */ + union x25519_quad257 Z; +}; + +/** An X25519 Montgomery ladder step */ +struct x25519_step { + /** X[n]/Z[n] */ + struct x25519_projective x_n; + /** X[n+1]/Z[n+1] */ + struct x25519_projective x_n1; +}; + +/** Constant p=2^255-19 (the finite field prime) */ +static const uint8_t x25519_p_raw[] = { + 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xed +}; + +/** Constant p=2^255-19 (the finite field prime) */ +static x25519_t x25519_p; + +/** Constant 2p=2^256-38 */ +static x25519_t x25519_2p; + +/** Constant 4p=2^257-76 */ +static x25519_t x25519_4p; + +/** Reduction constant (used during multiplication) */ +static const uint8_t x25519_reduce_256_raw[] = { X25519_REDUCE_256 }; + +/** Reduction constant (used during multiplication) */ +static bigint_t ( bigint_required_size ( sizeof ( x25519_reduce_256_raw ) ) ) + x25519_reduce_256; + +/** Constant 121665 (used in the Montgomery ladder) */ +static const uint8_t x25519_121665_raw[] = { 0x01, 0xdb, 0x41 }; + +/** Constant 121665 (used in the Montgomery ladder) */ +static union x25519_oct258 x25519_121665; + +/** + * Initialise constants + * + */ +static void x25519_init_constants ( void ) { + + /* Construct constant p */ + bigint_init ( &x25519_p, x25519_p_raw, sizeof ( x25519_p_raw ) ); + + /* Construct constant 2p */ + bigint_copy ( &x25519_p, &x25519_2p ); + bigint_add ( &x25519_p, &x25519_2p ); + + /* Construct constant 4p */ + bigint_copy ( &x25519_2p, &x25519_4p ); + bigint_add ( &x25519_2p, &x25519_4p ); + + /* Construct reduction constant */ + bigint_init ( &x25519_reduce_256, x25519_reduce_256_raw, + sizeof ( x25519_reduce_256_raw ) ); + + /* Construct constant 121665 */ + bigint_init ( &x25519_121665.value, x25519_121665_raw, + sizeof ( x25519_121665_raw ) ); +} + +/** Initialisation function */ +struct init_fn x25519_init_fn __init_fn ( INIT_NORMAL ) = { + .initialise = x25519_init_constants, +}; + +/** + * Add big integers modulo field prime + * + * @v augend Big integer to add + * @v addend Big integer to add + * @v result Big integer to hold result (may overlap augend) + */ +static inline __attribute__ (( always_inline )) void +x25519_add ( const union x25519_quad257 *augend, + const union x25519_quad257 *addend, + union x25519_oct258 *result ) { + int copy; + + /* Copy augend if necessary */ + copy = ( result != &augend->oct258 ); + build_assert ( __builtin_constant_p ( copy ) ); + if ( copy ) { + build_assert ( result != &addend->oct258 ); + bigint_copy ( &augend->oct258.value, &result->value ); + } + + /* Perform addition + * + * Both inputs are in the range [0,4p-1] and the resulting + * sum is therefore in the range [0,8p-2]. + * + * This range lies within the range [0,8p-1] and the result is + * therefore a valid X25519 unsigned 258-bit integer, as + * required. + */ + bigint_add ( &addend->value, &result->value ); +} + +/** + * Subtract big integers modulo field prime + * + * @v minuend Big integer from which to subtract + * @v subtrahend Big integer to subtract + * @v result Big integer to hold result (may overlap minuend) + */ +static inline __attribute__ (( always_inline )) void +x25519_subtract ( const union x25519_quad257 *minuend, + const union x25519_quad257 *subtrahend, + union x25519_oct258 *result ) { + int copy; + + /* Copy minuend if necessary */ + copy = ( result != &minuend->oct258 ); + build_assert ( __builtin_constant_p ( copy ) ); + if ( copy ) { + build_assert ( result != &subtrahend->oct258 ); + bigint_copy ( &minuend->oct258.value, &result->value ); + } + + /* Perform subtraction + * + * Both inputs are in the range [0,4p-1] and the resulting + * difference is therefore in the range [1-4p,4p-1]. + * + * This range lies partially outside the range [0,8p-1] and + * the result is therefore not yet a valid X25519 unsigned + * 258-bit integer. + */ + bigint_subtract ( &subtrahend->value, &result->value ); + + /* Add constant multiple of field prime p + * + * Add the constant 4p to the result. This brings the result + * within the range [1,8p-1] (without changing the value + * modulo p). + * + * This range lies within the range [0,8p-1] and the result is + * therefore now a valid X25519 unsigned 258-bit integer, as + * required. + */ + bigint_add ( &x25519_4p, &result->value ); +} + +/** + * Multiply big integers modulo field prime + * + * @v multiplicand Big integer to be multiplied + * @v multiplier Big integer to be multiplied + * @v result Big integer to hold result (may overlap either input) + */ +void x25519_multiply ( const union x25519_oct258 *multiplicand, + const union x25519_oct258 *multiplier, + union x25519_quad257 *result ) { + union x25519_multiply_workspace tmp; + union x25519_multiply_step1 *step1 = &tmp.step1; + union x25519_multiply_step2 *step2 = &tmp.step2; + union x25519_multiply_step3 *step3 = &tmp.step3; + + /* Step 1: perform raw multiplication + * + * step1 = multiplicand * multiplier + * + * Both inputs are 258-bit numbers and the step 1 result is + * therefore 258+258=516 bits. + */ + static_assert ( sizeof ( step1->product ) >= sizeof ( step1->parts ) ); + bigint_multiply ( &multiplicand->value, &multiplier->value, + &step1->product ); + + /* Step 2: reduce high-order 516-256=260 bits of step 1 result + * + * Use the identity 2^256=38 (mod p) to reduce the high-order + * bits of the step 1 result. We split the 516-bit result + * from step 1 into its low-order 256 bits and high-order 260 + * bits: + * + * step1 = step1(low 256 bits) + step1(high 260 bits) * 2^256 + * + * and then perform the calculation: + * + * step2 = step1 (mod p) + * = step1(low 256 bits) + step1(high 260 bits) * 2^256 (mod p) + * = step1(low 256 bits) + step1(high 260 bits) * 38 (mod p) + * + * There are 6 bits in the constant value 38. The step 2 + * multiplication product will therefore have 260+6=266 bits, + * and the step 2 result (after the addition) will therefore + * have 267 bits. + */ + static_assert ( sizeof ( step2->product ) >= sizeof ( step2->value ) ); + static_assert ( sizeof ( step2->product ) >= sizeof ( step2->parts ) ); + bigint_grow ( &step1->parts.low_256bit, &result->value ); + bigint_multiply ( &step1->parts.high_260bit, &x25519_reduce_256, + &step2->product ); + bigint_add ( &result->value, &step2->value ); + + /* Step 3: reduce high-order 267-256=11 bits of step 2 result + * + * Use the identity 2^256=38 (mod p) again to reduce the + * high-order bits of the step 2 result. As before, we split + * the 267-bit result from step 2 into its low-order 256 bits + * and high-order 11 bits: + * + * step2 = step2(low 256 bits) + step2(high 11 bits) * 2^256 + * + * and then perform the calculation: + * + * step3 = step2 (mod p) + * = step2(low 256 bits) + step2(high 11 bits) * 2^256 (mod p) + * = step2(low 256 bits) + step2(high 11 bits) * 38 (mod p) + * + * There are 6 bits in the constant value 38. The step 3 + * multiplication product will therefore have 11+6=19 bits, + * and the step 3 result (after the addition) will therefore + * have 257 bits. + * + * A loose upper bound for the step 3 result (after the + * addition) is given by: + * + * step3 < ( 2^256 - 1 ) + ( 2^19 - 1 ) + * < ( 2^257 - 2^256 - 1 ) + ( 2^19 - 1 ) + * < ( 2^257 - 76 ) - 2^256 + 2^19 + 74 + * < 4 * ( 2^255 - 19 ) - 2^256 + 2^19 + 74 + * < 4p - 2^256 + 2^19 + 74 + * + * and so the step 3 result is strictly less than 4p, and + * therefore lies within the range [0,4p-1]. + */ + memset ( &step3->value, 0, sizeof ( step3->value ) ); + bigint_grow ( &step2->parts.low_256bit, &result->value ); + bigint_multiply ( &step2->parts.high_11bit, &x25519_reduce_256, + &step3->product ); + bigint_add ( &step3->value, &result->value ); + + /* Step 1 calculates the product of the input operands, and + * each subsequent step reduces the number of bits in the + * result while preserving this value (modulo p). The final + * result is therefore equal to the product of the input + * operands (modulo p), as required. + * + * The step 3 result lies within the range [0,4p-1] and the + * final result is therefore a valid X25519 unsigned 257-bit + * integer, as required. + */ +} + +/** + * Compute multiplicative inverse + * + * @v invertend Big integer to be inverted + * @v result Big integer to hold result (may not overlap input) + */ +void x25519_invert ( const union x25519_oct258 *invertend, + union x25519_quad257 *result ) { + int i; + + /* Sanity check */ + assert ( invertend != &result->oct258 ); + + /* Calculate inverse as x^(-1)=x^(p-2) where p is the field prime + * + * The field prime is p=2^255-19 and so: + * + * p - 2 = 2^255 - 21 + * = (2^255 - 1) - 2^4 - 2^2 + * + * i.e. p-2 is a 254-bit number in which all bits are set + * apart from bit 2 and bit 4. + * + * We use the square-and-multiply method to compute x^(p-2). + */ + bigint_copy ( &invertend->value, &result->value ); + for ( i = 253 ; i >= 0 ; i-- ) { + + /* Square running total */ + x25519_multiply ( &result->oct258, &result->oct258, result ); + + /* For each set bit in the exponent, multiply by invertend */ + if ( ( i != 2 ) && ( i != 4 ) ) { + x25519_multiply ( invertend, &result->oct258, result ); + } + } +} + +/** + * Reduce big integer via conditional subtraction + * + * @v subtrahend Big integer to subtract + * @v value Big integer to be subtracted from, if possible + */ +static void x25519_reduce_by ( const x25519_t *subtrahend, x25519_t *value ) { + unsigned int max_bit = ( ( 8 * sizeof ( *value ) ) - 1 ); + x25519_t tmp; + + /* Conditionally subtract subtrahend + * + * Subtract the subtrahend, discarding the result (in constant + * time) if the subtraction underflows. + */ + bigint_copy ( value, &tmp ); + bigint_subtract ( subtrahend, value ); + bigint_swap ( value, &tmp, bigint_bit_is_set ( value, max_bit ) ); +} + +/** + * Reduce big integer to canonical range + * + * @v value Big integer to be reduced + */ +void x25519_reduce ( union x25519_quad257 *value ) { + + /* Conditionally subtract 2p + * + * Subtract twice the field prime, discarding the result (in + * constant time) if the subtraction underflows. + * + * The input value is in the range [0,4p-1]. After this + * conditional subtraction, the value is in the range + * [0,2p-1]. + */ + x25519_reduce_by ( &x25519_2p, &value->value ); + + /* Conditionally subtract p + * + * Subtract the field prime, discarding the result (in + * constant time) if the subtraction underflows. + * + * The value is already in the range [0,2p-1]. After this + * conditional subtraction, the value is in the range [0,p-1] + * and is therefore the canonical representation. + */ + x25519_reduce_by ( &x25519_p, &value->value ); +} + +/** + * Compute next step of the Montgomery ladder + * + * @v base Base point + * @v bit Bit value + * @v step Ladder step + */ +static void x25519_step ( const union x25519_quad257 *base, int bit, + struct x25519_step *step ) { + union x25519_quad257 *a = &step->x_n.X; + union x25519_quad257 *b = &step->x_n1.X; + union x25519_quad257 *c = &step->x_n.Z; + union x25519_quad257 *d = &step->x_n1.Z; + union x25519_oct258 e; + union x25519_quad257 f; + union x25519_oct258 *v1_e; + union x25519_oct258 *v2_a; + union x25519_oct258 *v3_c; + union x25519_oct258 *v4_b; + union x25519_quad257 *v5_d; + union x25519_quad257 *v6_f; + union x25519_quad257 *v7_a; + union x25519_quad257 *v8_c; + union x25519_oct258 *v9_e; + union x25519_oct258 *v10_a; + union x25519_quad257 *v11_b; + union x25519_oct258 *v12_c; + union x25519_quad257 *v13_a; + union x25519_oct258 *v14_a; + union x25519_quad257 *v15_c; + union x25519_quad257 *v16_a; + union x25519_quad257 *v17_d; + union x25519_quad257 *v18_b; + + /* See the referenced paper "Implementing Curve25519/X25519: A + * Tutorial on Elliptic Curve Cryptography" for the reasoning + * behind this calculation. + */ + + /* Reuse storage locations for intermediate results where possible */ + v1_e = &e; + v2_a = container_of ( &a->value, union x25519_oct258, value ); + v3_c = container_of ( &c->value, union x25519_oct258, value ); + v4_b = container_of ( &b->value, union x25519_oct258, value ); + v5_d = d; + v6_f = &f; + v7_a = a; + v8_c = c; + v9_e = &e; + v10_a = container_of ( &a->value, union x25519_oct258, value ); + v11_b = b; + v12_c = container_of ( &c->value, union x25519_oct258, value ); + v13_a = a; + v14_a = container_of ( &a->value, union x25519_oct258, value ); + v15_c = c; + v16_a = a; + v17_d = d; + v18_b = b; + + /* Select inputs */ + bigint_swap ( &a->value, &b->value, bit ); + bigint_swap ( &c->value, &d->value, bit ); + + /* v1 = a + c */ + x25519_add ( a, c, v1_e ); + + /* v2 = a - c */ + x25519_subtract ( a, c, v2_a ); + + /* v3 = b + d */ + x25519_add ( b, d, v3_c ); + + /* v4 = b - d */ + x25519_subtract ( b, d, v4_b ); + + /* v5 = v1^2 = (a + c)^2 = a^2 + 2ac + c^2 */ + x25519_multiply ( v1_e, v1_e, v5_d ); + + /* v6 = v2^2 = (a - c)^2 = a^2 - 2ac + c^2 */ + x25519_multiply ( v2_a, v2_a, v6_f ); + + /* v7 = v3 * v2 = (b + d) * (a - c) = ab - bc + ad - cd */ + x25519_multiply ( v3_c, v2_a, v7_a ); + + /* v8 = v4 * v1 = (b - d) * (a + c) = ab + bc - ad - cd */ + x25519_multiply ( v4_b, v1_e, v8_c ); + + /* v9 = v7 + v8 = 2 * (ab - cd) */ + x25519_add ( v7_a, v8_c, v9_e ); + + /* v10 = v7 - v8 = 2 * (ad - bc) */ + x25519_subtract ( v7_a, v8_c, v10_a ); + + /* v11 = v10^2 = 4 * (ad - bc)^2 */ + x25519_multiply ( v10_a, v10_a, v11_b ); + + /* v12 = v5 - v6 = (a + c)^2 - (a - c)^2 = 4ac */ + x25519_subtract ( v5_d, v6_f, v12_c ); + + /* v13 = v12 * 121665 = 486660ac = (A-2) * ac */ + x25519_multiply ( v12_c, &x25519_121665, v13_a ); + + /* v14 = v13 + v5 = (A-2) * ac + a^2 + 2ac + c^2 = a^2 + A * ac + c^2 */ + x25519_add ( v13_a, v5_d, v14_a ); + + /* v15 = v12 * v14 = 4ac * (a^2 + A * ac + c^2) */ + x25519_multiply ( v12_c, v14_a, v15_c ); + + /* v16 = v5 * v6 = (a + c)^2 * (a - c)^2 = (a^2 - c^2)^2 */ + x25519_multiply ( &v5_d->oct258, &v6_f->oct258, v16_a ); + + /* v17 = v11 * base = 4 * base * (ad - bc)^2 */ + x25519_multiply ( &v11_b->oct258, &base->oct258, v17_d ); + + /* v18 = v9^2 = 4 * (ab - cd)^2 */ + x25519_multiply ( v9_e, v9_e, v18_b ); + + /* Select outputs */ + bigint_swap ( &a->value, &b->value, bit ); + bigint_swap ( &c->value, &d->value, bit ); +} + +/** + * Multiply X25519 elliptic curve point + * + * @v base Base point + * @v scalar Scalar multiple + * @v result Point to hold result (may overlap base point) + */ +static void x25519_ladder ( const union x25519_quad257 *base, + struct x25519_value *scalar, + union x25519_quad257 *result ) { + static const uint8_t zero[] = { 0 }; + static const uint8_t one[] = { 1 }; + struct x25519_step step; + union x25519_quad257 *tmp; + int bit; + int i; + + /* Initialise ladder */ + bigint_init ( &step.x_n.X.value, one, sizeof ( one ) ); + bigint_init ( &step.x_n.Z.value, zero, sizeof ( zero ) ); + bigint_copy ( &base->value, &step.x_n1.X.value ); + bigint_init ( &step.x_n1.Z.value, one, sizeof ( one ) ); + + /* Use ladder */ + for ( i = 254 ; i >= 0 ; i-- ) { + bit = ( ( scalar->raw[ i / 8 ] >> ( i % 8 ) ) & 1 ); + x25519_step ( base, bit, &step ); + } + + /* Convert back to affine coordinate */ + tmp = &step.x_n1.X; + x25519_invert ( &step.x_n.Z.oct258, tmp ); + x25519_multiply ( &step.x_n.X.oct258, &tmp->oct258, result ); + x25519_reduce ( result ); +} + +/** + * Reverse X25519 value endianness + * + * @v value Value to reverse + */ +static void x25519_reverse ( struct x25519_value *value ) { + uint8_t *low = value->raw; + uint8_t *high = &value->raw[ sizeof ( value->raw ) - 1 ]; + uint8_t tmp; + + /* Reverse bytes */ + do { + tmp = *low; + *low = *high; + *high = tmp; + } while ( ++low < --high ); +} + +/** + * Calculate X25519 key + * + * @v base Base point + * @v scalar Scalar multiple + * @v result Point to hold result (may overlap base point) + */ +void x25519_key ( const struct x25519_value *base, + const struct x25519_value *scalar, + struct x25519_value *result ) { + struct x25519_value *tmp = result; + union x25519_quad257 point; + + /* Reverse base point and clear high bit as required by RFC7748 */ + memcpy ( tmp, base, sizeof ( *tmp ) ); + x25519_reverse ( tmp ); + tmp->raw[0] &= 0x7f; + bigint_init ( &point.value, tmp->raw, sizeof ( tmp->raw ) ); + + /* Clamp scalar as required by RFC7748 */ + memcpy ( tmp, scalar, sizeof ( *tmp ) ); + tmp->raw[0] &= 0xf8; + tmp->raw[31] |= 0x40; + + /* Multiply elliptic curve point */ + x25519_ladder ( &point, tmp, &point ); + + /* Reverse result */ + bigint_done ( &point.value, result->raw, sizeof ( result->raw ) ); + x25519_reverse ( result ); +} diff --git a/src/include/ipxe/x25519.h b/src/include/ipxe/x25519.h new file mode 100644 index 00000000..7a86c113 --- /dev/null +++ b/src/include/ipxe/x25519.h @@ -0,0 +1,91 @@ +#ifndef _IPXE_X25519_H +#define _IPXE_X25519_H + +/** @file + * + * X25519 key exchange + * + */ + +FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); + +#include +#include + +/** X25519 unsigned big integer size + * + * X25519 uses the finite field of integers modulo the prime + * p=2^255-19. The canonical representations of integers in this + * field therefore require only 255 bits. + * + * For internal calculations we use big integers containing up to 267 + * bits, since this ends up allowing us to avoid some unnecessary (and + * expensive) intermediate reductions modulo p. + */ +#define X25519_SIZE bigint_required_size ( ( 267 /* bits */ + 7 ) / 8 ) + +/** An X25519 unsigned big integer used in internal calculations */ +typedef bigint_t ( X25519_SIZE ) x25519_t; + +/** An X25519 unsigned 258-bit integer + * + * This is an unsigned integer N in the finite field of integers + * modulo the prime p=2^255-19. + * + * In this representation, N is encoded as any big integer that is in + * the same congruence class as N (i.e that has the same value as N + * modulo p) and that lies within the 258-bit range [0,8p-1]. + * + * This type can be used as an input for multiplication (but not for + * addition or subtraction). + * + * Addition or subtraction will produce an output of this type. + */ +union x25519_oct258 { + /** Big integer value */ + x25519_t value; +}; + +/** An X25519 unsigned 257-bit integer + * + * This is an unsigned integer N in the finite field of integers + * modulo the prime p=2^255-19. + * + * In this representation, N is encoded as any big integer that is in + * the same congruence class as N (i.e that has the same value as N + * modulo p) and that lies within the 257-bit range [0,4p-1]. + * + * This type can be used as an input for addition, subtraction, or + * multiplication. + * + * Multiplication will produce an output of this type. + */ +union x25519_quad257 { + /** Big integer value */ + x25519_t value; + /** X25519 unsigned 258-bit integer + * + * Any value in the range [0,4p-1] is automatically also + * within the range [0,8p-1] and so may be consumed as an + * unsigned 258-bit integer. + */ + const union x25519_oct258 oct258; +}; + +/** An X25519 32-byte value */ +struct x25519_value { + /** Raw value */ + uint8_t raw[32]; +}; + +extern void x25519_multiply ( const union x25519_oct258 *multiplicand, + const union x25519_oct258 *multiplier, + union x25519_quad257 *result ); +extern void x25519_invert ( const union x25519_oct258 *invertend, + union x25519_quad257 *result ); +extern void x25519_reduce ( union x25519_quad257 *value ); +extern void x25519_key ( const struct x25519_value *base, + const struct x25519_value *scalar, + struct x25519_value *result ); + +#endif /* _IPXE_X25519_H */ diff --git a/src/tests/tests.c b/src/tests/tests.c index fbdf562c..41c199c0 100644 --- a/src/tests/tests.c +++ b/src/tests/tests.c @@ -81,3 +81,4 @@ REQUIRE_OBJECT ( hmac_test ); REQUIRE_OBJECT ( dhe_test ); REQUIRE_OBJECT ( gcm_test ); REQUIRE_OBJECT ( nap_test ); +REQUIRE_OBJECT ( x25519_test ); diff --git a/src/tests/x25519_test.c b/src/tests/x25519_test.c new file mode 100644 index 00000000..3d781f91 --- /dev/null +++ b/src/tests/x25519_test.c @@ -0,0 +1,571 @@ +/* + * Copyright (C) 2024 Michael Brown . + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + * + * You can also choose to distribute this program under the terms of + * the Unmodified Binary Distribution Licence (as given in the file + * COPYING.UBDL), provided that you have satisfied its requirements. + */ + +FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); + +/** @file + * + * X25519 key exchange test + * + * Full key exchange test vectors are taken from RFC7748. + * + */ + +/* Forcibly enable assertions */ +#undef NDEBUG + +#include +#include +#include +#include + +/** Define inline multiplicand */ +#define MULTIPLICAND(...) { __VA_ARGS__ } + +/** Define inline multiplier */ +#define MULTIPLIER(...) { __VA_ARGS__ } + +/** Define inline invertend */ +#define INVERTEND(...) { __VA_ARGS__ } + +/** Define inline base point */ +#define BASE(...) { __VA_ARGS__ } + +/** Define inline scalar multiple */ +#define SCALAR(...) { __VA_ARGS__ } + +/** Define inline expected result */ +#define EXPECTED(...) { __VA_ARGS__ } + +/** An X25519 multiplication self-test */ +struct x25519_multiply_test { + /** Multiplicand */ + const void *multiplicand; + /** Length of multiplicand */ + size_t multiplicand_len; + /** Multiplier */ + const void *multiplier; + /** Length of multiplier */ + size_t multiplier_len; + /** Expected result */ + const void *expected; + /** Length of expected result */ + size_t expected_len; +}; + +/** + * Define an X25519 multiplication test + * + * @v name Test name + * @v MULTIPLICAND 258-bit multiplicand + * @v MULTIPLIER 258-bit multiplier + * @v EXPECTED 255-bit expected result + * @ret test X25519 multiplication test + */ +#define X25519_MULTIPLY_TEST( name, MULTIPLICAND, MULTIPLIER, \ + EXPECTED ) \ + static const uint8_t name ## _multiplicand[] = MULTIPLICAND; \ + static const uint8_t name ## _multiplier[] = MULTIPLIER; \ + static const uint8_t name ## _expected[] = EXPECTED; \ + static struct x25519_multiply_test name = { \ + .multiplicand = name ## _multiplicand, \ + .multiplicand_len = sizeof ( name ## _multiplicand ), \ + .multiplier = name ## _multiplier, \ + .multiplier_len = sizeof ( name ## _multiplier ), \ + .expected = name ## _expected, \ + .expected_len = sizeof ( name ## _expected ), \ + } + +/** An X25519 multiplicative inversion self-test */ +struct x25519_invert_test { + /** Invertend */ + const void *invertend; + /** Length of invertend */ + size_t invertend_len; + /** Expected result */ + const void *expected; + /** Length of expected result */ + size_t expected_len; +}; + +/** + * Define an X25519 multiplicative inversion test + * + * @v name Test name + * @v INVERTEND 258-bit invertend + * @v EXPECTED 255-bit expected result + * @ret test X25519 multiplicative inversion test + */ +#define X25519_INVERT_TEST( name, INVERTEND, EXPECTED ) \ + static const uint8_t name ## _invertend[] = INVERTEND; \ + static const uint8_t name ## _expected[] = EXPECTED; \ + static struct x25519_invert_test name = { \ + .invertend = name ## _invertend, \ + .invertend_len = sizeof ( name ## _invertend ), \ + .expected = name ## _expected, \ + .expected_len = sizeof ( name ## _expected ), \ + } + +/** An X25519 key exchange self-test */ +struct x25519_key_test { + /** Base */ + struct x25519_value base; + /** Scalar */ + struct x25519_value scalar; + /** Expected result */ + struct x25519_value expected; + /** Number of iterations */ + unsigned int count; +}; + +/** + * Define an X25519 key exchange test + * + * @v name Test name + * @v COUNT Number of iterations + * @v BASE Base point + * @v SCALAR Scalar multiple + * @v EXPECTED Expected result + * @ret test X25519 key exchange test + */ +#define X25519_KEY_TEST( name, COUNT, BASE, SCALAR, EXPECTED ) \ + static struct x25519_key_test name = { \ + .count = COUNT, \ + .base = { .raw = BASE }, \ + .scalar = { .raw = SCALAR }, \ + .expected = { .raw = EXPECTED }, \ + } + +/** + * Report an X25519 multiplication test result + * + * @v test X25519 multiplication test + * @v file Test code file + * @v line Test code line + */ +static void x25519_multiply_okx ( struct x25519_multiply_test *test, + const char *file, unsigned int line ) { + union x25519_oct258 multiplicand; + union x25519_oct258 multiplier; + union x25519_quad257 expected; + union x25519_quad257 actual; + + /* Construct big integers */ + bigint_init ( &multiplicand.value, test->multiplicand, + test->multiplicand_len ); + DBGC ( test, "X25519 multiplicand:\n" ); + DBGC_HDA ( test, 0, &multiplicand, sizeof ( multiplicand ) ); + bigint_init ( &multiplier.value, test->multiplier, + test->multiplier_len ); + DBGC ( test, "X25519 multiplier:\n" ); + DBGC_HDA ( test, 0, &multiplier, sizeof ( multiplier ) ); + bigint_init ( &expected.value, test->expected, test->expected_len ); + DBGC ( test, "X25519 expected product:\n" ); + DBGC_HDA ( test, 0, &expected, sizeof ( expected ) ); + + /* Perform multiplication */ + x25519_multiply ( &multiplicand, &multiplier, &actual ); + + /* Reduce result to allow for comparison */ + x25519_reduce ( &actual ); + DBGC ( test, "X25519 actual product:\n" ); + DBGC_HDA ( test, 0, &actual, sizeof ( actual ) ); + + /* Compare against expected result */ + okx ( memcmp ( &actual, &expected, sizeof ( expected ) ) == 0, + file, line ); +} +#define x25519_multiply_ok( test ) \ + x25519_multiply_okx ( test, __FILE__, __LINE__ ) + +/** + * Report an X25519 multiplicative inversion test result + * + * @v test X25519 multiplicative inversion test + * @v file Test code file + * @v line Test code line + */ +static void x25519_invert_okx ( struct x25519_invert_test *test, + const char *file, unsigned int line ) { + static const uint8_t one[] = { 1 }; + union x25519_oct258 invertend; + union x25519_quad257 expected; + union x25519_quad257 actual; + union x25519_quad257 product; + union x25519_quad257 identity; + + /* Construct big integers */ + bigint_init ( &invertend.value, test->invertend, test->invertend_len ); + DBGC ( test, "X25519 invertend:\n" ); + DBGC_HDA ( test, 0, &invertend, sizeof ( invertend ) ); + bigint_init ( &expected.value, test->expected, test->expected_len ); + DBGC ( test, "X25519 expected inverse:\n" ); + DBGC_HDA ( test, 0, &expected, sizeof ( expected ) ); + bigint_init ( &identity.value, one, sizeof ( one ) ); + + /* Perform inversion */ + x25519_invert ( &invertend, &actual ); + + /* Multiply invertend by inverse */ + x25519_multiply ( &invertend, &actual.oct258, &product ); + + /* Reduce results to allow for comparison */ + x25519_reduce ( &actual ); + DBGC ( test, "X25519 actual inverse:\n" ); + DBGC_HDA ( test, 0, &actual, sizeof ( actual ) ); + x25519_reduce ( &product ); + DBGC ( test, "X25519 actual product:\n" ); + DBGC_HDA ( test, 0, &product, sizeof ( product ) ); + + /* Compare against expected results */ + okx ( memcmp ( &actual, &expected, sizeof ( expected ) ) == 0, + file, line ); + okx ( memcmp ( &product, &identity, sizeof ( identity ) ) == 0, + file, line ); +} +#define x25519_invert_ok( test ) \ + x25519_invert_okx ( test, __FILE__, __LINE__ ) + +/** + * Report an X25519 key exchange test result + * + * @v test X25519 key exchange test + * @v file Test code file + * @v line Test code line + */ +static void x25519_key_okx ( struct x25519_key_test *test, + const char *file, unsigned int line ) { + struct x25519_value base; + struct x25519_value scalar; + struct x25519_value actual; + unsigned int i; + + /* Construct input values */ + memcpy ( &base, &test->base, sizeof ( test->base ) ); + memcpy ( &scalar, &test->scalar, sizeof ( test->scalar ) ); + DBGC ( test, "X25519 base:\n" ); + DBGC_HDA ( test, 0, &base, sizeof ( base ) ); + DBGC ( test, "X25519 scalar:\n" ); + DBGC_HDA ( test, 0, &scalar, sizeof ( scalar ) ); + DBGC ( test, "X25519 expected result (x%d):\n", test->count ); + DBGC_HDA ( test, 0, &test->expected, sizeof ( test->expected ) ); + + /* Calculate key */ + for ( i = 0 ; i < test->count ; i++ ) { + x25519_key ( &base, &scalar, &actual ); + memcpy ( &base, &scalar, sizeof ( base ) ); + memcpy ( &scalar, &actual, sizeof ( scalar ) ); + } + DBGC ( test, "X25519 actual result (x%d):\n", test->count ); + DBGC_HDA ( test, 0, &actual, sizeof ( actual ) ); + + /* Compare against expected result */ + okx ( memcmp ( &actual, &test->expected, + sizeof ( test->expected ) ) == 0, file, line ); +} +#define x25519_key_ok( test ) \ + x25519_key_okx ( test, __FILE__, __LINE__ ) + +/* Test multiplying small numbers */ +X25519_MULTIPLY_TEST ( multiply_small, MULTIPLICAND ( 6 ), + MULTIPLIER ( 9 ), EXPECTED ( 6 * 9 ) ); + +/* Test exact multiple of field prime */ +X25519_MULTIPLY_TEST ( multiply_k_p, + MULTIPLICAND ( 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xed ), + MULTIPLIER ( 0x00, 0xe8, 0x0d, 0x83, 0xd4, 0xe9, 0x1e, 0xdd, 0x7a, + 0x45, 0x14, 0x87, 0xb7, 0xfc, 0x62, 0x54, 0x1f, 0xb2, + 0x97, 0x24, 0xde, 0xfa, 0xd3, 0xe7, 0x3e, 0x83, 0x93, + 0x60, 0xbc, 0x20, 0x97, 0x9b, 0x22 ), + EXPECTED ( 0x00 ) ); + +/* 0x0223b8c1e9392456de3eb13b9046685257bdd640fb06671ad11c80317fa3b1799d * + * 0x006c031199972a846916419f828b9d2434e465e150bd9c66b3ad3c2d6d1a3d1fa7 = + * 0x1ba87e982f7c477616b4d5136ba54733e40081c1c2e27d864aa178ce893d1297 (mod p) + */ +X25519_MULTIPLY_TEST ( multiply_1, + MULTIPLICAND ( 0x02, 0x23, 0xb8, 0xc1, 0xe9, 0x39, 0x24, 0x56, 0xde, + 0x3e, 0xb1, 0x3b, 0x90, 0x46, 0x68, 0x52, 0x57, 0xbd, + 0xd6, 0x40, 0xfb, 0x06, 0x67, 0x1a, 0xd1, 0x1c, 0x80, + 0x31, 0x7f, 0xa3, 0xb1, 0x79, 0x9d ), + MULTIPLIER ( 0x00, 0x6c, 0x03, 0x11, 0x99, 0x97, 0x2a, 0x84, 0x69, + 0x16, 0x41, 0x9f, 0x82, 0x8b, 0x9d, 0x24, 0x34, 0xe4, + 0x65, 0xe1, 0x50, 0xbd, 0x9c, 0x66, 0xb3, 0xad, 0x3c, + 0x2d, 0x6d, 0x1a, 0x3d, 0x1f, 0xa7 ), + EXPECTED ( 0x1b, 0xa8, 0x7e, 0x98, 0x2f, 0x7c, 0x47, 0x76, 0x16, 0xb4, + 0xd5, 0x13, 0x6b, 0xa5, 0x47, 0x33, 0xe4, 0x00, 0x81, 0xc1, + 0xc2, 0xe2, 0x7d, 0x86, 0x4a, 0xa1, 0x78, 0xce, 0x89, 0x3d, + 0x12, 0x97 ) ); + +/* 0x008fadc1a606cb0fb39a1de644815ef6d13b8faa1837f8a88b17fc695a07a0ca6e * + * 0x0196da1dac72ff5d2a386ecbe06b65a6a48b8148f6b38a088ca65ed389b74d0fb1 = + * 0x351f7bf75ef580249ed6f9ff3996463b0730a1d49b5d36b863e192591157e950 (mod p) + */ +X25519_MULTIPLY_TEST ( multiply_2, + MULTIPLICAND ( 0x00, 0x8f, 0xad, 0xc1, 0xa6, 0x06, 0xcb, 0x0f, 0xb3, + 0x9a, 0x1d, 0xe6, 0x44, 0x81, 0x5e, 0xf6, 0xd1, 0x3b, + 0x8f, 0xaa, 0x18, 0x37, 0xf8, 0xa8, 0x8b, 0x17, 0xfc, + 0x69, 0x5a, 0x07, 0xa0, 0xca, 0x6e ), + MULTIPLIER ( 0x01, 0x96, 0xda, 0x1d, 0xac, 0x72, 0xff, 0x5d, 0x2a, + 0x38, 0x6e, 0xcb, 0xe0, 0x6b, 0x65, 0xa6, 0xa4, 0x8b, + 0x81, 0x48, 0xf6, 0xb3, 0x8a, 0x08, 0x8c, 0xa6, 0x5e, + 0xd3, 0x89, 0xb7, 0x4d, 0x0f, 0xb1 ), + EXPECTED ( 0x35, 0x1f, 0x7b, 0xf7, 0x5e, 0xf5, 0x80, 0x24, 0x9e, 0xd6, + 0xf9, 0xff, 0x39, 0x96, 0x46, 0x3b, 0x07, 0x30, 0xa1, 0xd4, + 0x9b, 0x5d, 0x36, 0xb8, 0x63, 0xe1, 0x92, 0x59, 0x11, 0x57, + 0xe9, 0x50 ) ); + +/* 0x016c307511b2b9437a28df6ec4ce4a2bbdc241330b01a9e71fde8a774bcf36d58b * + * 0x0117be31111a2a73ed562b0f79c37459eef50bea63371ecd7b27cd813047229389 = + * 0x6b43b5185965f8f0920f31ae1b2cefadd7b078fecf68dbeaa17b9c385b558329 (mod p) + */ +X25519_MULTIPLY_TEST ( multiply_3, + MULTIPLICAND ( 0x01, 0x6c, 0x30, 0x75, 0x11, 0xb2, 0xb9, 0x43, 0x7a, + 0x28, 0xdf, 0x6e, 0xc4, 0xce, 0x4a, 0x2b, 0xbd, 0xc2, + 0x41, 0x33, 0x0b, 0x01, 0xa9, 0xe7, 0x1f, 0xde, 0x8a, + 0x77, 0x4b, 0xcf, 0x36, 0xd5, 0x8b ), + MULTIPLIER ( 0x01, 0x17, 0xbe, 0x31, 0x11, 0x1a, 0x2a, 0x73, 0xed, + 0x56, 0x2b, 0x0f, 0x79, 0xc3, 0x74, 0x59, 0xee, 0xf5, + 0x0b, 0xea, 0x63, 0x37, 0x1e, 0xcd, 0x7b, 0x27, 0xcd, + 0x81, 0x30, 0x47, 0x22, 0x93, 0x89 ), + EXPECTED ( 0x6b, 0x43, 0xb5, 0x18, 0x59, 0x65, 0xf8, 0xf0, 0x92, 0x0f, + 0x31, 0xae, 0x1b, 0x2c, 0xef, 0xad, 0xd7, 0xb0, 0x78, 0xfe, + 0xcf, 0x68, 0xdb, 0xea, 0xa1, 0x7b, 0x9c, 0x38, 0x5b, 0x55, + 0x83, 0x29 ) ); + +/* 0x020b1f9163ce9ff57f43b7a3a69a8dca03580d7b71d8f564135be6128e18c26797 * + * 0x018d5288f1142c3fe860e7a113ec1b8ca1f91e1d4c1ff49b7889463e85759cde66 = + * 0x28a77d3c8a14323d63b288dbd40315b3f192b8485d86a02cb87d3dfb7a0b5447 (mod p) + */ +X25519_MULTIPLY_TEST ( multiply_4, + MULTIPLICAND ( 0x02, 0x0b, 0x1f, 0x91, 0x63, 0xce, 0x9f, 0xf5, 0x7f, + 0x43, 0xb7, 0xa3, 0xa6, 0x9a, 0x8d, 0xca, 0x03, 0x58, + 0x0d, 0x7b, 0x71, 0xd8, 0xf5, 0x64, 0x13, 0x5b, 0xe6, + 0x12, 0x8e, 0x18, 0xc2, 0x67, 0x97 ), + MULTIPLIER ( 0x01, 0x8d, 0x52, 0x88, 0xf1, 0x14, 0x2c, 0x3f, 0xe8, + 0x60, 0xe7, 0xa1, 0x13, 0xec, 0x1b, 0x8c, 0xa1, 0xf9, + 0x1e, 0x1d, 0x4c, 0x1f, 0xf4, 0x9b, 0x78, 0x89, 0x46, + 0x3e, 0x85, 0x75, 0x9c, 0xde, 0x66 ), + EXPECTED ( 0x28, 0xa7, 0x7d, 0x3c, 0x8a, 0x14, 0x32, 0x3d, 0x63, 0xb2, + 0x88, 0xdb, 0xd4, 0x03, 0x15, 0xb3, 0xf1, 0x92, 0xb8, 0x48, + 0x5d, 0x86, 0xa0, 0x2c, 0xb8, 0x7d, 0x3d, 0xfb, 0x7a, 0x0b, + 0x54, 0x47 ) ); + +/* 0x023139d32c93cd59bf5c941cf0dc98d2c1e2acf72f9e574f7aa0ee89aed453dd32 * + * 0x03146d3f31fc377a4c4a15544dc5e7ce8a3a578a8ea9488d990bbb259911ce5dd2 = + * 0x4bdb7a35c0a5182000aa67554741e88cfdf460a78c6fae07adf83d2f005d2767 (mod p) + */ +X25519_MULTIPLY_TEST ( multiply_5, + MULTIPLICAND ( 0x02, 0x31, 0x39, 0xd3, 0x2c, 0x93, 0xcd, 0x59, 0xbf, + 0x5c, 0x94, 0x1c, 0xf0, 0xdc, 0x98, 0xd2, 0xc1, 0xe2, + 0xac, 0xf7, 0x2f, 0x9e, 0x57, 0x4f, 0x7a, 0xa0, 0xee, + 0x89, 0xae, 0xd4, 0x53, 0xdd, 0x32 ), + MULTIPLIER ( 0x03, 0x14, 0x6d, 0x3f, 0x31, 0xfc, 0x37, 0x7a, 0x4c, + 0x4a, 0x15, 0x54, 0x4d, 0xc5, 0xe7, 0xce, 0x8a, 0x3a, + 0x57, 0x8a, 0x8e, 0xa9, 0x48, 0x8d, 0x99, 0x0b, 0xbb, + 0x25, 0x99, 0x11, 0xce, 0x5d, 0xd2 ), + EXPECTED ( 0x4b, 0xdb, 0x7a, 0x35, 0xc0, 0xa5, 0x18, 0x20, 0x00, 0xaa, + 0x67, 0x55, 0x47, 0x41, 0xe8, 0x8c, 0xfd, 0xf4, 0x60, 0xa7, + 0x8c, 0x6f, 0xae, 0x07, 0xad, 0xf8, 0x3d, 0x2f, 0x00, 0x5d, + 0x27, 0x67 ) ); + +/* 0x01d58842dea2bc372f7412b29347294739614ff3d719db3ad0ddd1dfb23b982ef8 ^ -1 = + * 0x093ff51750809d181a9a5481c564e37cff618def8ec45f464b1a6e24f8b826bd (mod p) + */ +X25519_INVERT_TEST ( invert_1, + INVERTEND ( 0x01, 0xd5, 0x88, 0x42, 0xde, 0xa2, 0xbc, 0x37, 0x2f, + 0x74, 0x12, 0xb2, 0x93, 0x47, 0x29, 0x47, 0x39, 0x61, + 0x4f, 0xf3, 0xd7, 0x19, 0xdb, 0x3a, 0xd0, 0xdd, 0xd1, + 0xdf, 0xb2, 0x3b, 0x98, 0x2e, 0xf8 ), + EXPECTED ( 0x09, 0x3f, 0xf5, 0x17, 0x50, 0x80, 0x9d, 0x18, 0x1a, 0x9a, + 0x54, 0x81, 0xc5, 0x64, 0xe3, 0x7c, 0xff, 0x61, 0x8d, 0xef, + 0x8e, 0xc4, 0x5f, 0x46, 0x4b, 0x1a, 0x6e, 0x24, 0xf8, 0xb8, + 0x26, 0xbd ) ); + +/* 0x02efc89849b3aa7efe4458a885ab9099a435a240ae5af305535ec42e0829a3b2e9 ^ -1 = + * 0x591607b163e89d0ac33a62c881e984a25d3826e3db5ce229af240dc58e5b579a (mod p) + */ +X25519_INVERT_TEST ( invert_2, + INVERTEND ( 0x02, 0xef, 0xc8, 0x98, 0x49, 0xb3, 0xaa, 0x7e, 0xfe, + 0x44, 0x58, 0xa8, 0x85, 0xab, 0x90, 0x99, 0xa4, 0x35, + 0xa2, 0x40, 0xae, 0x5a, 0xf3, 0x05, 0x53, 0x5e, 0xc4, + 0x2e, 0x08, 0x29, 0xa3, 0xb2, 0xe9 ), + EXPECTED ( 0x59, 0x16, 0x07, 0xb1, 0x63, 0xe8, 0x9d, 0x0a, 0xc3, 0x3a, + 0x62, 0xc8, 0x81, 0xe9, 0x84, 0xa2, 0x5d, 0x38, 0x26, 0xe3, + 0xdb, 0x5c, 0xe2, 0x29, 0xaf, 0x24, 0x0d, 0xc5, 0x8e, 0x5b, + 0x57, 0x9a ) ); + +/* 0x003eabedcbbaa80dd488bd64072bcfbe01a28defe39bf0027312476f57a5e5a5ab ^ -1 = + * 0x7d87c2e565b27c5038181a0a7cae9ebe826c8afc1f77128a4d62cce96d2759a2 (mod p) + */ +X25519_INVERT_TEST ( invert_3, + INVERTEND ( 0x00, 0x3e, 0xab, 0xed, 0xcb, 0xba, 0xa8, 0x0d, 0xd4, + 0x88, 0xbd, 0x64, 0x07, 0x2b, 0xcf, 0xbe, 0x01, 0xa2, + 0x8d, 0xef, 0xe3, 0x9b, 0xf0, 0x02, 0x73, 0x12, 0x47, + 0x6f, 0x57, 0xa5, 0xe5, 0xa5, 0xab ), + EXPECTED ( 0x7d, 0x87, 0xc2, 0xe5, 0x65, 0xb2, 0x7c, 0x50, 0x38, 0x18, + 0x1a, 0x0a, 0x7c, 0xae, 0x9e, 0xbe, 0x82, 0x6c, 0x8a, 0xfc, + 0x1f, 0x77, 0x12, 0x8a, 0x4d, 0x62, 0xcc, 0xe9, 0x6d, 0x27, + 0x59, 0xa2 ) ); + +/* 0x008e944239b02b61c4a3d70628ece66fa2fd5166e6451b4cf36123fdf77656af72 ^ -1 = + * 0x08e96161a0eee1b29af396f154950d5c715dc61aff66ee97377ab22adf3321d7 (mod p) + */ +X25519_INVERT_TEST ( invert_4, + INVERTEND ( 0x00, 0x8e, 0x94, 0x42, 0x39, 0xb0, 0x2b, 0x61, 0xc4, + 0xa3, 0xd7, 0x06, 0x28, 0xec, 0xe6, 0x6f, 0xa2, 0xfd, + 0x51, 0x66, 0xe6, 0x45, 0x1b, 0x4c, 0xf3, 0x61, 0x23, + 0xfd, 0xf7, 0x76, 0x56, 0xaf, 0x72 ), + EXPECTED ( 0x08, 0xe9, 0x61, 0x61, 0xa0, 0xee, 0xe1, 0xb2, 0x9a, 0xf3, + 0x96, 0xf1, 0x54, 0x95, 0x0d, 0x5c, 0x71, 0x5d, 0xc6, 0x1a, + 0xff, 0x66, 0xee, 0x97, 0x37, 0x7a, 0xb2, 0x2a, 0xdf, 0x33, + 0x21, 0xd7 ) ); + +/* 0x00d261a7ab3aa2e4f90e51f30dc6a7ee39c4b032ccd7c524a55304317faf42e12f ^ -1 = + * 0x0738781c0aeabfbe6e840c85bd30996ef71bc54988ce16cedd5ab4f30c281597 (mod p) + */ +X25519_INVERT_TEST ( invert_5, + INVERTEND ( 0x00, 0xd2, 0x61, 0xa7, 0xab, 0x3a, 0xa2, 0xe4, 0xf9, + 0x0e, 0x51, 0xf3, 0x0d, 0xc6, 0xa7, 0xee, 0x39, 0xc4, + 0xb0, 0x32, 0xcc, 0xd7, 0xc5, 0x24, 0xa5, 0x53, 0x04, + 0x31, 0x7f, 0xaf, 0x42, 0xe1, 0x2f ), + EXPECTED ( 0x07, 0x38, 0x78, 0x1c, 0x0a, 0xea, 0xbf, 0xbe, 0x6e, 0x84, + 0x0c, 0x85, 0xbd, 0x30, 0x99, 0x6e, 0xf7, 0x1b, 0xc5, 0x49, + 0x88, 0xce, 0x16, 0xce, 0xdd, 0x5a, 0xb4, 0xf3, 0x0c, 0x28, + 0x15, 0x97 ) ); + +/* Base: 0xe6db6867583030db3594c1a424b15f7c726624ec26b3353b10a903a6d0ab1c4c + * Scalar: 0xa546e36bf0527c9d3b16154b82465edd62144c0ac1fc5a18506a2244ba449ac4 + * Result: 0xc3da55379de9c6908e94ea4df28d084f32eccf03491c71f754b4075577a28552 + */ +X25519_KEY_TEST ( rfc7748_1, 1, + BASE ( 0xe6, 0xdb, 0x68, 0x67, 0x58, 0x30, 0x30, 0xdb, 0x35, 0x94, + 0xc1, 0xa4, 0x24, 0xb1, 0x5f, 0x7c, 0x72, 0x66, 0x24, 0xec, + 0x26, 0xb3, 0x35, 0x3b, 0x10, 0xa9, 0x03, 0xa6, 0xd0, 0xab, + 0x1c, 0x4c ), + SCALAR ( 0xa5, 0x46, 0xe3, 0x6b, 0xf0, 0x52, 0x7c, 0x9d, 0x3b, 0x16, + 0x15, 0x4b, 0x82, 0x46, 0x5e, 0xdd, 0x62, 0x14, 0x4c, 0x0a, + 0xc1, 0xfc, 0x5a, 0x18, 0x50, 0x6a, 0x22, 0x44, 0xba, 0x44, + 0x9a, 0xc4 ), + EXPECTED ( 0xc3, 0xda, 0x55, 0x37, 0x9d, 0xe9, 0xc6, 0x90, 0x8e, 0x94, + 0xea, 0x4d, 0xf2, 0x8d, 0x08, 0x4f, 0x32, 0xec, 0xcf, 0x03, + 0x49, 0x1c, 0x71, 0xf7, 0x54, 0xb4, 0x07, 0x55, 0x77, 0xa2, + 0x85, 0x52 ) ); + +/* Base: 0xe5210f12786811d3f4b7959d0538ae2c31dbe7106fc03c3efc4cd549c715a493 + * Scalar: 0x4b66e9d4d1b4673c5ad22691957d6af5c11b6421e0ea01d42ca4169e7918ba0d + * Result: 0x95cbde9476e8907d7aade45cb4b873f88b595a68799fa152e6f8f7647aac7957 + */ +X25519_KEY_TEST ( rfc7748_2, 1, + BASE ( 0xe5, 0x21, 0x0f, 0x12, 0x78, 0x68, 0x11, 0xd3, 0xf4, 0xb7, + 0x95, 0x9d, 0x05, 0x38, 0xae, 0x2c, 0x31, 0xdb, 0xe7, 0x10, + 0x6f, 0xc0, 0x3c, 0x3e, 0xfc, 0x4c, 0xd5, 0x49, 0xc7, 0x15, + 0xa4, 0x93 ), + SCALAR ( 0x4b, 0x66, 0xe9, 0xd4, 0xd1, 0xb4, 0x67, 0x3c, 0x5a, 0xd2, + 0x26, 0x91, 0x95, 0x7d, 0x6a, 0xf5, 0xc1, 0x1b, 0x64, 0x21, + 0xe0, 0xea, 0x01, 0xd4, 0x2c, 0xa4, 0x16, 0x9e, 0x79, 0x18, + 0xba, 0x0d ), + EXPECTED ( 0x95, 0xcb, 0xde, 0x94, 0x76, 0xe8, 0x90, 0x7d, 0x7a, 0xad, + 0xe4, 0x5c, 0xb4, 0xb8, 0x73, 0xf8, 0x8b, 0x59, 0x5a, 0x68, + 0x79, 0x9f, 0xa1, 0x52, 0xe6, 0xf8, 0xf7, 0x64, 0x7a, 0xac, + 0x79, 0x57 ) ); + +/* Base: 0x0900000000000000000000000000000000000000000000000000000000000000 + * Scalar: 0x0900000000000000000000000000000000000000000000000000000000000000 + * Result: 0x422c8e7a6227d7bca1350b3e2bb7279f7897b87bb6854b783c60e80311ae3079 + */ +X25519_KEY_TEST ( rfc7748_3, 1, + BASE ( 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00 ), + SCALAR ( 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00 ), + EXPECTED ( 0x42, 0x2c, 0x8e, 0x7a, 0x62, 0x27, 0xd7, 0xbc, 0xa1, 0x35, + 0x0b, 0x3e, 0x2b, 0xb7, 0x27, 0x9f, 0x78, 0x97, 0xb8, 0x7b, + 0xb6, 0x85, 0x4b, 0x78, 0x3c, 0x60, 0xe8, 0x03, 0x11, 0xae, + 0x30, 0x79 ) ); + +/* Base: 0x0900000000000000000000000000000000000000000000000000000000000000 + * Scalar: 0x0900000000000000000000000000000000000000000000000000000000000000 + * Result: 0xb1a5a73158904c020866c13939dd7e1aa26852ee1d2609c92e5a8f1debe2150a + * (after 100 iterations) + * + * RFC7748 gives test vectors for 1000 and 1000000 iterations with + * these starting values. This test case stops after 100 iterations + * to avoid a pointlessly slow test cycle in the common case of + * running tests under Valgrind. + */ +X25519_KEY_TEST ( rfc7748_4_100, 100, + BASE ( 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00 ), + SCALAR ( 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00 ), + EXPECTED ( 0xb1, 0xa5, 0xa7, 0x31, 0x58, 0x90, 0x4c, 0x02, 0x08, 0x66, + 0xc1, 0x39, 0x39, 0xdd, 0x7e, 0x1a, 0xa2, 0x68, 0x52, 0xee, + 0x1d, 0x26, 0x09, 0xc9, 0x2e, 0x5a, 0x8f, 0x1d, 0xeb, 0xe2, + 0x15, 0x0a ) ); + +/** + * Perform X25519 self-tests + * + */ +static void x25519_test_exec ( void ) { + + /* Perform multiplication tests */ + x25519_multiply_ok ( &multiply_small ); + x25519_multiply_ok ( &multiply_k_p ); + x25519_multiply_ok ( &multiply_1 ); + x25519_multiply_ok ( &multiply_2 ); + x25519_multiply_ok ( &multiply_3 ); + x25519_multiply_ok ( &multiply_4 ); + x25519_multiply_ok ( &multiply_5 ); + + /* Perform multiplicative inversion tests */ + x25519_invert_ok ( &invert_1 ); + x25519_invert_ok ( &invert_2 ); + x25519_invert_ok ( &invert_3 ); + x25519_invert_ok ( &invert_4 ); + x25519_invert_ok ( &invert_5 ); + + /* Perform key exchange tests */ + x25519_key_ok ( &rfc7748_1 ); + x25519_key_ok ( &rfc7748_2 ); + x25519_key_ok ( &rfc7748_3 ); + x25519_key_ok ( &rfc7748_4_100 ); +} + +/** X25519 self-test */ +struct self_test x25519_test __self_test = { + .name = "x25519", + .exec = x25519_test_exec, +}; -- cgit v1.2.3-55-g7522 From de8a0821c7bc737e724fa3dfb6d89dc36f591d7a Mon Sep 17 00:00:00 2001 From: Joseph Wong Date: Thu, 18 Jan 2024 21:53:44 -0800 Subject: [bnxt] Add support for additional chip IDs Add additional chip IDs that can be recognized as part of the thor family. Signed-off-by: Michael Brown --- src/drivers/net/bnxt/bnxt.c | 4 +++- src/drivers/net/bnxt/bnxt.h | 4 +++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/drivers/net/bnxt/bnxt.c b/src/drivers/net/bnxt/bnxt.c index 605aea32..5dd21797 100644 --- a/src/drivers/net/bnxt/bnxt.c +++ b/src/drivers/net/bnxt/bnxt.c @@ -722,7 +722,9 @@ static int bnxt_hwrm_ver_get ( struct bnxt *bp ) ( resp->dev_caps_cfg & SHORT_CMD_REQUIRED ) ) FLAG_SET ( bp->flags, BNXT_FLAG_HWRM_SHORT_CMD_SUPP ); bp->hwrm_max_ext_req_len = resp->max_ext_req_len; - if ( bp->chip_num == CHIP_NUM_57500 ) + if ( ( bp->chip_num == CHIP_NUM_57508 ) || + ( bp->chip_num == CHIP_NUM_57504 ) || + ( bp->chip_num == CHIP_NUM_57502 ) ) bp->thor = 1; dbg_fw_ver ( resp, bp->hwrm_cmd_timeout ); return STATUS_SUCCESS; diff --git a/src/drivers/net/bnxt/bnxt.h b/src/drivers/net/bnxt/bnxt.h index 2cbaec5e..cf2dea8b 100644 --- a/src/drivers/net/bnxt/bnxt.h +++ b/src/drivers/net/bnxt/bnxt.h @@ -868,4 +868,6 @@ struct bnxt { FUNC_VF_CFG_REQ_ENABLES_ASYNC_EVENT_CR | \ FUNC_VF_CFG_REQ_ENABLES_DFLT_MAC_ADDR) -#define CHIP_NUM_57500 0x1750 +#define CHIP_NUM_57508 0x1750 +#define CHIP_NUM_57504 0x1751 +#define CHIP_NUM_57502 0x1752 -- cgit v1.2.3-55-g7522 From 27398f136030efb8845c45fbe154e544feefd7e5 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Tue, 30 Jan 2024 13:14:21 +0000 Subject: [crypto] Check for all-zeros result from X25519 key exchange RFC7748 states that it is entirely optional for X25519 Diffie-Hellman implementations to check whether or not the result is the all-zero value (indicating that an attacker sent a malicious public key with a small order). RFC8422 states that implementations in TLS must abort the handshake if the all-zero value is obtained. Return an error if the all-zero value is obtained, so that the TLS code will not require knowledge specific to the X25519 curve. Signed-off-by: Michael Brown --- src/crypto/x25519.c | 11 ++++++++--- src/include/ipxe/errfile.h | 1 + src/include/ipxe/x25519.h | 6 +++--- src/tests/x25519_test.c | 41 +++++++++++++++++++++++++++++++++++------ 4 files changed, 47 insertions(+), 12 deletions(-) diff --git a/src/crypto/x25519.c b/src/crypto/x25519.c index 750a2a71..d3a19bc8 100644 --- a/src/crypto/x25519.c +++ b/src/crypto/x25519.c @@ -59,6 +59,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #include #include #include +#include #include #include @@ -781,10 +782,11 @@ static void x25519_reverse ( struct x25519_value *value ) { * @v base Base point * @v scalar Scalar multiple * @v result Point to hold result (may overlap base point) + * @ret rc Return status code */ -void x25519_key ( const struct x25519_value *base, - const struct x25519_value *scalar, - struct x25519_value *result ) { +int x25519_key ( const struct x25519_value *base, + const struct x25519_value *scalar, + struct x25519_value *result ) { struct x25519_value *tmp = result; union x25519_quad257 point; @@ -805,4 +807,7 @@ void x25519_key ( const struct x25519_value *base, /* Reverse result */ bigint_done ( &point.value, result->raw, sizeof ( result->raw ) ); x25519_reverse ( result ); + + /* Fail if result was all zeros (as required by RFC8422) */ + return ( bigint_is_zero ( &point.value ) ? -EPERM : 0 ); } diff --git a/src/include/ipxe/errfile.h b/src/include/ipxe/errfile.h index 320835a3..060a42a3 100644 --- a/src/include/ipxe/errfile.h +++ b/src/include/ipxe/errfile.h @@ -407,6 +407,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #define ERRFILE_efi_rng ( ERRFILE_OTHER | 0x005c0000 ) #define ERRFILE_efi_shim ( ERRFILE_OTHER | 0x005d0000 ) #define ERRFILE_efi_settings ( ERRFILE_OTHER | 0x005e0000 ) +#define ERRFILE_x25519 ( ERRFILE_OTHER | 0x005f0000 ) /** @} */ diff --git a/src/include/ipxe/x25519.h b/src/include/ipxe/x25519.h index 7a86c113..6524abb7 100644 --- a/src/include/ipxe/x25519.h +++ b/src/include/ipxe/x25519.h @@ -84,8 +84,8 @@ extern void x25519_multiply ( const union x25519_oct258 *multiplicand, extern void x25519_invert ( const union x25519_oct258 *invertend, union x25519_quad257 *result ); extern void x25519_reduce ( union x25519_quad257 *value ); -extern void x25519_key ( const struct x25519_value *base, - const struct x25519_value *scalar, - struct x25519_value *result ); +extern int x25519_key ( const struct x25519_value *base, + const struct x25519_value *scalar, + struct x25519_value *result ); #endif /* _IPXE_X25519_H */ diff --git a/src/tests/x25519_test.c b/src/tests/x25519_test.c index 3d781f91..3dfbd339 100644 --- a/src/tests/x25519_test.c +++ b/src/tests/x25519_test.c @@ -136,6 +136,8 @@ struct x25519_key_test { struct x25519_value expected; /** Number of iterations */ unsigned int count; + /** Key exchange is expected to fail (i.e. produce all-zeroes) */ + int fail; }; /** @@ -143,14 +145,16 @@ struct x25519_key_test { * * @v name Test name * @v COUNT Number of iterations + * @v FAIL Expected failure status * @v BASE Base point * @v SCALAR Scalar multiple * @v EXPECTED Expected result * @ret test X25519 key exchange test */ -#define X25519_KEY_TEST( name, COUNT, BASE, SCALAR, EXPECTED ) \ +#define X25519_KEY_TEST( name, COUNT, FAIL, BASE, SCALAR, EXPECTED ) \ static struct x25519_key_test name = { \ .count = COUNT, \ + .fail = FAIL, \ .base = { .raw = BASE }, \ .scalar = { .raw = SCALAR }, \ .expected = { .raw = EXPECTED }, \ @@ -259,6 +263,7 @@ static void x25519_key_okx ( struct x25519_key_test *test, struct x25519_value scalar; struct x25519_value actual; unsigned int i; + int rc; /* Construct input values */ memcpy ( &base, &test->base, sizeof ( test->base ) ); @@ -272,7 +277,12 @@ static void x25519_key_okx ( struct x25519_key_test *test, /* Calculate key */ for ( i = 0 ; i < test->count ; i++ ) { - x25519_key ( &base, &scalar, &actual ); + rc = x25519_key ( &base, &scalar, &actual ); + if ( test->fail ) { + okx ( rc != 0, file, line ); + } else { + okx ( rc == 0, file, line ); + } memcpy ( &base, &scalar, sizeof ( base ) ); memcpy ( &scalar, &actual, sizeof ( scalar ) ); } @@ -461,7 +471,7 @@ X25519_INVERT_TEST ( invert_5, * Scalar: 0xa546e36bf0527c9d3b16154b82465edd62144c0ac1fc5a18506a2244ba449ac4 * Result: 0xc3da55379de9c6908e94ea4df28d084f32eccf03491c71f754b4075577a28552 */ -X25519_KEY_TEST ( rfc7748_1, 1, +X25519_KEY_TEST ( rfc7748_1, 1, 0, BASE ( 0xe6, 0xdb, 0x68, 0x67, 0x58, 0x30, 0x30, 0xdb, 0x35, 0x94, 0xc1, 0xa4, 0x24, 0xb1, 0x5f, 0x7c, 0x72, 0x66, 0x24, 0xec, 0x26, 0xb3, 0x35, 0x3b, 0x10, 0xa9, 0x03, 0xa6, 0xd0, 0xab, @@ -479,7 +489,7 @@ X25519_KEY_TEST ( rfc7748_1, 1, * Scalar: 0x4b66e9d4d1b4673c5ad22691957d6af5c11b6421e0ea01d42ca4169e7918ba0d * Result: 0x95cbde9476e8907d7aade45cb4b873f88b595a68799fa152e6f8f7647aac7957 */ -X25519_KEY_TEST ( rfc7748_2, 1, +X25519_KEY_TEST ( rfc7748_2, 1, 0, BASE ( 0xe5, 0x21, 0x0f, 0x12, 0x78, 0x68, 0x11, 0xd3, 0xf4, 0xb7, 0x95, 0x9d, 0x05, 0x38, 0xae, 0x2c, 0x31, 0xdb, 0xe7, 0x10, 0x6f, 0xc0, 0x3c, 0x3e, 0xfc, 0x4c, 0xd5, 0x49, 0xc7, 0x15, @@ -497,7 +507,7 @@ X25519_KEY_TEST ( rfc7748_2, 1, * Scalar: 0x0900000000000000000000000000000000000000000000000000000000000000 * Result: 0x422c8e7a6227d7bca1350b3e2bb7279f7897b87bb6854b783c60e80311ae3079 */ -X25519_KEY_TEST ( rfc7748_3, 1, +X25519_KEY_TEST ( rfc7748_3, 1, 0, BASE ( 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, @@ -521,7 +531,7 @@ X25519_KEY_TEST ( rfc7748_3, 1, * to avoid a pointlessly slow test cycle in the common case of * running tests under Valgrind. */ -X25519_KEY_TEST ( rfc7748_4_100, 100, +X25519_KEY_TEST ( rfc7748_4_100, 100, 0, BASE ( 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, @@ -535,6 +545,24 @@ X25519_KEY_TEST ( rfc7748_4_100, 100, 0x1d, 0x26, 0x09, 0xc9, 0x2e, 0x5a, 0x8f, 0x1d, 0xeb, 0xe2, 0x15, 0x0a ) ); +/* Base: 2^255 - 19 + 1 (deliberately malicious public key) + * Scalar: 0x000102030405060708090a0b0c0d0e0f000102030405060708090a0b0c0d0e0f + * Result: Failure (all zeros) + */ +X25519_KEY_TEST ( malicious, 1, 1, + BASE ( 0xee, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0x7f ), + SCALAR ( 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x01, 0x02, 0x03, + 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, + 0x0e, 0x0f ), + EXPECTED ( 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00 ) ); + /** * Perform X25519 self-tests * @@ -562,6 +590,7 @@ static void x25519_test_exec ( void ) { x25519_key_ok ( &rfc7748_2 ); x25519_key_ok ( &rfc7748_3 ); x25519_key_ok ( &rfc7748_4_100 ); + x25519_key_ok ( &malicious ); } /** X25519 self-test */ -- cgit v1.2.3-55-g7522 From 17135c83fb056f93fe70bdb09dd05ecc08963eed Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Tue, 30 Jan 2024 13:26:36 +0000 Subject: [crypto] Add an abstraction of an elliptic curve Define an abstraction of an elliptic curve with a fixed generator and one supported operation (scalar multiplication of a curve point). Signed-off-by: Michael Brown --- src/crypto/x25519.c | 31 +++++++++++++++++++++++++++++++ src/include/ipxe/crypto.h | 23 +++++++++++++++++++++++ src/include/ipxe/x25519.h | 3 +++ 3 files changed, 57 insertions(+) diff --git a/src/crypto/x25519.c b/src/crypto/x25519.c index d3a19bc8..d58f7168 100644 --- a/src/crypto/x25519.c +++ b/src/crypto/x25519.c @@ -61,6 +61,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #include #include #include +#include #include /** X25519 reduction constant @@ -300,6 +301,11 @@ static const uint8_t x25519_121665_raw[] = { 0x01, 0xdb, 0x41 }; /** Constant 121665 (used in the Montgomery ladder) */ static union x25519_oct258 x25519_121665; +/** Constant g=9 (the group generator) */ +static struct x25519_value x25519_generator = { + .raw = { 9, } +}; + /** * Initialise constants * @@ -811,3 +817,28 @@ int x25519_key ( const struct x25519_value *base, /* Fail if result was all zeros (as required by RFC8422) */ return ( bigint_is_zero ( &point.value ) ? -EPERM : 0 ); } + +/** + * Multiply scalar by curve point + * + * @v base Base point (or NULL to use generator) + * @v scalar Scalar multiple + * @v result Result point to fill in + * @ret rc Return status code + */ +static int x25519_curve_multiply ( const void *base, const void *scalar, + void *result ) { + + /* Use base point if applicable */ + if ( ! base ) + base = &x25519_generator; + + return x25519_key ( base, scalar, result ); +} + +/** X25519 elliptic curve */ +struct elliptic_curve x25519_curve = { + .name = "x25519", + .keysize = sizeof ( struct x25519_value ), + .multiply = x25519_curve_multiply, +}; diff --git a/src/include/ipxe/crypto.h b/src/include/ipxe/crypto.h index a15d5eba..9ee1c40c 100644 --- a/src/include/ipxe/crypto.h +++ b/src/include/ipxe/crypto.h @@ -195,6 +195,23 @@ struct pubkey_algorithm { const void *public_key, size_t public_key_len ); }; +/** An elliptic curve */ +struct elliptic_curve { + /** Curve name */ + const char *name; + /** Key size */ + size_t keysize; + /** Multiply scalar by curve point + * + * @v base Base point (or NULL to use generator) + * @v scalar Scalar multiple + * @v result Result point to fill in + * @ret rc Return status code + */ + int ( * multiply ) ( const void *base, const void *scalar, + void *result ); +}; + static inline void digest_init ( struct digest_algorithm *digest, void *ctx ) { digest->init ( ctx ); @@ -302,6 +319,12 @@ static inline int pubkey_match ( struct pubkey_algorithm *pubkey, public_key_len ); } +static inline int elliptic_multiply ( struct elliptic_curve *curve, + const void *base, const void *scalar, + void *result ) { + return curve->multiply ( base, scalar, result ); +} + extern void digest_null_init ( void *ctx ); extern void digest_null_update ( void *ctx, const void *src, size_t len ); extern void digest_null_final ( void *ctx, void *out ); diff --git a/src/include/ipxe/x25519.h b/src/include/ipxe/x25519.h index 6524abb7..fd7caeee 100644 --- a/src/include/ipxe/x25519.h +++ b/src/include/ipxe/x25519.h @@ -11,6 +11,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #include #include +#include /** X25519 unsigned big integer size * @@ -88,4 +89,6 @@ extern int x25519_key ( const struct x25519_value *base, const struct x25519_value *scalar, struct x25519_value *result ); +extern struct elliptic_curve x25519_curve; + #endif /* _IPXE_X25519_H */ -- cgit v1.2.3-55-g7522 From 6f70e8be834e3531c9e8910c619ce9ed377f2081 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Tue, 30 Jan 2024 13:38:15 +0000 Subject: [tls] Restructure construction of ClientHello message Define an individual local structure for each extension and a single structure for the list of extensions. This makes it viable to add extensions such as the Supported Elliptic Curves extension, which must not be present if the list of curves is empty. Signed-off-by: Michael Brown --- src/net/tls.c | 171 +++++++++++++++++++++++++++++++++------------------------- 1 file changed, 99 insertions(+), 72 deletions(-) diff --git a/src/net/tls.c b/src/net/tls.c index 000a8a78..7f31c8f7 100644 --- a/src/net/tls.c +++ b/src/net/tls.c @@ -1121,6 +1121,57 @@ static int tls_client_hello ( struct tls_connection *tls, size_t len ) ) { struct tls_session *session = tls->session; size_t name_len = strlen ( session->name ); + struct { + uint16_t type; + uint16_t len; + struct { + uint16_t len; + struct { + uint8_t type; + uint16_t len; + uint8_t name[name_len]; + } __attribute__ (( packed )) list[1]; + } __attribute__ (( packed )) data; + } __attribute__ (( packed )) *server_name_ext; + struct { + uint16_t type; + uint16_t len; + struct { + uint8_t max; + } __attribute__ (( packed )) data; + } __attribute__ (( packed )) *max_fragment_length_ext; + struct { + uint16_t type; + uint16_t len; + struct { + uint16_t len; + struct tls_signature_hash_id + code[TLS_NUM_SIG_HASH_ALGORITHMS]; + } __attribute__ (( packed )) data; + } __attribute__ (( packed )) *signature_algorithms_ext; + struct { + uint16_t type; + uint16_t len; + struct { + uint8_t len; + uint8_t data[ tls->secure_renegotiation ? + sizeof ( tls->verify.client ) :0 ]; + } __attribute__ (( packed )) data; + } __attribute__ (( packed )) *renegotiation_info_ext; + struct { + uint16_t type; + uint16_t len; + struct { + uint8_t data[session->ticket_len]; + } __attribute__ (( packed )) data; + } __attribute__ (( packed )) *session_ticket_ext; + struct { + typeof ( *server_name_ext ) server_name; + typeof ( *max_fragment_length_ext ) max_fragment_length; + typeof ( *signature_algorithms_ext ) signature_algorithms; + typeof ( *renegotiation_info_ext ) renegotiation_info; + typeof ( *session_ticket_ext ) session_ticket; + } __attribute__ (( packed )) *extensions; struct { uint32_t type_length; uint16_t version; @@ -1132,42 +1183,7 @@ static int tls_client_hello ( struct tls_connection *tls, uint8_t compression_methods_len; uint8_t compression_methods[1]; uint16_t extensions_len; - struct { - uint16_t server_name_type; - uint16_t server_name_len; - struct { - uint16_t len; - struct { - uint8_t type; - uint16_t len; - uint8_t name[name_len]; - } __attribute__ (( packed )) list[1]; - } __attribute__ (( packed )) server_name; - uint16_t max_fragment_length_type; - uint16_t max_fragment_length_len; - struct { - uint8_t max; - } __attribute__ (( packed )) max_fragment_length; - uint16_t signature_algorithms_type; - uint16_t signature_algorithms_len; - struct { - uint16_t len; - struct tls_signature_hash_id - code[TLS_NUM_SIG_HASH_ALGORITHMS]; - } __attribute__ (( packed )) signature_algorithms; - uint16_t renegotiation_info_type; - uint16_t renegotiation_info_len; - struct { - uint8_t len; - uint8_t data[ tls->secure_renegotiation ? - sizeof ( tls->verify.client ) :0]; - } __attribute__ (( packed )) renegotiation_info; - uint16_t session_ticket_type; - uint16_t session_ticket_len; - struct { - uint8_t data[session->ticket_len]; - } __attribute__ (( packed )) session_ticket; - } __attribute__ (( packed )) extensions; + typeof ( *extensions ) extensions; } __attribute__ (( packed )) hello; struct tls_cipher_suite *suite; struct tls_signature_hash_algorithm *sighash; @@ -1188,43 +1204,54 @@ static int tls_client_hello ( struct tls_connection *tls, hello.cipher_suites[i++] = suite->code; hello.compression_methods_len = sizeof ( hello.compression_methods ); hello.extensions_len = htons ( sizeof ( hello.extensions ) ); - hello.extensions.server_name_type = htons ( TLS_SERVER_NAME ); - hello.extensions.server_name_len - = htons ( sizeof ( hello.extensions.server_name ) ); - hello.extensions.server_name.len - = htons ( sizeof ( hello.extensions.server_name.list ) ); - hello.extensions.server_name.list[0].type = TLS_SERVER_NAME_HOST_NAME; - hello.extensions.server_name.list[0].len - = htons ( sizeof ( hello.extensions.server_name.list[0].name )); - memcpy ( hello.extensions.server_name.list[0].name, session->name, - sizeof ( hello.extensions.server_name.list[0].name ) ); - hello.extensions.max_fragment_length_type - = htons ( TLS_MAX_FRAGMENT_LENGTH ); - hello.extensions.max_fragment_length_len - = htons ( sizeof ( hello.extensions.max_fragment_length ) ); - hello.extensions.max_fragment_length.max - = TLS_MAX_FRAGMENT_LENGTH_4096; - hello.extensions.signature_algorithms_type - = htons ( TLS_SIGNATURE_ALGORITHMS ); - hello.extensions.signature_algorithms_len - = htons ( sizeof ( hello.extensions.signature_algorithms ) ); - hello.extensions.signature_algorithms.len - = htons ( sizeof ( hello.extensions.signature_algorithms.code)); + extensions = &hello.extensions; + + /* Construct server name extension */ + server_name_ext = &extensions->server_name; + server_name_ext->type = htons ( TLS_SERVER_NAME ); + server_name_ext->len = htons ( sizeof ( server_name_ext->data ) ); + server_name_ext->data.len + = htons ( sizeof ( server_name_ext->data.list ) ); + server_name_ext->data.list[0].type = TLS_SERVER_NAME_HOST_NAME; + server_name_ext->data.list[0].len + = htons ( sizeof ( server_name_ext->data.list[0].name ) ); + memcpy ( server_name_ext->data.list[0].name, session->name, + sizeof ( server_name_ext->data.list[0].name ) ); + + /* Construct maximum fragment length extension */ + max_fragment_length_ext = &extensions->max_fragment_length; + max_fragment_length_ext->type = htons ( TLS_MAX_FRAGMENT_LENGTH ); + max_fragment_length_ext->len + = htons ( sizeof ( max_fragment_length_ext->data ) ); + max_fragment_length_ext->data.max = TLS_MAX_FRAGMENT_LENGTH_4096; + + /* Construct supported signature algorithms extension */ + signature_algorithms_ext = &extensions->signature_algorithms; + signature_algorithms_ext->type = htons ( TLS_SIGNATURE_ALGORITHMS ); + signature_algorithms_ext->len + = htons ( sizeof ( signature_algorithms_ext->data ) ); + signature_algorithms_ext->data.len + = htons ( sizeof ( signature_algorithms_ext->data.code ) ); i = 0 ; for_each_table_entry ( sighash, TLS_SIG_HASH_ALGORITHMS ) - hello.extensions.signature_algorithms.code[i++] = sighash->code; - hello.extensions.renegotiation_info_type - = htons ( TLS_RENEGOTIATION_INFO ); - hello.extensions.renegotiation_info_len - = htons ( sizeof ( hello.extensions.renegotiation_info ) ); - hello.extensions.renegotiation_info.len - = sizeof ( hello.extensions.renegotiation_info.data ); - memcpy ( hello.extensions.renegotiation_info.data, tls->verify.client, - sizeof ( hello.extensions.renegotiation_info.data ) ); - hello.extensions.session_ticket_type = htons ( TLS_SESSION_TICKET ); - hello.extensions.session_ticket_len - = htons ( sizeof ( hello.extensions.session_ticket ) ); - memcpy ( hello.extensions.session_ticket.data, session->ticket, - sizeof ( hello.extensions.session_ticket.data ) ); + signature_algorithms_ext->data.code[i++] = sighash->code; + + /* Construct renegotiation information extension */ + renegotiation_info_ext = &extensions->renegotiation_info; + renegotiation_info_ext->type = htons ( TLS_RENEGOTIATION_INFO ); + renegotiation_info_ext->len + = htons ( sizeof ( renegotiation_info_ext->data ) ); + renegotiation_info_ext->data.len + = sizeof ( renegotiation_info_ext->data.data ); + memcpy ( renegotiation_info_ext->data.data, tls->verify.client, + sizeof ( renegotiation_info_ext->data.data ) ); + + /* Construct session ticket extension */ + session_ticket_ext = &extensions->session_ticket; + session_ticket_ext->type = htons ( TLS_SESSION_TICKET ); + session_ticket_ext->len + = htons ( sizeof ( session_ticket_ext->data ) ); + memcpy ( session_ticket_ext->data.data, session->ticket, + sizeof ( session_ticket_ext->data.data ) ); return action ( tls, &hello, sizeof ( hello ) ); } -- cgit v1.2.3-55-g7522 From 989dbe0bc4e63a5843e0c23fb1fd25ba8403bc40 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Tue, 30 Jan 2024 15:17:49 +0000 Subject: [tls] Generate key material after sending ClientKeyExchange The construction of the key material for the pending cipher suites from the TLS master secret must happen regardless of which key exchange algorithm is in use, and the key material is not required to send the ClientKeyExchange handshake (which is sent before changing cipher suites). Centralise the call to tls_generate_keys() after performing key exchange via the selected algorithm. Signed-off-by: Michael Brown --- src/net/tls.c | 31 +++++++++++++++---------------- 1 file changed, 15 insertions(+), 16 deletions(-) diff --git a/src/net/tls.c b/src/net/tls.c index 7f31c8f7..da16889f 100644 --- a/src/net/tls.c +++ b/src/net/tls.c @@ -1363,13 +1363,6 @@ static int tls_send_client_key_exchange_pubkey ( struct tls_connection *tls ) { tls_generate_master_secret ( tls, &pre_master_secret, sizeof ( pre_master_secret ) ); - /* Generate keys */ - if ( ( rc = tls_generate_keys ( tls ) ) != 0 ) { - DBGC ( tls, "TLS %p could not generate keys: %s\n", - tls, strerror ( rc ) ); - return rc; - } - /* Encrypt pre-master secret using server's public key */ memset ( &key_xchg, 0, sizeof ( key_xchg ) ); len = pubkey_encrypt ( pubkey, cipherspec->pubkey_ctx, @@ -1567,13 +1560,6 @@ static int tls_send_client_key_exchange_dhe ( struct tls_connection *tls ) { /* Generate master secret */ tls_generate_master_secret ( tls, pre_master_secret, len ); - /* Generate keys */ - if ( ( rc = tls_generate_keys ( tls ) ) != 0 ) { - DBGC ( tls, "TLS %p could not generate keys: %s\n", - tls, strerror ( rc ) ); - goto err_generate_keys; - } - /* Transmit Client Key Exchange record */ if ( ( rc = tls_send_handshake ( tls, key_xchg, sizeof ( *key_xchg ) ) ) !=0){ @@ -1581,7 +1567,6 @@ static int tls_send_client_key_exchange_dhe ( struct tls_connection *tls ) { } err_send_handshake: - err_generate_keys: err_dhe_key: free ( dynamic ); } @@ -1608,9 +1593,23 @@ struct tls_key_exchange_algorithm tls_dhe_exchange_algorithm = { static int tls_send_client_key_exchange ( struct tls_connection *tls ) { struct tls_cipherspec *cipherspec = &tls->tx_cipherspec_pending; struct tls_cipher_suite *suite = cipherspec->suite; + int rc; /* Transmit Client Key Exchange record via key exchange algorithm */ - return suite->exchange->exchange ( tls ); + if ( ( rc = suite->exchange->exchange ( tls ) ) != 0 ) { + DBGC ( tls, "TLS %p could not exchange keys: %s\n", + tls, strerror ( rc ) ); + return rc; + } + + /* Generate keys from master secret */ + if ( ( rc = tls_generate_keys ( tls ) ) != 0 ) { + DBGC ( tls, "TLS %p could not generate keys: %s\n", + tls, strerror ( rc ) ); + return rc; + } + + return 0; } /** -- cgit v1.2.3-55-g7522 From 8e2469c861fd25ac4956ca6b3bc3ed4ab8d74308 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Tue, 30 Jan 2024 15:23:39 +0000 Subject: [tls] Split out Diffie-Hellman parameter signature verification DHE and ECDHE use essentially the same mechanism for verifying the signature over the Diffie-Hellman parameters, though the format of the parameters is different between the two methods. Split out the verification of the parameter signature so that it may be shared between the DHE and ECDHE key exchange algorithms. Signed-off-by: Michael Brown --- src/net/tls.c | 101 +++++++++++++++++++++++++++++++++++----------------------- 1 file changed, 62 insertions(+), 39 deletions(-) diff --git a/src/net/tls.c b/src/net/tls.c index da16889f..66ab1e9c 100644 --- a/src/net/tls.c +++ b/src/net/tls.c @@ -1394,21 +1394,18 @@ struct tls_key_exchange_algorithm tls_pubkey_exchange_algorithm = { }; /** - * Transmit Client Key Exchange record using DHE key exchange + * Verify Diffie-Hellman parameter signature * * @v tls TLS connection + * @v param_len Diffie-Hellman parameter length * @ret rc Return status code */ -static int tls_send_client_key_exchange_dhe ( struct tls_connection *tls ) { +static int tls_verify_dh_params ( struct tls_connection *tls, + size_t param_len ) { struct tls_cipherspec *cipherspec = &tls->tx_cipherspec_pending; struct pubkey_algorithm *pubkey; struct digest_algorithm *digest; int use_sig_hash = tls_version ( tls, TLS_VERSION_TLS_1_2 ); - uint8_t private[ sizeof ( tls->client_random.random ) ]; - const struct { - uint16_t len; - uint8_t data[0]; - } __attribute__ (( packed )) *dh_val[3]; const struct { struct tls_signature_hash_id sig_hash[use_sig_hash]; uint16_t signature_len; @@ -1416,29 +1413,14 @@ static int tls_send_client_key_exchange_dhe ( struct tls_connection *tls ) { } __attribute__ (( packed )) *sig; const void *data; size_t remaining; - size_t frag_len; - unsigned int i; int rc; - /* Parse ServerKeyExchange */ - data = tls->server_key; - remaining = tls->server_key_len; - for ( i = 0 ; i < ( sizeof ( dh_val ) / sizeof ( dh_val[0] ) ) ; i++ ){ - dh_val[i] = data; - if ( ( sizeof ( *dh_val[i] ) > remaining ) || - ( ntohs ( dh_val[i]->len ) > ( remaining - - sizeof ( *dh_val[i] ) ) )){ - DBGC ( tls, "TLS %p received underlength " - "ServerKeyExchange\n", tls ); - DBGC_HDA ( tls, 0, tls->server_key, - tls->server_key_len ); - rc = -EINVAL_KEY_EXCHANGE; - goto err_header; - } - frag_len = ( sizeof ( *dh_val[i] ) + ntohs ( dh_val[i]->len )); - data += frag_len; - remaining -= frag_len; - } + /* Signature follows parameters */ + assert ( param_len <= tls->server_key_len ); + data = ( tls->server_key + param_len ); + remaining = ( tls->server_key_len - param_len ); + + /* Parse signature from ServerKeyExchange */ sig = data; if ( ( sizeof ( *sig ) > remaining ) || ( ntohs ( sig->signature_len ) > ( remaining - @@ -1446,8 +1428,7 @@ static int tls_send_client_key_exchange_dhe ( struct tls_connection *tls ) { DBGC ( tls, "TLS %p received underlength ServerKeyExchange\n", tls ); DBGC_HDA ( tls, 0, tls->server_key, tls->server_key_len ); - rc = -EINVAL_KEY_EXCHANGE; - goto err_header; + return -EINVAL_KEY_EXCHANGE; } /* Identify signature and hash algorithm */ @@ -1457,15 +1438,13 @@ static int tls_send_client_key_exchange_dhe ( struct tls_connection *tls ) { if ( ( ! pubkey ) || ( ! digest ) ) { DBGC ( tls, "TLS %p ServerKeyExchange unsupported " "signature and hash algorithm\n", tls ); - rc = -ENOTSUP_SIG_HASH; - goto err_sig_hash; + return -ENOTSUP_SIG_HASH; } if ( pubkey != cipherspec->suite->pubkey ) { DBGC ( tls, "TLS %p ServerKeyExchange incorrect " "signature algorithm %s (expected %s)\n", tls, pubkey->name, cipherspec->suite->pubkey->name ); - rc = -EPERM_KEY_EXCHANGE; - goto err_sig_hash; + return -EPERM_KEY_EXCHANGE; } } else { pubkey = cipherspec->suite->pubkey; @@ -1485,8 +1464,7 @@ static int tls_send_client_key_exchange_dhe ( struct tls_connection *tls ) { sizeof ( tls->client_random ) ); digest_update ( digest, ctx, tls->server_random, sizeof ( tls->server_random ) ); - digest_update ( digest, ctx, tls->server_key, - ( tls->server_key_len - remaining ) ); + digest_update ( digest, ctx, tls->server_key, param_len ); digest_final ( digest, ctx, hash ); /* Verify signature */ @@ -1497,11 +1475,57 @@ static int tls_send_client_key_exchange_dhe ( struct tls_connection *tls ) { "verification\n", tls ); DBGC_HDA ( tls, 0, tls->server_key, tls->server_key_len ); - rc = -EPERM_KEY_EXCHANGE; - goto err_verify; + return -EPERM_KEY_EXCHANGE; } } + return 0; +} + +/** + * Transmit Client Key Exchange record using DHE key exchange + * + * @v tls TLS connection + * @ret rc Return status code + */ +static int tls_send_client_key_exchange_dhe ( struct tls_connection *tls ) { + uint8_t private[ sizeof ( tls->client_random.random ) ]; + const struct { + uint16_t len; + uint8_t data[0]; + } __attribute__ (( packed )) *dh_val[3]; + const void *data; + size_t remaining; + size_t frag_len; + size_t param_len; + unsigned int i; + int rc; + + /* Parse ServerKeyExchange */ + data = tls->server_key; + remaining = tls->server_key_len; + for ( i = 0 ; i < ( sizeof ( dh_val ) / sizeof ( dh_val[0] ) ) ; i++ ){ + dh_val[i] = data; + if ( ( sizeof ( *dh_val[i] ) > remaining ) || + ( ntohs ( dh_val[i]->len ) > ( remaining - + sizeof ( *dh_val[i] ) ) )){ + DBGC ( tls, "TLS %p received underlength " + "ServerKeyExchange\n", tls ); + DBGC_HDA ( tls, 0, tls->server_key, + tls->server_key_len ); + rc = -EINVAL_KEY_EXCHANGE; + goto err_header; + } + frag_len = ( sizeof ( *dh_val[i] ) + ntohs ( dh_val[i]->len )); + data += frag_len; + remaining -= frag_len; + } + param_len = ( tls->server_key_len - remaining ); + + /* Verify parameter signature */ + if ( ( rc = tls_verify_dh_params ( tls, param_len ) ) != 0 ) + goto err_verify; + /* Generate Diffie-Hellman private key */ if ( ( rc = tls_generate_random ( tls, private, sizeof ( private ) ) ) != 0 ) { @@ -1573,7 +1597,6 @@ static int tls_send_client_key_exchange_dhe ( struct tls_connection *tls ) { err_alloc: err_random: err_verify: - err_sig_hash: err_header: return rc; } -- cgit v1.2.3-55-g7522 From b234226dbc4f348c7e4a5c61bdf7b0f8f0aef16c Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Tue, 30 Jan 2024 15:09:49 +0000 Subject: [tls] Add support for Ephemeral Elliptic Curve Diffie-Hellman key exchange Add support for the Ephemeral Elliptic Curve Diffie-Hellman (ECDHE) key exchange algorithm. Signed-off-by: Michael Brown --- src/include/ipxe/tls.h | 24 +++++++ src/net/tls.c | 169 +++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 193 insertions(+) diff --git a/src/include/ipxe/tls.h b/src/include/ipxe/tls.h index 30bb1c48..5c218f84 100644 --- a/src/include/ipxe/tls.h +++ b/src/include/ipxe/tls.h @@ -119,6 +119,10 @@ struct tls_header { #define TLS_MAX_FRAGMENT_LENGTH_2048 3 #define TLS_MAX_FRAGMENT_LENGTH_4096 4 +/* TLS named curve extension */ +#define TLS_NAMED_CURVE 10 +#define TLS_NAMED_CURVE_X25519 29 + /* TLS signature algorithms extension */ #define TLS_SIGNATURE_ALGORITHMS 13 @@ -205,6 +209,25 @@ struct tls_cipher_suite { #define __tls_cipher_suite( pref ) \ __table_entry ( TLS_CIPHER_SUITES, pref ) +/** TLS named curved type */ +#define TLS_NAMED_CURVE_TYPE 3 + +/** A TLS named curve */ +struct tls_named_curve { + /** Elliptic curve */ + struct elliptic_curve *curve; + /** Numeric code (in network-endian order) */ + uint16_t code; +}; + +/** TLS named curve table */ +#define TLS_NAMED_CURVES \ + __table ( struct tls_named_curve, "tls_named_curves" ) + +/** Declare a TLS named curve */ +#define __tls_named_curve( pref ) \ + __table_entry ( TLS_NAMED_CURVES, pref ) + /** A TLS cipher specification */ struct tls_cipherspec { /** Cipher suite */ @@ -425,6 +448,7 @@ struct tls_connection { extern struct tls_key_exchange_algorithm tls_pubkey_exchange_algorithm; extern struct tls_key_exchange_algorithm tls_dhe_exchange_algorithm; +extern struct tls_key_exchange_algorithm tls_ecdhe_exchange_algorithm; extern int add_tls ( struct interface *xfer, const char *name, struct x509_root *root, struct private_key *key ); diff --git a/src/net/tls.c b/src/net/tls.c index 66ab1e9c..58fad65e 100644 --- a/src/net/tls.c +++ b/src/net/tls.c @@ -158,6 +158,10 @@ FILE_LICENCE ( GPL2_OR_LATER ); #define EINFO_ENOTSUP_VERSION \ __einfo_uniqify ( EINFO_ENOTSUP, 0x04, \ "Unsupported protocol version" ) +#define ENOTSUP_CURVE __einfo_error ( EINFO_ENOTSUP_CURVE ) +#define EINFO_ENOTSUP_CURVE \ + __einfo_uniqify ( EINFO_ENOTSUP, 0x05, \ + "Unsupported elliptic curve" ) #define EPERM_ALERT __einfo_error ( EINFO_EPERM_ALERT ) #define EINFO_EPERM_ALERT \ __einfo_uniqify ( EINFO_EPERM, 0x01, \ @@ -1042,6 +1046,35 @@ tls_signature_hash_digest ( struct tls_signature_hash_id code ) { return NULL; } +/****************************************************************************** + * + * Ephemeral Elliptic Curve Diffie-Hellman key exchange + * + ****************************************************************************** + */ + +/** Number of supported named curves */ +#define TLS_NUM_NAMED_CURVES table_num_entries ( TLS_NAMED_CURVES ) + +/** + * Identify named curve + * + * @v named_curve Named curve specification + * @ret curve Named curve, or NULL + */ +static struct tls_named_curve * +tls_find_named_curve ( unsigned int named_curve ) { + struct tls_named_curve *curve; + + /* Identify named curve */ + for_each_table_entry ( curve, TLS_NAMED_CURVES ) { + if ( curve->code == named_curve ) + return curve; + } + + return NULL; +} + /****************************************************************************** * * Record handling @@ -1165,12 +1198,22 @@ static int tls_client_hello ( struct tls_connection *tls, uint8_t data[session->ticket_len]; } __attribute__ (( packed )) data; } __attribute__ (( packed )) *session_ticket_ext; + struct { + uint16_t type; + uint16_t len; + struct { + uint16_t len; + uint16_t code[TLS_NUM_NAMED_CURVES]; + } __attribute__ (( packed )) data; + } __attribute__ (( packed )) *named_curve_ext; struct { typeof ( *server_name_ext ) server_name; typeof ( *max_fragment_length_ext ) max_fragment_length; typeof ( *signature_algorithms_ext ) signature_algorithms; typeof ( *renegotiation_info_ext ) renegotiation_info; typeof ( *session_ticket_ext ) session_ticket; + typeof ( *named_curve_ext ) + named_curve[TLS_NUM_NAMED_CURVES ? 1 : 0]; } __attribute__ (( packed )) *extensions; struct { uint32_t type_length; @@ -1187,6 +1230,7 @@ static int tls_client_hello ( struct tls_connection *tls, } __attribute__ (( packed )) hello; struct tls_cipher_suite *suite; struct tls_signature_hash_algorithm *sighash; + struct tls_named_curve *curve; unsigned int i; /* Construct record */ @@ -1253,6 +1297,18 @@ static int tls_client_hello ( struct tls_connection *tls, memcpy ( session_ticket_ext->data.data, session->ticket, sizeof ( session_ticket_ext->data.data ) ); + /* Construct named curves extension, if applicable */ + if ( sizeof ( extensions->named_curve ) ) { + named_curve_ext = &extensions->named_curve[0]; + named_curve_ext->type = htons ( TLS_NAMED_CURVE ); + named_curve_ext->len + = htons ( sizeof ( named_curve_ext->data ) ); + named_curve_ext->data.len + = htons ( sizeof ( named_curve_ext->data.code ) ); + i = 0 ; for_each_table_entry ( curve, TLS_NAMED_CURVES ) + named_curve_ext->data.code[i++] = curve->code; + } + return action ( tls, &hello, sizeof ( hello ) ); } @@ -1607,6 +1663,119 @@ struct tls_key_exchange_algorithm tls_dhe_exchange_algorithm = { .exchange = tls_send_client_key_exchange_dhe, }; +/** + * Transmit Client Key Exchange record using ECDHE key exchange + * + * @v tls TLS connection + * @ret rc Return status code + */ +static int tls_send_client_key_exchange_ecdhe ( struct tls_connection *tls ) { + struct tls_named_curve *curve; + const struct { + uint8_t curve_type; + uint16_t named_curve; + uint8_t public_len; + uint8_t public[0]; + } __attribute__ (( packed )) *ecdh; + size_t param_len; + int rc; + + /* Parse ServerKeyExchange record */ + ecdh = tls->server_key; + if ( ( sizeof ( *ecdh ) > tls->server_key_len ) || + ( ecdh->public_len > ( tls->server_key_len - sizeof ( *ecdh ) ))){ + DBGC ( tls, "TLS %p received underlength ServerKeyExchange\n", + tls ); + DBGC_HDA ( tls, 0, tls->server_key, tls->server_key_len ); + return -EINVAL_KEY_EXCHANGE; + } + param_len = ( sizeof ( *ecdh ) + ecdh->public_len ); + + /* Verify parameter signature */ + if ( ( rc = tls_verify_dh_params ( tls, param_len ) ) != 0 ) + return rc; + + /* Identify named curve */ + if ( ecdh->curve_type != TLS_NAMED_CURVE_TYPE ) { + DBGC ( tls, "TLS %p unsupported curve type %d\n", + tls, ecdh->curve_type ); + DBGC_HDA ( tls, 0, tls->server_key, tls->server_key_len ); + return -ENOTSUP_CURVE; + } + curve = tls_find_named_curve ( ecdh->named_curve ); + if ( ! curve ) { + DBGC ( tls, "TLS %p unsupported named curve %d\n", + tls, ntohs ( ecdh->named_curve ) ); + DBGC_HDA ( tls, 0, tls->server_key, tls->server_key_len ); + return -ENOTSUP_CURVE; + } + + /* Check key length */ + if ( ecdh->public_len != curve->curve->keysize ) { + DBGC ( tls, "TLS %p invalid %s key\n", + tls, curve->curve->name ); + DBGC_HDA ( tls, 0, tls->server_key, tls->server_key_len ); + return -EINVAL_KEY_EXCHANGE; + } + + /* Construct pre-master secret and ClientKeyExchange record */ + { + size_t len = curve->curve->keysize; + uint8_t private[len]; + uint8_t pre_master_secret[len]; + struct { + uint32_t type_length; + uint8_t public_len; + uint8_t public[len]; + } __attribute__ (( packed )) key_xchg; + + /* Generate ephemeral private key */ + if ( ( rc = tls_generate_random ( tls, private, + sizeof ( private ) ) ) != 0){ + return rc; + } + + /* Calculate pre-master secret */ + if ( ( rc = elliptic_multiply ( curve->curve, + ecdh->public, private, + pre_master_secret ) ) != 0 ) { + DBGC ( tls, "TLS %p could not exchange ECDHE key: %s\n", + tls, strerror ( rc ) ); + return rc; + } + + /* Generate master secret */ + tls_generate_master_secret ( tls, pre_master_secret, len ); + + /* Generate Client Key Exchange record */ + key_xchg.type_length = + ( cpu_to_le32 ( TLS_CLIENT_KEY_EXCHANGE ) | + htonl ( sizeof ( key_xchg ) - + sizeof ( key_xchg.type_length ) ) ); + key_xchg.public_len = len; + if ( ( rc = elliptic_multiply ( curve->curve, NULL, private, + key_xchg.public ) ) != 0 ) { + DBGC ( tls, "TLS %p could not generate ECDHE key: %s\n", + tls, strerror ( rc ) ); + return rc; + } + + /* Transmit Client Key Exchange record */ + if ( ( rc = tls_send_handshake ( tls, &key_xchg, + sizeof ( key_xchg ) ) ) !=0){ + return rc; + } + } + + return 0; +} + +/** Ephemeral Elliptic Curve Diffie-Hellman key exchange algorithm */ +struct tls_key_exchange_algorithm tls_ecdhe_exchange_algorithm = { + .name = "ecdhe", + .exchange = tls_send_client_key_exchange_ecdhe, +}; + /** * Transmit Client Key Exchange record * -- cgit v1.2.3-55-g7522 From a881a26061a75bbca68a709eb40b396c4ef5656b Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Tue, 30 Jan 2024 18:00:31 +0000 Subject: [crypto] Add X25519 OID-identified algorithm and TLS named curve Signed-off-by: Michael Brown --- src/config/config_crypto.c | 5 +++++ src/config/crypto.h | 3 +++ src/crypto/mishmash/oid_x25519.c | 45 ++++++++++++++++++++++++++++++++++++++++ src/include/ipxe/asn1.h | 7 +++++++ 4 files changed, 60 insertions(+) create mode 100644 src/crypto/mishmash/oid_x25519.c diff --git a/src/config/config_crypto.c b/src/config/config_crypto.c index fa1996a5..72b70920 100644 --- a/src/config/config_crypto.c +++ b/src/config/config_crypto.c @@ -83,6 +83,11 @@ REQUIRE_OBJECT ( oid_sha512_224 ); REQUIRE_OBJECT ( oid_sha512_256 ); #endif +/* X25519 */ +#if defined ( CRYPTO_CURVE_X25519 ) +REQUIRE_OBJECT ( oid_x25519 ); +#endif + /* RSA and MD5 */ #if defined ( CRYPTO_PUBKEY_RSA ) && defined ( CRYPTO_DIGEST_MD5 ) REQUIRE_OBJECT ( rsa_md5 ); diff --git a/src/config/crypto.h b/src/config/crypto.h index 76bf14d4..637a06c0 100644 --- a/src/config/crypto.h +++ b/src/config/crypto.h @@ -48,6 +48,9 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); /** SHA-512/256 digest algorithm */ //#define CRYPTO_DIGEST_SHA512_256 +/** X25519 elliptic curve */ +#define CRYPTO_CURVE_X25519 + /** Margin of error (in seconds) allowed in signed timestamps * * We default to allowing a reasonable margin of error: 12 hours to diff --git a/src/crypto/mishmash/oid_x25519.c b/src/crypto/mishmash/oid_x25519.c new file mode 100644 index 00000000..2f8aa065 --- /dev/null +++ b/src/crypto/mishmash/oid_x25519.c @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2024 Michael Brown . + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + * + * You can also choose to distribute this program under the terms of + * the Unmodified Binary Distribution Licence (as given in the file + * COPYING.UBDL), provided that you have satisfied its requirements. + */ + +FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); + +#include +#include +#include +#include + +/** "x25519" object identifier */ +static uint8_t oid_x25519[] = { ASN1_OID_X25519 }; + +/** "x25519" OID-identified algorithm */ +struct asn1_algorithm x25519_algorithm __asn1_algorithm = { + .name = "x25519", + .curve = &x25519_curve, + .oid = ASN1_CURSOR ( oid_x25519 ), +}; + +/** X25519 named curve */ +struct tls_named_curve tls_x25519_named_curve __tls_named_curve ( 01 ) = { + .curve = &x25519_curve, + .code = htons ( TLS_NAMED_CURVE_X25519 ), +}; diff --git a/src/include/ipxe/asn1.h b/src/include/ipxe/asn1.h index 452fcef0..ac7ea560 100644 --- a/src/include/ipxe/asn1.h +++ b/src/include/ipxe/asn1.h @@ -187,6 +187,11 @@ struct asn1_builder_header { ASN1_OID_SINGLE ( 3 ), ASN1_OID_SINGLE ( 2 ), \ ASN1_OID_SINGLE ( 26 ) +/** ASN.1 OID for id-x25519 (1.3.101.110) */ +#define ASN1_OID_X25519 \ + ASN1_OID_INITIAL ( 1, 3 ), ASN1_OID_SINGLE ( 101 ), \ + ASN1_OID_SINGLE ( 110 ) + /** ASN.1 OID for id-sha256 (2.16.840.1.101.3.4.2.1) */ #define ASN1_OID_SHA256 \ ASN1_OID_INITIAL ( 2, 16 ), ASN1_OID_DOUBLE ( 840 ), \ @@ -312,6 +317,8 @@ struct asn1_algorithm { struct pubkey_algorithm *pubkey; /** Digest algorithm (if applicable) */ struct digest_algorithm *digest; + /** Elliptic curve (if applicable) */ + struct elliptic_curve *curve; }; /** ASN.1 OID-identified algorithms */ -- cgit v1.2.3-55-g7522 From 8f6a9399b3dc5af227cbd6185eff077b6e9d0e37 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Tue, 30 Jan 2024 16:48:46 +0000 Subject: [tls] Make key exchange algorithms selectable via build configuration Allow the choice of key exchange algorithms to be controlled via build configuration options in config/crypto.h, as is already done for the choices of public-key algorithms, cipher algorithms, and digest algorithms. Signed-off-by: Michael Brown --- src/config/config_crypto.c | 40 ++++++++++++++---- src/config/crypto.h | 6 +++ src/crypto/mishmash/dhe_rsa_aes_cbc_sha1.c | 61 ++++++++++++++++++++++++++++ src/crypto/mishmash/dhe_rsa_aes_cbc_sha256.c | 60 +++++++++++++++++++++++++++ src/crypto/mishmash/dhe_rsa_aes_gcm_sha256.c | 45 ++++++++++++++++++++ src/crypto/mishmash/dhe_rsa_aes_gcm_sha384.c | 45 ++++++++++++++++++++ src/crypto/mishmash/rsa_aes_cbc_sha1.c | 30 -------------- src/crypto/mishmash/rsa_aes_cbc_sha256.c | 30 -------------- src/crypto/mishmash/rsa_aes_gcm_sha256.c | 15 ------- src/crypto/mishmash/rsa_aes_gcm_sha384.c | 15 ------- 10 files changed, 249 insertions(+), 98 deletions(-) create mode 100644 src/crypto/mishmash/dhe_rsa_aes_cbc_sha1.c create mode 100644 src/crypto/mishmash/dhe_rsa_aes_cbc_sha256.c create mode 100644 src/crypto/mishmash/dhe_rsa_aes_gcm_sha256.c create mode 100644 src/crypto/mishmash/dhe_rsa_aes_gcm_sha384.c diff --git a/src/config/config_crypto.c b/src/config/config_crypto.c index 72b70920..efcd5af6 100644 --- a/src/config/config_crypto.c +++ b/src/config/config_crypto.c @@ -119,25 +119,49 @@ REQUIRE_OBJECT ( rsa_sha512 ); #endif /* RSA, AES-CBC, and SHA-1 */ -#if defined ( CRYPTO_PUBKEY_RSA ) && defined ( CRYPTO_CIPHER_AES_CBC ) && \ - defined ( CRYPTO_DIGEST_SHA1 ) +#if defined ( CRYPTO_EXCHANGE_PUBKEY ) && defined ( CRYPTO_PUBKEY_RSA ) && \ + defined ( CRYPTO_CIPHER_AES_CBC ) && defined ( CRYPTO_DIGEST_SHA1 ) REQUIRE_OBJECT ( rsa_aes_cbc_sha1 ); #endif /* RSA, AES-CBC, and SHA-256 */ -#if defined ( CRYPTO_PUBKEY_RSA ) && defined ( CRYPTO_CIPHER_AES_CBC ) && \ - defined ( CRYPTO_DIGEST_SHA256 ) +#if defined ( CRYPTO_EXCHANGE_PUBKEY ) && defined ( CRYPTO_PUBKEY_RSA ) && \ + defined ( CRYPTO_CIPHER_AES_CBC ) && defined ( CRYPTO_DIGEST_SHA256 ) REQUIRE_OBJECT ( rsa_aes_cbc_sha256 ); #endif /* RSA, AES-GCM, and SHA-256 */ -#if defined ( CRYPTO_PUBKEY_RSA ) && defined ( CRYPTO_CIPHER_AES_GCM ) && \ - defined ( CRYPTO_DIGEST_SHA256 ) +#if defined ( CRYPTO_EXCHANGE_PUBKEY ) && defined ( CRYPTO_PUBKEY_RSA ) && \ + defined ( CRYPTO_CIPHER_AES_GCM ) && defined ( CRYPTO_DIGEST_SHA256 ) REQUIRE_OBJECT ( rsa_aes_gcm_sha256 ); #endif /* RSA, AES-GCM, and SHA-384 */ -#if defined ( CRYPTO_PUBKEY_RSA ) && defined ( CRYPTO_CIPHER_AES_GCM ) && \ - defined ( CRYPTO_DIGEST_SHA384 ) +#if defined ( CRYPTO_EXCHANGE_PUBKEY ) && defined ( CRYPTO_PUBKEY_RSA ) && \ + defined ( CRYPTO_CIPHER_AES_GCM ) && defined ( CRYPTO_DIGEST_SHA384 ) REQUIRE_OBJECT ( rsa_aes_gcm_sha384 ); #endif + +/* DHE, RSA, AES-CBC, and SHA-1 */ +#if defined ( CRYPTO_EXCHANGE_DHE ) && defined ( CRYPTO_PUBKEY_RSA ) && \ + defined ( CRYPTO_CIPHER_AES_CBC ) && defined ( CRYPTO_DIGEST_SHA1 ) +REQUIRE_OBJECT ( dhe_rsa_aes_cbc_sha1 ); +#endif + +/* DHE, RSA, AES-CBC, and SHA-256 */ +#if defined ( CRYPTO_EXCHANGE_DHE ) && defined ( CRYPTO_PUBKEY_RSA ) && \ + defined ( CRYPTO_CIPHER_AES_CBC ) && defined ( CRYPTO_DIGEST_SHA256 ) +REQUIRE_OBJECT ( dhe_rsa_aes_cbc_sha256 ); +#endif + +/* DHE, RSA, AES-GCM, and SHA-256 */ +#if defined ( CRYPTO_EXCHANGE_DHE ) && defined ( CRYPTO_PUBKEY_RSA ) && \ + defined ( CRYPTO_CIPHER_AES_GCM ) && defined ( CRYPTO_DIGEST_SHA256 ) +REQUIRE_OBJECT ( dhe_rsa_aes_gcm_sha256 ); +#endif + +/* DHE, RSA, AES-GCM, and SHA-384 */ +#if defined ( CRYPTO_EXCHANGE_DHE ) && defined ( CRYPTO_PUBKEY_RSA ) && \ + defined ( CRYPTO_CIPHER_AES_GCM ) && defined ( CRYPTO_DIGEST_SHA384 ) +REQUIRE_OBJECT ( dhe_rsa_aes_gcm_sha384 ); +#endif diff --git a/src/config/crypto.h b/src/config/crypto.h index 637a06c0..ccf22df6 100644 --- a/src/config/crypto.h +++ b/src/config/crypto.h @@ -12,6 +12,12 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); /** Minimum TLS version */ #define TLS_VERSION_MIN TLS_VERSION_TLS_1_1 +/** Public-key exchange algorithm */ +#define CRYPTO_EXCHANGE_PUBKEY + +/** DHE key exchange algorithm */ +#define CRYPTO_EXCHANGE_DHE + /** RSA public-key algorithm */ #define CRYPTO_PUBKEY_RSA diff --git a/src/crypto/mishmash/dhe_rsa_aes_cbc_sha1.c b/src/crypto/mishmash/dhe_rsa_aes_cbc_sha1.c new file mode 100644 index 00000000..95a87f9a --- /dev/null +++ b/src/crypto/mishmash/dhe_rsa_aes_cbc_sha1.c @@ -0,0 +1,61 @@ +/* + * Copyright (C) 2015 Michael Brown . + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + * + * You can also choose to distribute this program under the terms of + * the Unmodified Binary Distribution Licence (as given in the file + * COPYING.UBDL), provided that you have satisfied its requirements. + */ + +FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); + +#include +#include +#include +#include +#include +#include + +/** TLS_DHE_RSA_WITH_AES_128_CBC_SHA cipher suite */ +struct tls_cipher_suite +tls_dhe_rsa_with_aes_128_cbc_sha __tls_cipher_suite ( 05 ) = { + .code = htons ( TLS_DHE_RSA_WITH_AES_128_CBC_SHA ), + .key_len = ( 128 / 8 ), + .fixed_iv_len = 0, + .record_iv_len = AES_BLOCKSIZE, + .mac_len = SHA1_DIGEST_SIZE, + .exchange = &tls_dhe_exchange_algorithm, + .pubkey = &rsa_algorithm, + .cipher = &aes_cbc_algorithm, + .digest = &sha1_algorithm, + .handshake = &sha256_algorithm, +}; + +/** TLS_DHE_RSA_WITH_AES_256_CBC_SHA cipher suite */ +struct tls_cipher_suite +tls_dhe_rsa_with_aes_256_cbc_sha __tls_cipher_suite ( 06 ) = { + .code = htons ( TLS_DHE_RSA_WITH_AES_256_CBC_SHA ), + .key_len = ( 256 / 8 ), + .fixed_iv_len = 0, + .record_iv_len = AES_BLOCKSIZE, + .mac_len = SHA1_DIGEST_SIZE, + .exchange = &tls_dhe_exchange_algorithm, + .pubkey = &rsa_algorithm, + .cipher = &aes_cbc_algorithm, + .digest = &sha1_algorithm, + .handshake = &sha256_algorithm, +}; diff --git a/src/crypto/mishmash/dhe_rsa_aes_cbc_sha256.c b/src/crypto/mishmash/dhe_rsa_aes_cbc_sha256.c new file mode 100644 index 00000000..b60dff42 --- /dev/null +++ b/src/crypto/mishmash/dhe_rsa_aes_cbc_sha256.c @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2015 Michael Brown . + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + * + * You can also choose to distribute this program under the terms of + * the Unmodified Binary Distribution Licence (as given in the file + * COPYING.UBDL), provided that you have satisfied its requirements. + */ + +FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); + +#include +#include +#include +#include +#include + +/** TLS_DHE_RSA_WITH_AES_128_CBC_SHA256 cipher suite */ +struct tls_cipher_suite +tls_dhe_rsa_with_aes_128_cbc_sha256 __tls_cipher_suite ( 03 ) = { + .code = htons ( TLS_DHE_RSA_WITH_AES_128_CBC_SHA256 ), + .key_len = ( 128 / 8 ), + .fixed_iv_len = 0, + .record_iv_len = AES_BLOCKSIZE, + .mac_len = SHA256_DIGEST_SIZE, + .exchange = &tls_dhe_exchange_algorithm, + .pubkey = &rsa_algorithm, + .cipher = &aes_cbc_algorithm, + .digest = &sha256_algorithm, + .handshake = &sha256_algorithm, +}; + +/** TLS_DHE_RSA_WITH_AES_256_CBC_SHA256 cipher suite */ +struct tls_cipher_suite +tls_dhe_rsa_with_aes_256_cbc_sha256 __tls_cipher_suite ( 04 ) = { + .code = htons ( TLS_DHE_RSA_WITH_AES_256_CBC_SHA256 ), + .key_len = ( 256 / 8 ), + .fixed_iv_len = 0, + .record_iv_len = AES_BLOCKSIZE, + .mac_len = SHA256_DIGEST_SIZE, + .exchange = &tls_dhe_exchange_algorithm, + .pubkey = &rsa_algorithm, + .cipher = &aes_cbc_algorithm, + .digest = &sha256_algorithm, + .handshake = &sha256_algorithm, +}; diff --git a/src/crypto/mishmash/dhe_rsa_aes_gcm_sha256.c b/src/crypto/mishmash/dhe_rsa_aes_gcm_sha256.c new file mode 100644 index 00000000..9d039509 --- /dev/null +++ b/src/crypto/mishmash/dhe_rsa_aes_gcm_sha256.c @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2022 Michael Brown . + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + * + * You can also choose to distribute this program under the terms of + * the Unmodified Binary Distribution Licence (as given in the file + * COPYING.UBDL), provided that you have satisfied its requirements. + */ + +FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); + +#include +#include +#include +#include +#include + +/** TLS_DHE_RSA_WITH_AES_128_GCM_SHA256 cipher suite */ +struct tls_cipher_suite +tls_dhe_rsa_with_aes_128_gcm_sha256 __tls_cipher_suite ( 01 ) = { + .code = htons ( TLS_DHE_RSA_WITH_AES_128_GCM_SHA256 ), + .key_len = ( 128 / 8 ), + .fixed_iv_len = 4, + .record_iv_len = 8, + .mac_len = 0, + .exchange = &tls_dhe_exchange_algorithm, + .pubkey = &rsa_algorithm, + .cipher = &aes_gcm_algorithm, + .digest = &sha256_algorithm, + .handshake = &sha256_algorithm, +}; diff --git a/src/crypto/mishmash/dhe_rsa_aes_gcm_sha384.c b/src/crypto/mishmash/dhe_rsa_aes_gcm_sha384.c new file mode 100644 index 00000000..6acd4b1d --- /dev/null +++ b/src/crypto/mishmash/dhe_rsa_aes_gcm_sha384.c @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2022 Michael Brown . + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + * + * You can also choose to distribute this program under the terms of + * the Unmodified Binary Distribution Licence (as given in the file + * COPYING.UBDL), provided that you have satisfied its requirements. + */ + +FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); + +#include +#include +#include +#include +#include + +/** TLS_DHE_RSA_WITH_AES_256_GCM_SHA384 cipher suite */ +struct tls_cipher_suite +tls_dhe_rsa_with_aes_256_gcm_sha384 __tls_cipher_suite ( 02 ) = { + .code = htons ( TLS_DHE_RSA_WITH_AES_256_GCM_SHA384 ), + .key_len = ( 256 / 8 ), + .fixed_iv_len = 4, + .record_iv_len = 8, + .mac_len = 0, + .exchange = &tls_dhe_exchange_algorithm, + .pubkey = &rsa_algorithm, + .cipher = &aes_gcm_algorithm, + .digest = &sha384_algorithm, + .handshake = &sha384_algorithm, +}; diff --git a/src/crypto/mishmash/rsa_aes_cbc_sha1.c b/src/crypto/mishmash/rsa_aes_cbc_sha1.c index 9f8193de..fccb04a9 100644 --- a/src/crypto/mishmash/rsa_aes_cbc_sha1.c +++ b/src/crypto/mishmash/rsa_aes_cbc_sha1.c @@ -30,36 +30,6 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #include #include -/** TLS_DHE_RSA_WITH_AES_128_CBC_SHA cipher suite */ -struct tls_cipher_suite -tls_dhe_rsa_with_aes_128_cbc_sha __tls_cipher_suite ( 05 ) = { - .code = htons ( TLS_DHE_RSA_WITH_AES_128_CBC_SHA ), - .key_len = ( 128 / 8 ), - .fixed_iv_len = 0, - .record_iv_len = AES_BLOCKSIZE, - .mac_len = SHA1_DIGEST_SIZE, - .exchange = &tls_dhe_exchange_algorithm, - .pubkey = &rsa_algorithm, - .cipher = &aes_cbc_algorithm, - .digest = &sha1_algorithm, - .handshake = &sha256_algorithm, -}; - -/** TLS_DHE_RSA_WITH_AES_256_CBC_SHA cipher suite */ -struct tls_cipher_suite -tls_dhe_rsa_with_aes_256_cbc_sha __tls_cipher_suite ( 06 ) = { - .code = htons ( TLS_DHE_RSA_WITH_AES_256_CBC_SHA ), - .key_len = ( 256 / 8 ), - .fixed_iv_len = 0, - .record_iv_len = AES_BLOCKSIZE, - .mac_len = SHA1_DIGEST_SIZE, - .exchange = &tls_dhe_exchange_algorithm, - .pubkey = &rsa_algorithm, - .cipher = &aes_cbc_algorithm, - .digest = &sha1_algorithm, - .handshake = &sha256_algorithm, -}; - /** TLS_RSA_WITH_AES_128_CBC_SHA cipher suite */ struct tls_cipher_suite tls_rsa_with_aes_128_cbc_sha __tls_cipher_suite ( 15 ) = { diff --git a/src/crypto/mishmash/rsa_aes_cbc_sha256.c b/src/crypto/mishmash/rsa_aes_cbc_sha256.c index d0dc8496..ac379b4b 100644 --- a/src/crypto/mishmash/rsa_aes_cbc_sha256.c +++ b/src/crypto/mishmash/rsa_aes_cbc_sha256.c @@ -29,36 +29,6 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #include #include -/** TLS_DHE_RSA_WITH_AES_128_CBC_SHA256 cipher suite */ -struct tls_cipher_suite -tls_dhe_rsa_with_aes_128_cbc_sha256 __tls_cipher_suite ( 03 ) = { - .code = htons ( TLS_DHE_RSA_WITH_AES_128_CBC_SHA256 ), - .key_len = ( 128 / 8 ), - .fixed_iv_len = 0, - .record_iv_len = AES_BLOCKSIZE, - .mac_len = SHA256_DIGEST_SIZE, - .exchange = &tls_dhe_exchange_algorithm, - .pubkey = &rsa_algorithm, - .cipher = &aes_cbc_algorithm, - .digest = &sha256_algorithm, - .handshake = &sha256_algorithm, -}; - -/** TLS_DHE_RSA_WITH_AES_256_CBC_SHA256 cipher suite */ -struct tls_cipher_suite -tls_dhe_rsa_with_aes_256_cbc_sha256 __tls_cipher_suite ( 04 ) = { - .code = htons ( TLS_DHE_RSA_WITH_AES_256_CBC_SHA256 ), - .key_len = ( 256 / 8 ), - .fixed_iv_len = 0, - .record_iv_len = AES_BLOCKSIZE, - .mac_len = SHA256_DIGEST_SIZE, - .exchange = &tls_dhe_exchange_algorithm, - .pubkey = &rsa_algorithm, - .cipher = &aes_cbc_algorithm, - .digest = &sha256_algorithm, - .handshake = &sha256_algorithm, -}; - /** TLS_RSA_WITH_AES_128_CBC_SHA256 cipher suite */ struct tls_cipher_suite tls_rsa_with_aes_128_cbc_sha256 __tls_cipher_suite ( 13 ) = { diff --git a/src/crypto/mishmash/rsa_aes_gcm_sha256.c b/src/crypto/mishmash/rsa_aes_gcm_sha256.c index cf9c4c27..e08deff8 100644 --- a/src/crypto/mishmash/rsa_aes_gcm_sha256.c +++ b/src/crypto/mishmash/rsa_aes_gcm_sha256.c @@ -29,21 +29,6 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #include #include -/** TLS_DHE_RSA_WITH_AES_128_GCM_SHA256 cipher suite */ -struct tls_cipher_suite -tls_dhe_rsa_with_aes_128_gcm_sha256 __tls_cipher_suite ( 01 ) = { - .code = htons ( TLS_DHE_RSA_WITH_AES_128_GCM_SHA256 ), - .key_len = ( 128 / 8 ), - .fixed_iv_len = 4, - .record_iv_len = 8, - .mac_len = 0, - .exchange = &tls_dhe_exchange_algorithm, - .pubkey = &rsa_algorithm, - .cipher = &aes_gcm_algorithm, - .digest = &sha256_algorithm, - .handshake = &sha256_algorithm, -}; - /** TLS_RSA_WITH_AES_128_GCM_SHA256 cipher suite */ struct tls_cipher_suite tls_rsa_with_aes_128_gcm_sha256 __tls_cipher_suite ( 11 ) = { diff --git a/src/crypto/mishmash/rsa_aes_gcm_sha384.c b/src/crypto/mishmash/rsa_aes_gcm_sha384.c index 10a977f7..0b307b42 100644 --- a/src/crypto/mishmash/rsa_aes_gcm_sha384.c +++ b/src/crypto/mishmash/rsa_aes_gcm_sha384.c @@ -29,21 +29,6 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #include #include -/** TLS_DHE_RSA_WITH_AES_256_GCM_SHA384 cipher suite */ -struct tls_cipher_suite -tls_dhe_rsa_with_aes_256_gcm_sha384 __tls_cipher_suite ( 02 ) = { - .code = htons ( TLS_DHE_RSA_WITH_AES_256_GCM_SHA384 ), - .key_len = ( 256 / 8 ), - .fixed_iv_len = 4, - .record_iv_len = 8, - .mac_len = 0, - .exchange = &tls_dhe_exchange_algorithm, - .pubkey = &rsa_algorithm, - .cipher = &aes_gcm_algorithm, - .digest = &sha384_algorithm, - .handshake = &sha384_algorithm, -}; - /** TLS_RSA_WITH_AES_256_GCM_SHA384 cipher suite */ struct tls_cipher_suite tls_rsa_with_aes_256_gcm_sha384 __tls_cipher_suite ( 12 ) = { -- cgit v1.2.3-55-g7522 From 963ec1c4f379a49cf37d01472a770fff8e47470c Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Tue, 30 Jan 2024 17:42:16 +0000 Subject: [tls] Add ECDHE cipher suites Add ECDHE variants of the existing cipher suites, and lower the priority of the non-ECDHE variants. Signed-off-by: Michael Brown --- src/config/config_crypto.c | 30 +++++++++++++ src/config/crypto.h | 3 ++ src/crypto/mishmash/dhe_rsa_aes_cbc_sha1.c | 4 +- src/crypto/mishmash/dhe_rsa_aes_cbc_sha256.c | 4 +- src/crypto/mishmash/dhe_rsa_aes_gcm_sha256.c | 2 +- src/crypto/mishmash/dhe_rsa_aes_gcm_sha384.c | 2 +- src/crypto/mishmash/ecdhe_rsa_aes_cbc_sha1.c | 61 ++++++++++++++++++++++++++ src/crypto/mishmash/ecdhe_rsa_aes_cbc_sha256.c | 45 +++++++++++++++++++ src/crypto/mishmash/ecdhe_rsa_aes_cbc_sha384.c | 45 +++++++++++++++++++ src/crypto/mishmash/ecdhe_rsa_aes_gcm_sha256.c | 45 +++++++++++++++++++ src/crypto/mishmash/ecdhe_rsa_aes_gcm_sha384.c | 45 +++++++++++++++++++ src/crypto/mishmash/rsa_aes_cbc_sha1.c | 4 +- src/crypto/mishmash/rsa_aes_cbc_sha256.c | 4 +- src/crypto/mishmash/rsa_aes_gcm_sha256.c | 2 +- src/crypto/mishmash/rsa_aes_gcm_sha384.c | 2 +- src/include/ipxe/tls.h | 6 +++ 16 files changed, 292 insertions(+), 12 deletions(-) create mode 100644 src/crypto/mishmash/ecdhe_rsa_aes_cbc_sha1.c create mode 100644 src/crypto/mishmash/ecdhe_rsa_aes_cbc_sha256.c create mode 100644 src/crypto/mishmash/ecdhe_rsa_aes_cbc_sha384.c create mode 100644 src/crypto/mishmash/ecdhe_rsa_aes_gcm_sha256.c create mode 100644 src/crypto/mishmash/ecdhe_rsa_aes_gcm_sha384.c diff --git a/src/config/config_crypto.c b/src/config/config_crypto.c index efcd5af6..5211224a 100644 --- a/src/config/config_crypto.c +++ b/src/config/config_crypto.c @@ -165,3 +165,33 @@ REQUIRE_OBJECT ( dhe_rsa_aes_gcm_sha256 ); defined ( CRYPTO_CIPHER_AES_GCM ) && defined ( CRYPTO_DIGEST_SHA384 ) REQUIRE_OBJECT ( dhe_rsa_aes_gcm_sha384 ); #endif + +/* ECDHE, RSA, AES-CBC, and SHA-1 */ +#if defined ( CRYPTO_EXCHANGE_ECDHE ) && defined ( CRYPTO_PUBKEY_RSA ) && \ + defined ( CRYPTO_CIPHER_AES_CBC ) && defined ( CRYPTO_DIGEST_SHA1 ) +REQUIRE_OBJECT ( ecdhe_rsa_aes_cbc_sha1 ); +#endif + +/* ECDHE, RSA, AES-CBC, and SHA-256 */ +#if defined ( CRYPTO_EXCHANGE_ECDHE ) && defined ( CRYPTO_PUBKEY_RSA ) && \ + defined ( CRYPTO_CIPHER_AES_CBC ) && defined ( CRYPTO_DIGEST_SHA256 ) +REQUIRE_OBJECT ( ecdhe_rsa_aes_cbc_sha256 ); +#endif + +/* ECDHE, RSA, AES-CBC, and SHA-384 */ +#if defined ( CRYPTO_EXCHANGE_ECDHE ) && defined ( CRYPTO_PUBKEY_RSA ) && \ + defined ( CRYPTO_CIPHER_AES_CBC ) && defined ( CRYPTO_DIGEST_SHA384 ) +REQUIRE_OBJECT ( ecdhe_rsa_aes_cbc_sha384 ); +#endif + +/* ECDHE, RSA, AES-GCM, and SHA-256 */ +#if defined ( CRYPTO_EXCHANGE_ECDHE ) && defined ( CRYPTO_PUBKEY_RSA ) && \ + defined ( CRYPTO_CIPHER_AES_GCM ) && defined ( CRYPTO_DIGEST_SHA256 ) +REQUIRE_OBJECT ( ecdhe_rsa_aes_gcm_sha256 ); +#endif + +/* ECDHE, RSA, AES-GCM, and SHA-384 */ +#if defined ( CRYPTO_EXCHANGE_ECDHE ) && defined ( CRYPTO_PUBKEY_RSA ) && \ + defined ( CRYPTO_CIPHER_AES_GCM ) && defined ( CRYPTO_DIGEST_SHA384 ) +REQUIRE_OBJECT ( ecdhe_rsa_aes_gcm_sha384 ); +#endif diff --git a/src/config/crypto.h b/src/config/crypto.h index ccf22df6..589c4f0d 100644 --- a/src/config/crypto.h +++ b/src/config/crypto.h @@ -18,6 +18,9 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); /** DHE key exchange algorithm */ #define CRYPTO_EXCHANGE_DHE +/** ECDHE key exchange algorithm */ +#define CRYPTO_EXCHANGE_ECDHE + /** RSA public-key algorithm */ #define CRYPTO_PUBKEY_RSA diff --git a/src/crypto/mishmash/dhe_rsa_aes_cbc_sha1.c b/src/crypto/mishmash/dhe_rsa_aes_cbc_sha1.c index 95a87f9a..05e409f7 100644 --- a/src/crypto/mishmash/dhe_rsa_aes_cbc_sha1.c +++ b/src/crypto/mishmash/dhe_rsa_aes_cbc_sha1.c @@ -32,7 +32,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); /** TLS_DHE_RSA_WITH_AES_128_CBC_SHA cipher suite */ struct tls_cipher_suite -tls_dhe_rsa_with_aes_128_cbc_sha __tls_cipher_suite ( 05 ) = { +tls_dhe_rsa_with_aes_128_cbc_sha __tls_cipher_suite ( 15 ) = { .code = htons ( TLS_DHE_RSA_WITH_AES_128_CBC_SHA ), .key_len = ( 128 / 8 ), .fixed_iv_len = 0, @@ -47,7 +47,7 @@ tls_dhe_rsa_with_aes_128_cbc_sha __tls_cipher_suite ( 05 ) = { /** TLS_DHE_RSA_WITH_AES_256_CBC_SHA cipher suite */ struct tls_cipher_suite -tls_dhe_rsa_with_aes_256_cbc_sha __tls_cipher_suite ( 06 ) = { +tls_dhe_rsa_with_aes_256_cbc_sha __tls_cipher_suite ( 16 ) = { .code = htons ( TLS_DHE_RSA_WITH_AES_256_CBC_SHA ), .key_len = ( 256 / 8 ), .fixed_iv_len = 0, diff --git a/src/crypto/mishmash/dhe_rsa_aes_cbc_sha256.c b/src/crypto/mishmash/dhe_rsa_aes_cbc_sha256.c index b60dff42..6ce42864 100644 --- a/src/crypto/mishmash/dhe_rsa_aes_cbc_sha256.c +++ b/src/crypto/mishmash/dhe_rsa_aes_cbc_sha256.c @@ -31,7 +31,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); /** TLS_DHE_RSA_WITH_AES_128_CBC_SHA256 cipher suite */ struct tls_cipher_suite -tls_dhe_rsa_with_aes_128_cbc_sha256 __tls_cipher_suite ( 03 ) = { +tls_dhe_rsa_with_aes_128_cbc_sha256 __tls_cipher_suite ( 13 ) = { .code = htons ( TLS_DHE_RSA_WITH_AES_128_CBC_SHA256 ), .key_len = ( 128 / 8 ), .fixed_iv_len = 0, @@ -46,7 +46,7 @@ tls_dhe_rsa_with_aes_128_cbc_sha256 __tls_cipher_suite ( 03 ) = { /** TLS_DHE_RSA_WITH_AES_256_CBC_SHA256 cipher suite */ struct tls_cipher_suite -tls_dhe_rsa_with_aes_256_cbc_sha256 __tls_cipher_suite ( 04 ) = { +tls_dhe_rsa_with_aes_256_cbc_sha256 __tls_cipher_suite ( 14 ) = { .code = htons ( TLS_DHE_RSA_WITH_AES_256_CBC_SHA256 ), .key_len = ( 256 / 8 ), .fixed_iv_len = 0, diff --git a/src/crypto/mishmash/dhe_rsa_aes_gcm_sha256.c b/src/crypto/mishmash/dhe_rsa_aes_gcm_sha256.c index 9d039509..dc5cad9f 100644 --- a/src/crypto/mishmash/dhe_rsa_aes_gcm_sha256.c +++ b/src/crypto/mishmash/dhe_rsa_aes_gcm_sha256.c @@ -31,7 +31,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); /** TLS_DHE_RSA_WITH_AES_128_GCM_SHA256 cipher suite */ struct tls_cipher_suite -tls_dhe_rsa_with_aes_128_gcm_sha256 __tls_cipher_suite ( 01 ) = { +tls_dhe_rsa_with_aes_128_gcm_sha256 __tls_cipher_suite ( 11 ) = { .code = htons ( TLS_DHE_RSA_WITH_AES_128_GCM_SHA256 ), .key_len = ( 128 / 8 ), .fixed_iv_len = 4, diff --git a/src/crypto/mishmash/dhe_rsa_aes_gcm_sha384.c b/src/crypto/mishmash/dhe_rsa_aes_gcm_sha384.c index 6acd4b1d..0448255f 100644 --- a/src/crypto/mishmash/dhe_rsa_aes_gcm_sha384.c +++ b/src/crypto/mishmash/dhe_rsa_aes_gcm_sha384.c @@ -31,7 +31,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); /** TLS_DHE_RSA_WITH_AES_256_GCM_SHA384 cipher suite */ struct tls_cipher_suite -tls_dhe_rsa_with_aes_256_gcm_sha384 __tls_cipher_suite ( 02 ) = { +tls_dhe_rsa_with_aes_256_gcm_sha384 __tls_cipher_suite ( 12 ) = { .code = htons ( TLS_DHE_RSA_WITH_AES_256_GCM_SHA384 ), .key_len = ( 256 / 8 ), .fixed_iv_len = 4, diff --git a/src/crypto/mishmash/ecdhe_rsa_aes_cbc_sha1.c b/src/crypto/mishmash/ecdhe_rsa_aes_cbc_sha1.c new file mode 100644 index 00000000..c23f65cc --- /dev/null +++ b/src/crypto/mishmash/ecdhe_rsa_aes_cbc_sha1.c @@ -0,0 +1,61 @@ +/* + * Copyright (C) 2024 Michael Brown . + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + * + * You can also choose to distribute this program under the terms of + * the Unmodified Binary Distribution Licence (as given in the file + * COPYING.UBDL), provided that you have satisfied its requirements. + */ + +FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); + +#include +#include +#include +#include +#include +#include + +/** TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA cipher suite */ +struct tls_cipher_suite +tls_ecdhe_rsa_with_aes_128_cbc_sha __tls_cipher_suite ( 05 ) = { + .code = htons ( TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA ), + .key_len = ( 128 / 8 ), + .fixed_iv_len = 0, + .record_iv_len = AES_BLOCKSIZE, + .mac_len = SHA1_DIGEST_SIZE, + .exchange = &tls_ecdhe_exchange_algorithm, + .pubkey = &rsa_algorithm, + .cipher = &aes_cbc_algorithm, + .digest = &sha1_algorithm, + .handshake = &sha256_algorithm, +}; + +/** TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA cipher suite */ +struct tls_cipher_suite +tls_ecdhe_rsa_with_aes_256_cbc_sha __tls_cipher_suite ( 06 ) = { + .code = htons ( TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA ), + .key_len = ( 256 / 8 ), + .fixed_iv_len = 0, + .record_iv_len = AES_BLOCKSIZE, + .mac_len = SHA1_DIGEST_SIZE, + .exchange = &tls_ecdhe_exchange_algorithm, + .pubkey = &rsa_algorithm, + .cipher = &aes_cbc_algorithm, + .digest = &sha1_algorithm, + .handshake = &sha256_algorithm, +}; diff --git a/src/crypto/mishmash/ecdhe_rsa_aes_cbc_sha256.c b/src/crypto/mishmash/ecdhe_rsa_aes_cbc_sha256.c new file mode 100644 index 00000000..431e2e30 --- /dev/null +++ b/src/crypto/mishmash/ecdhe_rsa_aes_cbc_sha256.c @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2024 Michael Brown . + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + * + * You can also choose to distribute this program under the terms of + * the Unmodified Binary Distribution Licence (as given in the file + * COPYING.UBDL), provided that you have satisfied its requirements. + */ + +FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); + +#include +#include +#include +#include +#include + +/** TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256 cipher suite */ +struct tls_cipher_suite +tls_ecdhe_rsa_with_aes_128_cbc_sha256 __tls_cipher_suite ( 03 ) = { + .code = htons ( TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256 ), + .key_len = ( 128 / 8 ), + .fixed_iv_len = 0, + .record_iv_len = AES_BLOCKSIZE, + .mac_len = SHA256_DIGEST_SIZE, + .exchange = &tls_ecdhe_exchange_algorithm, + .pubkey = &rsa_algorithm, + .cipher = &aes_cbc_algorithm, + .digest = &sha256_algorithm, + .handshake = &sha256_algorithm, +}; diff --git a/src/crypto/mishmash/ecdhe_rsa_aes_cbc_sha384.c b/src/crypto/mishmash/ecdhe_rsa_aes_cbc_sha384.c new file mode 100644 index 00000000..c5297680 --- /dev/null +++ b/src/crypto/mishmash/ecdhe_rsa_aes_cbc_sha384.c @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2024 Michael Brown . + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + * + * You can also choose to distribute this program under the terms of + * the Unmodified Binary Distribution Licence (as given in the file + * COPYING.UBDL), provided that you have satisfied its requirements. + */ + +FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); + +#include +#include +#include +#include +#include + +/** TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384 cipher suite */ +struct tls_cipher_suite +tls_ecdhe_rsa_with_aes_256_cbc_sha384 __tls_cipher_suite ( 04 ) = { + .code = htons ( TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384 ), + .key_len = ( 256 / 8 ), + .fixed_iv_len = 0, + .record_iv_len = AES_BLOCKSIZE, + .mac_len = SHA384_DIGEST_SIZE, + .exchange = &tls_ecdhe_exchange_algorithm, + .pubkey = &rsa_algorithm, + .cipher = &aes_cbc_algorithm, + .digest = &sha384_algorithm, + .handshake = &sha384_algorithm, +}; diff --git a/src/crypto/mishmash/ecdhe_rsa_aes_gcm_sha256.c b/src/crypto/mishmash/ecdhe_rsa_aes_gcm_sha256.c new file mode 100644 index 00000000..4f4e38c6 --- /dev/null +++ b/src/crypto/mishmash/ecdhe_rsa_aes_gcm_sha256.c @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2024 Michael Brown . + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + * + * You can also choose to distribute this program under the terms of + * the Unmodified Binary Distribution Licence (as given in the file + * COPYING.UBDL), provided that you have satisfied its requirements. + */ + +FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); + +#include +#include +#include +#include +#include + +/** TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 cipher suite */ +struct tls_cipher_suite +tls_ecdhe_rsa_with_aes_128_gcm_sha256 __tls_cipher_suite ( 01 ) = { + .code = htons ( TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 ), + .key_len = ( 128 / 8 ), + .fixed_iv_len = 4, + .record_iv_len = 8, + .mac_len = 0, + .exchange = &tls_ecdhe_exchange_algorithm, + .pubkey = &rsa_algorithm, + .cipher = &aes_gcm_algorithm, + .digest = &sha256_algorithm, + .handshake = &sha256_algorithm, +}; diff --git a/src/crypto/mishmash/ecdhe_rsa_aes_gcm_sha384.c b/src/crypto/mishmash/ecdhe_rsa_aes_gcm_sha384.c new file mode 100644 index 00000000..0bc7c305 --- /dev/null +++ b/src/crypto/mishmash/ecdhe_rsa_aes_gcm_sha384.c @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2024 Michael Brown . + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + * + * You can also choose to distribute this program under the terms of + * the Unmodified Binary Distribution Licence (as given in the file + * COPYING.UBDL), provided that you have satisfied its requirements. + */ + +FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); + +#include +#include +#include +#include +#include + +/** TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 cipher suite */ +struct tls_cipher_suite +tls_ecdhe_rsa_with_aes_256_gcm_sha384 __tls_cipher_suite ( 02 ) = { + .code = htons ( TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 ), + .key_len = ( 256 / 8 ), + .fixed_iv_len = 4, + .record_iv_len = 8, + .mac_len = 0, + .exchange = &tls_ecdhe_exchange_algorithm, + .pubkey = &rsa_algorithm, + .cipher = &aes_gcm_algorithm, + .digest = &sha384_algorithm, + .handshake = &sha384_algorithm, +}; diff --git a/src/crypto/mishmash/rsa_aes_cbc_sha1.c b/src/crypto/mishmash/rsa_aes_cbc_sha1.c index fccb04a9..0862fb5a 100644 --- a/src/crypto/mishmash/rsa_aes_cbc_sha1.c +++ b/src/crypto/mishmash/rsa_aes_cbc_sha1.c @@ -32,7 +32,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); /** TLS_RSA_WITH_AES_128_CBC_SHA cipher suite */ struct tls_cipher_suite -tls_rsa_with_aes_128_cbc_sha __tls_cipher_suite ( 15 ) = { +tls_rsa_with_aes_128_cbc_sha __tls_cipher_suite ( 25 ) = { .code = htons ( TLS_RSA_WITH_AES_128_CBC_SHA ), .key_len = ( 128 / 8 ), .fixed_iv_len = 0, @@ -47,7 +47,7 @@ tls_rsa_with_aes_128_cbc_sha __tls_cipher_suite ( 15 ) = { /** TLS_RSA_WITH_AES_256_CBC_SHA cipher suite */ struct tls_cipher_suite -tls_rsa_with_aes_256_cbc_sha __tls_cipher_suite ( 16 ) = { +tls_rsa_with_aes_256_cbc_sha __tls_cipher_suite ( 26 ) = { .code = htons ( TLS_RSA_WITH_AES_256_CBC_SHA ), .key_len = ( 256 / 8 ), .fixed_iv_len = 0, diff --git a/src/crypto/mishmash/rsa_aes_cbc_sha256.c b/src/crypto/mishmash/rsa_aes_cbc_sha256.c index ac379b4b..e5928db8 100644 --- a/src/crypto/mishmash/rsa_aes_cbc_sha256.c +++ b/src/crypto/mishmash/rsa_aes_cbc_sha256.c @@ -31,7 +31,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); /** TLS_RSA_WITH_AES_128_CBC_SHA256 cipher suite */ struct tls_cipher_suite -tls_rsa_with_aes_128_cbc_sha256 __tls_cipher_suite ( 13 ) = { +tls_rsa_with_aes_128_cbc_sha256 __tls_cipher_suite ( 23 ) = { .code = htons ( TLS_RSA_WITH_AES_128_CBC_SHA256 ), .key_len = ( 128 / 8 ), .fixed_iv_len = 0, @@ -46,7 +46,7 @@ tls_rsa_with_aes_128_cbc_sha256 __tls_cipher_suite ( 13 ) = { /** TLS_RSA_WITH_AES_256_CBC_SHA256 cipher suite */ struct tls_cipher_suite -tls_rsa_with_aes_256_cbc_sha256 __tls_cipher_suite ( 14 ) = { +tls_rsa_with_aes_256_cbc_sha256 __tls_cipher_suite ( 24 ) = { .code = htons ( TLS_RSA_WITH_AES_256_CBC_SHA256 ), .key_len = ( 256 / 8 ), .fixed_iv_len = 0, diff --git a/src/crypto/mishmash/rsa_aes_gcm_sha256.c b/src/crypto/mishmash/rsa_aes_gcm_sha256.c index e08deff8..b18bbd84 100644 --- a/src/crypto/mishmash/rsa_aes_gcm_sha256.c +++ b/src/crypto/mishmash/rsa_aes_gcm_sha256.c @@ -31,7 +31,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); /** TLS_RSA_WITH_AES_128_GCM_SHA256 cipher suite */ struct tls_cipher_suite -tls_rsa_with_aes_128_gcm_sha256 __tls_cipher_suite ( 11 ) = { +tls_rsa_with_aes_128_gcm_sha256 __tls_cipher_suite ( 21 ) = { .code = htons ( TLS_RSA_WITH_AES_128_GCM_SHA256 ), .key_len = ( 128 / 8 ), .fixed_iv_len = 4, diff --git a/src/crypto/mishmash/rsa_aes_gcm_sha384.c b/src/crypto/mishmash/rsa_aes_gcm_sha384.c index 0b307b42..06558aae 100644 --- a/src/crypto/mishmash/rsa_aes_gcm_sha384.c +++ b/src/crypto/mishmash/rsa_aes_gcm_sha384.c @@ -31,7 +31,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); /** TLS_RSA_WITH_AES_256_GCM_SHA384 cipher suite */ struct tls_cipher_suite -tls_rsa_with_aes_256_gcm_sha384 __tls_cipher_suite ( 12 ) = { +tls_rsa_with_aes_256_gcm_sha384 __tls_cipher_suite ( 22 ) = { .code = htons ( TLS_RSA_WITH_AES_256_GCM_SHA384 ), .key_len = ( 256 / 8 ), .fixed_iv_len = 4, diff --git a/src/include/ipxe/tls.h b/src/include/ipxe/tls.h index 5c218f84..cf327782 100644 --- a/src/include/ipxe/tls.h +++ b/src/include/ipxe/tls.h @@ -96,6 +96,12 @@ struct tls_header { #define TLS_RSA_WITH_AES_256_GCM_SHA384 0x009d #define TLS_DHE_RSA_WITH_AES_128_GCM_SHA256 0x009e #define TLS_DHE_RSA_WITH_AES_256_GCM_SHA384 0x009f +#define TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA 0xc013 +#define TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA 0xc014 +#define TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256 0xc027 +#define TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384 0xc028 +#define TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 0xc02f +#define TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 0xc030 /* TLS hash algorithm identifiers */ #define TLS_MD5_ALGORITHM 1 -- cgit v1.2.3-55-g7522 From 65d69d33da445afc7ff56857af1881cf73666be4 Mon Sep 17 00:00:00 2001 From: Ross Lagerwall Date: Tue, 30 Jan 2024 10:52:29 +0000 Subject: [efi] Fix hang during ExitBootServices() When ExitBootServices() invokes efi_shutdown_hook(), there may be nothing to generate an interrupt since the timer is disabled in the first step of ExitBootServices(). Additionally, for VMs OVMF masks everything from the PIC (except the timer) by default. This means that calling cpu_nap() may hang indefinitely. This was seen in practice in netfront_reset() when running in a VM on XenServer. Fix this by skipping the halt if an EFI shutdown is in progress. Signed-off-by: Ross Lagerwall Modified-by: Michael Brown Signed-off-by: Michael Brown --- src/arch/arm/interface/efi/efiarm_nap.c | 6 +++++- src/arch/loong64/interface/efi/efiloong64_nap.c | 6 +++++- src/arch/x86/interface/efi/efix86_nap.c | 6 +++++- 3 files changed, 15 insertions(+), 3 deletions(-) diff --git a/src/arch/arm/interface/efi/efiarm_nap.c b/src/arch/arm/interface/efi/efiarm_nap.c index 9ed638e9..fba7a5d8 100644 --- a/src/arch/arm/interface/efi/efiarm_nap.c +++ b/src/arch/arm/interface/efi/efiarm_nap.c @@ -46,8 +46,12 @@ static void efiarm_cpu_nap ( void ) { * The EFI shell doesn't seem to bother sleeping the CPU; it * just sits there idly burning power. * + * If a shutdown is in progess, there may be nothing to + * generate an interrupt since the timer is disabled in the + * first step of ExitBootServices(). */ - __asm__ __volatile__ ( "wfi" ); + if ( ! efi_shutdown_in_progress ) + __asm__ __volatile__ ( "wfi" ); } PROVIDE_NAP ( efiarm, cpu_nap, efiarm_cpu_nap ); diff --git a/src/arch/loong64/interface/efi/efiloong64_nap.c b/src/arch/loong64/interface/efi/efiloong64_nap.c index 5cd1c1b9..0a760978 100644 --- a/src/arch/loong64/interface/efi/efiloong64_nap.c +++ b/src/arch/loong64/interface/efi/efiloong64_nap.c @@ -46,8 +46,12 @@ static void efiloong64_cpu_nap ( void ) { * The EFI shell doesn't seem to bother sleeping the CPU; it * just sits there idly burning power. * + * If a shutdown is in progess, there may be nothing to + * generate an interrupt since the timer is disabled in the + * first step of ExitBootServices(). */ - __asm__ __volatile__ ( "idle 0" ); + if ( ! efi_shutdown_in_progress ) + __asm__ __volatile__ ( "idle 0" ); } PROVIDE_NAP ( efiloong64, cpu_nap, efiloong64_cpu_nap ); diff --git a/src/arch/x86/interface/efi/efix86_nap.c b/src/arch/x86/interface/efi/efix86_nap.c index 3ebf0bd6..296876b8 100644 --- a/src/arch/x86/interface/efi/efix86_nap.c +++ b/src/arch/x86/interface/efi/efix86_nap.c @@ -46,8 +46,12 @@ static void efix86_cpu_nap ( void ) { * The EFI shell doesn't seem to bother sleeping the CPU; it * just sits there idly burning power. * + * If a shutdown is in progess, there may be nothing to + * generate an interrupt since the timer is disabled in the + * first step of ExitBootServices(). */ - __asm__ __volatile__ ( "hlt" ); + if ( ! efi_shutdown_in_progress ) + __asm__ __volatile__ ( "hlt" ); } PROVIDE_NAP ( efix86, cpu_nap, efix86_cpu_nap ); -- cgit v1.2.3-55-g7522 From 0cc0f47443ef9711775a748c2b0fb40e38643733 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Wed, 31 Jan 2024 13:49:35 +0000 Subject: [tls] Tidy up error handling flow in tls_send_plaintext() Coverity reported that tls_send_plaintext() failed to check the return status from tls_generate_random(), which could potentially result in uninitialised random data being used as the block initialisation vector (instead of intentionally random data). Add the missing return status check, and separate out the error handling code paths (since on the successful exit code path there will be no need to free either the plaintext or the ciphertext anyway). Signed-off-by: Michael Brown --- src/net/tls.c | 30 ++++++++++++++++++++---------- 1 file changed, 20 insertions(+), 10 deletions(-) diff --git a/src/net/tls.c b/src/net/tls.c index 58fad65e..5f89be45 100644 --- a/src/net/tls.c +++ b/src/net/tls.c @@ -2945,9 +2945,9 @@ static int tls_send_plaintext ( struct tls_connection *tls, unsigned int type, } __attribute__ (( packed )) iv; struct tls_auth_header authhdr; struct tls_header *tlshdr; - void *plaintext = NULL; - size_t plaintext_len = len; - struct io_buffer *ciphertext = NULL; + void *plaintext; + size_t plaintext_len; + struct io_buffer *ciphertext; size_t ciphertext_len; size_t padding_len; uint8_t mac[digest->digestsize]; @@ -2956,7 +2956,10 @@ static int tls_send_plaintext ( struct tls_connection *tls, unsigned int type, /* Construct initialisation vector */ memcpy ( iv.fixed, cipherspec->fixed_iv, sizeof ( iv.fixed ) ); - tls_generate_random ( tls, iv.record, sizeof ( iv.record ) ); + if ( ( rc = tls_generate_random ( tls, iv.record, + sizeof ( iv.record ) ) ) != 0 ) { + goto err_random; + } /* Construct authentication data */ authhdr.seq = cpu_to_be64 ( tls->tx_seq ); @@ -2965,7 +2968,7 @@ static int tls_send_plaintext ( struct tls_connection *tls, unsigned int type, authhdr.header.length = htons ( len ); /* Calculate padding length */ - plaintext_len += suite->mac_len; + plaintext_len = ( len + suite->mac_len ); if ( is_block_cipher ( cipher ) ) { padding_len = ( ( ( cipher->blocksize - 1 ) & -( plaintext_len + 1 ) ) + 1 ); @@ -2980,7 +2983,7 @@ static int tls_send_plaintext ( struct tls_connection *tls, unsigned int type, DBGC ( tls, "TLS %p could not allocate %zd bytes for " "plaintext\n", tls, plaintext_len ); rc = -ENOMEM_TX_PLAINTEXT; - goto done; + goto err_plaintext; } /* Assemble plaintext */ @@ -3014,7 +3017,7 @@ static int tls_send_plaintext ( struct tls_connection *tls, unsigned int type, DBGC ( tls, "TLS %p could not allocate %zd bytes for " "ciphertext\n", tls, ciphertext_len ); rc = -ENOMEM_TX_CIPHERTEXT; - goto done; + goto err_ciphertext; } /* Assemble ciphertext */ @@ -3039,15 +3042,22 @@ static int tls_send_plaintext ( struct tls_connection *tls, unsigned int type, iob_disown ( ciphertext ) ) ) != 0 ) { DBGC ( tls, "TLS %p could not deliver ciphertext: %s\n", tls, strerror ( rc ) ); - goto done; + goto err_deliver; } /* Update TX state machine to next record */ tls->tx_seq += 1; - done: - free ( plaintext ); + assert ( plaintext == NULL ); + assert ( ciphertext == NULL ); + return 0; + + err_deliver: free_iob ( ciphertext ); + err_ciphertext: + free ( plaintext ); + err_plaintext: + err_random: return rc; } -- cgit v1.2.3-55-g7522 From 36a27b22b1c4a587e66cc1eff1193f6c8c927b05 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Fri, 2 Feb 2024 17:09:06 +0000 Subject: [crypto] Fix stray references to AES The CBC_CIPHER() macro contains some accidentally hardcoded references to an underlying AES cipher, instead of using the cipher specified in the macro parameters. Fix by using the macro parameter as required. Signed-off-by: Michael Brown --- src/include/ipxe/cbc.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/include/ipxe/cbc.h b/src/include/ipxe/cbc.h index 382fc903..f02e5193 100644 --- a/src/include/ipxe/cbc.h +++ b/src/include/ipxe/cbc.h @@ -77,19 +77,19 @@ static void _cbc_name ## _setiv ( void *ctx, const void *iv, \ size_t ivlen ) { \ struct _cbc_name ## _context * _cbc_name ## _ctx = ctx; \ cbc_setiv ( &_cbc_name ## _ctx->raw_ctx, iv, ivlen, \ - &_raw_cipher, &aes_cbc_ctx->cbc_ctx ); \ + &_raw_cipher, &_cbc_name ## _ctx->cbc_ctx ); \ } \ static void _cbc_name ## _encrypt ( void *ctx, const void *src, \ void *dst, size_t len ) { \ struct _cbc_name ## _context * _cbc_name ## _ctx = ctx; \ cbc_encrypt ( &_cbc_name ## _ctx->raw_ctx, src, dst, len, \ - &_raw_cipher, &aes_cbc_ctx->cbc_ctx ); \ + &_raw_cipher, &_cbc_name ## _ctx->cbc_ctx ); \ } \ static void _cbc_name ## _decrypt ( void *ctx, const void *src, \ void *dst, size_t len ) { \ struct _cbc_name ## _context * _cbc_name ## _ctx = ctx; \ cbc_decrypt ( &_cbc_name ## _ctx->raw_ctx, src, dst, len, \ - &_raw_cipher, &aes_cbc_ctx->cbc_ctx ); \ + &_raw_cipher, &_cbc_name ## _ctx->cbc_ctx ); \ } \ struct cipher_algorithm _cbc_cipher = { \ .name = #_cbc_name, \ -- cgit v1.2.3-55-g7522 From af4583b214bfe98df82d6645387d6c78fd698d7f Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Wed, 7 Feb 2024 21:16:47 +0000 Subject: [test] Remove dummy initialisation vector for ECB-mode AES tests A block cipher in ECB mode has no concept of an initialisation vector, and any data provided to cipher_setiv() for an ECB cipher will be ignored. There is no requirement within our cipher algorithm abstraction for a dummy initialisation vector to be provided. Remove the entirely spurious dummy 16-byte initialisation vector from the ECB test cases. Signed-off-by: Michael Brown --- src/tests/aes_test.c | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/src/tests/aes_test.c b/src/tests/aes_test.c index be119c8d..46a052a2 100644 --- a/src/tests/aes_test.c +++ b/src/tests/aes_test.c @@ -63,11 +63,6 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); 0x2c, 0x07, 0x3b, 0x61, 0x08, 0xd7, 0x2d, 0x98, 0x10, \ 0xa3, 0x09, 0x14, 0xdf, 0xf4 ) -/** Dummy initialisation vector used for NIST ECB-mode test vectors */ -#define AES_IV_NIST_DUMMY \ - IV ( 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 ) - /** Initialisation vector used for NIST CBC-mode test vectors */ #define AES_IV_NIST_CBC \ IV ( 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, \ @@ -86,7 +81,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); /** AES-128-ECB (same test as AES-128-Core) */ CIPHER_TEST ( aes_128_ecb, &aes_ecb_algorithm, - AES_KEY_NIST_128, AES_IV_NIST_DUMMY, ADDITIONAL(), AES_PLAINTEXT_NIST, + AES_KEY_NIST_128, IV(), ADDITIONAL(), AES_PLAINTEXT_NIST, CIPHERTEXT ( 0x3a, 0xd7, 0x7b, 0xb4, 0x0d, 0x7a, 0x36, 0x60, 0xa8, 0x9e, 0xca, 0xf3, 0x24, 0x66, 0xef, 0x97, 0xf5, 0xd3, 0xd5, 0x85, 0x03, 0xb9, 0x69, 0x9d, @@ -110,7 +105,7 @@ CIPHER_TEST ( aes_128_cbc, &aes_cbc_algorithm, /** AES-192-ECB (same test as AES-192-Core) */ CIPHER_TEST ( aes_192_ecb, &aes_ecb_algorithm, - AES_KEY_NIST_192, AES_IV_NIST_DUMMY, ADDITIONAL(), AES_PLAINTEXT_NIST, + AES_KEY_NIST_192, IV(), ADDITIONAL(), AES_PLAINTEXT_NIST, CIPHERTEXT ( 0xbd, 0x33, 0x4f, 0x1d, 0x6e, 0x45, 0xf2, 0x5f, 0xf7, 0x12, 0xa2, 0x14, 0x57, 0x1f, 0xa5, 0xcc, 0x97, 0x41, 0x04, 0x84, 0x6d, 0x0a, 0xd3, 0xad, @@ -134,7 +129,7 @@ CIPHER_TEST ( aes_192_cbc, &aes_cbc_algorithm, /** AES-256-ECB (same test as AES-256-Core) */ CIPHER_TEST ( aes_256_ecb, &aes_ecb_algorithm, - AES_KEY_NIST_256, AES_IV_NIST_DUMMY, ADDITIONAL(), AES_PLAINTEXT_NIST, + AES_KEY_NIST_256, IV(), ADDITIONAL(), AES_PLAINTEXT_NIST, CIPHERTEXT ( 0xf3, 0xee, 0xd1, 0xbd, 0xb5, 0xd2, 0xa0, 0x3c, 0x06, 0x4b, 0x5a, 0x7e, 0x3d, 0xb1, 0x81, 0xf8, 0x59, 0x1c, 0xcb, 0x10, 0xd4, 0x10, 0xed, 0x26, -- cgit v1.2.3-55-g7522 From e7ae51b0d75d9b9925748743b91405c99e5c7fec Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Wed, 7 Feb 2024 21:20:20 +0000 Subject: [crypto] Add implementation of the DES cipher The DES block cipher dates back to the 1970s. It is no longer relevant for use in TLS cipher suites, but it is still used by the MS-CHAPv2 authentication protocol which remains unfortunately common for 802.1x port authentication. Add an implementation of the DES block cipher, complete with the extremely comprehensive test vectors published by NBS (the precursor to NIST) in the form of an utterly adorable typewritten and hand-drawn paper document. Signed-off-by: Michael Brown --- src/crypto/des.c | 695 +++++++++++++++++++++++++++++++++++ src/include/ipxe/des.h | 91 +++++ src/include/ipxe/errfile.h | 1 + src/tests/des_test.c | 898 +++++++++++++++++++++++++++++++++++++++++++++ src/tests/tests.c | 1 + 5 files changed, 1686 insertions(+) create mode 100644 src/crypto/des.c create mode 100644 src/include/ipxe/des.h create mode 100644 src/tests/des_test.c diff --git a/src/crypto/des.c b/src/crypto/des.c new file mode 100644 index 00000000..6918bec3 --- /dev/null +++ b/src/crypto/des.c @@ -0,0 +1,695 @@ +/* + * Copyright (C) 2024 Michael Brown . + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + * + * You can also choose to distribute this program under the terms of + * the Unmodified Binary Distribution Licence (as given in the file + * COPYING.UBDL), provided that you have satisfied its requirements. + */ + +FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); + +/** @file + * + * DES algorithm + * + * DES was not designed to be implemented in software, and therefore + * contains a large number of bit permutation operations that are + * essentially free in hardware (requiring only wires, no gates) but + * expensive in software. + * + * Since DES is no longer used as a practical block cipher for large + * volumes of data, we optimise for code size, and do not attempt to + * obtain fast throughput. + * + * The algorithm is specified in NIST SP 800-67, downloadable from + * https://nvlpubs.nist.gov/nistpubs/SpecialPublications/NIST.SP.800-67r2.pdf + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/** + * DES shift schedule + * + * The DES shift schedule (ordered from round 16 down to round 1) is + * {1,2,2,2,2,2,2,1,2,2,2,2,2,2,1,1}. In binary, this may be + * represented as {1,10,10,10,10,10,10,1,10,10,10,10,10,10,1,1} and + * concatenated (without padding) to produce a single binary integer + * 1101010101010110101010101011 (equal to 0x0d556aab in hexadecimal). + * + * This integer may then be consumed LSB-first, where a 1 bit + * indicates a shift and the generation of a round key, and a 0 bit + * indicates a shift without the generation of a round key. + */ +#define DES_SCHEDULE 0x0d556aab + +/** + * Define an element pair in a DES S-box + * + * @v x Upper element of element pair + * @v y Lower element of element pair + * + * DES S-box elements are 4-bit values. We encode two values per + * byte, ordering the elements so that the six-bit input value may be + * used directly as a lookup index. + * + * Specifically, if the input value is {r1,c3,c2,c1,c0,r0}, where + * {r1,r0} is the table row index and {c3,c2,c1,c0} is the table + * column index (as used in the DES specification), then: + * + * - {r1,c3,c2,c1,c0} is the byte index into the table + * + * - (4*r0) is the required bit shift to extract the 4-bit value + */ +#define SBYTE( x, y ) ( ( (y) << 4 ) | (x) ) + +/** + * Define a row pair in a DES S-box + * + * @v x0..xf Upper row of row pair + * @v y0..yf Lower row of row pair + */ +#define SBOX( x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, xa, xb, xc, xd, xe, xf, \ + y0, y1, y2, y3, y4, y5, y6, y7, y8, y9, ya, yb, yc, yd, ye, yf ) \ + SBYTE ( x0, y0 ), SBYTE ( x1, y1 ), SBYTE ( x2, y2 ), SBYTE ( x3, y3 ),\ + SBYTE ( x4, y4 ), SBYTE ( x5, y5 ), SBYTE ( x6, y6 ), SBYTE ( x7, y7 ),\ + SBYTE ( x8, y8 ), SBYTE ( x9, y9 ), SBYTE ( xa, ya ), SBYTE ( xb, yb ),\ + SBYTE ( xc, yc ), SBYTE ( xd, yd ), SBYTE ( xe, ye ), SBYTE ( xf, yf ) + +/** DES S-boxes S1..S8 */ +static const uint8_t des_s[8][32] = { { + /* S1 */ + SBOX ( 14, 4, 13, 1, 2, 15, 11, 8, 3, 10, 6, 12, 5, 9, 0, 7, + 0, 15, 7, 4, 14, 2, 13, 1, 10, 6, 12, 11, 9, 5, 3, 8 ), + SBOX ( 4, 1, 14, 8, 13, 6, 2, 11, 15, 12, 9, 7, 3, 10, 5, 0, + 15, 12, 8, 2, 4, 9, 1, 7, 5, 11, 3, 14, 10, 0, 6, 13 ) +}, { + /* S2 */ + SBOX ( 15, 1, 8, 14, 6, 11, 3, 4, 9, 7, 2, 13, 12, 0, 5, 10, + 3, 13, 4, 7, 15, 2, 8, 14, 12, 0, 1, 10, 6, 9, 11, 5 ), + SBOX ( 0, 14, 7, 11, 10, 4, 13, 1, 5, 8, 12, 6, 9, 3, 2, 15, + 13, 8, 10, 1, 3, 15, 4, 2, 11, 6, 7, 12, 0, 5, 14, 9 ) +}, { + /* S3 */ + SBOX ( 10, 0, 9, 14, 6, 3, 15, 5, 1, 13, 12, 7, 11, 4, 2, 8, + 13, 7, 0, 9, 3, 4, 6, 10, 2, 8, 5, 14, 12, 11, 15, 1 ), + SBOX ( 13, 6, 4, 9, 8, 15, 3, 0, 11, 1, 2, 12, 5, 10, 14, 7, + 1, 10, 13, 0, 6, 9, 8, 7, 4, 15, 14, 3, 11, 5, 2, 12 ) +}, { + /* S4 */ + SBOX ( 7, 13, 14, 3, 0, 6, 9, 10, 1, 2, 8, 5, 11, 12, 4, 15, + 13, 8, 11, 5, 6, 15, 0, 3, 4, 7, 2, 12, 1, 10, 14, 9 ), + SBOX ( 10, 6, 9, 0, 12, 11, 7, 13, 15, 1, 3, 14, 5, 2, 8, 4, + 3, 15, 0, 6, 10, 1, 13, 8, 9, 4, 5, 11, 12, 7, 2, 14 ) +}, { + /* S5 */ + SBOX ( 2, 12, 4, 1, 7, 10, 11, 6, 8, 5, 3, 15, 13, 0, 14, 9, + 14, 11, 2, 12, 4, 7, 13, 1, 5, 0, 15, 10, 3, 9, 8, 6 ), + SBOX ( 4, 2, 1, 11, 10, 13, 7, 8, 15, 9, 12, 5, 6, 3, 0, 14, + 11, 8, 12, 7, 1, 14, 2, 13, 6, 15, 0, 9, 10, 4, 5, 3 ) +}, { + /* S6 */ + SBOX ( 12, 1, 10, 15, 9, 2, 6, 8, 0, 13, 3, 4, 14, 7, 5, 11, + 10, 15, 4, 2, 7, 12, 9, 5, 6, 1, 13, 14, 0, 11, 3, 8 ), + SBOX ( 9, 14, 15, 5, 2, 8, 12, 3, 7, 0, 4, 10, 1, 13, 11, 6, + 4, 3, 2, 12, 9, 5, 15, 10, 11, 14, 1, 7, 6, 0, 8, 13 ) +}, { + /* S7 */ + SBOX ( 4, 11, 2, 14, 15, 0, 8, 13, 3, 12, 9, 7, 5, 10, 6, 1, + 13, 0, 11, 7, 4, 9, 1, 10, 14, 3, 5, 12, 2, 15, 8, 6 ), + SBOX ( 1, 4, 11, 13, 12, 3, 7, 14, 10, 15, 6, 8, 0, 5, 9, 2, + 6, 11, 13, 8, 1, 4, 10, 7, 9, 5, 0, 15, 14, 2, 3, 12 ) +}, { + /* S8 */ + SBOX ( 13, 2, 8, 4, 6, 15, 11, 1, 10, 9, 3, 14, 5, 0, 12, 7, + 1, 15, 13, 8, 10, 3, 7, 4, 12, 5, 6, 11, 0, 14, 9, 2 ), + SBOX ( 7, 11, 4, 1, 9, 12, 14, 2, 0, 6, 10, 13, 15, 3, 5, 8, + 2, 1, 14, 7, 4, 10, 8, 13, 15, 12, 9, 0, 3, 5, 6, 11 ) +} }; + +/** + * Define a bit index within permuted choice 2 (PC2) + * + * @v bit Bit index + * + * Permuted choice 2 (PC2) is used to select bits from a concatenated + * pair of 28-bit registers ("C" and "D") as part of the key schedule. + * We store these as 32-bit registers and so must add 4 to indexes + * above 28. + */ +#define DES_PC2( x ) ( (x) + ( ( (x) > 28 ) ? 4 : 0 ) ) + +/** + * Define six bits of permuted choice 2 (PC2) + * + * @v r1:r0 Bits corresponding to S-box row index + * @v c3:c0 Bits corresponding to S-box column index + * + * There are 8 steps within a DES round (one step per S-box). Each + * step requires six bits of the round key, corresponding to the S-box + * input value {r1,c3,c2,c1,c0,r0}, where {r1,r0} is the table row + * index and {c3,c2,c1,c0} is the table column index. + * + * As an optimisation, we store the least significant of the 6 bits in + * the sign bit of a signed 8-bit value, and the remaining 5 bits in + * the least significant 5 bits of the 8-bit value. See the comments + * in des_sbox() for further details. + */ +#define DES_PC2R( r1, c3, c2, c1, c0, r0 ) \ + DES_PC2 ( r0 ), /* LSB stored in sign bit */ \ + DES_PC2 ( r0 ), /* Unused bit */ \ + DES_PC2 ( r0 ), /* Unused bit */ \ + DES_PC2 ( r1 ), /* Remaining 5 bits */ \ + DES_PC2 ( c3 ), /* ... */ \ + DES_PC2 ( c2 ), /* ... */ \ + DES_PC2 ( c1 ), /* ... */ \ + DES_PC2 ( c0 ) /* ... */ + +/** + * A DES systematic permutation generator + * + * Many of the permutations used in DES comprise systematic bit + * patterns. We generate these permutations at runtime to save on + * code size. + */ +struct des_generator { + /** Permutation */ + uint8_t *permutation; + /** Seed value */ + uint32_t seed; +}; + +/** + * Define a DES permutation generator + * + * @v PERMUTATION Permutation + * @v OFFSET Fixed input bit offset (0 or 1) + * @v INV Input bit index bit should be inverted + * @v BIT Source bit for input bit index bit + * @ret generator Permutation generator + */ +#define DES_GENERATOR( PERMUTATION, OFFSET, INV5, BIT5, INV4, BIT4, \ + INV3, BIT3, INV2, BIT2, INV1, BIT1, INV0, BIT0 ) \ + { \ + .permutation = (PERMUTATION), \ + .seed = ( ( (INV0) << 31 ) | ( (BIT0) << 28 ) | \ + ( (INV1) << 27 ) | ( (BIT1) << 24 ) | \ + ( (INV2) << 23 ) | ( (BIT2) << 20 ) | \ + ( (INV3) << 19 ) | ( (BIT3) << 16 ) | \ + ( (INV4) << 15 ) | ( (BIT4) << 12 ) | \ + ( (INV5) << 11 ) | ( (BIT5) << 8 ) | \ + ( ( uint32_t ) sizeof (PERMUTATION) - 1 ) | \ + (OFFSET) ), \ + } + +/** DES permuted choice 1 (PC1) "C" register */ +static uint8_t des_pc1c[29]; + +/** DES permuted choice 1 (PC1) "D" register */ +static uint8_t des_pc1d[33]; + +/** DES permuted choice 2 (PC2) */ +static const uint8_t des_pc2[65] = { + DES_PC2R ( 14, 17, 11, 24, 1, 5 ), + DES_PC2R ( 3, 28, 15, 6, 21, 10 ), + DES_PC2R ( 23, 19, 12, 4, 26, 8 ), + DES_PC2R ( 16, 7, 27, 20, 13, 2 ), + DES_PC2R ( 41, 52, 31, 37, 47, 55 ), + DES_PC2R ( 30, 40, 51, 45, 33, 48 ), + DES_PC2R ( 44, 49, 39, 56, 34, 53 ), + DES_PC2R ( 46, 42, 50, 36, 29, 32 ), + 0 /* terminator */ +}; + +/** DES initial permutation (IP) */ +static uint8_t des_ip[65]; + +/** DES data permutation (P) */ +static const uint8_t des_p[33] = { + 16, 7, 20, 21, 29, 12, 28, 17, 1, 15, 23, 26, 5, 18, 31, 10, + 2, 8, 24, 14, 32, 27, 3, 9, 19, 13, 30, 6, 22, 11, 4, 25, + 0 /* terminator */ +}; + +/** DES final / inverse initial permutation (FP / IP^-1) */ +static uint8_t des_fp[65]; + +/** DES permutation generators */ +static struct des_generator des_generators[] = { + + /* The DES initial permutation transforms the bit index + * {x5,x4,x3,x2,x1,x0}+1 into {~x2,~x1,~x0,x4,x3,~x5}+1 + */ + DES_GENERATOR ( des_ip, 1, 1, 2, 1, 1, 1, 0, 0, 4, 0, 3, 1, 5 ), + + /* The DES final permutation transforms the bit index + * {x5,x4,x3,x2,x1,x0}+1 into {~x0,x2,x1,~x5,~x4,~x3}+1 + * + * There is an asymmetry in the DES block diagram for the last + * of the 16 rounds, which is functionally equivalent to + * performing 16 identical rounds and then swapping the left + * and right halves before applying the final permutation. We + * may therefore account for this asymmetry by inverting the + * MSB in each bit index, to point to the corresponding bit in + * the other half. + * + * This is equivalent to using a permutation that transforms + * {x5,x4,x3,x2,x1,x0}+1 into {x0,x2,x1,~x5,~x4,~x3}+1 + */ + DES_GENERATOR ( des_fp, 1, 0, 0, 0, 2, 0, 1, 1, 5, 1, 4, 1, 3 ), + + /* The "C" half of DES permuted choice 1 (PC1) transforms the + * bit index {x5,x4,x3,x2,x1,x0}+1 into {~x2,~x1,~x0,x5,x4,x3}+1 + */ + DES_GENERATOR ( des_pc1c, 1, 1, 2, 1, 1, 1, 0, 0, 5, 0, 4, 0, 3 ), + + /* The "D" half of DES permuted choice 1 (PC1) transforms the + * bit index {x5,x4,x3,x2,x1,x0}+1 into {~x2,~x1,~x0,~x5,~x4,~x3}+0 + * + * Due to the idosyncratic design choice of using 28-bit + * registers in the DES key expansion schedule, the final four + * permutation values appear at indices [28:31] instead of + * [24:27]. This is adjusted for in @c des_setkey(). + */ + DES_GENERATOR ( des_pc1d, 0, 1, 2, 1, 1, 1, 0, 1, 5, 1, 4, 1, 3 ), +}; + +/** + * Generate DES permutation + * + * @v generator Generator + */ +static __attribute__ (( noinline )) void +des_generate ( struct des_generator *generator ) { + uint8_t *permutation = generator->permutation; + uint32_t seed = generator->seed; + unsigned int index = 0; + uint8_t accum; + uint8_t bit; + + /* Generate permutations + * + * This loop is optimised for code size on a + * register-constrained architecture such as i386. + */ + do { + /* Rotate seed to access MSB's bit descriptor */ + seed = ror32 ( seed, 8 ); + + /* Initialise accumulator with six flag bits */ + accum = 0xfc; + + /* Accumulate bits until all six flag bits are cleared */ + do { + /* Extract specified bit from index. Use a + * rotation instead of a shift, since this + * will allow the mask to be elided. + */ + bit = ror8 ( index, ( seed & 0x07 ) ); + seed = ror32 ( seed, 3 ); + + /* Toggle bit if applicable */ + bit ^= seed; + seed = ror32 ( seed, 1 ); + + /* Add bit to accumulator and clear one flag bit */ + accum <<= 1; + accum |= ( bit & 0x01 ); + + } while ( accum & 0x80 ); + + /* Add constant offset if applicable */ + accum += ( seed & 0x01 ); + + /* Store permutation */ + permutation[index] = accum; + + /* Loop until reaching length (which is always even) */ + } while ( ++index < ( seed & 0xfe ) ); + DBGC2 ( permutation, "DES generated permutation %p:\n", permutation ); + DBGC2_HDA ( permutation, 0, permutation, + ( ( seed & 0xfe ) + 1 /* zero terminator */ ) ); +} + +/** + * Initialise permutations + */ +static void des_init ( void ) { + unsigned int i; + + /* Generate all generated permutations */ + for ( i = 0 ; i < ( sizeof ( des_generators ) / + sizeof ( des_generators[0] ) ) ; i++ ) { + des_generate ( &des_generators[i] ); + } +} + +/** Initialisation function */ +struct init_fn des_init_fn __init_fn ( INIT_NORMAL ) = { + .initialise = des_init, +}; + +/** + * Perform bit permutation + * + * @v permutation Bit permutation (zero-terminated) + * @v in Input value + * @v out Output value + */ +static void des_permute ( const uint8_t *permutation, const uint8_t *in, + uint8_t *out ) { + uint8_t mask = 0x80; + uint8_t accum = 0; + unsigned int bit; + + /* Extract individual input bits to construct output value */ + while ( ( bit = *(permutation++) ) ) { + bit--; + if ( in[ bit / 8 ] & ( 0x80 >> ( bit % 8 ) ) ) + accum |= mask; + *out = accum; + mask = ror8 ( mask, 1 ); + if ( mask == 0x80 ) { + out++; + accum = 0; + } + } +} + +/** + * Perform DES S-box substitution + * + * @v in 32-bit input value (native endian) + * @v rkey 48-bit round key + * @ret out 32-bit output value (native endian) + */ +static uint32_t des_sbox ( uint32_t in, const union des_round_key *rkey ) { + uint32_t out = 0; + uint32_t lookup; + int32_t key; + uint8_t sub; + unsigned int i; + + /* Perform input expansion, key addition, and S-box substitution */ + for ( i = 0 ; i < 8 ; i++ ) { + + /* Rotate input and output */ + out = rol32 ( out, 4 ); + in = rol32 ( in, 4 ); + + /* Extract step key from relevant 6 bits of round key + * + * The least significant of the 6 bits (corresponding + * to bit r0 in the S-box lookup index) is stored in + * the sign bit of the step key byte. It will + * therefore be propagated via sign extension to the + * MSB of the 32-bit step key. + * + * The remaining 5 of the 6 bits (corresponding to + * bits {r1,c3,c2,c1,c0} in the S-box lookup index) + * are stored in the least significant 5 bits of the + * step key byte and will end up in the least + * significant 5 bits of the 32-bit step key. + */ + key = rkey->step[i]; + + /* Add step key to input to produce S-box lookup index + * + * We do not ever perform an explicit expansion of the + * input value from 32 to 48 bits. Instead, we rotate + * the 32-bit input value by 4 bits on each step, and + * extract the relevant 6 bits. + * + * The least significant of the 6 bits (corresponding + * to bit r0 in the S-box lookup index) is currently + * in the MSB of the 32-bit (rotated) input value. + * + * The remaining 5 of the 6 bits (corresponding to + * bits {r1,c3,c2,c1,c0} in the S-box lookup index) + * are currently in the least significant 5 bits of + * the 32-bit (rotated) input value. + * + * This aligns with the placement of the bits in the + * step key (see above), and we can therefore perform + * a single XOR to add the 6-bit step key to the + * relevant 6 bits of the input value. + */ + lookup = ( in ^ key ); + + /* Look up S[i][in ^ key] from S-box + * + * We have bits {r1,c3,c2,c1,c0} in the least + * significant 5 bits of the lookup index, and so can + * use the masked lookup index directly as a byte + * index into the relevant S-box to extract the byte + * containing both {r1,c3,c2,c1,c0,'0'} and + * {r1,c3,c2,c1,c0,'1'}. + * + * We then use the MSB of the 32-bit lookup index to + * extract the relevant nibble for the full lookup + * index {r1,c3,c2,c1,c0,r0}. + */ + sub = des_s[i][ lookup & 0x1f ]; + sub >>= ( ( lookup >> 29 ) & 4 ); + sub &= 0x0f; + + /* Substitute S[i][input ^ key] into output */ + out |= sub; + } + + return out; +} + +/** + * Perform a single DES round + * + * @v block DES block + * @v rkey 48-bit round key + */ +static void des_round ( union des_block *block, + const union des_round_key *rkey ) { + union des_dword sbox; + uint32_t left; + uint32_t right; + + /* Extract left and right halves L[n-1] and R[n-1] */ + left = block->left.dword; + right = block->right.dword; + DBGC2 ( block, "DES L=%08x R=%08x K=%08x%08x", be32_to_cpu ( left ), + be32_to_cpu ( right ), be32_to_cpu ( rkey->dword[0] ), + be32_to_cpu ( rkey->dword[1] ) ); + + /* L[n] = R[n-1] */ + block->left.dword = right; + + /* Calculate Feistel function f(R[n-1], K[n]) */ + sbox.dword = cpu_to_be32 ( des_sbox ( be32_to_cpu ( right ), rkey ) ); + des_permute ( des_p, sbox.byte, block->right.byte ); + + /* R[n] = L[n-1] + f(R[n-1], K[n]) */ + block->right.dword ^= left; + DBGC2 ( block, " => L=%08x R=%08x\n", + be32_to_cpu ( block->left.dword ), + be32_to_cpu ( block->right.dword ) ); +} + +/** + * Perform all DES rounds + * + * @v in Input DES block + * @v out Output DES block + * @v rkey Starting 48-bit round key + * @v offset Byte offset between round keys + */ +static void des_rounds ( const union des_block *in, union des_block *out, + const union des_round_key *rkey, + ssize_t offset ) { + union des_block tmp; + unsigned int i; + + /* Apply initial permutation */ + des_permute ( des_ip, in->byte, tmp.byte ); + + /* Perform all DES rounds, consuming keys in the specified order */ + for ( i = 0 ; i < DES_ROUNDS ; i++ ) { + des_round ( &tmp, rkey ); + rkey = ( ( ( void * ) rkey ) + offset ); + } + + /* Apply final permutation */ + DBGC ( &tmp, "DES %scrypted %08x%08x => ", + ( ( offset > 0 ) ? "en" : "de" ), be32_to_cpu ( in->dword[0] ), + be32_to_cpu ( in->dword[1] ) ); + des_permute ( des_fp, tmp.byte, out->byte ); + DBGC ( &tmp, "%08x%08x\n", be32_to_cpu ( out->dword[0] ), + be32_to_cpu ( out->dword[1] ) ); +} + +/** + * Rotate 28-bit word + * + * @v dword 28-bit dword value + * @ret dword Rotated 28-bit dword value + */ +static uint32_t des_rol28 ( uint32_t dword ) { + int32_t sdword; + + /* Convert to native-endian */ + sdword = be32_to_cpu ( dword ); + + /* Signed shift right by 4 places to copy bit 31 to bits 27:31 */ + sdword >>= 4; + + /* Rotate left */ + sdword = rol32 ( sdword, 1 ); + + /* Shift left by 4 places to restore bit positions */ + sdword <<= 4; + + /* Convert back to big-endian */ + dword = cpu_to_be32 ( sdword ); + + return dword; +} + +/** + * Set key + * + * @v ctx Context + * @v key Key + * @v keylen Key length + * @ret rc Return status code + */ +static int des_setkey ( void *ctx, const void *key, size_t keylen ) { + struct des_context *des = ctx; + union des_round_key *rkey = des->rkey; + union des_block reg; + uint32_t schedule; + + /* Validate key length */ + if ( keylen != DES_BLOCKSIZE ) + return -EINVAL; + DBGC ( des, "DES %p new key:\n", des ); + DBGC_HDA ( des, 0, key, keylen ); + + /* Apply permuted choice 1 */ + des_permute ( des_pc1c, key, reg.c.byte ); + des_permute ( des_pc1d, key, reg.d.byte ); + reg.d.byte[3] <<= 4; /* see comment for @c des_pc1d */ + DBGC2 ( des, "DES %p C[ 0]=%07x D[ 0]=%07x\n", + des, ( be32_to_cpu ( reg.c.dword ) >> 4 ), + ( be32_to_cpu ( reg.d.dword ) >> 4 ) ); + + /* Generate round keys */ + for ( schedule = DES_SCHEDULE ; schedule ; schedule >>= 1 ) { + + /* Shift 28-bit words */ + reg.c.dword = des_rol28 ( reg.c.dword ); + reg.d.dword = des_rol28 ( reg.d.dword ); + + /* Skip rounds according to shift schedule */ + if ( ! ( schedule & 1 ) ) + continue; + + /* Apply permuted choice 2 */ + des_permute ( des_pc2, reg.byte, rkey->byte ); + DBGC2 ( des, "DES %p C[%2zd]=%07x D[%2zd]=%07x K[%2zd]=" + "%08x%08x\n", des, ( ( rkey - des->rkey ) + 1 ), + ( be32_to_cpu ( reg.c.dword ) >> 4 ), + ( ( rkey - des->rkey ) + 1 ), + ( be32_to_cpu ( reg.d.dword ) >> 4 ), + ( ( rkey - des->rkey ) + 1 ), + be32_to_cpu ( rkey->dword[0] ), + be32_to_cpu ( rkey->dword[1] ) ); + + /* Move to next key */ + rkey++; + } + + /* Sanity check */ + assert ( rkey == &des->rkey[DES_ROUNDS] ); + + return 0; +} + +/** + * Encrypt data + * + * @v ctx Context + * @v src Data to encrypt + * @v dst Buffer for encrypted data + * @v len Length of data + */ +static void des_encrypt ( void *ctx, const void *src, void *dst, size_t len ) { + struct des_context *des = ctx; + + /* Sanity check */ + assert ( len == DES_BLOCKSIZE ); + + /* Cipher using keys in forward direction */ + des_rounds ( src, dst, &des->rkey[0], sizeof ( des->rkey[0] ) ); +} + +/** + * Decrypt data + * + * @v ctx Context + * @v src Data to decrypt + * @v dst Buffer for decrypted data + * @v len Length of data + */ +static void des_decrypt ( void *ctx, const void *src, void *dst, size_t len ) { + struct des_context *des = ctx; + + /* Sanity check */ + assert ( len == DES_BLOCKSIZE ); + + /* Cipher using keys in reverse direction */ + des_rounds ( src, dst, &des->rkey[ DES_ROUNDS - 1 ], + -sizeof ( des->rkey[0] ) ); +} + +/** Basic DES algorithm */ +struct cipher_algorithm des_algorithm = { + .name = "des", + .ctxsize = sizeof ( struct des_context ), + .blocksize = DES_BLOCKSIZE, + .alignsize = 0, + .authsize = 0, + .setkey = des_setkey, + .setiv = cipher_null_setiv, + .encrypt = des_encrypt, + .decrypt = des_decrypt, + .auth = cipher_null_auth, +}; + +/* DES in Electronic Codebook mode */ +ECB_CIPHER ( des_ecb, des_ecb_algorithm, + des_algorithm, struct des_context, DES_BLOCKSIZE ); + +/* DES in Cipher Block Chaining mode */ +CBC_CIPHER ( des_cbc, des_cbc_algorithm, + des_algorithm, struct des_context, DES_BLOCKSIZE ); diff --git a/src/include/ipxe/des.h b/src/include/ipxe/des.h new file mode 100644 index 00000000..755a90ea --- /dev/null +++ b/src/include/ipxe/des.h @@ -0,0 +1,91 @@ +#ifndef _IPXE_DES_H +#define _IPXE_DES_H + +/** @file + * + * DES algorithm + * + */ + +FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); + +#include + +/** A DES 32-bit dword value + * + * DES views data as 64-bit big-endian values, typically handled as a + * most-significant "left" half and a least-significant "right" half. + */ +union des_dword { + /** Raw bytes */ + uint8_t byte[4]; + /** 32-bit big-endian dword */ + uint32_t dword; +}; + +/** A DES 64-bit block */ +union des_block { + /** Raw bytes */ + uint8_t byte[8]; + /** 32-bit big-endian dwords */ + uint32_t dword[2]; + /** Named left and right halves */ + struct { + /** Left (most significant) half */ + union des_dword left; + /** Right (least significant) half */ + union des_dword right; + }; + /** Named "C" and "D" halves */ + struct { + /** "C" (most significant) half */ + union des_dword c; + /** "D" (least significant) half */ + union des_dword d; + }; +}; + +/** DES blocksize */ +#define DES_BLOCKSIZE sizeof ( union des_block ) + +/** A DES round key + * + * A DES round key is a 48-bit value, consumed as 8 groups of 6 bits. + * We store these as 8 separate bytes, for simplicity of consumption. + */ +union des_round_key { + /** Raw bytes */ + uint8_t byte[8]; + /** 32-bit big-endian dwords */ + uint32_t dword[2]; + /** 6-bit step key byte + * + * There are 8 steps within a DES round (one step per S-box). + * Each step requires six bits of the round key. + * + * As an optimisation, we store the least significant of the 6 + * bits in the sign bit of a signed 8-bit value, and the + * remaining 5 bits in the least significant 5 bits of the + * 8-bit value. See the comments in des_sbox() for further + * details. + */ + int8_t step[8]; +}; + +/** Number of DES rounds */ +#define DES_ROUNDS 16 + +/** DES context */ +struct des_context { + /** Round keys */ + union des_round_key rkey[DES_ROUNDS]; +}; + +/** DES context size */ +#define DES_CTX_SIZE sizeof ( struct des_context ) + +extern struct cipher_algorithm des_algorithm; +extern struct cipher_algorithm des_ecb_algorithm; +extern struct cipher_algorithm des_cbc_algorithm; + +#endif /* _IPXE_DES_H */ diff --git a/src/include/ipxe/errfile.h b/src/include/ipxe/errfile.h index 060a42a3..f7a00dbe 100644 --- a/src/include/ipxe/errfile.h +++ b/src/include/ipxe/errfile.h @@ -408,6 +408,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #define ERRFILE_efi_shim ( ERRFILE_OTHER | 0x005d0000 ) #define ERRFILE_efi_settings ( ERRFILE_OTHER | 0x005e0000 ) #define ERRFILE_x25519 ( ERRFILE_OTHER | 0x005f0000 ) +#define ERRFILE_des ( ERRFILE_OTHER | 0x00600000 ) /** @} */ diff --git a/src/tests/des_test.c b/src/tests/des_test.c new file mode 100644 index 00000000..ffafbd81 --- /dev/null +++ b/src/tests/des_test.c @@ -0,0 +1,898 @@ +/* + * Copyright (C) 2024 Michael Brown . + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + * + * You can also choose to distribute this program under the terms of + * the Unmodified Binary Distribution Licence (as given in the file + * COPYING.UBDL), provided that you have satisfied its requirements. + */ + +FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); + +/** @file + * + * DES tests + * + * These test vectors are originally provided by NBS (the precursor of + * NIST) in SP 500-20, downloadable as a scan of the typewritten + * original from: + * + * https://nvlpubs.nist.gov/nistpubs/Legacy/SP/nbsspecialpublication500-20e1980.pdf + */ + +/* Forcibly enable assertions */ +#undef NDEBUG + +#include +#include +#include +#include "cipher_test.h" + +/** Define a DES 64-bit test value */ +#define DES_VALUE(value) { \ + ( ( ( ( uint64_t ) (value) ) >> 56 ) & 0xff ), \ + ( ( ( ( uint64_t ) (value) ) >> 48 ) & 0xff ), \ + ( ( ( ( uint64_t ) (value) ) >> 40 ) & 0xff ), \ + ( ( ( ( uint64_t ) (value) ) >> 32 ) & 0xff ), \ + ( ( ( ( uint64_t ) (value) ) >> 24 ) & 0xff ), \ + ( ( ( ( uint64_t ) (value) ) >> 16 ) & 0xff ), \ + ( ( ( ( uint64_t ) (value) ) >> 8 ) & 0xff ), \ + ( ( ( ( uint64_t ) (value) ) >> 0 ) & 0xff ) \ + } + +/** Define a DES test */ +#define DES_TEST( name, key, plaintext, ciphertext ) \ + CIPHER_TEST ( name, &des_ecb_algorithm, DES_VALUE ( key ), \ + IV(), ADDITIONAL(), DES_VALUE ( plaintext ), \ + DES_VALUE ( ciphertext ), AUTH() ) + +/* Sample round outputs (page 9) */ +DES_TEST ( des_round_sample, + 0x10316e028c8f3b4a, 0x0000000000000000, 0x82dcbafbdeab6602 ); + +/* Test 1: Initial permutation and expansion tests + * + * "Set Key=0 and encrypt the 64-bit data vectors e[i]: i=1,...,64" + * + * Appendix B, page 28 ("IP and E test") + */ +DES_TEST ( des_test1_1, + 0x0101010101010101, 0x8000000000000000, 0x95f8a5e5dd31d900 ); +DES_TEST ( des_test1_2, + 0x0101010101010101, 0x4000000000000000, 0xdd7f121ca5015619 ); +DES_TEST ( des_test1_3, + 0x0101010101010101, 0x2000000000000000, 0x2e8653104f3834ea ); +DES_TEST ( des_test1_4, + 0x0101010101010101, 0x1000000000000000, 0x4bd388ff6cd81d4f ); +DES_TEST ( des_test1_5, + 0x0101010101010101, 0x0800000000000000, 0x20b9e767b2fb1456 ); +DES_TEST ( des_test1_6, + 0x0101010101010101, 0x0400000000000000, 0x55579380d77138ef ); +DES_TEST ( des_test1_7, + 0x0101010101010101, 0x0200000000000000, 0x6cc5defaaf04512f ); +DES_TEST ( des_test1_8, + 0x0101010101010101, 0x0100000000000000, 0x0d9f279ba5d87260 ); +DES_TEST ( des_test1_9, + 0x0101010101010101, 0x0080000000000000, 0xd9031b0271bd5a0a ); +DES_TEST ( des_test1_10, + 0x0101010101010101, 0x0040000000000000, 0x424250b37c3dd951 ); +DES_TEST ( des_test1_11, + 0x0101010101010101, 0x0020000000000000, 0xb8061b7ecd9a21e5 ); +DES_TEST ( des_test1_12, + 0x0101010101010101, 0x0010000000000000, 0xf15d0f286b65bd28 ); +DES_TEST ( des_test1_13, + 0x0101010101010101, 0x0008000000000000, 0xadd0cc8d6e5deba1 ); +DES_TEST ( des_test1_14, + 0x0101010101010101, 0x0004000000000000, 0xe6d5f82752ad63d1 ); +DES_TEST ( des_test1_15, + 0x0101010101010101, 0x0002000000000000, 0xecbfe3bd3f591a5e ); +DES_TEST ( des_test1_16, + 0x0101010101010101, 0x0001000000000000, 0xf356834379d165cd ); +DES_TEST ( des_test1_17, + 0x0101010101010101, 0x0000800000000000, 0x2b9f982f20037fa9 ); +DES_TEST ( des_test1_18, + 0x0101010101010101, 0x0000400000000000, 0x889de068a16f0be6 ); +DES_TEST ( des_test1_19, + 0x0101010101010101, 0x0000200000000000, 0xe19e275d846a1298 ); +DES_TEST ( des_test1_20, + 0x0101010101010101, 0x0000100000000000, 0x329a8ed523d71aec ); +DES_TEST ( des_test1_21, + 0x0101010101010101, 0x0000080000000000, 0xe7fce22557d23c97 ); +DES_TEST ( des_test1_22, + 0x0101010101010101, 0x0000040000000000, 0x12a9f5817ff2d65d ); +DES_TEST ( des_test1_23, + 0x0101010101010101, 0x0000020000000000, 0xa484c3ad38dc9c19 ); +DES_TEST ( des_test1_24, + 0x0101010101010101, 0x0000010000000000, 0xfbe00a8a1ef8ad72 ); +DES_TEST ( des_test1_25, + 0x0101010101010101, 0x0000008000000000, 0x750d079407521363 ); +DES_TEST ( des_test1_26, + 0x0101010101010101, 0x0000004000000000, 0x64feed9c724c2faf ); +DES_TEST ( des_test1_27, + 0x0101010101010101, 0x0000002000000000, 0xf02b263b328e2b60 ); +DES_TEST ( des_test1_28, + 0x0101010101010101, 0x0000001000000000, 0x9d64555a9a10b852 ); +DES_TEST ( des_test1_29, + 0x0101010101010101, 0x0000000800000000, 0xd106ff0bed5255d7 ); +DES_TEST ( des_test1_30, + 0x0101010101010101, 0x0000000400000000, 0xe1652c6b138c64a5 ); +DES_TEST ( des_test1_31, + 0x0101010101010101, 0x0000000200000000, 0xe428581186ec8f46 ); +DES_TEST ( des_test1_32, + 0x0101010101010101, 0x0000000100000000, 0xaeb5f5ede22d1a36 ); +DES_TEST ( des_test1_33, + 0x0101010101010101, 0x0000000080000000, 0xe943d7568aec0c5c ); +DES_TEST ( des_test1_34, + 0x0101010101010101, 0x0000000040000000, 0xdf98c8276f54b04b ); +DES_TEST ( des_test1_35, + 0x0101010101010101, 0x0000000020000000, 0xb160e4680f6c696f ); +DES_TEST ( des_test1_36, + 0x0101010101010101, 0x0000000010000000, 0xfa0752b07d9c4ab8 ); +DES_TEST ( des_test1_37, + 0x0101010101010101, 0x0000000008000000, 0xca3a2b036dbc8502 ); +DES_TEST ( des_test1_38, + 0x0101010101010101, 0x0000000004000000, 0x5e0905517bb59bcf ); +DES_TEST ( des_test1_39, + 0x0101010101010101, 0x0000000002000000, 0x814eeb3b91d90726 ); +DES_TEST ( des_test1_40, + 0x0101010101010101, 0x0000000001000000, 0x4d49db1532919c9f ); +DES_TEST ( des_test1_41, + 0x0101010101010101, 0x0000000000800000, 0x25eb5fc3f8cf0621 ); +DES_TEST ( des_test1_42, + 0x0101010101010101, 0x0000000000400000, 0xab6a20c0620d1c6f ); +DES_TEST ( des_test1_43, + 0x0101010101010101, 0x0000000000200000, 0x79e90dbc98f92cca ); +DES_TEST ( des_test1_44, + 0x0101010101010101, 0x0000000000100000, 0x866ecedd8072bb0e ); +DES_TEST ( des_test1_45, + 0x0101010101010101, 0x0000000000080000, 0x8b54536f2f3e64a8 ); +DES_TEST ( des_test1_46, + 0x0101010101010101, 0x0000000000040000, 0xea51d3975595b86b ); +DES_TEST ( des_test1_47, + 0x0101010101010101, 0x0000000000020000, 0xcaffc6ac4542de31 ); +DES_TEST ( des_test1_48, + 0x0101010101010101, 0x0000000000010000, 0x8dd45a2ddf90796c ); +DES_TEST ( des_test1_49, + 0x0101010101010101, 0x0000000000008000, 0x1029d55e880ec2d0 ); +DES_TEST ( des_test1_50, + 0x0101010101010101, 0x0000000000004000, 0x5d86cb23639dbea9 ); +DES_TEST ( des_test1_51, + 0x0101010101010101, 0x0000000000002000, 0x1d1ca853ae7c0c5f ); +DES_TEST ( des_test1_52, + 0x0101010101010101, 0x0000000000001000, 0xce332329248f3228 ); +DES_TEST ( des_test1_53, + 0x0101010101010101, 0x0000000000000800, 0x8405d1abe24fb942 ); +DES_TEST ( des_test1_54, + 0x0101010101010101, 0x0000000000000400, 0xe643d78090ca4207 ); +DES_TEST ( des_test1_55, + 0x0101010101010101, 0x0000000000000200, 0x48221b9937748a23 ); +DES_TEST ( des_test1_56, + 0x0101010101010101, 0x0000000000000100, 0xdd7c0bbd61fafd54 ); +DES_TEST ( des_test1_57, + 0x0101010101010101, 0x0000000000000080, 0x2fbc291a570db5c4 ); +DES_TEST ( des_test1_58, + 0x0101010101010101, 0x0000000000000040, 0xe07c30d7e4e26e12 ); +DES_TEST ( des_test1_59, + 0x0101010101010101, 0x0000000000000020, 0x0953e2258e8e90a1 ); +DES_TEST ( des_test1_60, + 0x0101010101010101, 0x0000000000000010, 0x5b711bc4ceebf2ee ); +DES_TEST ( des_test1_61, + 0x0101010101010101, 0x0000000000000008, 0xcc083f1e6d9e85f6 ); +DES_TEST ( des_test1_62, + 0x0101010101010101, 0x0000000000000004, 0xd2fd8867d50d2dfe ); +DES_TEST ( des_test1_63, + 0x0101010101010101, 0x0000000000000002, 0x06e7ea22ce92708f ); +DES_TEST ( des_test1_64, + 0x0101010101010101, 0x0000000000000001, 0x166b40b44aba4bd6 ); + +/* Test 2: Inverse permutation and expansion tests + * + * "Set Key=0 and encrypt the results c[i] obtained in Test 1" + * + * Appendix B, page 28 ("IP and E test") + */ +DES_TEST ( des_test2_1, + 0x0101010101010101, 0x95f8a5e5dd31d900, 0x8000000000000000 ); +DES_TEST ( des_test2_2, + 0x0101010101010101, 0xdd7f121ca5015619, 0x4000000000000000 ); +DES_TEST ( des_test2_3, + 0x0101010101010101, 0x2e8653104f3834ea, 0x2000000000000000 ); +DES_TEST ( des_test2_4, + 0x0101010101010101, 0x4bd388ff6cd81d4f, 0x1000000000000000 ); +DES_TEST ( des_test2_5, + 0x0101010101010101, 0x20b9e767b2fb1456, 0x0800000000000000 ); +DES_TEST ( des_test2_6, + 0x0101010101010101, 0x55579380d77138ef, 0x0400000000000000 ); +DES_TEST ( des_test2_7, + 0x0101010101010101, 0x6cc5defaaf04512f, 0x0200000000000000 ); +DES_TEST ( des_test2_8, + 0x0101010101010101, 0x0d9f279ba5d87260, 0x0100000000000000 ); +DES_TEST ( des_test2_9, + 0x0101010101010101, 0xd9031b0271bd5a0a, 0x0080000000000000 ); +DES_TEST ( des_test2_10, + 0x0101010101010101, 0x424250b37c3dd951, 0x0040000000000000 ); +DES_TEST ( des_test2_11, + 0x0101010101010101, 0xb8061b7ecd9a21e5, 0x0020000000000000 ); +DES_TEST ( des_test2_12, + 0x0101010101010101, 0xf15d0f286b65bd28, 0x0010000000000000 ); +DES_TEST ( des_test2_13, + 0x0101010101010101, 0xadd0cc8d6e5deba1, 0x0008000000000000 ); +DES_TEST ( des_test2_14, + 0x0101010101010101, 0xe6d5f82752ad63d1, 0x0004000000000000 ); +DES_TEST ( des_test2_15, + 0x0101010101010101, 0xecbfe3bd3f591a5e, 0x0002000000000000 ); +DES_TEST ( des_test2_16, + 0x0101010101010101, 0xf356834379d165cd, 0x0001000000000000 ); +DES_TEST ( des_test2_17, + 0x0101010101010101, 0x2b9f982f20037fa9, 0x0000800000000000 ); +DES_TEST ( des_test2_18, + 0x0101010101010101, 0x889de068a16f0be6, 0x0000400000000000 ); +DES_TEST ( des_test2_19, + 0x0101010101010101, 0xe19e275d846a1298, 0x0000200000000000 ); +DES_TEST ( des_test2_20, + 0x0101010101010101, 0x329a8ed523d71aec, 0x0000100000000000 ); +DES_TEST ( des_test2_21, + 0x0101010101010101, 0xe7fce22557d23c97, 0x0000080000000000 ); +DES_TEST ( des_test2_22, + 0x0101010101010101, 0x12a9f5817ff2d65d, 0x0000040000000000 ); +DES_TEST ( des_test2_23, + 0x0101010101010101, 0xa484c3ad38dc9c19, 0x0000020000000000 ); +DES_TEST ( des_test2_24, + 0x0101010101010101, 0xfbe00a8a1ef8ad72, 0x0000010000000000 ); +DES_TEST ( des_test2_25, + 0x0101010101010101, 0x750d079407521363, 0x0000008000000000 ); +DES_TEST ( des_test2_26, + 0x0101010101010101, 0x64feed9c724c2faf, 0x0000004000000000 ); +DES_TEST ( des_test2_27, + 0x0101010101010101, 0xf02b263b328e2b60, 0x0000002000000000 ); +DES_TEST ( des_test2_28, + 0x0101010101010101, 0x9d64555a9a10b852, 0x0000001000000000 ); +DES_TEST ( des_test2_29, + 0x0101010101010101, 0xd106ff0bed5255d7, 0x0000000800000000 ); +DES_TEST ( des_test2_30, + 0x0101010101010101, 0xe1652c6b138c64a5, 0x0000000400000000 ); +DES_TEST ( des_test2_31, + 0x0101010101010101, 0xe428581186ec8f46, 0x0000000200000000 ); +DES_TEST ( des_test2_32, + 0x0101010101010101, 0xaeb5f5ede22d1a36, 0x0000000100000000 ); +DES_TEST ( des_test2_33, + 0x0101010101010101, 0xe943d7568aec0c5c, 0x0000000080000000 ); +DES_TEST ( des_test2_34, + 0x0101010101010101, 0xdf98c8276f54b04b, 0x0000000040000000 ); +DES_TEST ( des_test2_35, + 0x0101010101010101, 0xb160e4680f6c696f, 0x0000000020000000 ); +DES_TEST ( des_test2_36, + 0x0101010101010101, 0xfa0752b07d9c4ab8, 0x0000000010000000 ); +DES_TEST ( des_test2_37, + 0x0101010101010101, 0xca3a2b036dbc8502, 0x0000000008000000 ); +DES_TEST ( des_test2_38, + 0x0101010101010101, 0x5e0905517bb59bcf, 0x0000000004000000 ); +DES_TEST ( des_test2_39, + 0x0101010101010101, 0x814eeb3b91d90726, 0x0000000002000000 ); +DES_TEST ( des_test2_40, + 0x0101010101010101, 0x4d49db1532919c9f, 0x0000000001000000 ); +DES_TEST ( des_test2_41, + 0x0101010101010101, 0x25eb5fc3f8cf0621, 0x0000000000800000 ); +DES_TEST ( des_test2_42, + 0x0101010101010101, 0xab6a20c0620d1c6f, 0x0000000000400000 ); +DES_TEST ( des_test2_43, + 0x0101010101010101, 0x79e90dbc98f92cca, 0x0000000000200000 ); +DES_TEST ( des_test2_44, + 0x0101010101010101, 0x866ecedd8072bb0e, 0x0000000000100000 ); +DES_TEST ( des_test2_45, + 0x0101010101010101, 0x8b54536f2f3e64a8, 0x0000000000080000 ); +DES_TEST ( des_test2_46, + 0x0101010101010101, 0xea51d3975595b86b, 0x0000000000040000 ); +DES_TEST ( des_test2_47, + 0x0101010101010101, 0xcaffc6ac4542de31, 0x0000000000020000 ); +DES_TEST ( des_test2_48, + 0x0101010101010101, 0x8dd45a2ddf90796c, 0x0000000000010000 ); +DES_TEST ( des_test2_49, + 0x0101010101010101, 0x1029d55e880ec2d0, 0x0000000000008000 ); +DES_TEST ( des_test2_50, + 0x0101010101010101, 0x5d86cb23639dbea9, 0x0000000000004000 ); +DES_TEST ( des_test2_51, + 0x0101010101010101, 0x1d1ca853ae7c0c5f, 0x0000000000002000 ); +DES_TEST ( des_test2_52, + 0x0101010101010101, 0xce332329248f3228, 0x0000000000001000 ); +DES_TEST ( des_test2_53, + 0x0101010101010101, 0x8405d1abe24fb942, 0x0000000000000800 ); +DES_TEST ( des_test2_54, + 0x0101010101010101, 0xe643d78090ca4207, 0x0000000000000400 ); +DES_TEST ( des_test2_55, + 0x0101010101010101, 0x48221b9937748a23, 0x0000000000000200 ); +DES_TEST ( des_test2_56, + 0x0101010101010101, 0xdd7c0bbd61fafd54, 0x0000000000000100 ); +DES_TEST ( des_test2_57, + 0x0101010101010101, 0x2fbc291a570db5c4, 0x0000000000000080 ); +DES_TEST ( des_test2_58, + 0x0101010101010101, 0xe07c30d7e4e26e12, 0x0000000000000040 ); +DES_TEST ( des_test2_59, + 0x0101010101010101, 0x0953e2258e8e90a1, 0x0000000000000020 ); +DES_TEST ( des_test2_60, + 0x0101010101010101, 0x5b711bc4ceebf2ee, 0x0000000000000010 ); +DES_TEST ( des_test2_61, + 0x0101010101010101, 0xcc083f1e6d9e85f6, 0x0000000000000008 ); +DES_TEST ( des_test2_62, + 0x0101010101010101, 0xd2fd8867d50d2dfe, 0x0000000000000004 ); +DES_TEST ( des_test2_63, + 0x0101010101010101, 0x06e7ea22ce92708f, 0x0000000000000002 ); +DES_TEST ( des_test2_64, + 0x0101010101010101, 0x166b40b44aba4bd6, 0x0000000000000001 ); + +/* Test 3: Data permutation tests + * + * "Set the plaintext to zero and process the 32 keys in PTEST" + * + * Appendix B, page 32 ("PTEST") + */ +DES_TEST ( des_test3_1, + 0x1046913489980131, 0x0000000000000000, 0x88d55e54f54c97b4 ); +DES_TEST ( des_test3_2, + 0x1007103489988020, 0x0000000000000000, 0x0c0cc00c83ea48fd ); +DES_TEST ( des_test3_3, + 0x10071034c8980120, 0x0000000000000000, 0x83bc8ef3a6570183 ); +DES_TEST ( des_test3_4, + 0x1046103489988020, 0x0000000000000000, 0xdf725dcad94ea2e9 ); +DES_TEST ( des_test3_5, + 0x1086911519190101, 0x0000000000000000, 0xe652b53b550be8b0 ); +DES_TEST ( des_test3_6, + 0x1086911519580101, 0x0000000000000000, 0xaf527120c485cbb0 ); +DES_TEST ( des_test3_7, + 0x5107b01519580101, 0x0000000000000000, 0x0f04ce393db926d5 ); +DES_TEST ( des_test3_8, + 0x1007b01519190101, 0x0000000000000000, 0xc9f00ffc74079067 ); +DES_TEST ( des_test3_9, + 0x3107915498080101, 0x0000000000000000, 0x7cfd82a593252b4e ); +DES_TEST ( des_test3_10, + 0x3107919498080101, 0x0000000000000000, 0xcb49a2f9e91363e3 ); +DES_TEST ( des_test3_11, + 0x10079115b9080140, 0x0000000000000000, 0x00b588be70d23f56 ); +DES_TEST ( des_test3_12, + 0x3107911598080140, 0x0000000000000000, 0x406a9a6ab43399ae ); +DES_TEST ( des_test3_13, + 0x1007d01589980101, 0x0000000000000000, 0x6cb773611dca9ada ); +DES_TEST ( des_test3_14, + 0x9107911589980101, 0x0000000000000000, 0x67fd21c17dbb5d70 ); +DES_TEST ( des_test3_15, + 0x9107d01589190101, 0x0000000000000000, 0x9592cb4110430787 ); +DES_TEST ( des_test3_16, + 0x1007d01598980120, 0x0000000000000000, 0xa6b7ff68a318ddd3 ); +DES_TEST ( des_test3_17, + 0x1007940498190101, 0x0000000000000000, 0x4d102196c914ca16 ); +DES_TEST ( des_test3_18, + 0x0107910491190401, 0x0000000000000000, 0x2dfa9f4573594965 ); +DES_TEST ( des_test3_19, + 0x0107910491190101, 0x0000000000000000, 0xb46604816c0e0774 ); +DES_TEST ( des_test3_20, + 0x0107940491190401, 0x0000000000000000, 0x6e7e6221a4f34e87 ); +DES_TEST ( des_test3_21, + 0x19079210981a0101, 0x0000000000000000, 0xaa85e74643233199 ); +DES_TEST ( des_test3_22, + 0x1007911998190801, 0x0000000000000000, 0x2e5a19db4d1962d6 ); +DES_TEST ( des_test3_23, + 0x10079119981a0801, 0x0000000000000000, 0x23a866a809d30894 ); +DES_TEST ( des_test3_24, + 0x1007921098190101, 0x0000000000000000, 0xd812d961f017d320 ); +DES_TEST ( des_test3_25, + 0x100791159819010b, 0x0000000000000000, 0x055605816e58608f ); +DES_TEST ( des_test3_26, + 0x1004801598190101, 0x0000000000000000, 0xabd88e8b1b7716f1 ); +DES_TEST ( des_test3_27, + 0x1004801598190102, 0x0000000000000000, 0x537ac95be69da1e1 ); +DES_TEST ( des_test3_28, + 0x1004801598190108, 0x0000000000000000, 0xaed0f6ae3c25cdd8 ); +DES_TEST ( des_test3_29, + 0x1002911498100104, 0x0000000000000000, 0xb3e35a5ee53e7b8d ); +DES_TEST ( des_test3_30, + 0x1002911598190104, 0x0000000000000000, 0x61c79c71921a2ef8 ); +DES_TEST ( des_test3_31, + 0x1002911598100201, 0x0000000000000000, 0xe2f5728f0995013c ); +DES_TEST ( des_test3_32, + 0x1002911698100101, 0x0000000000000000, 0x1aeac39a61f0a464 ); + +/* Test 4: Key permutation tests + * + * "Set Data=0 and use the keys e[i]: i=1,...,64 ignoring i=8,16,...,64" + * + * Test 4 part 1 is the forward direction as described above. Test 4 + * part 2 ("set data=c[i] from part 1 ... then decipher") is carried + * out for us automatically, since CIPHER_TEST() performs both + * encryption and decryption tests. + * + * Appendix B, page 30 ("PC1 and PC2 test") + */ +DES_TEST ( des_test4_1, + 0x8001010101010101, 0x0000000000000000, 0x95a8d72813daa94d ); +DES_TEST ( des_test4_2, + 0x4001010101010101, 0x0000000000000000, 0x0eec1487dd8c26d5 ); +DES_TEST ( des_test4_3, + 0x2001010101010101, 0x0000000000000000, 0x7ad16ffb79c45926 ); +DES_TEST ( des_test4_4, + 0x1001010101010101, 0x0000000000000000, 0xd3746294ca6a6cf3 ); +DES_TEST ( des_test4_5, + 0x0801010101010101, 0x0000000000000000, 0x809f5f873c1fd761 ); +DES_TEST ( des_test4_6, + 0x0401010101010101, 0x0000000000000000, 0xc02faffec989d1fc ); +DES_TEST ( des_test4_7, + 0x0201010101010101, 0x0000000000000000, 0x4615aa1d33e72f10 ); +DES_TEST ( des_test4_8, + 0x0180010101010101, 0x0000000000000000, 0x2055123350c00858 ); +DES_TEST ( des_test4_9, + 0x0140010101010101, 0x0000000000000000, 0xdf3b99d6577397c8 ); +DES_TEST ( des_test4_10, + 0x0120010101010101, 0x0000000000000000, 0x31fe17369b5288c9 ); +DES_TEST ( des_test4_11, + 0x0110010101010101, 0x0000000000000000, 0xdfdd3cc64dae1642 ); +DES_TEST ( des_test4_12, + 0x0108010101010101, 0x0000000000000000, 0x178c83ce2b399d94 ); +DES_TEST ( des_test4_13, + 0x0104010101010101, 0x0000000000000000, 0x50f636324a9b7f80 ); +DES_TEST ( des_test4_14, + 0x0102010101010101, 0x0000000000000000, 0xa8468ee3bc18f06d ); +DES_TEST ( des_test4_15, + 0x0101800101010101, 0x0000000000000000, 0xa2dc9e92fd3cde92 ); +DES_TEST ( des_test4_16, + 0x0101400101010101, 0x0000000000000000, 0xcac09f797d031287 ); +DES_TEST ( des_test4_17, + 0x0101200101010101, 0x0000000000000000, 0x90ba680b22aeb525 ); +DES_TEST ( des_test4_18, + 0x0101100101010101, 0x0000000000000000, 0xce7a24f350e280b6 ); +DES_TEST ( des_test4_19, + 0x0101080101010101, 0x0000000000000000, 0x882bff0aa01a0b87 ); +DES_TEST ( des_test4_20, + 0x0101040101010101, 0x0000000000000000, 0x25610288924511c2 ); +DES_TEST ( des_test4_21, + 0x0101020101010101, 0x0000000000000000, 0xc71516c29c75d170 ); +DES_TEST ( des_test4_22, + 0x0101018001010101, 0x0000000000000000, 0x5199c29a52c9f059 ); +DES_TEST ( des_test4_23, + 0x0101014001010101, 0x0000000000000000, 0xc22f0a294a71f29f ); +DES_TEST ( des_test4_24, + 0x0101012001010101, 0x0000000000000000, 0xee371483714c02ea ); +DES_TEST ( des_test4_25, + 0x0101011001010101, 0x0000000000000000, 0xa81fbd448f9e522f ); +DES_TEST ( des_test4_26, + 0x0101010801010101, 0x0000000000000000, 0x4f644c92e192dfed ); +DES_TEST ( des_test4_27, + 0x0101010401010101, 0x0000000000000000, 0x1afa9a66a6df92ae ); +DES_TEST ( des_test4_28, + 0x0101010201010101, 0x0000000000000000, 0xb3c1cc715cb879d8 ); +DES_TEST ( des_test4_29, + 0x0101010180010101, 0x0000000000000000, 0x19d032e64ab0bd8b ); +DES_TEST ( des_test4_30, + 0x0101010140010101, 0x0000000000000000, 0x3cfaa7a7dc8720dc ); +DES_TEST ( des_test4_31, + 0x0101010120010101, 0x0000000000000000, 0xb7265f7f447ac6f3 ); +DES_TEST ( des_test4_32, + 0x0101010110010101, 0x0000000000000000, 0x9db73b3c0d163f54 ); +DES_TEST ( des_test4_33, + 0x0101010108010101, 0x0000000000000000, 0x8181b65babf4a975 ); +DES_TEST ( des_test4_34, + 0x0101010104010101, 0x0000000000000000, 0x93c9b64042eaa240 ); +DES_TEST ( des_test4_35, + 0x0101010102010101, 0x0000000000000000, 0x5570530829705592 ); +DES_TEST ( des_test4_36, + 0x0101010101800101, 0x0000000000000000, 0x8638809e878787a0 ); +DES_TEST ( des_test4_37, + 0x0101010101400101, 0x0000000000000000, 0x41b9a79af79ac208 ); +DES_TEST ( des_test4_38, + 0x0101010101200101, 0x0000000000000000, 0x7a9be42f2009a892 ); +DES_TEST ( des_test4_39, + 0x0101010101100101, 0x0000000000000000, 0x29038d56ba6d2745 ); +DES_TEST ( des_test4_40, + 0x0101010101080101, 0x0000000000000000, 0x5495c6abf1e5df51 ); +DES_TEST ( des_test4_41, + 0x0101010101040101, 0x0000000000000000, 0xae13dbd561488933 ); +DES_TEST ( des_test4_42, + 0x0101010101020101, 0x0000000000000000, 0x024d1ffa8904e389 ); +DES_TEST ( des_test4_43, + 0x0101010101018001, 0x0000000000000000, 0xd1399712f99bf02e ); +DES_TEST ( des_test4_44, + 0x0101010101014001, 0x0000000000000000, 0x14c1d7c1cffec79e ); +DES_TEST ( des_test4_45, + 0x0101010101012001, 0x0000000000000000, 0x1de5279dae3bed6f ); +DES_TEST ( des_test4_46, + 0x0101010101011001, 0x0000000000000000, 0xe941a33f85501303 ); +DES_TEST ( des_test4_47, + 0x0101010101010801, 0x0000000000000000, 0xda99dbbc9a03f379 ); +DES_TEST ( des_test4_48, + 0x0101010101010401, 0x0000000000000000, 0xb7fc92f91d8e92e9 ); +DES_TEST ( des_test4_49, + 0x0101010101010201, 0x0000000000000000, 0xae8e5caa3ca04e85 ); +DES_TEST ( des_test4_50, + 0x0101010101010180, 0x0000000000000000, 0x9cc62df43b6eed74 ); +DES_TEST ( des_test4_51, + 0x0101010101010140, 0x0000000000000000, 0xd863dbb5c59a91a0 ); +DES_TEST ( des_test4_52, + 0x0101010101010120, 0x0000000000000000, 0xa1ab2190545b91d7 ); +DES_TEST ( des_test4_53, + 0x0101010101010110, 0x0000000000000000, 0x0875041e64c570f7 ); +DES_TEST ( des_test4_54, + 0x0101010101010108, 0x0000000000000000, 0x5a594528bebef1cc ); +DES_TEST ( des_test4_55, + 0x0101010101010104, 0x0000000000000000, 0xfcdb3291de21f0c0 ); +DES_TEST ( des_test4_56, + 0x0101010101010102, 0x0000000000000000, 0x869efd7f9f265a09 ); + +/* Test 5: S-box tests + * + * "Set Data and Key equal to the inputs defined in the Substitution + * Table test" + * + * Appendix B, page 33 ("19 key data pairs which exercise every S-box entry") + */ +DES_TEST ( des_test5_1, + 0x7ca110454a1a6e57, 0x01a1d6d039776742, 0x690f5b0d9a26939b ); +DES_TEST ( des_test5_2, + 0x0131d9619dc1376e, 0x5cd54ca83def57da, 0x7a389d10354bd271 ); +DES_TEST ( des_test5_3, + 0x07a1133e4a0b2686, 0x0248d43806f67172, 0x868ebb51cab4599a ); +DES_TEST ( des_test5_4, + 0x3849674c2602319e, 0x51454b582ddf440a, 0x7178876e01f19b2a ); +DES_TEST ( des_test5_5, + 0x04b915ba43feb5b6, 0x42fd443059577fa2, 0xaf37fb421f8c4095 ); +DES_TEST ( des_test5_6, + 0x0113b970fd34f2ce, 0x059b5e0851cf143a, 0x86a560f10ec6d85b ); +DES_TEST ( des_test5_7, + 0x0170f175468fb5e6, 0x0756d8e0774761d2, 0x0cd3da020021dc09 ); +DES_TEST ( des_test5_8, + 0x43297fad38e373fe, 0x762514b829bf486a, 0xea676b2cb7db2b7a ); +DES_TEST ( des_test5_9, + 0x07a7137045da2a16, 0x3bdd119049372802, 0xdfd64a815caf1a0f ); +DES_TEST ( des_test5_10, + 0x04689104c2fd3b2f, 0x26955f6835af609a, 0x5c513c9c4886c088 ); +DES_TEST ( des_test5_11, + 0x37d06bb516cb7546, 0x164d5e404f275232, 0x0a2aeeae3ff4ab77 ); +DES_TEST ( des_test5_12, + 0x1f08260d1ac2465e, 0x6b056e18759f5cca, 0xef1bf03e5dfa575a ); +DES_TEST ( des_test5_13, + 0x584023641aba6176, 0x004bd6ef09176062, 0x88bf0db6d70dee56 ); +DES_TEST ( des_test5_14, + 0x025816164629b007, 0x480d39006ee762f2, 0xa1f9915541020b56 ); +DES_TEST ( des_test5_15, + 0x49793ebc79b3258f, 0x437540c8698f3cfa, 0x6fbf1cafcffd0556 ); +DES_TEST ( des_test5_16, + 0x4fb05e1515ab73a7, 0x072d43a077075292, 0x2f22e49bab7ca1ac ); +DES_TEST ( des_test5_17, + 0x49e95d6d4ca229bf, 0x02fe55778117f12a, 0x5a6b612cc26cce4a ); +DES_TEST ( des_test5_18, + 0x018310dc409b26d6, 0x1d9d5c5018f728c2, 0x5f4c038ed12b2e41 ); +DES_TEST ( des_test5_19, + 0x1c587f1c13924fef, 0x305532286d6f295a, 0x63fac0d034d9f793 ); + +/* Unofficial tests + * + * The official tests are all exactly one block in length. Add some + * multi-block tests (generated in Python). + */ +CIPHER_TEST ( des_unofficial_ecb, &des_ecb_algorithm, + KEY ( 0x6e, 0x6f, 0x70, 0x61, 0x72, 0x69, 0x74, 0x79 ), + IV(), ADDITIONAL(), + PLAINTEXT ( 0x53, 0x6f, 0x20, 0x63, 0x75, 0x74, 0x65, 0x20, + 0x74, 0x6f, 0x20, 0x73, 0x65, 0x65, 0x20, 0x61, + 0x20, 0x73, 0x70, 0x65, 0x63, 0x69, 0x66, 0x69, + 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x77, + 0x72, 0x69, 0x74, 0x74, 0x65, 0x6e, 0x20, 0x6f, + 0x6e, 0x20, 0x61, 0x6e, 0x20, 0x61, 0x63, 0x74, + 0x75, 0x61, 0x6c, 0x20, 0x74, 0x79, 0x70, 0x65, + 0x77, 0x72, 0x69, 0x74, 0x65, 0x72, 0x21, 0x21 ), + CIPHERTEXT ( 0x1a, 0x02, 0x17, 0xcb, 0x93, 0xa3, 0xd2, 0xf2, + 0xf9, 0x45, 0x71, 0x1c, 0x33, 0xb1, 0x5c, 0xa4, + 0x8b, 0x6b, 0x11, 0x7a, 0x7c, 0x86, 0x7c, 0x7f, + 0x9f, 0x56, 0x61, 0x46, 0x7f, 0xa6, 0xae, 0xf1, + 0x49, 0xf7, 0x53, 0xe0, 0xbc, 0x15, 0x6a, 0x30, + 0xe7, 0xf8, 0xf3, 0x29, 0x11, 0xd8, 0x7d, 0x04, + 0x62, 0x5a, 0xaa, 0xa1, 0x89, 0x61, 0x4c, 0xf6, + 0x5a, 0x47, 0x3b, 0xc6, 0x04, 0x15, 0xce, 0xf6 ), + AUTH() ); +CIPHER_TEST ( des_unofficial_cbc, &des_cbc_algorithm, + KEY ( 0x6e, 0x6f, 0x70, 0x61, 0x72, 0x69, 0x74, 0x79 ), + IV ( 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08 ), + ADDITIONAL(), + PLAINTEXT ( 0x53, 0x6f, 0x20, 0x63, 0x75, 0x74, 0x65, 0x20, + 0x74, 0x6f, 0x20, 0x73, 0x65, 0x65, 0x20, 0x61, + 0x20, 0x73, 0x70, 0x65, 0x63, 0x69, 0x66, 0x69, + 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x77, + 0x72, 0x69, 0x74, 0x74, 0x65, 0x6e, 0x20, 0x6f, + 0x6e, 0x20, 0x61, 0x6e, 0x20, 0x61, 0x63, 0x74, + 0x75, 0x61, 0x6c, 0x20, 0x74, 0x79, 0x70, 0x65, + 0x77, 0x72, 0x69, 0x74, 0x65, 0x72, 0x21, 0x21 ), + CIPHERTEXT ( 0x4c, 0x5f, 0x62, 0xfc, 0xf4, 0x93, 0x09, 0xb5, + 0x1d, 0x52, 0x25, 0xec, 0xc7, 0x42, 0x3c, 0x29, + 0x33, 0x67, 0xf5, 0xe9, 0xd6, 0x3c, 0x27, 0x5b, + 0x49, 0x69, 0xc5, 0xa9, 0x08, 0xa3, 0x14, 0x66, + 0x3c, 0x95, 0x33, 0x30, 0xcf, 0x3c, 0x7c, 0xaf, + 0xa3, 0xe4, 0xf8, 0x2e, 0xc3, 0x55, 0x57, 0x81, + 0x33, 0xd9, 0x90, 0xe2, 0x99, 0xdc, 0x32, 0x10, + 0x13, 0x21, 0xb6, 0xc1, 0x6b, 0x0f, 0x22, 0xa9 ), + AUTH() ); + +/** + * Perform DES self-test + * + */ +static void des_test_exec ( void ) { + + /* Sample round outputs (page 9) */ + cipher_ok ( &des_round_sample ); + + /* Test 1: Initial permutation and expansion tests */ + cipher_ok ( &des_test1_1 ); + cipher_ok ( &des_test1_2 ); + cipher_ok ( &des_test1_3 ); + cipher_ok ( &des_test1_4 ); + cipher_ok ( &des_test1_5 ); + cipher_ok ( &des_test1_6 ); + cipher_ok ( &des_test1_7 ); + cipher_ok ( &des_test1_8 ); + cipher_ok ( &des_test1_9 ); + cipher_ok ( &des_test1_10 ); + cipher_ok ( &des_test1_11 ); + cipher_ok ( &des_test1_12 ); + cipher_ok ( &des_test1_13 ); + cipher_ok ( &des_test1_14 ); + cipher_ok ( &des_test1_15 ); + cipher_ok ( &des_test1_16 ); + cipher_ok ( &des_test1_17 ); + cipher_ok ( &des_test1_18 ); + cipher_ok ( &des_test1_19 ); + cipher_ok ( &des_test1_20 ); + cipher_ok ( &des_test1_21 ); + cipher_ok ( &des_test1_22 ); + cipher_ok ( &des_test1_23 ); + cipher_ok ( &des_test1_24 ); + cipher_ok ( &des_test1_25 ); + cipher_ok ( &des_test1_26 ); + cipher_ok ( &des_test1_27 ); + cipher_ok ( &des_test1_28 ); + cipher_ok ( &des_test1_29 ); + cipher_ok ( &des_test1_30 ); + cipher_ok ( &des_test1_31 ); + cipher_ok ( &des_test1_32 ); + cipher_ok ( &des_test1_33 ); + cipher_ok ( &des_test1_34 ); + cipher_ok ( &des_test1_35 ); + cipher_ok ( &des_test1_36 ); + cipher_ok ( &des_test1_37 ); + cipher_ok ( &des_test1_38 ); + cipher_ok ( &des_test1_39 ); + cipher_ok ( &des_test1_40 ); + cipher_ok ( &des_test1_41 ); + cipher_ok ( &des_test1_42 ); + cipher_ok ( &des_test1_43 ); + cipher_ok ( &des_test1_44 ); + cipher_ok ( &des_test1_45 ); + cipher_ok ( &des_test1_46 ); + cipher_ok ( &des_test1_47 ); + cipher_ok ( &des_test1_48 ); + cipher_ok ( &des_test1_49 ); + cipher_ok ( &des_test1_50 ); + cipher_ok ( &des_test1_51 ); + cipher_ok ( &des_test1_52 ); + cipher_ok ( &des_test1_53 ); + cipher_ok ( &des_test1_54 ); + cipher_ok ( &des_test1_55 ); + cipher_ok ( &des_test1_56 ); + cipher_ok ( &des_test1_57 ); + cipher_ok ( &des_test1_58 ); + cipher_ok ( &des_test1_59 ); + cipher_ok ( &des_test1_60 ); + cipher_ok ( &des_test1_61 ); + cipher_ok ( &des_test1_62 ); + cipher_ok ( &des_test1_63 ); + cipher_ok ( &des_test1_64 ); + + /* Test 2: Inverse permutation and expansion tests */ + cipher_ok ( &des_test2_1 ); + cipher_ok ( &des_test2_2 ); + cipher_ok ( &des_test2_3 ); + cipher_ok ( &des_test2_4 ); + cipher_ok ( &des_test2_5 ); + cipher_ok ( &des_test2_6 ); + cipher_ok ( &des_test2_7 ); + cipher_ok ( &des_test2_8 ); + cipher_ok ( &des_test2_9 ); + cipher_ok ( &des_test2_10 ); + cipher_ok ( &des_test2_11 ); + cipher_ok ( &des_test2_12 ); + cipher_ok ( &des_test2_13 ); + cipher_ok ( &des_test2_14 ); + cipher_ok ( &des_test2_15 ); + cipher_ok ( &des_test2_16 ); + cipher_ok ( &des_test2_17 ); + cipher_ok ( &des_test2_18 ); + cipher_ok ( &des_test2_19 ); + cipher_ok ( &des_test2_20 ); + cipher_ok ( &des_test2_21 ); + cipher_ok ( &des_test2_22 ); + cipher_ok ( &des_test2_23 ); + cipher_ok ( &des_test2_24 ); + cipher_ok ( &des_test2_25 ); + cipher_ok ( &des_test2_26 ); + cipher_ok ( &des_test2_27 ); + cipher_ok ( &des_test2_28 ); + cipher_ok ( &des_test2_29 ); + cipher_ok ( &des_test2_30 ); + cipher_ok ( &des_test2_31 ); + cipher_ok ( &des_test2_32 ); + cipher_ok ( &des_test2_33 ); + cipher_ok ( &des_test2_34 ); + cipher_ok ( &des_test2_35 ); + cipher_ok ( &des_test2_36 ); + cipher_ok ( &des_test2_37 ); + cipher_ok ( &des_test2_38 ); + cipher_ok ( &des_test2_39 ); + cipher_ok ( &des_test2_40 ); + cipher_ok ( &des_test2_41 ); + cipher_ok ( &des_test2_42 ); + cipher_ok ( &des_test2_43 ); + cipher_ok ( &des_test2_44 ); + cipher_ok ( &des_test2_45 ); + cipher_ok ( &des_test2_46 ); + cipher_ok ( &des_test2_47 ); + cipher_ok ( &des_test2_48 ); + cipher_ok ( &des_test2_49 ); + cipher_ok ( &des_test2_50 ); + cipher_ok ( &des_test2_51 ); + cipher_ok ( &des_test2_52 ); + cipher_ok ( &des_test2_53 ); + cipher_ok ( &des_test2_54 ); + cipher_ok ( &des_test2_55 ); + cipher_ok ( &des_test2_56 ); + cipher_ok ( &des_test2_57 ); + cipher_ok ( &des_test2_58 ); + cipher_ok ( &des_test2_59 ); + cipher_ok ( &des_test2_60 ); + cipher_ok ( &des_test2_61 ); + cipher_ok ( &des_test2_62 ); + cipher_ok ( &des_test2_63 ); + cipher_ok ( &des_test2_64 ); + + /* Test 3: Data permutation tests */ + cipher_ok ( &des_test3_1 ); + cipher_ok ( &des_test3_2 ); + cipher_ok ( &des_test3_3 ); + cipher_ok ( &des_test3_4 ); + cipher_ok ( &des_test3_5 ); + cipher_ok ( &des_test3_6 ); + cipher_ok ( &des_test3_7 ); + cipher_ok ( &des_test3_8 ); + cipher_ok ( &des_test3_9 ); + cipher_ok ( &des_test3_10 ); + cipher_ok ( &des_test3_11 ); + cipher_ok ( &des_test3_12 ); + cipher_ok ( &des_test3_13 ); + cipher_ok ( &des_test3_14 ); + cipher_ok ( &des_test3_15 ); + cipher_ok ( &des_test3_16 ); + cipher_ok ( &des_test3_17 ); + cipher_ok ( &des_test3_18 ); + cipher_ok ( &des_test3_19 ); + cipher_ok ( &des_test3_20 ); + cipher_ok ( &des_test3_21 ); + cipher_ok ( &des_test3_22 ); + cipher_ok ( &des_test3_23 ); + cipher_ok ( &des_test3_24 ); + cipher_ok ( &des_test3_25 ); + cipher_ok ( &des_test3_26 ); + cipher_ok ( &des_test3_27 ); + cipher_ok ( &des_test3_28 ); + cipher_ok ( &des_test3_29 ); + cipher_ok ( &des_test3_30 ); + cipher_ok ( &des_test3_31 ); + cipher_ok ( &des_test3_32 ); + + /* Test 4: Key permutation tests */ + cipher_ok ( &des_test4_1 ); + cipher_ok ( &des_test4_2 ); + cipher_ok ( &des_test4_3 ); + cipher_ok ( &des_test4_4 ); + cipher_ok ( &des_test4_5 ); + cipher_ok ( &des_test4_6 ); + cipher_ok ( &des_test4_7 ); + cipher_ok ( &des_test4_8 ); + cipher_ok ( &des_test4_9 ); + cipher_ok ( &des_test4_10 ); + cipher_ok ( &des_test4_11 ); + cipher_ok ( &des_test4_12 ); + cipher_ok ( &des_test4_13 ); + cipher_ok ( &des_test4_14 ); + cipher_ok ( &des_test4_15 ); + cipher_ok ( &des_test4_16 ); + cipher_ok ( &des_test4_17 ); + cipher_ok ( &des_test4_18 ); + cipher_ok ( &des_test4_19 ); + cipher_ok ( &des_test4_20 ); + cipher_ok ( &des_test4_21 ); + cipher_ok ( &des_test4_22 ); + cipher_ok ( &des_test4_23 ); + cipher_ok ( &des_test4_24 ); + cipher_ok ( &des_test4_25 ); + cipher_ok ( &des_test4_26 ); + cipher_ok ( &des_test4_27 ); + cipher_ok ( &des_test4_28 ); + cipher_ok ( &des_test4_29 ); + cipher_ok ( &des_test4_30 ); + cipher_ok ( &des_test4_31 ); + cipher_ok ( &des_test4_32 ); + cipher_ok ( &des_test4_33 ); + cipher_ok ( &des_test4_34 ); + cipher_ok ( &des_test4_35 ); + cipher_ok ( &des_test4_36 ); + cipher_ok ( &des_test4_37 ); + cipher_ok ( &des_test4_38 ); + cipher_ok ( &des_test4_39 ); + cipher_ok ( &des_test4_40 ); + cipher_ok ( &des_test4_41 ); + cipher_ok ( &des_test4_42 ); + cipher_ok ( &des_test4_43 ); + cipher_ok ( &des_test4_44 ); + cipher_ok ( &des_test4_45 ); + cipher_ok ( &des_test4_46 ); + cipher_ok ( &des_test4_47 ); + cipher_ok ( &des_test4_48 ); + cipher_ok ( &des_test4_49 ); + cipher_ok ( &des_test4_50 ); + cipher_ok ( &des_test4_51 ); + cipher_ok ( &des_test4_52 ); + cipher_ok ( &des_test4_53 ); + cipher_ok ( &des_test4_54 ); + cipher_ok ( &des_test4_55 ); + cipher_ok ( &des_test4_56 ); + + /* Test 5: S-box tests */ + cipher_ok ( &des_test5_1 ); + cipher_ok ( &des_test5_2 ); + cipher_ok ( &des_test5_3 ); + cipher_ok ( &des_test5_4 ); + cipher_ok ( &des_test5_5 ); + cipher_ok ( &des_test5_6 ); + cipher_ok ( &des_test5_7 ); + cipher_ok ( &des_test5_8 ); + cipher_ok ( &des_test5_9 ); + cipher_ok ( &des_test5_10 ); + cipher_ok ( &des_test5_11 ); + cipher_ok ( &des_test5_12 ); + cipher_ok ( &des_test5_13 ); + cipher_ok ( &des_test5_14 ); + cipher_ok ( &des_test5_15 ); + cipher_ok ( &des_test5_16 ); + cipher_ok ( &des_test5_17 ); + cipher_ok ( &des_test5_18 ); + cipher_ok ( &des_test5_19 ); + + /* Multi-block tests */ + cipher_ok ( &des_unofficial_ecb ); + cipher_ok ( &des_unofficial_cbc ); + + /* Speed tests */ + DBG ( "DES-ECB encryption required %ld cycles per byte\n", + cipher_cost_encrypt ( &des_ecb_algorithm, 8 ) ); + DBG ( "DES-ECB decryption required %ld cycles per byte\n", + cipher_cost_decrypt ( &des_ecb_algorithm, 8 ) ); + DBG ( "DES-CBC encryption required %ld cycles per byte\n", + cipher_cost_encrypt ( &des_cbc_algorithm, 8 ) ); + DBG ( "DES-CBC decryption required %ld cycles per byte\n", + cipher_cost_decrypt ( &des_cbc_algorithm, 8 ) ); +} + +/** DES self-test */ +struct self_test des_test __self_test = { + .name = "des", + .exec = des_test_exec, +}; diff --git a/src/tests/tests.c b/src/tests/tests.c index 41c199c0..282d2eb6 100644 --- a/src/tests/tests.c +++ b/src/tests/tests.c @@ -82,3 +82,4 @@ REQUIRE_OBJECT ( dhe_test ); REQUIRE_OBJECT ( gcm_test ); REQUIRE_OBJECT ( nap_test ); REQUIRE_OBJECT ( x25519_test ); +REQUIRE_OBJECT ( des_test ); -- cgit v1.2.3-55-g7522 From a846c4ccfc7db212dff792e081991df17268b4d5 Mon Sep 17 00:00:00 2001 From: Joseph Wong Date: Wed, 7 Feb 2024 14:14:25 -0800 Subject: [bnxt] Add support for BCM957608 Add support for BCM957608 device. Add support for additional link speeds supported by BCM957608. Signed-off-by: Joseph Wong --- src/drivers/net/bnxt/bnxt.c | 375 +++++++++++++++++++++++++++++++--------- src/drivers/net/bnxt/bnxt.h | 211 +++++++++++++++++++++- src/drivers/net/bnxt/bnxt_dbg.h | 6 +- src/drivers/net/bnxt/bnxt_hsi.h | 229 +++++++++++++++++++++++- 4 files changed, 720 insertions(+), 101 deletions(-) diff --git a/src/drivers/net/bnxt/bnxt.c b/src/drivers/net/bnxt/bnxt.c index 5dd21797..a99f29ec 100644 --- a/src/drivers/net/bnxt/bnxt.c +++ b/src/drivers/net/bnxt/bnxt.c @@ -76,6 +76,7 @@ static struct pci_device_id bnxt_nics[] = { PCI_ROM( 0x14e4, 0x1801, "14e4-1801", "14e4-1801", 0 ), PCI_ROM( 0x14e4, 0x1804, "14e4-1804", "14e4-1804", 0 ), PCI_ROM( 0x14e4, 0x1752, "14e4-1752", "14e4-1752", 0 ), + PCI_ROM( 0x14e4, 0x1760, "14e4-1760", "14e4-1760", 0 ), PCI_ROM( 0x14e4, 0x1800, "14e4-1800", "14e4-1800", 0 ), PCI_ROM( 0x14e4, 0x1803, "14e4-1803", "14e4-1803", 0 ), PCI_ROM( 0x14e4, 0x1806, "14e4-1806", "14e4-1806", BNXT_FLAG_PCI_VF ), @@ -181,7 +182,7 @@ static void bnxt_set_link ( struct bnxt *bp ) netdev_link_down ( bp->dev ); } -static void thor_db ( struct bnxt *bp, u32 idx, u32 xid, u32 flag ) +static void dev_p5_db ( struct bnxt *bp, u32 idx, u32 xid, u32 flag ) { void *off; u64 val; @@ -196,10 +197,28 @@ static void thor_db ( struct bnxt *bp, u32 idx, u32 xid, u32 flag ) write64 ( val, off ); } +static void dev_p7_db ( struct bnxt *bp, u32 idx, u32 xid, u32 flag, u32 epoch, u32 toggle ) +{ + void *off; + u64 val; + + off = ( void * ) ( bp->bar1 ); + + val = ( ( u64 )DBC_MSG_XID ( xid, flag ) << 32 ) | + ( u64 )DBC_MSG_IDX ( idx ) | + ( u64 )DBC_MSG_EPCH ( epoch ) | + ( u64 )DBC_MSG_TOGGLE ( toggle ); + write64 ( val, off ); +} + static void bnxt_db_nq ( struct bnxt *bp ) { - if ( bp->thor ) - thor_db ( bp, ( u32 )bp->nq.cons_id, + if ( FLAG_TEST ( bp->flags, BNXT_FLAG_IS_CHIP_P7 ) ) + dev_p7_db ( bp, ( u32 )bp->nq.cons_id, + ( u32 )bp->nq_ring_id, DBC_DBC_TYPE_NQ_ARM, + ( u32 )bp->nq.epoch, 0 ); + else if ( FLAG_TEST ( bp->flags, BNXT_FLAG_IS_CHIP_P5 ) ) + dev_p5_db ( bp, ( u32 )bp->nq.cons_id, ( u32 )bp->nq_ring_id, DBC_DBC_TYPE_NQ_ARM ); else write32 ( CMPL_DOORBELL_KEY_CMPL, ( bp->bar1 + 0 ) ); @@ -207,8 +226,12 @@ static void bnxt_db_nq ( struct bnxt *bp ) static void bnxt_db_cq ( struct bnxt *bp ) { - if ( bp->thor ) - thor_db ( bp, ( u32 )bp->cq.cons_id, + if ( FLAG_TEST ( bp->flags, BNXT_FLAG_IS_CHIP_P7 ) ) + dev_p7_db ( bp, ( u32 )bp->cq.cons_id, + ( u32 )bp->cq_ring_id, DBC_DBC_TYPE_CQ_ARMALL, + ( u32 )bp->cq.epoch, ( u32 )bp->nq.toggle ); + else if ( FLAG_TEST ( bp->flags, BNXT_FLAG_IS_CHIP_P5 ) ) + dev_p5_db ( bp, ( u32 )bp->cq.cons_id, ( u32 )bp->cq_ring_id, DBC_DBC_TYPE_CQ_ARMALL ); else write32 ( CQ_DOORBELL_KEY_IDX ( bp->cq.cons_id ), @@ -217,16 +240,22 @@ static void bnxt_db_cq ( struct bnxt *bp ) static void bnxt_db_rx ( struct bnxt *bp, u32 idx ) { - if ( bp->thor ) - thor_db ( bp, idx, ( u32 )bp->rx_ring_id, DBC_DBC_TYPE_SRQ ); + if ( FLAG_TEST ( bp->flags, BNXT_FLAG_IS_CHIP_P7 ) ) + dev_p7_db ( bp, idx, ( u32 )bp->rx_ring_id, DBC_DBC_TYPE_SRQ, + ( u32 )bp->rx.epoch, 0 ); + else if ( FLAG_TEST ( bp->flags, BNXT_FLAG_IS_CHIP_P5 ) ) + dev_p5_db ( bp, idx, ( u32 )bp->rx_ring_id, DBC_DBC_TYPE_SRQ ); else write32 ( RX_DOORBELL_KEY_RX | idx, ( bp->bar1 + 0 ) ); } static void bnxt_db_tx ( struct bnxt *bp, u32 idx ) { - if ( bp->thor ) - thor_db ( bp, idx, ( u32 )bp->tx_ring_id, DBC_DBC_TYPE_SQ ); + if ( FLAG_TEST ( bp->flags, BNXT_FLAG_IS_CHIP_P7 ) ) + dev_p7_db ( bp, idx, ( u32 )bp->tx_ring_id, DBC_DBC_TYPE_SQ, + ( u32 )bp->tx.epoch, 0 ); + else if ( FLAG_TEST ( bp->flags, BNXT_FLAG_IS_CHIP_P5 ) ) + dev_p5_db ( bp, idx, ( u32 )bp->tx_ring_id, DBC_DBC_TYPE_SQ ); else write32 ( ( u32 ) ( TX_DOORBELL_KEY_TX | idx ), ( bp->bar1 + 0 ) ); @@ -253,6 +282,31 @@ static u16 bnxt_get_pkt_vlan ( char *src ) return 0; } +static u16 bnxt_get_rx_vlan ( struct rx_pkt_cmpl *rx_cmp, struct rx_pkt_cmpl_hi *rx_cmp_hi ) +{ + struct rx_pkt_v3_cmpl *rx_cmp_v3 = ( struct rx_pkt_v3_cmpl * )rx_cmp; + struct rx_pkt_v3_cmpl_hi *rx_cmp_hi_v3 = ( struct rx_pkt_v3_cmpl_hi * )rx_cmp_hi; + u16 rx_vlan; + + /* Get VLAN ID from RX completion ring */ + if ( ( rx_cmp_v3->flags_type & RX_PKT_V3_CMPL_TYPE_MASK ) == + RX_PKT_V3_CMPL_TYPE_RX_L2_V3 ) { + if ( rx_cmp_hi_v3->flags2 & RX_PKT_V3_CMPL_HI_FLAGS2_META_FORMAT_ACT_REC_PTR ) + rx_vlan = ( rx_cmp_hi_v3->metadata0 & + RX_PKT_V3_CMPL_HI_METADATA0_VID_MASK ); + else + rx_vlan = 0; + } else { + if ( rx_cmp_hi->flags2 & RX_PKT_CMPL_FLAGS2_META_FORMAT_VLAN ) + rx_vlan = ( rx_cmp_hi->metadata & + RX_PKT_CMPL_METADATA_VID_MASK ); + else + rx_vlan = 0; + } + + return rx_vlan; +} + int bnxt_vlan_drop ( struct bnxt *bp, u16 rx_vlan ) { if ( rx_vlan ) { @@ -382,6 +436,9 @@ int bnxt_post_rx_buffers ( struct bnxt *bp ) } } cons_id = NEXT_IDX ( cons_id, bp->rx.ring_cnt ); + /* If the ring has wrapped, flip the epoch bit */ + if ( iob_idx > cons_id ) + bp->rx.epoch ^= 1; bp->rx.iob_cnt++; } @@ -396,14 +453,21 @@ int bnxt_post_rx_buffers ( struct bnxt *bp ) } u8 bnxt_rx_drop ( struct bnxt *bp, struct io_buffer *iob, + struct rx_pkt_cmpl *rx_cmp, struct rx_pkt_cmpl_hi *rx_cmp_hi, u16 rx_len ) { + struct rx_pkt_v3_cmpl *rx_cmp_v3 = ( struct rx_pkt_v3_cmpl * )rx_cmp; + struct rx_pkt_v3_cmpl_hi *rx_cmp_hi_v3 = ( struct rx_pkt_v3_cmpl_hi * )rx_cmp_hi; u8 *rx_buf = ( u8 * )iob->data; u16 err_flags, rx_vlan; u8 ignore_chksum_err = 0; int i; - err_flags = rx_cmp_hi->errors_v2 >> RX_PKT_CMPL_ERRORS_BUFFER_ERROR_SFT; + if ( ( rx_cmp_v3->flags_type & RX_PKT_V3_CMPL_TYPE_MASK ) == + RX_PKT_V3_CMPL_TYPE_RX_L2_V3 ) { + err_flags = rx_cmp_hi_v3->errors_v2 >> RX_PKT_V3_CMPL_HI_ERRORS_BUFFER_ERROR_SFT; + } else + err_flags = rx_cmp_hi->errors_v2 >> RX_PKT_CMPL_ERRORS_BUFFER_ERROR_SFT; if ( rx_cmp_hi->errors_v2 == 0x20 || rx_cmp_hi->errors_v2 == 0x21 ) ignore_chksum_err = 1; @@ -423,13 +487,7 @@ u8 bnxt_rx_drop ( struct bnxt *bp, struct io_buffer *iob, return 2; } - /* Get VLAN ID from RX completion ring */ - if ( rx_cmp_hi->flags2 & RX_PKT_CMPL_FLAGS2_META_FORMAT_VLAN ) - rx_vlan = ( rx_cmp_hi->metadata & - RX_PKT_CMPL_METADATA_VID_MASK ); - else - rx_vlan = 0; - + rx_vlan = bnxt_get_rx_vlan ( rx_cmp, rx_cmp_hi ); dbg_rx_vlan ( bp, rx_cmp_hi->metadata, rx_cmp_hi->flags2, rx_vlan ); if ( bnxt_vlan_drop ( bp, rx_vlan ) ) { bp->rx.drop_vlan++; @@ -449,10 +507,11 @@ static void bnxt_adv_cq_index ( struct bnxt *bp, u16 cnt ) u16 cons_id; cons_id = bp->cq.cons_id + cnt; - if ( cons_id >= MAX_CQ_DESC_CNT ) { + if ( cons_id >= bp->cq.ring_cnt) { /* Toggle completion bit when the ring wraps. */ bp->cq.completion_bit ^= 1; - cons_id = cons_id - MAX_CQ_DESC_CNT; + bp->cq.epoch ^= 1; + cons_id = cons_id - bp->cq.ring_cnt; } bp->cq.cons_id = cons_id; } @@ -466,7 +525,7 @@ void bnxt_rx_process ( struct net_device *dev, struct bnxt *bp, dump_rx_bd ( rx_cmp, rx_cmp_hi, desc_idx ); assert ( !iob ); - drop = bnxt_rx_drop ( bp, iob, rx_cmp_hi, rx_cmp->len ); + drop = bnxt_rx_drop ( bp, iob, rx_cmp, rx_cmp_hi, rx_cmp->len ); dbg_rxp ( iob->data, rx_cmp->len, drop ); if ( drop ) netdev_rx_err ( dev, iob, -EINVAL ); @@ -531,12 +590,17 @@ void bnxt_mm_nic ( struct bnxt *bp ) memset ( bp->nq.bd_virt, 0, NQ_RING_BUFFER_SIZE ); bp->nq.cons_id = 0; bp->nq.completion_bit = 0x1; + bp->nq.epoch = 0; + bp->nq.toggle = 0; bp->cq.cons_id = 0; bp->cq.completion_bit = 0x1; + bp->cq.epoch = 0; bp->tx.prod_id = 0; bp->tx.cons_id = 0; + bp->tx.epoch = 0; bp->rx.cons_id = 0; bp->rx.iob_cnt = 0; + bp->rx.epoch = 0; bp->link_status = STATUS_LINK_DOWN; bp->wait_link_timeout = LINK_DEFAULT_TIMEOUT; @@ -724,8 +788,14 @@ static int bnxt_hwrm_ver_get ( struct bnxt *bp ) bp->hwrm_max_ext_req_len = resp->max_ext_req_len; if ( ( bp->chip_num == CHIP_NUM_57508 ) || ( bp->chip_num == CHIP_NUM_57504 ) || - ( bp->chip_num == CHIP_NUM_57502 ) ) - bp->thor = 1; + ( bp->chip_num == CHIP_NUM_57502 ) ) { + FLAG_SET ( bp->flags, BNXT_FLAG_IS_CHIP_P5 ); + FLAG_SET ( bp->flags, BNXT_FLAG_IS_CHIP_P5_PLUS ); + } + if ( bp->chip_num == CHIP_NUM_57608 ) { + FLAG_SET ( bp->flags, BNXT_FLAG_IS_CHIP_P7 ); + FLAG_SET ( bp->flags, BNXT_FLAG_IS_CHIP_P5_PLUS ); + } dbg_fw_ver ( resp, bp->hwrm_cmd_timeout ); return STATUS_SUCCESS; } @@ -917,6 +987,30 @@ static int bnxt_hwrm_func_qcfg_req ( struct bnxt *bp ) return STATUS_SUCCESS; } +static int bnxt_hwrm_port_phy_qcaps_req ( struct bnxt *bp ) +{ + u16 cmd_len = ( u16 )sizeof ( struct hwrm_port_phy_qcaps_input ); + struct hwrm_port_phy_qcaps_input *req; + struct hwrm_port_phy_qcaps_output *resp; + int rc; + + DBGP ( "%s\n", __func__ ); + + req = ( struct hwrm_port_phy_qcaps_input * )bp->hwrm_addr_req; + resp = ( struct hwrm_port_phy_qcaps_output * )bp->hwrm_addr_resp; + hwrm_init ( bp, ( void * )req, ( u16 )HWRM_PORT_PHY_QCAPS, cmd_len ); + rc = wait_resp ( bp, bp->hwrm_cmd_timeout, cmd_len, __func__ ); + if ( rc ) { + DBGP ( "-s %s ( ): Failed\n", __func__ ); + return STATUS_FAILURE; + } + + if ( resp->flags2 & PORT_PHY_QCAPS_RESP_FLAGS2_SPEEDS2_SUPPORTED ) + FLAG_SET ( bp->flags, BNXT_FLAG_LINK_SPEEDS2 ); + + return STATUS_SUCCESS; +} + static int bnxt_hwrm_func_reset_req ( struct bnxt *bp ) { u16 cmd_len = ( u16 )sizeof ( struct hwrm_func_reset_input ); @@ -944,7 +1038,7 @@ static int bnxt_hwrm_func_cfg_req ( struct bnxt *bp ) hwrm_init ( bp, ( void * )req, ( u16 )HWRM_FUNC_CFG, cmd_len ); req->fid = ( u16 )HWRM_NA_SIGNATURE; bnxt_hwrm_assign_resources ( bp ); - if ( bp->thor ) { + if ( FLAG_TEST ( bp->flags, BNXT_FLAG_IS_CHIP_P5_PLUS ) ) { req->enables |= ( FUNC_CFG_REQ_ENABLES_NUM_MSIX | FUNC_CFG_REQ_ENABLES_NUM_VNICS | FUNC_CFG_REQ_ENABLES_EVB_MODE ); @@ -1011,7 +1105,7 @@ static int bnxt_hwrm_set_async_event ( struct bnxt *bp ) u16 idx; DBGP ( "%s\n", __func__ ); - if ( bp->thor ) + if ( FLAG_TEST ( bp->flags, BNXT_FLAG_IS_CHIP_P5_PLUS ) ) idx = bp->nq_ring_id; else idx = bp->cq_ring_id; @@ -1162,6 +1256,10 @@ static int bnxt_hwrm_port_phy_qcfg ( struct bnxt *bp, u16 idx ) if ( idx & SUPPORT_SPEEDS ) bp->support_speeds = resp->support_speeds; + if ( idx & SUPPORT_SPEEDS2 ) + if ( FLAG_TEST ( bp->flags, BNXT_FLAG_LINK_SPEEDS2 ) ) + bp->auto_link_speeds2_mask = resp->auto_link_speeds2; + if ( idx & DETECT_MEDIA ) bp->media_detect = resp->module_status; @@ -1201,22 +1299,24 @@ static int bnxt_get_link_speed ( struct bnxt *bp ) u32 *ptr32 = ( u32 * )bp->hwrm_addr_dma; DBGP ( "%s\n", __func__ ); - test_if ( bnxt_hwrm_nvm_get_variable_req ( bp, 4, - ( u16 )LINK_SPEED_DRV_NUM, - 1, ( u16 )bp->port_idx ) != STATUS_SUCCESS ) - return STATUS_FAILURE; - bp->link_set = SET_LINK ( *ptr32, SPEED_DRV_MASK, SPEED_DRV_SHIFT ); + if ( ! ( FLAG_TEST (bp->flags, BNXT_FLAG_IS_CHIP_P7 ) ) ) { + test_if ( bnxt_hwrm_nvm_get_variable_req ( bp, 4, + ( u16 )LINK_SPEED_DRV_NUM, + 1, ( u16 )bp->port_idx ) != STATUS_SUCCESS ) + return STATUS_FAILURE; + bp->link_set = SET_LINK ( *ptr32, SPEED_DRV_MASK, SPEED_DRV_SHIFT ); + test_if ( bnxt_hwrm_nvm_get_variable_req ( bp, 4, + ( u16 )D3_LINK_SPEED_FW_NUM, 1, + ( u16 )bp->port_idx ) != STATUS_SUCCESS ) + return STATUS_FAILURE; + bp->link_set |= SET_LINK ( *ptr32, D3_SPEED_FW_MASK, + D3_SPEED_FW_SHIFT ); + } test_if ( bnxt_hwrm_nvm_get_variable_req ( bp, 4, ( u16 )LINK_SPEED_FW_NUM, 1, ( u16 )bp->port_idx ) != STATUS_SUCCESS ) return STATUS_FAILURE; bp->link_set |= SET_LINK ( *ptr32, SPEED_FW_MASK, SPEED_FW_SHIFT ); - test_if ( bnxt_hwrm_nvm_get_variable_req ( bp, 4, - ( u16 )D3_LINK_SPEED_FW_NUM, 1, - ( u16 )bp->port_idx ) != STATUS_SUCCESS ) - return STATUS_FAILURE; - bp->link_set |= SET_LINK ( *ptr32, D3_SPEED_FW_MASK, - D3_SPEED_FW_SHIFT ); test_if ( bnxt_hwrm_nvm_get_variable_req ( bp, 1, ( u16 )PORT_CFG_LINK_SETTINGS_MEDIA_AUTO_DETECT_NUM, 1, ( u16 )bp->port_idx ) != STATUS_SUCCESS ) @@ -1224,32 +1324,51 @@ static int bnxt_get_link_speed ( struct bnxt *bp ) bp->link_set |= SET_LINK ( *ptr32, MEDIA_AUTO_DETECT_MASK, MEDIA_AUTO_DETECT_SHIFT ); - switch ( bp->link_set & LINK_SPEED_DRV_MASK ) { - case LINK_SPEED_DRV_1G: + /* Use LINK_SPEED_FW_xxx which is valid for CHIP_P7 and earlier devices */ + switch ( bp->link_set & LINK_SPEED_FW_MASK ) { + case LINK_SPEED_FW_1G: bp->medium = SET_MEDIUM_SPEED ( bp, MEDIUM_SPEED_1000MBPS ); break; - case LINK_SPEED_DRV_2_5G: + case LINK_SPEED_FW_2_5G: bp->medium = SET_MEDIUM_SPEED ( bp, MEDIUM_SPEED_2500MBPS ); break; - case LINK_SPEED_DRV_10G: + case LINK_SPEED_FW_10G: bp->medium = SET_MEDIUM_SPEED ( bp, MEDIUM_SPEED_10GBPS ); break; - case LINK_SPEED_DRV_25G: + case LINK_SPEED_FW_25G: bp->medium = SET_MEDIUM_SPEED ( bp, MEDIUM_SPEED_25GBPS ); break; - case LINK_SPEED_DRV_40G: + case LINK_SPEED_FW_40G: bp->medium = SET_MEDIUM_SPEED ( bp, MEDIUM_SPEED_40GBPS ); break; - case LINK_SPEED_DRV_50G: + case LINK_SPEED_FW_50G: bp->medium = SET_MEDIUM_SPEED ( bp, MEDIUM_SPEED_50GBPS ); break; - case LINK_SPEED_DRV_100G: + case LINK_SPEED_FW_50G_PAM4: + bp->medium = SET_MEDIUM_SPEED ( bp, MEDIUM_SPEED_50PAM4GBPS ); + break; + case LINK_SPEED_FW_100G: bp->medium = SET_MEDIUM_SPEED ( bp, MEDIUM_SPEED_100GBPS ); break; - case LINK_SPEED_DRV_200G: + case LINK_SPEED_FW_100G_PAM4: + bp->medium = SET_MEDIUM_SPEED ( bp, MEDIUM_SPEED_100PAM4GBPS ); + break; + case LINK_SPEED_FW_100G_PAM4_112: + bp->medium = SET_MEDIUM_SPEED ( bp, MEDIUM_SPEED_100PAM4_112GBPS ); + break; + case LINK_SPEED_FW_200G: bp->medium = SET_MEDIUM_SPEED ( bp, MEDIUM_SPEED_200GBPS ); break; - case LINK_SPEED_DRV_AUTONEG: + case LINK_SPEED_FW_200G_PAM4_112: + bp->medium = SET_MEDIUM_SPEED ( bp, MEDIUM_SPEED_200PAM4_112GBPS ); + break; + case LINK_SPEED_FW_400G_PAM4: + bp->medium = SET_MEDIUM_SPEED ( bp, MEDIUM_SPEED_400PAM4GBPS ); + break; + case LINK_SPEED_FW_400G_PAM4_112: + bp->medium = SET_MEDIUM_SPEED ( bp, MEDIUM_SPEED_400PAM4_112GBPS ); + break; + case LINK_SPEED_FW_AUTONEG: bp->medium = SET_MEDIUM_SPEED ( bp, MEDIUM_SPEED_AUTONEG ); break; default: @@ -1268,27 +1387,29 @@ static int bnxt_get_vlan ( struct bnxt *bp ) if ( bp->vf ) return STATUS_SUCCESS; - test_if ( bnxt_hwrm_nvm_get_variable_req ( bp, 1, - ( u16 )FUNC_CFG_PRE_BOOT_MBA_VLAN_NUM, 1, - ( u16 )bp->ordinal_value ) != STATUS_SUCCESS ) - return STATUS_FAILURE; + if ( ! ( FLAG_TEST ( bp->flags, BNXT_FLAG_IS_CHIP_P7 ) ) ) { + test_if ( bnxt_hwrm_nvm_get_variable_req ( bp, 1, + ( u16 )FUNC_CFG_PRE_BOOT_MBA_VLAN_NUM, 1, + ( u16 )bp->ordinal_value ) != STATUS_SUCCESS ) + return STATUS_FAILURE; - bp->mba_cfg2 = SET_MBA ( *ptr32, VLAN_MASK, VLAN_SHIFT ); - test_if ( bnxt_hwrm_nvm_get_variable_req ( bp, 16, - ( u16 )FUNC_CFG_PRE_BOOT_MBA_VLAN_VALUE_NUM, 1, - ( u16 )bp->ordinal_value ) != STATUS_SUCCESS ) - return STATUS_FAILURE; + bp->mba_cfg2 = SET_MBA ( *ptr32, VLAN_MASK, VLAN_SHIFT ); + test_if ( bnxt_hwrm_nvm_get_variable_req ( bp, 16, + ( u16 )FUNC_CFG_PRE_BOOT_MBA_VLAN_VALUE_NUM, 1, + ( u16 )bp->ordinal_value ) != STATUS_SUCCESS ) + return STATUS_FAILURE; - bp->mba_cfg2 |= SET_MBA ( *ptr32, VLAN_VALUE_MASK, VLAN_VALUE_SHIFT ); - if ( bp->mba_cfg2 & FUNC_CFG_PRE_BOOT_MBA_VLAN_ENABLED ) - bp->vlan_id = bp->mba_cfg2 & VLAN_VALUE_MASK; - else - bp->vlan_id = 0; + bp->mba_cfg2 |= SET_MBA ( *ptr32, VLAN_VALUE_MASK, VLAN_VALUE_SHIFT ); + if ( bp->mba_cfg2 & FUNC_CFG_PRE_BOOT_MBA_VLAN_ENABLED ) + bp->vlan_id = bp->mba_cfg2 & VLAN_VALUE_MASK; + else + bp->vlan_id = 0; - if ( bp->mba_cfg2 & FUNC_CFG_PRE_BOOT_MBA_VLAN_ENABLED ) - DBGP ( "VLAN MBA Enabled ( %d )\n", - ( bp->mba_cfg2 & VLAN_VALUE_MASK ) ); + if ( bp->mba_cfg2 & FUNC_CFG_PRE_BOOT_MBA_VLAN_ENABLED ) + DBGP ( "VLAN MBA Enabled ( %d )\n", + ( bp->mba_cfg2 & VLAN_VALUE_MASK ) ); + } return STATUS_SUCCESS; } @@ -1298,7 +1419,7 @@ static int bnxt_hwrm_backing_store_qcfg ( struct bnxt *bp ) struct hwrm_func_backing_store_qcfg_input *req; DBGP ( "%s\n", __func__ ); - if ( !bp->thor ) + if ( ! ( FLAG_TEST ( bp->flags, BNXT_FLAG_IS_CHIP_P5_PLUS ) ) ) return STATUS_SUCCESS; req = ( struct hwrm_func_backing_store_qcfg_input * )bp->hwrm_addr_req; @@ -1313,7 +1434,7 @@ static int bnxt_hwrm_backing_store_cfg ( struct bnxt *bp ) struct hwrm_func_backing_store_cfg_input *req; DBGP ( "%s\n", __func__ ); - if ( !bp->thor ) + if ( ! ( FLAG_TEST ( bp->flags, BNXT_FLAG_IS_CHIP_P5_PLUS ) ) ) return STATUS_SUCCESS; req = ( struct hwrm_func_backing_store_cfg_input * )bp->hwrm_addr_req; @@ -1332,7 +1453,7 @@ static int bnxt_hwrm_queue_qportcfg ( struct bnxt *bp ) int rc; DBGP ( "%s\n", __func__ ); - if ( !bp->thor ) + if ( ! ( FLAG_TEST ( bp->flags, BNXT_FLAG_IS_CHIP_P5_PLUS ) ) ) return STATUS_SUCCESS; req = ( struct hwrm_queue_qportcfg_input * )bp->hwrm_addr_req; @@ -1372,7 +1493,10 @@ static int bnxt_hwrm_port_phy_cfg ( struct bnxt *bp ) u32 flags; u32 enables = 0; u16 force_link_speed = 0; + u16 force_link_speeds2 = 0; + u16 force_pam4_link_speed = 0; u16 auto_link_speed_mask = 0; + u16 auto_link_speeds2_mask = 0; u8 auto_mode = 0; u8 auto_pause = 0; u8 auto_duplex = 0; @@ -1387,34 +1511,111 @@ static int bnxt_hwrm_port_phy_cfg ( struct bnxt *bp ) force_link_speed = PORT_PHY_CFG_REQ_FORCE_LINK_SPEED_1GB; break; case MEDIUM_SPEED_10GBPS: - force_link_speed = PORT_PHY_CFG_REQ_FORCE_LINK_SPEED_10GB; + if ( FLAG_TEST ( bp->flags, BNXT_FLAG_LINK_SPEEDS2 ) ) { + force_link_speeds2 = PORT_PHY_CFG_REQ_FORCE_LINK_SPEEDS2_10GB; + enables |= PORT_PHY_CFG_REQ_ENABLES_FORCE_LINK_SPEEDS2; + } else { + force_link_speed = PORT_PHY_CFG_REQ_FORCE_LINK_SPEED_10GB; + } break; case MEDIUM_SPEED_25GBPS: - force_link_speed = PORT_PHY_CFG_REQ_FORCE_LINK_SPEED_25GB; + if ( FLAG_TEST ( bp->flags, BNXT_FLAG_LINK_SPEEDS2 ) ) { + force_link_speeds2 = PORT_PHY_CFG_REQ_FORCE_LINK_SPEEDS2_25GB; + enables |= PORT_PHY_CFG_REQ_ENABLES_FORCE_LINK_SPEEDS2; + } else { + force_link_speed = PORT_PHY_CFG_REQ_FORCE_LINK_SPEED_25GB; + } break; case MEDIUM_SPEED_40GBPS: - force_link_speed = PORT_PHY_CFG_REQ_FORCE_LINK_SPEED_40GB; + if ( FLAG_TEST ( bp->flags, BNXT_FLAG_LINK_SPEEDS2 ) ) { + force_link_speeds2 = PORT_PHY_CFG_REQ_FORCE_LINK_SPEEDS2_40GB; + enables |= PORT_PHY_CFG_REQ_ENABLES_FORCE_LINK_SPEEDS2; + } else { + force_link_speed = PORT_PHY_CFG_REQ_FORCE_LINK_SPEED_40GB; + } break; case MEDIUM_SPEED_50GBPS: - force_link_speed = PORT_PHY_CFG_REQ_FORCE_LINK_SPEED_50GB; + if ( FLAG_TEST ( bp->flags, BNXT_FLAG_LINK_SPEEDS2 ) ) { + force_link_speeds2 = PORT_PHY_CFG_REQ_FORCE_LINK_SPEEDS2_50GB; + enables |= PORT_PHY_CFG_REQ_ENABLES_FORCE_LINK_SPEEDS2; + } else { + force_link_speed = PORT_PHY_CFG_REQ_FORCE_LINK_SPEED_50GB; + } + break; + case MEDIUM_SPEED_50PAM4GBPS: + if ( FLAG_TEST ( bp->flags, BNXT_FLAG_LINK_SPEEDS2 ) ) { + force_link_speeds2 = PORT_PHY_CFG_REQ_FORCE_LINK_SPEEDS2_50GB_PAM4_56; + enables |= PORT_PHY_CFG_REQ_ENABLES_FORCE_LINK_SPEEDS2; + } else { + force_pam4_link_speed = PORT_PHY_CFG_REQ_FORCE_PAM4_LINK_SPEED_50GB; + enables |= PORT_PHY_CFG_REQ_ENABLES_FORCE_PAM4_LINK_SPEED; + } break; case MEDIUM_SPEED_100GBPS: - force_link_speed = PORT_PHY_CFG_REQ_FORCE_LINK_SPEED_100GB; + if ( FLAG_TEST ( bp->flags, BNXT_FLAG_LINK_SPEEDS2 ) ) { + force_link_speeds2 = PORT_PHY_CFG_REQ_FORCE_LINK_SPEEDS2_100GB; + enables |= PORT_PHY_CFG_REQ_ENABLES_FORCE_LINK_SPEEDS2; + } else { + force_link_speed = PORT_PHY_CFG_REQ_FORCE_LINK_SPEED_100GB; + } + break; + case MEDIUM_SPEED_100PAM4GBPS: + if ( FLAG_TEST ( bp->flags, BNXT_FLAG_LINK_SPEEDS2 ) ) { + force_link_speeds2 = PORT_PHY_CFG_REQ_FORCE_LINK_SPEEDS2_100GB_PAM4_56; + enables |= PORT_PHY_CFG_REQ_ENABLES_FORCE_LINK_SPEEDS2; + } else { + force_pam4_link_speed = PORT_PHY_CFG_REQ_FORCE_PAM4_LINK_SPEED_100GB; + enables |= PORT_PHY_CFG_REQ_ENABLES_FORCE_PAM4_LINK_SPEED; + } + break; + case MEDIUM_SPEED_100PAM4_112GBPS: + if ( FLAG_TEST ( bp->flags, BNXT_FLAG_LINK_SPEEDS2 ) ) { + force_link_speeds2 = PORT_PHY_CFG_REQ_FORCE_LINK_SPEEDS2_100GB_PAM4_112; + enables |= PORT_PHY_CFG_REQ_ENABLES_FORCE_LINK_SPEEDS2; + } break; case MEDIUM_SPEED_200GBPS: - force_link_speed = PORT_PHY_CFG_REQ_FORCE_LINK_SPEED_200GB; + if ( FLAG_TEST ( bp->flags, BNXT_FLAG_LINK_SPEEDS2 ) ) { + force_link_speeds2 = PORT_PHY_CFG_REQ_FORCE_LINK_SPEEDS2_200GB_PAM4_56; + enables |= PORT_PHY_CFG_REQ_ENABLES_FORCE_LINK_SPEEDS2; + } else { + force_pam4_link_speed = PORT_PHY_CFG_REQ_FORCE_PAM4_LINK_SPEED_200GB; + enables |= PORT_PHY_CFG_REQ_ENABLES_FORCE_PAM4_LINK_SPEED; + } + break; + case MEDIUM_SPEED_200PAM4_112GBPS: + if ( FLAG_TEST ( bp->flags, BNXT_FLAG_LINK_SPEEDS2 ) ) { + force_link_speeds2 = PORT_PHY_CFG_REQ_FORCE_LINK_SPEEDS2_200GB_PAM4_112; + enables |= PORT_PHY_CFG_REQ_ENABLES_FORCE_LINK_SPEEDS2; + } + break; + case MEDIUM_SPEED_400PAM4GBPS: + if ( FLAG_TEST ( bp->flags, BNXT_FLAG_LINK_SPEEDS2 ) ) { + force_link_speeds2 = PORT_PHY_CFG_REQ_FORCE_LINK_SPEEDS2_400GB_PAM4_56; + enables |= PORT_PHY_CFG_REQ_ENABLES_FORCE_LINK_SPEEDS2; + } break; + case MEDIUM_SPEED_400PAM4_112GBPS: + if ( FLAG_TEST ( bp->flags, BNXT_FLAG_LINK_SPEEDS2 ) ) { + force_link_speeds2 = PORT_PHY_CFG_REQ_FORCE_LINK_SPEEDS2_400GB_PAM4_112; + enables |= PORT_PHY_CFG_REQ_ENABLES_FORCE_LINK_SPEEDS2; + } + break; default: auto_mode = PORT_PHY_CFG_REQ_AUTO_MODE_SPEED_MASK; flags &= ~PORT_PHY_CFG_REQ_FLAGS_FORCE; enables |= PORT_PHY_CFG_REQ_ENABLES_AUTO_MODE | - PORT_PHY_CFG_REQ_ENABLES_AUTO_LINK_SPEED_MASK | PORT_PHY_CFG_REQ_ENABLES_AUTO_DUPLEX | PORT_PHY_CFG_REQ_ENABLES_AUTO_PAUSE; + if ( FLAG_TEST (bp->flags, BNXT_FLAG_LINK_SPEEDS2 ) ) + enables |= PORT_PHY_CFG_REQ_ENABLES_AUTO_LINK_SPEEDS2_MASK; + else + enables |= PORT_PHY_CFG_REQ_ENABLES_AUTO_LINK_SPEED_MASK; auto_pause = PORT_PHY_CFG_REQ_AUTO_PAUSE_TX | PORT_PHY_CFG_REQ_AUTO_PAUSE_RX; auto_duplex = PORT_PHY_CFG_REQ_AUTO_DUPLEX_BOTH; auto_link_speed_mask = bp->support_speeds; + auto_link_speeds2_mask = bp->auto_link_speeds2_mask; break; } @@ -1423,10 +1624,13 @@ static int bnxt_hwrm_port_phy_cfg ( struct bnxt *bp ) req->enables = enables; req->port_id = bp->port_idx; req->force_link_speed = force_link_speed; + req->force_pam4_link_speed = force_pam4_link_speed; + req->force_link_speeds2 = force_link_speeds2; req->auto_mode = auto_mode; req->auto_duplex = auto_duplex; req->auto_pause = auto_pause; req->auto_link_speed_mask = auto_link_speed_mask; + req->auto_link_speeds2_mask = auto_link_speeds2_mask; return wait_resp ( bp, bp->hwrm_cmd_timeout, cmd_len, __func__ ); } @@ -1565,7 +1769,7 @@ static int bnxt_hwrm_ring_alloc_grp ( struct bnxt *bp ) int rc; DBGP ( "%s\n", __func__ ); - if ( bp->thor ) + if ( FLAG_TEST ( bp->flags, BNXT_FLAG_IS_CHIP_P5_PLUS ) ) return STATUS_SUCCESS; req = ( struct hwrm_ring_grp_alloc_input * )bp->hwrm_addr_req; @@ -1616,7 +1820,7 @@ static int bnxt_hwrm_ring_alloc ( struct bnxt *bp, u8 type ) switch ( type ) { case RING_ALLOC_REQ_RING_TYPE_NQ: req->page_size = LM_PAGE_BITS ( 12 ); - req->int_mode = BNXT_CQ_INTR_MODE ( bp->vf ); + req->int_mode = BNXT_CQ_INTR_MODE ( ( (FLAG_TEST ( bp->flags, BNXT_FLAG_IS_CHIP_P7) ) || bp->vf ) ); req->length = ( u32 )bp->nq.ring_cnt; req->logical_id = 0xFFFF; // Required value for Thor FW? req->page_tbl_addr = virt_to_bus ( bp->nq.bd_virt ); @@ -1626,7 +1830,7 @@ static int bnxt_hwrm_ring_alloc ( struct bnxt *bp, u8 type ) req->int_mode = BNXT_CQ_INTR_MODE ( bp->vf ); req->length = ( u32 )bp->cq.ring_cnt; req->page_tbl_addr = virt_to_bus ( bp->cq.bd_virt ); - if ( !bp->thor ) + if ( ! ( FLAG_TEST ( bp->flags, BNXT_FLAG_IS_CHIP_P5_PLUS ) ) ) break; req->enables = RING_ALLOC_REQ_ENABLES_NQ_RING_ID_VALID; req->nq_ring_id = bp->nq_ring_id; @@ -1648,7 +1852,7 @@ static int bnxt_hwrm_ring_alloc ( struct bnxt *bp, u8 type ) req->stat_ctx_id = ( u32 )STAT_CTX_ID; req->cmpl_ring_id = bp->cq_ring_id; req->page_tbl_addr = virt_to_bus ( bp->rx.bd_virt ); - if ( !bp->thor ) + if ( ! ( FLAG_TEST ( bp->flags, BNXT_FLAG_IS_CHIP_P5_PLUS ) ) ) break; req->queue_id = ( u16 )RX_RING_QID; req->rx_buf_size = MAX_ETHERNET_PACKET_BUFFER_SIZE; @@ -1744,7 +1948,7 @@ static int bnxt_hwrm_ring_free_rx ( struct bnxt *bp ) static int bnxt_hwrm_ring_alloc_nq ( struct bnxt *bp ) { - if ( !bp->thor ) + if ( ! ( FLAG_TEST ( bp->flags, BNXT_FLAG_IS_CHIP_P5_PLUS ) ) ) return STATUS_SUCCESS; return bnxt_hwrm_ring_alloc ( bp, RING_ALLOC_REQ_RING_TYPE_NQ ); } @@ -1753,7 +1957,7 @@ static int bnxt_hwrm_ring_free_nq ( struct bnxt *bp ) { int ret = STATUS_SUCCESS; - if ( !bp->thor ) + if ( ! ( FLAG_TEST ( bp->flags, BNXT_FLAG_IS_CHIP_P5_PLUS ) ) ) return STATUS_SUCCESS; DBGP ( "%s\n", __func__ ); @@ -1824,7 +2028,7 @@ static int bnxt_hwrm_vnic_cfg ( struct bnxt *bp ) req->enables = VNIC_CFG_REQ_ENABLES_MRU; req->mru = bp->mtu; - if ( bp->thor ) { + if ( FLAG_TEST ( bp->flags, BNXT_FLAG_IS_CHIP_P5_PLUS ) ) { req->enables |= ( VNIC_CFG_REQ_ENABLES_DEFAULT_RX_RING_ID | VNIC_CFG_REQ_ENABLES_DEFAULT_CMPL_RING_ID ); req->default_rx_ring_id = bp->rx_ring_id; @@ -1878,6 +2082,7 @@ hwrm_func_t bring_up_chip[] = { bnxt_hwrm_backing_store_cfg, /* HWRM_FUNC_BACKING_STORE_CFG */ bnxt_hwrm_backing_store_qcfg, /* HWRM_FUNC_BACKING_STORE_QCFG */ bnxt_hwrm_func_resource_qcaps, /* HWRM_FUNC_RESOURCE_QCAPS */ + bnxt_hwrm_port_phy_qcaps_req, /* HWRM_PORT_PHY_QCAPS */ bnxt_hwrm_func_qcfg_req, /* HWRM_FUNC_QCFG */ bnxt_get_vlan, /* HWRM_NVM_GET_VARIABLE - vlan */ bnxt_hwrm_port_mac_cfg, /* HWRM_PORT_MAC_CFG */ @@ -1970,6 +2175,9 @@ static int bnxt_tx ( struct net_device *dev, struct io_buffer *iob ) bp->tx.iob[entry] = iob; bnxt_set_txq ( bp, entry, mapping, len ); entry = NEXT_IDX ( entry, bp->tx.ring_cnt ); + /* If the ring has wrapped, toggle the epoch bit */ + if ( bp->tx.prod_id > entry ) + bp->tx.epoch ^= 1; dump_tx_pkt ( ( u8 * )iob->data, len, bp->tx.prod_id ); /* Packets are ready, update Tx producer idx local and on card. */ bnxt_db_tx ( bp, ( u32 )entry ); @@ -1988,6 +2196,7 @@ static void bnxt_adv_nq_index ( struct bnxt *bp, u16 cnt ) if ( cons_id >= bp->nq.ring_cnt ) { /* Toggle completion bit when the ring wraps. */ bp->nq.completion_bit ^= 1; + bp->nq.epoch ^= 1; cons_id = cons_id - bp->nq.ring_cnt; } bp->nq.cons_id = cons_id; @@ -2028,7 +2237,7 @@ static void bnxt_service_cq ( struct net_device *dev ) cq_type = cmp->type & CMPL_BASE_TYPE_MASK; dump_evt ( ( u8 * )cmp, cq_type, bp->cq.cons_id, 0 ); - dump_cq ( cmp, bp->cq.cons_id ); + dump_cq ( cmp, bp->cq.cons_id, bp->nq.toggle ); switch ( cq_type ) { case CMPL_BASE_TYPE_TX_L2: @@ -2039,6 +2248,7 @@ static void bnxt_service_cq ( struct net_device *dev ) bnxt_adv_cq_index ( bp, 1 ); break; case CMPL_BASE_TYPE_RX_L2: + case CMPL_BASE_TYPE_RX_L2_V3: done = bnxt_rx_complete ( dev, ( struct rx_pkt_cmpl * )cmp ); break; @@ -2065,7 +2275,7 @@ static void bnxt_service_nq ( struct net_device *dev ) int done = SERVICE_NEXT_NQ_BD; u32 nq_type; - if ( !bp->thor ) + if ( ! ( FLAG_TEST ( bp->flags, BNXT_FLAG_IS_CHIP_P5_PLUS ) ) ) return; while ( done == SERVICE_NEXT_NQ_BD ) { @@ -2074,6 +2284,7 @@ static void bnxt_service_nq ( struct net_device *dev ) if ( ( nqp->v & NQ_CN_V ) ^ bp->nq.completion_bit ) break; nq_type = ( nqp->type & NQ_CN_TYPE_MASK ); + bp->nq.toggle = ( ( nqp->type & NQ_CN_TOGGLE_MASK ) >> NQ_CN_TOGGLE_SFT ); dump_evt ( ( u8 * )nqp, nq_type, bp->nq.cons_id, 1 ); dump_nq ( nqp, bp->nq.cons_id ); @@ -2098,8 +2309,8 @@ static void bnxt_service_nq ( struct net_device *dev ) static void bnxt_poll ( struct net_device *dev ) { mb ( ); - bnxt_service_cq ( dev ); bnxt_service_nq ( dev ); + bnxt_service_cq ( dev ); } static void bnxt_close ( struct net_device *dev ) diff --git a/src/drivers/net/bnxt/bnxt.h b/src/drivers/net/bnxt/bnxt.h index cf2dea8b..8c8a3328 100644 --- a/src/drivers/net/bnxt/bnxt.h +++ b/src/drivers/net/bnxt/bnxt.h @@ -52,6 +52,10 @@ union dma_addr64_t { #define BNXT_FLAG_NPAR_MODE 0x0010 #define BNXT_FLAG_ATOMICS_ENABLE 0x0020 #define BNXT_FLAG_PCI_VF 0x0040 +#define BNXT_FLAG_LINK_SPEEDS2 0x0080 +#define BNXT_FLAG_IS_CHIP_P5 0x0100 +#define BNXT_FLAG_IS_CHIP_P5_PLUS 0x0200 +#define BNXT_FLAG_IS_CHIP_P7 0x0400 /******************************************************************************* * Status codes. ******************************************************************************/ @@ -106,6 +110,12 @@ union dma_addr64_t { #define MEDIUM_SPEED_50GBPS 0x0a00L #define MEDIUM_SPEED_100GBPS 0x0b00L #define MEDIUM_SPEED_200GBPS 0x0c00L +#define MEDIUM_SPEED_50PAM4GBPS 0x0d00L +#define MEDIUM_SPEED_100PAM4GBPS 0x0e00L +#define MEDIUM_SPEED_100PAM4_112GBPS 0x0f00L +#define MEDIUM_SPEED_200PAM4_112GBPS 0x1000L +#define MEDIUM_SPEED_400PAM4GBPS 0x2000L +#define MEDIUM_SPEED_400PAM4_112GBPS 0x3000L #define MEDIUM_SPEED_AUTONEG_1G_FALLBACK 0x8000L /* Serdes */ #define MEDIUM_SPEED_AUTONEG_2_5G_FALLBACK 0x8100L /* Serdes */ #define MEDIUM_SPEED_HARDWARE_DEFAULT 0xff00L /* Serdes nvram def.*/ @@ -168,9 +178,9 @@ union dma_addr64_t { RX_MASK_ACCEPT_MULTICAST) #define MAX_NQ_DESC_CNT 64 #define NQ_RING_BUFFER_SIZE (MAX_NQ_DESC_CNT * sizeof(struct cmpl_base)) -#define TX_RING_QID (bp->thor ? (u16)bp->queue_id : ((u16)bp->port_idx * 10)) -#define RX_RING_QID (bp->thor ? bp->queue_id : 0) -#define STAT_CTX_ID ((bp->vf || bp->thor) ? bp->stat_ctx_id : 0) +#define TX_RING_QID (FLAG_TEST(bp->flags, BNXT_FLAG_IS_CHIP_P5_PLUS) ? (u16)bp->queue_id : ((u16)bp->port_idx * 10)) +#define RX_RING_QID (FLAG_TEST(bp->flags, BNXT_FLAG_IS_CHIP_P5_PLUS) ? bp->queue_id : 0) +#define STAT_CTX_ID ((bp->vf || FLAG_TEST(bp->flags, BNXT_FLAG_IS_CHIP_P5_PLUS)) ? bp->stat_ctx_id : 0) #define TX_AVAIL(r) (r - 1) #define TX_IN_USE(a, b, c) ((a - b) & (c - 1)) #define NO_MORE_NQ_BD_TO_SERVICE 1 @@ -189,13 +199,19 @@ union dma_addr64_t { ((idx) << DBC_DBC_INDEX_SFT) & DBC_DBC_INDEX_MASK) #define DBC_MSG_XID(xid, flg) (\ (((xid) << DBC_DBC_XID_SFT) & DBC_DBC_XID_MASK) | \ - DBC_DBC_PATH_L2 | (flg)) + DBC_DBC_PATH_L2 | (FLAG_TEST ( bp->flags, BNXT_FLAG_IS_CHIP_P7 ) ? DBC_DBC_VALID : 0) | (flg)) +#define DBC_MSG_EPCH(idx) (\ + ((idx) << DBC_DBC_EPOCH_SFT)) +#define DBC_MSG_TOGGLE(idx) (\ + ((idx) << DBC_DBC_TOGGLE_SFT) & DBC_DBC_TOGGLE_MASK) #define PHY_STATUS 0x0001 #define PHY_SPEED 0x0002 #define DETECT_MEDIA 0x0004 #define SUPPORT_SPEEDS 0x0008 +#define SUPPORT_SPEEDS2 0x0010 #define QCFG_PHY_ALL (\ - SUPPORT_SPEEDS | DETECT_MEDIA | PHY_SPEED | PHY_STATUS) + SUPPORT_SPEEDS | SUPPORT_SPEEDS2 | \ + DETECT_MEDIA | PHY_SPEED | PHY_STATUS) #define str_mbps "Mbps" #define str_gbps "Gbps" /* @@ -287,6 +303,18 @@ union dma_addr64_t { #define NS_LINK_SPEED_FW_100G (0x6) #define LINK_SPEED_FW_200G (0x7L << 7) #define NS_LINK_SPEED_FW_200G (0x7) +#define LINK_SPEED_FW_50G_PAM4 (0x8L << 7) +#define NS_LINK_SPEED_FW_50G_PAM4 (0x8) +#define LINK_SPEED_FW_100G_PAM4 (0x9L << 7) +#define NS_LINK_SPEED_FW_100G_PAM4 (0x9) +#define LINK_SPEED_FW_100G_PAM4_112 (0xAL << 7) +#define NS_LINK_SPEED_FW_100G_PAM4_112 (0xA) +#define LINK_SPEED_FW_200G_PAM4_112 (0xBL << 7) +#define NS_LINK_SPEED_FW_200G_PAM4_112 (0xB) +#define LINK_SPEED_FW_400G_PAM4 (0xCL << 7) +#define NS_LINK_SPEED_FW_400G_PAM4 (0xC) +#define LINK_SPEED_FW_400G_PAM4_112 (0xDL << 7) +#define NS_LINK_SPEED_FW_400G_PAM4_112 (0xD) #define LINK_SPEED_FW_2_5G (0xEL << 7) #define NS_LINK_SPEED_FW_2_5G (0xE) #define LINK_SPEED_FW_100M (0xFL << 7) @@ -387,6 +415,10 @@ struct dbc_dbc { __le32 index; #define DBC_DBC_INDEX_MASK 0xffffffUL #define DBC_DBC_INDEX_SFT 0 + #define DBC_DBC_EPOCH 0x1000000UL + #define DBC_DBC_EPOCH_SFT 24 + #define DBC_DBC_TOGGLE_MASK 0x6000000UL + #define DBC_DBC_TOGGLE_SFT 25 __le32 type_path_xid; #define DBC_DBC_XID_MASK 0xfffffUL #define DBC_DBC_XID_SFT 0 @@ -396,6 +428,7 @@ struct dbc_dbc { #define DBC_DBC_PATH_L2 (0x1UL << 24) #define DBC_DBC_PATH_ENGINE (0x2UL << 24) #define DBC_DBC_PATH_LAST DBC_DBC_PATH_ENGINE + #define DBC_DBC_VALID 0x4000000UL #define DBC_DBC_DEBUG_TRACE 0x8000000UL #define DBC_DBC_TYPE_MASK 0xf0000000UL #define DBC_DBC_TYPE_SFT 28 @@ -481,6 +514,8 @@ struct tx_info { u16 ring_cnt; u32 cnt; /* Tx statistics. */ u32 cnt_req; + u8 epoch; + u8 res[3]; }; struct cmpl_base { @@ -492,6 +527,7 @@ struct cmpl_base { #define CMPL_BASE_TYPE_RX_AGG 0x12UL #define CMPL_BASE_TYPE_RX_TPA_START 0x13UL #define CMPL_BASE_TYPE_RX_TPA_END 0x15UL +#define CMPL_BASE_TYPE_RX_L2_V3 0x17UL #define CMPL_BASE_TYPE_STAT_EJECT 0x1aUL #define CMPL_BASE_TYPE_HWRM_DONE 0x20UL #define CMPL_BASE_TYPE_HWRM_FWD_REQ 0x22UL @@ -517,7 +553,8 @@ struct cmp_info { u16 cons_id; u16 ring_cnt; u8 completion_bit; - u8 res[3]; + u8 epoch; + u8 res[2]; }; /* Completion Queue Notification */ @@ -533,6 +570,8 @@ struct nq_base { */ #define NQ_CN_TYPE_MASK 0x3fUL #define NQ_CN_TYPE_SFT 0 +#define NQ_CN_TOGGLE_MASK 0xc0UL +#define NQ_CN_TOGGLE_SFT 6 /* CQ Notification */ #define NQ_CN_TYPE_CQ_NOTIFICATION 0x30UL #define NQ_CN_TYPE_LAST NQ_CN_TYPE_CQ_NOTIFICATION @@ -561,7 +600,9 @@ struct nq_info { u16 cons_id; u16 ring_cnt; u8 completion_bit; - u8 res[3]; + u8 epoch; + u8 toggle; + u8 res[1]; }; struct rx_pkt_cmpl { @@ -675,6 +716,156 @@ struct rx_pkt_cmpl_hi { #define RX_PKT_CMPL_REORDER_SFT 0 }; +struct rx_pkt_v3_cmpl { + u16 flags_type; + #define RX_PKT_V3_CMPL_TYPE_MASK 0x3fUL + #define RX_PKT_V3_CMPL_TYPE_SFT 0 + /* + * RX L2 V3 completion: + * Completion of and L2 RX packet. Length = 32B + * This is the new version of the RX_L2 completion used in Thor2 + * and later chips. + */ + #define RX_PKT_V3_CMPL_TYPE_RX_L2_V3 0x17UL + #define RX_PKT_V3_CMPL_TYPE_LAST RX_PKT_V3_CMPL_TYPE_RX_L2_V3 + #define RX_PKT_V3_CMPL_FLAGS_MASK 0xffc0UL + #define RX_PKT_V3_CMPL_FLAGS_SFT 6 + #define RX_PKT_V3_CMPL_FLAGS_ERROR 0x40UL + #define RX_PKT_V3_CMPL_FLAGS_PLACEMENT_MASK 0x380UL + #define RX_PKT_V3_CMPL_FLAGS_PLACEMENT_SFT 7 + #define RX_PKT_V3_CMPL_FLAGS_PLACEMENT_NORMAL (0x0UL << 7) + #define RX_PKT_V3_CMPL_FLAGS_PLACEMENT_JUMBO (0x1UL << 7) + #define RX_PKT_V3_CMPL_FLAGS_PLACEMENT_HDS (0x2UL << 7) + #define RX_PKT_V3_CMPL_FLAGS_PLACEMENT_TRUNCATION (0x3UL << 7) + #define RX_PKT_V3_CMPL_FLAGS_PLACEMENT_LAST RX_PKT_V3_CMPL_FLAGS_PLACEMENT_TRUNCATION + #define RX_PKT_V3_CMPL_FLAGS_RSS_VALID 0x400UL + #define RX_PKT_V3_CMPL_FLAGS_PKT_METADATA_PRESENT 0x800UL + #define RX_PKT_V3_CMPL_FLAGS_ITYPE_MASK 0xf000UL + #define RX_PKT_V3_CMPL_FLAGS_ITYPE_SFT 12 + #define RX_PKT_V3_CMPL_FLAGS_ITYPE_NOT_KNOWN (0x0UL << 12) + #define RX_PKT_V3_CMPL_FLAGS_ITYPE_IP (0x1UL << 12) + #define RX_PKT_V3_CMPL_FLAGS_ITYPE_TCP (0x2UL << 12) + #define RX_PKT_V3_CMPL_FLAGS_ITYPE_UDP (0x3UL << 12) + #define RX_PKT_V3_CMPL_FLAGS_ITYPE_FCOE (0x4UL << 12) + #define RX_PKT_V3_CMPL_FLAGS_ITYPE_ROCE (0x5UL << 12) + #define RX_PKT_V3_CMPL_FLAGS_ITYPE_ICMP (0x7UL << 12) + #define RX_PKT_V3_CMPL_FLAGS_ITYPE_PTP_WO_TIMESTAMP (0x8UL << 12) + #define RX_PKT_V3_CMPL_FLAGS_ITYPE_PTP_W_TIMESTAMP (0x9UL << 12) + #define RX_PKT_V3_CMPL_FLAGS_ITYPE_LAST RX_PKT_V3_CMPL_FLAGS_ITYPE_PTP_W_TIMESTAMP + u16 len; + u32 opaque; + u16 rss_hash_type_agg_bufs_v1; + #define RX_PKT_V3_CMPL_V1 0x1UL + #define RX_PKT_V3_CMPL_AGG_BUFS_MASK 0x3eUL + #define RX_PKT_V3_CMPL_AGG_BUFS_SFT 1 + #define RX_PKT_V3_CMPL_UNUSED1 0x40UL + #define RX_PKT_V3_CMPL_RSS_HASH_TYPE_MASK 0xff80UL + #define RX_PKT_V3_CMPL_RSS_HASH_TYPE_SFT 7 + #define RX_PKT_V3_CMPL_RSS_HASH_TYPE_ENUM_0 (0x0UL << 7) + #define RX_PKT_V3_CMPL_RSS_HASH_TYPE_ENUM_1 (0x1UL << 7) + #define RX_PKT_V3_CMPL_RSS_HASH_TYPE_ENUM_3 (0x3UL << 7) + #define RX_PKT_V3_CMPL_RSS_HASH_TYPE_ENUM_4 (0x4UL << 7) + #define RX_PKT_V3_CMPL_RSS_HASH_TYPE_ENUM_5 (0x5UL << 7) + #define RX_PKT_V3_CMPL_RSS_HASH_TYPE_ENUM_6 (0x6UL << 7) + #define RX_PKT_V3_CMPL_RSS_HASH_TYPE_ENUM_7 (0x7UL << 7) + #define RX_PKT_V3_CMPL_RSS_HASH_TYPE_ENUM_8 (0x8UL << 7) + #define RX_PKT_V3_CMPL_RSS_HASH_TYPE_ENUM_9 (0x9UL << 7) + #define RX_PKT_V3_CMPL_RSS_HASH_TYPE_ENUM_10 (0xaUL << 7) + #define RX_PKT_V3_CMPL_RSS_HASH_TYPE_ENUM_11 (0xbUL << 7) + #define RX_PKT_V3_CMPL_RSS_HASH_TYPE_ENUM_12 (0xcUL << 7) + #define RX_PKT_V3_CMPL_RSS_HASH_TYPE_ENUM_13 (0xdUL << 7) + #define RX_PKT_V3_CMPL_RSS_HASH_TYPE_ENUM_14 (0xeUL << 7) + #define RX_PKT_V3_CMPL_RSS_HASH_TYPE_LAST RX_PKT_V3_CMPL_RSS_HASH_TYPE_ENUM_14 + u16 metadata1_payload_offset; + #define RX_PKT_V3_CMPL_PAYLOAD_OFFSET_MASK 0x1ffUL + #define RX_PKT_V3_CMPL_PAYLOAD_OFFSET_SFT 0 + #define RX_PKT_V3_CMPL_METADATA1_MASK 0xf000UL + #define RX_PKT_V3_CMPL_METADATA1_SFT 12 + #define RX_PKT_V3_CMPL_METADATA1_TPID_SEL_MASK 0x7000UL + #define RX_PKT_V3_CMPL_METADATA1_TPID_SEL_SFT 12 + #define RX_PKT_V3_CMPL_METADATA1_TPID_SEL_TPID88A8 (0x0UL << 12) + #define RX_PKT_V3_CMPL_METADATA1_TPID_SEL_TPID8100 (0x1UL << 12) + #define RX_PKT_V3_CMPL_METADATA1_TPID_SEL_TPID9100 (0x2UL << 12) + #define RX_PKT_V3_CMPL_METADATA1_TPID_SEL_TPID9200 (0x3UL << 12) + #define RX_PKT_V3_CMPL_METADATA1_TPID_SEL_TPID9300 (0x4UL << 12) + #define RX_PKT_V3_CMPL_METADATA1_TPID_SEL_TPIDCFG (0x5UL << 12) + #define RX_PKT_V3_CMPL_METADATA1_TPID_SEL_LAST RX_PKT_V3_CMPL_METADATA1_TPID_SEL_TPIDCFG + #define RX_PKT_V3_CMPL_METADATA1_VALID 0x8000UL + u32 rss_hash; +}; + +struct rx_pkt_v3_cmpl_hi { + u32 flags2; + #define RX_PKT_V3_CMPL_HI_FLAGS2_IP_CS_CALC 0x1UL + #define RX_PKT_V3_CMPL_HI_FLAGS2_L4_CS_CALC 0x2UL + #define RX_PKT_V3_CMPL_HI_FLAGS2_T_IP_CS_CALC 0x4UL + #define RX_PKT_V3_CMPL_HI_FLAGS2_T_L4_CS_CALC 0x8UL + #define RX_PKT_V3_CMPL_HI_FLAGS2_META_FORMAT_MASK 0xf0UL + #define RX_PKT_V3_CMPL_HI_FLAGS2_META_FORMAT_SFT 4 + #define RX_PKT_V3_CMPL_HI_FLAGS2_META_FORMAT_NONE (0x0UL << 4) + #define RX_PKT_V3_CMPL_HI_FLAGS2_META_FORMAT_ACT_REC_PTR (0x1UL << 4) + #define RX_PKT_V3_CMPL_HI_FLAGS2_META_FORMAT_TUNNEL_ID (0x2UL << 4) + #define RX_PKT_V3_CMPL_HI_FLAGS2_META_FORMAT_CHDR_DATA (0x3UL << 4) + #define RX_PKT_V3_CMPL_HI_FLAGS2_META_FORMAT_HDR_OFFSET (0x4UL << 4) + #define RX_PKT_V3_CMPL_HI_FLAGS2_META_FORMAT_LAST RX_PKT_V3_CMPL_HI_FLAGS2_META_FORMAT_HDR_OFFSET + #define RX_PKT_V3_CMPL_HI_FLAGS2_IP_TYPE 0x100UL + #define RX_PKT_V3_CMPL_HI_FLAGS2_COMPLETE_CHECKSUM_CALC 0x200UL + #define RX_PKT_V3_CMPL_HI_FLAGS2_T_IP_TYPE 0x400UL + #define RX_PKT_V3_CMPL_HI_FLAGS2_T_IP_TYPE_IPV4 (0x0UL << 10) + #define RX_PKT_V3_CMPL_HI_FLAGS2_T_IP_TYPE_IPV6 (0x1UL << 10) + #define RX_PKT_V3_CMPL_HI_FLAGS2_T_IP_TYPE_LAST RX_PKT_V3_CMPL_HI_FLAGS2_T_IP_TYPE_IPV6 + #define RX_PKT_V3_CMPL_HI_FLAGS2_COMPLETE_CHECKSUM_MASK 0xffff0000UL + #define RX_PKT_V3_CMPL_HI_FLAGS2_COMPLETE_CHECKSUM_SFT 16 + u32 metadata2; + u16 errors_v2; + #define RX_PKT_V3_CMPL_HI_V2 0x1UL + #define RX_PKT_V3_CMPL_HI_ERRORS_MASK 0xfffeUL + #define RX_PKT_V3_CMPL_HI_ERRORS_SFT 1 + #define RX_PKT_V3_CMPL_HI_ERRORS_BUFFER_ERROR_MASK 0xeUL + #define RX_PKT_V3_CMPL_HI_ERRORS_BUFFER_ERROR_SFT 1 + #define RX_PKT_V3_CMPL_HI_ERRORS_BUFFER_ERROR_NO_BUFFER (0x0UL << 1) + #define RX_PKT_V3_CMPL_HI_ERRORS_BUFFER_ERROR_DID_NOT_FIT (0x1UL << 1) + #define RX_PKT_V3_CMPL_HI_ERRORS_BUFFER_ERROR_NOT_ON_CHIP (0x2UL << 1) + #define RX_PKT_V3_CMPL_HI_ERRORS_BUFFER_ERROR_BAD_FORMAT (0x3UL << 1) + #define RX_PKT_V3_CMPL_HI_ERRORS_BUFFER_ERROR_FLUSH (0x5UL << 1) + #define RX_PKT_V3_CMPL_HI_ERRORS_BUFFER_ERROR_LAST RX_PKT_V3_CMPL_HI_ERRORS_BUFFER_ERROR_FLUSH + #define RX_PKT_V3_CMPL_HI_ERRORS_IP_CS_ERROR 0x10UL + #define RX_PKT_V3_CMPL_HI_ERRORS_L4_CS_ERROR 0x20UL + #define RX_PKT_V3_CMPL_HI_ERRORS_T_IP_CS_ERROR 0x40UL + #define RX_PKT_V3_CMPL_HI_ERRORS_T_L4_CS_ERROR 0x80UL + #define RX_PKT_V3_CMPL_HI_ERRORS_CRC_ERROR 0x100UL + #define RX_PKT_V3_CMPL_HI_ERRORS_T_PKT_ERROR_MASK 0xe00UL + #define RX_PKT_V3_CMPL_HI_ERRORS_T_PKT_ERROR_SFT 9 + #define RX_PKT_V3_CMPL_HI_ERRORS_T_PKT_ERROR_NO_ERROR (0x0UL << 9) + #define RX_PKT_V3_CMPL_HI_ERRORS_T_PKT_ERROR_T_L3_BAD_VERSION (0x1UL << 9) + #define RX_PKT_V3_CMPL_HI_ERRORS_T_PKT_ERROR_T_L3_BAD_HDR_LEN (0x2UL << 9) + #define RX_PKT_V3_CMPL_HI_ERRORS_T_PKT_ERROR_T_IP_TOTAL_ERROR (0x3UL << 9) + #define RX_PKT_V3_CMPL_HI_ERRORS_T_PKT_ERROR_T_UDP_TOTAL_ERROR (0x4UL << 9) + #define RX_PKT_V3_CMPL_HI_ERRORS_T_PKT_ERROR_T_L3_BAD_TTL (0x5UL << 9) + #define RX_PKT_V3_CMPL_HI_ERRORS_T_PKT_ERROR_T_TOTAL_ERROR (0x6UL << 9) + #define RX_PKT_V3_CMPL_HI_ERRORS_T_PKT_ERROR_LAST RX_PKT_V3_CMPL_HI_ERRORS_T_PKT_ERROR_T_TOTAL_ERROR + #define RX_PKT_V3_CMPL_HI_ERRORS_PKT_ERROR_MASK 0xf000UL + #define RX_PKT_V3_CMPL_HI_ERRORS_PKT_ERROR_SFT 12 + #define RX_PKT_V3_CMPL_HI_ERRORS_PKT_ERROR_NO_ERROR (0x0UL << 12) + #define RX_PKT_V3_CMPL_HI_ERRORS_PKT_ERROR_L3_BAD_VERSION (0x1UL << 12) + #define RX_PKT_V3_CMPL_HI_ERRORS_PKT_ERROR_L3_BAD_HDR_LEN (0x2UL << 12) + #define RX_PKT_V3_CMPL_HI_ERRORS_PKT_ERROR_L3_BAD_TTL (0x3UL << 12) + #define RX_PKT_V3_CMPL_HI_ERRORS_PKT_ERROR_IP_TOTAL_ERROR (0x4UL << 12) + #define RX_PKT_V3_CMPL_HI_ERRORS_PKT_ERROR_UDP_TOTAL_ERROR (0x5UL << 12) + #define RX_PKT_V3_CMPL_HI_ERRORS_PKT_ERROR_L4_BAD_HDR_LEN (0x6UL << 12) + #define RX_PKT_V3_CMPL_HI_ERRORS_PKT_ERROR_L4_BAD_HDR_LEN_TOO_SMALL (0x7UL << 12) + #define RX_PKT_V3_CMPL_HI_ERRORS_PKT_ERROR_L4_BAD_OPT_LEN (0x8UL << 12) + #define RX_PKT_V3_CMPL_HI_ERRORS_PKT_ERROR_LAST RX_PKT_V3_CMPL_HI_ERRORS_PKT_ERROR_L4_BAD_OPT_LEN + u16 metadata0; + #define RX_PKT_V3_CMPL_HI_METADATA0_VID_MASK 0xfffUL + #define RX_PKT_V3_CMPL_HI_METADATA0_VID_SFT 0 + #define RX_PKT_V3_CMPL_HI_METADATA0_DE 0x1000UL + /* When meta_format=1, this value is the VLAN PRI. */ + #define RX_PKT_V3_CMPL_HI_METADATA0_PRI_MASK 0xe000UL + #define RX_PKT_V3_CMPL_HI_METADATA0_PRI_SFT 13 + u32 timestamp; +}; + struct rx_prod_pkt_bd { u16 flags_type; #define RX_PROD_PKT_BD_TYPE_MASK 0x3fUL @@ -705,6 +896,8 @@ struct rx_info { u32 drop_err; u32 drop_lb; u32 drop_vlan; + u8 epoch; + u8 res[3]; }; #define VALID_DRIVER_REG 0x0001 @@ -750,7 +943,6 @@ struct bnxt { struct nq_info nq; /* completion info. */ u16 nq_ring_id; u8 queue_id; - u8 thor; u16 last_resp_code; u16 seq_id; u32 flag_hwrm; @@ -792,6 +984,7 @@ struct bnxt { u32 mba_cfg2; u32 medium; u16 support_speeds; + u16 auto_link_speeds2_mask; u32 link_set; u8 media_detect; u8 rsvd; @@ -871,3 +1064,5 @@ struct bnxt { #define CHIP_NUM_57508 0x1750 #define CHIP_NUM_57504 0x1751 #define CHIP_NUM_57502 0x1752 + +#define CHIP_NUM_57608 0x1760 diff --git a/src/drivers/net/bnxt/bnxt_dbg.h b/src/drivers/net/bnxt/bnxt_dbg.h index 188978ad..14540281 100644 --- a/src/drivers/net/bnxt/bnxt_dbg.h +++ b/src/drivers/net/bnxt/bnxt_dbg.h @@ -475,7 +475,7 @@ void dbg_rx_stat(struct bnxt *bp) #endif #if defined(DEBUG_CQ) -static void dump_cq(struct cmpl_base *cmp, u16 cid) +static void dump_cq(struct cmpl_base *cmp, u16 cid, u8 toggle) { dbg_prn("- CQ Type "); switch (cmp->type & CMPL_BASE_TYPE_MASK) { @@ -495,7 +495,7 @@ static void dump_cq(struct cmpl_base *cmp, u16 cid) dbg_prn("%04x", (u16)(cmp->type & CMPL_BASE_TYPE_MASK)); break; } - dbg_prn(" cid %d", cid); + dbg_prn(" cid %d, tog %d", cid, toggle); #if defined(DEBUG_CQ_DUMP) dump_mem((u8 *)cmp, (u32)sizeof(struct cmpl_base), DISP_U8); #else @@ -513,7 +513,7 @@ static void dump_nq(struct nq_base *nqp, u16 cid) #endif } #else -#define dump_cq(cq, id) +#define dump_cq(cq, id, toggle) #define dump_nq(nq, id) #endif diff --git a/src/drivers/net/bnxt/bnxt_hsi.h b/src/drivers/net/bnxt/bnxt_hsi.h index 086acb8b..dbcffd90 100644 --- a/src/drivers/net/bnxt/bnxt_hsi.h +++ b/src/drivers/net/bnxt/bnxt_hsi.h @@ -2929,7 +2929,7 @@ struct hwrm_func_drv_if_change_output { u8 valid; }; -/* hwrm_port_phy_cfg_input (size:448b/56B) */ +/* hwrm_port_phy_cfg_input (size:512b/64B) */ struct hwrm_port_phy_cfg_input { __le16 req_type; __le16 cmpl_ring; @@ -2952,6 +2952,15 @@ struct hwrm_port_phy_cfg_input { #define PORT_PHY_CFG_REQ_FLAGS_FEC_CLAUSE91_ENABLE 0x1000UL #define PORT_PHY_CFG_REQ_FLAGS_FEC_CLAUSE91_DISABLE 0x2000UL #define PORT_PHY_CFG_REQ_FLAGS_FORCE_LINK_DWN 0x4000UL + #define PORT_PHY_CFG_REQ_FLAGS_FEC_RS544_1XN_ENABLE 0x8000UL + #define PORT_PHY_CFG_REQ_FLAGS_FEC_RS544_1XN_DISABLE 0x10000UL + #define PORT_PHY_CFG_REQ_FLAGS_FEC_RS544_IEEE_ENABLE 0x20000UL + #define PORT_PHY_CFG_REQ_FLAGS_FEC_RS544_IEEE_DISABLE 0x40000UL + #define PORT_PHY_CFG_REQ_FLAGS_FEC_RS272_1XN_ENABLE 0x80000UL + #define PORT_PHY_CFG_REQ_FLAGS_FEC_RS272_1XN_DISABLE 0x100000UL + #define PORT_PHY_CFG_REQ_FLAGS_FEC_RS272_IEEE_ENABLE 0x200000UL + #define PORT_PHY_CFG_REQ_FLAGS_FEC_RS272_IEEE_DISABLE 0x400000UL + __le32 enables; #define PORT_PHY_CFG_REQ_ENABLES_AUTO_MODE 0x1UL #define PORT_PHY_CFG_REQ_ENABLES_AUTO_DUPLEX 0x2UL @@ -2964,6 +2973,10 @@ struct hwrm_port_phy_cfg_input { #define PORT_PHY_CFG_REQ_ENABLES_FORCE_PAUSE 0x100UL #define PORT_PHY_CFG_REQ_ENABLES_EEE_LINK_SPEED_MASK 0x200UL #define PORT_PHY_CFG_REQ_ENABLES_TX_LPI_TIMER 0x400UL + #define PORT_PHY_CFG_REQ_ENABLES_FORCE_PAM4_LINK_SPEED 0x800UL + #define PORT_PHY_CFG_REQ_ENABLES_AUTO_PAM4_LINK_SPEED_MASK 0x1000UL + #define PORT_PHY_CFG_REQ_ENABLES_FORCE_LINK_SPEEDS2 0x2000UL + #define PORT_PHY_CFG_REQ_ENABLES_AUTO_LINK_SPEEDS2_MASK 0x4000UL __le16 port_id; __le16 force_link_speed; #define PORT_PHY_CFG_REQ_FORCE_LINK_SPEED_100MB 0x1UL @@ -3049,11 +3062,48 @@ struct hwrm_port_phy_cfg_input { #define PORT_PHY_CFG_REQ_EEE_LINK_SPEED_MASK_RSVD3 0x10UL #define PORT_PHY_CFG_REQ_EEE_LINK_SPEED_MASK_RSVD4 0x20UL #define PORT_PHY_CFG_REQ_EEE_LINK_SPEED_MASK_10GB 0x40UL - u8 unused_2[2]; + __le16 force_pam4_link_speed; + #define PORT_PHY_CFG_REQ_FORCE_PAM4_LINK_SPEED_50GB 0x1f4UL + #define PORT_PHY_CFG_REQ_FORCE_PAM4_LINK_SPEED_100GB 0x3e8UL + #define PORT_PHY_CFG_REQ_FORCE_PAM4_LINK_SPEED_200GB 0x7d0UL + #define PORT_PHY_CFG_REQ_FORCE_PAM4_LINK_SPEED_LAST PORT_PHY_CFG_REQ_FORCE_PAM4_LINK_SPEED_200GB __le32 tx_lpi_timer; #define PORT_PHY_CFG_REQ_TX_LPI_TIMER_MASK 0xffffffUL #define PORT_PHY_CFG_REQ_TX_LPI_TIMER_SFT 0 - __le32 unused_3; + __le16 auto_link_pam4_speed_mask; + #define PORT_PHY_CFG_REQ_AUTO_LINK_PAM4_SPEED_MASK_50G 0x1UL + #define PORT_PHY_CFG_REQ_AUTO_LINK_PAM4_SPEED_MASK_100G 0x2UL + #define PORT_PHY_CFG_REQ_AUTO_LINK_PAM4_SPEED_MASK_200G 0x4UL + __le16 force_link_speeds2; + #define PORT_PHY_CFG_REQ_FORCE_LINK_SPEEDS2_1GB 0xaUL + #define PORT_PHY_CFG_REQ_FORCE_LINK_SPEEDS2_10GB 0x64UL + #define PORT_PHY_CFG_REQ_FORCE_LINK_SPEEDS2_25GB 0xfaUL + #define PORT_PHY_CFG_REQ_FORCE_LINK_SPEEDS2_40GB 0x190UL + #define PORT_PHY_CFG_REQ_FORCE_LINK_SPEEDS2_50GB 0x1f4UL + #define PORT_PHY_CFG_REQ_FORCE_LINK_SPEEDS2_100GB 0x3e8UL + #define PORT_PHY_CFG_REQ_FORCE_LINK_SPEEDS2_50GB_PAM4_56 0x1f5UL + #define PORT_PHY_CFG_REQ_FORCE_LINK_SPEEDS2_100GB_PAM4_56 0x3e9UL + #define PORT_PHY_CFG_REQ_FORCE_LINK_SPEEDS2_200GB_PAM4_56 0x7d1UL + #define PORT_PHY_CFG_REQ_FORCE_LINK_SPEEDS2_400GB_PAM4_56 0xfa1UL + #define PORT_PHY_CFG_REQ_FORCE_LINK_SPEEDS2_100GB_PAM4_112 0x3eaUL + #define PORT_PHY_CFG_REQ_FORCE_LINK_SPEEDS2_200GB_PAM4_112 0x7d2UL + #define PORT_PHY_CFG_REQ_FORCE_LINK_SPEEDS2_400GB_PAM4_112 0xfa2UL + #define PORT_PHY_CFG_REQ_FORCE_LINK_SPEEDS2_LAST PORT_PHY_CFG_REQ_FORCE_LINK_SPEEDS2_400GB_PAM4_112 + __le16 auto_link_speeds2_mask; + #define PORT_PHY_CFG_REQ_AUTO_LINK_SPEEDS2_MASK_1GB 0x1UL + #define PORT_PHY_CFG_REQ_AUTO_LINK_SPEEDS2_MASK_10GB 0x2UL + #define PORT_PHY_CFG_REQ_AUTO_LINK_SPEEDS2_MASK_25GB 0x4UL + #define PORT_PHY_CFG_REQ_AUTO_LINK_SPEEDS2_MASK_40GB 0x8UL + #define PORT_PHY_CFG_REQ_AUTO_LINK_SPEEDS2_MASK_50GB 0x10UL + #define PORT_PHY_CFG_REQ_AUTO_LINK_SPEEDS2_MASK_100GB 0x20UL + #define PORT_PHY_CFG_REQ_AUTO_LINK_SPEEDS2_MASK_50GB_PAM4_56 0x40UL + #define PORT_PHY_CFG_REQ_AUTO_LINK_SPEEDS2_MASK_100GB_PAM4_56 0x80UL + #define PORT_PHY_CFG_REQ_AUTO_LINK_SPEEDS2_MASK_200GB_PAM4_56 0x100UL + #define PORT_PHY_CFG_REQ_AUTO_LINK_SPEEDS2_MASK_400GB_PAM4_56 0x200UL + #define PORT_PHY_CFG_REQ_AUTO_LINK_SPEEDS2_MASK_100GB_PAM4_112 0x400UL + #define PORT_PHY_CFG_REQ_AUTO_LINK_SPEEDS2_MASK_200GB_PAM4_112 0x800UL + #define PORT_PHY_CFG_REQ_AUTO_LINK_SPEEDS2_MASK_400GB_PAM4_112 0x1000UL + u8 unused_2[6]; }; /* hwrm_port_phy_cfg_output (size:128b/16B) */ @@ -3087,7 +3137,7 @@ struct hwrm_port_phy_qcfg_input { u8 unused_0[6]; }; -/* hwrm_port_phy_qcfg_output (size:768b/96B) */ +/* hwrm_port_phy_qcfg_output (size:832b/104B) */ struct hwrm_port_phy_qcfg_output { __le16 error_code; __le16 req_type; @@ -3098,7 +3148,23 @@ struct hwrm_port_phy_qcfg_output { #define PORT_PHY_QCFG_RESP_LINK_SIGNAL 0x1UL #define PORT_PHY_QCFG_RESP_LINK_LINK 0x2UL #define PORT_PHY_QCFG_RESP_LINK_LAST PORT_PHY_QCFG_RESP_LINK_LINK - u8 unused_0; + u8 active_fec_signal_mode; + #define PORT_PHY_QCFG_RESP_SIGNAL_MODE_MASK 0xfUL + #define PORT_PHY_QCFG_RESP_SIGNAL_MODE_SFT 0 + #define PORT_PHY_QCFG_RESP_SIGNAL_MODE_NRZ 0x0UL + #define PORT_PHY_QCFG_RESP_SIGNAL_MODE_PAM4 0x1UL + #define PORT_PHY_QCFG_RESP_SIGNAL_MODE_PAM4_112 0x2UL + #define PORT_PHY_QCFG_RESP_SIGNAL_MODE_LAST HWRM_PORT_PHY_QCFG_RESP_SIGNAL_MODE_PAM4_112 + #define PORT_PHY_QCFG_RESP_ACTIVE_FEC_MASK 0xf0UL + #define PORT_PHY_QCFG_RESP_ACTIVE_FEC_SFT 4 + #define PORT_PHY_QCFG_RESP_ACTIVE_FEC_FEC_NONE_ACTIVE (0x0UL << 4) + #define PORT_PHY_QCFG_RESP_ACTIVE_FEC_FEC_CLAUSE74_ACTIVE (0x1UL << 4) + #define PORT_PHY_QCFG_RESP_ACTIVE_FEC_FEC_CLAUSE91_ACTIVE (0x2UL << 4) + #define PORT_PHY_QCFG_RESP_ACTIVE_FEC_FEC_RS544_1XN_ACTIVE (0x3UL << 4) + #define PORT_PHY_QCFG_RESP_ACTIVE_FEC_FEC_RS544_IEEE_ACTIVE (0x4UL << 4) + #define PORT_PHY_QCFG_RESP_ACTIVE_FEC_FEC_RS272_1XN_ACTIVE (0x5UL << 4) + #define PORT_PHY_QCFG_RESP_ACTIVE_FEC_FEC_RS272_IEEE_ACTIVE (0x6UL << 4) + #define PORT_PHY_QCFG_RESP_ACTIVE_FEC_LAST PORT_PHY_QCFG_RESP_ACTIVE_FEC_FEC_RS272_IEEE_ACTIVE __le16 link_speed; #define PORT_PHY_QCFG_RESP_LINK_SPEED_100MB 0x1UL #define PORT_PHY_QCFG_RESP_LINK_SPEED_1GB 0xaUL @@ -3111,6 +3177,7 @@ struct hwrm_port_phy_qcfg_output { #define PORT_PHY_QCFG_RESP_LINK_SPEED_50GB 0x1f4UL #define PORT_PHY_QCFG_RESP_LINK_SPEED_100GB 0x3e8UL #define PORT_PHY_QCFG_RESP_LINK_SPEED_200GB 0x7d0UL + #define PORT_PHY_QCFG_RESP_LINK_SPEED_400GB 0xfa0UL #define PORT_PHY_QCFG_RESP_LINK_SPEED_10MB 0xffffUL #define PORT_PHY_QCFG_RESP_LINK_SPEED_LAST PORT_PHY_QCFG_RESP_LINK_SPEED_10MB u8 duplex_cfg; @@ -3249,7 +3316,31 @@ struct hwrm_port_phy_qcfg_output { #define PORT_PHY_QCFG_RESP_PHY_TYPE_200G_BASESR4 0x1dUL #define PORT_PHY_QCFG_RESP_PHY_TYPE_200G_BASELR4 0x1eUL #define PORT_PHY_QCFG_RESP_PHY_TYPE_200G_BASEER4 0x1fUL - #define PORT_PHY_QCFG_RESP_PHY_TYPE_LAST PORT_PHY_QCFG_RESP_PHY_TYPE_200G_BASEER4 + #define PORT_PHY_QCFG_RESP_PHY_TYPE_50G_BASECR 0x20UL + #define PORT_PHY_QCFG_RESP_PHY_TYPE_50G_BASESR 0x21UL + #define PORT_PHY_QCFG_RESP_PHY_TYPE_50G_BASELR 0x22UL + #define PORT_PHY_QCFG_RESP_PHY_TYPE_50G_BASEER 0x23UL + #define PORT_PHY_QCFG_RESP_PHY_TYPE_100G_BASECR2 0x24UL + #define PORT_PHY_QCFG_RESP_PHY_TYPE_100G_BASESR2 0x25UL + #define PORT_PHY_QCFG_RESP_PHY_TYPE_100G_BASELR2 0x26UL + #define PORT_PHY_QCFG_RESP_PHY_TYPE_100G_BASEER2 0x27UL + #define PORT_PHY_QCFG_RESP_PHY_TYPE_100G_BASECR 0x28UL + #define PORT_PHY_QCFG_RESP_PHY_TYPE_100G_BASESR 0x29UL + #define PORT_PHY_QCFG_RESP_PHY_TYPE_100G_BASELR 0x2aUL + #define PORT_PHY_QCFG_RESP_PHY_TYPE_100G_BASEER 0x2bUL + #define PORT_PHY_QCFG_RESP_PHY_TYPE_200G_BASECR2 0x2cUL + #define PORT_PHY_QCFG_RESP_PHY_TYPE_200G_BASESR2 0x2dUL + #define PORT_PHY_QCFG_RESP_PHY_TYPE_200G_BASELR2 0x2eUL + #define PORT_PHY_QCFG_RESP_PHY_TYPE_200G_BASEER2 0x2fUL + #define PORT_PHY_QCFG_RESP_PHY_TYPE_400G_BASECR8 0x30UL + #define PORT_PHY_QCFG_RESP_PHY_TYPE_400G_BASESR8 0x31UL + #define PORT_PHY_QCFG_RESP_PHY_TYPE_400G_BASELR8 0x32UL + #define PORT_PHY_QCFG_RESP_PHY_TYPE_400G_BASEER8 0x33UL + #define PORT_PHY_QCFG_RESP_PHY_TYPE_400G_BASECR4 0x34UL + #define PORT_PHY_QCFG_RESP_PHY_TYPE_400G_BASESR4 0x35UL + #define PORT_PHY_QCFG_RESP_PHY_TYPE_400G_BASELR4 0x36UL + #define PORT_PHY_QCFG_RESP_PHY_TYPE_400G_BASEER4 0x37UL + #define PORT_PHY_QCFG_RESP_PHY_TYPE_LAST PORT_PHY_QCFG_RESP_PHY_TYPE_400G_BASEER4 u8 media_type; #define PORT_PHY_QCFG_RESP_MEDIA_TYPE_UNKNOWN 0x0UL #define PORT_PHY_QCFG_RESP_MEDIA_TYPE_TP 0x1UL @@ -3330,15 +3421,90 @@ struct hwrm_port_phy_qcfg_output { #define PORT_PHY_QCFG_RESP_FEC_CFG_FEC_CLAUSE74_ENABLED 0x10UL #define PORT_PHY_QCFG_RESP_FEC_CFG_FEC_CLAUSE91_SUPPORTED 0x20UL #define PORT_PHY_QCFG_RESP_FEC_CFG_FEC_CLAUSE91_ENABLED 0x40UL + #define PORT_PHY_QCFG_RESP_FEC_CFG_FEC_RS544_1XN_SUPPORTED 0x80UL + #define PORT_PHY_QCFG_RESP_FEC_CFG_FEC_RS544_1XN_ENABLED 0x100UL + #define PORT_PHY_QCFG_RESP_FEC_CFG_FEC_RS544_IEEE_SUPPORTED 0x200UL + #define PORT_PHY_QCFG_RESP_FEC_CFG_FEC_RS544_IEEE_ENABLED 0x400UL + #define PORT_PHY_QCFG_RESP_FEC_CFG_FEC_RS272_1XN_SUPPORTED 0x800UL + #define PORT_PHY_QCFG_RESP_FEC_CFG_FEC_RS272_1XN_ENABLED 0x1000UL + #define PORT_PHY_QCFG_RESP_FEC_CFG_FEC_RS272_IEEE_SUPPORTED 0x2000UL + #define PORT_PHY_QCFG_RESP_FEC_CFG_FEC_RS272_IEEE_ENABLED 0x4000UL u8 duplex_state; #define PORT_PHY_QCFG_RESP_DUPLEX_STATE_HALF 0x0UL #define PORT_PHY_QCFG_RESP_DUPLEX_STATE_FULL 0x1UL #define PORT_PHY_QCFG_RESP_DUPLEX_STATE_LAST PORT_PHY_QCFG_RESP_DUPLEX_STATE_FULL u8 option_flags; #define PORT_PHY_QCFG_RESP_OPTION_FLAGS_MEDIA_AUTO_DETECT 0x1UL + #define PORT_PHY_QCFG_RESP_OPTION_FLAGS_SIGNAL_MODE_KNOWN 0x2UL + #define PORT_PHY_QCFG_RESP_OPTION_FLAGS_SPEEDS2_SUPPORTED 0x4UL char phy_vendor_name[16]; char phy_vendor_partnumber[16]; - u8 unused_2[7]; + __le16 support_pam4_speeds; + #define PORT_PHY_QCFG_RESP_SUPPORT_PAM4_SPEEDS_50G 0x1UL + #define PORT_PHY_QCFG_RESP_SUPPORT_PAM4_SPEEDS_100G 0x2UL + #define PORT_PHY_QCFG_RESP_SUPPORT_PAM4_SPEEDS_200G 0x4UL + __le16 force_pam4_link_speed; + #define PORT_PHY_QCFG_RESP_FORCE_PAM4_LINK_SPEED_50GB 0x1f4UL + #define PORT_PHY_QCFG_RESP_FORCE_PAM4_LINK_SPEED_100GB 0x3e8UL + #define PORT_PHY_QCFG_RESP_FORCE_PAM4_LINK_SPEED_200GB 0x7d0UL + #define PORT_PHY_QCFG_RESP_FORCE_PAM4_LINK_SPEED_LAST PORT_PHY_QCFG_RESP_FORCE_PAM4_LINK_SPEED_200GB + __le16 auto_pam4_link_speed_mask; + #define PORT_PHY_QCFG_RESP_AUTO_PAM4_LINK_SPEED_MASK_50G 0x1UL + #define PORT_PHY_QCFG_RESP_AUTO_PAM4_LINK_SPEED_MASK_100G 0x2UL + #define PORT_PHY_QCFG_RESP_AUTO_PAM4_LINK_SPEED_MASK_200G 0x4UL + u8 link_partner_pam4_adv_speeds; + #define PORT_PHY_QCFG_RESP_LINK_PARTNER_PAM4_ADV_SPEEDS_50GB 0x1UL + #define PORT_PHY_QCFG_RESP_LINK_PARTNER_PAM4_ADV_SPEEDS_100GB 0x2UL + #define PORT_PHY_QCFG_RESP_LINK_PARTNER_PAM4_ADV_SPEEDS_200GB 0x4UL + u8 link_down_reason; + #define PORT_PHY_QCFG_RESP_LINK_DOWN_REASON_RF 0x1UL + __le16 support_speeds2; + #define PORT_PHY_QCFG_RESP_SUPPORT_SPEEDS2_1GB 0x1UL + #define PORT_PHY_QCFG_RESP_SUPPORT_SPEEDS2_10GB 0x2UL + #define PORT_PHY_QCFG_RESP_SUPPORT_SPEEDS2_25GB 0x4UL + #define PORT_PHY_QCFG_RESP_SUPPORT_SPEEDS2_40GB 0x8UL + #define PORT_PHY_QCFG_RESP_SUPPORT_SPEEDS2_50GB 0x10UL + #define PORT_PHY_QCFG_RESP_SUPPORT_SPEEDS2_100GB 0x20UL + #define PORT_PHY_QCFG_RESP_SUPPORT_SPEEDS2_50GB_PAM4_56 0x40UL + #define PORT_PHY_QCFG_RESP_SUPPORT_SPEEDS2_100GB_PAM4_56 0x80UL + #define PORT_PHY_QCFG_RESP_SUPPORT_SPEEDS2_200GB_PAM4_56 0x100UL + #define PORT_PHY_QCFG_RESP_SUPPORT_SPEEDS2_400GB_PAM4_56 0x200UL + #define PORT_PHY_QCFG_RESP_SUPPORT_SPEEDS2_100GB_PAM4_112 0x400UL + #define PORT_PHY_QCFG_RESP_SUPPORT_SPEEDS2_200GB_PAM4_112 0x800UL + #define PORT_PHY_QCFG_RESP_SUPPORT_SPEEDS2_400GB_PAM4_112 0x1000UL + #define PORT_PHY_QCFG_RESP_SUPPORT_SPEEDS2_800GB_PAM4_112 0x2000UL + __le16 force_link_speeds2; + #define PORT_PHY_QCFG_RESP_FORCE_LINK_SPEEDS2_1GB 0xaUL + #define PORT_PHY_QCFG_RESP_FORCE_LINK_SPEEDS2_10GB 0x64UL + #define PORT_PHY_QCFG_RESP_FORCE_LINK_SPEEDS2_25GB 0xfaUL + #define PORT_PHY_QCFG_RESP_FORCE_LINK_SPEEDS2_40GB 0x190UL + #define PORT_PHY_QCFG_RESP_FORCE_LINK_SPEEDS2_50GB 0x1f4UL + #define PORT_PHY_QCFG_RESP_FORCE_LINK_SPEEDS2_100GB 0x3e8UL + #define PORT_PHY_QCFG_RESP_FORCE_LINK_SPEEDS2_50GB_PAM4_56 0x1f5UL + #define PORT_PHY_QCFG_RESP_FORCE_LINK_SPEEDS2_100GB_PAM4_56 0x3e9UL + #define PORT_PHY_QCFG_RESP_FORCE_LINK_SPEEDS2_200GB_PAM4_56 0x7d1UL + #define PORT_PHY_QCFG_RESP_FORCE_LINK_SPEEDS2_400GB_PAM4_56 0xfa1UL + #define PORT_PHY_QCFG_RESP_FORCE_LINK_SPEEDS2_100GB_PAM4_112 0x3eaUL + #define PORT_PHY_QCFG_RESP_FORCE_LINK_SPEEDS2_200GB_PAM4_112 0x7d2UL + #define PORT_PHY_QCFG_RESP_FORCE_LINK_SPEEDS2_400GB_PAM4_112 0xfa2UL + #define PORT_PHY_QCFG_RESP_FORCE_LINK_SPEEDS2_800GB_PAM4_112 0x1f42UL + #define PORT_PHY_QCFG_RESP_FORCE_LINK_SPEEDS2_LAST PORT_PHY_QCFG_RESP_FORCE_LINK_SPEEDS2_800GB_PAM4_112 + __le16 auto_link_speeds2; + #define PORT_PHY_QCFG_RESP_AUTO_LINK_SPEEDS2_1GB 0x1UL + #define PORT_PHY_QCFG_RESP_AUTO_LINK_SPEEDS2_10GB 0x2UL + #define PORT_PHY_QCFG_RESP_AUTO_LINK_SPEEDS2_25GB 0x4UL + #define PORT_PHY_QCFG_RESP_AUTO_LINK_SPEEDS2_40GB 0x8UL + #define PORT_PHY_QCFG_RESP_AUTO_LINK_SPEEDS2_50GB 0x10UL + #define PORT_PHY_QCFG_RESP_AUTO_LINK_SPEEDS2_100GB 0x20UL + #define PORT_PHY_QCFG_RESP_AUTO_LINK_SPEEDS2_50GB_PAM4_56 0x40UL + #define PORT_PHY_QCFG_RESP_AUTO_LINK_SPEEDS2_100GB_PAM4_56 0x80UL + #define PORT_PHY_QCFG_RESP_AUTO_LINK_SPEEDS2_200GB_PAM4_56 0x100UL + #define PORT_PHY_QCFG_RESP_AUTO_LINK_SPEEDS2_400GB_PAM4_56 0x200UL + #define PORT_PHY_QCFG_RESP_AUTO_LINK_SPEEDS2_100GB_PAM4_112 0x400UL + #define PORT_PHY_QCFG_RESP_AUTO_LINK_SPEEDS2_200GB_PAM4_112 0x800UL + #define PORT_PHY_QCFG_RESP_AUTO_LINK_SPEEDS2_400GB_PAM4_112 0x1000UL + #define PORT_PHY_QCFG_RESP_AUTO_LINK_SPEEDS2_800GB_PAM4_112 0x2000UL + u8 active_lanes; u8 valid; }; @@ -3888,7 +4054,7 @@ struct hwrm_port_phy_qcaps_input { u8 unused_0[6]; }; -/* hwrm_port_phy_qcaps_output (size:192b/24B) */ +/* hwrm_port_phy_qcaps_output (size:320b/40B) */ struct hwrm_port_phy_qcaps_output { __le16 error_code; __le16 req_type; @@ -3954,6 +4120,53 @@ struct hwrm_port_phy_qcaps_output { #define PORT_PHY_QCAPS_RESP_TX_LPI_TIMER_HIGH_SFT 0 #define PORT_PHY_QCAPS_RESP_VALID_MASK 0xff000000UL #define PORT_PHY_QCAPS_RESP_VALID_SFT 24 + __le16 supported_pam4_speeds_auto_mode; + #define PORT_PHY_QCAPS_RESP_SUPPORTED_PAM4_SPEEDS_AUTO_MODE_50G 0x1UL + #define PORT_PHY_QCAPS_RESP_SUPPORTED_PAM4_SPEEDS_AUTO_MODE_100G 0x2UL + #define PORT_PHY_QCAPS_RESP_SUPPORTED_PAM4_SPEEDS_AUTO_MODE_200G 0x4UL + __le16 supported_pam4_speeds_force_mode; + #define PORT_PHY_QCAPS_RESP_SUPPORTED_PAM4_SPEEDS_FORCE_MODE_50G 0x1UL + #define PORT_PHY_QCAPS_RESP_SUPPORTED_PAM4_SPEEDS_FORCE_MODE_100G 0x2UL + #define PORT_PHY_QCAPS_RESP_SUPPORTED_PAM4_SPEEDS_FORCE_MODE_200G 0x4UL + __le16 flags2; + #define PORT_PHY_QCAPS_RESP_FLAGS2_PAUSE_UNSUPPORTED 0x1UL + #define PORT_PHY_QCAPS_RESP_FLAGS2_PFC_UNSUPPORTED 0x2UL + #define PORT_PHY_QCAPS_RESP_FLAGS2_BANK_ADDR_SUPPORTED 0x4UL + #define PORT_PHY_QCAPS_RESP_FLAGS2_SPEEDS2_SUPPORTED 0x8UL + u8 internal_port_cnt; + u8 unused_0; + __le16 supported_speeds2_force_mode; + #define PORT_PHY_QCAPS_RESP_SUPPORTED_SPEEDS2_FORCE_MODE_1GB 0x1UL + #define PORT_PHY_QCAPS_RESP_SUPPORTED_SPEEDS2_FORCE_MODE_10GB 0x2UL + #define PORT_PHY_QCAPS_RESP_SUPPORTED_SPEEDS2_FORCE_MODE_25GB 0x4UL + #define PORT_PHY_QCAPS_RESP_SUPPORTED_SPEEDS2_FORCE_MODE_40GB 0x8UL + #define PORT_PHY_QCAPS_RESP_SUPPORTED_SPEEDS2_FORCE_MODE_50GB 0x10UL + #define PORT_PHY_QCAPS_RESP_SUPPORTED_SPEEDS2_FORCE_MODE_100GB 0x20UL + #define PORT_PHY_QCAPS_RESP_SUPPORTED_SPEEDS2_FORCE_MODE_50GB_PAM4_56 0x40UL + #define PORT_PHY_QCAPS_RESP_SUPPORTED_SPEEDS2_FORCE_MODE_100GB_PAM4_56 0x80UL + #define PORT_PHY_QCAPS_RESP_SUPPORTED_SPEEDS2_FORCE_MODE_200GB_PAM4_56 0x100UL + #define PORT_PHY_QCAPS_RESP_SUPPORTED_SPEEDS2_FORCE_MODE_400GB_PAM4_56 0x200UL + #define PORT_PHY_QCAPS_RESP_SUPPORTED_SPEEDS2_FORCE_MODE_100GB_PAM4_112 0x400UL + #define PORT_PHY_QCAPS_RESP_SUPPORTED_SPEEDS2_FORCE_MODE_200GB_PAM4_112 0x800UL + #define PORT_PHY_QCAPS_RESP_SUPPORTED_SPEEDS2_FORCE_MODE_400GB_PAM4_112 0x1000UL + #define PORT_PHY_QCAPS_RESP_SUPPORTED_SPEEDS2_FORCE_MODE_800GB_PAM4_112 0x2000UL + __le16 supported_speeds2_auto_mode; + #define PORT_PHY_QCAPS_RESP_SUPPORTED_SPEEDS2_AUTO_MODE_1GB 0x1UL + #define PORT_PHY_QCAPS_RESP_SUPPORTED_SPEEDS2_AUTO_MODE_10GB 0x2UL + #define PORT_PHY_QCAPS_RESP_SUPPORTED_SPEEDS2_AUTO_MODE_25GB 0x4UL + #define PORT_PHY_QCAPS_RESP_SUPPORTED_SPEEDS2_AUTO_MODE_40GB 0x8UL + #define PORT_PHY_QCAPS_RESP_SUPPORTED_SPEEDS2_AUTO_MODE_50GB 0x10UL + #define PORT_PHY_QCAPS_RESP_SUPPORTED_SPEEDS2_AUTO_MODE_100GB 0x20UL + #define PORT_PHY_QCAPS_RESP_SUPPORTED_SPEEDS2_AUTO_MODE_50GB_PAM4_56 0x40UL + #define PORT_PHY_QCAPS_RESP_SUPPORTED_SPEEDS2_AUTO_MODE_100GB_PAM4_56 0x80UL + #define PORT_PHY_QCAPS_RESP_SUPPORTED_SPEEDS2_AUTO_MODE_200GB_PAM4_56 0x100UL + #define PORT_PHY_QCAPS_RESP_SUPPORTED_SPEEDS2_AUTO_MODE_400GB_PAM4_56 0x200UL + #define PORT_PHY_QCAPS_RESP_SUPPORTED_SPEEDS2_AUTO_MODE_100GB_PAM4_112 0x400UL + #define PORT_PHY_QCAPS_RESP_SUPPORTED_SPEEDS2_AUTO_MODE_200GB_PAM4_112 0x800UL + #define PORT_PHY_QCAPS_RESP_SUPPORTED_SPEEDS2_AUTO_MODE_400GB_PAM4_112 0x1000UL + #define PORT_PHY_QCAPS_RESP_SUPPORTED_SPEEDS2_AUTO_MODE_800GB_PAM4_112 0x2000UL + u8 unused_1[3]; + u8 valid; }; /* hwrm_port_phy_i2c_write_input (size:832b/104B) */ -- cgit v1.2.3-55-g7522 From 0f5abd8b117ea7da0747fe36b66c050706f6584f Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Thu, 8 Feb 2024 16:39:35 +0000 Subject: [libc] Allow build_assert() failures to be ignored via NO_WERROR=1 We build with -Werror by default so that any warning is treated as an error and aborts the build. The build system allows NO_WERROR=1 to be used to override this behaviour, in order to allow builds to succeed when spurious warnings occur (e.g. when using a newer compiler that includes checks for which the codebase is not yet prepared). Some versions of gcc (observed with gcc 4.8.5 in CentOS 7) will report spurious build_assert() failures: the compilation will fail due to an allegedly unelided call to the build assertion's external function declared with __attribute__((error)) even though the compiler does manage to successfully elide the call (as verified by the fact that there are no unresolvable symbol references in the compiler output). Change build_assert() to declare __attribute__((warning)) instead of __attribute__((error)) on its extern function. This will still abort a normal build if the assertion fails, but may be overridden using NO_WERROR=1 if necessary to work around a spurious assertion failure. Note that if the build assertion has genuinely failed (i.e. if the compiler has genuinely not been able to elide the call) then the object will still contain an unresolvable symbol reference that will cause the link to fail (which matches the behaviour of the old linker_assert() mechanism). Signed-off-by: Michael Brown --- src/include/assert.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/include/assert.h b/src/include/assert.h index b3a9b1fe..01a28785 100644 --- a/src/include/assert.h +++ b/src/include/assert.h @@ -76,7 +76,7 @@ assert_printf ( const char *fmt, ... ) asm ( "printf" ); #define build_assert( condition ) \ do { \ if ( ! (condition) ) { \ - extern void __attribute__ (( error ( \ + extern void __attribute__ (( warning ( \ "build_assert(" #condition ") failed" \ ) )) _C2 ( build_assert_, __LINE__ ) ( void ); \ _C2 ( build_assert_, __LINE__ ) (); \ -- cgit v1.2.3-55-g7522 From 94b39fbe9298160b034c93ca06deb39a907e3b3f Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Sat, 10 Feb 2024 14:41:29 +0000 Subject: [build] Fix build failures with older versions of gcc Some versions of gcc (observed with gcc 4.8.5 in CentOS 7) will report spurious build_assert() failures for some assertions about structure layouts. There is no clear pattern as to what causes these spurious failures, and the build assertion does succeed in that no unresolvable symbol reference is generated in the compiled code. Adjust the assertions to work around these apparent compiler issues. Signed-off-by: Michael Brown --- src/crypto/gcm.c | 14 ++++++++------ src/include/ipxe/gcm.h | 3 ++- 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/src/crypto/gcm.c b/src/crypto/gcm.c index c21aad14..a32890d5 100644 --- a/src/crypto/gcm.c +++ b/src/crypto/gcm.c @@ -469,13 +469,15 @@ int gcm_setkey ( struct gcm_context *context, const void *key, size_t keylen, * @v ivlen Initialisation vector length */ void gcm_setiv ( struct gcm_context *context, const void *iv, size_t ivlen ) { - union gcm_block *check = ( ( void * ) context ); - /* Sanity checks */ - build_assert ( &context->hash == check ); - build_assert ( &context->len == check + 1 ); - build_assert ( &context->ctr == check + 2 ); - build_assert ( &context->key == check + 3 ); + /* Sanity check: ensure that memset()s will clear expected state */ + build_assert ( &context->hash < &context->ctr ); + build_assert ( &context->len < &context->ctr ); + build_assert ( &context->ctr < &context->key ); + build_assert ( ( ( void * ) &context->raw_cipher ) > + ( ( void * ) &context->key ) ); + build_assert ( ( ( void * ) context->raw_ctx ) > + ( ( void * ) &context->key ) ); /* Reset non-key state */ memset ( context, 0, offsetof ( typeof ( *context ), key ) ); diff --git a/src/include/ipxe/gcm.h b/src/include/ipxe/gcm.h index 9653a0a1..4864445d 100644 --- a/src/include/ipxe/gcm.h +++ b/src/include/ipxe/gcm.h @@ -89,7 +89,8 @@ static int _gcm_name ## _setkey ( void *ctx, const void *key, \ size_t keylen ) { \ struct _gcm_name ## _context *context = ctx; \ build_assert ( _blocksize == sizeof ( context->gcm.key ) ); \ - build_assert ( ( ( void * ) &context->gcm ) == ctx ); \ + build_assert ( ( ( void * ) &context->gcm ) == \ + ( ( void * ) context ) ); \ build_assert ( ( ( void * ) &context->raw ) == \ ( ( void * ) context->gcm.raw_ctx ) ); \ return gcm_setkey ( &context->gcm, key, keylen, &_raw_cipher ); \ -- cgit v1.2.3-55-g7522 From 88b291d647686ac686a5614fdd7be92b48747360 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Wed, 14 Feb 2024 16:01:43 +0000 Subject: [list] Add list_is_head_entry() Signed-off-by: Michael Brown --- src/include/ipxe/list.h | 11 +++++++++++ src/tests/list_test.c | 16 ++++++++++++++++ 2 files changed, 27 insertions(+) diff --git a/src/include/ipxe/list.h b/src/include/ipxe/list.h index 8de25498..53edfc9f 100644 --- a/src/include/ipxe/list.h +++ b/src/include/ipxe/list.h @@ -398,6 +398,17 @@ extern void extern_list_splice_tail_init ( struct list_head *list, #define list_is_last_entry( entry, head, member ) \ ( (head)->prev == &(entry)->member ) +/** + * Test if entry is the list head + * + * @v entry List entry + * @v head List head + * @v member Name of list field within iterator's type + * @ret is_head Entry is the list head + */ +#define list_is_head_entry( entry, head, member ) \ + ( (head) == &(entry)->member ) + /** * Iterate over a list * diff --git a/src/tests/list_test.c b/src/tests/list_test.c index d5b5c65d..f18c63f2 100644 --- a/src/tests/list_test.c +++ b/src/tests/list_test.c @@ -440,6 +440,22 @@ static void list_test_exec ( void ) { ok ( list_is_first_entry ( &list_tests[3], list, list ) ); ok ( list_is_last_entry ( &list_tests[3], list, list ) ); + /* Test list_is_head_entry() */ + INIT_LIST_HEAD ( list ); + list_add_tail ( &list_tests[1].list, list ); + list_add_tail ( &list_tests[6].list, list ); + list_add_tail ( &list_tests[8].list, list ); + ok ( list_is_head_entry ( list_entry ( list, typeof ( *pos ), list ), + list, list ) ); + ok ( ! list_is_head_entry ( &list_tests[1], list, list ) ); + ok ( ! list_is_head_entry ( &list_tests[6], list, list ) ); + ok ( ! list_is_head_entry ( &list_tests[8], list, list ) ); + list_for_each_entry ( pos, list, list ) { + ok ( list_contains_entry ( pos, list, list ) ); + ok ( ! list_is_head_entry ( pos, list, list ) ); + } + ok ( list_is_head_entry ( pos, list, list ) ); + /* Test list_for_each() */ INIT_LIST_HEAD ( list ); list_add_tail ( &list_tests[6].list, list ); -- cgit v1.2.3-55-g7522 From e10dfe5dc7a5985333c85d6b196196b5cce9303a Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Tue, 13 Feb 2024 16:26:34 +0000 Subject: [list] Add list_for_each_entry_safe_continue() Signed-off-by: Michael Brown --- src/include/ipxe/list.h | 16 ++++++++++++++++ src/tests/list_test.c | 32 ++++++++++++++++++++++++++++++++ 2 files changed, 48 insertions(+) diff --git a/src/include/ipxe/list.h b/src/include/ipxe/list.h index 53edfc9f..2f02e71f 100644 --- a/src/include/ipxe/list.h +++ b/src/include/ipxe/list.h @@ -489,6 +489,22 @@ extern void extern_list_splice_tail_init ( struct list_head *list, &pos->member != (head); \ pos = list_entry ( pos->member.prev, typeof ( *pos ), member ) ) +/** + * Iterate over subsequent entries in a list, safe against deletion + * + * @v pos Iterator + * @v tmp Temporary value (of same type as iterator) + * @v head List head + * @v member Name of list field within iterator's type + */ +#define list_for_each_entry_safe_continue( pos, tmp, head, member ) \ + for ( list_check ( (head) ), \ + pos = list_entry ( pos->member.next, typeof ( *pos ), member ), \ + tmp = list_entry ( pos->member.next, typeof ( *tmp ), member ); \ + &pos->member != (head); \ + pos = tmp, \ + tmp = list_entry ( tmp->member.next, typeof ( *tmp ), member ) ) + /** * Test if list contains a specified entry * diff --git a/src/tests/list_test.c b/src/tests/list_test.c index f18c63f2..c24e8082 100644 --- a/src/tests/list_test.c +++ b/src/tests/list_test.c @@ -518,6 +518,38 @@ static void list_test_exec ( void ) { list_iterate_entry_ok ( list_for_each_entry_continue_reverse, "", pos, list, list ); + /* Test list_for_each_entry_safe_continue() */ + INIT_LIST_HEAD ( list ); + list_add_tail ( &list_tests[9].list, list ); + list_add_tail ( &list_tests[4].list, list ); + list_add_tail ( &list_tests[2].list, list ); + list_add_tail ( &list_tests[5].list, list ); + list_add_tail ( &list_tests[7].list, list ); + { + char *expecteds[] = { "94257", "9457", "947", "94" }; + char **expected = expecteds; + pos = &list_tests[4]; + list_for_each_entry_safe_continue ( pos, tmp, list, list ) { + list_contents_ok ( list, *expected ); + list_del ( &pos->list ); + expected++; + list_contents_ok ( list, *expected ); + } + } + list_contents_ok ( list, "94" ); + { + char *expecteds[] = { "94", "4", "" }; + char **expected = expecteds; + ok ( pos == list_entry ( list, struct list_test, list ) ); + list_for_each_entry_safe_continue ( pos, tmp, list, list ) { + list_contents_ok ( list, *expected ); + list_del ( &pos->list ); + expected++; + list_contents_ok ( list, *expected ); + } + } + ok ( list_empty ( list ) ); + /* Test list_contains() and list_contains_entry() */ INIT_LIST_HEAD ( list ); INIT_LIST_HEAD ( &list_tests[3].list ); -- cgit v1.2.3-55-g7522 From 3e721e0c0836588b64deb6e1c1befd08f0f02e71 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Tue, 13 Feb 2024 16:27:31 +0000 Subject: [crypto] Add x509_truncate() to truncate a certificate chain Downloading a cross-signed certificate chain to partially replace (rather than simply extend) an existing chain will require the ability to discard all certificates after a specified link in the chain. Extract the relevant logic from x509_free_chain() and expose it separately as x509_truncate(). Signed-off-by: Michael Brown --- src/crypto/x509.c | 32 +++++++++++++++++++++++--------- src/include/ipxe/x509.h | 1 + src/tests/x509_test.c | 13 +++++++++++++ 3 files changed, 37 insertions(+), 9 deletions(-) diff --git a/src/crypto/x509.c b/src/crypto/x509.c index 1f017eb0..92318093 100644 --- a/src/crypto/x509.c +++ b/src/crypto/x509.c @@ -1603,19 +1603,12 @@ int x509_check_name ( struct x509_certificate *cert, const char *name ) { static void x509_free_chain ( struct refcnt *refcnt ) { struct x509_chain *chain = container_of ( refcnt, struct x509_chain, refcnt ); - struct x509_link *link; - struct x509_link *tmp; DBGC2 ( chain, "X509 chain %p freed\n", chain ); - /* Free each link in the chain */ - list_for_each_entry_safe ( link, tmp, &chain->links, list ) { - x509_put ( link->cert ); - list_del ( &link->list ); - free ( link ); - } - /* Free chain */ + x509_truncate ( chain, NULL ); + assert ( list_empty ( &chain->links ) ); free ( chain ); } @@ -1696,6 +1689,27 @@ int x509_append_raw ( struct x509_chain *chain, const void *data, return rc; } +/** + * Truncate X.509 certificate chain + * + * @v chain X.509 certificate chain + * @v link Link after which to truncate chain, or NULL + */ +void x509_truncate ( struct x509_chain *chain, struct x509_link *link ) { + struct x509_link *tmp; + + /* Truncate entire chain if no link is specified */ + if ( ! link ) + link = list_entry ( &chain->links, struct x509_link, list ); + + /* Free each link in the chain */ + list_for_each_entry_safe_continue ( link, tmp, &chain->links, list ) { + x509_put ( link->cert ); + list_del ( &link->list ); + free ( link ); + } +} + /** * Identify X.509 certificate by subject * diff --git a/src/include/ipxe/x509.h b/src/include/ipxe/x509.h index c703c8f1..5cad4597 100644 --- a/src/include/ipxe/x509.h +++ b/src/include/ipxe/x509.h @@ -391,6 +391,7 @@ extern int x509_append ( struct x509_chain *chain, struct x509_certificate *cert ); extern int x509_append_raw ( struct x509_chain *chain, const void *data, size_t len ); +extern void x509_truncate ( struct x509_chain *chain, struct x509_link *link ); extern int x509_auto_append ( struct x509_chain *chain, struct x509_chain *certs ); extern int x509_validate_chain ( struct x509_chain *chain, time_t time, diff --git a/src/tests/x509_test.c b/src/tests/x509_test.c index b6cba575..bc903204 100644 --- a/src/tests/x509_test.c +++ b/src/tests/x509_test.c @@ -984,6 +984,7 @@ static void x509_validate_chain_fail_okx ( struct x509_test_chain *chn, * */ static void x509_test_exec ( void ) { + struct x509_link *link; /* Parse all certificates */ x509_certificate_ok ( &root_crt ); @@ -1089,6 +1090,18 @@ static void x509_test_exec ( void ) { x509_validate_chain_fail_ok ( &useless_chain, test_ca_expired, &empty_store, &test_root ); + /* Check chain truncation */ + link = list_last_entry ( &server_chain.chain->links, + struct x509_link, list ); + ok ( link->cert == root_crt.cert ); + link = list_prev_entry ( link, &server_chain.chain->links, list ); + ok ( link->cert == intermediate_crt.cert ); + x509_validate_chain_ok ( &server_chain, test_time, + &empty_store, &test_root ); + x509_truncate ( server_chain.chain, link ); + x509_validate_chain_fail_ok ( &server_chain, test_time, + &empty_store, &test_root ); + /* Sanity check */ assert ( list_empty ( &empty_store.links ) ); -- cgit v1.2.3-55-g7522 From 943d75b557a8bf857d651e8116a7368b9d284e41 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Thu, 15 Feb 2024 12:43:51 +0000 Subject: [crypto] Add x509_is_self_signed() helper function Signed-off-by: Michael Brown --- src/include/ipxe/x509.h | 10 ++++++++++ src/net/validator.c | 2 +- src/tests/x509_test.c | 4 ++++ 3 files changed, 15 insertions(+), 1 deletion(-) diff --git a/src/include/ipxe/x509.h b/src/include/ipxe/x509.h index 5cad4597..d2ba49fb 100644 --- a/src/include/ipxe/x509.h +++ b/src/include/ipxe/x509.h @@ -374,6 +374,16 @@ x509_root_put ( struct x509_root *root ) { ref_put ( &root->refcnt ); } +/** + * Check if X.509 certificate is self-signed + * + * @v cert X.509 certificate + * @ret is_self_signed X.509 certificate is self-signed + */ +static inline int x509_is_self_signed ( struct x509_certificate *cert ) { + return ( asn1_compare ( &cert->issuer.raw, &cert->subject.raw ) == 0 ); +} + extern const char * x509_name ( struct x509_certificate *cert ); extern int x509_parse ( struct x509_certificate *cert, const struct asn1_cursor *raw ); diff --git a/src/net/validator.c b/src/net/validator.c index 693d4464..333c6079 100644 --- a/src/net/validator.c +++ b/src/net/validator.c @@ -595,7 +595,7 @@ static void validator_step ( struct validator *validator ) { * nothing more to do. */ last = x509_last ( validator->chain ); - if ( asn1_compare ( &last->issuer.raw, &last->subject.raw ) == 0 ) { + if ( x509_is_self_signed ( last ) ) { validator_finished ( validator, rc ); return; } diff --git a/src/tests/x509_test.c b/src/tests/x509_test.c index bc903204..50eb4d78 100644 --- a/src/tests/x509_test.c +++ b/src/tests/x509_test.c @@ -1102,6 +1102,10 @@ static void x509_test_exec ( void ) { x509_validate_chain_fail_ok ( &server_chain, test_time, &empty_store, &test_root ); + /* Check self-signedess */ + ok ( x509_is_self_signed ( root_crt.cert ) ); + ok ( ! x509_is_self_signed ( intermediate_crt.cert ) ); + /* Sanity check */ assert ( list_empty ( &empty_store.links ) ); -- cgit v1.2.3-55-g7522 From 929f06a76de37612015882af592997a7da15a82d Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Wed, 14 Feb 2024 16:02:43 +0000 Subject: [crypto] Allow for multiple cross-signed certificate download attempts Certificates issued by Let's Encrypt have two options for their chain of trust: the chain can either terminate in the self-signed ISRG Root X1 root certificate, or in an intermediate ISRG Root X1 certificate that is signed in turn by the self-signed DST Root CA X3 root certificate. This is a historical artifact: when Let's Encrypt first launched as a project, the chain ending in DST Root CA X3 was used since existing clients would not have recognised the ISRG Root X1 certificate as a trusted root certificate. The DST Root CA X3 certificate expired in September 2021, and so is no longer trusted by clients (such as iPXE) that validate the expiry times of all certificates in the certificate chain. In order to maintain usability of certificates on older Android devices, the default certificate chain provided by Let's Encrypt still terminates in DST Root CA X3, even though that certificate has now expired. On newer devices which include ISRG Root X1 as a trusted root certificate, the intermediate version of ISRG Root X1 in the certificate chain is ignored and validation is performed as though the chain had terminated in the self-signed ISRG Root X1 root certificate. On older Android devices which do not include ISRG Root X1 as a trusted root certificate, the validation succeeds since Android chooses to ignore expiry times for root certificates and so continues to trust the DST Root CA X3 root certificate. This backwards compatibility hack unfortunately breaks the cross- signing mechanism used by iPXE, which assumes that the certificate chain will always terminate in a non-expired root certificate. Generalise the validator's cross-signed certificate download mechanism to walk up the certificate chain in the event of a failure, attempting to find a replacement cross-signed certificate chain starting from the next level up. This allows the validator to step over the expired (and hence invalidatable) DST Root CA X3 certificate, and instead download the cross-signed version of the ISRG Root X1 certificate. This generalisation also gives us the ability to handle servers that provide a full certificate chain including their root certificate: iPXE will step over the untrusted public root certificate and attempt to find a cross-signed version of it instead. Signed-off-by: Michael Brown --- src/include/ipxe/x509.h | 22 ++++ src/net/validator.c | 327 +++++++++++++++++++++++++++++++++--------------- 2 files changed, 249 insertions(+), 100 deletions(-) diff --git a/src/include/ipxe/x509.h b/src/include/ipxe/x509.h index d2ba49fb..87323cec 100644 --- a/src/include/ipxe/x509.h +++ b/src/include/ipxe/x509.h @@ -171,6 +171,28 @@ struct x509_link { struct list_head list; /** Certificate */ struct x509_certificate *cert; + /** Flags */ + unsigned int flags; +}; + +/** X.509 certficate chain link flags */ +enum x509_link_flags { + /** Cross-signed certificate download has been attempted + * + * This indicates that a cross-signature download attempt has + * been made to find a cross-signed issuer for this link's + * certificate. + */ + X509_LINK_FL_CROSSED = 0x0001, + /** OCSP has been attempted + * + * This indicates that an OCSP attempt has been made using + * this link's certificate as an issuer. (We record the flag + * on the issuer rather than on the issued certificate, since + * we want to retry OCSP if an issuer is replaced with a + * downloaded cross-signed certificate.) + */ + X509_LINK_FL_OCSPED = 0x0002, }; /** An X.509 certificate chain */ diff --git a/src/net/validator.c b/src/net/validator.c index 333c6079..69c0df33 100644 --- a/src/net/validator.c +++ b/src/net/validator.c @@ -57,8 +57,7 @@ struct validator_action { /** Name */ const char *name; /** Action to take upon completed transfer */ - int ( * done ) ( struct validator *validator, const void *data, - size_t len ); + void ( * done ) ( struct validator *validator, int rc ); }; /** A certificate validator */ @@ -72,6 +71,40 @@ struct validator { /** Process */ struct process process; + /** Most relevant status code + * + * The cross-signed certificate mechanism may attempt several + * downloads as it works its way up the provided partial chain + * to locate a suitable cross-signed certificate with which to + * complete the chain. + * + * Some of these download or validation attempts may fail for + * uninteresting reasons (i.e. because a cross-signed + * certificate has never existed for that link in the chain). + * + * We must therefore keep track of the most relevant error + * that has occurred, in order to be able to report a + * meaningful overall status to the user. + * + * As a concrete example: consider the case of an expired OCSP + * signer for an intermediate certificate. This will cause + * OCSP validation to fail for that intermediate certificate, + * and this is the error that should eventually be reported to + * the user. We do not want to instead report the + * uninteresting fact that no cross-signed certificate was + * found for the remaining links in the chain, nor do we want + * to report just a generic "OCSP required" error. + * + * We record the most relevant status code whenever a + * definitely relevant error occurs, and clear it whenever we + * successfully make forward progress (e.g. by completing + * OCSP, or by adding new cross-signed certificates). + * + * When we subsequently attempt to validate the chain, we + * report the most relevant error status code (if recorded), + * otherwise we report the validation error itself. + */ + int rc; /** Root of trust (or NULL to use default) */ struct x509_root *root; @@ -84,13 +117,15 @@ struct validator { /** Current action */ const struct validator_action *action; - /** Current certificate + /** Current certificate (for progress reporting) * * This will always be present within the certificate chain * and so this pointer does not hold a reference to the * certificate. */ struct x509_certificate *cert; + /** Current link within certificate chain */ + struct x509_link *link; }; /** @@ -196,17 +231,36 @@ static const char crosscert_default[] = CROSSCERT; * Append cross-signing certificates to certificate chain * * @v validator Certificate validator - * @v data Raw cross-signing certificate data - * @v len Length of raw data + * @v rc Completion status code * @ret rc Return status code */ -static int validator_append ( struct validator *validator, - const void *data, size_t len ) { +static void validator_append ( struct validator *validator, int rc ) { struct asn1_cursor cursor; struct x509_chain *certs; struct x509_certificate *cert; - struct x509_certificate *last; - int rc; + struct x509_link *link; + struct x509_link *prev; + + /* Check for errors */ + if ( rc != 0 ) { + DBGC ( validator, "VALIDATOR %p \"%s\" could not download ", + validator, validator_name ( validator ) ); + DBGC ( validator, "\"%s\" cross-signature: %s\n", + x509_name ( validator->cert ), strerror ( rc ) ); + /* If the overall validation is going to fail, then we + * will end up attempting multiple downloads for + * non-existent cross-signed certificates as we work + * our way up the certificate chain. Do not record + * these as relevant errors, since we want to + * eventually report whichever much more relevant + * error occurred previously. + */ + goto err_irrelevant; + } + DBGC ( validator, "VALIDATOR %p \"%s\" downloaded ", + validator, validator_name ( validator ) ); + DBGC ( validator, "\"%s\" cross-signature\n", + x509_name ( validator->cert ) ); /* Allocate certificate list */ certs = x509_alloc_chain(); @@ -216,8 +270,8 @@ static int validator_append ( struct validator *validator, } /* Initialise cursor */ - cursor.data = data; - cursor.len = len; + cursor.data = validator->buffer.data; + cursor.len = validator->buffer.len; /* Enter certificateSet */ if ( ( rc = asn1_enter ( &cursor, ASN1_SET ) ) != 0 ) { @@ -230,14 +284,14 @@ static int validator_append ( struct validator *validator, /* Add each certificate to list */ while ( cursor.len ) { - /* Add certificate to chain */ + /* Add certificate to list */ if ( ( rc = x509_append_raw ( certs, cursor.data, cursor.len ) ) != 0 ) { DBGC ( validator, "VALIDATOR %p \"%s\" could not " "append certificate: %s\n", validator, validator_name ( validator ), strerror ( rc) ); DBGC_HDA ( validator, 0, cursor.data, cursor.len ); - return rc; + goto err_append_raw; } cert = x509_last ( certs ); DBGC ( validator, "VALIDATOR %p \"%s\" found certificate ", @@ -248,8 +302,12 @@ static int validator_append ( struct validator *validator, asn1_skip_any ( &cursor ); } + /* Truncate existing certificate chain at current link */ + link = validator->link; + assert ( link->flags & X509_LINK_FL_CROSSED ); + x509_truncate ( validator->chain, link ); + /* Append certificates to chain */ - last = x509_last ( validator->chain ); if ( ( rc = x509_auto_append ( validator->chain, certs ) ) != 0 ) { DBGC ( validator, "VALIDATOR %p \"%s\" could not append " "certificates: %s\n", validator, @@ -257,26 +315,31 @@ static int validator_append ( struct validator *validator, goto err_auto_append; } - /* Check that at least one certificate has been added */ - if ( last == x509_last ( validator->chain ) ) { - DBGC ( validator, "VALIDATOR %p \"%s\" failed to append any " - "applicable certificates\n", validator, - validator_name ( validator ) ); - rc = -EACCES; - goto err_no_progress; + /* Record that a cross-signed certificate download has already + * been performed for all but the last of the appended + * certificates. (It may be necessary to perform a further + * download to complete the chain, if this download did not + * extend all the way to a root of trust.) + */ + prev = NULL; + list_for_each_entry_continue ( link, &validator->chain->links, list ) { + if ( prev ) + prev->flags |= X509_LINK_FL_CROSSED; + prev = link; } - /* Drop reference to certificate list */ - x509_chain_put ( certs ); - - return 0; + /* Success */ + rc = 0; - err_no_progress: err_auto_append: + err_append_raw: err_certificateset: x509_chain_put ( certs ); err_alloc_certs: - return rc; + validator->rc = rc; + err_irrelevant: + /* Do not record irrelevant errors */ + return; } /** Cross-signing certificate download validator action */ @@ -289,11 +352,12 @@ static const struct validator_action validator_crosscert = { * Start download of cross-signing certificate * * @v validator Certificate validator - * @v cert X.509 certificate + * @v link Link in certificate chain * @ret rc Return status code */ static int validator_start_download ( struct validator *validator, - struct x509_certificate *cert ) { + struct x509_link *link ) { + struct x509_certificate *cert = link->cert; const struct asn1_cursor *issuer = &cert->issuer.raw; const char *crosscert; char *crosscert_copy; @@ -336,6 +400,7 @@ static int validator_start_download ( struct validator *validator, /* Set completion handler */ validator->action = &validator_crosscert; validator->cert = cert; + validator->link = link; /* Open URI */ if ( ( rc = xfer_open_uri_string ( &validator->xfer, @@ -346,14 +411,20 @@ static int validator_start_download ( struct validator *validator, goto err_open_uri_string; } + /* Free temporary allocations */ + free ( uri_string ); + free ( crosscert_copy ); + /* Success */ - rc = 0; + return 0; + intf_restart ( &validator->xfer, rc ); err_open_uri_string: free ( uri_string ); err_alloc_uri_string: err_check_uri_string: free ( crosscert_copy ); + validator->rc = rc; return rc; } @@ -367,21 +438,27 @@ static int validator_start_download ( struct validator *validator, * Validate OCSP response * * @v validator Certificate validator - * @v data Raw OCSP response - * @v len Length of raw data - * @ret rc Return status code + * @v rc Completion status code */ -static int validator_ocsp_validate ( struct validator *validator, - const void *data, size_t len ) { +static void validator_ocsp_validate ( struct validator *validator, int rc ) { + const void *data = validator->buffer.data; + size_t len = validator->buffer.len; time_t now; - int rc; + + /* Check for errors */ + if ( rc != 0 ) { + DBGC ( validator, "VALIDATOR %p \"%s\" could not fetch OCSP " + "response: %s\n", validator, + validator_name ( validator ), strerror ( rc ) ); + goto err_status; + } /* Record OCSP response */ if ( ( rc = ocsp_response ( validator->ocsp, data, len ) ) != 0 ) { DBGC ( validator, "VALIDATOR %p \"%s\" could not record OCSP " "response: %s\n", validator, - validator_name ( validator ),strerror ( rc ) ); - return rc; + validator_name ( validator ), strerror ( rc ) ); + goto err_response; } /* Validate OCSP response */ @@ -390,14 +467,20 @@ static int validator_ocsp_validate ( struct validator *validator, DBGC ( validator, "VALIDATOR %p \"%s\" could not validate " "OCSP response: %s\n", validator, validator_name ( validator ), strerror ( rc ) ); - return rc; + goto err_validate; } - /* Drop reference to OCSP check */ + /* Success */ + DBGC ( validator, "VALIDATOR %p \"%s\" checked ", + validator, validator_name ( validator ) ); + DBGC ( validator, "\"%s\" via OCSP\n", x509_name ( validator->cert ) ); + + err_validate: + err_response: + err_status: ocsp_put ( validator->ocsp ); validator->ocsp = NULL; - - return 0; + validator->rc = rc; } /** OCSP validator action */ @@ -426,7 +509,7 @@ static int validator_start_ocsp ( struct validator *validator, DBGC ( validator, "VALIDATOR %p \"%s\" could not create OCSP " "check: %s\n", validator, validator_name ( validator ), strerror ( rc ) ); - return rc; + goto err_check; } /* Set completion handler */ @@ -444,10 +527,18 @@ static int validator_start_ocsp ( struct validator *validator, DBGC ( validator, "VALIDATOR %p \"%s\" could not open %s: " "%s\n", validator, validator_name ( validator ), uri_string, strerror ( rc ) ); - return rc; + goto err_open; } return 0; + + intf_restart ( &validator->xfer, rc ); + err_open: + ocsp_put ( validator->ocsp ); + validator->ocsp = NULL; + err_check: + validator->rc = rc; + return rc; } /**************************************************************************** @@ -466,34 +557,18 @@ static void validator_xfer_close ( struct validator *validator, int rc ) { /* Close data transfer interface */ intf_restart ( &validator->xfer, rc ); - - /* Check for errors */ - if ( rc != 0 ) { - DBGC ( validator, "VALIDATOR %p \"%s\" transfer failed: %s\n", - validator, validator_name ( validator ), - strerror ( rc ) ); - goto err_transfer; - } DBGC2 ( validator, "VALIDATOR %p \"%s\" transfer complete\n", validator, validator_name ( validator ) ); /* Process completed download */ assert ( validator->action != NULL ); - if ( ( rc = validator->action->done ( validator, validator->buffer.data, - validator->buffer.len ) ) != 0 ) - goto err_append; + validator->action->done ( validator, rc ); /* Free downloaded data */ xferbuf_free ( &validator->buffer ); /* Resume validation process */ process_add ( &validator->process ); - - return; - - err_append: - err_transfer: - validator_finished ( validator, rc ); } /** @@ -515,7 +590,7 @@ static int validator_xfer_deliver ( struct validator *validator, DBGC ( validator, "VALIDATOR %p \"%s\" could not receive " "data: %s\n", validator, validator_name ( validator ), strerror ( rc ) ); - validator_finished ( validator, rc ); + validator_xfer_close ( validator, rc ); return rc; } @@ -544,10 +619,10 @@ static struct interface_descriptor validator_xfer_desc = * @v validator Certificate validator */ static void validator_step ( struct validator *validator ) { + struct x509_chain *chain = validator->chain; struct x509_link *link; + struct x509_link *prev; struct x509_certificate *cert; - struct x509_certificate *issuer = NULL; - struct x509_certificate *last; time_t now; int rc; @@ -556,57 +631,109 @@ static void validator_step ( struct validator *validator ) { * previously. */ now = time ( NULL ); - if ( ( rc = x509_validate_chain ( validator->chain, now, NULL, + if ( ( rc = x509_validate_chain ( chain, now, NULL, validator->root ) ) == 0 ) { DBGC ( validator, "VALIDATOR %p \"%s\" validated\n", validator, validator_name ( validator ) ); validator_finished ( validator, 0 ); return; } + DBGC ( validator, "VALIDATOR %p \"%s\" not yet valid: %s\n", + validator, validator_name ( validator ), strerror ( rc ) ); - /* If there is a certificate that could be validated using - * OCSP, try it. + /* Record as the most relevant error, if no more relevant + * error has already been recorded. */ - list_for_each_entry ( link, &validator->chain->links, list ) { - cert = issuer; - issuer = link->cert; - if ( ! cert ) - continue; - if ( ! x509_is_valid ( issuer, validator->root ) ) - continue; - /* The issuer is valid, but this certificate is not - * yet valid. If OCSP is applicable, start it. - */ - if ( ocsp_required ( cert ) ) { - /* Start OCSP */ - if ( ( rc = validator_start_ocsp ( validator, cert, - issuer ) ) != 0 ) { - validator_finished ( validator, rc ); - return; - } - return; - } - /* Otherwise, this is a permanent failure */ - validator_finished ( validator, rc ); - return; + if ( validator->rc == 0 ) + validator->rc = rc; + + /* Find the first valid link in the chain, if any + * + * There is no point in attempting OCSP or cross-signed + * certificate downloads for certificates after the first + * valid link in the chain, since they cannot make a + * difference to the overall validation of the chain. + */ + prev = NULL; + list_for_each_entry ( link, &chain->links, list ) { + + /* Dump link information (for debugging) */ + DBGC ( validator, "VALIDATOR %p \"%s\" has link ", + validator, validator_name ( validator ) ); + DBGC ( validator, "\"%s\"%s%s%s%s%s\n", + x509_name ( link->cert ), + ( ocsp_required ( link->cert ) ? " [NEEDOCSP]" : "" ), + ( ( link->flags & X509_LINK_FL_OCSPED ) ? + " [OCSPED]" : "" ), + ( ( link->flags & X509_LINK_FL_CROSSED ) ? + " [CROSSED]" : "" ), + ( x509_is_self_signed ( link->cert ) ? " [SELF]" : "" ), + ( x509_is_valid ( link->cert, validator->root ) ? + " [VALID]" : "" ) ); + + /* Stop at first valid link */ + if ( x509_is_valid ( link->cert, validator->root ) ) + break; + prev = link; } - /* If chain ends with a self-issued certificate, then there is - * nothing more to do. + /* If this link is the issuer for a certificate that is + * pending an OCSP check attempt, then start OCSP to validate + * that certificate. + * + * If OCSP is not required for the issued certificate, or has + * already been attempted, or if we were unable to start OCSP + * for any reason, then proceed to attempting a cross-signed + * certificate download (which may end up replacing this + * issuer anyway). */ - last = x509_last ( validator->chain ); - if ( x509_is_self_signed ( last ) ) { - validator_finished ( validator, rc ); - return; + if ( ( ! list_is_head_entry ( link, &chain->links, list ) ) && + ( ! ( link->flags & X509_LINK_FL_OCSPED ) ) && + ( prev != NULL ) && ocsp_required ( prev->cert ) ) { + + /* Mark OCSP as attempted with this issuer */ + link->flags |= X509_LINK_FL_OCSPED; + + /* Start OCSP */ + if ( ( rc = validator_start_ocsp ( validator, prev->cert, + link->cert ) ) == 0 ) { + /* Sleep until OCSP is complete */ + return; + } } - /* Otherwise, try to download a suitable cross-signing - * certificate. + /* Work back up the chain (starting from the already + * identified first valid link, if any) to find a not-yet + * valid certificate for which we could attempt to download a + * cross-signed certificate chain. */ - if ( ( rc = validator_start_download ( validator, last ) ) != 0 ) { - validator_finished ( validator, rc ); - return; + list_for_each_entry_continue_reverse ( link, &chain->links, list ) { + cert = link->cert; + + /* Sanity check */ + assert ( ! x509_is_valid ( cert, validator->root ) ); + + /* Skip self-signed certificates (cannot be cross-signed) */ + if ( x509_is_self_signed ( cert ) ) + continue; + + /* Skip previously attempted cross-signed downloads */ + if ( link->flags & X509_LINK_FL_CROSSED ) + continue; + + /* Mark cross-signed certificate download as attempted */ + link->flags |= X509_LINK_FL_CROSSED; + + /* Start cross-signed certificate download */ + if ( ( rc = validator_start_download ( validator, + link ) ) == 0 ) { + /* Sleep until download is complete */ + return; + } } + + /* Nothing more to try: fail the validation */ + validator_finished ( validator, validator->rc ); } /** Certificate validator process descriptor */ -- cgit v1.2.3-55-g7522 From 075292cc2dcde1ad2580d37ac019f29a0eaa01ef Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Wed, 21 Feb 2024 16:45:50 +0000 Subject: [crypto] Add implementation of MS-CHAPv2 authentication Add an implementation of the authentication portions of the MS-CHAPv2 algorithm as defined in RFC 2759, along with the single test vector provided therein. Signed-off-by: Michael Brown --- src/crypto/mschapv2.c | 363 ++++++++++++++++++++++++++++++++++++++++++++ src/include/ipxe/mschapv2.h | 59 +++++++ src/tests/mschapv2_test.c | 144 ++++++++++++++++++ src/tests/tests.c | 1 + 4 files changed, 567 insertions(+) create mode 100644 src/crypto/mschapv2.c create mode 100644 src/include/ipxe/mschapv2.h create mode 100644 src/tests/mschapv2_test.c diff --git a/src/crypto/mschapv2.c b/src/crypto/mschapv2.c new file mode 100644 index 00000000..ac55fec1 --- /dev/null +++ b/src/crypto/mschapv2.c @@ -0,0 +1,363 @@ +/* + * Copyright (C) 2024 Michael Brown . + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + * + * You can also choose to distribute this program under the terms of + * the Unmodified Binary Distribution Licence (as given in the file + * COPYING.UBDL), provided that you have satisfied its requirements. + */ + +FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); + +/** @file + * + * MS-CHAPv2 authentication + * + * The algorithms used for MS-CHAPv2 authentication are defined in + * RFC 2759 section 8. + */ + +#include +#include +#include +#include +#include +#include +#include + +/** + * MS-CHAPv2 context block + * + * For no particularly discernible reason, MS-CHAPv2 uses two + * different digest algorithms and one block cipher. The uses do not + * overlap, so share the context storage between these to reduce stack + * usage. + */ +union mschapv2_context { + /** SHA-1 digest context */ + uint8_t sha1[SHA1_CTX_SIZE]; + /** MD4 digest context */ + uint8_t md4[MD4_CTX_SIZE]; + /** DES cipher context */ + uint8_t des[DES_CTX_SIZE]; +}; + +/** + * MS-CHAPv2 challenge hash + * + * MS-CHAPv2 calculates the SHA-1 digest of the peer challenge, the + * authenticator challenge, and the username, and then uses only the + * first 8 bytes of the result (as a DES plaintext block). + */ +union mschapv2_challenge_hash { + /** SHA-1 digest */ + uint8_t sha1[SHA1_DIGEST_SIZE]; + /** DES plaintext block */ + uint8_t des[DES_BLOCKSIZE]; +}; + +/** + * MS-CHAPv2 password hash + * + * MS-CHAPv2 calculates the MD4 digest of an unspecified two-byte + * little-endian Unicode encoding (presumably either UCS-2LE or + * UTF-16LE) of the password. + * + * For constructing the challenge response, the MD4 digest is then + * zero-padded to 21 bytes and used as three separate 56-bit DES keys. + * + * For constructing the authenticator response, the MD4 digest is then + * used as an input to a SHA-1 digest along with the NT response and a + * magic constant. + */ +union mschapv2_password_hash { + /** MD4 digest */ + uint8_t md4[MD4_DIGEST_SIZE]; + /** SHA-1 digest */ + uint8_t sha1[SHA1_DIGEST_SIZE]; + /** DES keys */ + uint8_t des[3][DES_BLOCKSIZE]; + /** DES key expansion */ + uint8_t expand[ 3 * DES_BLOCKSIZE ]; +}; + +/** MS-CHAPv2 magic constant 1 */ +static const char mschapv2_magic1[39] = + "Magic server to client signing constant"; + +/** MS-CHAPv2 magic constant 2 */ +static const char mschapv2_magic2[41] = + "Pad to make it do more than one iteration"; + +/** + * Calculate MS-CHAPv2 challenge hash + * + * @v ctx Context block + * @v challenge Authenticator challenge + * @v peer Peer challenge + * @v username User name (or NULL to use empty string) + * @v chash Challenge hash to fill in + * + * This is the ChallengeHash() function as documented in RFC 2759 + * section 8.2. + */ +static void +mschapv2_challenge_hash ( union mschapv2_context *ctx, + const struct mschapv2_challenge *challenge, + const struct mschapv2_challenge *peer, + const char *username, + union mschapv2_challenge_hash *chash ) { + struct digest_algorithm *sha1 = &sha1_algorithm; + + /* Calculate SHA-1 hash of challenges and username */ + digest_init ( sha1, ctx->sha1 ); + digest_update ( sha1, ctx->sha1, peer, sizeof ( *peer ) ); + digest_update ( sha1, ctx->sha1, challenge, sizeof ( *challenge ) ); + if ( username ) { + digest_update ( sha1, ctx->sha1, username, + strlen ( username ) ); + } + digest_final ( sha1, ctx->sha1, chash->sha1 ); + DBGC ( ctx, "MSCHAPv2 authenticator challenge:\n" ); + DBGC_HDA ( ctx, 0, challenge, sizeof ( *challenge ) ); + DBGC ( ctx, "MSCHAPv2 peer challenge:\n" ); + DBGC_HDA ( ctx, 0, peer, sizeof ( *peer ) ); + DBGC ( ctx, "MSCHAPv2 challenge hash:\n" ); + DBGC_HDA ( ctx, 0, chash->des, sizeof ( chash->des ) ); +} + +/** + * Calculate MS-CHAPv2 password hash + * + * @v ctx Context block + * @v password Password (or NULL to use empty string) + * @v phash Password hash to fill in + * + * This is the NtPasswordHash() function as documented in RFC 2759 + * section 8.3. + */ +static void mschapv2_password_hash ( union mschapv2_context *ctx, + const char *password, + union mschapv2_password_hash *phash ) { + struct digest_algorithm *md4 = &md4_algorithm; + uint16_t wc; + uint8_t c; + + /* Construct zero-padded MD4 hash of encoded password */ + memset ( phash, 0, sizeof ( *phash ) ); + digest_init ( md4, ctx->md4 ); + if ( password ) { + while ( ( c = *(password++) ) ) { + wc = cpu_to_le16 ( c ); + digest_update ( md4, ctx->md4, &wc, sizeof ( wc ) ); + } + } + digest_final ( md4, ctx->md4, phash->md4 ); + DBGC ( ctx, "MSCHAPv2 password hash:\n" ); + DBGC_HDA ( ctx, 0, phash->md4, sizeof ( phash->md4 ) ); +} + +/** + * Hash the MS-CHAPv2 password hash + * + * @v ctx Context block + * @v phash Password hash to be rehashed + * + * This is the HashNtPasswordHash() function as documented in RFC 2759 + * section 8.4. + */ +static void mschapv2_hash_hash ( union mschapv2_context *ctx, + union mschapv2_password_hash *phash ) { + struct digest_algorithm *md4 = &md4_algorithm; + + /* Calculate MD4 hash of existing MD4 hash */ + digest_init ( md4, ctx->md4 ); + digest_update ( md4, ctx->md4, phash->md4, sizeof ( phash->md4 ) ); + digest_final ( md4, ctx->md4, phash->md4 ); + DBGC ( ctx, "MSCHAPv2 password hash hash:\n" ); + DBGC_HDA ( ctx, 0, phash->md4, sizeof ( phash->md4 ) ); +} + +/** + * Expand MS-CHAPv2 password hash by inserting DES dummy parity bits + * + * @v ctx Context block + * @v phash Password hash to expand + * + * This is part of the DesEncrypt() function as documented in RFC 2759 + * section 8.6. + */ +static void mschapv2_expand_hash ( union mschapv2_context *ctx, + union mschapv2_password_hash *phash ) { + uint8_t *dst; + uint8_t *src; + unsigned int i; + + /* Expand password hash by inserting (unused) DES parity bits */ + for ( i = ( sizeof ( phash->expand ) - 1 ) ; i > 0 ; i-- ) { + dst = &phash->expand[i]; + src = ( dst - ( i / 8 ) ); + *dst = ( ( ( src[-1] << 8 ) | src[0] ) >> ( i % 8 ) ); + } + DBGC ( ctx, "MSCHAPv2 expanded password hash:\n" ); + DBGC_HDA ( ctx, 0, phash->expand, sizeof ( phash->expand ) ); +} + +/** + * Calculate MS-CHAPv2 challenge response + * + * @v ctx Context block + * @v chash Challenge hash + * @v phash Password hash (after expansion) + * @v nt NT response to fill in + * + * This is the ChallengeResponse() function as documented in RFC 2759 + * section 8.5. + */ +static void +mschapv2_challenge_response ( union mschapv2_context *ctx, + const union mschapv2_challenge_hash *chash, + const union mschapv2_password_hash *phash, + struct mschapv2_nt_response *nt ) { + struct cipher_algorithm *des = &des_algorithm; + unsigned int i; + int rc; + + /* Construct response. The design of the algorithm here is + * interesting, suggesting that an intern at Microsoft had + * heard the phrase "Triple DES" and hazarded a blind guess at + * what it might mean. + */ + for ( i = 0 ; i < ( sizeof ( phash->des ) / + sizeof ( phash->des[0] ) ) ; i++ ) { + rc = cipher_setkey ( des, ctx->des, phash->des[i], + sizeof ( phash->des[i] ) ); + assert ( rc == 0 ); /* no failure mode exists */ + cipher_encrypt ( des, ctx->des, chash->des, nt->block[i], + sizeof ( chash->des ) ); + } + DBGC ( ctx, "MSCHAPv2 NT response:\n" ); + DBGC_HDA ( ctx, 0, nt, sizeof ( *nt ) ); +} + +/** + * Calculate MS-CHAPv2 challenge response + * + * @v username User name (or NULL to use empty string) + * @v password Password (or NULL to use empty string) + * @v challenge Authenticator challenge + * @v peer Peer challenge + * @v response Challenge response to fill in + * + * This is essentially the GenerateNTResponse() function as documented + * in RFC 2759 section 8.1. + */ +void mschapv2_response ( const char *username, const char *password, + const struct mschapv2_challenge *challenge, + const struct mschapv2_challenge *peer, + struct mschapv2_response *response ) { + union mschapv2_context ctx; + union mschapv2_challenge_hash chash; + union mschapv2_password_hash phash; + + /* Zero reserved fields */ + memset ( response, 0, sizeof ( *response ) ); + + /* Copy peer challenge to response */ + memcpy ( &response->peer, peer, sizeof ( response->peer ) ); + + /* Construct challenge hash */ + mschapv2_challenge_hash ( &ctx, challenge, peer, username, &chash ); + + /* Construct expanded password hash */ + mschapv2_password_hash ( &ctx, password, &phash ); + mschapv2_expand_hash ( &ctx, &phash ); + + /* Construct NT response */ + mschapv2_challenge_response ( &ctx, &chash, &phash, &response->nt ); + DBGC ( &ctx, "MSCHAPv2 challenge response:\n" ); + DBGC_HDA ( &ctx, 0, response, sizeof ( *response ) ); +} + +/** + * Calculate MS-CHAPv2 authenticator response + * + * @v username User name (or NULL to use empty string) + * @v password Password (or NULL to use empty string) + * @v challenge Authenticator challenge + * @v response Challenge response + * @v auth Authenticator response to fill in + * + * This is essentially the GenerateAuthenticatorResponse() function as + * documented in RFC 2759 section 8.7. + */ +void mschapv2_auth ( const char *username, const char *password, + const struct mschapv2_challenge *challenge, + const struct mschapv2_response *response, + struct mschapv2_auth *auth ) { + struct digest_algorithm *sha1 = &sha1_algorithm; + union mschapv2_context ctx; + union mschapv2_challenge_hash chash; + union mschapv2_password_hash phash; + char tmp[3]; + char *wtf; + unsigned int i; + + /* Construct hash of password hash */ + mschapv2_password_hash ( &ctx, password, &phash ); + mschapv2_hash_hash ( &ctx, &phash ); + + /* Construct unnamed intermediate hash */ + digest_init ( sha1, ctx.sha1 ); + digest_update ( sha1, ctx.sha1, phash.md4, sizeof ( phash.md4 ) ); + digest_update ( sha1, ctx.sha1, &response->nt, + sizeof ( response->nt ) ); + digest_update ( sha1, ctx.sha1, mschapv2_magic1, + sizeof ( mschapv2_magic1 ) ); + digest_final ( sha1, ctx.sha1, phash.sha1 ); + DBGC ( &ctx, "MSCHAPv2 NT response:\n" ); + DBGC_HDA ( &ctx, 0, &response->nt, sizeof ( response->nt ) ); + DBGC ( &ctx, "MSCHAPv2 unnamed intermediate hash:\n" ); + DBGC_HDA ( &ctx, 0, phash.sha1, sizeof ( phash.sha1 ) ); + + /* Construct challenge hash */ + mschapv2_challenge_hash ( &ctx, challenge, &response->peer, + username, &chash ); + + /* Construct authenticator response hash */ + digest_init ( sha1, ctx.sha1 ); + digest_update ( sha1, ctx.sha1, phash.sha1, sizeof ( phash.sha1 ) ); + digest_update ( sha1, ctx.sha1, chash.des, sizeof ( chash.des ) ); + digest_update ( sha1, ctx.sha1, mschapv2_magic2, + sizeof ( mschapv2_magic2 ) ); + digest_final ( sha1, ctx.sha1, phash.sha1 ); + DBGC ( &ctx, "MSCHAPv2 authenticator response hash:\n" ); + DBGC_HDA ( &ctx, 0, phash.sha1, sizeof ( phash.sha1 ) ); + + /* Encode authenticator response hash */ + wtf = auth->wtf; + *(wtf++) = 'S'; + *(wtf++) = '='; + DBGC ( &ctx, "MSCHAPv2 authenticator response: S=" ); + for ( i = 0 ; i < sizeof ( phash.sha1 ) ; i++ ) { + snprintf ( tmp, sizeof ( tmp ), "%02X", phash.sha1[i] ); + *(wtf++) = tmp[0]; + *(wtf++) = tmp[1]; + DBGC ( &ctx, "%s", tmp ); + } + DBGC ( &ctx, "\n" ); +} diff --git a/src/include/ipxe/mschapv2.h b/src/include/ipxe/mschapv2.h new file mode 100644 index 00000000..59cf37ee --- /dev/null +++ b/src/include/ipxe/mschapv2.h @@ -0,0 +1,59 @@ +#ifndef _IPXE_MSCHAPV2_H +#define _IPXE_MSCHAPV2_H + +/** @file + * + * MS-CHAPv2 authentication + * + */ + +FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); + +#include + +/** An MS-CHAPv2 challenge */ +struct mschapv2_challenge { + /** Raw bytes */ + uint8_t byte[16]; +} __attribute__ (( packed )); + +/** An MS-CHAPv2 NT response */ +struct mschapv2_nt_response { + /** DES-encrypted blocks */ + uint8_t block[3][8]; +} __attribute__ (( packed )); + +/** An MS-CHAPv2 challenge response */ +struct mschapv2_response { + /** Peer challenge */ + struct mschapv2_challenge peer; + /** Reserved, must be zero */ + uint8_t reserved[8]; + /** NT response */ + struct mschapv2_nt_response nt; + /** Flags, must be zero */ + uint8_t flags; +} __attribute__ (( packed )); + +/** An MS-CHAPv2 authenticator response */ +struct mschapv2_auth { + /** Authenticator response string + * + * This is an unterminated 42-byte string of the form + * "S=" where is the upper-cased + * hexadecimal encoding of the actual authenticator response + * value. Joy. + */ + char wtf[42]; +} __attribute__ (( packed )); + +extern void mschapv2_response ( const char *username, const char *password, + const struct mschapv2_challenge *challenge, + const struct mschapv2_challenge *peer, + struct mschapv2_response *response ); +extern void mschapv2_auth ( const char *username, const char *password, + const struct mschapv2_challenge *challenge, + const struct mschapv2_response *response, + struct mschapv2_auth *auth ); + +#endif /* _IPXE_MSCHAPV2_H */ diff --git a/src/tests/mschapv2_test.c b/src/tests/mschapv2_test.c new file mode 100644 index 00000000..3d10ed18 --- /dev/null +++ b/src/tests/mschapv2_test.c @@ -0,0 +1,144 @@ +/* + * Copyright (C) 2024 Michael Brown . + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + * + * You can also choose to distribute this program under the terms of + * the Unmodified Binary Distribution Licence (as given in the file + * COPYING.UBDL), provided that you have satisfied its requirements. + */ + +FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); + +/** @file + * + * MS-CHAPv2 authentication self-tests + * + */ + +/* Forcibly enable assertions */ +#undef NDEBUG + +#include +#include +#include +#include + +/** An MS-CHAPv2 test */ +struct mschapv2_test { + /** Username */ + const char *username; + /** Password */ + const char *password; + /** Authenticator challenge */ + const struct mschapv2_challenge *challenge; + /** Peer challenge */ + const struct mschapv2_challenge *peer; + /** Expected challenge response */ + const struct mschapv2_response *response; + /** Expected authenticator response */ + const struct mschapv2_auth *auth; +}; + +/** Define inline data */ +#define DATA(...) { __VA_ARGS__ } + +/** Define an MS-CHAPv2 test */ +#define MSCHAPV2_TEST( name, USERNAME, PASSWORD, CHALLENGE, PEER, \ + RESPONSE, AUTH ) \ + static const struct mschapv2_challenge name ## _challenge = { \ + .byte = CHALLENGE, \ + }; \ + static const struct mschapv2_challenge name ## _peer = { \ + .byte = PEER, \ + }; \ + static const union { \ + struct mschapv2_response response; \ + uint8_t byte[ sizeof ( struct mschapv2_response ) ]; \ + } name ## _response = { \ + .byte = RESPONSE, \ + }; \ + static const union { \ + struct mschapv2_auth auth; \ + uint8_t byte[ sizeof ( struct mschapv2_auth ) ]; \ + } name ## _auth = { \ + .byte = AUTH, \ + }; \ + static struct mschapv2_test name = { \ + .username = USERNAME, \ + .password = PASSWORD, \ + .challenge = &name ## _challenge, \ + .peer = &name ## _peer, \ + .response = &name ## _response.response, \ + .auth = &name ## _auth.auth, \ + }; + +/** RFC 2759 section 9.2 test case */ +MSCHAPV2_TEST ( rfc2759_test, + "User", "clientPass", + DATA ( 0x5b, 0x5d, 0x7c, 0x7d, 0x7b, 0x3f, 0x2f, 0x3e, + 0x3c, 0x2c, 0x60, 0x21, 0x32, 0x26, 0x26, 0x28 ), + DATA ( 0x21, 0x40, 0x23, 0x24, 0x25, 0x5e, 0x26, 0x2a, + 0x28, 0x29, 0x5f, 0x2b, 0x3a, 0x33, 0x7c, 0x7e ), + DATA ( 0x21, 0x40, 0x23, 0x24, 0x25, 0x5e, 0x26, 0x2a, + 0x28, 0x29, 0x5f, 0x2b, 0x3a, 0x33, 0x7c, 0x7e, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x82, 0x30, 0x9e, 0xcd, 0x8d, 0x70, 0x8b, 0x5e, + 0xa0, 0x8f, 0xaa, 0x39, 0x81, 0xcd, 0x83, 0x54, + 0x42, 0x33, 0x11, 0x4a, 0x3d, 0x85, 0xd6, 0xdf, + 0x00 ), + "S=407A5589115FD0D6209F510FE9C04566932CDA56" ); + +/** + * Report an MS-CHAPv2 test result + * + * @v test Authentication test + * @v file Test code file + * @v line Test code line + */ +static void mschapv2_okx ( struct mschapv2_test *test, + const char *file, unsigned int line ) { + struct mschapv2_response response; + struct mschapv2_auth auth; + + /* Compute challenge response */ + mschapv2_response ( test->username, test->password, test->challenge, + test->peer, &response ); + okx ( memcmp ( &response, test->response, sizeof ( response ) ) == 0, + file, line ); + + /* Compute authenticator response */ + mschapv2_auth ( test->username, test->password, test->challenge, + test->response, &auth ); + okx ( memcmp ( &auth, test->auth, sizeof ( auth ) ) == 0, file, line ); +} +#define mschapv2_ok( test ) \ + mschapv2_okx ( test, __FILE__, __LINE__ ) + +/** + * Perform MS-CHAPv2 self-test + * + */ +static void mschapv2_test_exec ( void ) { + + mschapv2_ok ( &rfc2759_test ); +} + +/** MS-CHAPv2 self-test */ +struct self_test mschapv2_test __self_test = { + .name = "mschapv2", + .exec = mschapv2_test_exec, +}; diff --git a/src/tests/tests.c b/src/tests/tests.c index 282d2eb6..90cec948 100644 --- a/src/tests/tests.c +++ b/src/tests/tests.c @@ -83,3 +83,4 @@ REQUIRE_OBJECT ( gcm_test ); REQUIRE_OBJECT ( nap_test ); REQUIRE_OBJECT ( x25519_test ); REQUIRE_OBJECT ( des_test ); +REQUIRE_OBJECT ( mschapv2_test ); -- cgit v1.2.3-55-g7522 From 582132fe3f72377f592aa127d920355afa887384 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Thu, 22 Feb 2024 12:55:59 +0000 Subject: [crypto] Force inlining of trivial wrapper functions Inspection of the generated assembly shows that gcc will often emit standalone implementations of frequently invoked functions such as digest_update(), which contain no logic and exist only as syntactic sugar. Force inlining of these functions to reduce the overall binary size. Signed-off-by: Michael Brown --- src/include/ipxe/crypto.h | 99 ++++++++++++++++++++++++++--------------------- 1 file changed, 55 insertions(+), 44 deletions(-) diff --git a/src/include/ipxe/crypto.h b/src/include/ipxe/crypto.h index 9ee1c40c..a6f43765 100644 --- a/src/include/ipxe/crypto.h +++ b/src/include/ipxe/crypto.h @@ -212,34 +212,37 @@ struct elliptic_curve { void *result ); }; -static inline void digest_init ( struct digest_algorithm *digest, - void *ctx ) { +static inline __attribute__ (( always_inline )) void +digest_init ( struct digest_algorithm *digest, void *ctx ) { digest->init ( ctx ); } -static inline void digest_update ( struct digest_algorithm *digest, - void *ctx, const void *data, size_t len ) { +static inline __attribute__ (( always_inline )) void +digest_update ( struct digest_algorithm *digest, void *ctx, + const void *data, size_t len ) { digest->update ( ctx, data, len ); } -static inline void digest_final ( struct digest_algorithm *digest, - void *ctx, void *out ) { +static inline __attribute__ (( always_inline )) void +digest_final ( struct digest_algorithm *digest, void *ctx, void *out ) { digest->final ( ctx, out ); } -static inline int cipher_setkey ( struct cipher_algorithm *cipher, - void *ctx, const void *key, size_t keylen ) { +static inline __attribute__ (( always_inline )) int +cipher_setkey ( struct cipher_algorithm *cipher, void *ctx, + const void *key, size_t keylen ) { return cipher->setkey ( ctx, key, keylen ); } -static inline void cipher_setiv ( struct cipher_algorithm *cipher, - void *ctx, const void *iv, size_t ivlen ) { +static inline __attribute__ (( always_inline )) void +cipher_setiv ( struct cipher_algorithm *cipher, void *ctx, + const void *iv, size_t ivlen ) { cipher->setiv ( ctx, iv, ivlen ); } -static inline void cipher_encrypt ( struct cipher_algorithm *cipher, - void *ctx, const void *src, void *dst, - size_t len ) { +static inline __attribute__ (( always_inline )) void +cipher_encrypt ( struct cipher_algorithm *cipher, void *ctx, + const void *src, void *dst, size_t len ) { cipher->encrypt ( ctx, src, dst, len ); } #define cipher_encrypt( cipher, ctx, src, dst, len ) do { \ @@ -247,9 +250,9 @@ static inline void cipher_encrypt ( struct cipher_algorithm *cipher, cipher_encrypt ( (cipher), (ctx), (src), (dst), (len) ); \ } while ( 0 ) -static inline void cipher_decrypt ( struct cipher_algorithm *cipher, - void *ctx, const void *src, void *dst, - size_t len ) { +static inline __attribute__ (( always_inline )) void +cipher_decrypt ( struct cipher_algorithm *cipher, void *ctx, + const void *src, void *dst, size_t len ) { cipher->decrypt ( ctx, src, dst, len ); } #define cipher_decrypt( cipher, ctx, src, dst, len ) do { \ @@ -257,71 +260,79 @@ static inline void cipher_decrypt ( struct cipher_algorithm *cipher, cipher_decrypt ( (cipher), (ctx), (src), (dst), (len) ); \ } while ( 0 ) -static inline void cipher_auth ( struct cipher_algorithm *cipher, void *ctx, - void *auth ) { +static inline __attribute__ (( always_inline )) void +cipher_auth ( struct cipher_algorithm *cipher, void *ctx, void *auth ) { cipher->auth ( ctx, auth ); } -static inline int is_stream_cipher ( struct cipher_algorithm *cipher ) { +static inline __attribute__ (( always_inline )) int +is_stream_cipher ( struct cipher_algorithm *cipher ) { return ( cipher->blocksize == 1 ); } -static inline int is_block_cipher ( struct cipher_algorithm *cipher ) { +static inline __attribute__ (( always_inline )) int +is_block_cipher ( struct cipher_algorithm *cipher ) { return ( cipher->blocksize > 1 ); } -static inline int is_auth_cipher ( struct cipher_algorithm *cipher ) { +static inline __attribute__ (( always_inline )) int +is_auth_cipher ( struct cipher_algorithm *cipher ) { return cipher->authsize; } -static inline int pubkey_init ( struct pubkey_algorithm *pubkey, void *ctx, - const void *key, size_t key_len ) { +static inline __attribute__ (( always_inline )) int +pubkey_init ( struct pubkey_algorithm *pubkey, void *ctx, + const void *key, size_t key_len ) { return pubkey->init ( ctx, key, key_len ); } -static inline size_t pubkey_max_len ( struct pubkey_algorithm *pubkey, - void *ctx ) { +static inline __attribute__ (( always_inline )) size_t +pubkey_max_len ( struct pubkey_algorithm *pubkey, void *ctx ) { return pubkey->max_len ( ctx ); } -static inline int pubkey_encrypt ( struct pubkey_algorithm *pubkey, void *ctx, - const void *data, size_t len, void *out ) { +static inline __attribute__ (( always_inline )) int +pubkey_encrypt ( struct pubkey_algorithm *pubkey, void *ctx, + const void *data, size_t len, void *out ) { return pubkey->encrypt ( ctx, data, len, out ); } -static inline int pubkey_decrypt ( struct pubkey_algorithm *pubkey, void *ctx, - const void *data, size_t len, void *out ) { +static inline __attribute__ (( always_inline )) int +pubkey_decrypt ( struct pubkey_algorithm *pubkey, void *ctx, + const void *data, size_t len, void *out ) { return pubkey->decrypt ( ctx, data, len, out ); } -static inline int pubkey_sign ( struct pubkey_algorithm *pubkey, void *ctx, - struct digest_algorithm *digest, - const void *value, void *signature ) { +static inline __attribute__ (( always_inline )) int +pubkey_sign ( struct pubkey_algorithm *pubkey, void *ctx, + struct digest_algorithm *digest, const void *value, + void *signature ) { return pubkey->sign ( ctx, digest, value, signature ); } -static inline int pubkey_verify ( struct pubkey_algorithm *pubkey, void *ctx, - struct digest_algorithm *digest, - const void *value, const void *signature, - size_t signature_len ) { +static inline __attribute__ (( always_inline )) int +pubkey_verify ( struct pubkey_algorithm *pubkey, void *ctx, + struct digest_algorithm *digest, const void *value, + const void *signature, size_t signature_len ) { return pubkey->verify ( ctx, digest, value, signature, signature_len ); } -static inline void pubkey_final ( struct pubkey_algorithm *pubkey, void *ctx ) { +static inline __attribute__ (( always_inline )) void +pubkey_final ( struct pubkey_algorithm *pubkey, void *ctx ) { pubkey->final ( ctx ); } -static inline int pubkey_match ( struct pubkey_algorithm *pubkey, - const void *private_key, - size_t private_key_len, const void *public_key, - size_t public_key_len ) { +static inline __attribute__ (( always_inline )) int +pubkey_match ( struct pubkey_algorithm *pubkey, + const void *private_key, size_t private_key_len, + const void *public_key, size_t public_key_len ) { return pubkey->match ( private_key, private_key_len, public_key, public_key_len ); } -static inline int elliptic_multiply ( struct elliptic_curve *curve, - const void *base, const void *scalar, - void *result ) { +static inline __attribute__ (( always_inline )) int +elliptic_multiply ( struct elliptic_curve *curve, + const void *base, const void *scalar, void *result ) { return curve->multiply ( base, scalar, result ); } -- cgit v1.2.3-55-g7522 From e5f3ba0ca773e8ea4dcfec6e10f18a06d14e79e0 Mon Sep 17 00:00:00 2001 From: Geert Stappers Date: Sun, 18 Feb 2024 12:29:59 +0100 Subject: [drivers] Sort PCI_ROM() entries numerically Done with the help of this Perl script: $MARKER = 'PCI_ROM'; # a regex $AB = 1; # At Begin @HEAD = (); @ITEMS = (); @TAIL = (); foreach $fn (@ARGV) { open(IN, $fn) or die "Can't open file '$fn': $!\n"; while () { if (/$MARKER/) { push @ITEMS, $_; $AB = 0; # not anymore at begin } else { if ($AB) { push @HEAD, $_; } else { push @TAIL, $_; } } } } continue { close IN; open(OUT, ">$fn") or die "Can't open file '$fn' for output: $!\n"; print OUT @HEAD; print OUT sort @ITEMS; print OUT @TAIL; close OUT; # For a next file $AB = 1; @HEAD = (); @ITEMS = (); @TAIL = (); } Executed that script while src/drivers/ as current working directory, provided '$(grep -rl PCI_ROM)' as argument. Signed-off-by: Geert Stappers --- src/drivers/infiniband/arbel.c | 2 +- src/drivers/infiniband/hermon.c | 9 ++-- src/drivers/net/3c595.c | 4 +- src/drivers/net/3c90x.c | 12 ++--- src/drivers/net/ath/ath5k/ath5k.c | 8 +-- src/drivers/net/b44.c | 2 +- src/drivers/net/bnxt/bnxt.c | 22 ++++---- src/drivers/net/davicom.c | 2 +- src/drivers/net/dmfe.c | 2 +- src/drivers/net/eepro100.c | 10 ++-- src/drivers/net/forcedeth.c | 22 ++++---- src/drivers/net/ns8390.c | 12 ++--- src/drivers/net/pcnet32.c | 2 +- src/drivers/net/prism2_plx.c | 4 +- src/drivers/net/rhine.c | 4 +- src/drivers/net/rtl818x/rtl8180.c | 2 +- src/drivers/net/sky2.c | 2 +- src/drivers/net/sundance.c | 2 +- src/drivers/net/tg3/tg3.c | 108 +++++++++++++++++++------------------- src/drivers/net/tlan.c | 14 ++--- src/drivers/net/tulip.c | 28 +++++----- 21 files changed, 136 insertions(+), 137 deletions(-) diff --git a/src/drivers/infiniband/arbel.c b/src/drivers/infiniband/arbel.c index 24c0b53b..8be06d93 100644 --- a/src/drivers/infiniband/arbel.c +++ b/src/drivers/infiniband/arbel.c @@ -3139,8 +3139,8 @@ static void arbel_remove ( struct pci_device *pci ) { } static struct pci_device_id arbel_nics[] = { - PCI_ROM ( 0x15b3, 0x6282, "mt25218", "MT25218 HCA driver", 0 ), PCI_ROM ( 0x15b3, 0x6274, "mt25204", "MT25204 HCA driver", 0 ), + PCI_ROM ( 0x15b3, 0x6282, "mt25218", "MT25218 HCA driver", 0 ), }; struct pci_driver arbel_driver __pci_driver = { diff --git a/src/drivers/infiniband/hermon.c b/src/drivers/infiniband/hermon.c index 6fc7d8bd..e5c3544f 100644 --- a/src/drivers/infiniband/hermon.c +++ b/src/drivers/infiniband/hermon.c @@ -4214,6 +4214,9 @@ static void hermon_bofm_remove ( struct pci_device *pci ) { } static struct pci_device_id hermon_nics[] = { + /* Mellanox ConnectX-3 VPI (ethernet + infiniband) */ + PCI_ROM ( 0x15b3, 0x1003, "mt4099", "ConnectX-3 HCA driver", 0 ), + PCI_ROM ( 0x15b3, 0x1007, "mt4103", "ConnectX-3 Pro HCA driver", 0 ), /* Mellanox ConnectX VPI (ethernet + infiniband) */ PCI_ROM ( 0x15b3, 0x6340, "mt25408", "MT25408 HCA driver", 0 ), PCI_ROM ( 0x15b3, 0x634a, "mt25418", "MT25418 HCA driver", 0 ), @@ -4226,17 +4229,13 @@ static struct pci_device_id hermon_nics[] = { PCI_ROM ( 0x15b3, 0x6732, "mt26418", "MT26418 HCA driver", 0 ), PCI_ROM ( 0x15b3, 0x673c, "mt26428", "MT26428 HCA driver", 0 ), PCI_ROM ( 0x15b3, 0x6746, "mt26438", "MT26438 HCA driver", 0 ), - PCI_ROM ( 0x15b3, 0x6778, "mt26488", "MT26488 HCA driver", 0 ), /* Mellanox ConnectX-2 EN (ethernet only) */ PCI_ROM ( 0x15b3, 0x6750, "mt26448", "MT26448 HCA driver", 0 ), PCI_ROM ( 0x15b3, 0x675a, "mt26458", "MT26458 HCA driver", 0 ), PCI_ROM ( 0x15b3, 0x6764, "mt26468", "MT26468 HCA driver", 0 ), PCI_ROM ( 0x15b3, 0x676e, "mt26478", "MT26478 HCA driver", 0 ), - - /* Mellanox ConnectX-3 VPI (ethernet + infiniband) */ - PCI_ROM ( 0x15b3, 0x1003, "mt4099", "ConnectX-3 HCA driver", 0 ), - PCI_ROM ( 0x15b3, 0x1007, "mt4103", "ConnectX-3 Pro HCA driver", 0 ), + PCI_ROM ( 0x15b3, 0x6778, "mt26488", "MT26488 HCA driver", 0 ), }; struct pci_driver hermon_driver __pci_driver = { diff --git a/src/drivers/net/3c595.c b/src/drivers/net/3c595.c index 92d38cfc..c6983100 100644 --- a/src/drivers/net/3c595.c +++ b/src/drivers/net/3c595.c @@ -523,10 +523,12 @@ static struct nic_operations t595_operations = { }; static struct pci_device_id t595_nics[] = { +PCI_ROM(0x10b7, 0x4500, "3c450-1", "3Com450 HomePNA Tornado", 0), PCI_ROM(0x10b7, 0x5900, "3c590", "3Com590", 0), /* Vortex 10Mbps */ PCI_ROM(0x10b7, 0x5950, "3c595", "3Com595", 0), /* Vortex 100baseTx */ PCI_ROM(0x10b7, 0x5951, "3c595-1", "3Com595", 0), /* Vortex 100baseT4 */ PCI_ROM(0x10b7, 0x5952, "3c595-2", "3Com595", 0), /* Vortex 100base-MII */ +PCI_ROM(0x10b7, 0x7646, "3csoho100-tx-1", "3CSOHO100-TX", 0), /* Hurricane */ PCI_ROM(0x10b7, 0x9000, "3c900-tpo", "3Com900-TPO", 0), /* 10 Base TPO */ PCI_ROM(0x10b7, 0x9001, "3c900-t4", "3Com900-Combo", 0), /* 10/100 T4 */ PCI_ROM(0x10b7, 0x9004, "3c900b-tpo", "3Com900B-TPO", 0), /* 10 Base TPO */ @@ -535,8 +537,6 @@ PCI_ROM(0x10b7, 0x9006, "3c900b-tpb2", "3Com900B-2/T", 0), /* 10 Base TP and PCI_ROM(0x10b7, 0x900a, "3c900b-fl", "3Com900B-FL", 0), /* 10 Base F */ PCI_ROM(0x10b7, 0x9800, "3c980-cyclone-1", "3Com980-Cyclone", 0), /* Cyclone */ PCI_ROM(0x10b7, 0x9805, "3c9805-1", "3Com9805", 0), /* Dual Port Server Cyclone */ -PCI_ROM(0x10b7, 0x7646, "3csoho100-tx-1", "3CSOHO100-TX", 0), /* Hurricane */ -PCI_ROM(0x10b7, 0x4500, "3c450-1", "3Com450 HomePNA Tornado", 0), }; PCI_DRIVER ( t595_driver, t595_nics, PCI_NO_CLASS ); diff --git a/src/drivers/net/3c90x.c b/src/drivers/net/3c90x.c index 1b8190c4..a94473ef 100644 --- a/src/drivers/net/3c90x.c +++ b/src/drivers/net/3c90x.c @@ -955,16 +955,20 @@ static int a3c90x_probe(struct pci_device *pci) static struct pci_device_id a3c90x_nics[] = { /* Original 90x revisions: */ + PCI_ROM(0x10b7, 0x1201, "3c982a", "3Com982A", 0), + PCI_ROM(0x10b7, 0x1202, "3c982b", "3Com982B", 0), + PCI_ROM(0x10b7, 0x4500, "3c450", "3Com450 HomePNA Tornado", 0), PCI_ROM(0x10b7, 0x6055, "3c556", "3C556", 0), /* Huricane */ + PCI_ROM(0x10b7, 0x7646, "3csoho100-tx", "3CSOHO100-TX", 0), /* Hurricane */ PCI_ROM(0x10b7, 0x9000, "3c905-tpo", "3Com900-TPO", 0), /* 10 Base TPO */ PCI_ROM(0x10b7, 0x9001, "3c905-t4", "3Com900-Combo", 0), /* 10/100 T4 */ - PCI_ROM(0x10b7, 0x9050, "3c905-tpo100", "3Com905-TX", 0), /* 100 Base TX / 10/100 TPO */ - PCI_ROM(0x10b7, 0x9051, "3c905-combo", "3Com905-T4", 0), /* 100 Base T4 / 10 Base Combo */ /* Newer 90xB revisions: */ PCI_ROM(0x10b7, 0x9004, "3c905b-tpo", "3Com900B-TPO", 0), /* 10 Base TPO */ PCI_ROM(0x10b7, 0x9005, "3c905b-combo", "3Com900B-Combo", 0), /* 10 Base Combo */ PCI_ROM(0x10b7, 0x9006, "3c905b-tpb2", "3Com900B-2/T", 0), /* 10 Base TP and Base2 */ PCI_ROM(0x10b7, 0x900a, "3c905b-fl", "3Com900B-FL", 0), /* 10 Base FL */ + PCI_ROM(0x10b7, 0x9050, "3c905-tpo100", "3Com905-TX", 0), /* 100 Base TX / 10/100 TPO */ + PCI_ROM(0x10b7, 0x9051, "3c905-combo", "3Com905-T4", 0), /* 100 Base T4 / 10 Base Combo */ PCI_ROM(0x10b7, 0x9055, "3c905b-tpo100", "3Com905B-TX", 0), /* 10/100 TPO */ PCI_ROM(0x10b7, 0x9056, "3c905b-t4", "3Com905B-T4", 0), /* 10/100 T4 */ PCI_ROM(0x10b7, 0x9058, "3c905b-9058", "3Com905B-9058", 0), /* Cyclone 10/100/BNC */ @@ -975,10 +979,6 @@ static struct pci_device_id a3c90x_nics[] = { PCI_ROM(0x10b7, 0x9210, "3c920b-emb-wnm", "3Com20B-EMB WNM", 0), PCI_ROM(0x10b7, 0x9800, "3c980", "3Com980-Cyclone", 0), /* Cyclone */ PCI_ROM(0x10b7, 0x9805, "3c9805", "3Com9805", 0), /* Dual Port Server Cyclone */ - PCI_ROM(0x10b7, 0x7646, "3csoho100-tx", "3CSOHO100-TX", 0), /* Hurricane */ - PCI_ROM(0x10b7, 0x4500, "3c450", "3Com450 HomePNA Tornado", 0), - PCI_ROM(0x10b7, 0x1201, "3c982a", "3Com982A", 0), - PCI_ROM(0x10b7, 0x1202, "3c982b", "3Com982B", 0), }; struct pci_driver a3c90x_driver __pci_driver = { diff --git a/src/drivers/net/ath/ath5k/ath5k.c b/src/drivers/net/ath/ath5k/ath5k.c index e43eb0aa..643884d4 100644 --- a/src/drivers/net/ath/ath5k/ath5k.c +++ b/src/drivers/net/ath/ath5k/ath5k.c @@ -65,14 +65,11 @@ FILE_LICENCE ( BSD3 ); /* Known PCI ids */ static struct pci_device_id ath5k_nics[] = { - PCI_ROM(0x168c, 0x0207, "ath5210e", "Atheros 5210 early", AR5K_AR5210), + PCI_ROM(0x10b7, 0x0013, "rdag675", "3com 3CRDAG675", AR5K_AR5212), PCI_ROM(0x168c, 0x0007, "ath5210", "Atheros 5210", AR5K_AR5210), PCI_ROM(0x168c, 0x0011, "ath5311", "Atheros 5311 (AHB)", AR5K_AR5211), PCI_ROM(0x168c, 0x0012, "ath5211", "Atheros 5211", AR5K_AR5211), PCI_ROM(0x168c, 0x0013, "ath5212", "Atheros 5212", AR5K_AR5212), - PCI_ROM(0xa727, 0x0013, "ath5212c","3com Ath 5212", AR5K_AR5212), - PCI_ROM(0x10b7, 0x0013, "rdag675", "3com 3CRDAG675", AR5K_AR5212), - PCI_ROM(0x168c, 0x1014, "ath5212m", "Ath 5212 miniPCI", AR5K_AR5212), PCI_ROM(0x168c, 0x0014, "ath5212x14", "Atheros 5212 x14", AR5K_AR5212), PCI_ROM(0x168c, 0x0015, "ath5212x15", "Atheros 5212 x15", AR5K_AR5212), PCI_ROM(0x168c, 0x0016, "ath5212x16", "Atheros 5212 x16", AR5K_AR5212), @@ -83,6 +80,9 @@ static struct pci_device_id ath5k_nics[] = { PCI_ROM(0x168c, 0x001b, "ath5413", "Atheros 5413 Eagle", AR5K_AR5212), PCI_ROM(0x168c, 0x001c, "ath5212e", "Atheros 5212 PCI-E", AR5K_AR5212), PCI_ROM(0x168c, 0x001d, "ath2417", "Atheros 2417 Nala", AR5K_AR5212), + PCI_ROM(0x168c, 0x0207, "ath5210e", "Atheros 5210 early", AR5K_AR5210), + PCI_ROM(0x168c, 0x1014, "ath5212m", "Ath 5212 miniPCI", AR5K_AR5212), + PCI_ROM(0xa727, 0x0013, "ath5212c","3com Ath 5212", AR5K_AR5212), }; #define ATH5K_SPMBL_NO 1 diff --git a/src/drivers/net/b44.c b/src/drivers/net/b44.c index 1ca7e2e5..30ece557 100644 --- a/src/drivers/net/b44.c +++ b/src/drivers/net/b44.c @@ -945,8 +945,8 @@ static struct net_device_operations b44_operations = { static struct pci_device_id b44_nics[] = { - PCI_ROM(0x14e4, 0x4401, "BCM4401", "BCM4401", 0), PCI_ROM(0x14e4, 0x170c, "BCM4401-B0", "BCM4401-B0", 0), + PCI_ROM(0x14e4, 0x4401, "BCM4401", "BCM4401", 0), PCI_ROM(0x14e4, 0x4402, "BCM4401-B1", "BCM4401-B1", 0), }; diff --git a/src/drivers/net/bnxt/bnxt.c b/src/drivers/net/bnxt/bnxt.c index a99f29ec..a127f6ce 100644 --- a/src/drivers/net/bnxt/bnxt.c +++ b/src/drivers/net/bnxt/bnxt.c @@ -24,6 +24,11 @@ static int bnxt_rx_complete ( struct net_device *dev, struct rx_pkt_cmpl *rx ); void bnxt_link_evt ( struct bnxt *bp, struct hwrm_async_event_cmpl *evt ); static struct pci_device_id bnxt_nics[] = { + PCI_ROM( 0x14e4, 0x1604, "14e4-1604", "14e4-1604", 0 ), + PCI_ROM( 0x14e4, 0x1605, "14e4-1605", "14e4-1605", 0 ), + PCI_ROM( 0x14e4, 0x1606, "14e4-1606", "14e4-1606", 0 ), + PCI_ROM( 0x14e4, 0x1609, "14e4-1609", "14e4-1609", 0 ), + PCI_ROM( 0x14e4, 0x1614, "14e4-1614", "14e4-1614", 0 ), PCI_ROM( 0x14e4, 0x16c0, "14e4-16C0", "14e4-16C0", 0 ), PCI_ROM( 0x14e4, 0x16c1, "14e4-16C1", "14e4-16C1", BNXT_FLAG_PCI_VF ), PCI_ROM( 0x14e4, 0x16c8, "14e4-16C8", "14e4-16C8", 0 ), @@ -62,27 +67,22 @@ static struct pci_device_id bnxt_nics[] = { PCI_ROM( 0x14e4, 0x16ef, "14e4-16EF", "14e4-16EF", 0 ), PCI_ROM( 0x14e4, 0x16f0, "14e4-16F0", "14e4-16F0", 0 ), PCI_ROM( 0x14e4, 0x16f1, "14e4-16F1", "14e4-16F1", 0 ), - PCI_ROM( 0x14e4, 0x1604, "14e4-1604", "14e4-1604", 0 ), - PCI_ROM( 0x14e4, 0x1605, "14e4-1605", "14e4-1605", 0 ), - PCI_ROM( 0x14e4, 0x1606, "14e4-1606", "14e4-1606", 0 ), - PCI_ROM( 0x14e4, 0x1609, "14e4-1609", "14e4-1609", 0 ), - PCI_ROM( 0x14e4, 0x1614, "14e4-1614", "14e4-1614", 0 ), - PCI_ROM( 0x14e4, 0xd802, "14e4-D802", "14e4-D802", 0 ), - PCI_ROM( 0x14e4, 0xd804, "14e4-D804", "14e4-D804", 0 ), PCI_ROM( 0x14e4, 0x1750, "14e4-1750", "14e4-1750", 0 ), - PCI_ROM( 0x14e4, 0x1802, "14e4-1802", "14e4-1802", 0 ), - PCI_ROM( 0x14e4, 0x1805, "14e4-1805", "14e4-1805", 0 ), PCI_ROM( 0x14e4, 0x1751, "14e4-1751", "14e4-1751", 0 ), - PCI_ROM( 0x14e4, 0x1801, "14e4-1801", "14e4-1801", 0 ), - PCI_ROM( 0x14e4, 0x1804, "14e4-1804", "14e4-1804", 0 ), PCI_ROM( 0x14e4, 0x1752, "14e4-1752", "14e4-1752", 0 ), PCI_ROM( 0x14e4, 0x1760, "14e4-1760", "14e4-1760", 0 ), PCI_ROM( 0x14e4, 0x1800, "14e4-1800", "14e4-1800", 0 ), + PCI_ROM( 0x14e4, 0x1801, "14e4-1801", "14e4-1801", 0 ), + PCI_ROM( 0x14e4, 0x1802, "14e4-1802", "14e4-1802", 0 ), PCI_ROM( 0x14e4, 0x1803, "14e4-1803", "14e4-1803", 0 ), + PCI_ROM( 0x14e4, 0x1804, "14e4-1804", "14e4-1804", 0 ), + PCI_ROM( 0x14e4, 0x1805, "14e4-1805", "14e4-1805", 0 ), PCI_ROM( 0x14e4, 0x1806, "14e4-1806", "14e4-1806", BNXT_FLAG_PCI_VF ), PCI_ROM( 0x14e4, 0x1807, "14e4-1807", "14e4-1807", BNXT_FLAG_PCI_VF ), PCI_ROM( 0x14e4, 0x1808, "14e4-1808", "14e4-1808", BNXT_FLAG_PCI_VF ), PCI_ROM( 0x14e4, 0x1809, "14e4-1809", "14e4-1809", BNXT_FLAG_PCI_VF ), + PCI_ROM( 0x14e4, 0xd802, "14e4-D802", "14e4-D802", 0 ), + PCI_ROM( 0x14e4, 0xd804, "14e4-D804", "14e4-D804", 0 ), }; /** diff --git a/src/drivers/net/davicom.c b/src/drivers/net/davicom.c index 9d3d8b91..0c96796d 100644 --- a/src/drivers/net/davicom.c +++ b/src/drivers/net/davicom.c @@ -689,9 +689,9 @@ static struct nic_operations davicom_operations = { }; static struct pci_device_id davicom_nics[] = { +PCI_ROM(0x1282, 0x9009, "davicom9009", "Davicom 9009", 0), PCI_ROM(0x1282, 0x9100, "davicom9100", "Davicom 9100", 0), PCI_ROM(0x1282, 0x9102, "davicom9102", "Davicom 9102", 0), -PCI_ROM(0x1282, 0x9009, "davicom9009", "Davicom 9009", 0), PCI_ROM(0x1282, 0x9132, "davicom9132", "Davicom 9132", 0), /* Needs probably some fixing */ }; diff --git a/src/drivers/net/dmfe.c b/src/drivers/net/dmfe.c index 2ea0d2b2..53b05815 100644 --- a/src/drivers/net/dmfe.c +++ b/src/drivers/net/dmfe.c @@ -1208,9 +1208,9 @@ static struct nic_operations dmfe_operations = { }; static struct pci_device_id dmfe_nics[] = { + PCI_ROM(0x1282, 0x9009, "dmfe9009", "Davicom 9009", 0), PCI_ROM(0x1282, 0x9100, "dmfe9100", "Davicom 9100", 0), PCI_ROM(0x1282, 0x9102, "dmfe9102", "Davicom 9102", 0), - PCI_ROM(0x1282, 0x9009, "dmfe9009", "Davicom 9009", 0), PCI_ROM(0x1282, 0x9132, "dmfe9132", "Davicom 9132", 0), /* Needs probably some fixing */ }; diff --git a/src/drivers/net/eepro100.c b/src/drivers/net/eepro100.c index a0551a89..49b00d44 100644 --- a/src/drivers/net/eepro100.c +++ b/src/drivers/net/eepro100.c @@ -1126,8 +1126,12 @@ PCI_ROM(0x8086, 0x103b, "82562etb", "Intel PRO100 VE 82562ETB", 0), PCI_ROM(0x8086, 0x103c, "eepro100-103c", "Intel PRO/100 VM Network Connection", 0), PCI_ROM(0x8086, 0x103d, "eepro100-103d", "Intel PRO/100 VE Network Connection", 0), PCI_ROM(0x8086, 0x103e, "eepro100-103e", "Intel PRO/100 VM Network Connection", 0), +PCI_ROM(0x8086, 0x1050, "82562ez", "Intel 82562EZ Network Connection", 0), PCI_ROM(0x8086, 0x1051, "prove", "Intel PRO/100 VE Network Connection", 0), PCI_ROM(0x8086, 0x1059, "82551qm", "Intel PRO/100 M Mobile Connection", 0), +PCI_ROM(0x8086, 0x1065, "82562-3", "Intel 82562 based Fast Ethernet Connection", 0), +PCI_ROM(0x8086, 0x1092, "82562-3", "Intel Pro/100 VE Network", 0), +PCI_ROM(0x8086, 0x10fe, "82552", "Intel 82552 10/100 Network Connection", 0), PCI_ROM(0x8086, 0x1209, "82559er", "Intel EtherExpressPro100 82559ER", 0), PCI_ROM(0x8086, 0x1227, "82865", "Intel 82865 EtherExpress PRO/100A", 0), PCI_ROM(0x8086, 0x1228, "82556", "Intel 82556 EtherExpress PRO/100 Smart", 0), @@ -1135,13 +1139,9 @@ PCI_ROM(0x8086, 0x1229, "eepro100", "Intel EtherExpressPro100", 0), PCI_ROM(0x8086, 0x2449, "82562em", "Intel EtherExpressPro100 82562EM", 0), PCI_ROM(0x8086, 0x2459, "82562-1", "Intel 82562 based Fast Ethernet Connection", 0), PCI_ROM(0x8086, 0x245d, "82562-2", "Intel 82562 based Fast Ethernet Connection", 0), -PCI_ROM(0x8086, 0x1050, "82562ez", "Intel 82562EZ Network Connection", 0), -PCI_ROM(0x8086, 0x1065, "82562-3", "Intel 82562 based Fast Ethernet Connection", 0), +PCI_ROM(0x8086, 0x27dc, "eepro100-27dc", "Intel 82801G (ICH7) Chipset Ethernet Controller", 0), PCI_ROM(0x8086, 0x5200, "eepro100-5200", "Intel EtherExpress PRO/100 Intelligent Server", 0), PCI_ROM(0x8086, 0x5201, "eepro100-5201", "Intel EtherExpress PRO/100 Intelligent Server", 0), -PCI_ROM(0x8086, 0x1092, "82562-3", "Intel Pro/100 VE Network", 0), -PCI_ROM(0x8086, 0x27dc, "eepro100-27dc", "Intel 82801G (ICH7) Chipset Ethernet Controller", 0), -PCI_ROM(0x8086, 0x10fe, "82552", "Intel 82552 10/100 Network Connection", 0), }; /* Cards with device ids 0x1030 to 0x103F, 0x2449, 0x2459 or 0x245D might need diff --git a/src/drivers/net/forcedeth.c b/src/drivers/net/forcedeth.c index ec3a5bdb..b4019d04 100644 --- a/src/drivers/net/forcedeth.c +++ b/src/drivers/net/forcedeth.c @@ -1928,17 +1928,17 @@ forcedeth_remove ( struct pci_device *pdev ) } static struct pci_device_id forcedeth_nics[] = { - PCI_ROM(0x10DE, 0x01C3, "nForce", "nForce Ethernet Controller", DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER), + PCI_ROM(0x10DE, 0x0037, "MCP04", "MCP04 Ethernet Controller", DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM| DEV_HAS_HIGH_DMA|DEV_HAS_STATISTICS_V1|DEV_NEED_TX_LIMIT), + PCI_ROM(0x10DE, 0x0038, "MCP04", "MCP04 Ethernet Controller", DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM| DEV_HAS_HIGH_DMA|DEV_HAS_STATISTICS_V1|DEV_NEED_TX_LIMIT), + PCI_ROM(0x10DE, 0x0056, "CK804", "CK804 Ethernet Controller", DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM| DEV_HAS_HIGH_DMA|DEV_HAS_STATISTICS_V1|DEV_NEED_TX_LIMIT), + PCI_ROM(0x10DE, 0x0057, "CK804", "CK804 Ethernet Controller", DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM| DEV_HAS_HIGH_DMA|DEV_HAS_STATISTICS_V1|DEV_NEED_TX_LIMIT), PCI_ROM(0x10DE, 0x0066, "nForce2", "nForce2 Ethernet Controller", DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER), - PCI_ROM(0x10DE, 0x00D6, "nForce3", "nForce3 Ethernet Controller", DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER), PCI_ROM(0x10DE, 0x0086, "nForce3", "nForce3 Ethernet Controller", DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC| DEV_HAS_CHECKSUM), PCI_ROM(0x10DE, 0x008C, "nForce3", "nForce3 Ethernet Controller", DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC| DEV_HAS_CHECKSUM), - PCI_ROM(0x10DE, 0x00E6, "nForce3", "nForce3 Ethernet Controller", DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC| DEV_HAS_CHECKSUM), + PCI_ROM(0x10DE, 0x00D6, "nForce3", "nForce3 Ethernet Controller", DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER), PCI_ROM(0x10DE, 0x00DF, "nForce3", "nForce3 Ethernet Controller", DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC| DEV_HAS_CHECKSUM), - PCI_ROM(0x10DE, 0x0056, "CK804", "CK804 Ethernet Controller", DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM| DEV_HAS_HIGH_DMA|DEV_HAS_STATISTICS_V1|DEV_NEED_TX_LIMIT), - PCI_ROM(0x10DE, 0x0057, "CK804", "CK804 Ethernet Controller", DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM| DEV_HAS_HIGH_DMA|DEV_HAS_STATISTICS_V1|DEV_NEED_TX_LIMIT), - PCI_ROM(0x10DE, 0x0037, "MCP04", "MCP04 Ethernet Controller", DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM| DEV_HAS_HIGH_DMA|DEV_HAS_STATISTICS_V1|DEV_NEED_TX_LIMIT), - PCI_ROM(0x10DE, 0x0038, "MCP04", "MCP04 Ethernet Controller", DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM| DEV_HAS_HIGH_DMA|DEV_HAS_STATISTICS_V1|DEV_NEED_TX_LIMIT), + PCI_ROM(0x10DE, 0x00E6, "nForce3", "nForce3 Ethernet Controller", DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC| DEV_HAS_CHECKSUM), + PCI_ROM(0x10DE, 0x01C3, "nForce", "nForce Ethernet Controller", DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER), PCI_ROM(0x10DE, 0x0268, "MCP51", "MCP51 Ethernet Controller", DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL| DEV_HAS_STATISTICS_V1|DEV_NEED_LOW_POWER_FIX), PCI_ROM(0x10DE, 0x0269, "MCP51", "MCP51 Ethernet Controller", DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL| DEV_HAS_STATISTICS_V1|DEV_NEED_LOW_POWER_FIX), PCI_ROM(0x10DE, 0x0372, "MCP55", "MCP55 Ethernet Controller", DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM| DEV_HAS_HIGH_DMA|DEV_HAS_VLAN|DEV_HAS_MSI|DEV_HAS_MSI_X| DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX_V1| DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED| DEV_HAS_MGMT_UNIT|DEV_NEED_TX_LIMIT|DEV_NEED_MSI_FIX), @@ -1955,14 +1955,14 @@ static struct pci_device_id forcedeth_nics[] = { PCI_ROM(0x10DE, 0x054D, "MCP67", "MCP67 Ethernet Controller", DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL| DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2| DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR| DEV_HAS_GEAR_MODE|DEV_NEED_MSI_FIX), PCI_ROM(0x10DE, 0x054E, "MCP67", "MCP67 Ethernet Controller", DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL| DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2| DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR| DEV_HAS_GEAR_MODE|DEV_NEED_MSI_FIX), PCI_ROM(0x10DE, 0x054F, "MCP67", "MCP67 Ethernet Controller", DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL| DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2| DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR| DEV_HAS_GEAR_MODE|DEV_NEED_MSI_FIX), - PCI_ROM(0x10DE, 0x07DC, "MCP73", "MCP73 Ethernet Controller", DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL| DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2| DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR| DEV_HAS_COLLISION_FIX|DEV_HAS_GEAR_MODE|DEV_NEED_MSI_FIX), - PCI_ROM(0x10DE, 0x07DD, "MCP73", "MCP73 Ethernet Controller", DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL| DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2| DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR| DEV_HAS_COLLISION_FIX|DEV_HAS_GEAR_MODE|DEV_NEED_MSI_FIX), - PCI_ROM(0x10DE, 0x07DE, "MCP73", "MCP73 Ethernet Controller", DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL| DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2| DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR| DEV_HAS_COLLISION_FIX|DEV_HAS_GEAR_MODE|DEV_NEED_MSI_FIX), - PCI_ROM(0x10DE, 0x07DF, "MCP73", "MCP73 Ethernet Controller", DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL| DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2| DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR| DEV_HAS_COLLISION_FIX|DEV_HAS_GEAR_MODE|DEV_NEED_MSI_FIX), PCI_ROM(0x10DE, 0x0760, "MCP77", "MCP77 Ethernet Controller", DEV_NEED_LINKTIMER|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA| DEV_HAS_MSI|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX_V2| DEV_HAS_STATISTICS_V3|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT| DEV_HAS_CORRECT_MACADDR|DEV_HAS_COLLISION_FIX| DEV_NEED_TX_LIMIT2|DEV_HAS_GEAR_MODE|DEV_NEED_PHY_INIT_FIX| DEV_NEED_MSI_FIX), PCI_ROM(0x10DE, 0x0761, "MCP77", "MCP77 Ethernet Controller", DEV_NEED_LINKTIMER|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA| DEV_HAS_MSI|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX_V2| DEV_HAS_STATISTICS_V3|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT| DEV_HAS_CORRECT_MACADDR|DEV_HAS_COLLISION_FIX| DEV_NEED_TX_LIMIT2|DEV_HAS_GEAR_MODE|DEV_NEED_PHY_INIT_FIX| DEV_NEED_MSI_FIX), PCI_ROM(0x10DE, 0x0762, "MCP77", "MCP77 Ethernet Controller", DEV_NEED_LINKTIMER|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA| DEV_HAS_MSI|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX_V2| DEV_HAS_STATISTICS_V3|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT| DEV_HAS_CORRECT_MACADDR|DEV_HAS_COLLISION_FIX| DEV_NEED_TX_LIMIT2|DEV_HAS_GEAR_MODE|DEV_NEED_PHY_INIT_FIX| DEV_NEED_MSI_FIX), PCI_ROM(0x10DE, 0x0763, "MCP77", "MCP77 Ethernet Controller", DEV_NEED_LINKTIMER|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA| DEV_HAS_MSI|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX_V2| DEV_HAS_STATISTICS_V3|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT| DEV_HAS_CORRECT_MACADDR|DEV_HAS_COLLISION_FIX| DEV_NEED_TX_LIMIT2|DEV_HAS_GEAR_MODE|DEV_NEED_PHY_INIT_FIX| DEV_NEED_MSI_FIX), + PCI_ROM(0x10DE, 0x07DC, "MCP73", "MCP73 Ethernet Controller", DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL| DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2| DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR| DEV_HAS_COLLISION_FIX|DEV_HAS_GEAR_MODE|DEV_NEED_MSI_FIX), + PCI_ROM(0x10DE, 0x07DD, "MCP73", "MCP73 Ethernet Controller", DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL| DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2| DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR| DEV_HAS_COLLISION_FIX|DEV_HAS_GEAR_MODE|DEV_NEED_MSI_FIX), + PCI_ROM(0x10DE, 0x07DE, "MCP73", "MCP73 Ethernet Controller", DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL| DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2| DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR| DEV_HAS_COLLISION_FIX|DEV_HAS_GEAR_MODE|DEV_NEED_MSI_FIX), + PCI_ROM(0x10DE, 0x07DF, "MCP73", "MCP73 Ethernet Controller", DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL| DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2| DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR| DEV_HAS_COLLISION_FIX|DEV_HAS_GEAR_MODE|DEV_NEED_MSI_FIX), PCI_ROM(0x10DE, 0x0AB0, "MCP79", "MCP79 Ethernet Controller", DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM| DEV_HAS_HIGH_DMA|DEV_HAS_MSI|DEV_HAS_POWER_CNTRL| DEV_HAS_PAUSEFRAME_TX_V3|DEV_HAS_STATISTICS_V3| DEV_HAS_TEST_EXTENDED|DEV_HAS_CORRECT_MACADDR| DEV_HAS_COLLISION_FIX|DEV_NEED_TX_LIMIT2|DEV_HAS_GEAR_MODE| DEV_NEED_PHY_INIT_FIX|DEV_NEED_MSI_FIX), PCI_ROM(0x10DE, 0x0AB1, "MCP79", "MCP79 Ethernet Controller", DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM| DEV_HAS_HIGH_DMA|DEV_HAS_MSI|DEV_HAS_POWER_CNTRL| DEV_HAS_PAUSEFRAME_TX_V3|DEV_HAS_STATISTICS_V3| DEV_HAS_TEST_EXTENDED|DEV_HAS_CORRECT_MACADDR| DEV_HAS_COLLISION_FIX|DEV_NEED_TX_LIMIT2|DEV_HAS_GEAR_MODE| DEV_NEED_PHY_INIT_FIX|DEV_NEED_MSI_FIX), PCI_ROM(0x10DE, 0x0AB2, "MCP79", "MCP79 Ethernet Controller", DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM| DEV_HAS_HIGH_DMA|DEV_HAS_MSI|DEV_HAS_POWER_CNTRL| DEV_HAS_PAUSEFRAME_TX_V3|DEV_HAS_STATISTICS_V3| DEV_HAS_TEST_EXTENDED|DEV_HAS_CORRECT_MACADDR| DEV_HAS_COLLISION_FIX|DEV_NEED_TX_LIMIT2|DEV_HAS_GEAR_MODE| DEV_NEED_PHY_INIT_FIX|DEV_NEED_MSI_FIX), diff --git a/src/drivers/net/ns8390.c b/src/drivers/net/ns8390.c index 0ffc6216..8e8d8500 100644 --- a/src/drivers/net/ns8390.c +++ b/src/drivers/net/ns8390.c @@ -1006,17 +1006,17 @@ ISA_ROM("ne","NE1000/2000 and clones"); #ifdef INCLUDE_NS8390 static struct pci_device_id nepci_nics[] = { /* A few NE2000 PCI clones, list not exhaustive */ -PCI_ROM(0x10ec, 0x8029, "rtl8029", "Realtek 8029", 0), -PCI_ROM(0x1186, 0x0300, "dlink-528", "D-Link DE-528", 0), PCI_ROM(0x1050, 0x0940, "winbond940", "Winbond NE2000-PCI", 0), /* Winbond 86C940 / 89C940 */ PCI_ROM(0x1050, 0x5a5a, "winbond940f", "Winbond W89c940F", 0), /* Winbond 89C940F */ +PCI_ROM(0x10bd, 0x0e34, "surecom-ne34", "Surecom NE34", 0), +PCI_ROM(0x10ec, 0x8029, "rtl8029", "Realtek 8029", 0), +PCI_ROM(0x1106, 0x0926, "via86c926", "Via 86c926", 0), +PCI_ROM(0x1186, 0x0300, "dlink-528", "D-Link DE-528", 0), PCI_ROM(0x11f6, 0x1401, "compexrl2000", "Compex ReadyLink 2000", 0), -PCI_ROM(0x8e2e, 0x3000, "ktiet32p2", "KTI ET32P2", 0), -PCI_ROM(0x4a14, 0x5000, "nv5000sc", "NetVin NV5000SC", 0), PCI_ROM(0x12c3, 0x0058, "holtek80232", "Holtek HT80232", 0), PCI_ROM(0x12c3, 0x5598, "holtek80229", "Holtek HT80229", 0), -PCI_ROM(0x10bd, 0x0e34, "surecom-ne34", "Surecom NE34", 0), -PCI_ROM(0x1106, 0x0926, "via86c926", "Via 86c926", 0), +PCI_ROM(0x4a14, 0x5000, "nv5000sc", "NetVin NV5000SC", 0), +PCI_ROM(0x8e2e, 0x3000, "ktiet32p2", "KTI ET32P2", 0), }; PCI_DRIVER ( nepci_driver, nepci_nics, PCI_NO_CLASS ); diff --git a/src/drivers/net/pcnet32.c b/src/drivers/net/pcnet32.c index 7da884e5..a9286d6a 100644 --- a/src/drivers/net/pcnet32.c +++ b/src/drivers/net/pcnet32.c @@ -1149,8 +1149,8 @@ pcnet32_remove ( struct pci_device *pdev ) static struct pci_device_id pcnet32_nics[] = { PCI_ROM(0x1022, 0x2000, "pcnet32", "AMD PCnet/PCI", 0), - PCI_ROM(0x1022, 0x2625, "pcnetfastiii", "AMD PCNet FAST III", 0), PCI_ROM(0x1022, 0x2001, "amdhomepna", "AMD PCnet/HomePNA", 0), + PCI_ROM(0x1022, 0x2625, "pcnetfastiii", "AMD PCNet FAST III", 0), }; struct pci_driver pcnet32_driver __pci_driver = { diff --git a/src/drivers/net/prism2_plx.c b/src/drivers/net/prism2_plx.c index a73b0e08..770cf328 100644 --- a/src/drivers/net/prism2_plx.c +++ b/src/drivers/net/prism2_plx.c @@ -104,9 +104,10 @@ static void prism2_plx_disable ( struct nic *nic ) { } static struct pci_device_id prism2_plx_nics[] = { -PCI_ROM(0x1385, 0x4100, "ma301", "Netgear MA301", 0), PCI_ROM(0x10b7, 0x7770, "3c-airconnect", "3Com AirConnect", 0), PCI_ROM(0x111a, 0x1023, "ss1023", "Siemens SpeedStream SS1023", 0), +PCI_ROM(0x126c, 0x8030, "emobility", "Nortel emobility", 0), +PCI_ROM(0x1385, 0x4100, "ma301", "Netgear MA301", 0), PCI_ROM(0x15e8, 0x0130, "correga", "Correga", 0), PCI_ROM(0x1638, 0x1100, "smc2602w", "SMC EZConnect SMC2602W", 0), /* or Eumitcom PCI WL11000, Addtron AWA-100 */ PCI_ROM(0x16ab, 0x1100, "gl24110p", "Global Sun Tech GL24110P", 0), @@ -114,7 +115,6 @@ PCI_ROM(0x16ab, 0x1101, "16ab-1101", "Unknown", 0), PCI_ROM(0x16ab, 0x1102, "wdt11", "Linksys WDT11", 0), PCI_ROM(0x16ec, 0x3685, "usr2415", "USR 2415", 0), PCI_ROM(0xec80, 0xec00, "f5d6000", "Belkin F5D6000", 0), -PCI_ROM(0x126c, 0x8030, "emobility", "Nortel emobility", 0), }; PCI_DRIVER ( prism2_plx_driver, prism2_plx_nics, PCI_NO_CLASS ); diff --git a/src/drivers/net/rhine.c b/src/drivers/net/rhine.c index f4d3a258..fa0876ad 100644 --- a/src/drivers/net/rhine.c +++ b/src/drivers/net/rhine.c @@ -775,10 +775,10 @@ static void rhine_remove ( struct pci_device *pci ) { /** Rhine PCI device IDs */ static struct pci_device_id rhine_nics[] = { - PCI_ROM ( 0x1106, 0x3065, "dlink-530tx", "VIA VT6102", 0 ), - PCI_ROM ( 0x1106, 0x3106, "vt6105", "VIA VT6105", 0 ), PCI_ROM ( 0x1106, 0x3043, "dlink-530tx-old", "VIA VT3043", 0 ), PCI_ROM ( 0x1106, 0x3053, "vt6105m", "VIA VT6105M", 0 ), + PCI_ROM ( 0x1106, 0x3065, "dlink-530tx", "VIA VT6102", 0 ), + PCI_ROM ( 0x1106, 0x3106, "vt6105", "VIA VT6105", 0 ), PCI_ROM ( 0x1106, 0x6100, "via-rhine-old", "VIA 86C100A", 0 ) }; diff --git a/src/drivers/net/rtl818x/rtl8180.c b/src/drivers/net/rtl818x/rtl8180.c index 5f97480f..b3f68541 100644 --- a/src/drivers/net/rtl818x/rtl8180.c +++ b/src/drivers/net/rtl818x/rtl8180.c @@ -7,9 +7,9 @@ FILE_LICENCE(GPL2_OR_LATER); static struct pci_device_id rtl8180_nics[] = { PCI_ROM(0x10ec, 0x8180, "rtl8180", "Realtek 8180", 0), + PCI_ROM(0x1186, 0x3300, "dwl510", "D-Link DWL-510", 0), PCI_ROM(0x1799, 0x6001, "f5d6001", "Belkin F5D6001", 0), PCI_ROM(0x1799, 0x6020, "f5d6020", "Belkin F5D6020", 0), - PCI_ROM(0x1186, 0x3300, "dwl510", "D-Link DWL-510", 0), }; struct pci_driver rtl8180_driver __pci_driver = { diff --git a/src/drivers/net/sky2.c b/src/drivers/net/sky2.c index 26396585..4f8ec3e4 100644 --- a/src/drivers/net/sky2.c +++ b/src/drivers/net/sky2.c @@ -81,8 +81,8 @@ FILE_LICENCE ( GPL2_ONLY ); static struct pci_device_id sky2_id_table[] = { PCI_ROM(0x1148, 0x9000, "sk9sxx", "Syskonnect SK-9Sxx", 0), PCI_ROM(0x1148, 0x9e00, "sk9exx", "Syskonnect SK-9Exx", 0), - PCI_ROM(0x1186, 0x4b00, "dge560t", "D-Link DGE-560T", 0), PCI_ROM(0x1186, 0x4001, "dge550sx", "D-Link DGE-550SX", 0), + PCI_ROM(0x1186, 0x4b00, "dge560t", "D-Link DGE-560T", 0), PCI_ROM(0x1186, 0x4b02, "dge560sx", "D-Link DGE-560SX", 0), PCI_ROM(0x1186, 0x4b03, "dge550t", "D-Link DGE-550T", 0), PCI_ROM(0x11ab, 0x4340, "m88e8021", "Marvell 88E8021", 0), diff --git a/src/drivers/net/sundance.c b/src/drivers/net/sundance.c index 9127fa2c..8eb09b98 100644 --- a/src/drivers/net/sundance.c +++ b/src/drivers/net/sundance.c @@ -880,9 +880,9 @@ static void set_rx_mode(struct nic *nic __unused) } static struct pci_device_id sundance_nics[] = { - PCI_ROM(0x13f0, 0x0201, "sundance", "ST201 Sundance 'Alta' based Adaptor", 0), PCI_ROM(0x1186, 0x1002, "dfe530txs", "D-Link DFE530TXS (Sundance ST201 Alta)", 0), PCI_ROM(0x13f0, 0x0200, "ip100a", "IC+ IP100A", 0), + PCI_ROM(0x13f0, 0x0201, "sundance", "ST201 Sundance 'Alta' based Adaptor", 0), }; PCI_DRIVER ( sundance_driver, sundance_nics, PCI_NO_CLASS ); diff --git a/src/drivers/net/tg3/tg3.c b/src/drivers/net/tg3/tg3.c index 559c2d63..05af22d6 100644 --- a/src/drivers/net/tg3/tg3.c +++ b/src/drivers/net/tg3/tg3.c @@ -856,88 +856,88 @@ static void tg3_remove_one(struct pci_device *pci) } static struct pci_device_id tg3_nics[] = { + PCI_ROM(0x106b, 0x1645, "106b-1645", "106b-1645", 0), + PCI_ROM(0x1148, 0x4400, "1148-4400", "1148-4400", 0), + PCI_ROM(0x1148, 0x4500, "1148-4500", "1148-4500", 0), + PCI_ROM(0x14e4, 0x1600, "14e4-1600", "14e4-1600", 0), + PCI_ROM(0x14e4, 0x1601, "14e4-1601", "14e4-1601", 0), PCI_ROM(0x14e4, 0x1644, "14e4-1644", "14e4-1644", 0), PCI_ROM(0x14e4, 0x1645, "14e4-1645", "14e4-1645", 0), PCI_ROM(0x14e4, 0x1646, "14e4-1646", "14e4-1646", 0), PCI_ROM(0x14e4, 0x1647, "14e4-1647", "14e4-1647", 0), PCI_ROM(0x14e4, 0x1648, "14e4-1648", "14e4-1648", 0), + PCI_ROM(0x14e4, 0x1649, "14e4-1649", "14e4-1649", 0), PCI_ROM(0x14e4, 0x164d, "14e4-164d", "14e4-164d", 0), PCI_ROM(0x14e4, 0x1653, "14e4-1653", "14e4-1653", 0), PCI_ROM(0x14e4, 0x1654, "14e4-1654", "14e4-1654", 0), + PCI_ROM(0x14e4, 0x1655, "14e4-1655", "14e4-1655", 0), + PCI_ROM(0x14e4, 0x1656, "14e4-1656", "14e4-1656", 0), + PCI_ROM(0x14e4, 0x1657, "14e4-1657", "14e4-1657", 0), + PCI_ROM(0x14e4, 0x1659, "14e4-1659", "14e4-1659", 0), + PCI_ROM(0x14e4, 0x165a, "14e4-165a", "14e4-165a", 0), + PCI_ROM(0x14e4, 0x165b, "14e4-165b", "14e4-165b", 0), PCI_ROM(0x14e4, 0x165d, "14e4-165d", "14e4-165d", 0), PCI_ROM(0x14e4, 0x165e, "14e4-165e", "14e4-165e", 0), - PCI_ROM(0x14e4, 0x16a6, "14e4-16a6", "14e4-16a6", 0), - PCI_ROM(0x14e4, 0x16a7, "14e4-16a7", "14e4-16a7", 0), - PCI_ROM(0x14e4, 0x16a8, "14e4-16a8", "14e4-16a8", 0), - PCI_ROM(0x14e4, 0x16c6, "14e4-16c6", "14e4-16c6", 0), - PCI_ROM(0x14e4, 0x16c7, "14e4-16c7", "14e4-16c7", 0), - PCI_ROM(0x14e4, 0x1696, "14e4-1696", "14e4-1696", 0), - PCI_ROM(0x14e4, 0x169c, "14e4-169c", "14e4-169c", 0), - PCI_ROM(0x14e4, 0x169d, "14e4-169d", "14e4-169d", 0), - PCI_ROM(0x14e4, 0x170d, "14e4-170d", "14e4-170d", 0), - PCI_ROM(0x14e4, 0x170e, "14e4-170e", "14e4-170e", 0), - PCI_ROM(0x14e4, 0x1649, "14e4-1649", "14e4-1649", 0), + PCI_ROM(0x14e4, 0x165f, "14e4-165f", "14e4-165f", 0), + PCI_ROM(0x14e4, 0x1668, "14e4-1668", "14e4-1668", 0), + PCI_ROM(0x14e4, 0x1669, "14e4-1669", "14e4-1669", 0), + PCI_ROM(0x14e4, 0x166a, "14e4-166a", "14e4-166a", 0), + PCI_ROM(0x14e4, 0x166b, "14e4-166b", "14e4-166b", 0), PCI_ROM(0x14e4, 0x166e, "14e4-166e", "14e4-166e", 0), - PCI_ROM(0x14e4, 0x1659, "14e4-1659", "14e4-1659", 0), - PCI_ROM(0x14e4, 0x165a, "14e4-165a", "14e4-165a", 0), - PCI_ROM(0x14e4, 0x1677, "14e4-1677", "14e4-1677", 0), - PCI_ROM(0x14e4, 0x167d, "14e4-167d", "14e4-167d", 0), - PCI_ROM(0x14e4, 0x167e, "14e4-167e", "14e4-167e", 0), - PCI_ROM(0x14e4, 0x1600, "14e4-1600", "14e4-1600", 0), - PCI_ROM(0x14e4, 0x1601, "14e4-1601", "14e4-1601", 0), - PCI_ROM(0x14e4, 0x16f7, "14e4-16f7", "14e4-16f7", 0), - PCI_ROM(0x14e4, 0x16fd, "14e4-16fd", "14e4-16fd", 0), - PCI_ROM(0x14e4, 0x16fe, "14e4-16fe", "14e4-16fe", 0), - PCI_ROM(0x14e4, 0x167a, "14e4-167a", "14e4-167a", 0), PCI_ROM(0x14e4, 0x1672, "14e4-1672", "14e4-1672", 0), - PCI_ROM(0x14e4, 0x167b, "14e4-167b", "14e4-167b", 0), PCI_ROM(0x14e4, 0x1673, "14e4-1673", "14e4-1673", 0), PCI_ROM(0x14e4, 0x1674, "14e4-1674", "14e4-1674", 0), - PCI_ROM(0x14e4, 0x169a, "14e4-169a", "14e4-169a", 0), - PCI_ROM(0x14e4, 0x169b, "14e4-169b", "14e4-169b", 0), - PCI_ROM(0x14e4, 0x1693, "14e4-1693", "14e4-1693", 0), - PCI_ROM(0x14e4, 0x167f, "14e4-167f", "14e4-167f", 0), - PCI_ROM(0x14e4, 0x1668, "14e4-1668", "14e4-1668", 0), - PCI_ROM(0x14e4, 0x1669, "14e4-1669", "14e4-1669", 0), + PCI_ROM(0x14e4, 0x1677, "14e4-1677", "14e4-1677", 0), PCI_ROM(0x14e4, 0x1678, "14e4-1678", "14e4-1678", 0), PCI_ROM(0x14e4, 0x1679, "14e4-1679", "14e4-1679", 0), - PCI_ROM(0x14e4, 0x166a, "14e4-166a", "14e4-166a", 0), - PCI_ROM(0x14e4, 0x166b, "14e4-166b", "14e4-166b", 0), - PCI_ROM(0x14e4, 0x16dd, "14e4-16dd", "14e4-16dd", 0), - PCI_ROM(0x14e4, 0x1712, "14e4-1712", "14e4-1712", 0), - PCI_ROM(0x14e4, 0x1713, "14e4-1713", "14e4-1713", 0), - PCI_ROM(0x14e4, 0x1698, "14e4-1698", "14e4-1698", 0), - PCI_ROM(0x14e4, 0x1684, "14e4-1684", "14e4-1684", 0), - PCI_ROM(0x14e4, 0x165b, "14e4-165b", "14e4-165b", 0), + PCI_ROM(0x14e4, 0x167a, "14e4-167a", "14e4-167a", 0), + PCI_ROM(0x14e4, 0x167b, "14e4-167b", "14e4-167b", 0), + PCI_ROM(0x14e4, 0x167d, "14e4-167d", "14e4-167d", 0), + PCI_ROM(0x14e4, 0x167e, "14e4-167e", "14e4-167e", 0), + PCI_ROM(0x14e4, 0x167f, "14e4-167f", "14e4-167f", 0), + PCI_ROM(0x14e4, 0x1680, "14e4-1680", "14e4-1680", 0), PCI_ROM(0x14e4, 0x1681, "14e4-1681", "14e4-1681", 0), PCI_ROM(0x14e4, 0x1682, "14e4-1682", "14e4-1682", 0), - PCI_ROM(0x14e4, 0x1680, "14e4-1680", "14e4-1680", 0), + PCI_ROM(0x14e4, 0x1684, "14e4-1684", "14e4-1684", 0), + PCI_ROM(0x14e4, 0x1686, "14e4-1686", "14e4-1686", 0), PCI_ROM(0x14e4, 0x1688, "14e4-1688", "14e4-1688", 0), PCI_ROM(0x14e4, 0x1689, "14e4-1689", "14e4-1689", 0), - PCI_ROM(0x14e4, 0x1699, "14e4-1699", "14e4-1699", 0), - PCI_ROM(0x14e4, 0x16a0, "14e4-16a0", "14e4-16a0", 0), - PCI_ROM(0x14e4, 0x1692, "14e4-1692", "14e4-1692", 0), PCI_ROM(0x14e4, 0x1690, "14e4-1690", "14e4-1690", 0), - PCI_ROM(0x14e4, 0x1694, "14e4-1694", "14e4-1694", 0), PCI_ROM(0x14e4, 0x1691, "14e4-1691", "14e4-1691", 0), - PCI_ROM(0x14e4, 0x1655, "14e4-1655", "14e4-1655", 0), - PCI_ROM(0x14e4, 0x1656, "14e4-1656", "14e4-1656", 0), - PCI_ROM(0x14e4, 0x16b1, "14e4-16b1", "14e4-16b1", 0), - PCI_ROM(0x14e4, 0x16b5, "14e4-16b5", "14e4-16b5", 0), + PCI_ROM(0x14e4, 0x1692, "14e4-1692", "14e4-1692", 0), + PCI_ROM(0x14e4, 0x1693, "14e4-1693", "14e4-1693", 0), + PCI_ROM(0x14e4, 0x1694, "14e4-1694", "14e4-1694", 0), + PCI_ROM(0x14e4, 0x1696, "14e4-1696", "14e4-1696", 0), + PCI_ROM(0x14e4, 0x1698, "14e4-1698", "14e4-1698", 0), + PCI_ROM(0x14e4, 0x1699, "14e4-1699", "14e4-1699", 0), + PCI_ROM(0x14e4, 0x169a, "14e4-169a", "14e4-169a", 0), + PCI_ROM(0x14e4, 0x169b, "14e4-169b", "14e4-169b", 0), + PCI_ROM(0x14e4, 0x169c, "14e4-169c", "14e4-169c", 0), + PCI_ROM(0x14e4, 0x169d, "14e4-169d", "14e4-169d", 0), + PCI_ROM(0x14e4, 0x16a0, "14e4-16a0", "14e4-16a0", 0), + PCI_ROM(0x14e4, 0x16a6, "14e4-16a6", "14e4-16a6", 0), + PCI_ROM(0x14e4, 0x16a7, "14e4-16a7", "14e4-16a7", 0), + PCI_ROM(0x14e4, 0x16a8, "14e4-16a8", "14e4-16a8", 0), PCI_ROM(0x14e4, 0x16b0, "14e4-16b0", "14e4-16b0", 0), - PCI_ROM(0x14e4, 0x16b4, "14e4-16b4", "14e4-16b4", 0), + PCI_ROM(0x14e4, 0x16b1, "14e4-16b1", "14e4-16b1", 0), PCI_ROM(0x14e4, 0x16b2, "14e4-16b2", "14e4-16b2", 0), + PCI_ROM(0x14e4, 0x16b4, "14e4-16b4", "14e4-16b4", 0), + PCI_ROM(0x14e4, 0x16b5, "14e4-16b5", "14e4-16b5", 0), PCI_ROM(0x14e4, 0x16b6, "14e4-16b6", "14e4-16b6", 0), - PCI_ROM(0x14e4, 0x1657, "14e4-1657", "14e4-1657", 0), - PCI_ROM(0x14e4, 0x165f, "14e4-165f", "14e4-165f", 0), - PCI_ROM(0x14e4, 0x1686, "14e4-1686", "14e4-1686", 0), - PCI_ROM(0x1148, 0x4400, "1148-4400", "1148-4400", 0), - PCI_ROM(0x1148, 0x4500, "1148-4500", "1148-4500", 0), + PCI_ROM(0x14e4, 0x16c6, "14e4-16c6", "14e4-16c6", 0), + PCI_ROM(0x14e4, 0x16c7, "14e4-16c7", "14e4-16c7", 0), + PCI_ROM(0x14e4, 0x16dd, "14e4-16dd", "14e4-16dd", 0), + PCI_ROM(0x14e4, 0x16f7, "14e4-16f7", "14e4-16f7", 0), + PCI_ROM(0x14e4, 0x16fd, "14e4-16fd", "14e4-16fd", 0), + PCI_ROM(0x14e4, 0x16fe, "14e4-16fe", "14e4-16fe", 0), + PCI_ROM(0x14e4, 0x170d, "14e4-170d", "14e4-170d", 0), + PCI_ROM(0x14e4, 0x170e, "14e4-170e", "14e4-170e", 0), + PCI_ROM(0x14e4, 0x1712, "14e4-1712", "14e4-1712", 0), + PCI_ROM(0x14e4, 0x1713, "14e4-1713", "14e4-1713", 0), PCI_ROM(0x173b, 0x03e8, "173b-03e8", "173b-03e8", 0), PCI_ROM(0x173b, 0x03e9, "173b-03e9", "173b-03e9", 0), - PCI_ROM(0x173b, 0x03eb, "173b-03eb", "173b-03eb", 0), PCI_ROM(0x173b, 0x03ea, "173b-03ea", "173b-03ea", 0), - PCI_ROM(0x106b, 0x1645, "106b-1645", "106b-1645", 0), + PCI_ROM(0x173b, 0x03eb, "173b-03eb", "173b-03eb", 0), }; struct pci_driver tg3_pci_driver __pci_driver = { diff --git a/src/drivers/net/tlan.c b/src/drivers/net/tlan.c index 0e85b35b..93533b43 100644 --- a/src/drivers/net/tlan.c +++ b/src/drivers/net/tlan.c @@ -1697,19 +1697,19 @@ void TLan_PhyMonitor(struct net_device *dev) #endif /* MONITOR */ static struct pci_device_id tlan_nics[] = { - PCI_ROM(0x0e11, 0xae34, "netel10", "Compaq Netelligent 10 T PCI UTP", 0), PCI_ROM(0x0e11, 0xae32, "netel100","Compaq Netelligent 10/100 TX PCI UTP", 0), + PCI_ROM(0x0e11, 0xae34, "netel10", "Compaq Netelligent 10 T PCI UTP", 0), PCI_ROM(0x0e11, 0xae35, "netflex3i", "Compaq Integrated NetFlex-3/P", 0), - PCI_ROM(0x0e11, 0xf130, "thunder", "Compaq NetFlex-3/P", 0), - PCI_ROM(0x0e11, 0xf150, "netflex3b", "Compaq NetFlex-3/P", 0), - PCI_ROM(0x0e11, 0xae43, "netel100pi", "Compaq Netelligent Integrated 10/100 TX UTP", 0), PCI_ROM(0x0e11, 0xae40, "netel100d", "Compaq Netelligent Dual 10/100 TX PCI UTP", 0), + PCI_ROM(0x0e11, 0xae43, "netel100pi", "Compaq Netelligent Integrated 10/100 TX UTP", 0), PCI_ROM(0x0e11, 0xb011, "netel100i", "Compaq Netelligent 10/100 TX Embedded UTP", 0), - PCI_ROM(0x108d, 0x0013, "oc2183", "Olicom OC-2183/2185", 0), + PCI_ROM(0x0e11, 0xb012, "netelligent_10_t2", "Compaq Netelligent 10 T/2 PCI UTP/Coax", 0), + PCI_ROM(0x0e11, 0xb030, "netelligent_10_100_ws_5100", "Compaq Netelligent 10/100 TX UTP", 0), + PCI_ROM(0x0e11, 0xf130, "thunder", "Compaq NetFlex-3/P", 0), + PCI_ROM(0x0e11, 0xf150, "netflex3b", "Compaq NetFlex-3/P", 0), PCI_ROM(0x108d, 0x0012, "oc2325", "Olicom OC-2325", 0), + PCI_ROM(0x108d, 0x0013, "oc2183", "Olicom OC-2183/2185", 0), PCI_ROM(0x108d, 0x0014, "oc2326", "Olicom OC-2326", 0), - PCI_ROM(0x0e11, 0xb030, "netelligent_10_100_ws_5100", "Compaq Netelligent 10/100 TX UTP", 0), - PCI_ROM(0x0e11, 0xb012, "netelligent_10_t2", "Compaq Netelligent 10 T/2 PCI UTP/Coax", 0), }; PCI_DRIVER ( tlan_driver, tlan_nics, PCI_NO_CLASS ); diff --git a/src/drivers/net/tulip.c b/src/drivers/net/tulip.c index e4e6ffa8..fddebfe5 100644 --- a/src/drivers/net/tulip.c +++ b/src/drivers/net/tulip.c @@ -1921,31 +1921,30 @@ PCI_ROM(0x1011, 0x0002, "dc21040", "Digital Tulip", 0), PCI_ROM(0x1011, 0x0009, "ds21140", "Digital Tulip Fast", 0), PCI_ROM(0x1011, 0x0014, "dc21041", "Digital Tulip+", 0), PCI_ROM(0x1011, 0x0019, "ds21142", "Digital Tulip 21142", 0), +PCI_ROM(0x104a, 0x0981, "tulip-0981", "Tulip 0x104a 0x0981", 0), +PCI_ROM(0x104a, 0x2774, "SGThomson-STE10100A", "Tulip 0x104a 0x2774", 0), /*Modified by Ramesh Chander*/ PCI_ROM(0x10b7, 0x9300, "3csoho100b-tx","3ComSOHO100B-TX", 0), PCI_ROM(0x10b9, 0x5261, "ali1563", "ALi 1563 integrated ethernet", 0), PCI_ROM(0x10d9, 0x0512, "mx98713", "Macronix MX987x3", 0), PCI_ROM(0x10d9, 0x0531, "mx98715", "Macronix MX987x5", 0), +PCI_ROM(0x1113, 0x1216, "an983", "ADMTek AN983 Comet", 0), PCI_ROM(0x1113, 0x1217, "mxic-98715", "Macronix MX987x5", 0), -PCI_ROM(0x11ad, 0xc115, "lc82c115", "LinkSys LNE100TX", 0), +PCI_ROM(0x1113, 0x9511, "tulip-9511", "Tulip 0x1113 0x9511", 0), +PCI_ROM(0x115d, 0x0003, "xircomtulip", "Xircom Tulip", 0), +PCI_ROM(0x1186, 0x1561, "tulip-1561", "Tulip 0x1186 0x1561", 0), PCI_ROM(0x11ad, 0x0002, "82c168", "Netgear FA310TX", 0), +PCI_ROM(0x11ad, 0xc115, "lc82c115", "LinkSys LNE100TX", 0), +PCI_ROM(0x11f6, 0x9881, "rl100tx", "Compex RL100-TX", 0), +PCI_ROM(0x1259, 0xa120, "tulip-a120", "Tulip 0x1259 0xa120", 0), +PCI_ROM(0x125b, 0x1400, "ax88140", "ASIX AX88140", 0), +PCI_ROM(0x1282, 0x9009, "dm9009", "Davicom 9009", 0), PCI_ROM(0x1282, 0x9100, "dm9100", "Davicom 9100", 0), PCI_ROM(0x1282, 0x9102, "dm9102", "Davicom 9102", 0), -PCI_ROM(0x1282, 0x9009, "dm9009", "Davicom 9009", 0), PCI_ROM(0x1282, 0x9132, "dm9132", "Davicom 9132", 0), -PCI_ROM(0x1317, 0x0985, "centaur-p", "ADMtek Centaur-P", 0), PCI_ROM(0x1317, 0x0981, "an981", "ADMtek AN981 Comet", 0), /* ADMTek Centaur-P (stmicro) */ -PCI_ROM(0x1113, 0x1216, "an983", "ADMTek AN983 Comet", 0), -PCI_ROM(0x1317, 0x9511, "an983b", "ADMTek Comet 983b", 0), +PCI_ROM(0x1317, 0x0985, "centaur-p", "ADMtek Centaur-P", 0), PCI_ROM(0x1317, 0x1985, "centaur-c", "ADMTek Centaur-C", 0), -PCI_ROM(0x8086, 0x0039, "intel21145", "Intel Tulip", 0), -PCI_ROM(0x125b, 0x1400, "ax88140", "ASIX AX88140", 0), -PCI_ROM(0x11f6, 0x9881, "rl100tx", "Compex RL100-TX", 0), -PCI_ROM(0x115d, 0x0003, "xircomtulip", "Xircom Tulip", 0), -PCI_ROM(0x104a, 0x0981, "tulip-0981", "Tulip 0x104a 0x0981", 0), -PCI_ROM(0x104a, 0x2774, "SGThomson-STE10100A", "Tulip 0x104a 0x2774", 0), /*Modified by Ramesh Chander*/ -PCI_ROM(0x1113, 0x9511, "tulip-9511", "Tulip 0x1113 0x9511", 0), -PCI_ROM(0x1186, 0x1561, "tulip-1561", "Tulip 0x1186 0x1561", 0), -PCI_ROM(0x1259, 0xa120, "tulip-a120", "Tulip 0x1259 0xa120", 0), +PCI_ROM(0x1317, 0x9511, "an983b", "ADMTek Comet 983b", 0), PCI_ROM(0x13d1, 0xab02, "tulip-ab02", "Tulip 0x13d1 0xab02", 0), PCI_ROM(0x13d1, 0xab03, "tulip-ab03", "Tulip 0x13d1 0xab03", 0), PCI_ROM(0x13d1, 0xab08, "tulip-ab08", "Tulip 0x13d1 0xab08", 0), @@ -1953,6 +1952,7 @@ PCI_ROM(0x14f1, 0x1803, "lanfinity", "Conexant LANfinity", 0), PCI_ROM(0x1626, 0x8410, "tulip-8410", "Tulip 0x1626 0x8410", 0), PCI_ROM(0x1737, 0xab08, "tulip-1737-ab08","Tulip 0x1737 0xab08", 0), PCI_ROM(0x1737, 0xab09, "tulip-ab09", "Tulip 0x1737 0xab09", 0), +PCI_ROM(0x8086, 0x0039, "intel21145", "Intel Tulip", 0), }; PCI_DRIVER ( tulip_driver, tulip_nics, PCI_NO_CLASS ); -- cgit v1.2.3-55-g7522 From ee6185dcf5ad7b0d5e486e66c424341764fc221d Mon Sep 17 00:00:00 2001 From: Alexey Sheplyakov Date: Wed, 21 Feb 2024 13:07:21 +0400 Subject: [efi] Ignore new LoongArch PC-relative relocations and relaxations Several new relocations types have been added in LoongArch ABI version 2.10. In particular: - R_LARCH_B16 (18-bit PC-relative jump) - R_LARCH_B21 (23-bit PC-relative jump) - R_LARCH_PCREL20_S2 (22-bit PC-relative offset) Also relocation relaxations have been introduced. Recent GCC (13.2) and binutils 2.41+ use these types of relocations, which confuses elf2efi tool. As a result, iPXE EFI images for LoongArch fail to build with the following error: Unrecognised relocation type 103 Fix by ignoring R_LARCH_B{16,21} and R_LARCH_PCREL20_S2 (as with other PC-relative relocations), and by ignoring relaxations (R_LARCH_RELAX). Relocation relaxations are basically optimizations: ignoring them results in a correct binary (although it might be suboptimal). Modified-by: Michael Brown Signed-off-by: Michael Brown --- src/util/elf2efi.c | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/src/util/elf2efi.c b/src/util/elf2efi.c index 88713b66..4af587d8 100644 --- a/src/util/elf2efi.c +++ b/src/util/elf2efi.c @@ -140,6 +140,12 @@ #ifndef R_LARCH_64 #define R_LARCH_64 2 #endif +#ifndef R_LARCH_B16 +#define R_LARCH_B16 64 +#endif +#ifndef R_LARCH_B21 +#define R_LARCH_B21 65 +#endif #ifndef R_LARCH_B26 #define R_LARCH_B26 66 #endif @@ -155,6 +161,12 @@ #ifndef R_LARCH_GOT_PC_LO12 #define R_LARCH_GOT_PC_LO12 76 #endif +#ifndef R_LARCH_RELAX +#define R_LARCH_RELAX 100 +#endif +#ifndef R_LARCH_PCREL20_S2 +#define R_LARCH_PCREL20_S2 103 +#endif #ifndef R_X86_64_GOTPCRELX #define R_X86_64_GOTPCRELX 41 #endif @@ -849,16 +861,24 @@ static void process_reloc ( struct elf_file *elf, const Elf_Shdr *shdr, case ELF_MREL ( EM_AARCH64, R_AARCH64_LDST32_ABS_LO12_NC ) : case ELF_MREL ( EM_AARCH64, R_AARCH64_LDST64_ABS_LO12_NC ) : case ELF_MREL ( EM_AARCH64, R_AARCH64_LDST128_ABS_LO12_NC ) : + case ELF_MREL ( EM_LOONGARCH, R_LARCH_B16): + case ELF_MREL ( EM_LOONGARCH, R_LARCH_B21): case ELF_MREL ( EM_LOONGARCH, R_LARCH_B26): case ELF_MREL ( EM_LOONGARCH, R_LARCH_PCALA_HI20 ): case ELF_MREL ( EM_LOONGARCH, R_LARCH_PCALA_LO12 ): case ELF_MREL ( EM_LOONGARCH, R_LARCH_GOT_PC_HI20 ): case ELF_MREL ( EM_LOONGARCH, R_LARCH_GOT_PC_LO12 ): + case ELF_MREL ( EM_LOONGARCH, R_LARCH_PCREL20_S2 ): /* Skip PC-relative relocations; all relative * offsets remain unaltered when the object is * loaded. */ break; + case ELF_MREL ( EM_LOONGARCH, R_LARCH_RELAX ): + /* Relocation can be relaxed (optimized out). + * Ignore it for now. + */ + break; case ELF_MREL ( EM_X86_64, R_X86_64_32 ) : /* Ignore 32-bit relocations in a hybrid * 32-bit BIOS and 64-bit UEFI binary, -- cgit v1.2.3-55-g7522 From 834f319f87bd2a1135c51375774f6bfe17a244cc Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Fri, 23 Feb 2024 15:58:51 +0000 Subject: [eap] Add progress debug messages Add debug messages for each EAP Request and Response, and to show the list of methods offered when sending a Nak. Signed-off-by: Michael Brown --- src/net/eap.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/net/eap.c b/src/net/eap.c index 79b060aa..696b7fe9 100644 --- a/src/net/eap.c +++ b/src/net/eap.c @@ -65,6 +65,8 @@ static int eap_tx_response ( struct eap_supplicant *supplicant, msg->hdr.len = htons ( len ); msg->type = supplicant->type; memcpy ( msg->data, rsp, rsp_len ); + DBGC ( netdev, "EAP %s Response id %#02x type %d\n", + netdev->name, msg->hdr.id, msg->type ); /* Transmit response */ if ( ( rc = supplicant->tx ( supplicant, msg, len ) ) != 0 ) { @@ -86,18 +88,24 @@ static int eap_tx_response ( struct eap_supplicant *supplicant, * @ret rc Return status code */ static int eap_tx_nak ( struct eap_supplicant *supplicant ) { + struct net_device *netdev = supplicant->netdev; unsigned int max = table_num_entries ( EAP_METHODS ); uint8_t methods[ max + 1 /* potential EAP_TYPE_NONE */ ]; unsigned int count = 0; struct eap_method *method; /* Populate methods list */ + DBGC ( netdev, "EAP %s Nak offering types {", netdev->name ); for_each_table_entry ( method, EAP_METHODS ) { - if ( method->type > EAP_TYPE_NAK ) + if ( method->type > EAP_TYPE_NAK ) { + DBGC ( netdev, "%s%d", + ( count ? ", " : "" ), method->type ); methods[count++] = method->type; + } } if ( ! count ) methods[count++] = EAP_TYPE_NONE; + DBGC ( netdev, "}\n" ); assert ( count <= max ); /* Transmit response */ @@ -269,6 +277,8 @@ static int eap_rx_request ( struct eap_supplicant *supplicant, /* Record request details */ supplicant->id = msg->hdr.id; supplicant->type = msg->type; + DBGC ( netdev, "EAP %s Request id %#02x type %d\n", + netdev->name, msg->hdr.id, msg->type ); /* Handle according to type */ for_each_table_entry ( method, EAP_METHODS ) { -- cgit v1.2.3-55-g7522 From 25ffcd79bfd38da96f9905b78e3d5c3cab33dad3 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Fri, 23 Feb 2024 12:33:57 +0000 Subject: [eap] Allow MD5-Challenge authentication method to be disabled RFC 3748 states that implementations must support the MD5-Challenge method. However, some network environments may wish to disable it as a matter of policy. Allow support for MD5-Challenge to be controllable via the build configuration option EAP_METHOD_MD5 in config/general.h. Signed-off-by: Michael Brown --- src/config/config_eap.c | 39 +++++++++++++++ src/config/general.h | 6 +++ src/include/ipxe/eap.h | 2 + src/include/ipxe/errfile.h | 1 + src/net/eap.c | 90 ++++------------------------------- src/net/eap_md5.c | 116 +++++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 172 insertions(+), 82 deletions(-) create mode 100644 src/config/config_eap.c create mode 100644 src/net/eap_md5.c diff --git a/src/config/config_eap.c b/src/config/config_eap.c new file mode 100644 index 00000000..d3fd77aa --- /dev/null +++ b/src/config/config_eap.c @@ -0,0 +1,39 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + * + * You can also choose to distribute this program under the terms of + * the Unmodified Binary Distribution Licence (as given in the file + * COPYING.UBDL), provided that you have satisfied its requirements. + */ + +FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); + +#include + +/** @file + * + * EAP configuration options + * + */ + +PROVIDE_REQUIRING_SYMBOL(); + +/* + * Drag in EAP authentication methods + */ +#ifdef EAP_METHOD_MD5 +REQUIRE_OBJECT ( eap_md5 ); +#endif diff --git a/src/config/general.h b/src/config/general.h index 6e8e86b2..de009a87 100644 --- a/src/config/general.h +++ b/src/config/general.h @@ -91,6 +91,12 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #define CRYPTO_80211_WPA /* WPA Personal, authenticating with passphrase */ #define CRYPTO_80211_WPA2 /* Add support for stronger WPA cryptography */ +/* + * 802.1x EAP authentication methods + * + */ +#define EAP_METHOD_MD5 /* MD5-Challenge port authentication */ + /* * Name resolution modules * diff --git a/src/include/ipxe/eap.h b/src/include/ipxe/eap.h index cf1c7c00..fe1bb528 100644 --- a/src/include/ipxe/eap.h +++ b/src/include/ipxe/eap.h @@ -166,6 +166,8 @@ struct eap_method { /** Declare an EAP method */ #define __eap_method __table_entry ( EAP_METHODS, 01 ) +extern int eap_tx_response ( struct eap_supplicant *supplicant, + const void *rsp, size_t rsp_len ); extern int eap_rx ( struct eap_supplicant *supplicant, const void *data, size_t len ); diff --git a/src/include/ipxe/errfile.h b/src/include/ipxe/errfile.h index f7a00dbe..1768748d 100644 --- a/src/include/ipxe/errfile.h +++ b/src/include/ipxe/errfile.h @@ -297,6 +297,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #define ERRFILE_httpntlm ( ERRFILE_NET | 0x004a0000 ) #define ERRFILE_eap ( ERRFILE_NET | 0x004b0000 ) #define ERRFILE_lldp ( ERRFILE_NET | 0x004c0000 ) +#define ERRFILE_eap_md5 ( ERRFILE_NET | 0x004d0000 ) #define ERRFILE_image ( ERRFILE_IMAGE | 0x00000000 ) #define ERRFILE_elf ( ERRFILE_IMAGE | 0x00010000 ) diff --git a/src/net/eap.c b/src/net/eap.c index 696b7fe9..87327d72 100644 --- a/src/net/eap.c +++ b/src/net/eap.c @@ -28,8 +28,6 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #include #include #include -#include -#include #include /** @file @@ -46,8 +44,8 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); * @v rsp_len Length of response type data * @ret rc Return status code */ -static int eap_tx_response ( struct eap_supplicant *supplicant, - const void *rsp, size_t rsp_len ) { +int eap_tx_response ( struct eap_supplicant *supplicant, + const void *rsp, size_t rsp_len ) { struct net_device *netdev = supplicant->netdev; struct eap_message *msg; size_t len; @@ -167,84 +165,6 @@ struct eap_method eap_identity_method __eap_method = { .rx = eap_rx_identity, }; -/** - * Handle EAP MD5-Challenge - * - * @v req Request type data - * @v req_len Length of request type data - * @ret rc Return status code - */ -static int eap_rx_md5 ( struct eap_supplicant *supplicant, - const void *req, size_t req_len ) { - struct net_device *netdev = supplicant->netdev; - const struct eap_md5 *md5req = req; - struct { - uint8_t len; - uint8_t value[MD5_DIGEST_SIZE]; - } __attribute__ (( packed )) md5rsp; - struct chap_response chap; - void *secret; - int secret_len; - int rc; - - /* Sanity checks */ - if ( req_len < sizeof ( *md5req ) ) { - DBGC ( netdev, "EAP %s underlength MD5-Challenge:\n", - netdev->name ); - DBGC_HDA ( netdev, 0, req, req_len ); - rc = -EINVAL; - goto err_sanity; - } - if ( ( req_len - sizeof ( *md5req ) ) < md5req->len ) { - DBGC ( netdev, "EAP %s truncated MD5-Challenge:\n", - netdev->name ); - DBGC_HDA ( netdev, 0, req, req_len ); - rc = -EINVAL; - goto err_sanity; - } - - /* Construct response */ - if ( ( rc = chap_init ( &chap, &md5_algorithm ) ) != 0 ) { - DBGC ( netdev, "EAP %s could not initialise CHAP: %s\n", - netdev->name, strerror ( rc ) ); - goto err_chap; - } - chap_set_identifier ( &chap, supplicant->id ); - secret_len = fetch_raw_setting_copy ( netdev_settings ( netdev ), - &password_setting, &secret ); - if ( secret_len < 0 ) { - rc = secret_len; - DBGC ( netdev, "EAP %s has no secret: %s\n", - netdev->name, strerror ( rc ) ); - goto err_secret; - } - chap_update ( &chap, secret, secret_len ); - chap_update ( &chap, md5req->value, md5req->len ); - chap_respond ( &chap ); - assert ( chap.response_len == sizeof ( md5rsp.value ) ); - md5rsp.len = sizeof ( md5rsp.value ); - memcpy ( md5rsp.value, chap.response, sizeof ( md5rsp.value ) ); - - /* Transmit response */ - if ( ( rc = eap_tx_response ( supplicant, &md5rsp, - sizeof ( md5rsp ) ) ) != 0 ) - goto err_tx; - - err_tx: - free ( secret ); - err_secret: - chap_finish ( &chap ); - err_chap: - err_sanity: - return rc; -} - -/** EAP MD5-Challenge method */ -struct eap_method eap_md5_method __eap_method = { - .type = EAP_TYPE_MD5, - .rx = eap_rx_md5, -}; - /** * Handle EAP Request * @@ -370,3 +290,9 @@ int eap_rx ( struct eap_supplicant *supplicant, const void *data, return -ENOTSUP; } } + +/* Drag in objects via eap_rx() */ +REQUIRING_SYMBOL ( eap_rx ); + +/* Drag in EAP configuration */ +REQUIRE_OBJECT ( config_eap ); diff --git a/src/net/eap_md5.c b/src/net/eap_md5.c new file mode 100644 index 00000000..0664174f --- /dev/null +++ b/src/net/eap_md5.c @@ -0,0 +1,116 @@ +/* + * Copyright (C) 2024 Michael Brown . + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + * + * You can also choose to distribute this program under the terms of + * the Unmodified Binary Distribution Licence (as given in the file + * COPYING.UBDL), provided that you have satisfied its requirements. + */ + +FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); + +#include +#include +#include +#include +#include +#include + +/** @file + * + * EAP MD5-Challenge authentication method + * + */ + +/** + * Handle EAP MD5-Challenge + * + * @v supplicant EAP supplicant + * @v req Request type data + * @v req_len Length of request type data + * @ret rc Return status code + */ +static int eap_rx_md5 ( struct eap_supplicant *supplicant, + const void *req, size_t req_len ) { + struct net_device *netdev = supplicant->netdev; + const struct eap_md5 *md5req = req; + struct { + uint8_t len; + uint8_t value[MD5_DIGEST_SIZE]; + } __attribute__ (( packed )) md5rsp; + struct chap_response chap; + void *secret; + int secret_len; + int rc; + + /* Sanity checks */ + if ( req_len < sizeof ( *md5req ) ) { + DBGC ( netdev, "EAP %s underlength MD5-Challenge:\n", + netdev->name ); + DBGC_HDA ( netdev, 0, req, req_len ); + rc = -EINVAL; + goto err_sanity; + } + if ( ( req_len - sizeof ( *md5req ) ) < md5req->len ) { + DBGC ( netdev, "EAP %s truncated MD5-Challenge:\n", + netdev->name ); + DBGC_HDA ( netdev, 0, req, req_len ); + rc = -EINVAL; + goto err_sanity; + } + + /* Construct response */ + if ( ( rc = chap_init ( &chap, &md5_algorithm ) ) != 0 ) { + DBGC ( netdev, "EAP %s could not initialise CHAP: %s\n", + netdev->name, strerror ( rc ) ); + goto err_chap; + } + chap_set_identifier ( &chap, supplicant->id ); + secret_len = fetch_raw_setting_copy ( netdev_settings ( netdev ), + &password_setting, &secret ); + if ( secret_len < 0 ) { + rc = secret_len; + DBGC ( netdev, "EAP %s has no secret: %s\n", + netdev->name, strerror ( rc ) ); + goto err_secret; + } + chap_update ( &chap, secret, secret_len ); + chap_update ( &chap, md5req->value, md5req->len ); + chap_respond ( &chap ); + assert ( chap.response_len == sizeof ( md5rsp.value ) ); + md5rsp.len = sizeof ( md5rsp.value ); + memcpy ( md5rsp.value, chap.response, sizeof ( md5rsp.value ) ); + + /* Transmit response */ + if ( ( rc = eap_tx_response ( supplicant, &md5rsp, + sizeof ( md5rsp ) ) ) != 0 ) + goto err_tx; + + err_tx: + free ( secret ); + err_secret: + chap_finish ( &chap ); + err_chap: + err_sanity: + return rc; +} + +/** EAP MD5-Challenge method */ +struct eap_method eap_md5_method __eap_method = { + .type = EAP_TYPE_MD5, + .rx = eap_rx_md5, +}; -- cgit v1.2.3-55-g7522 From 43e385091a36af34e495ac8c6595bddab55665bb Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Fri, 23 Feb 2024 14:15:22 +0000 Subject: [eap] Add support for the MS-CHAPv2 authentication method Add support for EAP-MSCHAPv2 (note that this is not the same as PEAP-MSCHAPv2), controllable via the build configuration option EAP_METHOD_MSCHAPV2 in config/general.h. Our model for EAP does not encompass mutual authentication: we will starting sending plaintext packets (e.g. DHCP requests) over the link even before EAP completes, and our only use for an EAP success is to mark the link as unblocked. We therefore ignore the content of the EAP-MSCHAPv2 success request (containing the MS-CHAPv2 authenticator response) and just send back an EAP-MSCHAPv2 success response, so that the EAP authenticator will complete the process and send through the real EAP success packet (which will, in turn, cause us to unblock the link). Signed-off-by: Michael Brown --- src/config/config_eap.c | 3 + src/config/general.h | 1 + src/include/ipxe/eap.h | 29 ++++++ src/include/ipxe/errfile.h | 1 + src/net/eap_mschapv2.c | 251 +++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 285 insertions(+) create mode 100644 src/net/eap_mschapv2.c diff --git a/src/config/config_eap.c b/src/config/config_eap.c index d3fd77aa..e18c48ca 100644 --- a/src/config/config_eap.c +++ b/src/config/config_eap.c @@ -37,3 +37,6 @@ PROVIDE_REQUIRING_SYMBOL(); #ifdef EAP_METHOD_MD5 REQUIRE_OBJECT ( eap_md5 ); #endif +#ifdef EAP_METHOD_MSCHAPV2 +REQUIRE_OBJECT ( eap_mschapv2 ); +#endif diff --git a/src/config/general.h b/src/config/general.h index de009a87..c9cdb3dd 100644 --- a/src/config/general.h +++ b/src/config/general.h @@ -96,6 +96,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); * */ #define EAP_METHOD_MD5 /* MD5-Challenge port authentication */ +//#define EAP_METHOD_MSCHAPV2 /* MS-CHAPv2 port authentication */ /* * Name resolution modules diff --git a/src/include/ipxe/eap.h b/src/include/ipxe/eap.h index fe1bb528..a44f01e0 100644 --- a/src/include/ipxe/eap.h +++ b/src/include/ipxe/eap.h @@ -60,6 +60,35 @@ struct eap_md5 { uint8_t value[0]; } __attribute__ (( packed )); +/** EAP MS-CHAPv2 request/response */ +#define EAP_TYPE_MSCHAPV2 26 + +/** EAP MS-CHAPv2 request/response type data */ +struct eap_mschapv2 { + /** Code + * + * This is in the same namespace as the EAP header's code + * field, but is used to extend the handshake by allowing for + * "success request" and "success response" packets. + */ + uint8_t code; + /** Identifier + * + * This field serves no purposes: it always has the same value + * as the EAP header's identifier field (located 5 bytes + * earlier in the same packet). + */ + uint8_t id; + /** Length + * + * This field serves no purpose: it always has the same value + * as the EAP header's length field (located 5 bytes earlier + * in the same packet), minus the 5 byte length of the EAP + * header. + */ + uint16_t len; +} __attribute__ (( packed )); + /** EAP success */ #define EAP_CODE_SUCCESS 3 diff --git a/src/include/ipxe/errfile.h b/src/include/ipxe/errfile.h index 1768748d..662f8496 100644 --- a/src/include/ipxe/errfile.h +++ b/src/include/ipxe/errfile.h @@ -298,6 +298,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #define ERRFILE_eap ( ERRFILE_NET | 0x004b0000 ) #define ERRFILE_lldp ( ERRFILE_NET | 0x004c0000 ) #define ERRFILE_eap_md5 ( ERRFILE_NET | 0x004d0000 ) +#define ERRFILE_eap_mschapv2 ( ERRFILE_NET | 0x004e0000 ) #define ERRFILE_image ( ERRFILE_IMAGE | 0x00000000 ) #define ERRFILE_elf ( ERRFILE_IMAGE | 0x00010000 ) diff --git a/src/net/eap_mschapv2.c b/src/net/eap_mschapv2.c new file mode 100644 index 00000000..0be62ed5 --- /dev/null +++ b/src/net/eap_mschapv2.c @@ -0,0 +1,251 @@ +/* + * Copyright (C) 2024 Michael Brown . + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + * + * You can also choose to distribute this program under the terms of + * the Unmodified Binary Distribution Licence (as given in the file + * COPYING.UBDL), provided that you have satisfied its requirements. + */ + +FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); + +#include +#include +#include +#include +#include +#include + +/** @file + * + * EAP MS-CHAPv2 authentication method + * + * EAP-MSCHAPv2 was described in a draft RFC first published in 2002 + * (draft-kamath-pppext-eap-mschapv2-02.txt). The draft eventually + * expired in 2007 without becoming an official RFC, quite possibly + * because the protocol design was too ugly to be called an IETF + * standard. It is, however, fairly widely used. + */ + +/** An EAP MS-CHAPv2 request message */ +struct eap_mschapv2_request { + /** EAP-MSCHAPv2 header */ + struct eap_mschapv2 hdr; + /** MS-CHAPv2 challenge length (fixed value) */ + uint8_t len; + /** MS-CHAPv2 challenge */ + struct mschapv2_challenge msg; +} __attribute__ (( packed )); + +/** An EAP MS-CHAPv2 response message */ +struct eap_mschapv2_response { + /** EAP-MSCHAPv2 header */ + struct eap_mschapv2 hdr; + /** MS-CHAPv2 response length (fixed value) */ + uint8_t len; + /** MS-CHAPv2 response */ + struct mschapv2_response msg; + /** User name */ + char name[0]; +} __attribute__ (( packed )); + +/** An EAP MS-CHAPv2 success request message */ +struct eap_mschapv2_success_request { + /** EAP-MSCHAPv2 header */ + struct eap_mschapv2 hdr; + /** Message */ + char message[0]; +} __attribute__ (( packed )); + +/** An EAP MS-CHAPv2 success response message */ +struct eap_mschapv2_success_response { + /** Opcode */ + uint8_t code; +} __attribute__ (( packed )); + +/** + * Handle EAP MS-CHAPv2 request + * + * @v supplicant EAP supplicant + * @v hdr EAP-MSCHAPv2 header + * @v len Message length + * @ret rc Return status code + */ +static int eap_rx_mschapv2_request ( struct eap_supplicant *supplicant, + const struct eap_mschapv2 *hdr, + size_t len ) { + struct net_device *netdev = supplicant->netdev; + struct settings *settings = netdev_settings ( netdev ); + const struct eap_mschapv2_request *msreq = + container_of ( hdr, struct eap_mschapv2_request, hdr ); + struct eap_mschapv2_response *msrsp; + struct mschapv2_challenge peer; + char *username; + char *password; + int username_len; + int password_len; + size_t msrsp_len; + unsigned int i; + int rc; + + /* Sanity check */ + if ( len < sizeof ( *msreq ) ) { + DBGC ( netdev, "EAP %s underlength MS-CHAPv2 request\n", + netdev->name ); + DBGC_HDA ( netdev, 0, hdr, len ); + rc = -EINVAL; + goto err_sanity; + } + + /* Fetch username and password */ + username_len = fetch_string_setting_copy ( settings, &username_setting, + &username ); + if ( username_len < 0 ) { + rc = username_len; + DBGC ( netdev, "EAP %s has no username: %s\n", + netdev->name, strerror ( rc ) ); + goto err_username; + } + password_len = fetch_string_setting_copy ( settings, &password_setting, + &password ); + if ( password_len < 0 ) { + rc = password_len; + DBGC ( netdev, "EAP %s has no password: %s\n", + netdev->name, strerror ( rc ) ); + goto err_password; + } + + /* Construct a peer challenge. We do not perform mutual + * authentication, so this does not need to be strong. + */ + for ( i = 0 ; i < ( sizeof ( peer.byte ) / + sizeof ( peer.byte[0] ) ) ; i++ ) { + peer.byte[i] = random(); + } + + /* Allocate response */ + msrsp_len = ( sizeof ( *msrsp ) + username_len ); + msrsp = malloc ( msrsp_len ); + if ( ! msrsp ) { + rc = -ENOMEM; + goto err_alloc; + } + + /* Construct response */ + msrsp->hdr.code = EAP_CODE_RESPONSE; + msrsp->hdr.id = msreq->hdr.id; + msrsp->hdr.len = htons ( msrsp_len ); + msrsp->len = sizeof ( msrsp->msg ); + mschapv2_response ( username, password, &msreq->msg, &peer, + &msrsp->msg ); + memcpy ( msrsp->name, username, username_len ); + + /* Send response */ + if ( ( rc = eap_tx_response ( supplicant, msrsp, msrsp_len ) ) != 0 ) + goto err_tx; + + err_tx: + free ( msrsp ); + err_alloc: + free ( password ); + err_password: + free ( username ); + err_username: + err_sanity: + return rc; +} + +/** + * Handle EAP MS-CHAPv2 success request + * + * @v supplicant EAP supplicant + * @v hdr EAP-MSCHAPv2 header + * @v len Message length + * @ret rc Return status code + */ +static int eap_rx_mschapv2_success ( struct eap_supplicant *supplicant, + const struct eap_mschapv2 *hdr, + size_t len ) { + const struct eap_mschapv2_success_request *msreq = + container_of ( hdr, struct eap_mschapv2_success_request, hdr ); + static const struct eap_mschapv2_success_response msrsp = { + .code = EAP_CODE_SUCCESS, + }; + + /* Sanity check */ + assert ( len >= sizeof ( *msreq ) ); + + /* The success request contains the MS-CHAPv2 authenticator + * response, which could potentially be used to verify that + * the EAP authenticator also knew the password (or, at least, + * the MD4 hash of the password). + * + * Our model for EAP does not encompass mutual authentication: + * we will starting sending plaintext packets (e.g. DHCP + * requests) over the link even before EAP completes, and our + * only use for an EAP success is to mark the link as + * unblocked. + * + * We therefore ignore the content of the success request and + * just send back a success response, so that the EAP + * authenticator will complete the process and send through + * the real EAP success packet (which will, in turn, cause us + * to unblock the link). + */ + return eap_tx_response ( supplicant, &msrsp, sizeof ( msrsp ) ); +} + +/** + * Handle EAP MS-CHAPv2 + * + * @v supplicant EAP supplicant + * @v req Request type data + * @v req_len Length of request type data + * @ret rc Return status code + */ +static int eap_rx_mschapv2 ( struct eap_supplicant *supplicant, + const void *req, size_t req_len ) { + struct net_device *netdev = supplicant->netdev; + const struct eap_mschapv2 *hdr = req; + + /* Sanity check */ + if ( req_len < sizeof ( *hdr ) ) { + DBGC ( netdev, "EAP %s underlength MS-CHAPv2:\n", + netdev->name ); + DBGC_HDA ( netdev, 0, req, req_len ); + return -EINVAL; + } + + /* Handle according to opcode */ + switch ( hdr->code ) { + case EAP_CODE_REQUEST: + return eap_rx_mschapv2_request ( supplicant, hdr, req_len ); + case EAP_CODE_SUCCESS: + return eap_rx_mschapv2_success ( supplicant, hdr, req_len ); + default: + DBGC ( netdev, "EAP %s unsupported MS-CHAPv2 opcode %d\n", + netdev->name, hdr->code ); + DBGC_HDA ( netdev, 0, req, req_len ); + return -ENOTSUP; + } +} + +/** EAP MS-CHAPv2 method */ +struct eap_method eap_mschapv2_method __eap_method = { + .type = EAP_TYPE_MSCHAPV2, + .rx = eap_rx_mschapv2, +}; -- cgit v1.2.3-55-g7522 From 182ee909313fc60875d3f1741cd4a0bb7dfd15e1 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Tue, 27 Feb 2024 13:34:17 +0000 Subject: [efi] Work around broken boot services table manipulation by UEFI shim The UEFI shim installs wrappers around several boot services functions before invoking its next stage bootloader, in an attempt to enforce its desired behaviour upon the aforementioned bootloader. For example, shim checks that the bootloader has either invoked StartImage() or has called into the "shim lock protocol" before allowing an ExitBootServices() call to proceed. When invoking a shim, iPXE will also install boot services function wrappers in order to work around assorted bugs in the UEFI shim code that would otherwise prevent it from being used to boot a kernel. For details on these workarounds, see commits 28184b7 ("[efi] Add support for executing images via a shim") and 5b43181 ("[efi] Support versions of shim that perform SBAT verification"). Using boot services function wrappers in this way is not intrinsically problematic, provided that wrappers are installed before starting the wrapped program, and uninstalled only after the wrapped program exits. This strict ordering requirement ensures that all layers of wrappers are called in the expected order, and that no calls are issued through a no-longer-valid function pointer. Unfortunately, the UEFI shim does not respect this strict ordering requirement, and will instead uninstall (and reinstall) its wrappers midway through the execution of the wrapped program. This leaves the wrapped program with an inconsistent view of the boot services table, leading to incorrect behaviour. This results in a boot failure when a first shim is used to boot iPXE, which then uses a second shim to boot a Linux kernel: - First shim installs StartImage() and ExitBootServices() wrappers - First shim invokes iPXE via its own PE loader - iPXE installs ExitBootServices() wrapper - iPXE invokes second shim via StartImage() At this point, the first shim's StartImage() wrapper will illegally uninstall its ExitBootServices() wrapper, without first checking that nothing else has modified the ExitBootServices function pointer. This effectively bypasses iPXE's own ExitBootServices() wrapper, which causes a boot failure since the code within that wrapper does not get called. A proper fix would be for shim to install its wrappers before starting the image and uninstall its wrappers only after the started image has exited. Instead of repeatedly uninstalling and reinstalling its wrappers while the wrapped program is running, shim should simply use a flag to keep track of whether or not it needs to modify the behaviour of the wrapped calls. Experience shows that there is unfortunately no point in trying to get a fix for this upstreamed into shim. We therefore work around the shim bug by removing our ExitBootServices() wrapper and moving the relevant code into our GetMemoryMap() wrapper. Signed-off-by: Michael Brown --- src/interface/efi/efi_shim.c | 92 +++++++++++++++++++++----------------------- 1 file changed, 43 insertions(+), 49 deletions(-) diff --git a/src/interface/efi/efi_shim.c b/src/interface/efi/efi_shim.c index a46d79d0..d5419512 100644 --- a/src/interface/efi/efi_shim.c +++ b/src/interface/efi/efi_shim.c @@ -112,9 +112,6 @@ struct image_tag efi_shim __image_tag = { /** Original GetMemoryMap() function */ static EFI_GET_MEMORY_MAP efi_shim_orig_get_memory_map; -/** Original ExitBootServices() function */ -static EFI_EXIT_BOOT_SERVICES efi_shim_orig_exit_boot_services; - /** Original SetVariable() function */ static EFI_SET_VARIABLE efi_shim_orig_set_variable; @@ -160,49 +157,6 @@ static void efi_shim_unlock ( void ) { } } -/** - * Wrap GetMemoryMap() - * - * @v len Memory map size - * @v map Memory map - * @v key Memory map key - * @v desclen Descriptor size - * @v descver Descriptor version - * @ret efirc EFI status code - */ -static EFIAPI EFI_STATUS efi_shim_get_memory_map ( UINTN *len, - EFI_MEMORY_DESCRIPTOR *map, - UINTN *key, UINTN *desclen, - UINT32 *descver ) { - - /* Unlock shim */ - if ( ! efi_shim_require_loader ) - efi_shim_unlock(); - - /* Hand off to original GetMemoryMap() */ - return efi_shim_orig_get_memory_map ( len, map, key, desclen, - descver ); -} - -/** - * Wrap ExitBootServices() - * - * @v handle Image handle - * @v key Memory map key - * @ret efirc EFI status code - */ -static EFIAPI EFI_STATUS efi_shim_exit_boot_services ( EFI_HANDLE handle, - UINTN key ) { - EFI_RUNTIME_SERVICES *rs = efi_systab->RuntimeServices; - - /* Restore original runtime services functions */ - rs->SetVariable = efi_shim_orig_set_variable; - rs->GetVariable = efi_shim_orig_get_variable; - - /* Hand off to original ExitBootServices() */ - return efi_shim_orig_exit_boot_services ( handle, key ); -} - /** * Wrap SetVariable() * @@ -270,6 +224,47 @@ efi_shim_get_variable ( CHAR16 *name, EFI_GUID *guid, UINT32 *attrs, return efirc; } +/** + * Wrap GetMemoryMap() + * + * @v len Memory map size + * @v map Memory map + * @v key Memory map key + * @v desclen Descriptor size + * @v descver Descriptor version + * @ret efirc EFI status code + */ +static EFIAPI EFI_STATUS efi_shim_get_memory_map ( UINTN *len, + EFI_MEMORY_DESCRIPTOR *map, + UINTN *key, UINTN *desclen, + UINT32 *descver ) { + EFI_RUNTIME_SERVICES *rs = efi_systab->RuntimeServices; + + /* Unlock shim */ + if ( ! efi_shim_require_loader ) + efi_shim_unlock(); + + /* Uninstall runtime services wrappers, if still installed */ + if ( rs->SetVariable == efi_shim_set_variable ) { + rs->SetVariable = efi_shim_orig_set_variable; + DBGC ( &efi_shim, "SHIM uninstalled SetVariable() wrapper\n" ); + } else if ( rs->SetVariable != efi_shim_orig_set_variable ) { + DBGC ( &efi_shim, "SHIM could not uninstall SetVariable() " + "wrapper!\n" ); + } + if ( rs->GetVariable == efi_shim_get_variable ) { + rs->GetVariable = efi_shim_orig_get_variable; + DBGC ( &efi_shim, "SHIM uninstalled GetVariable() wrapper\n" ); + } else if ( rs->GetVariable != efi_shim_orig_get_variable ) { + DBGC ( &efi_shim, "SHIM could not uninstall GetVariable() " + "wrapper!\n" ); + } + + /* Hand off to original GetMemoryMap() */ + return efi_shim_orig_get_memory_map ( len, map, key, desclen, + descver ); +} + /** * Inhibit use of PXE base code * @@ -373,15 +368,14 @@ int efi_shim_install ( struct image *shim, EFI_HANDLE handle, /* Record original boot and runtime services functions */ efi_shim_orig_get_memory_map = bs->GetMemoryMap; - efi_shim_orig_exit_boot_services = bs->ExitBootServices; efi_shim_orig_set_variable = rs->SetVariable; efi_shim_orig_get_variable = rs->GetVariable; /* Wrap relevant boot and runtime services functions */ bs->GetMemoryMap = efi_shim_get_memory_map; - bs->ExitBootServices = efi_shim_exit_boot_services; rs->SetVariable = efi_shim_set_variable; rs->GetVariable = efi_shim_get_variable; + DBGC ( &efi_shim, "SHIM installed wrappers\n" ); return 0; } @@ -396,7 +390,7 @@ void efi_shim_uninstall ( void ) { /* Restore original boot and runtime services functions */ bs->GetMemoryMap = efi_shim_orig_get_memory_map; - bs->ExitBootServices = efi_shim_orig_exit_boot_services; rs->SetVariable = efi_shim_orig_set_variable; rs->GetVariable = efi_shim_orig_get_variable; + DBGC ( &efi_shim, "SHIM uninstalled wrappers\n" ); } -- cgit v1.2.3-55-g7522 From da7b2662890dfb284786f37237a6c92809eee217 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Thu, 29 Feb 2024 13:58:50 +0000 Subject: [uuid] Add uuid_aton() to parse a UUID from a string Add uuid_aton() to parse a UUID value from a string (analogous to inet_aton(), inet6_aton(), sock_aton(), etc), treating it as a 32-digit hex string with optional hyphen separators. The placement of the separators is not checked: each byte within the hex string may be separated by a hyphen, or not separated at all. Add dedicated self-tests for UUID parsing and formatting (already partially covered by the ":uuid" and ":guid" settings self-tests). Signed-off-by: Michael Brown --- src/core/base16.c | 15 ++++- src/core/uuid.c | 28 ++++++++ src/include/ipxe/base16.h | 3 + src/include/ipxe/errfile.h | 1 + src/include/ipxe/uuid.h | 1 + src/tests/tests.c | 1 + src/tests/uuid_test.c | 156 +++++++++++++++++++++++++++++++++++++++++++++ 7 files changed, 203 insertions(+), 2 deletions(-) create mode 100644 src/tests/uuid_test.c diff --git a/src/core/base16.c b/src/core/base16.c index f9e0f336..47e35f41 100644 --- a/src/core/base16.c +++ b/src/core/base16.c @@ -78,12 +78,23 @@ int hex_decode ( char separator, const char *encoded, void *data, size_t len ) { unsigned int count = 0; unsigned int sixteens; unsigned int units; + int optional; + /* Strip out optionality flag from separator character */ + optional = ( separator & HEX_DECODE_OPTIONAL ); + separator &= ~HEX_DECODE_OPTIONAL; + + /* Decode string */ while ( *encoded ) { /* Check separator, if applicable */ - if ( count && separator && ( ( *(encoded++) != separator ) ) ) - return -EINVAL; + if ( count && separator ) { + if ( *encoded == separator ) { + encoded++; + } else if ( ! optional ) { + return -EINVAL; + } + } /* Extract digits. Note that either digit may be NUL, * which would be interpreted as an invalid value by diff --git a/src/core/uuid.c b/src/core/uuid.c index c43d4216..b6600af7 100644 --- a/src/core/uuid.c +++ b/src/core/uuid.c @@ -25,7 +25,9 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #include #include +#include #include +#include #include /** @file @@ -53,3 +55,29 @@ const char * uuid_ntoa ( const union uuid *uuid ) { uuid->canonical.e[4], uuid->canonical.e[5] ); return buf; } + +/** + * Parse UUID + * + * @v string UUID string + * @v uuid UUID to fill in + * @ret rc Return status code + */ +int uuid_aton ( const char *string, union uuid *uuid ) { + int len; + int rc; + + /* Decode as hex string with optional '-' separator */ + len = hex_decode ( ( '-' | HEX_DECODE_OPTIONAL ), string, uuid->raw, + sizeof ( *uuid ) ); + if ( len < 0 ) { + rc = len; + return rc; + } + + /* Check length */ + if ( len != sizeof ( *uuid ) ) + return -EINVAL; + + return 0; +} diff --git a/src/include/ipxe/base16.h b/src/include/ipxe/base16.h index 8c44da17..c9e430e7 100644 --- a/src/include/ipxe/base16.h +++ b/src/include/ipxe/base16.h @@ -12,6 +12,9 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #include #include +/** Treat separator as optional while decoding */ +#define HEX_DECODE_OPTIONAL 0x80 + /** * Calculate length of base16-encoded data * diff --git a/src/include/ipxe/errfile.h b/src/include/ipxe/errfile.h index 662f8496..7cff594d 100644 --- a/src/include/ipxe/errfile.h +++ b/src/include/ipxe/errfile.h @@ -79,6 +79,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #define ERRFILE_cachedhcp ( ERRFILE_CORE | 0x00270000 ) #define ERRFILE_acpimac ( ERRFILE_CORE | 0x00280000 ) #define ERRFILE_efi_strings ( ERRFILE_CORE | 0x00290000 ) +#define ERRFILE_uuid ( ERRFILE_CORE | 0x002a0000 ) #define ERRFILE_eisa ( ERRFILE_DRIVER | 0x00000000 ) #define ERRFILE_isa ( ERRFILE_DRIVER | 0x00010000 ) diff --git a/src/include/ipxe/uuid.h b/src/include/ipxe/uuid.h index 24c46aca..4874b738 100644 --- a/src/include/ipxe/uuid.h +++ b/src/include/ipxe/uuid.h @@ -48,5 +48,6 @@ static inline void uuid_mangle ( union uuid *uuid ) { } extern const char * uuid_ntoa ( const union uuid *uuid ); +extern int uuid_aton ( const char *string, union uuid *uuid ); #endif /* _IPXE_UUID_H */ diff --git a/src/tests/tests.c b/src/tests/tests.c index 90cec948..cb296049 100644 --- a/src/tests/tests.c +++ b/src/tests/tests.c @@ -84,3 +84,4 @@ REQUIRE_OBJECT ( nap_test ); REQUIRE_OBJECT ( x25519_test ); REQUIRE_OBJECT ( des_test ); REQUIRE_OBJECT ( mschapv2_test ); +REQUIRE_OBJECT ( uuid_test ); diff --git a/src/tests/uuid_test.c b/src/tests/uuid_test.c new file mode 100644 index 00000000..42dc5264 --- /dev/null +++ b/src/tests/uuid_test.c @@ -0,0 +1,156 @@ +/* + * Copyright (C) 2024 Michael Brown . + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + * + * You can also choose to distribute this program under the terms of + * the Unmodified Binary Distribution Licence (as given in the file + * COPYING.UBDL), provided that you have satisfied its requirements. + */ + +FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); + +/** @file + * + * UUID tests + * + */ + +/* Forcibly enable assertions */ +#undef NDEBUG + +#include +#include +#include +#include + +/** Define an inline UUID value */ +#define UUID( A, B, C, D, E0, E1, E2, E3, E4, E5 ) { \ + .a = htonl ( A ), \ + .b = htons ( B ), \ + .c = htons ( C ), \ + .d = htons ( D ), \ + .e = { E0, E1, E2, E3, E4, E5 }, \ + } + +/** + * Report a uuid_ntoa() test result + * + * @v uuid UUID + * @v text Expected textual representation + * @v file Test code file + * @v line Test code line + */ +static void uuid_ntoa_okx ( const union uuid *uuid, const char *text, + const char *file, unsigned int line ) { + const char *actual; + + /* Format address */ + actual = uuid_ntoa ( uuid ); + DBG ( "uuid_ntoa ( %08x-%04x-%04x-%04x-%02x%02x%02x%02x%02x%02x ) = " + "\"%s\"\n", ntohl ( uuid->canonical.a ), + ntohs ( uuid->canonical.b ), ntohs ( uuid->canonical.c ), + ntohs ( uuid->canonical.d ), uuid->canonical.e[0], + uuid->canonical.e[1], uuid->canonical.e[2], uuid->canonical.e[3], + uuid->canonical.e[4], uuid->canonical.e[5], actual ); + okx ( strcmp ( actual, text ) == 0, file, line ); +} +#define uuid_ntoa_ok( value, text ) do { \ + static const union uuid uuid = { \ + .canonical = value, \ + }; \ + uuid_ntoa_okx ( &uuid, text, __FILE__, __LINE__ ); \ + } while ( 0 ) + +/** + * Report a uuid_aton() test result + * + * @v text Textual representation + * @v uuid Expected UUID + * @v file Test code file + * @v line Test code line + */ +static void uuid_aton_okx ( const char *text, const union uuid *uuid, + const char *file, unsigned int line ) { + union uuid actual; + + /* Parse address */ + okx ( uuid_aton ( text, &actual ) == 0, file, line ); + DBG ( "uuid_aton ( \"%s\" ) = %s\n", text, uuid_ntoa ( &actual ) ); + okx ( memcmp ( &actual, uuid, sizeof ( actual ) ) == 0, file, line ); +}; +#define uuid_aton_ok( text, value ) do { \ + static const union uuid uuid = { \ + .canonical = value, \ + }; \ + uuid_aton_okx ( text, &uuid, __FILE__, __LINE__ ); \ + } while ( 0 ) + +/** + * Report a uuid_aton() failure test result + * + * @v text Textual representation + * @v file Test code file + * @v line Test code line + */ +static void uuid_aton_fail_okx ( const char *text, const char *file, + unsigned int line ) { + union uuid actual; + + /* Attempt to parse address */ + okx ( uuid_aton ( text, &actual ) != 0, file, line ); +} +#define uuid_aton_fail_ok( text ) \ + uuid_aton_fail_okx ( text, __FILE__, __LINE__ ) + +/** + * Perform UUID self-tests + * + */ +static void uuid_test_exec ( void ) { + + /* uuid_ntoa() tests */ + uuid_ntoa_ok ( UUID ( 0x18725ca6, 0xd699, 0x4e4d, 0xb501, + 0xc3, 0x80, 0x91, 0xd2, 0xa4, 0x33 ), + "18725ca6-d699-4e4d-b501-c38091d2a433" ); + uuid_ntoa_ok ( UUID ( 0x1a969b23, 0xc7d5, 0x40fe, 0xb79a, + 0xc9, 0x2e, 0xa3, 0x4a ,0xb4, 0x5b ), + "1a969b23-c7d5-40fe-b79a-c92ea34ab45b" ); + + /* uuid_aton() tests */ + uuid_aton_ok ( "62b907a8-e1a7-460e-82f7-667d84270c84", + UUID ( 0x62b907a8, 0xe1a7, 0x460e, 0x82f7, + 0x66, 0x7d, 0x84, 0x27, 0x0c, 0x84 ) ); + uuid_aton_ok ( "F5D0349C-EF7C-4AD4-B40B-FC2E522A7327", + UUID ( 0xf5d0349c, 0xef7c, 0x4ad4, 0xb40b, + 0xfc, 0x2e, 0x52, 0x2a, 0x73, 0x27 ) ); + uuid_aton_ok ( "4edd80ff7b43465589a02b1e7cffa196", + UUID ( 0x4edd80ff, 0x7b43, 0x4655, 0x89a0, + 0x2b, 0x1e, 0x7c, 0xff, 0xa1, 0x96 ) ); + + /* uuid_aton() failure tests */ + uuid_aton_fail_ok ( "628d677b-cf38-471e-9ad9-c8a5d9220055b6" ); + uuid_aton_fail_ok ( "5071ca26-fc5f-4580-887a-46d9a103e4" ); + uuid_aton_fail_ok ( "453aee96:0fb5-4aeb-aecd-d060b2121218" ); + uuid_aton_fail_ok ( "1ccb524a-b8b9-4b17-x5e2-7996867edc7d" ); + uuid_aton_fail_ok ( "" ); +} + +/** UUID self-test */ +struct self_test uuid_test __self_test = { + .name = "uuid", + .exec = uuid_test_exec, +}; -- cgit v1.2.3-55-g7522 From 0eb8fbd0bfc9331ecdcd74c9406251e5a6e450af Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Thu, 29 Feb 2024 14:04:47 +0000 Subject: [settings] Add parsing for UUID and GUID settings types The ":uuid" and ":guid" settings types are currently format-only: it is possible to format a setting as a UUID (via e.g. "show foo:uuid") but it is not currently possible to parse a string into a UUID setting (via e.g. "set foo:uuid 406343fe-998b-44be-8a28-44ca38cb202b"). Use uuid_aton() to implement parsing of these settings types, and add appropriate test cases for both. Signed-off-by: Michael Brown --- src/core/settings.c | 33 +++++++++++++++++++++++++++++++++ src/tests/settings_test.c | 14 +++++++++++--- 2 files changed, 44 insertions(+), 3 deletions(-) diff --git a/src/core/settings.c b/src/core/settings.c index da075baa..4593876f 100644 --- a/src/core/settings.c +++ b/src/core/settings.c @@ -2194,6 +2194,37 @@ const struct setting_type setting_type_base64 __setting_type = { .format = format_base64_setting, }; +/** + * Parse UUID/GUID setting value + * + * @v type Setting type + * @v value Formatted setting value + * @v buf Buffer to contain raw value + * @v len Length of buffer + * @v size Integer size, in bytes + * @ret len Length of raw value, or negative error + */ +static int parse_uuid_setting ( const struct setting_type *type, + const char *value, void *buf, size_t len ) { + union uuid uuid; + int rc; + + /* Parse UUID */ + if ( ( rc = uuid_aton ( value, &uuid ) ) != 0 ) + return rc; + + /* Mangle GUID byte ordering */ + if ( type == &setting_type_guid ) + uuid_mangle ( &uuid ); + + /* Copy value */ + if ( len > sizeof ( uuid ) ) + len = sizeof ( uuid ); + memcpy ( buf, uuid.raw, len ); + + return ( sizeof ( uuid ) ); +} + /** * Format UUID/GUID setting value * @@ -2227,12 +2258,14 @@ static int format_uuid_setting ( const struct setting_type *type, /** UUID setting type */ const struct setting_type setting_type_uuid __setting_type = { .name = "uuid", + .parse = parse_uuid_setting, .format = format_uuid_setting, }; /** GUID setting type */ const struct setting_type setting_type_guid __setting_type = { .name = "guid", + .parse = parse_uuid_setting, .format = format_uuid_setting, }; diff --git a/src/tests/settings_test.c b/src/tests/settings_test.c index 5da7eb00..edd7b9d7 100644 --- a/src/tests/settings_test.c +++ b/src/tests/settings_test.c @@ -420,13 +420,21 @@ static void settings_test_exec ( void ) { RAW ( 0x80, 0x81, 0x82, 0x83, 0x84, 0x00, 0xff ), "gIGCg4QA/w==" ); - /* "uuid" setting type (no store capability) */ + /* "uuid" setting type */ + storef_ok ( &test_settings, &test_uuid_setting, + "36d22ed9-b64f-4fdb-941b-a54a0854f991", + RAW ( 0x36, 0xd2, 0x2e, 0xd9, 0xb6, 0x4f, 0x4f, 0xdb, 0x94, + 0x1b, 0xa5, 0x4a, 0x08, 0x54, 0xf9, 0x91 ) ); + storef_ok ( &test_settings, &test_guid_setting, + "7ad4478f-c270-4601-a245-78598f25a984", + RAW ( 0x8f, 0x47, 0xd4, 0x7a, 0x70, 0xc2, 0x01, 0x46, 0xa2, + 0x45, 0x78, 0x59, 0x8f, 0x25, 0xa9, 0x84 ) ); fetchf_ok ( &test_settings, &test_uuid_setting, - RAW ( 0x1a, 0x6a, 0x74, 0x9d, 0x0e, 0xda, 0x46, 0x1a,0xa8, + RAW ( 0x1a, 0x6a, 0x74, 0x9d, 0x0e, 0xda, 0x46, 0x1a, 0xa8, 0x7a, 0x7c, 0xfe, 0x4f, 0xca, 0x4a, 0x57 ), "1a6a749d-0eda-461a-a87a-7cfe4fca4a57" ); fetchf_ok ( &test_settings, &test_guid_setting, - RAW ( 0x1a, 0x6a, 0x74, 0x9d, 0x0e, 0xda, 0x46, 0x1a,0xa8, + RAW ( 0x1a, 0x6a, 0x74, 0x9d, 0x0e, 0xda, 0x46, 0x1a, 0xa8, 0x7a, 0x7c, 0xfe, 0x4f, 0xca, 0x4a, 0x57 ), "9d746a1a-da0e-1a46-a87a-7cfe4fca4a57" ); -- cgit v1.2.3-55-g7522 From 7cd73884e51f6d3649aa2ea0ed0cec0b39192f61 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Thu, 29 Feb 2024 14:05:39 +0000 Subject: [parseopt] Add parse_uuid() for parsing UUID command-line arguments Signed-off-by: Michael Brown --- src/core/parseopt.c | 23 +++++++++++++++++++++++ src/include/ipxe/parseopt.h | 2 ++ 2 files changed, 25 insertions(+) diff --git a/src/core/parseopt.c b/src/core/parseopt.c index cd3b3101..7aff1485 100644 --- a/src/core/parseopt.c +++ b/src/core/parseopt.c @@ -31,6 +31,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #include #include #include +#include #include #include #include @@ -124,6 +125,28 @@ int parse_timeout ( char *text, unsigned long *value ) { return 0; } +/** + * Parse UUID + * + * @v text Text + * @ret value UUID value + * @ret rc Return status code + */ +int parse_uuid ( char *text, union uuid *value ) { + int rc; + + /* Sanity check */ + assert ( text != NULL ); + + /* Parse UUID */ + if ( ( rc = uuid_aton ( text, value ) ) != 0 ) { + printf ( "\"%s\": invalid UUID\n", text ); + return rc; + } + + return 0; +} + /** * Parse network device name * diff --git a/src/include/ipxe/parseopt.h b/src/include/ipxe/parseopt.h index 829b3431..ebd18804 100644 --- a/src/include/ipxe/parseopt.h +++ b/src/include/ipxe/parseopt.h @@ -11,6 +11,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #include #include +#include #include struct net_device; @@ -128,6 +129,7 @@ struct named_setting { extern int parse_string ( char *text, char **value ); extern int parse_integer ( char *text, unsigned int *value ); extern int parse_timeout ( char *text, unsigned long *value ); +extern int parse_uuid ( char *text, union uuid *value ); extern int parse_netdev ( char *text, struct net_device **netdev ); extern int parse_netdev_configurator ( char *text, -- cgit v1.2.3-55-g7522 From 1b23d4de25d1dacf164eec442780bbfb026fbda7 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Mon, 4 Mar 2024 12:08:01 +0000 Subject: [efi] Use long forms of device paths in debug messages We currently call ConvertDevicePathToText() with DisplayOnly=TRUE when constructing a device path to appear within a debug message. For ATAPI device paths, this will unfortunately omit some key information: the textual representation will not indicate which ATA bus or drive is represented. This can lead to misleading debug messages that appear to refer to identical devices. Fix by setting DisplayOnly=FALSE to select the long form of device path textual representations. Signed-off-by: Michael Brown --- src/interface/efi/efi_debug.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/interface/efi/efi_debug.c b/src/interface/efi/efi_debug.c index ad79f0d3..52efebe5 100644 --- a/src/interface/efi/efi_debug.c +++ b/src/interface/efi/efi_debug.c @@ -479,7 +479,7 @@ efi_devpath_text ( EFI_DEVICE_PATH_PROTOCOL *path ) { } /* Convert path to a textual representation */ - wtext = efidpt->ConvertDevicePathToText ( path, TRUE, FALSE ); + wtext = efidpt->ConvertDevicePathToText ( path, FALSE, FALSE ); if ( ! wtext ) return NULL; -- cgit v1.2.3-55-g7522 From 75c7904482b5397c41b4a91ce266f25a8a196e13 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Mon, 4 Mar 2024 12:50:25 +0000 Subject: [block] Use drive number as debug message stream ID We currently use the SAN device pointer as the debug message stream identifier. This pointer is not always available: for example, when booting from a local disk there is no underlying SAN device. Switch to using the drive number as the debug message colour stream identifier, so that all block device debug messages may be colourised consistently. Signed-off-by: Michael Brown --- src/arch/x86/interface/pcbios/int13.c | 210 ++++++++++++++++++---------------- src/core/dummy_sanboot.c | 4 +- src/core/sanboot.c | 43 +++---- src/interface/efi/efi_block.c | 82 +++++++------ 4 files changed, 173 insertions(+), 166 deletions(-) diff --git a/src/arch/x86/interface/pcbios/int13.c b/src/arch/x86/interface/pcbios/int13.c index d6c4d7eb..2c5e8624 100644 --- a/src/arch/x86/interface/pcbios/int13.c +++ b/src/arch/x86/interface/pcbios/int13.c @@ -183,8 +183,8 @@ static int int13_parse_eltorito ( struct san_device *sandev, void *scratch ) { /* Read boot record volume descriptor */ if ( ( rc = sandev_read ( sandev, ELTORITO_LBA, 1, virt_to_user ( boot ) ) ) != 0 ) { - DBGC ( sandev, "INT13 drive %02x could not read El Torito boot " - "record volume descriptor: %s\n", + DBGC ( sandev->drive, "INT13 drive %02x could not read El " + "Torito boot record volume descriptor: %s\n", sandev->drive, strerror ( rc ) ); return rc; } @@ -192,10 +192,11 @@ static int int13_parse_eltorito ( struct san_device *sandev, void *scratch ) { /* Check for an El Torito boot catalog */ if ( memcmp ( boot, &boot_check, sizeof ( boot_check ) ) == 0 ) { int13->boot_catalog = boot->sector; - DBGC ( sandev, "INT13 drive %02x has an El Torito boot catalog " - "at LBA %08x\n", sandev->drive, int13->boot_catalog ); + DBGC ( sandev->drive, "INT13 drive %02x has an El Torito boot " + "catalog at LBA %08x\n", sandev->drive, + int13->boot_catalog ); } else { - DBGC ( sandev, "INT13 drive %02x has no El Torito boot " + DBGC ( sandev->drive, "INT13 drive %02x has no El Torito boot " "catalog\n", sandev->drive ); } @@ -228,14 +229,14 @@ static int int13_guess_geometry_hdd ( struct san_device *sandev, void *scratch, /* Read partition table */ if ( ( rc = sandev_read ( sandev, 0, 1, virt_to_user ( mbr ) ) ) != 0 ) { - DBGC ( sandev, "INT13 drive %02x could not read " + DBGC ( sandev->drive, "INT13 drive %02x could not read " "partition table to guess geometry: %s\n", sandev->drive, strerror ( rc ) ); return rc; } - DBGC2 ( sandev, "INT13 drive %02x has MBR:\n", sandev->drive ); - DBGC2_HDA ( sandev, 0, mbr, sizeof ( *mbr ) ); - DBGC ( sandev, "INT13 drive %02x has signature %08x\n", + DBGC2 ( sandev->drive, "INT13 drive %02x has MBR:\n", sandev->drive ); + DBGC2_HDA ( sandev->drive, 0, mbr, sizeof ( *mbr ) ); + DBGC ( sandev->drive, "INT13 drive %02x has signature %08x\n", sandev->drive, mbr->signature ); /* Scan through partition table and modify guesses for @@ -260,8 +261,8 @@ static int int13_guess_geometry_hdd ( struct san_device *sandev, void *scratch, if ( ( start_cylinder == 0 ) && ( start_head != 0 ) ) { *sectors = ( ( partition->start + 1 - start_sector ) / start_head ); - DBGC ( sandev, "INT13 drive %02x guessing C/H/S " - "xx/xx/%d based on partition %d\n", + DBGC ( sandev->drive, "INT13 drive %02x guessing " + "C/H/S xx/xx/%d based on partition %d\n", sandev->drive, *sectors, ( i + 1 ) ); } @@ -272,14 +273,14 @@ static int int13_guess_geometry_hdd ( struct san_device *sandev, void *scratch, end_sector = PART_SECTOR ( partition->chs_end ); if ( ( end_head + 1 ) > *heads ) { *heads = ( end_head + 1 ); - DBGC ( sandev, "INT13 drive %02x guessing C/H/S " - "xx/%d/xx based on partition %d\n", + DBGC ( sandev->drive, "INT13 drive %02x guessing " + "C/H/S xx/%d/xx based on partition %d\n", sandev->drive, *heads, ( i + 1 ) ); } if ( end_sector > *sectors ) { *sectors = end_sector; - DBGC ( sandev, "INT13 drive %02x guessing C/H/S " - "xx/xx/%d based on partition %d\n", + DBGC ( sandev->drive, "INT13 drive %02x guessing " + "C/H/S xx/xx/%d based on partition %d\n", sandev->drive, *sectors, ( i + 1 ) ); } } @@ -343,9 +344,10 @@ static int int13_guess_geometry_fdd ( struct san_device *sandev, *heads = INT13_FDD_HEADS ( geometry ); *sectors = INT13_FDD_SECTORS ( geometry ); if ( ( cylinders * (*heads) * (*sectors) ) == blocks ) { - DBGC ( sandev, "INT13 drive %02x guessing C/H/S " - "%d/%d/%d based on size %dK\n", sandev->drive, - cylinders, *heads, *sectors, ( blocks / 2 ) ); + DBGC ( sandev->drive, "INT13 drive %02x guessing " + "C/H/S %d/%d/%d based on size %dK\n", + sandev->drive, cylinders, *heads, *sectors, + ( blocks / 2 ) ); return 0; } } @@ -355,8 +357,9 @@ static int int13_guess_geometry_fdd ( struct san_device *sandev, */ *heads = 2; *sectors = 18; - DBGC ( sandev, "INT13 drive %02x guessing C/H/S xx/%d/%d based on size " - "%dK\n", sandev->drive, *heads, *sectors, ( blocks / 2 ) ); + DBGC ( sandev->drive, "INT13 drive %02x guessing C/H/S xx/%d/%d " + "based on size %dK\n", sandev->drive, *heads, *sectors, + ( blocks / 2 ) ); return 0; } @@ -431,8 +434,8 @@ static void int13_sync_num_drives ( void ) { required = ( ( max_drive & 0x7f ) + 1 ); if ( *counter < required ) { *counter = required; - DBGC ( sandev, "INT13 drive %02x added to drive count: " - "%d HDDs, %d FDDs\n", + DBGC ( sandev->drive, "INT13 drive %02x added to " + "drive count: %d HDDs, %d FDDs\n", sandev->drive, num_drives, num_fdds ); } } @@ -472,7 +475,7 @@ static int int13_reset ( struct san_device *sandev, struct i386_all_regs *ix86 __unused ) { int rc; - DBGC2 ( sandev, "Reset drive\n" ); + DBGC2 ( sandev->drive, "Reset drive\n" ); /* Reset SAN device */ if ( ( rc = sandev_reset ( sandev ) ) != 0 ) @@ -491,7 +494,7 @@ static int int13_get_last_status ( struct san_device *sandev, struct i386_all_regs *ix86 __unused ) { struct int13_data *int13 = sandev->priv; - DBGC2 ( sandev, "Get status of last operation\n" ); + DBGC2 ( sandev->drive, "Get status of last operation\n" ); return int13->last_status; } @@ -524,8 +527,8 @@ static int int13_rw_sectors ( struct san_device *sandev, /* Validate blocksize */ if ( sandev_blksize ( sandev ) != INT13_BLKSIZE ) { - DBGC ( sandev, "\nINT 13 drive %02x invalid blocksize (%zd) " - "for non-extended read/write\n", + DBGC ( sandev->drive, "\nINT 13 drive %02x invalid blocksize " + "(%zd) for non-extended read/write\n", sandev->drive, sandev_blksize ( sandev ) ); return -INT13_STATUS_INVALID; } @@ -537,9 +540,10 @@ static int int13_rw_sectors ( struct san_device *sandev, if ( ( cylinder >= int13->cylinders ) || ( head >= int13->heads ) || ( sector < 1 ) || ( sector > int13->sectors_per_track ) ) { - DBGC ( sandev, "C/H/S %d/%d/%d out of range for geometry " - "%d/%d/%d\n", cylinder, head, sector, int13->cylinders, - int13->heads, int13->sectors_per_track ); + DBGC ( sandev->drive, "C/H/S %d/%d/%d out of range for " + "geometry %d/%d/%d\n", cylinder, head, sector, + int13->cylinders, int13->heads, + int13->sectors_per_track ); return -INT13_STATUS_INVALID; } lba = ( ( ( ( cylinder * int13->heads ) + head ) @@ -547,13 +551,13 @@ static int int13_rw_sectors ( struct san_device *sandev, count = ix86->regs.al; buffer = real_to_user ( ix86->segs.es, ix86->regs.bx ); - DBGC2 ( sandev, "C/H/S %d/%d/%d = LBA %08lx <-> %04x:%04x (count %d)\n", - cylinder, head, sector, lba, ix86->segs.es, ix86->regs.bx, - count ); + DBGC2 ( sandev->drive, "C/H/S %d/%d/%d = LBA %08lx <-> %04x:%04x " + "(count %d)\n", cylinder, head, sector, lba, ix86->segs.es, + ix86->regs.bx, count ); /* Read from / write to block device */ if ( ( rc = sandev_rw ( sandev, lba, count, buffer ) ) != 0 ){ - DBGC ( sandev, "INT13 drive %02x I/O failed: %s\n", + DBGC ( sandev->drive, "INT13 drive %02x I/O failed: %s\n", sandev->drive, strerror ( rc ) ); return -INT13_STATUS_READ_ERROR; } @@ -577,7 +581,7 @@ static int int13_rw_sectors ( struct san_device *sandev, static int int13_read_sectors ( struct san_device *sandev, struct i386_all_regs *ix86 ) { - DBGC2 ( sandev, "Read: " ); + DBGC2 ( sandev->drive, "Read: " ); return int13_rw_sectors ( sandev, ix86, sandev_read ); } @@ -597,7 +601,7 @@ static int int13_read_sectors ( struct san_device *sandev, static int int13_write_sectors ( struct san_device *sandev, struct i386_all_regs *ix86 ) { - DBGC2 ( sandev, "Write: " ); + DBGC2 ( sandev->drive, "Write: " ); return int13_rw_sectors ( sandev, ix86, sandev_write ); } @@ -619,12 +623,12 @@ static int int13_get_parameters ( struct san_device *sandev, unsigned int max_head = int13->heads - 1; unsigned int max_sector = int13->sectors_per_track; /* sic */ - DBGC2 ( sandev, "Get drive parameters\n" ); + DBGC2 ( sandev->drive, "Get drive parameters\n" ); /* Validate blocksize */ if ( sandev_blksize ( sandev ) != INT13_BLKSIZE ) { - DBGC ( sandev, "\nINT 13 drive %02x invalid blocksize (%zd) " - "for non-extended parameters\n", + DBGC ( sandev->drive, "\nINT 13 drive %02x invalid blocksize " + "(%zd) for non-extended parameters\n", sandev->drive, sandev_blksize ( sandev ) ); return -INT13_STATUS_INVALID; } @@ -657,7 +661,7 @@ static int int13_get_disk_type ( struct san_device *sandev, struct i386_all_regs *ix86 ) { uint32_t blocks; - DBGC2 ( sandev, "Get disk type\n" ); + DBGC2 ( sandev->drive, "Get disk type\n" ); if ( int13_is_fdd ( sandev ) ) { return INT13_DISK_TYPE_FDD; @@ -682,7 +686,7 @@ static int int13_extension_check ( struct san_device *sandev, struct i386_all_regs *ix86 ) { if ( ( ix86->regs.bx == 0x55aa ) && ! int13_is_fdd ( sandev ) ) { - DBGC2 ( sandev, "INT13 extensions installation check\n" ); + DBGC2 ( sandev->drive, "INT13 extensions check\n" ); ix86->regs.bx = 0xaa55; ix86->regs.cx = ( INT13_EXTENSION_LINEAR | INT13_EXTENSION_EDD | @@ -725,7 +729,8 @@ static int int13_extended_rw ( struct san_device *sandev, get_real ( bufsize, ix86->segs.ds, ( ix86->regs.si + offsetof ( typeof ( addr ), bufsize ) ) ); if ( bufsize < offsetof ( typeof ( addr ), buffer_phys ) ) { - DBGC2 ( sandev, "\n", bufsize ); + DBGC2 ( sandev->drive, "\n", + bufsize ); return -INT13_STATUS_INVALID; } @@ -733,17 +738,18 @@ static int int13_extended_rw ( struct san_device *sandev, memset ( &addr, 0, sizeof ( addr ) ); copy_from_real ( &addr, ix86->segs.ds, ix86->regs.si, bufsize ); lba = addr.lba; - DBGC2 ( sandev, "LBA %08llx <-> ", ( ( unsigned long long ) lba ) ); + DBGC2 ( sandev->drive, "LBA %08llx <-> ", + ( ( unsigned long long ) lba ) ); if ( ( addr.count == 0xff ) || ( ( addr.buffer.segment == 0xffff ) && ( addr.buffer.offset == 0xffff ) ) ) { buffer = phys_to_user ( addr.buffer_phys ); - DBGC2 ( sandev, "%08llx", + DBGC2 ( sandev->drive, "%08llx", ( ( unsigned long long ) addr.buffer_phys ) ); } else { buffer = real_to_user ( addr.buffer.segment, addr.buffer.offset ); - DBGC2 ( sandev, "%04x:%04x", addr.buffer.segment, + DBGC2 ( sandev->drive, "%04x:%04x", addr.buffer.segment, addr.buffer.offset ); } if ( addr.count <= 0x7f ) { @@ -751,15 +757,15 @@ static int int13_extended_rw ( struct san_device *sandev, } else if ( addr.count == 0xff ) { count = addr.long_count; } else { - DBGC2 ( sandev, " \n", addr.count ); + DBGC2 ( sandev->drive, " \n", addr.count ); return -INT13_STATUS_INVALID; } - DBGC2 ( sandev, " (count %ld)\n", count ); + DBGC2 ( sandev->drive, " (count %ld)\n", count ); /* Read from / write to block device */ if ( ( rc = sandev_rw ( sandev, lba, count, buffer ) ) != 0 ) { - DBGC ( sandev, "INT13 drive %02x extended I/O failed: %s\n", - sandev->drive, strerror ( rc ) ); + DBGC ( sandev->drive, "INT13 drive %02x extended I/O failed: " + "%s\n", sandev->drive, strerror ( rc ) ); /* Record that no blocks were transferred successfully */ addr.count = 0; put_real ( addr.count, ix86->segs.ds, @@ -781,7 +787,7 @@ static int int13_extended_rw ( struct san_device *sandev, static int int13_extended_read ( struct san_device *sandev, struct i386_all_regs *ix86 ) { - DBGC2 ( sandev, "Extended read: " ); + DBGC2 ( sandev->drive, "Extended read: " ); return int13_extended_rw ( sandev, ix86, sandev_read ); } @@ -795,7 +801,7 @@ static int int13_extended_read ( struct san_device *sandev, static int int13_extended_write ( struct san_device *sandev, struct i386_all_regs *ix86 ) { - DBGC2 ( sandev, "Extended write: " ); + DBGC2 ( sandev->drive, "Extended write: " ); return int13_extended_rw ( sandev, ix86, sandev_write ); } @@ -818,7 +824,7 @@ static int int13_extended_verify ( struct san_device *sandev, sizeof ( addr )); lba = addr.lba; count = addr.count; - DBGC2 ( sandev, "Verify: LBA %08llx (count %ld)\n", + DBGC2 ( sandev->drive, "Verify: LBA %08llx (count %ld)\n", ( ( unsigned long long ) lba ), count ); } @@ -845,7 +851,7 @@ static int int13_extended_seek ( struct san_device *sandev, sizeof ( addr )); lba = addr.lba; count = addr.count; - DBGC2 ( sandev, "Seek: LBA %08llx (count %ld)\n", + DBGC2 ( sandev->drive, "Seek: LBA %08llx (count %ld)\n", ( ( unsigned long long ) lba ), count ); } @@ -879,8 +885,8 @@ static int int13_device_path_info ( struct san_device *sandev, /* Get underlying hardware device */ device = identify_device ( &sanpath->block ); if ( ! device ) { - DBGC ( sandev, "INT13 drive %02x cannot identify hardware " - "device\n", sandev->drive ); + DBGC ( sandev->drive, "INT13 drive %02x cannot identify " + "hardware device\n", sandev->drive ); return -ENODEV; } @@ -895,16 +901,16 @@ static int int13_device_path_info ( struct san_device *sandev, dpi->interface_path.pci.channel = 0xff; /* unused */ break; default: - DBGC ( sandev, "INT13 drive %02x unrecognised bus type %d\n", - sandev->drive, desc->bus_type ); + DBGC ( sandev->drive, "INT13 drive %02x unrecognised bus " + "type %d\n", sandev->drive, desc->bus_type ); return -ENOTSUP; } /* Get EDD block device description */ if ( ( rc = edd_describe ( &sanpath->block, &dpi->interface_type, &dpi->device_path ) ) != 0 ) { - DBGC ( sandev, "INT13 drive %02x cannot identify block device: " - "%s\n", sandev->drive, strerror ( rc ) ); + DBGC ( sandev->drive, "INT13 drive %02x cannot identify " + "block device: %s\n", sandev->drive, strerror ( rc ) ); return rc; } @@ -938,8 +944,8 @@ static int int13_get_extended_parameters ( struct san_device *sandev, get_real ( bufsize, ix86->segs.ds, ( ix86->regs.si + offsetof ( typeof ( params ), bufsize ))); - DBGC2 ( sandev, "Get extended drive parameters to %04x:%04x+%02x\n", - ix86->segs.ds, ix86->regs.si, bufsize ); + DBGC2 ( sandev->drive, "Get extended drive parameters to " + "%04x:%04x+%02x\n", ix86->segs.ds, ix86->regs.si, bufsize ); /* Build drive parameters */ memset ( ¶ms, 0, sizeof ( params ) ); @@ -955,8 +961,8 @@ static int int13_get_extended_parameters ( struct san_device *sandev, params.sector_size = sandev_blksize ( sandev ); memset ( ¶ms.dpte, 0xff, sizeof ( params.dpte ) ); if ( ( rc = int13_device_path_info ( sandev, ¶ms.dpi ) ) != 0 ) { - DBGC ( sandev, "INT13 drive %02x could not provide device " - "path information: %s\n", + DBGC ( sandev->drive, "INT13 drive %02x could not provide " + "device path information: %s\n", sandev->drive, strerror ( rc ) ); len = offsetof ( typeof ( params ), dpi ); } @@ -973,11 +979,11 @@ static int int13_get_extended_parameters ( struct san_device *sandev, params.bufsize = offsetof ( typeof ( params ), dpi ); } - DBGC ( sandev, "INT 13 drive %02x described using extended " + DBGC ( sandev->drive, "INT 13 drive %02x described using extended " "parameters:\n", sandev->drive ); address.segment = ix86->segs.ds; address.offset = ix86->regs.si; - DBGC_HDA ( sandev, address, ¶ms, len ); + DBGC_HDA ( sandev->drive, address, ¶ms, len ); /* Return drive parameters */ if ( len > bufsize ) @@ -998,13 +1004,13 @@ static int int13_cdrom_status_terminate ( struct san_device *sandev, struct i386_all_regs *ix86 ) { struct int13_cdrom_specification specification; - DBGC2 ( sandev, "Get CD-ROM emulation status to %04x:%04x%s\n", + DBGC2 ( sandev->drive, "Get CD-ROM emulation status to %04x:%04x%s\n", ix86->segs.ds, ix86->regs.si, ( ix86->regs.al ? "" : " and terminate" ) ); /* Fail if we are not a CD-ROM */ if ( ! sandev->is_cdrom ) { - DBGC ( sandev, "INT13 drive %02x is not a CD-ROM\n", + DBGC ( sandev->drive, "INT13 drive %02x is not a CD-ROM\n", sandev->drive ); return -INT13_STATUS_INVALID; } @@ -1039,11 +1045,12 @@ static int int13_cdrom_read_boot_catalog ( struct san_device *sandev, /* Read parameters from command packet */ copy_from_real ( &command, ix86->segs.ds, ix86->regs.si, sizeof ( command ) ); - DBGC2 ( sandev, "Read CD-ROM boot catalog to %08x\n", command.buffer ); + DBGC2 ( sandev->drive, "Read CD-ROM boot catalog to %08x\n", + command.buffer ); /* Fail if we have no boot catalog */ if ( ! int13->boot_catalog ) { - DBGC ( sandev, "INT13 drive %02x has no boot catalog\n", + DBGC ( sandev->drive, "INT13 drive %02x has no boot catalog\n", sandev->drive ); return -INT13_STATUS_INVALID; } @@ -1052,8 +1059,8 @@ static int int13_cdrom_read_boot_catalog ( struct san_device *sandev, /* Read from boot catalog */ if ( ( rc = sandev_read ( sandev, start, command.count, phys_to_user ( command.buffer ) ) ) != 0 ) { - DBGC ( sandev, "INT13 drive %02x could not read boot catalog: " - "%s\n", sandev->drive, strerror ( rc ) ); + DBGC ( sandev->drive, "INT13 drive %02x could not read boot " + "catalog: %s\n", sandev->drive, strerror ( rc ) ); return -INT13_STATUS_READ_ERROR; } @@ -1080,8 +1087,8 @@ static __asmcall __used void int13 ( struct i386_all_regs *ix86 ) { if ( bios_drive != sandev->drive ) { /* Remap any accesses to this drive's natural number */ if ( bios_drive == int13->natural_drive ) { - DBGC2 ( sandev, "INT13,%02x (%02x) remapped to " - "(%02x)\n", ix86->regs.ah, + DBGC2 ( sandev->drive, "INT13,%02x (%02x) " + "remapped to (%02x)\n", ix86->regs.ah, bios_drive, sandev->drive ); ix86->regs.dl = sandev->drive; return; @@ -1094,7 +1101,7 @@ static __asmcall __used void int13 ( struct i386_all_regs *ix86 ) { } } - DBGC2 ( sandev, "INT13,%02x (%02x): ", + DBGC2 ( sandev->drive, "INT13,%02x (%02x): ", ix86->regs.ah, bios_drive ); switch ( command ) { @@ -1141,7 +1148,7 @@ static __asmcall __used void int13 ( struct i386_all_regs *ix86 ) { status = int13_cdrom_read_boot_catalog ( sandev, ix86 ); break; default: - DBGC2 ( sandev, "*** Unrecognised INT13 ***\n" ); + DBGC2 ( sandev->drive, "*** Unrecognised INT13 ***\n" ); status = -INT13_STATUS_INVALID; break; } @@ -1152,8 +1159,9 @@ static __asmcall __used void int13 ( struct i386_all_regs *ix86 ) { /* Negative status indicates an error */ if ( status < 0 ) { status = -status; - DBGC ( sandev, "INT13,%02x (%02x) failed with status " - "%02x\n", ix86->regs.ah, sandev->drive, status ); + DBGC ( sandev->drive, "INT13,%02x (%02x) failed with " + "status %02x\n", ix86->regs.ah, sandev->drive, + status ); } else { ix86->flags &= ~CF; } @@ -1269,7 +1277,7 @@ static int int13_hook ( unsigned int drive, struct uri **uris, /* Register SAN device */ if ( ( rc = register_sandev ( sandev, drive, flags ) ) != 0 ) { - DBGC ( sandev, "INT13 drive %02x could not register: %s\n", + DBGC ( drive, "INT13 drive %02x could not register: %s\n", drive, strerror ( rc ) ); goto err_register; } @@ -1289,10 +1297,9 @@ static int int13_hook ( unsigned int drive, struct uri **uris, ( ( rc = int13_guess_geometry ( sandev, scratch ) ) != 0 ) ) goto err_guess_geometry; - DBGC ( sandev, "INT13 drive %02x (naturally %02x) registered with " - "C/H/S geometry %d/%d/%d\n", - sandev->drive, int13->natural_drive, int13->cylinders, - int13->heads, int13->sectors_per_track ); + DBGC ( drive, "INT13 drive %02x (naturally %02x) registered with " + "C/H/S geometry %d/%d/%d\n", drive, int13->natural_drive, + int13->cylinders, int13->heads, int13->sectors_per_track ); /* Hook INT 13 vector if not already hooked */ if ( need_hook ) { @@ -1332,7 +1339,7 @@ static void int13_unhook ( unsigned int drive ) { /* Find drive */ sandev = sandev_find ( drive ); if ( ! sandev ) { - DBG ( "INT13 cannot find drive %02x\n", drive ); + DBGC ( drive, "INT13 drive %02x is not a SAN drive\n", drive ); return; } @@ -1343,7 +1350,7 @@ static void int13_unhook ( unsigned int drive ) { * to do so reliably. */ - DBGC ( sandev, "INT13 drive %02x unregistered\n", sandev->drive ); + DBGC ( drive, "INT13 drive %02x unregistered\n", drive ); /* Unhook INT 13 vector if no more drives */ if ( ! have_sandevs() ) { @@ -1387,8 +1394,8 @@ static int int13_load_mbr ( unsigned int drive, struct segoff *address ) { : "a" ( 0x0201 ), "b" ( *address ), "c" ( 1 ), "d" ( drive ) ); if ( status ) { - DBG ( "INT13 drive %02x could not read MBR (status %04x)\n", - drive, status ); + DBGC ( drive, "INT13 drive %02x could not read MBR (status " + "%04x)\n", drive, status ); return -EIO; } @@ -1397,8 +1404,8 @@ static int int13_load_mbr ( unsigned int drive, struct segoff *address ) { ( address->offset + offsetof ( struct master_boot_record, magic ) ) ); if ( magic != INT13_MBR_MAGIC ) { - DBG ( "INT13 drive %02x does not contain a valid MBR\n", - drive ); + DBGC ( drive, "INT13 drive %02x does not contain a valid MBR\n", + drive ); return -ENOEXEC; } @@ -1444,8 +1451,8 @@ static int int13_load_eltorito ( unsigned int drive, struct segoff *address ) { : "a" ( 0x4d00 ), "d" ( drive ), "S" ( __from_data16 ( &eltorito_cmd ) ) ); if ( status ) { - DBG ( "INT13 drive %02x could not read El Torito boot catalog " - "(status %04x)\n", drive, status ); + DBGC ( drive, "INT13 drive %02x could not read El Torito boot " + "catalog (status %04x)\n", drive, status ); return -EIO; } copy_from_user ( &catalog, phys_to_user ( eltorito_cmd.buffer ), 0, @@ -1453,26 +1460,27 @@ static int int13_load_eltorito ( unsigned int drive, struct segoff *address ) { /* Sanity checks */ if ( catalog.valid.platform_id != ELTORITO_PLATFORM_X86 ) { - DBG ( "INT13 drive %02x El Torito specifies unknown platform " - "%02x\n", drive, catalog.valid.platform_id ); + DBGC ( drive, "INT13 drive %02x El Torito specifies unknown " + "platform %02x\n", drive, catalog.valid.platform_id ); return -ENOEXEC; } if ( catalog.boot.indicator != ELTORITO_BOOTABLE ) { - DBG ( "INT13 drive %02x El Torito is not bootable\n", drive ); + DBGC ( drive, "INT13 drive %02x El Torito is not bootable\n", + drive ); return -ENOEXEC; } if ( catalog.boot.media_type != ELTORITO_NO_EMULATION ) { - DBG ( "INT13 drive %02x El Torito requires emulation " + DBGC ( drive, "INT13 drive %02x El Torito requires emulation " "type %02x\n", drive, catalog.boot.media_type ); return -ENOTSUP; } - DBG ( "INT13 drive %02x El Torito boot image at LBA %08x (count %d)\n", - drive, catalog.boot.start, catalog.boot.length ); + DBGC ( drive, "INT13 drive %02x El Torito boot image at LBA %08x " + "(count %d)\n", drive, catalog.boot.start, catalog.boot.length ); address->segment = ( catalog.boot.load_segment ? catalog.boot.load_segment : 0x7c0 ); address->offset = 0; - DBG ( "INT13 drive %02x El Torito boot image loads at %04x:%04x\n", - drive, address->segment, address->offset ); + DBGC ( drive, "INT13 drive %02x El Torito boot image loads at " + "%04x:%04x\n", drive, address->segment, address->offset ); /* Use INT 13, 42 to read the boot image */ eltorito_address.bufsize = @@ -1491,8 +1499,8 @@ static int int13_load_eltorito ( unsigned int drive, struct segoff *address ) { : "a" ( 0x4200 ), "d" ( drive ), "S" ( __from_data16 ( &eltorito_address ) ) ); if ( status ) { - DBG ( "INT13 drive %02x could not read El Torito boot image " - "(status %04x)\n", drive, status ); + DBGC ( drive, "INT13 drive %02x could not read El Torito boot " + "image (status %04x)\n", drive, status ); return -EIO; } @@ -1533,8 +1541,8 @@ static int int13_boot ( unsigned int drive, const char *filename __unused ) { /* Jump to boot sector */ if ( ( rc = call_bootsector ( address.segment, address.offset, drive ) ) != 0 ) { - DBG ( "INT13 drive %02x boot returned: %s\n", - drive, strerror ( rc ) ); + DBGC ( drive, "INT13 drive %02x boot returned: %s\n", + drive, strerror ( rc ) ); return rc; } diff --git a/src/core/dummy_sanboot.c b/src/core/dummy_sanboot.c index e6293099..506b20c1 100644 --- a/src/core/dummy_sanboot.c +++ b/src/core/dummy_sanboot.c @@ -55,7 +55,7 @@ static int dummy_san_hook ( unsigned int drive, struct uri **uris, /* Register SAN device */ if ( ( rc = register_sandev ( sandev, drive, flags ) ) != 0 ) { - DBGC ( sandev, "SAN %#02x could not register: %s\n", + DBGC ( sandev->drive, "SAN %#02x could not register: %s\n", sandev->drive, strerror ( rc ) ); goto err_register; } @@ -80,7 +80,7 @@ static void dummy_san_unhook ( unsigned int drive ) { /* Find drive */ sandev = sandev_find ( drive ); if ( ! sandev ) { - DBG ( "SAN %#02x does not exist\n", drive ); + DBGC ( drive, "SAN %#02x does not exist\n", drive ); return; } diff --git a/src/core/sanboot.c b/src/core/sanboot.c index cabc4843..7e3a09e4 100644 --- a/src/core/sanboot.c +++ b/src/core/sanboot.c @@ -197,7 +197,7 @@ static int sanpath_open ( struct san_path *sanpath ) { /* Open interface */ if ( ( rc = xfer_open_uri ( &sanpath->block, sanpath->uri ) ) != 0 ) { - DBGC ( sandev, "SAN %#02x.%d could not (re)open URI: " + DBGC ( sandev->drive, "SAN %#02x.%d could not (re)open URI: " "%s\n", sandev->drive, sanpath->index, strerror ( rc ) ); return rc; } @@ -265,7 +265,7 @@ static void sanpath_block_close ( struct san_path *sanpath, int rc ) { /* Any closure is an error from our point of view */ if ( rc == 0 ) rc = -ENOTCONN; - DBGC ( sandev, "SAN %#02x.%d closed: %s\n", + DBGC ( sandev->drive, "SAN %#02x.%d closed: %s\n", sandev->drive, sanpath->index, strerror ( rc ) ); /* Close path */ @@ -307,11 +307,11 @@ static void sanpath_step ( struct san_path *sanpath ) { /* Mark as active path or close as applicable */ if ( ! sandev->active ) { - DBGC ( sandev, "SAN %#02x.%d is active\n", + DBGC ( sandev->drive, "SAN %#02x.%d is active\n", sandev->drive, sanpath->index ); sandev->active = sanpath; } else { - DBGC ( sandev, "SAN %#02x.%d is available\n", + DBGC ( sandev->drive, "SAN %#02x.%d is available\n", sandev->drive, sanpath->index ); sanpath_close ( sanpath, 0 ); } @@ -398,8 +398,9 @@ int sandev_reopen ( struct san_device *sandev ) { rc = sanpath->path_rc; break; } - DBGC ( sandev, "SAN %#02x never became available: %s\n", - sandev->drive, strerror ( rc ) ); + DBGC ( sandev->drive, "SAN %#02x never became " + "available: %s\n", sandev->drive, + strerror ( rc ) ); goto err_none; } } @@ -453,8 +454,9 @@ static int sandev_command_rw ( struct san_device *sandev, if ( ( rc = params->rw.block_rw ( &sanpath->block, &sandev->command, params->rw.lba, params->rw.count, params->rw.buffer, len ) ) != 0 ) { - DBGC ( sandev, "SAN %#02x.%d could not initiate read/write: " - "%s\n", sandev->drive, sanpath->index, strerror ( rc ) ); + DBGC ( sandev->drive, "SAN %#02x.%d could not initiate " + "read/write: %s\n", sandev->drive, sanpath->index, + strerror ( rc ) ); return rc; } @@ -480,8 +482,9 @@ sandev_command_read_capacity ( struct san_device *sandev, /* Initiate read capacity command */ if ( ( rc = block_read_capacity ( &sanpath->block, &sandev->command ) ) != 0 ) { - DBGC ( sandev, "SAN %#02x.%d could not initiate read capacity: " - "%s\n", sandev->drive, sanpath->index, strerror ( rc ) ); + DBGC ( sandev->drive, "SAN %#02x.%d could not initiate read " + "capacity: %s\n", sandev->drive, sanpath->index, + strerror ( rc ) ); return rc; } @@ -565,7 +568,7 @@ sandev_command ( struct san_device *sandev, int sandev_reset ( struct san_device *sandev ) { int rc; - DBGC ( sandev, "SAN %#02x reset\n", sandev->drive ); + DBGC ( sandev->drive, "SAN %#02x reset\n", sandev->drive ); /* Close and reopen underlying block device */ if ( ( rc = sandev_reopen ( sandev ) ) != 0 ) @@ -698,8 +701,8 @@ static int sandev_describe ( struct san_device *sandev ) { if ( ! desc ) continue; if ( ( rc = desc->model->complete ( desc ) ) != 0 ) { - DBGC ( sandev, "SAN %#02x.%d could not be " - "described: %s\n", sandev->drive, + DBGC ( sandev->drive, "SAN %#02x.%d could not " + "be described: %s\n", sandev->drive, sanpath->index, strerror ( rc ) ); return rc; } @@ -792,8 +795,8 @@ static int sandev_parse_iso9660 ( struct san_device *sandev ) { /* Read primary volume descriptor */ if ( ( rc = sandev_read ( sandev, lba, count, virt_to_user ( scratch ) ) ) != 0 ) { - DBGC ( sandev, "SAN %#02x could not read ISO9660 primary" - "volume descriptor: %s\n", + DBGC ( sandev->drive, "SAN %#02x could not read ISO9660 " + "primary volume descriptor: %s\n", sandev->drive, strerror ( rc ) ); goto err_rw; } @@ -801,8 +804,8 @@ static int sandev_parse_iso9660 ( struct san_device *sandev ) { /* Configure as CD-ROM if applicable */ if ( memcmp ( &scratch->primary.fixed, &primary_check, sizeof ( primary_check ) ) == 0 ) { - DBGC ( sandev, "SAN %#02x contains an ISO9660 filesystem; " - "treating as CD-ROM\n", sandev->drive ); + DBGC ( sandev->drive, "SAN %#02x contains an ISO9660 " + "filesystem; treating as CD-ROM\n", sandev->drive ); sandev->blksize_shift = blksize_shift; sandev->is_cdrom = 1; } @@ -871,7 +874,7 @@ int register_sandev ( struct san_device *sandev, unsigned int drive, /* Check that drive number is not in use */ if ( sandev_find ( drive ) != NULL ) { - DBGC ( sandev, "SAN %#02x is already in use\n", drive ); + DBGC ( sandev->drive, "SAN %#02x is already in use\n", drive ); rc = -EADDRINUSE; goto err_in_use; } @@ -902,7 +905,7 @@ int register_sandev ( struct san_device *sandev, unsigned int drive, /* Add to list of SAN devices */ list_add_tail ( &sandev->list, &san_devices ); - DBGC ( sandev, "SAN %#02x registered\n", sandev->drive ); + DBGC ( sandev->drive, "SAN %#02x registered\n", sandev->drive ); return 0; @@ -936,7 +939,7 @@ void unregister_sandev ( struct san_device *sandev ) { /* Remove ACPI descriptors */ sandev_undescribe ( sandev ); - DBGC ( sandev, "SAN %#02x unregistered\n", sandev->drive ); + DBGC ( sandev->drive, "SAN %#02x unregistered\n", sandev->drive ); } /** The "san-drive" setting */ diff --git a/src/interface/efi/efi_block.c b/src/interface/efi/efi_block.c index cb73260d..86186c0a 100644 --- a/src/interface/efi/efi_block.c +++ b/src/interface/efi/efi_block.c @@ -101,7 +101,7 @@ static int efi_block_rw ( struct san_device *sandev, uint64_t lba, /* Sanity check */ count = ( len / block->media.BlockSize ); if ( ( count * block->media.BlockSize ) != len ) { - DBGC ( sandev, "EFIBLK %#02x impossible length %#zx\n", + DBGC ( sandev->drive, "EFIBLK %#02x impossible length %#zx\n", sandev->drive, len ); return -EINVAL; } @@ -109,7 +109,7 @@ static int efi_block_rw ( struct san_device *sandev, uint64_t lba, /* Read from / write to block device */ if ( ( rc = sandev_rw ( sandev, lba, count, virt_to_user ( data ) ) ) != 0 ) { - DBGC ( sandev, "EFIBLK %#02x I/O failed: %s\n", + DBGC ( sandev->drive, "EFIBLK %#02x I/O failed: %s\n", sandev->drive, strerror ( rc ) ); return rc; } @@ -131,7 +131,7 @@ static EFI_STATUS EFIAPI efi_block_io_reset ( EFI_BLOCK_IO_PROTOCOL *block_io, struct san_device *sandev = block->sandev; int rc; - DBGC2 ( sandev, "EFIBLK %#02x reset\n", sandev->drive ); + DBGC2 ( sandev->drive, "EFIBLK %#02x reset\n", sandev->drive ); efi_snp_claim(); rc = sandev_reset ( sandev ); efi_snp_release(); @@ -156,7 +156,7 @@ efi_block_io_read ( EFI_BLOCK_IO_PROTOCOL *block_io, UINT32 media __unused, struct san_device *sandev = block->sandev; int rc; - DBGC2 ( sandev, "EFIBLK %#02x read LBA %#08llx to %p+%#08zx\n", + DBGC2 ( sandev->drive, "EFIBLK %#02x read LBA %#08llx to %p+%#08zx\n", sandev->drive, lba, data, ( ( size_t ) len ) ); efi_snp_claim(); rc = efi_block_rw ( sandev, lba, data, len, sandev_read ); @@ -182,8 +182,8 @@ efi_block_io_write ( EFI_BLOCK_IO_PROTOCOL *block_io, UINT32 media __unused, struct san_device *sandev = block->sandev; int rc; - DBGC2 ( sandev, "EFIBLK %#02x write LBA %#08llx from %p+%#08zx\n", - sandev->drive, lba, data, ( ( size_t ) len ) ); + DBGC2 ( sandev->drive, "EFIBLK %#02x write LBA %#08llx from " + "%p+%#08zx\n", sandev->drive, lba, data, ( ( size_t ) len ) ); efi_snp_claim(); rc = efi_block_rw ( sandev, lba, data, len, sandev_write ); efi_snp_release(); @@ -202,7 +202,7 @@ efi_block_io_flush ( EFI_BLOCK_IO_PROTOCOL *block_io ) { container_of ( block_io, struct efi_block_data, block_io ); struct san_device *sandev = block->sandev; - DBGC2 ( sandev, "EFIBLK %#02x flush\n", sandev->drive ); + DBGC2 ( sandev->drive, "EFIBLK %#02x flush\n", sandev->drive ); /* Nothing to do */ return 0; @@ -223,12 +223,13 @@ static void efi_block_connect ( struct san_device *sandev ) { if ( ( efirc = bs->ConnectController ( block->handle, NULL, NULL, TRUE ) ) != 0 ) { rc = -EEFI ( efirc ); - DBGC ( sandev, "EFIBLK %#02x could not connect drivers: %s\n", - sandev->drive, strerror ( rc ) ); + DBGC ( sandev->drive, "EFIBLK %#02x could not connect " + "drivers: %s\n", sandev->drive, strerror ( rc ) ); /* May not be an error; may already be connected */ } - DBGC2 ( sandev, "EFIBLK %#02x supports protocols:\n", sandev->drive ); - DBGC2_EFI_PROTOCOLS ( sandev, block->handle ); + DBGC2 ( sandev->drive, "EFIBLK %#02x supports protocols:\n", + sandev->drive ); + DBGC2_EFI_PROTOCOLS ( sandev->drive, block->handle ); } /** @@ -251,7 +252,7 @@ static int efi_block_hook ( unsigned int drive, struct uri **uris, /* Sanity check */ if ( ! count ) { - DBG ( "EFIBLK has no URIs\n" ); + DBGC ( drive, "EFIBLK %#02x has no URIs\n", drive ); rc = -ENOTTY; goto err_no_uris; } @@ -275,7 +276,7 @@ static int efi_block_hook ( unsigned int drive, struct uri **uris, /* Register SAN device */ if ( ( rc = register_sandev ( sandev, drive, flags ) ) != 0 ) { - DBGC ( sandev, "EFIBLK %#02x could not register: %s\n", + DBGC ( drive, "EFIBLK %#02x could not register: %s\n", drive, strerror ( rc ) ); goto err_register; } @@ -289,17 +290,17 @@ static int efi_block_hook ( unsigned int drive, struct uri **uris, /* Construct device path */ if ( ! sandev->active ) { rc = -ENODEV; - DBGC ( sandev, "EFIBLK %#02x not active after registration\n", + DBGC ( drive, "EFIBLK %#02x not active after registration\n", drive ); goto err_active; } block->path = efi_describe ( &sandev->active->block ); if ( ! block->path ) { rc = -ENODEV; - DBGC ( sandev, "EFIBLK %#02x has no device path\n", drive ); + DBGC ( drive, "EFIBLK %#02x has no device path\n", drive ); goto err_describe; } - DBGC ( sandev, "EFIBLK %#02x has device path %s\n", + DBGC ( drive, "EFIBLK %#02x has device path %s\n", drive, efi_devpath_text ( block->path ) ); /* Install protocols */ @@ -309,8 +310,8 @@ static int efi_block_hook ( unsigned int drive, struct uri **uris, &efi_device_path_protocol_guid, block->path, NULL ) ) != 0 ) { rc = -EEFI ( efirc ); - DBGC ( sandev, "EFIBLK %#02x could not install protocols: %s\n", - sandev->drive, strerror ( rc ) ); + DBGC ( drive, "EFIBLK %#02x could not install protocols: %s\n", + drive, strerror ( rc ) ); goto err_install; } @@ -324,8 +325,8 @@ static int efi_block_hook ( unsigned int drive, struct uri **uris, &efi_block_io_protocol_guid, &block->block_io, &efi_device_path_protocol_guid, block->path, NULL ) ) != 0 ) { - DBGC ( sandev, "EFIBLK %#02x could not uninstall protocols: " - "%s\n", sandev->drive, strerror ( -EEFI ( efirc ) ) ); + DBGC ( drive, "EFIBLK %#02x could not uninstall protocols: " + "%s\n", drive, strerror ( -EEFI ( efirc ) ) ); leak = 1; } efi_nullify_block ( &block->block_io ); @@ -342,10 +343,8 @@ static int efi_block_hook ( unsigned int drive, struct uri **uris, sandev_put ( sandev ); err_alloc: err_no_uris: - if ( leak ) { - DBGC ( sandev, "EFIBLK %#02x nullified and leaked\n", - sandev->drive ); - } + if ( leak ) + DBGC ( drive, "EFIBLK %#02x nullified and leaked\n", drive ); return rc; } @@ -364,7 +363,7 @@ static void efi_block_unhook ( unsigned int drive ) { /* Find SAN device */ sandev = sandev_find ( drive ); if ( ! sandev ) { - DBG ( "EFIBLK cannot find drive %#02x\n", drive ); + DBGC ( drive, "EFIBLK %#02x is not a SAN drive\n", drive ); return; } block = sandev->priv; @@ -376,8 +375,8 @@ static void efi_block_unhook ( unsigned int drive ) { &efi_block_io_protocol_guid, &block->block_io, &efi_device_path_protocol_guid, block->path, NULL ) ) != 0 ) ) { - DBGC ( sandev, "EFIBLK %#02x could not uninstall protocols: " - "%s\n", sandev->drive, strerror ( -EEFI ( efirc ) ) ); + DBGC ( drive, "EFIBLK %#02x could not uninstall protocols: " + "%s\n", drive, strerror ( -EEFI ( efirc ) ) ); leak = 1; } efi_nullify_block ( &block->block_io ); @@ -396,10 +395,8 @@ static void efi_block_unhook ( unsigned int drive ) { sandev_put ( sandev ); /* Report leakage, if applicable */ - if ( leak && ( ! efi_shutdown_in_progress ) ) { - DBGC ( sandev, "EFIBLK %#02x nullified and leaked\n", - sandev->drive ); - } + if ( leak && ( ! efi_shutdown_in_progress ) ) + DBGC ( drive, "EFIBLK %#02x nullified and leaked\n", drive ); } /** An installed ACPI table */ @@ -539,8 +536,8 @@ static int efi_block_boot_image ( struct san_device *sandev, EFI_HANDLE handle, &path.interface, efi_image_handle, handle, EFI_OPEN_PROTOCOL_GET_PROTOCOL ))!=0){ - DBGC ( sandev, "EFIBLK %#02x found filesystem with no device " - "path??", sandev->drive ); + DBGC ( sandev->drive, "EFIBLK %#02x found filesystem with no " + "device path??", sandev->drive ); rc = -EEFI ( efirc ); goto err_open_device_path; } @@ -552,7 +549,7 @@ static int efi_block_boot_image ( struct san_device *sandev, EFI_HANDLE handle, rc = -ENOTTY; goto err_not_child; } - DBGC ( sandev, "EFIBLK %#02x found child device %s\n", + DBGC ( sandev->drive, "EFIBLK %#02x found child device %s\n", sandev->drive, efi_devpath_text ( path.path ) ); /* Construct device path for boot image */ @@ -583,7 +580,7 @@ static int efi_block_boot_image ( struct san_device *sandev, EFI_HANDLE handle, } end = ( ( ( void * ) filepath ) + filepath_len ); efi_path_terminate ( end ); - DBGC ( sandev, "EFIBLK %#02x trying to load %s\n", + DBGC ( sandev->drive, "EFIBLK %#02x trying to load %s\n", sandev->drive, efi_devpath_text ( boot_path ) ); /* Try loading boot image from this device */ @@ -591,7 +588,7 @@ static int efi_block_boot_image ( struct san_device *sandev, EFI_HANDLE handle, if ( ( efirc = bs->LoadImage ( FALSE, efi_image_handle, boot_path, NULL, 0, image ) ) != 0 ) { rc = -EEFI ( efirc ); - DBGC ( sandev, "EFIBLK %#02x could not load image: %s\n", + DBGC ( sandev->drive, "EFIBLK %#02x could not load image: %s\n", sandev->drive, strerror ( rc ) ); if ( efirc == EFI_SECURITY_VIOLATION ) bs->UnloadImage ( *image ); @@ -629,7 +626,7 @@ static int efi_block_boot ( unsigned int drive, const char *filename ) { /* Find SAN device */ sandev = sandev_find ( drive ); if ( ! sandev ) { - DBG ( "EFIBLK cannot find drive %#02x\n", drive ); + DBGC ( drive, "EFIBLK %#02x is not a SAN drive\n", drive ); rc = -ENODEV; goto err_sandev_find; } @@ -645,8 +642,8 @@ static int efi_block_boot ( unsigned int drive, const char *filename ) { ByProtocol, &efi_simple_file_system_protocol_guid, NULL, &count, &handles ) ) != 0 ) { rc = -EEFI ( efirc ); - DBGC ( sandev, "EFIBLK %#02x cannot locate file systems: %s\n", - sandev->drive, strerror ( rc ) ); + DBGC ( drive, "EFIBLK %#02x cannot locate file systems: %s\n", + drive, strerror ( rc ) ); goto err_locate_file_systems; } @@ -660,13 +657,12 @@ static int efi_block_boot ( unsigned int drive, const char *filename ) { if ( ( rc = efi_block_boot_image ( sandev, handles[i], filename, &image ) ) != 0 ) continue; - DBGC ( sandev, "EFIBLK %#02x found boot image\n", - sandev->drive ); + DBGC ( drive, "EFIBLK %#02x found boot image\n", drive ); efirc = bs->StartImage ( image, NULL, NULL ); rc = ( efirc ? -EEFI ( efirc ) : 0 ); bs->UnloadImage ( image ); - DBGC ( sandev, "EFIBLK %#02x boot image returned: %s\n", - sandev->drive, strerror ( rc ) ); + DBGC ( drive, "EFIBLK %#02x boot image returned: %s\n", + drive, strerror ( rc ) ); break; } -- cgit v1.2.3-55-g7522 From eb720d2224c3d0b311f526c922c7388819d97778 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Sun, 3 Mar 2024 15:25:11 +0000 Subject: [efi] Use file system protocol to check for SAN boot filename existence The "sanboot" command allows a custom boot filename to be specified via the "--filename" option. We currently rely on LoadImage() to perform both the existence check and to load the image ready for execution. This may give a false negative result if Secure Boot is enabled and the boot file is not correctly signed. Carry out the existence check using EFI_SIMPLE_FILE_SYSTEM_PROTOCOL separately from loading the image via LoadImage(). Signed-off-by: Michael Brown --- src/interface/efi/efi_block.c | 304 ++++++++++++++++++++++++++++++------------ 1 file changed, 218 insertions(+), 86 deletions(-) diff --git a/src/interface/efi/efi_block.c b/src/interface/efi/efi_block.c index 86186c0a..a4eab42b 100644 --- a/src/interface/efi/efi_block.c +++ b/src/interface/efi/efi_block.c @@ -505,69 +505,224 @@ static int efi_block_describe ( void ) { } /** - * Try booting from child device of EFI block device + * Check for existence of a file within a filesystem * * @v sandev SAN device - * @v handle EFI handle + * @v handle Filesystem handle * @v filename Filename (or NULL to use default) - * @v image Image handle to fill in * @ret rc Return status code */ -static int efi_block_boot_image ( struct san_device *sandev, EFI_HANDLE handle, - const char *filename, EFI_HANDLE *image ) { +static int efi_block_filename ( struct san_device *sandev, EFI_HANDLE handle, + const char *filename ) { EFI_BOOT_SERVICES *bs = efi_systab->BootServices; - struct efi_block_data *block = sandev->priv; + EFI_GUID *protocol = &efi_simple_file_system_protocol_guid; + CHAR16 tmp[ filename ? ( strlen ( filename ) + 1 /* wNUL */ ) : 0 ]; + union { + EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *fs; + void *interface; + } u; + CHAR16 *wname; + EFI_FILE_PROTOCOL *root; + EFI_FILE_PROTOCOL *file; + EFI_STATUS efirc; + int rc; + + /* Construct filename */ + if ( filename ) { + efi_snprintf ( tmp, sizeof ( tmp ), "%s", filename ); + wname = tmp; + } else { + wname = efi_block_boot_filename; + } + + /* Open file system protocol */ + if ( ( efirc = bs->OpenProtocol ( handle, protocol, &u.interface, + efi_image_handle, handle, + EFI_OPEN_PROTOCOL_GET_PROTOCOL ))!=0){ + rc = -EEFI ( efirc ); + DBGC ( sandev->drive, "EFIBLK %#02x could not open %s device " + "path: %s\n", sandev->drive, efi_handle_name ( handle ), + strerror ( rc ) ); + goto err_open; + } + + /* Open root volume */ + if ( ( efirc = u.fs->OpenVolume ( u.fs, &root ) ) != 0 ) { + rc = -EEFI ( efirc ); + DBGC ( sandev->drive, "EFIBLK %#02x could not open %s root: " + "%s\n", sandev->drive, efi_handle_name ( handle ), + strerror ( rc ) ); + goto err_volume; + } + + /* Try opening file */ + if ( ( efirc = root->Open ( root, &file, wname, + EFI_FILE_MODE_READ, 0 ) ) != 0 ) { + rc = -EEFI ( efirc ); + DBGC ( sandev->drive, "EFIBLK %#02x could not open %s/%ls: " + "%s\n", sandev->drive, efi_handle_name ( handle ), + wname, strerror ( rc ) ); + goto err_file; + } + + /* Success */ + rc = 0; + + file->Close ( file ); + err_file: + root->Close ( root ); + err_volume: + bs->CloseProtocol ( handle, protocol, efi_image_handle, handle ); + err_open: + return rc; +} + +/** + * Check EFI block device filesystem match + * + * @v sandev SAN device + * @v handle Filesystem handle + * @v path Block device path + * @v filename Filename (or NULL to use default) + * @v fspath Filesystem device path to fill in + * @ret rc Return status code + */ +static int efi_block_match ( struct san_device *sandev, EFI_HANDLE handle, + EFI_DEVICE_PATH_PROTOCOL *path, + const char *filename, + EFI_DEVICE_PATH_PROTOCOL **fspath ) { + EFI_BOOT_SERVICES *bs = efi_systab->BootServices; + EFI_GUID *protocol = &efi_device_path_protocol_guid; union { EFI_DEVICE_PATH_PROTOCOL *path; void *interface; - } path; - EFI_DEVICE_PATH_PROTOCOL *boot_path; - FILEPATH_DEVICE_PATH *filepath; - EFI_DEVICE_PATH_PROTOCOL *end; - size_t prefix_len; - size_t filepath_len; - size_t boot_path_len; + } u; EFI_STATUS efirc; int rc; /* Identify device path */ - if ( ( efirc = bs->OpenProtocol ( handle, - &efi_device_path_protocol_guid, - &path.interface, efi_image_handle, - handle, + if ( ( efirc = bs->OpenProtocol ( handle, protocol, &u.interface, + efi_image_handle, handle, EFI_OPEN_PROTOCOL_GET_PROTOCOL ))!=0){ - DBGC ( sandev->drive, "EFIBLK %#02x found filesystem with no " - "device path??", sandev->drive ); rc = -EEFI ( efirc ); - goto err_open_device_path; + DBGC ( sandev->drive, "EFIBLK %#02x could not open %s device " + "path: %s\n", sandev->drive, efi_handle_name ( handle ), + strerror ( rc ) ); + goto err_open; } + *fspath = u.path; - /* Check if this device is a child of our block device */ - prefix_len = efi_path_len ( block->path ); - if ( memcmp ( path.path, block->path, prefix_len ) != 0 ) { + /* Check if filesystem is a child of this block device */ + if ( memcmp ( u.path, path, efi_path_len ( path ) ) != 0 ) { /* Not a child device */ rc = -ENOTTY; + DBGC2 ( sandev->drive, "EFIBLK %#02x is not parent of %s\n", + sandev->drive, efi_handle_name ( handle ) ); goto err_not_child; } - DBGC ( sandev->drive, "EFIBLK %#02x found child device %s\n", - sandev->drive, efi_devpath_text ( path.path ) ); + DBGC ( sandev->drive, "EFIBLK %#02x contains filesystem %s\n", + sandev->drive, efi_devpath_text ( u.path ) ); + + /* Check if filesystem contains boot filename */ + if ( ( rc = efi_block_filename ( sandev, handle, filename ) ) != 0 ) + goto err_filename; + + /* Success */ + rc = 0; + + err_filename: + err_not_child: + bs->CloseProtocol ( handle, protocol, efi_image_handle, handle ); + err_open: + return rc; +} + +/** + * Scan EFI block device for a matching filesystem + * + * @v sandev SAN device + * @v filename Filename (or NULL to use default) + * @v fspath Filesystem device path to fill in + * @ret rc Return status code + */ +static int efi_block_scan ( struct san_device *sandev, const char *filename, + EFI_DEVICE_PATH_PROTOCOL **fspath ) { + EFI_BOOT_SERVICES *bs = efi_systab->BootServices; + struct efi_block_data *block = sandev->priv; + EFI_HANDLE *handles; + UINTN count; + unsigned int i; + EFI_STATUS efirc; + int rc; + + /* Connect up possible file system drivers */ + efi_block_connect ( sandev ); + + /* Locate all Simple File System protocol handles */ + if ( ( efirc = bs->LocateHandleBuffer ( + ByProtocol, &efi_simple_file_system_protocol_guid, + NULL, &count, &handles ) ) != 0 ) { + rc = -EEFI ( efirc ); + DBGC ( sandev->drive, "EFIBLK %#02x cannot locate file " + "systems: %s\n", sandev->drive, strerror ( rc ) ); + goto err_locate; + } + + /* Scan for a matching filesystem */ + rc = -ENOENT; + for ( i = 0 ; i < count ; i++ ) { + + /* Check for a matching filesystem */ + if ( ( rc = efi_block_match ( sandev, handles[i], block->path, + filename, fspath ) ) != 0 ) + continue; + + break; + } + + bs->FreePool ( handles ); + err_locate: + return rc; +} + +/** + * Boot from EFI block device filesystem boot image + * + * @v sandev SAN device + * @v fspath Filesystem device path + * @v filename Filename (or NULL to use default) + * @ret rc Return status code + */ +static int efi_block_exec ( struct san_device *sandev, + EFI_DEVICE_PATH_PROTOCOL *fspath, + const char *filename ) { + EFI_BOOT_SERVICES *bs = efi_systab->BootServices; + EFI_DEVICE_PATH_PROTOCOL *path; + FILEPATH_DEVICE_PATH *filepath; + EFI_DEVICE_PATH_PROTOCOL *end; + EFI_HANDLE image; + size_t fspath_len; + size_t filepath_len; + size_t path_len; + EFI_STATUS efirc; + int rc; /* Construct device path for boot image */ - end = efi_path_end ( path.path ); - prefix_len = ( ( ( void * ) end ) - ( ( void * ) path.path ) ); + end = efi_path_end ( fspath ); + fspath_len = ( ( ( void * ) end ) - ( ( void * ) fspath ) ); filepath_len = ( SIZE_OF_FILEPATH_DEVICE_PATH + ( filename ? ( ( strlen ( filename ) + 1 /* NUL */ ) * sizeof ( filepath->PathName[0] ) ) : sizeof ( efi_block_boot_filename ) ) ); - boot_path_len = ( prefix_len + filepath_len + sizeof ( *end ) ); - boot_path = zalloc ( boot_path_len ); - if ( ! boot_path ) { + path_len = ( fspath_len + filepath_len + sizeof ( *end ) ); + path = zalloc ( path_len ); + if ( ! path ) { rc = -ENOMEM; - goto err_alloc_path; + goto err_alloc; } - memcpy ( boot_path, path.path, prefix_len ); - filepath = ( ( ( void * ) boot_path ) + prefix_len ); + memcpy ( path, fspath, fspath_len ); + filepath = ( ( ( void * ) path ) + fspath_len ); filepath->Header.Type = MEDIA_DEVICE_PATH; filepath->Header.SubType = MEDIA_FILEPATH_DP; filepath->Header.Length[0] = ( filepath_len & 0xff ); @@ -581,28 +736,33 @@ static int efi_block_boot_image ( struct san_device *sandev, EFI_HANDLE handle, end = ( ( ( void * ) filepath ) + filepath_len ); efi_path_terminate ( end ); DBGC ( sandev->drive, "EFIBLK %#02x trying to load %s\n", - sandev->drive, efi_devpath_text ( boot_path ) ); + sandev->drive, efi_devpath_text ( path ) ); - /* Try loading boot image from this device */ - *image = NULL; - if ( ( efirc = bs->LoadImage ( FALSE, efi_image_handle, boot_path, - NULL, 0, image ) ) != 0 ) { + /* Load image */ + image = NULL; + if ( ( efirc = bs->LoadImage ( FALSE, efi_image_handle, path, NULL, 0, + &image ) ) != 0 ) { rc = -EEFI ( efirc ); - DBGC ( sandev->drive, "EFIBLK %#02x could not load image: %s\n", + DBGC ( sandev->drive, "EFIBLK %#02x could not load: %s\n", sandev->drive, strerror ( rc ) ); - if ( efirc == EFI_SECURITY_VIOLATION ) - bs->UnloadImage ( *image ); - goto err_load_image; + if ( efirc == EFI_SECURITY_VIOLATION ) { + goto err_load_security_violation; + } else { + goto err_load; + } } - /* Success */ - rc = 0; + /* Start image */ + efirc = bs->StartImage ( image, NULL, NULL ); + rc = ( efirc ? -EEFI ( efirc ) : 0 ); + DBGC ( sandev->drive, "EFIBLK %#02x boot image returned: %s\n", + sandev->drive, strerror ( rc ) ); - err_load_image: - free ( boot_path ); - err_alloc_path: - err_not_child: - err_open_device_path: + err_load_security_violation: + bs->UnloadImage ( image ); + err_load: + free ( path ); + err_alloc: return rc; } @@ -614,13 +774,8 @@ static int efi_block_boot_image ( struct san_device *sandev, EFI_HANDLE handle, * @ret rc Return status code */ static int efi_block_boot ( unsigned int drive, const char *filename ) { - EFI_BOOT_SERVICES *bs = efi_systab->BootServices; + EFI_DEVICE_PATH_PROTOCOL *fspath = NULL; struct san_device *sandev; - EFI_HANDLE *handles; - EFI_HANDLE image = NULL; - UINTN count; - unsigned int i; - EFI_STATUS efirc; int rc; /* Find SAN device */ @@ -634,40 +789,17 @@ static int efi_block_boot ( unsigned int drive, const char *filename ) { /* Release SNP devices */ efi_snp_release(); - /* Connect all possible protocols */ - efi_block_connect ( sandev ); - - /* Locate all handles supporting the Simple File System protocol */ - if ( ( efirc = bs->LocateHandleBuffer ( - ByProtocol, &efi_simple_file_system_protocol_guid, - NULL, &count, &handles ) ) != 0 ) { - rc = -EEFI ( efirc ); - DBGC ( drive, "EFIBLK %#02x cannot locate file systems: %s\n", - drive, strerror ( rc ) ); - goto err_locate_file_systems; + /* Scan for a matching filesystem within this block device */ + if ( ( rc = efi_block_scan ( sandev, filename, &fspath ) ) != 0 ) { + goto err_scan; } - /* Try booting from any available child device containing a - * suitable boot image. This is something of a wild stab in - * the dark, but should end up conforming to user expectations - * most of the time. - */ - rc = -ENOENT; - for ( i = 0 ; i < count ; i++ ) { - if ( ( rc = efi_block_boot_image ( sandev, handles[i], filename, - &image ) ) != 0 ) - continue; - DBGC ( drive, "EFIBLK %#02x found boot image\n", drive ); - efirc = bs->StartImage ( image, NULL, NULL ); - rc = ( efirc ? -EEFI ( efirc ) : 0 ); - bs->UnloadImage ( image ); - DBGC ( drive, "EFIBLK %#02x boot image returned: %s\n", - drive, strerror ( rc ) ); - break; - } + /* Attempt to boot from this filesystem */ + if ( ( rc = efi_block_exec ( sandev, fspath, filename ) ) != 0 ) + goto err_exec; - bs->FreePool ( handles ); - err_locate_file_systems: + err_exec: + err_scan: efi_snp_claim(); err_sandev_find: return rc; -- cgit v1.2.3-55-g7522 From 37edfea72be8d202d2590c89e9b8416f3c615216 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Mon, 4 Mar 2024 14:21:59 +0000 Subject: [efi] Generalise block device boot to support arbitrary EFI handles SAN devices created by iPXE are visible to the firmware, and may be accessed using the firmware's standard block I/O device interface (e.g. INT 13 for BIOS, or EFI_BLOCK_IO_PROTOCOL for UEFI). The iPXE code to perform a SAN boot acts as a client of this standard block I/O device interface, even when the underlying block I/O is being performed by iPXE itself. We rely on this separation to allow the "sanboot" command to be used to boot from a local disk: since the code to perform a SAN boot does not need direct access to an underlying iPXE SAN device, it may be used to boot from any device providing the firmware's standard block I/O device interface. Clean up the EFI SAN boot code to require only a drive number and an EFI_BLOCK_IO_PROTOCOL handle, in preparation for adding support for booting from a local disk under UEFI. Signed-off-by: Michael Brown --- src/interface/efi/efi_block.c | 113 ++++++++++++++++++++++++------------------ 1 file changed, 66 insertions(+), 47 deletions(-) diff --git a/src/interface/efi/efi_block.c b/src/interface/efi/efi_block.c index a4eab42b..79ef7455 100644 --- a/src/interface/efi/efi_block.c +++ b/src/interface/efi/efi_block.c @@ -211,25 +211,24 @@ efi_block_io_flush ( EFI_BLOCK_IO_PROTOCOL *block_io ) { /** * Connect all possible drivers to EFI block device * - * @v sandev SAN device + * @v drive Drive number + * @v handle Block device handle */ -static void efi_block_connect ( struct san_device *sandev ) { +static void efi_block_connect ( unsigned int drive, EFI_HANDLE handle ) { EFI_BOOT_SERVICES *bs = efi_systab->BootServices; - struct efi_block_data *block = sandev->priv; EFI_STATUS efirc; int rc; /* Try to connect all possible drivers to this block device */ - if ( ( efirc = bs->ConnectController ( block->handle, NULL, - NULL, TRUE ) ) != 0 ) { + if ( ( efirc = bs->ConnectController ( handle, NULL, NULL, + TRUE ) ) != 0 ) { rc = -EEFI ( efirc ); - DBGC ( sandev->drive, "EFIBLK %#02x could not connect " - "drivers: %s\n", sandev->drive, strerror ( rc ) ); + DBGC ( drive, "EFIBLK %#02x could not connect drivers: %s\n", + drive, strerror ( rc ) ); /* May not be an error; may already be connected */ } - DBGC2 ( sandev->drive, "EFIBLK %#02x supports protocols:\n", - sandev->drive ); - DBGC2_EFI_PROTOCOLS ( sandev->drive, block->handle ); + DBGC2 ( drive, "EFIBLK %#02x supports protocols:\n", drive ); + DBGC2_EFI_PROTOCOLS ( drive, handle ); } /** @@ -316,7 +315,7 @@ static int efi_block_hook ( unsigned int drive, struct uri **uris, } /* Connect all possible protocols */ - efi_block_connect ( sandev ); + efi_block_connect ( drive, block->handle ); return drive; @@ -507,12 +506,12 @@ static int efi_block_describe ( void ) { /** * Check for existence of a file within a filesystem * - * @v sandev SAN device + * @v drive Drive number * @v handle Filesystem handle * @v filename Filename (or NULL to use default) * @ret rc Return status code */ -static int efi_block_filename ( struct san_device *sandev, EFI_HANDLE handle, +static int efi_block_filename ( unsigned int drive, EFI_HANDLE handle, const char *filename ) { EFI_BOOT_SERVICES *bs = efi_systab->BootServices; EFI_GUID *protocol = &efi_simple_file_system_protocol_guid; @@ -540,8 +539,8 @@ static int efi_block_filename ( struct san_device *sandev, EFI_HANDLE handle, efi_image_handle, handle, EFI_OPEN_PROTOCOL_GET_PROTOCOL ))!=0){ rc = -EEFI ( efirc ); - DBGC ( sandev->drive, "EFIBLK %#02x could not open %s device " - "path: %s\n", sandev->drive, efi_handle_name ( handle ), + DBGC ( drive, "EFIBLK %#02x could not open %s device path: " + "%s\n", drive, efi_handle_name ( handle ), strerror ( rc ) ); goto err_open; } @@ -549,9 +548,8 @@ static int efi_block_filename ( struct san_device *sandev, EFI_HANDLE handle, /* Open root volume */ if ( ( efirc = u.fs->OpenVolume ( u.fs, &root ) ) != 0 ) { rc = -EEFI ( efirc ); - DBGC ( sandev->drive, "EFIBLK %#02x could not open %s root: " - "%s\n", sandev->drive, efi_handle_name ( handle ), - strerror ( rc ) ); + DBGC ( drive, "EFIBLK %#02x could not open %s root: %s\n", + drive, efi_handle_name ( handle ), strerror ( rc ) ); goto err_volume; } @@ -559,9 +557,9 @@ static int efi_block_filename ( struct san_device *sandev, EFI_HANDLE handle, if ( ( efirc = root->Open ( root, &file, wname, EFI_FILE_MODE_READ, 0 ) ) != 0 ) { rc = -EEFI ( efirc ); - DBGC ( sandev->drive, "EFIBLK %#02x could not open %s/%ls: " - "%s\n", sandev->drive, efi_handle_name ( handle ), - wname, strerror ( rc ) ); + DBGC ( drive, "EFIBLK %#02x could not open %s/%ls: %s\n", + drive, efi_handle_name ( handle ), wname, + strerror ( rc ) ); goto err_file; } @@ -580,14 +578,14 @@ static int efi_block_filename ( struct san_device *sandev, EFI_HANDLE handle, /** * Check EFI block device filesystem match * - * @v sandev SAN device + * @v drive Drive number * @v handle Filesystem handle * @v path Block device path * @v filename Filename (or NULL to use default) * @v fspath Filesystem device path to fill in * @ret rc Return status code */ -static int efi_block_match ( struct san_device *sandev, EFI_HANDLE handle, +static int efi_block_match ( unsigned int drive, EFI_HANDLE handle, EFI_DEVICE_PATH_PROTOCOL *path, const char *filename, EFI_DEVICE_PATH_PROTOCOL **fspath ) { @@ -605,8 +603,8 @@ static int efi_block_match ( struct san_device *sandev, EFI_HANDLE handle, efi_image_handle, handle, EFI_OPEN_PROTOCOL_GET_PROTOCOL ))!=0){ rc = -EEFI ( efirc ); - DBGC ( sandev->drive, "EFIBLK %#02x could not open %s device " - "path: %s\n", sandev->drive, efi_handle_name ( handle ), + DBGC ( drive, "EFIBLK %#02x could not open %s device path: " + "%s\n", drive, efi_handle_name ( handle ), strerror ( rc ) ); goto err_open; } @@ -616,15 +614,15 @@ static int efi_block_match ( struct san_device *sandev, EFI_HANDLE handle, if ( memcmp ( u.path, path, efi_path_len ( path ) ) != 0 ) { /* Not a child device */ rc = -ENOTTY; - DBGC2 ( sandev->drive, "EFIBLK %#02x is not parent of %s\n", - sandev->drive, efi_handle_name ( handle ) ); + DBGC2 ( drive, "EFIBLK %#02x is not parent of %s\n", + drive, efi_handle_name ( handle ) ); goto err_not_child; } - DBGC ( sandev->drive, "EFIBLK %#02x contains filesystem %s\n", - sandev->drive, efi_devpath_text ( u.path ) ); + DBGC ( drive, "EFIBLK %#02x contains filesystem %s\n", + drive, efi_devpath_text ( u.path ) ); /* Check if filesystem contains boot filename */ - if ( ( rc = efi_block_filename ( sandev, handle, filename ) ) != 0 ) + if ( ( rc = efi_block_filename ( drive, handle, filename ) ) != 0 ) goto err_filename; /* Success */ @@ -640,15 +638,21 @@ static int efi_block_match ( struct san_device *sandev, EFI_HANDLE handle, /** * Scan EFI block device for a matching filesystem * - * @v sandev SAN device + * @v drive Drive number + * @v handle Block device handle * @v filename Filename (or NULL to use default) * @v fspath Filesystem device path to fill in * @ret rc Return status code */ -static int efi_block_scan ( struct san_device *sandev, const char *filename, +static int efi_block_scan ( unsigned int drive, EFI_HANDLE handle, + const char *filename, EFI_DEVICE_PATH_PROTOCOL **fspath ) { EFI_BOOT_SERVICES *bs = efi_systab->BootServices; - struct efi_block_data *block = sandev->priv; + EFI_GUID *protocol = &efi_device_path_protocol_guid; + union { + EFI_DEVICE_PATH_PROTOCOL *path; + void *interface; + } u; EFI_HANDLE *handles; UINTN count; unsigned int i; @@ -656,15 +660,25 @@ static int efi_block_scan ( struct san_device *sandev, const char *filename, int rc; /* Connect up possible file system drivers */ - efi_block_connect ( sandev ); + efi_block_connect ( drive, handle ); + + /* Identify device path */ + if ( ( efirc = bs->OpenProtocol ( handle, protocol, &u.interface, + efi_image_handle, handle, + EFI_OPEN_PROTOCOL_GET_PROTOCOL ))!=0){ + rc = -EEFI ( efirc ); + DBGC ( drive, "EFIBLK %#02x could not open device path: %s\n", + drive, strerror ( rc ) ); + goto err_open; + } /* Locate all Simple File System protocol handles */ if ( ( efirc = bs->LocateHandleBuffer ( ByProtocol, &efi_simple_file_system_protocol_guid, NULL, &count, &handles ) ) != 0 ) { rc = -EEFI ( efirc ); - DBGC ( sandev->drive, "EFIBLK %#02x cannot locate file " - "systems: %s\n", sandev->drive, strerror ( rc ) ); + DBGC ( drive, "EFIBLK %#02x cannot locate file systems: %s\n", + drive, strerror ( rc ) ); goto err_locate; } @@ -673,7 +687,7 @@ static int efi_block_scan ( struct san_device *sandev, const char *filename, for ( i = 0 ; i < count ; i++ ) { /* Check for a matching filesystem */ - if ( ( rc = efi_block_match ( sandev, handles[i], block->path, + if ( ( rc = efi_block_match ( drive, handles[i], u.path, filename, fspath ) ) != 0 ) continue; @@ -682,18 +696,20 @@ static int efi_block_scan ( struct san_device *sandev, const char *filename, bs->FreePool ( handles ); err_locate: + bs->CloseProtocol ( handle, protocol, efi_image_handle, handle ); + err_open: return rc; } /** * Boot from EFI block device filesystem boot image * - * @v sandev SAN device + * @v drive Drive number * @v fspath Filesystem device path * @v filename Filename (or NULL to use default) * @ret rc Return status code */ -static int efi_block_exec ( struct san_device *sandev, +static int efi_block_exec ( unsigned int drive, EFI_DEVICE_PATH_PROTOCOL *fspath, const char *filename ) { EFI_BOOT_SERVICES *bs = efi_systab->BootServices; @@ -735,16 +751,16 @@ static int efi_block_exec ( struct san_device *sandev, } end = ( ( ( void * ) filepath ) + filepath_len ); efi_path_terminate ( end ); - DBGC ( sandev->drive, "EFIBLK %#02x trying to load %s\n", - sandev->drive, efi_devpath_text ( path ) ); + DBGC ( drive, "EFIBLK %#02x trying to load %s\n", + drive, efi_devpath_text ( path ) ); /* Load image */ image = NULL; if ( ( efirc = bs->LoadImage ( FALSE, efi_image_handle, path, NULL, 0, &image ) ) != 0 ) { rc = -EEFI ( efirc ); - DBGC ( sandev->drive, "EFIBLK %#02x could not load: %s\n", - sandev->drive, strerror ( rc ) ); + DBGC ( drive, "EFIBLK %#02x could not load: %s\n", + drive, strerror ( rc ) ); if ( efirc == EFI_SECURITY_VIOLATION ) { goto err_load_security_violation; } else { @@ -755,8 +771,8 @@ static int efi_block_exec ( struct san_device *sandev, /* Start image */ efirc = bs->StartImage ( image, NULL, NULL ); rc = ( efirc ? -EEFI ( efirc ) : 0 ); - DBGC ( sandev->drive, "EFIBLK %#02x boot image returned: %s\n", - sandev->drive, strerror ( rc ) ); + DBGC ( drive, "EFIBLK %#02x boot image returned: %s\n", + drive, strerror ( rc ) ); err_load_security_violation: bs->UnloadImage ( image ); @@ -776,6 +792,7 @@ static int efi_block_exec ( struct san_device *sandev, static int efi_block_boot ( unsigned int drive, const char *filename ) { EFI_DEVICE_PATH_PROTOCOL *fspath = NULL; struct san_device *sandev; + struct efi_block_data *block; int rc; /* Find SAN device */ @@ -785,17 +802,19 @@ static int efi_block_boot ( unsigned int drive, const char *filename ) { rc = -ENODEV; goto err_sandev_find; } + block = sandev->priv; /* Release SNP devices */ efi_snp_release(); /* Scan for a matching filesystem within this block device */ - if ( ( rc = efi_block_scan ( sandev, filename, &fspath ) ) != 0 ) { + if ( ( rc = efi_block_scan ( drive, block->handle, filename, + &fspath ) ) != 0 ) { goto err_scan; } /* Attempt to boot from this filesystem */ - if ( ( rc = efi_block_exec ( sandev, fspath, filename ) ) != 0 ) + if ( ( rc = efi_block_exec ( drive, fspath, filename ) ) != 0 ) goto err_exec; err_exec: -- cgit v1.2.3-55-g7522 From 8da22a59eecda30087504efa2153ceddacda08fd Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Tue, 5 Mar 2024 12:50:25 +0000 Subject: [block] Allow for iteration over SAN device list in drive number order Maintain the SAN device list in order of drive number, and provide sandev_next() to locate the first SAN device at or above a given drive number. Signed-off-by: Michael Brown --- src/core/sanboot.c | 25 +++++++++++++++++++++++-- src/include/ipxe/sanboot.h | 1 + 2 files changed, 24 insertions(+), 2 deletions(-) diff --git a/src/core/sanboot.c b/src/core/sanboot.c index 7e3a09e4..5b7a2165 100644 --- a/src/core/sanboot.c +++ b/src/core/sanboot.c @@ -107,6 +107,22 @@ struct san_device * sandev_find ( unsigned int drive ) { return NULL; } +/** + * Find next SAN device by drive number + * + * @v drive Minimum drive number + * @ret sandev SAN device, or NULL + */ +struct san_device * sandev_next ( unsigned int drive ) { + struct san_device *sandev; + + list_for_each_entry ( sandev, &san_devices, list ) { + if ( sandev->drive >= drive ) + return sandev; + } + return NULL; +} + /** * Free SAN device * @@ -870,6 +886,7 @@ struct san_device * alloc_sandev ( struct uri **uris, unsigned int count, */ int register_sandev ( struct san_device *sandev, unsigned int drive, unsigned int flags ) { + struct san_device *before; int rc; /* Check that drive number is not in use */ @@ -903,8 +920,12 @@ int register_sandev ( struct san_device *sandev, unsigned int drive, if ( ( rc = sandev_parse_iso9660 ( sandev ) ) != 0 ) goto err_iso9660; - /* Add to list of SAN devices */ - list_add_tail ( &sandev->list, &san_devices ); + /* Add to list of SAN devices, in drive order */ + for_each_sandev ( before ) { + if ( before->drive > sandev->drive ) + break; + } + list_add_tail ( &sandev->list, &before->list ); DBGC ( sandev->drive, "SAN %#02x registered\n", sandev->drive ); return 0; diff --git a/src/include/ipxe/sanboot.h b/src/include/ipxe/sanboot.h index b163a94b..a1b6d7f3 100644 --- a/src/include/ipxe/sanboot.h +++ b/src/include/ipxe/sanboot.h @@ -234,6 +234,7 @@ static inline int sandev_needs_reopen ( struct san_device *sandev ) { } extern struct san_device * sandev_find ( unsigned int drive ); +extern struct san_device * sandev_next ( unsigned int drive ); extern int sandev_reopen ( struct san_device *sandev ); extern int sandev_reset ( struct san_device *sandev ); extern int sandev_read ( struct san_device *sandev, uint64_t lba, -- cgit v1.2.3-55-g7522 From b1c13cc43ece3008f7012cf736fc943d5bb89131 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Tue, 5 Mar 2024 12:54:44 +0000 Subject: [efi] Allow booting from local disks via the "sanboot" command Extend the EFI SAN boot code to allow for booting from a local disk, as is already possible with the BIOS SAN boot code. There is unfortunately no direct UEFI equivalent of the BIOS drive number. The UEFI shell does provide numbered mappings fs0:, blk0:, etc, but these numberings exist only while the UEFI shell is running and are not necessarily stable between shell invocations or across reboots. A substantial amount of existing third-party documentation for iPXE will suggest using "sanboot --drive 0x80" to boot from a local disk (when no SAN drives are present), since this suggestion has been present in the official documentation for the "sanboot" command for almost thirteen years. We therefore aim to ensure that this instruction will also work for UEFI, i.e. that in a situation where there are local disks but no SAN disks, then the first local disk will be treated as being drive 0x80. We therefore assign local disks the virtual drive numbers 0x80, 0x81, etc, matching the numbering typically used in a BIOS environment. Where a SAN disk is already occupying one of these drive numbers, the local disks' virtual drive numbers will be incremented as necessary. This provides a rough approximation of the equivalent functionality under BIOS, where existing local disks' drive numbers are remapped to make way for SAN disks. We do not make any attempt to sort the list of local disks: the order used for allocating virtual drive numbers will be whatever order is returned by LocateHandle(). This will typically match the creation order of the EFI handles, which will typically match the hardware enumeration order of the devices, which will typically match user expectations as to which local disk is first, second, etc. We explicitly do not attempt to match the numbering used by the UEFI shell (which initially sorts in increasing order of device path, but does not renumber when new devices are added or removed). We can never guarantee matching this partly transient UEFI shell numbering, so it is best not to set any expectation that it will be matched. (Using local drive numbers starting at 0x80 helps to avoid setting up this impossible expectation, since the UEFI shell uses local drive numbers starting at zero.) Since floppy disks are essentially non-existent in any plausible UEFI system, overload "--drive 0" to mean "boot from any drive containing the specified (or default) boot filename". Signed-off-by: Michael Brown --- src/core/sanboot.c | 10 --- src/include/ipxe/sanboot.h | 10 +++ src/interface/efi/efi_block.c | 177 +++++++++++++++++++++++++++++++++++++----- 3 files changed, 166 insertions(+), 31 deletions(-) diff --git a/src/core/sanboot.c b/src/core/sanboot.c index 5b7a2165..e49a3f92 100644 --- a/src/core/sanboot.c +++ b/src/core/sanboot.c @@ -44,16 +44,6 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #include #include -/** - * Default SAN drive number - * - * The drive number is a meaningful concept only in a BIOS - * environment, where it represents the INT13 drive number (0x80 for - * the first hard disk). We retain it in other environments to allow - * for a simple way for iPXE commands to refer to SAN drives. - */ -#define SAN_DEFAULT_DRIVE 0x80 - /** * Timeout for block device commands (in ticks) * diff --git a/src/include/ipxe/sanboot.h b/src/include/ipxe/sanboot.h index a1b6d7f3..b11197f9 100644 --- a/src/include/ipxe/sanboot.h +++ b/src/include/ipxe/sanboot.h @@ -21,6 +21,16 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #include #include +/** + * Default SAN drive number + * + * The drive number is an externally defined concept only in a BIOS + * environment, where it represents the INT13 drive number (0x80 for + * the first hard disk). We retain it in other environments to allow + * for a simple way for iPXE commands to refer to SAN drives. + */ +#define SAN_DEFAULT_DRIVE 0x80 + /** A SAN path */ struct san_path { /** Containing SAN device */ diff --git a/src/interface/efi/efi_block.c b/src/interface/efi/efi_block.c index 79ef7455..11d11156 100644 --- a/src/interface/efi/efi_block.c +++ b/src/interface/efi/efi_block.c @@ -299,8 +299,8 @@ static int efi_block_hook ( unsigned int drive, struct uri **uris, DBGC ( drive, "EFIBLK %#02x has no device path\n", drive ); goto err_describe; } - DBGC ( drive, "EFIBLK %#02x has device path %s\n", - drive, efi_devpath_text ( block->path ) ); + DBGC2 ( drive, "EFIBLK %#02x has device path %s\n", + drive, efi_devpath_text ( block->path ) ); /* Install protocols */ if ( ( efirc = bs->InstallMultipleProtocolInterfaces ( @@ -313,6 +313,8 @@ static int efi_block_hook ( unsigned int drive, struct uri **uris, drive, strerror ( rc ) ); goto err_install; } + DBGC ( drive, "EFIBLK %#02x installed as SAN drive %s\n", + drive, efi_handle_name ( block->handle ) ); /* Connect all possible protocols */ efi_block_connect ( drive, block->handle ); @@ -782,6 +784,65 @@ static int efi_block_exec ( unsigned int drive, return rc; } +/** + * Check that EFI block device is eligible for a local virtual drive number + * + * @v handle Block device handle + * @ret rc Return status code + * + * We assign virtual drive numbers for local (non-SAN) EFI block + * devices that represent complete disks, to provide roughly + * equivalent functionality to BIOS drive numbers. + */ +static int efi_block_local ( EFI_HANDLE handle ) { + EFI_BOOT_SERVICES *bs = efi_systab->BootServices; + EFI_GUID *protocol = &efi_block_io_protocol_guid; + struct san_device *sandev; + struct efi_block_data *block; + union { + EFI_BLOCK_IO_PROTOCOL *blockio; + void *interface; + } u; + EFI_STATUS efirc; + int rc; + + /* Check if handle belongs to a SAN device */ + for_each_sandev ( sandev ) { + block = sandev->priv; + if ( handle == block->handle ) { + rc = -ENOTTY; + goto err_sandev; + } + } + + /* Open block I/O protocol */ + if ( ( efirc = bs->OpenProtocol ( handle, protocol, &u.interface, + efi_image_handle, handle, + EFI_OPEN_PROTOCOL_GET_PROTOCOL ))!=0){ + rc = -EEFI ( efirc ); + DBGC ( handle, "EFIBLK %s could not open block I/O: %s\n", + efi_handle_name ( handle ), strerror ( rc ) ); + goto err_open; + } + + /* Do not assign drive numbers for partitions */ + if ( u.blockio->Media->LogicalPartition ) { + rc = -ENOTTY; + DBGC2 ( handle, "EFLBLK %s is a partition\n", + efi_handle_name ( handle ) ); + goto err_partition; + } + + /* Success */ + rc = 0; + + err_partition: + bs->CloseProtocol ( handle, protocol, efi_image_handle, handle ); + err_open: + err_sandev: + return rc; +} + /** * Boot from EFI block device * @@ -790,37 +851,111 @@ static int efi_block_exec ( unsigned int drive, * @ret rc Return status code */ static int efi_block_boot ( unsigned int drive, const char *filename ) { + EFI_BOOT_SERVICES *bs = efi_systab->BootServices; EFI_DEVICE_PATH_PROTOCOL *fspath = NULL; + EFI_HANDLE *handles; + EFI_HANDLE handle; + UINTN count; struct san_device *sandev; struct efi_block_data *block; + unsigned int vdrive; + unsigned int index; + EFI_STATUS efirc; int rc; - /* Find SAN device */ - sandev = sandev_find ( drive ); - if ( ! sandev ) { - DBGC ( drive, "EFIBLK %#02x is not a SAN drive\n", drive ); - rc = -ENODEV; - goto err_sandev_find; - } - block = sandev->priv; - /* Release SNP devices */ efi_snp_release(); - /* Scan for a matching filesystem within this block device */ - if ( ( rc = efi_block_scan ( drive, block->handle, filename, - &fspath ) ) != 0 ) { - goto err_scan; + /* Locate all block I/O protocol handles */ + if ( ( efirc = bs->LocateHandleBuffer ( ByProtocol, + &efi_block_io_protocol_guid, + NULL, &count, + &handles ) ) != 0 ) { + rc = -EEFI ( efirc ); + DBGC ( drive, "EFIBLK %#02x cannot locate block I/O: %s\n", + drive, strerror ( rc ) ); + goto err_locate_block_io; } - /* Attempt to boot from this filesystem */ - if ( ( rc = efi_block_exec ( drive, fspath, filename ) ) != 0 ) - goto err_exec; + /* Try booting from the first matching block device, if any */ + rc = -ENOENT; + for ( vdrive = 0, index = 0 ; ; vdrive++ ) { + + /* Identify next drive number and block I/O handle */ + if ( ( sandev = sandev_next ( vdrive ) ) && + ( ( sandev->drive == vdrive ) || + ( sandev->drive <= SAN_DEFAULT_DRIVE ) || + ( index >= count ) ) ) { + + /* There is a SAN drive that either: + * + * a) has the current virtual drive number, or + * b) has a drive number below SAN_DEFAULT_DRIVE, or + * c) has a drive number higher than any local drive + * + * Use this SAN drive, since the explicit SAN + * drive numbering takes precedence over the + * implicit local drive numbering. + */ + block = sandev->priv; + handle = block->handle; + + /* Use SAN drive's explicit drive number */ + vdrive = sandev->drive; + DBGC ( vdrive, "EFIBLK %#02x is SAN drive %s\n", + vdrive, efi_handle_name ( handle ) ); + + } else if ( index < count ) { + + /* There is no SAN drive meeting any of the + * above criteria. Try the next block I/O + * handle. + */ + handle = handles[index++]; + + /* Check if this handle is eligible to be + * given a local virtual drive number. + */ + if ( ( rc = efi_block_local ( handle ) ) != 0 ) { + /* Do not consume virtual drive number */ + vdrive--; + continue; + } + + /* Use the current virtual drive number, with + * a minimum of SAN_DEFAULT_DRIVE to match + * typical BIOS drive numbering. + */ + if ( vdrive < SAN_DEFAULT_DRIVE ) + vdrive = SAN_DEFAULT_DRIVE; + DBGC ( vdrive, "EFIBLK %#02x is local drive %s\n", + vdrive, efi_handle_name ( handle ) ); + + } else { + + /* No more SAN or local drives */ + break; + } + + /* Skip non-matching drives */ + if ( drive && ( drive != vdrive ) ) + continue; + DBGC ( vdrive, "EFIBLK %#02x attempting to boot\n", vdrive ); + + /* Scan for a matching filesystem within this drive */ + if ( ( rc = efi_block_scan ( vdrive, handle, filename, + &fspath ) ) != 0 ) { + continue; + } - err_exec: - err_scan: + /* Attempt to boot from the matched filesystem */ + rc = efi_block_exec ( vdrive, fspath, filename ); + break; + } + + bs->FreePool ( handles ); + err_locate_block_io: efi_snp_claim(); - err_sandev_find: return rc; } -- cgit v1.2.3-55-g7522 From 636ccb4ca55c73841e634f9d5986087fb3565da4 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Tue, 5 Mar 2024 20:20:10 +0000 Subject: [block] Allow for additional SAN boot parameters alongside filename The drive specification alone does not necessarily contain enough information to perform a SAN boot (or local disk boot) under UEFI. If the next-stage bootloader is installed in the EFI system partition under a non-standard name (e.g. "\EFI\debian\grubx64.efi") then this explicit boot filename must also be specified. Generalise this concept to use a "SAN boot configuration parameters" structure (currently containing only the optional explicit boot filename), to allow for easy expansion to provide other parameters such as the partition UUID or volume label. Signed-off-by: Michael Brown --- src/arch/x86/interface/pcbios/int13.c | 5 +++-- src/core/dummy_sanboot.c | 4 ++-- src/core/null_sanboot.c | 2 +- src/hci/commands/sanboot_cmd.c | 6 +++++- src/include/ipxe/sanboot.h | 10 ++++++++-- src/include/usr/autoboot.h | 3 ++- src/interface/efi/efi_block.c | 23 +++++++++++++---------- src/usr/autoboot.c | 15 +++++++++++---- 8 files changed, 45 insertions(+), 23 deletions(-) diff --git a/src/arch/x86/interface/pcbios/int13.c b/src/arch/x86/interface/pcbios/int13.c index 2c5e8624..372d40ba 100644 --- a/src/arch/x86/interface/pcbios/int13.c +++ b/src/arch/x86/interface/pcbios/int13.c @@ -1511,7 +1511,7 @@ static int int13_load_eltorito ( unsigned int drive, struct segoff *address ) { * Attempt to boot from an INT 13 drive * * @v drive Drive number - * @v filename Filename (or NULL to use default) + * @v config Boot configuration parameters * @ret rc Return status code * * This boots from the specified INT 13 drive by loading the Master @@ -1521,7 +1521,8 @@ static int int13_load_eltorito ( unsigned int drive, struct segoff *address ) { * * Note that this function can never return success, by definition. */ -static int int13_boot ( unsigned int drive, const char *filename __unused ) { +static int int13_boot ( unsigned int drive, + struct san_boot_config *config __unused ) { struct memory_map memmap; struct segoff address; int rc; diff --git a/src/core/dummy_sanboot.c b/src/core/dummy_sanboot.c index 506b20c1..e22998da 100644 --- a/src/core/dummy_sanboot.c +++ b/src/core/dummy_sanboot.c @@ -95,11 +95,11 @@ static void dummy_san_unhook ( unsigned int drive ) { * Boot from dummy SAN device * * @v drive Drive number - * @v filename Filename (or NULL to use default) + * @v config Boot configuration parameters * @ret rc Return status code */ static int dummy_san_boot ( unsigned int drive __unused, - const char *filename __unused ) { + struct san_boot_config *config __unused ) { return -EOPNOTSUPP; } diff --git a/src/core/null_sanboot.c b/src/core/null_sanboot.c index 7c0680f5..2340cd2a 100644 --- a/src/core/null_sanboot.c +++ b/src/core/null_sanboot.c @@ -38,7 +38,7 @@ static void null_san_unhook ( unsigned int drive __unused ) { } static int null_san_boot ( unsigned int drive __unused, - const char *filename __unused ) { + struct san_boot_config *config __unused ) { return -EOPNOTSUPP; } diff --git a/src/hci/commands/sanboot_cmd.c b/src/hci/commands/sanboot_cmd.c index 3907276a..9c7e9ab7 100644 --- a/src/hci/commands/sanboot_cmd.c +++ b/src/hci/commands/sanboot_cmd.c @@ -100,6 +100,7 @@ static int sanboot_core_exec ( int argc, char **argv, struct command_descriptor *cmd, int default_flags, int no_root_path_flags ) { struct sanboot_options opts; + struct san_boot_config config; struct uri *uris[argc]; int count; int flags; @@ -124,6 +125,9 @@ static int sanboot_core_exec ( int argc, char **argv, } } + /* Construct configuration parameters */ + config.filename = opts.filename; + /* Construct flags */ flags = default_flags; if ( opts.no_describe ) @@ -134,7 +138,7 @@ static int sanboot_core_exec ( int argc, char **argv, flags |= no_root_path_flags; /* Boot from root path */ - if ( ( rc = uriboot ( NULL, uris, count, opts.drive, opts.filename, + if ( ( rc = uriboot ( NULL, uris, count, opts.drive, &config, flags ) ) != 0 ) goto err_uriboot; diff --git a/src/include/ipxe/sanboot.h b/src/include/ipxe/sanboot.h index b11197f9..d981226e 100644 --- a/src/include/ipxe/sanboot.h +++ b/src/include/ipxe/sanboot.h @@ -105,6 +105,12 @@ enum san_device_flags { SAN_NO_DESCRIBE = 0x0001, }; +/** SAN boot configuration parameters */ +struct san_boot_config { + /** Boot filename (or NULL to use default) */ + const char *filename; +}; + /** * Calculate static inline sanboot API function name * @@ -165,10 +171,10 @@ void san_unhook ( unsigned int drive ); * Attempt to boot from a SAN device * * @v drive Drive number - * @v filename Filename (or NULL to use default) + * @v config Boot configuration parameters * @ret rc Return status code */ -int san_boot ( unsigned int drive, const char *filename ); +int san_boot ( unsigned int drive, struct san_boot_config *config ); /** * Describe SAN devices for SAN-booted operating system diff --git a/src/include/usr/autoboot.h b/src/include/usr/autoboot.h index 3719b824..a081a70d 100644 --- a/src/include/usr/autoboot.h +++ b/src/include/usr/autoboot.h @@ -14,6 +14,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); struct net_device; struct uri; struct settings; +struct san_boot_config; /** uriboot() flags */ enum uriboot_flags { @@ -33,7 +34,7 @@ extern void set_autoboot_ll_addr ( const void *ll_addr, size_t len, extern int uriboot ( struct uri *filename, struct uri **root_paths, unsigned int root_path_count, int drive, - const char *san_filename, unsigned int flags ); + struct san_boot_config *san_config, unsigned int flags ); extern struct uri * fetch_next_server_and_filename ( struct settings *settings ); extern int netboot ( struct net_device *netdev ); diff --git a/src/interface/efi/efi_block.c b/src/interface/efi/efi_block.c index 11d11156..e81d6bb7 100644 --- a/src/interface/efi/efi_block.c +++ b/src/interface/efi/efi_block.c @@ -583,13 +583,13 @@ static int efi_block_filename ( unsigned int drive, EFI_HANDLE handle, * @v drive Drive number * @v handle Filesystem handle * @v path Block device path - * @v filename Filename (or NULL to use default) + * @v config Boot configuration parameters * @v fspath Filesystem device path to fill in * @ret rc Return status code */ static int efi_block_match ( unsigned int drive, EFI_HANDLE handle, EFI_DEVICE_PATH_PROTOCOL *path, - const char *filename, + struct san_boot_config *config, EFI_DEVICE_PATH_PROTOCOL **fspath ) { EFI_BOOT_SERVICES *bs = efi_systab->BootServices; EFI_GUID *protocol = &efi_device_path_protocol_guid; @@ -624,8 +624,10 @@ static int efi_block_match ( unsigned int drive, EFI_HANDLE handle, drive, efi_devpath_text ( u.path ) ); /* Check if filesystem contains boot filename */ - if ( ( rc = efi_block_filename ( drive, handle, filename ) ) != 0 ) + if ( ( rc = efi_block_filename ( drive, handle, + config->filename ) ) != 0 ) { goto err_filename; + } /* Success */ rc = 0; @@ -642,12 +644,12 @@ static int efi_block_match ( unsigned int drive, EFI_HANDLE handle, * * @v drive Drive number * @v handle Block device handle - * @v filename Filename (or NULL to use default) + * @v config Boot configuration parameters * @v fspath Filesystem device path to fill in * @ret rc Return status code */ static int efi_block_scan ( unsigned int drive, EFI_HANDLE handle, - const char *filename, + struct san_boot_config *config, EFI_DEVICE_PATH_PROTOCOL **fspath ) { EFI_BOOT_SERVICES *bs = efi_systab->BootServices; EFI_GUID *protocol = &efi_device_path_protocol_guid; @@ -690,7 +692,7 @@ static int efi_block_scan ( unsigned int drive, EFI_HANDLE handle, /* Check for a matching filesystem */ if ( ( rc = efi_block_match ( drive, handles[i], u.path, - filename, fspath ) ) != 0 ) + config, fspath ) ) != 0 ) continue; break; @@ -847,10 +849,11 @@ static int efi_block_local ( EFI_HANDLE handle ) { * Boot from EFI block device * * @v drive Drive number - * @v filename Filename (or NULL to use default) + * @v config Boot configuration parameters * @ret rc Return status code */ -static int efi_block_boot ( unsigned int drive, const char *filename ) { +static int efi_block_boot ( unsigned int drive, + struct san_boot_config *config ) { EFI_BOOT_SERVICES *bs = efi_systab->BootServices; EFI_DEVICE_PATH_PROTOCOL *fspath = NULL; EFI_HANDLE *handles; @@ -943,13 +946,13 @@ static int efi_block_boot ( unsigned int drive, const char *filename ) { DBGC ( vdrive, "EFIBLK %#02x attempting to boot\n", vdrive ); /* Scan for a matching filesystem within this drive */ - if ( ( rc = efi_block_scan ( vdrive, handle, filename, + if ( ( rc = efi_block_scan ( vdrive, handle, config, &fspath ) ) != 0 ) { continue; } /* Attempt to boot from the matched filesystem */ - rc = efi_block_exec ( vdrive, fspath, filename ); + rc = efi_block_exec ( vdrive, fspath, config->filename ); break; } diff --git a/src/usr/autoboot.c b/src/usr/autoboot.c index d1f25962..4b64ca82 100644 --- a/src/usr/autoboot.c +++ b/src/usr/autoboot.c @@ -116,7 +116,7 @@ const struct setting skip_san_boot_setting __setting ( SETTING_SANBOOT_EXTRA, * @v root_paths Root path(s) * @v root_path_count Number of root paths * @v drive SAN drive (if applicable) - * @v san_filename SAN filename (or NULL to use default) + * @v san_config SAN boot configuration parameters * @v flags Boot action flags * @ret rc Return status code * @@ -128,8 +128,9 @@ const struct setting skip_san_boot_setting __setting ( SETTING_SANBOOT_EXTRA, */ int uriboot ( struct uri *filename, struct uri **root_paths, unsigned int root_path_count, int drive, - const char *san_filename, unsigned int flags ) { + struct san_boot_config *san_config, unsigned int flags ) { struct image *image; + const char *san_filename; int rc; /* Hook SAN device, if applicable */ @@ -182,11 +183,12 @@ int uriboot ( struct uri *filename, struct uri **root_paths, /* Attempt SAN boot if applicable */ if ( ! ( flags & URIBOOT_NO_SAN_BOOT ) ) { + san_filename = san_config->filename; if ( fetch_intz_setting ( NULL, &skip_san_boot_setting) == 0 ) { printf ( "Booting%s%s from SAN device %#02x\n", ( san_filename ? " " : "" ), ( san_filename ? san_filename : "" ), drive ); - rc = san_boot ( drive, san_filename ); + rc = san_boot ( drive, san_config ); printf ( "Boot from SAN device %#02x failed: %s\n", drive, strerror ( rc ) ); } else { @@ -387,6 +389,7 @@ static int have_pxe_menu ( void ) { * @ret rc Return status code */ int netboot ( struct net_device *netdev ) { + struct san_boot_config san_config; struct uri *filename; struct uri *root_path; char *san_filename; @@ -421,6 +424,10 @@ int netboot ( struct net_device *netdev ) { /* Fetch SAN filename (if any) */ san_filename = fetch_san_filename ( NULL ); + /* Construct SAN boot configuration parameters */ + memset ( &san_config, 0, sizeof ( san_config ) ); + san_config.filename = san_filename; + /* If we have both a filename and a root path, ignore an * unsupported or missing URI scheme in the root path, since * it may represent an NFS root. @@ -442,7 +449,7 @@ int netboot ( struct net_device *netdev ) { /* Boot using next server, filename and root path */ if ( ( rc = uriboot ( filename, &root_path, ( root_path ? 1 : 0 ), - san_default_drive(), san_filename, + san_default_drive(), &san_config, ( root_path ? 0 : URIBOOT_NO_SAN ) ) ) != 0 ) goto err_uriboot; -- cgit v1.2.3-55-g7522 From c4471e3408d85c51a69991974985fe283d869eac Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Tue, 5 Mar 2024 20:00:15 +0000 Subject: [efi] Add efi_path_guid() utility function EFI provides no API for determining the partition GUID (if any) for a specified device handle. The partition GUID appears to be exposed only as part of the device path. Add efi_path_guid() to extract the partition GUID (if any) from a device path. Signed-off-by: Michael Brown --- src/include/ipxe/efi/efi_path.h | 2 ++ src/include/ipxe/errfile.h | 1 + src/interface/efi/efi_path.c | 43 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 46 insertions(+) diff --git a/src/include/ipxe/efi/efi_path.h b/src/include/ipxe/efi/efi_path.h index e75ae42c..20ff43f6 100644 --- a/src/include/ipxe/efi/efi_path.h +++ b/src/include/ipxe/efi/efi_path.h @@ -20,6 +20,7 @@ struct aoe_device; struct fcp_description; struct ib_srp_device; struct usb_function; +union uuid; /** * Terminate device path @@ -43,6 +44,7 @@ extern EFI_DEVICE_PATH_PROTOCOL * efi_path_end ( EFI_DEVICE_PATH_PROTOCOL *path ); extern size_t efi_path_len ( EFI_DEVICE_PATH_PROTOCOL *path ); extern unsigned int efi_path_vlan ( EFI_DEVICE_PATH_PROTOCOL *path ); +extern int efi_path_guid ( EFI_DEVICE_PATH_PROTOCOL *path, union uuid *uuid ); extern EFI_DEVICE_PATH_PROTOCOL * efi_paths ( EFI_DEVICE_PATH_PROTOCOL *first, ... ); extern EFI_DEVICE_PATH_PROTOCOL * efi_netdev_path ( struct net_device *netdev ); diff --git a/src/include/ipxe/errfile.h b/src/include/ipxe/errfile.h index 7cff594d..1fe34113 100644 --- a/src/include/ipxe/errfile.h +++ b/src/include/ipxe/errfile.h @@ -80,6 +80,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #define ERRFILE_acpimac ( ERRFILE_CORE | 0x00280000 ) #define ERRFILE_efi_strings ( ERRFILE_CORE | 0x00290000 ) #define ERRFILE_uuid ( ERRFILE_CORE | 0x002a0000 ) +#define ERRFILE_efi_path ( ERRFILE_CORE | 0x002b0000 ) #define ERRFILE_eisa ( ERRFILE_DRIVER | 0x00000000 ) #define ERRFILE_isa ( ERRFILE_DRIVER | 0x00010000 ) diff --git a/src/interface/efi/efi_path.c b/src/interface/efi/efi_path.c index a78f97fc..d1e22eea 100644 --- a/src/interface/efi/efi_path.c +++ b/src/interface/efi/efi_path.c @@ -22,9 +22,11 @@ FILE_LICENCE ( GPL2_OR_LATER ); #include #include #include +#include #include #include #include +#include #include #include #include @@ -132,6 +134,47 @@ unsigned int efi_path_vlan ( EFI_DEVICE_PATH_PROTOCOL *path ) { return 0; } +/** + * Get partition GUID from device path + * + * @v path Device path + * @v guid Partition GUID to fill in + * @ret rc Return status code + */ +int efi_path_guid ( EFI_DEVICE_PATH_PROTOCOL *path, union uuid *guid ) { + EFI_DEVICE_PATH_PROTOCOL *next; + HARDDRIVE_DEVICE_PATH *hd; + int rc; + + /* Search for most specific partition device path */ + rc = -ENOENT; + for ( ; ( next = efi_path_next ( path ) ) ; path = next ) { + + /* Skip non-harddrive device paths */ + if ( path->Type != MEDIA_DEVICE_PATH ) + continue; + if ( path->SubType != MEDIA_HARDDRIVE_DP ) + continue; + + /* Skip non-GUID signatures */ + hd = container_of ( path, HARDDRIVE_DEVICE_PATH, Header ); + if ( hd->SignatureType != SIGNATURE_TYPE_GUID ) + continue; + + /* Extract GUID */ + memcpy ( guid, hd->Signature, sizeof ( *guid ) ); + uuid_mangle ( guid ); + + /* Record success, but continue searching in case + * there exists a more specific GUID (e.g. a partition + * GUID rather than a disk GUID). + */ + rc = 0; + } + + return rc; +} + /** * Concatenate EFI device paths * -- cgit v1.2.3-55-g7522 From cea22d76e4cfdbd2d5a3a29bd541346710760457 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Wed, 6 Mar 2024 08:55:55 +0000 Subject: [block] Allow SAN boot device to be identified by UUID Add a "--uuid" option which may be used to specify a boot device UUID, to be matched against the GPT partition GUID. Signed-off-by: Michael Brown --- src/core/parseopt.c | 7 ++++--- src/hci/commands/sanboot_cmd.c | 10 +++++++--- src/include/ipxe/parseopt.h | 10 +++++++++- src/include/ipxe/sanboot.h | 3 +++ src/interface/efi/efi_block.c | 18 ++++++++++++++++++ 5 files changed, 41 insertions(+), 7 deletions(-) diff --git a/src/core/parseopt.c b/src/core/parseopt.c index 7aff1485..8410e6e9 100644 --- a/src/core/parseopt.c +++ b/src/core/parseopt.c @@ -129,20 +129,21 @@ int parse_timeout ( char *text, unsigned long *value ) { * Parse UUID * * @v text Text - * @ret value UUID value + * @ret uuid UUID value * @ret rc Return status code */ -int parse_uuid ( char *text, union uuid *value ) { +int parse_uuid ( char *text, struct uuid_option *uuid ) { int rc; /* Sanity check */ assert ( text != NULL ); /* Parse UUID */ - if ( ( rc = uuid_aton ( text, value ) ) != 0 ) { + if ( ( rc = uuid_aton ( text, &uuid->buf ) ) != 0 ) { printf ( "\"%s\": invalid UUID\n", text ); return rc; } + uuid->value = &uuid->buf; return 0; } diff --git a/src/hci/commands/sanboot_cmd.c b/src/hci/commands/sanboot_cmd.c index 9c7e9ab7..b3d9ccad 100644 --- a/src/hci/commands/sanboot_cmd.c +++ b/src/hci/commands/sanboot_cmd.c @@ -49,12 +49,14 @@ struct sanboot_options { int keep; /** Filename */ char *filename; + /** UUID */ + struct uuid_option uuid; }; /** "sanboot" option list */ static union { - /* "sanboot" takes all four options */ - struct option_descriptor sanboot[4]; + /* "sanboot" takes all options */ + struct option_descriptor sanboot[5]; /* "sanhook" takes only --drive and --no-describe */ struct option_descriptor sanhook[2]; /* "sanunhook" takes only --drive */ @@ -69,10 +71,11 @@ static union { struct sanboot_options, keep, parse_flag ), OPTION_DESC ( "filename", 'f', required_argument, struct sanboot_options, filename, parse_string ), + OPTION_DESC ( "uuid", 'u', required_argument, + struct sanboot_options, uuid, parse_uuid ), }, }; - /** "sanhook" command descriptor */ static struct command_descriptor sanhook_cmd = COMMAND_DESC ( struct sanboot_options, opts.sanhook, 1, MAX_ARGUMENTS, @@ -127,6 +130,7 @@ static int sanboot_core_exec ( int argc, char **argv, /* Construct configuration parameters */ config.filename = opts.filename; + config.uuid = opts.uuid.value; /* Construct flags */ flags = default_flags; diff --git a/src/include/ipxe/parseopt.h b/src/include/ipxe/parseopt.h index ebd18804..61010f22 100644 --- a/src/include/ipxe/parseopt.h +++ b/src/include/ipxe/parseopt.h @@ -126,10 +126,18 @@ struct named_setting { struct setting setting; }; +/** A UUID command-line option */ +struct uuid_option { + /** UUID */ + union uuid *value; + /** Storage buffer */ + union uuid buf; +}; + extern int parse_string ( char *text, char **value ); extern int parse_integer ( char *text, unsigned int *value ); extern int parse_timeout ( char *text, unsigned long *value ); -extern int parse_uuid ( char *text, union uuid *value ); +extern int parse_uuid ( char *text, struct uuid_option *uuid ); extern int parse_netdev ( char *text, struct net_device **netdev ); extern int parse_netdev_configurator ( char *text, diff --git a/src/include/ipxe/sanboot.h b/src/include/ipxe/sanboot.h index d981226e..9841edda 100644 --- a/src/include/ipxe/sanboot.h +++ b/src/include/ipxe/sanboot.h @@ -19,6 +19,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #include #include #include +#include #include /** @@ -109,6 +110,8 @@ enum san_device_flags { struct san_boot_config { /** Boot filename (or NULL to use default) */ const char *filename; + /** UUID (or NULL to ignore UUID) */ + union uuid *uuid; }; /** diff --git a/src/interface/efi/efi_block.c b/src/interface/efi/efi_block.c index e81d6bb7..f5b913f1 100644 --- a/src/interface/efi/efi_block.c +++ b/src/interface/efi/efi_block.c @@ -597,6 +597,7 @@ static int efi_block_match ( unsigned int drive, EFI_HANDLE handle, EFI_DEVICE_PATH_PROTOCOL *path; void *interface; } u; + union uuid guid; EFI_STATUS efirc; int rc; @@ -623,6 +624,21 @@ static int efi_block_match ( unsigned int drive, EFI_HANDLE handle, DBGC ( drive, "EFIBLK %#02x contains filesystem %s\n", drive, efi_devpath_text ( u.path ) ); + /* Check if filesystem matches GUID, if applicable */ + if ( config->uuid ) { + if ( ( rc = efi_path_guid ( u.path, &guid ) ) != 0 ) { + DBGC ( drive, "EFIBLK %#02x could not determine GUID: " + "%s\n", drive, strerror ( rc ) ); + goto err_no_guid; + } + if ( memcmp ( config->uuid, &guid, sizeof ( guid ) ) != 0 ) { + DBGC ( drive, "EFIBLK %#02x has wrong GUID %s\n", + drive, uuid_ntoa ( &guid ) ); + rc = -ENOENT; + goto err_wrong_guid; + } + } + /* Check if filesystem contains boot filename */ if ( ( rc = efi_block_filename ( drive, handle, config->filename ) ) != 0 ) { @@ -633,6 +649,8 @@ static int efi_block_match ( unsigned int drive, EFI_HANDLE handle, rc = 0; err_filename: + err_wrong_guid: + err_no_guid: err_not_child: bs->CloseProtocol ( handle, protocol, efi_image_handle, handle ); err_open: -- cgit v1.2.3-55-g7522 From 62b6d363351fb5d8890cdcd36c949d6d8563b4e9 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Thu, 7 Mar 2024 13:31:29 +0000 Subject: [block] Allow SAN boot device to be identified by an extra filename Add an "--extra" option that can be used to specify an extra (non-boot) filename that must exist within the booted filesystem. Note that only files within the FAT-formatted bootable partition will be visible to this filter. Files within the operating system's root disk (e.g. "/etc/redhat-release") are not generally accessible to the firmware and so cannot be used as the existence check filter filename. Signed-off-by: Michael Brown --- src/hci/commands/sanboot_cmd.c | 9 ++++- src/include/ipxe/sanboot.h | 2 + src/interface/efi/efi_block.c | 85 +++++++++++++++++++++++++++++------------- 3 files changed, 68 insertions(+), 28 deletions(-) diff --git a/src/hci/commands/sanboot_cmd.c b/src/hci/commands/sanboot_cmd.c index b3d9ccad..add0756d 100644 --- a/src/hci/commands/sanboot_cmd.c +++ b/src/hci/commands/sanboot_cmd.c @@ -47,8 +47,10 @@ struct sanboot_options { int no_describe; /** Keep SAN device */ int keep; - /** Filename */ + /** Boot filename */ char *filename; + /** Required extra filename */ + char *extra; /** UUID */ struct uuid_option uuid; }; @@ -56,7 +58,7 @@ struct sanboot_options { /** "sanboot" option list */ static union { /* "sanboot" takes all options */ - struct option_descriptor sanboot[5]; + struct option_descriptor sanboot[6]; /* "sanhook" takes only --drive and --no-describe */ struct option_descriptor sanhook[2]; /* "sanunhook" takes only --drive */ @@ -71,6 +73,8 @@ static union { struct sanboot_options, keep, parse_flag ), OPTION_DESC ( "filename", 'f', required_argument, struct sanboot_options, filename, parse_string ), + OPTION_DESC ( "extra", 'e', required_argument, + struct sanboot_options, extra, parse_string ), OPTION_DESC ( "uuid", 'u', required_argument, struct sanboot_options, uuid, parse_uuid ), }, @@ -130,6 +134,7 @@ static int sanboot_core_exec ( int argc, char **argv, /* Construct configuration parameters */ config.filename = opts.filename; + config.extra = opts.extra; config.uuid = opts.uuid.value; /* Construct flags */ diff --git a/src/include/ipxe/sanboot.h b/src/include/ipxe/sanboot.h index 9841edda..91c848b0 100644 --- a/src/include/ipxe/sanboot.h +++ b/src/include/ipxe/sanboot.h @@ -110,6 +110,8 @@ enum san_device_flags { struct san_boot_config { /** Boot filename (or NULL to use default) */ const char *filename; + /** Required extra filename (or NULL to ignore) */ + const char *extra; /** UUID (or NULL to ignore UUID) */ union uuid *uuid; }; diff --git a/src/interface/efi/efi_block.c b/src/interface/efi/efi_block.c index f5b913f1..269b9abd 100644 --- a/src/interface/efi/efi_block.c +++ b/src/interface/efi/efi_block.c @@ -506,55 +506,77 @@ static int efi_block_describe ( void ) { } /** - * Check for existence of a file within a filesystem + * Open root directory within a filesystem * * @v drive Drive number * @v handle Filesystem handle - * @v filename Filename (or NULL to use default) + * @v root Root directory file to fill in * @ret rc Return status code */ -static int efi_block_filename ( unsigned int drive, EFI_HANDLE handle, - const char *filename ) { +static int efi_block_root ( unsigned int drive, EFI_HANDLE handle, + EFI_FILE_PROTOCOL **root ) { EFI_BOOT_SERVICES *bs = efi_systab->BootServices; EFI_GUID *protocol = &efi_simple_file_system_protocol_guid; - CHAR16 tmp[ filename ? ( strlen ( filename ) + 1 /* wNUL */ ) : 0 ]; union { EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *fs; void *interface; } u; - CHAR16 *wname; - EFI_FILE_PROTOCOL *root; - EFI_FILE_PROTOCOL *file; EFI_STATUS efirc; int rc; - /* Construct filename */ - if ( filename ) { - efi_snprintf ( tmp, sizeof ( tmp ), "%s", filename ); - wname = tmp; - } else { - wname = efi_block_boot_filename; - } - - /* Open file system protocol */ + /* Open filesystem protocol */ if ( ( efirc = bs->OpenProtocol ( handle, protocol, &u.interface, efi_image_handle, handle, EFI_OPEN_PROTOCOL_GET_PROTOCOL ))!=0){ rc = -EEFI ( efirc ); - DBGC ( drive, "EFIBLK %#02x could not open %s device path: " - "%s\n", drive, efi_handle_name ( handle ), - strerror ( rc ) ); + DBGC ( drive, "EFIBLK %#02x could not open %s filesystem: %s\n", + drive, efi_handle_name ( handle ), strerror ( rc ) ); goto err_open; } /* Open root volume */ - if ( ( efirc = u.fs->OpenVolume ( u.fs, &root ) ) != 0 ) { + if ( ( efirc = u.fs->OpenVolume ( u.fs, root ) ) != 0 ) { rc = -EEFI ( efirc ); DBGC ( drive, "EFIBLK %#02x could not open %s root: %s\n", drive, efi_handle_name ( handle ), strerror ( rc ) ); goto err_volume; } + /* Success */ + rc = 0; + + err_volume: + bs->CloseProtocol ( handle, protocol, efi_image_handle, handle ); + err_open: + return rc; +} + +/** + * Check for existence of a file within a filesystem + * + * @v drive Drive number + * @v handle Filesystem handle + * @v root Root directory + * @v filename Filename (or NULL to use default) + * @ret rc Return status code + */ +static int efi_block_filename ( unsigned int drive, EFI_HANDLE handle, + EFI_FILE_PROTOCOL *root, + const char *filename ) { + CHAR16 tmp[ filename ? ( strlen ( filename ) + 1 /* wNUL */ ) : 0 ]; + CHAR16 *wname; + EFI_FILE_PROTOCOL *file; + EFI_STATUS efirc; + int rc; + + /* Construct filename */ + if ( filename ) { + efi_snprintf ( tmp, sizeof ( tmp ), "%s", filename ); + wname = tmp; + } else { + wname = efi_block_boot_filename; + } + /* Try opening file */ if ( ( efirc = root->Open ( root, &file, wname, EFI_FILE_MODE_READ, 0 ) ) != 0 ) { @@ -570,10 +592,6 @@ static int efi_block_filename ( unsigned int drive, EFI_HANDLE handle, file->Close ( file ); err_file: - root->Close ( root ); - err_volume: - bs->CloseProtocol ( handle, protocol, efi_image_handle, handle ); - err_open: return rc; } @@ -597,6 +615,7 @@ static int efi_block_match ( unsigned int drive, EFI_HANDLE handle, EFI_DEVICE_PATH_PROTOCOL *path; void *interface; } u; + EFI_FILE *root; union uuid guid; EFI_STATUS efirc; int rc; @@ -639,16 +658,30 @@ static int efi_block_match ( unsigned int drive, EFI_HANDLE handle, } } + /* Open root directory */ + if ( ( rc = efi_block_root ( drive, handle, &root ) ) != 0 ) + goto err_root; + /* Check if filesystem contains boot filename */ - if ( ( rc = efi_block_filename ( drive, handle, + if ( ( rc = efi_block_filename ( drive, handle, root, config->filename ) ) != 0 ) { goto err_filename; } + /* Check if filesystem contains additional filename, if applicable */ + if ( config->extra && + ( ( rc = efi_block_filename ( drive, handle, root, + config->extra ) ) != 0 ) ) { + goto err_extra; + } + /* Success */ rc = 0; + err_extra: err_filename: + root->Close ( root ); + err_root: err_wrong_guid: err_no_guid: err_not_child: -- cgit v1.2.3-55-g7522 From 24a855f1fc8d97ad3ca6be3eaabdc1c8285e86e8 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Thu, 7 Mar 2024 14:09:54 +0000 Subject: [block] Allow SAN boot device to be identified by filesystem label Add a "--label" option that can be used to specify a filesystem label, to be matched against the FAT volume label. Signed-off-by: Michael Brown --- src/hci/commands/sanboot_cmd.c | 7 +++- src/include/ipxe/sanboot.h | 2 ++ src/interface/efi/efi_block.c | 73 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 81 insertions(+), 1 deletion(-) diff --git a/src/hci/commands/sanboot_cmd.c b/src/hci/commands/sanboot_cmd.c index add0756d..6ab9e884 100644 --- a/src/hci/commands/sanboot_cmd.c +++ b/src/hci/commands/sanboot_cmd.c @@ -51,6 +51,8 @@ struct sanboot_options { char *filename; /** Required extra filename */ char *extra; + /** Volume label */ + char *label; /** UUID */ struct uuid_option uuid; }; @@ -58,7 +60,7 @@ struct sanboot_options { /** "sanboot" option list */ static union { /* "sanboot" takes all options */ - struct option_descriptor sanboot[6]; + struct option_descriptor sanboot[7]; /* "sanhook" takes only --drive and --no-describe */ struct option_descriptor sanhook[2]; /* "sanunhook" takes only --drive */ @@ -75,6 +77,8 @@ static union { struct sanboot_options, filename, parse_string ), OPTION_DESC ( "extra", 'e', required_argument, struct sanboot_options, extra, parse_string ), + OPTION_DESC ( "label", 'l', required_argument, + struct sanboot_options, label, parse_string ), OPTION_DESC ( "uuid", 'u', required_argument, struct sanboot_options, uuid, parse_uuid ), }, @@ -135,6 +139,7 @@ static int sanboot_core_exec ( int argc, char **argv, /* Construct configuration parameters */ config.filename = opts.filename; config.extra = opts.extra; + config.label = opts.label; config.uuid = opts.uuid.value; /* Construct flags */ diff --git a/src/include/ipxe/sanboot.h b/src/include/ipxe/sanboot.h index 91c848b0..e44367cd 100644 --- a/src/include/ipxe/sanboot.h +++ b/src/include/ipxe/sanboot.h @@ -112,6 +112,8 @@ struct san_boot_config { const char *filename; /** Required extra filename (or NULL to ignore) */ const char *extra; + /** Filesystem label (or NULL to ignore volume label) */ + const char *label; /** UUID (or NULL to ignore UUID) */ union uuid *uuid; }; diff --git a/src/interface/efi/efi_block.c b/src/interface/efi/efi_block.c index 269b9abd..28a7f723 100644 --- a/src/interface/efi/efi_block.c +++ b/src/interface/efi/efi_block.c @@ -32,7 +32,9 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #include #include +#include #include +#include #include #include #include @@ -51,6 +53,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #include #include #include +#include #include #include #include @@ -595,6 +598,68 @@ static int efi_block_filename ( unsigned int drive, EFI_HANDLE handle, return rc; } +/** + * Check for EFI block device filesystem label + * + * @v drive Drive number + * @v root Root directory + * @v label Volume label + * @ret rc Return status code + */ +static int efi_block_label ( unsigned int drive, EFI_FILE_PROTOCOL *root, + const char *label ) { + EFI_FILE_SYSTEM_INFO *info; + UINTN size; + char *actual; + EFI_STATUS efirc; + int rc; + + /* Get length of file system information */ + size = 0; + root->GetInfo ( root, &efi_file_system_info_id, &size, NULL ); + + /* Allocate file system information */ + info = malloc ( size ); + if ( ! info ) { + rc = -ENOMEM; + goto err_alloc_info; + } + + /* Get file system information */ + if ( ( efirc = root->GetInfo ( root, &efi_file_system_info_id, &size, + info ) ) != 0 ) { + rc = -EEFI ( efirc ); + DBGC ( drive, "EFIBLK %#02x could not get filesystem info: " + "%s\n", drive, strerror ( rc ) ); + goto err_get_info; + } + + /* Construct volume label for comparison */ + if ( asprintf ( &actual, "%ls", info->VolumeLabel ) < 0 ) { + rc = -ENOMEM; + goto err_alloc_label; + } + + /* Compare volume label */ + if ( strcasecmp ( label, actual ) != 0 ) { + DBGC ( drive, "EFIBLK %#02x has wrong label \"%s\"\n", + drive, actual ); + rc = -ENOENT; + goto err_compare; + } + + /* Success */ + rc = 0; + + err_compare: + free ( actual ); + err_alloc_label: + err_get_info: + free ( info ); + err_alloc_info: + return rc; +} + /** * Check EFI block device filesystem match * @@ -675,9 +740,17 @@ static int efi_block_match ( unsigned int drive, EFI_HANDLE handle, goto err_extra; } + /* Check volume label, if applicable */ + if ( config->label && + ( ( rc = efi_block_label ( drive, root, + config->label ) ) != 0 ) ) { + goto err_label; + } + /* Success */ rc = 0; + err_label: err_extra: err_filename: root->Close ( root ); -- cgit v1.2.3-55-g7522 From 06e229590c6e94c1dd8606a374714f7cfc50241a Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Thu, 7 Mar 2024 13:34:33 +0000 Subject: [efi] Do not report return status from efi_block_local() The return status from efi_block_local() indicates whether or not the handle is eligible to be assigned a local virtual drive number. There will always be several enumerated EFI_BLOCK_IO_PROTOCOL handles that are not eligible for a local virtual drive number (e.g. the handles corresponding to partitions, rather than to complete disks), and this is not an interesting error to report. Do not report errors from efi_block_local() as the overall error status for a SAN boot, since doing so would be likely to mask a much more relevant error from having previously attempted to scan for a matching filesystem within an eligible block device handle. Signed-off-by: Michael Brown --- src/interface/efi/efi_block.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/interface/efi/efi_block.c b/src/interface/efi/efi_block.c index 28a7f723..2f0187a0 100644 --- a/src/interface/efi/efi_block.c +++ b/src/interface/efi/efi_block.c @@ -1042,8 +1042,12 @@ static int efi_block_boot ( unsigned int drive, /* Check if this handle is eligible to be * given a local virtual drive number. + * + * Do not record this as the overall error + * status, since it is not an interesting + * error. */ - if ( ( rc = efi_block_local ( handle ) ) != 0 ) { + if ( efi_block_local ( handle ) != 0 ) { /* Do not consume virtual drive number */ vdrive--; continue; -- cgit v1.2.3-55-g7522 From 226531ed36ec682728a13d2bd327a3d587a88926 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Thu, 7 Mar 2024 23:25:35 +0000 Subject: [ci] Update action versions to silence GitHub warnings Signed-off-by: Michael Brown --- .github/workflows/build.yml | 14 +++++++------- .github/workflows/coverity.yml | 2 +- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 232375ad..c6988a11 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -12,7 +12,7 @@ jobs: run: | sudo chown $(id -un) /var/cache/apt/archives - name: Cache packages - uses: actions/cache@v3 + uses: actions/cache@v4 with: path: /var/cache/apt/archives/*.deb key: apt-cache-${{ github.run_id }}-${{ github.run_attempt }} @@ -32,14 +32,14 @@ jobs: needs: cache steps: - name: Check out code - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: fetch-depth: 0 - name: Cache permissions run: | sudo chown $(id -un) /var/cache/apt/archives - name: Cache packages - uses: actions/cache/restore@v3 + uses: actions/cache/restore@v4 with: path: /var/cache/apt/archives/*.deb key: apt-cache-${{ github.run_id }}-${{ github.run_attempt }} @@ -68,14 +68,14 @@ jobs: needs: cache steps: - name: Check out code - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: fetch-depth: 0 - name: Cache permissions run: | sudo chown $(id -un) /var/cache/apt/archives - name: Cache packages - uses: actions/cache/restore@v3 + uses: actions/cache/restore@v4 with: path: /var/cache/apt/archives/*.deb key: apt-cache-${{ github.run_id }}-${{ github.run_attempt }} @@ -97,14 +97,14 @@ jobs: needs: cache steps: - name: Check out code - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: fetch-depth: 0 - name: Cache permissions run: | sudo chown $(id -un) /var/cache/apt/archives - name: Cache packages - uses: actions/cache/restore@v3 + uses: actions/cache/restore@v4 with: path: /var/cache/apt/archives/*.deb key: apt-cache-${{ github.run_id }}-${{ github.run_attempt }} diff --git a/.github/workflows/coverity.yml b/.github/workflows/coverity.yml index ba868180..4c3e2e48 100644 --- a/.github/workflows/coverity.yml +++ b/.github/workflows/coverity.yml @@ -11,7 +11,7 @@ jobs: runs-on: ubuntu-22.04 steps: - name: Check out code - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Download Coverity Scan run: | curl --form token=${{ secrets.COVERITY_SCAN_TOKEN }} \ -- cgit v1.2.3-55-g7522 From df2f23e333601e587f72c68cb7b7b116796f9d3c Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Mon, 11 Mar 2024 12:12:31 +0000 Subject: [efi] Update to current EDK2 headers Signed-off-by: Michael Brown --- src/include/ipxe/efi/Guid/FileInfo.h | 1 + src/include/ipxe/efi/IndustryStandard/Acpi30.h | 14 ++ src/include/ipxe/efi/IndustryStandard/Acpi40.h | 5 + src/include/ipxe/efi/IndustryStandard/Acpi50.h | 10 + src/include/ipxe/efi/IndustryStandard/Acpi51.h | 10 + src/include/ipxe/efi/IndustryStandard/Acpi60.h | 10 + src/include/ipxe/efi/Library/BaseLib.h | 284 ++++++++++++++++++++++++ src/include/ipxe/efi/Protocol/DebugSupport.h | 14 ++ src/include/ipxe/efi/Protocol/FormBrowser2.h | 6 +- src/include/ipxe/efi/Protocol/HiiConfigAccess.h | 9 +- src/include/ipxe/efi/Protocol/Tcp6.h | 4 +- src/include/ipxe/efi/Uefi/UefiSpec.h | 65 +++++- 12 files changed, 421 insertions(+), 11 deletions(-) diff --git a/src/include/ipxe/efi/Guid/FileInfo.h b/src/include/ipxe/efi/Guid/FileInfo.h index 4fc9e860..62c5f4c0 100644 --- a/src/include/ipxe/efi/Guid/FileInfo.h +++ b/src/include/ipxe/efi/Guid/FileInfo.h @@ -49,6 +49,7 @@ typedef struct { UINT64 Attribute; /// /// The Null-terminated name of the file. + /// For a root directory, the name is an empty string. /// CHAR16 FileName[1]; } EFI_FILE_INFO; diff --git a/src/include/ipxe/efi/IndustryStandard/Acpi30.h b/src/include/ipxe/efi/IndustryStandard/Acpi30.h index c7dfd5c7..ff82bf20 100644 --- a/src/include/ipxe/efi/IndustryStandard/Acpi30.h +++ b/src/include/ipxe/efi/IndustryStandard/Acpi30.h @@ -19,6 +19,20 @@ FILE_LICENCE ( BSD2_PATENT ); #define ACPI_EXTENDED_ADDRESS_SPACE_DESCRIPTOR 0x8B +/// +/// C-state Coordination Types +/// See s8.4.2.2 _CSD (C-State Dependency) +/// +#define ACPI_AML_COORD_TYPE_SW_ALL 0xFC +#define ACPI_AML_COORD_TYPE_SW_ANY 0xFD +#define ACPI_AML_COORD_TYPE_HW_ALL 0xFE + +/// +/// _PSD Revision for ACPI 3.0 +// See s8.4.4.5 _PSD (P-State Dependency) +/// +#define EFI_ACPI_3_0_AML_PSD_REVISION 0 + // // Ensure proper structure formats // diff --git a/src/include/ipxe/efi/IndustryStandard/Acpi40.h b/src/include/ipxe/efi/IndustryStandard/Acpi40.h index f6c70d74..97b81703 100644 --- a/src/include/ipxe/efi/IndustryStandard/Acpi40.h +++ b/src/include/ipxe/efi/IndustryStandard/Acpi40.h @@ -12,6 +12,11 @@ FILE_LICENCE ( BSD2_PATENT ); #include +/// +/// _PSD Revision for ACPI 4.0 +/// +#define EFI_ACPI_4_0_AML_PSD_REVISION 0 + // // Ensure proper structure formats // diff --git a/src/include/ipxe/efi/IndustryStandard/Acpi50.h b/src/include/ipxe/efi/IndustryStandard/Acpi50.h index 7d57b9ff..2addcb00 100644 --- a/src/include/ipxe/efi/IndustryStandard/Acpi50.h +++ b/src/include/ipxe/efi/IndustryStandard/Acpi50.h @@ -25,6 +25,16 @@ FILE_LICENCE ( BSD2_PATENT ); #define ACPI_GPIO_CONNECTION_DESCRIPTOR 0x8C #define ACPI_GENERIC_SERIAL_BUS_CONNECTION_DESCRIPTOR 0x8E +/// +/// _PSD Revision for ACPI 5.0 +/// +#define EFI_ACPI_5_0_AML_PSD_REVISION 0 + +/// +/// _CPC Revision for ACPI 5.0 +/// +#define EFI_ACPI_5_0_AML_CPC_REVISION 1 + #pragma pack(1) /// diff --git a/src/include/ipxe/efi/IndustryStandard/Acpi51.h b/src/include/ipxe/efi/IndustryStandard/Acpi51.h index 49bb972e..a2079ecc 100644 --- a/src/include/ipxe/efi/IndustryStandard/Acpi51.h +++ b/src/include/ipxe/efi/IndustryStandard/Acpi51.h @@ -15,6 +15,16 @@ FILE_LICENCE ( BSD2_PATENT ); #include +/// +/// _PSD Revision for ACPI 5.1 +/// +#define EFI_ACPI_5_1_AML_PSD_REVISION 0 + +/// +/// _CPC Revision for ACPI 5.1 +/// +#define EFI_ACPI_5_1_AML_CPC_REVISION 2 + // // Ensure proper structure formats // diff --git a/src/include/ipxe/efi/IndustryStandard/Acpi60.h b/src/include/ipxe/efi/IndustryStandard/Acpi60.h index 9bd821c7..c8d99214 100644 --- a/src/include/ipxe/efi/IndustryStandard/Acpi60.h +++ b/src/include/ipxe/efi/IndustryStandard/Acpi60.h @@ -14,6 +14,16 @@ FILE_LICENCE ( BSD2_PATENT ); #include +/// +/// _PSD Revision for ACPI 6.0 +/// +#define EFI_ACPI_6_0_AML_PSD_REVISION 0 + +/// +/// _CPC Revision for ACPI 6.0 +/// +#define EFI_ACPI_6_0_AML_CPC_REVISION 2 + // // Ensure proper structure formats // diff --git a/src/include/ipxe/efi/Library/BaseLib.h b/src/include/ipxe/efi/Library/BaseLib.h index 6d236595..16ea35cd 100644 --- a/src/include/ipxe/efi/Library/BaseLib.h +++ b/src/include/ipxe/efi/Library/BaseLib.h @@ -193,6 +193,11 @@ RiscVReadTimer ( VOID ); +VOID +RiscVSetSupervisorTimeCompareRegister ( + IN UINT64 + ); + VOID RiscVEnableTimerInterrupt ( VOID @@ -208,6 +213,59 @@ RiscVClearPendingTimerInterrupt ( VOID ); +/** + RISC-V invalidate instruction cache. + +**/ +VOID +EFIAPI +RiscVInvalidateInstCacheFenceAsm ( + VOID + ); + +/** + RISC-V invalidate data cache. + +**/ +VOID +EFIAPI +RiscVInvalidateDataCacheFenceAsm ( + VOID + ); + +/** + RISC-V flush cache block. Atomically perform a clean operation + followed by an invalidate operation + +**/ +VOID +EFIAPI +RiscVCpuCacheFlushCmoAsm ( + IN UINTN + ); + +/** +Perform a write transfer to another cache or to memory if the +data in the copy of the cache block have been modified by a store +operation + +**/ +VOID +EFIAPI +RiscVCpuCacheCleanCmoAsm ( + IN UINTN + ); + +/** +Deallocate the copy of the cache block + +**/ +VOID +EFIAPI +RiscVCpuCacheInvalCmoAsm ( + IN UINTN + ); + #endif // defined (MDE_CPU_RISCV64) #if defined (MDE_CPU_LOONGARCH64) @@ -231,6 +289,227 @@ typedef struct { #define BASE_LIBRARY_JUMP_BUFFER_ALIGNMENT 8 +/* + * Set the exception base address for LoongArch. + * + * @param ExceptionBaseAddress The exception base address, must be aligned greater than or qeual to 4K . + */ +VOID +SetExceptionBaseAddress ( + IN UINT64 + ); + +/* + * Set the TlbRebase address for LoongArch. + * + * @param TlbRebaseAddress The TlbRebase address, must be aligned greater than or qeual to 4K . + */ +VOID +SetTlbRebaseAddress ( + IN UINT64 + ); + +/** + Enables local CPU interrupts. + + @param Needs to enable local interrupt bit. +**/ +VOID +EnableLocalInterrupts ( + IN UINT16 + ); + +/** + Disables local CPU interrupts. + + @param Needs to disable local interrupt bit. +**/ +VOID +DisableLocalInterrupts ( + IN UINT16 + ); + +/** + Read CPUCFG register. + + @param Index Specifies the register number of the CPUCFG to read the data. + @param Data A pointer to the variable used to store the CPUCFG register value. +**/ +VOID +AsmCpucfg ( + IN UINT32 Index, + OUT UINT32 *Data + ); + +/** + Gets the timer count value. + + @param[] VOID + @retval timer count value. + +**/ +UINTN +AsmReadStableCounter ( + VOID + ); + +/** + CSR read operation. + + @param[in] Select CSR read instruction select values. + + @return The return value of csrrd instruction, return -1 means no CSR instruction + is found. +**/ +UINTN +CsrRead ( + IN UINT16 Select + ); + +/** + CSR write operation. + + @param[in] Select CSR write instruction select values. + @param[in] Value The csrwr will write the value. + + @return The return value of csrwr instruction, that is, store the old value of + the register, return -1 means no CSR instruction is found. +**/ +UINTN +CsrWrite ( + IN UINT16 Select, + IN UINTN Value + ); + +/** + CSR exchange operation. + + @param[in] Select CSR exchange instruction select values. + @param[in] Value The csrxchg will write the value. + @param[in] Mask The csrxchg mask value. + + @return The return value of csrxchg instruction, that is, store the old value of + the register, return -1 means no CSR instruction is found. +**/ +UINTN +CsrXChg ( + IN UINT16 Select, + IN UINTN Value, + IN UINTN Mask + ); + +/** + IO CSR read byte operation. + + @param[in] Select IO CSR read instruction select values. + + @return The return value of iocsrrd.b instruction. + +**/ +UINT8 +IoCsrRead8 ( + IN UINTN Select + ); + +/** + IO CSR read half word operation. + + @param[in] Select IO CSR read instruction select values. + + @return The return value of iocsrrd.h instruction. + +**/ +UINT16 +IoCsrRead16 ( + IN UINTN Select + ); + +/** + IO CSR read word operation. + + @param[in] Select IO CSR read instruction select values. + + @return The return value of iocsrrd.w instruction. + +**/ +UINT32 +IoCsrRead32 ( + IN UINTN Select + ); + +/** + IO CSR read double word operation. Only for LoongArch64. + + @param[in] Select IO CSR read instruction select values. + + @return The return value of iocsrrd.d instruction. + +**/ +UINT64 +IoCsrRead64 ( + IN UINTN Select + ); + +/** + IO CSR write byte operation. + + @param[in] Select IO CSR write instruction select values. + @param[in] Value The iocsrwr.b will write the value. + + @return VOID. + +**/ +VOID +IoCsrWrite8 ( + IN UINTN Select, + IN UINT8 Value + ); + +/** + IO CSR write half word operation. + + @param[in] Select IO CSR write instruction select values. + @param[in] Value The iocsrwr.h will write the value. + + @return VOID. + +**/ +VOID +IoCsrWrite16 ( + IN UINTN Select, + IN UINT16 Value + ); + +/** + IO CSR write word operation. + + @param[in] Select IO CSR write instruction select values. + @param[in] Value The iocsrwr.w will write the value. + + @return VOID. + +**/ +VOID +IoCsrWrite32 ( + IN UINTN Select, + IN UINT32 Value + ); + +/** + IO CSR write double word operation. Only for LoongArch64. + + @param[in] Select IO CSR write instruction select values. + @param[in] Value The iocsrwr.d will write the value. + + @return VOID. + +**/ +VOID +IoCsrWrite64 ( + IN UINTN Select, + IN UINT64 Value + ); + #endif // defined (MDE_CPU_LOONGARCH64) // @@ -4601,6 +4880,11 @@ CalculateCrc16Ansi ( IN UINT16 InitialValue ); +// +// Initial value for the CRC16-ANSI algorithm, when no prior checksum has been calculated. +// +#define CRC16ANSI_INIT 0xffff + /** Calculates the CRC32c checksum of the given buffer. diff --git a/src/include/ipxe/efi/Protocol/DebugSupport.h b/src/include/ipxe/efi/Protocol/DebugSupport.h index 453ea975..8f930e33 100644 --- a/src/include/ipxe/efi/Protocol/DebugSupport.h +++ b/src/include/ipxe/efi/Protocol/DebugSupport.h @@ -685,6 +685,20 @@ typedef struct { // // LoongArch processor exception types. // +// The exception types is located in the CSR ESTAT +// register offset 16 bits, width 6 bits. +// +// If you want to register an exception hook, you can +// shfit the number left by 16 bits, and the exception +// handler will know the types. +// +// For example: +// mCpu->CpuRegisterInterruptHandler ( +// mCpu, +// (EXCEPT_LOONGARCH_PPI << CSR_ESTAT_EXC_SHIFT), +// PpiExceptionHandler +// ); +// #define EXCEPT_LOONGARCH_INT 0 #define EXCEPT_LOONGARCH_PIL 1 #define EXCEPT_LOONGARCH_PIS 2 diff --git a/src/include/ipxe/efi/Protocol/FormBrowser2.h b/src/include/ipxe/efi/Protocol/FormBrowser2.h index b1c0d200..5e6f940b 100644 --- a/src/include/ipxe/efi/Protocol/FormBrowser2.h +++ b/src/include/ipxe/efi/Protocol/FormBrowser2.h @@ -57,6 +57,7 @@ typedef UINTN EFI_BROWSER_ACTION_REQUEST; #define EFI_BROWSER_ACTION_REQUEST_FORM_APPLY 6 #define EFI_BROWSER_ACTION_REQUEST_FORM_DISCARD 7 #define EFI_BROWSER_ACTION_REQUEST_RECONNECT 8 +#define EFI_BROWSER_ACTION_REQUEST_QUESTION_APPLY 9 /** Initialize the browser to display the specified configuration forms. @@ -140,10 +141,13 @@ EFI_STATUS @retval EFI_SUCCESS The results have been distributed or are awaiting distribution. - @retval EFI_OUT_OF_RESOURCES The ResultsDataSize specified + @retval EFI_BUFFER_TOO_SMALL The ResultsDataSize specified was too small to contain the results data. + @retval EFI_UNSUPPORTED Uncommitted browser state is not available + at the current stage of execution. + **/ typedef EFI_STATUS diff --git a/src/include/ipxe/efi/Protocol/HiiConfigAccess.h b/src/include/ipxe/efi/Protocol/HiiConfigAccess.h index beae0820..aaa51a31 100644 --- a/src/include/ipxe/efi/Protocol/HiiConfigAccess.h +++ b/src/include/ipxe/efi/Protocol/HiiConfigAccess.h @@ -104,9 +104,16 @@ typedef UINTN EFI_BROWSER_ACTION; string. @retval EFI_INVALID_PARAMETER Unknown name. Progress points - to the & before the name in + to the "&" before the name in question. + @retval EFI_INVALID_PARAMETER If Results or Progress is NULL. + + @retval EFI_ACCESS_DENIED The action violated a system policy. + + @retval EFI_DEVICE_ERROR Failed to extract the current configuration + for one or more named elements. + **/ typedef EFI_STATUS diff --git a/src/include/ipxe/efi/Protocol/Tcp6.h b/src/include/ipxe/efi/Protocol/Tcp6.h index eed2f7cc..ddceaaf9 100644 --- a/src/include/ipxe/efi/Protocol/Tcp6.h +++ b/src/include/ipxe/efi/Protocol/Tcp6.h @@ -194,12 +194,12 @@ typedef struct { BOOLEAN EnableNagle; /// /// Set it to TRUE to enable TCP timestamps option as defined in - /// RFC1323. Set to FALSE to disable it. + /// RFC7323. Set to FALSE to disable it. /// BOOLEAN EnableTimeStamp; /// /// Set it to TRUE to enable TCP window scale option as defined in - /// RFC1323. Set it to FALSE to disable it. + /// RFC7323. Set it to FALSE to disable it. /// BOOLEAN EnableWindowScaling; /// diff --git a/src/include/ipxe/efi/Uefi/UefiSpec.h b/src/include/ipxe/efi/Uefi/UefiSpec.h index e5a32d88..cc166fc3 100644 --- a/src/include/ipxe/efi/Uefi/UefiSpec.h +++ b/src/include/ipxe/efi/Uefi/UefiSpec.h @@ -112,6 +112,21 @@ typedef enum { // #define EFI_MEMORY_RUNTIME 0x8000000000000000ULL +// +// If this flag is set, the memory region is +// described with additional ISA-specific memory attributes +// as specified in EFI_MEMORY_ISA_MASK. +// +#define EFI_MEMORY_ISA_VALID 0x4000000000000000ULL + +// +// Defines the bits reserved for describing optional ISA-specific cacheability +// attributes that are not covered by the standard UEFI Memory Attributes cacheability +// bits (EFI_MEMORY_UC, EFI_MEMORY_WC, EFI_MEMORY_WT, EFI_MEMORY_WB and EFI_MEMORY_UCE). +// See Calling Conventions for further ISA-specific enumeration of these bits. +// +#define EFI_MEMORY_ISA_MASK 0x0FFFF00000000000ULL + // // Attributes bitmasks, grouped by type // @@ -307,6 +322,9 @@ EFI_STATUS map that requires a mapping. @retval EFI_NOT_FOUND A virtual address was supplied for an address that is not found in the memory map. + @retval EFI_UNSUPPORTED This call is not supported by this platform at the time the call is made. + The platform should describe this runtime service as unsupported at runtime + via an EFI_RT_PROPERTIES_TABLE configuration table. **/ typedef @@ -397,11 +415,14 @@ EFI_STATUS for the new virtual address mappings being applied. @retval EFI_SUCCESS The pointer pointed to by Address was modified. - @retval EFI_INVALID_PARAMETER 1) Address is NULL. - 2) *Address is NULL and DebugDisposition does - not have the EFI_OPTIONAL_PTR bit set. @retval EFI_NOT_FOUND The pointer pointed to by Address was not found to be part of the current memory map. This is normally fatal. + @retval EFI_INVALID_PARAMETER Address is NULL. + @retval EFI_INVALID_PARAMETER *Address is NULL and DebugDisposition does + not have the EFI_OPTIONAL_PTR bit set. + @retval EFI_UNSUPPORTED This call is not supported by this platform at the time the call is made. + The platform should describe this runtime service as unsupported at runtime + via an EFI_RT_PROPERTIES_TABLE configuration table. **/ typedef @@ -666,6 +687,10 @@ VOID @retval EFI_INVALID_PARAMETER The DataSize is not too small and Data is NULL. @retval EFI_DEVICE_ERROR The variable could not be retrieved due to a hardware error. @retval EFI_SECURITY_VIOLATION The variable could not be retrieved due to an authentication failure. + @retval EFI_UNSUPPORTED After ExitBootServices() has been called, this return code may be returned + if no variable storage is supported. The platform should describe this + runtime service as unsupported at runtime via an EFI_RT_PROPERTIES_TABLE + configuration table. **/ typedef @@ -702,6 +727,10 @@ EFI_STATUS @retval EFI_INVALID_PARAMETER Null-terminator is not found in the first VariableNameSize bytes of the input VariableName buffer. @retval EFI_DEVICE_ERROR The variable could not be retrieved due to a hardware error. + @retval EFI_UNSUPPORTED After ExitBootServices() has been called, this return code may be returned + if no variable storage is supported. The platform should describe this + runtime service as unsupported at runtime via an EFI_RT_PROPERTIES_TABLE + configuration table. **/ typedef @@ -744,6 +773,9 @@ EFI_STATUS but the AuthInfo does NOT pass the validation check carried out by the firmware. @retval EFI_NOT_FOUND The variable trying to be updated or deleted was not found. + @retval EFI_UNSUPPORTED This call is not supported by this platform at the time the call is made. + The platform should describe this runtime service as unsupported at runtime + via an EFI_RT_PROPERTIES_TABLE configuration table. **/ typedef @@ -796,6 +828,9 @@ typedef struct { @retval EFI_SUCCESS The operation completed successfully. @retval EFI_INVALID_PARAMETER Time is NULL. @retval EFI_DEVICE_ERROR The time could not be retrieved due to hardware error. + @retval EFI_UNSUPPORTED This call is not supported by this platform at the time the call is made. + The platform should describe this runtime service as unsupported at runtime + via an EFI_RT_PROPERTIES_TABLE configuration table. **/ typedef @@ -813,6 +848,9 @@ EFI_STATUS @retval EFI_SUCCESS The operation completed successfully. @retval EFI_INVALID_PARAMETER A time field is out of range. @retval EFI_DEVICE_ERROR The time could not be set due due to hardware error. + @retval EFI_UNSUPPORTED This call is not supported by this platform at the time the call is made. + The platform should describe this runtime service as unsupported at runtime + via an EFI_RT_PROPERTIES_TABLE configuration table. **/ typedef @@ -833,7 +871,9 @@ EFI_STATUS @retval EFI_INVALID_PARAMETER Pending is NULL. @retval EFI_INVALID_PARAMETER Time is NULL. @retval EFI_DEVICE_ERROR The wakeup time could not be retrieved due to a hardware error. - @retval EFI_UNSUPPORTED A wakeup timer is not supported on this platform. + @retval EFI_UNSUPPORTED This call is not supported by this platform at the time the call is made. + The platform should describe this runtime service as unsupported at runtime + via an EFI_RT_PROPERTIES_TABLE configuration table. **/ typedef @@ -855,7 +895,9 @@ EFI_STATUS Enable is FALSE, then the wakeup alarm was disabled. @retval EFI_INVALID_PARAMETER A time field is out of range. @retval EFI_DEVICE_ERROR The wakeup time could not be set due to a hardware error. - @retval EFI_UNSUPPORTED A wakeup timer is not supported on this platform. + @retval EFI_UNSUPPORTED This call is not supported by this platform at the time the call is made. + The platform should describe this runtime service as unsupported at runtime + via an EFI_RT_PROPERTIES_TABLE configuration table. **/ typedef @@ -900,7 +942,7 @@ EFI_STATUS (EFIAPI *EFI_IMAGE_LOAD)( IN BOOLEAN BootPolicy, IN EFI_HANDLE ParentImageHandle, - IN EFI_DEVICE_PATH_PROTOCOL *DevicePath, + IN EFI_DEVICE_PATH_PROTOCOL *DevicePath OPTIONAL, IN VOID *SourceBuffer OPTIONAL, IN UINTN SourceSize, OUT EFI_HANDLE *ImageHandle @@ -1077,6 +1119,9 @@ EFI_STATUS @retval EFI_SUCCESS The next high monotonic count was returned. @retval EFI_INVALID_PARAMETER HighCount is NULL. @retval EFI_DEVICE_ERROR The device is not functioning properly. + @retval EFI_UNSUPPORTED This call is not supported by this platform at the time the call is made. + The platform should describe this runtime service as unsupported at runtime + via an EFI_RT_PROPERTIES_TABLE configuration table. **/ typedef @@ -1650,7 +1695,7 @@ typedef struct { /// UINT32 Flags; /// - /// Size in bytes of the capsule. + /// Size in bytes of the capsule (including capsule header). /// UINT32 CapsuleImageSize; } EFI_CAPSULE_HEADER; @@ -1703,6 +1748,9 @@ typedef struct { in runtime. The caller may resubmit the capsule prior to ExitBootServices(). @retval EFI_OUT_OF_RESOURCES When ExitBootServices() has not been previously called then this error indicates the capsule is compatible with this platform but there are insufficient resources to process. + @retval EFI_UNSUPPORTED This call is not supported by this platform at the time the call is made. + The platform should describe this runtime service as unsupported at runtime + via an EFI_RT_PROPERTIES_TABLE configuration table. **/ typedef @@ -1734,6 +1782,9 @@ EFI_STATUS in runtime. The caller may resubmit the capsule prior to ExitBootServices(). @retval EFI_OUT_OF_RESOURCES When ExitBootServices() has not been previously called then this error indicates the capsule is compatible with this platform but there are insufficient resources to process. + @retval EFI_UNSUPPORTED This call is not supported by this platform at the time the call is made. + The platform should describe this runtime service as unsupported at runtime + via an EFI_RT_PROPERTIES_TABLE configuration table. **/ typedef -- cgit v1.2.3-55-g7522