diff --git a/benchmark/idle.c b/benchmark/idle.c index 27c886374..17f8516cd 100644 --- a/benchmark/idle.c +++ b/benchmark/idle.c @@ -20,13 +20,16 @@ struct bench *b; static inline uint64_t read_cycle_count() { - uint64_t cycle_count; + uint64_t cycle_count = 0; #if defined(CONFIG_ARCH_ARM) SEL4BENCH_READ_CCNT(cycle_count); #elif defined(CONFIG_ARCH_RISCV) asm volatile("rdcycle %0" : "=r"(cycle_count)); #elif defined(CONFIG_ARCH_X86_64) - // Do nothing only for build atm + uint32_t lo, hi, unused; + __asm__ __volatile__("rdtscp" : "=a"(lo), "=d"(hi), "=c"(unused)); + __asm__ __volatile__("lfence" ::: "memory"); + cycle_count = ((uint64_t)hi << 32) | lo; #else #error "read_cycle_count: unsupported architecture" #endif diff --git a/ci/examples/echo_server.py b/ci/examples/echo_server.py index d1596c4fb..e83e5f593 100755 --- a/ci/examples/echo_server.py +++ b/ci/examples/echo_server.py @@ -47,6 +47,10 @@ async def test(backend: HardwareBackend, test_config: common.TestConfig): # See https://github.com/au-ts/sddf/issues/698 for details timeout = 30 + if test_config.board.startswith("vb_105"): + # This x86 machine takes around 3 mintues to boot + timeout = 200 + async with asyncio.timeout(timeout): await wait_for_output(backend, b"DHCP request finished") dhcp_client1 = await wait_for_output(backend, b"\r\n") diff --git a/drivers/network/ixgbe/eth_driver.mk b/drivers/network/ixgbe/eth_driver.mk new file mode 100644 index 000000000..67208da1a --- /dev/null +++ b/drivers/network/ixgbe/eth_driver.mk @@ -0,0 +1,28 @@ +# +# Copyright 2026, UNSW +# +# SPDX-License-Identifier: BSD-2-Clause +# +# Include this snippet in your project Makefile to build +# the IXGBE NIC driver +# +# NOTES +# Generates eth_driver.elf (alternative unique name eth_driver_ixgbe.elf) +# Expects libsddf_util_debug.a to be in LIBS + +ETHERNET_DRIVER_DIR := $(dir $(lastword $(MAKEFILE_LIST))) +CHECK_NETDRV_FLAGS_MD5:=.netdrv_cflags-$(shell echo -- ${CFLAGS} ${CFLAGS_network} | shasum | sed 's/ *-//') + +${CHECK_NETDRV_FLAGS_MD5}: + -rm -f .netdrv_cflags-* + touch $@ + +eth_driver_ixgbe.elf: network/ixgbe/ethernet.o + $(LD) $(LDFLAGS) $< $(LIBS) -o $@ + +network/ixgbe/ethernet.o: ${ETHERNET_DRIVER_DIR}/ethernet.c ${CHECK_NETDRV_FLAGS_MD5} + mkdir -p network/ixgbe + ${CC} -c ${CFLAGS} ${CFLAGS_network} -I ${ETHERNET_DRIVER_DIR} -o $@ $< + + +-include ixgbe/ethernet.d diff --git a/drivers/network/ixgbe/ethernet.c b/drivers/network/ixgbe/ethernet.c new file mode 100644 index 000000000..f71f43183 --- /dev/null +++ b/drivers/network/ixgbe/ethernet.c @@ -0,0 +1,478 @@ +/* + * Copyright 2026, UNSW + * SPDX-License-Identifier: BSD-2-Clause + * + * Intel Ethernet Controller X550 Datasheet: + * https://cdrdv2-public.intel.com/333369/333369_X550_Datasheet_Rev2.7.pdf + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "ethernet.h" + +__attribute__((__section__(".device_resources"))) device_resources_t device_resources; +__attribute__((__section__(".timer_client_config"))) timer_client_config_t timer_config; +__attribute__((__section__(".net_driver_config"))) net_driver_config_t config; + +#define RX_IRQ_VECTOR 0 +#define TX_IRQ_VECTOR 1 +#define IRQ_CH 16 + +// Minimum inter-interrupt interval specified in 2.048 us units +// at 1 GbE and 10 GbE link +#define IRQ_INTERVAL 40 + +const uintptr_t hw_rx_ring_paddr = 0x10000000; +const uintptr_t hw_rx_ring_vaddr = 0x2400000; +const uintptr_t hw_tx_ring_paddr = 0x10004000; +const uintptr_t hw_tx_ring_vaddr = 0x2404000; + +#define NUM_TX_DESCS 512llu +#define NUM_RX_DESCS 512llu +#define TX_CLEAN_BATCH 32llu + +struct ixgbe_device { + volatile ixgbe_adv_rx_desc_t *rx_ring; + uint32_t rx_head, rx_tail; + volatile ixgbe_adv_tx_desc_t *tx_ring; + uint32_t tx_head, tx_tail; + net_buff_desc_t rx_descr_mdata[NUM_RX_DESCS]; + net_buff_desc_t tx_descr_mdata[NUM_TX_DESCS]; + int init_stage; +} device; + +net_queue_handle_t rx_queue; +net_queue_handle_t tx_queue; + +#define MAX_PACKET_SIZE 1536 + +volatile eth_regs_t *eth_regs = (volatile eth_regs_t *)0x2000000; + +static inline bool hw_tx_ring_empty(void) +{ + return device.tx_head == device.tx_tail; +} + +static inline bool hw_tx_ring_full(void) +{ + return (device.tx_tail + 1) % NUM_TX_DESCS == device.tx_head; +} + +static inline bool hw_rx_ring_empty(void) +{ + return device.rx_head == device.rx_tail; +} + +static inline bool hw_rx_ring_full(void) +{ + return (device.rx_tail + 1) % NUM_RX_DESCS == device.rx_head; +} + +void clear_interrupts(void) +{ + (void)eth_regs->eicr; +} + +void disable_interrupts(void) +{ + eth_regs->eimc = IXGBE_IRQ_CLEAR_MASK; + clear_interrupts(); +} + +void enable_interrupts(void) +{ + // Section 8.2.2.6.10 + // - Bit[5:0] vector number for RX_QUEUE 0, BIT(vector number) is set on EICR if triggered + // - Bit[7] enable IRQ for RX_QUEUE 0 + // - Bit[13:8] vector number for TX_QUEUE 0 + // - Bit[15] enable IRQ for TX_QUEUE 0 + eth_regs->ivar[0] = RX_IRQ_VECTOR | BIT(7) | (TX_IRQ_VECTOR << 8) | BIT(15); + + // Section 7.3.1.6 - No need to enable auto-clear + eth_regs->eiac = 0; + + // Section 8.2.2.6.4 + // - Bits[11:3] Minimum inter-interrupt interval specified in 2.048us units + // at 1 GbE and 10 GbE link + eth_regs->eitr[0] = IXGBE_EITR_ITR_INTERVAL * IRQ_INTERVAL; + clear_interrupts(); + + // Section 8.2.2.6.1 + // - Bit[15:0] for Receive/Transmit Queue Interrupts. We only enable those IRQs + // because the driver doesn't know how to handle IRQs caused by other reasons. + eth_regs->eims = 0xFF; +} + +void print_mac_addr() +{ + uint8_t mac[6]; + uint64_t low = eth_regs->rx_addr[0].lo; + uint64_t high = eth_regs->rx_addr[0].hi; + + mac[0] = low & 0xff; + mac[1] = low >> 8 & 0xff; + mac[2] = low >> 16 & 0xff; + mac[3] = low >> 24; + mac[4] = high & 0xff; + mac[5] = high >> 8 & 0xff; + + LOG_DRIVER("mac - %02x:%02x:%02x:%02x:%02x:%02x\n", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); +} + +uint32_t get_link_speed(void) +{ + uint32_t speed = eth_regs->links; + if ((speed & IXGBE_LINKS_UP) == 0) { + return 0; + } + switch (speed & IXGBE_LINKS_SPEED_82599) { + case IXGBE_LINKS_SPEED_100_82599: + return 100; + case IXGBE_LINKS_SPEED_1G_82599: + return 1000; + case IXGBE_LINKS_SPEED_10G_82599: + return 10000; + default: + return 0; + } +} + +void rx_provide(void) +{ + bool reprocess = true; + while (reprocess) { + bool provided = false; + + while (!hw_rx_ring_full() && !net_queue_empty_free(&rx_queue)) { + net_buff_desc_t buffer; + int err = net_dequeue_free(&rx_queue, &buffer); + assert(!err); + + volatile ixgbe_adv_rx_desc_t *desc = &device.rx_ring[device.rx_tail]; + desc->read.pkt_addr = buffer.io_or_offset; + desc->read.hdr_addr = 0; + + // Section 7.1.5.2.2 - We need a local copy becasue RX descriptor + // does not contain the address at write-back phase. + device.rx_descr_mdata[device.rx_tail] = buffer; + + device.rx_tail = (device.rx_tail + 1) % NUM_RX_DESCS; + provided = true; + } + + if (provided) { + wwmb(); + eth_regs->rx_dma[0].rdt = device.rx_tail; + } + + /* Only request a notification from multiplexer if HW ring is empty */ + if (!hw_rx_ring_full()) { + net_request_signal_free(&rx_queue); + } else { + net_cancel_signal_free(&rx_queue); + } + reprocess = false; + + if (!net_queue_empty_free(&rx_queue) && !hw_rx_ring_full()) { + net_cancel_signal_free(&rx_queue); + reprocess = true; + } + } +} + +static void rx_return(void) +{ + bool packets_transferred = false; + while (!hw_rx_ring_empty()) { + ixgbe_adv_rx_desc_wb_t desc = device.rx_ring[device.rx_head].wb; + if ((desc.upper.status_error & IXGBE_RXDADV_STAT_DD) == 0) { + // The desciptor hasn't been used by hardware, implying no more available packets received + break; + } + if ((desc.upper.status_error & IXGBE_RXDADV_STAT_EOP) == 0) { + // See Table 7-16: DD=1 and EOP=0 + sddf_dprintf("ETH|ERROR: The packet spans across multiple descriptors.\n"); + break; + } + + // The access to `status_error` field should be ordered before the access to the `length` field + rrmb(); + + net_buff_desc_t buffer = device.rx_descr_mdata[device.rx_head]; + buffer.len = desc.upper.length; + int err = net_enqueue_active(&rx_queue, buffer); + assert(!err); + + packets_transferred = true; + device.rx_head = (device.rx_head + 1) % NUM_RX_DESCS; + } + + if (packets_transferred && net_require_signal_active(&rx_queue)) { + net_cancel_signal_active(&rx_queue); + microkit_notify(config.virt_rx.id); + } +} + +void tx_provide(void) +{ + bool reprocess = true; + while (reprocess) { + bool provided = false; + + while (!(hw_tx_ring_full()) && !net_queue_empty_active(&tx_queue)) { + + net_buff_desc_t buffer; + int err = net_dequeue_active(&tx_queue, &buffer); + assert(!err); + + volatile ixgbe_adv_tx_desc_t *desc = &device.tx_ring[device.tx_tail]; + desc->read.buffer_addr = buffer.io_or_offset; + desc->read.cmd_type_len = IXGBE_ADVTXD_DCMD_EOP | IXGBE_ADVTXD_DCMD_RS | IXGBE_ADVTXD_DCMD_IFCS + | IXGBE_ADVTXD_DCMD_DEXT | IXGBE_ADVTXD_DTYP_DATA | (uint32_t)buffer.len; + desc->read.olinfo_status = ((uint32_t)buffer.len << IXGBE_ADVTXD_PAYLEN_SHIFT); + + // Section 7.2.3.2.3 - We need a local copy becasue TX descriptor + // does not contain the address at write-back phase. + device.tx_descr_mdata[device.tx_tail] = buffer; + + device.tx_tail = (device.tx_tail + 1) % NUM_TX_DESCS; + provided = true; + } + + if (provided) { + wwmb(); + eth_regs->tx_dma[0].tdt = device.tx_tail; + eth_regs->tx_dma[0].tdt; // Write flush + } + + net_request_signal_active(&tx_queue); + reprocess = false; + + if (!hw_tx_ring_full() && !net_queue_empty_active(&tx_queue)) { + net_cancel_signal_active(&tx_queue); + reprocess = true; + } + } +} + +void tx_return(void) +{ + bool enqueued = false; + while (!hw_tx_ring_empty()) { + /* Ensure that this buffer has been sent by the device */ + ixgbe_adv_tx_desc_wb_t hw_desc = device.tx_ring[device.tx_head].wb; + + if ((hw_desc.status & IXGBE_ADVTXD_STAT_DD) == 0) + break; + + net_buff_desc_t descr_mdata = device.tx_descr_mdata[device.tx_head]; + int err = net_enqueue_free(&tx_queue, descr_mdata); + assert(!err); + enqueued = true; + + device.tx_head = (device.tx_head + 1) % NUM_TX_DESCS; + } + + if (enqueued && net_require_signal_free(&tx_queue)) { + net_cancel_signal_free(&tx_queue); + microkit_notify(config.virt_tx.id); + } +} + +void init(void) +{ + device.rx_ring = (void *)hw_rx_ring_vaddr; + device.tx_ring = (void *)hw_tx_ring_vaddr; + + net_queue_init(&rx_queue, config.virt_rx.free_queue.vaddr, config.virt_rx.active_queue.vaddr, + config.virt_rx.num_buffers); + net_queue_init(&tx_queue, config.virt_tx.free_queue.vaddr, config.virt_tx.active_queue.vaddr, + config.virt_tx.num_buffers); + + // Disable Interrupts, see Section 4.6.3.1 + disable_interrupts(); + + // Master disable prior to link reset, see Section 4.2.1.7 + eth_regs->ctrl = IXGBE_CTRL_PCIE_MASTER_DISABLE; + while (eth_regs->status & IXGBE_STATUS_PCIE_MASTER_STATUS); + + // Global Reset and General Configuration, see Section 4.6.3.2 + eth_regs->ctrl |= IXGBE_CTRL_RST; + while ((eth_regs->ctrl & IXGBE_CTRL_RST_MASK) != 0); + + // Wait at least 10ms + sddf_timer_set_timeout(timer_config.driver_id, 100 * NS_IN_MS); +} + +void init_1(void) +{ + device.init_stage = 1; + // section 4.6.3.1 - disable interrupts again after reset + disable_interrupts(); + + // section 4.6.3 - wait for EEPROM auto read completion + while ((eth_regs->eec & IXGBE_EEC_ARD) != IXGBE_EEC_ARD); + + // section 4.6.3 - wait for dma initialization done + while ((eth_regs->rdrxctl & IXGBE_RDRXCTL_DMAIDONE) != IXGBE_RDRXCTL_DMAIDONE); + + // section 4.6.4 - initialize link (auto negotiation) + // link auto-configuration register should already be set correctly + // datasheet wants us to wait for the link here, but we can continue and wait afterwards + + // section 4.6.5 - statistical counters + // Initialise the Rx statistic registers. + eth_regs->rqsmr[0] = 0; + // reset-on-read registers, just read them once + eth_regs->gprc; + eth_regs->gptc; + eth_regs->gorcl; + eth_regs->gorch; + eth_regs->gotcl; + eth_regs->gotch; + + // section 4.6.7 - init rx + { + // disable rx while re-configuring it + eth_regs->rxctrl &= (~IXGBE_RXCTRL_RXEN); + + // Section 8.2.2.8.23 + // - Default MRQC: No DCB, No RSS: Queue 0 is used for all packets. + + eth_regs->rxpbsize[0] = IXGBE_RXPBSIZE_128KB; + for (int i = 1; i < 8; i++) { + eth_regs->rxpbsize[i] = 0; + } + + eth_regs->hlreg0 |= IXGBE_HLREG0_RXCRCSTRP; + eth_regs->rdrxctl |= IXGBE_RDRXCTL_CRCSTRIP; + + // accept broadcast packets, promiscuous + eth_regs->fctrl |= IXGBE_FCTRL_BAM | IXGBE_FCTRL_MPE | IXGBE_FCTRL_UPE; + + // use only queue 0 + eth_regs->rx_dma[0].srrctl &= ~IXGBE_SRRCTL_DESCTYPE_MASK; + eth_regs->rx_dma[0].srrctl |= IXGBE_SRRCTL_DESCTYPE_ADV_ONEBUF | IXGBE_SRRCTL_DROP_EN; + eth_regs->rx_dma[0].rdbal = (uint32_t)(hw_rx_ring_paddr & 0xFFFFFFFFull); + eth_regs->rx_dma[0].rdbah = (uint32_t)(hw_rx_ring_paddr >> 32); + eth_regs->rx_dma[0].rdlen = NUM_RX_DESCS * sizeof(ixgbe_adv_rx_desc_t); + eth_regs->rx_dma[0].rdh = 0; + eth_regs->rx_dma[0].rdt = 0; + + eth_regs->ctrl_ext = IXGBE_CTRL_EXT_NS_DIS; + eth_regs->rxctrl |= IXGBE_RXCTRL_RXEN; + eth_regs->rx_dma[0].rxdctl = IXGBE_RXDCTL_ENABLE; + while ((eth_regs->rx_dma[0].rxdctl & IXGBE_RXDCTL_ENABLE) == 0); + } + + // section 4.6.8 - init tx + { + eth_regs->txpbsize[0] = IXGBE_TXPBSIZE_40KB; + for (int i = 1; i < 8; i++) { + eth_regs->txpbsize[i] = 0; + } + + eth_regs->txpbthresh[0] = 0xA0; + for (int i = 1; i < 8; i++) { + eth_regs->txpbthresh[i] = 0; + } + + eth_regs->tx_dma[0].tdbal = (uint32_t)(hw_tx_ring_paddr & 0xFFFFFFFFull); + eth_regs->tx_dma[0].tdbah = (uint32_t)(hw_tx_ring_paddr >> 32); + eth_regs->tx_dma[0].tdh = 0; + eth_regs->tx_dma[0].tdt = 0; + + eth_regs->tx_dma[0].tdlen = NUM_TX_DESCS * sizeof(ixgbe_adv_tx_desc_t); + + // Section 8.2.2.10.10 + // - Bits[6:0] pthresh: pre-fetch if less than `pthresh` unprocessed descriptors valid + // - Bits[14:8] hthresh: pre-fetch if at least `hthresh` unprocessed descriptors valid + // - Bits[22:16] wthresh: number of processed descriptors before write-back + eth_regs->tx_dma[0].txdctl &= ~(0x7F | (0x7F << 8) | (0x7F << 16)); // clear bits + eth_regs->tx_dma[0].txdctl |= (36 | (8 << 8) | (4 << 16)); // from DPDK + + // final step: enable DMA + eth_regs->dmatxctl = IXGBE_DMATXCTL_TE; + eth_regs->tx_dma[0].txdctl |= IXGBE_TXDCTL_ENABLE; + while ((eth_regs->tx_dma[0].txdctl & IXGBE_TXDCTL_ENABLE) == 0); + } + + // wait some time for the link to come up + sddf_timer_set_timeout(timer_config.driver_id, 100 * NS_IN_MS); +} + +void init_2(void) +{ + uint32_t speed = get_link_speed(); + if (speed == 0) { + sddf_timer_set_timeout(timer_config.driver_id, 100 * NS_IN_MS); + return; + } + + device.init_stage = 2; + + // sleep for 10 seconds. Just stabilize the hardware + // Well. this ugliness costed us two days of debugging. + sddf_timer_set_timeout(timer_config.driver_id, 3 * NS_IN_S); +} + +void init_3(void) +{ + device.init_stage = 3; + + rx_provide(); + tx_provide(); + + enable_interrupts(); + + LOG_DRIVER("Finish NIC reset\n"); + device.init_stage = 4; +} + +void notified(microkit_channel ch) +{ + if (ch == timer_config.driver_id) { + if (device.init_stage == 0) { + init_1(); + } else if (device.init_stage == 1) { + init_2(); + } else if (device.init_stage == 2) { + init_3(); + } + } else if (device.init_stage != 4 && ch == IRQ_CH) { + sddf_deferred_irq_ack(ch); + } else if (device.init_stage == 4) { + if (ch == IRQ_CH) { + // read-to-clear + uint32_t cause = eth_regs->eicr; + if (cause & BIT(TX_IRQ_VECTOR)) { + tx_return(); + tx_provide(); + } + if (cause & BIT(RX_IRQ_VECTOR)) { + rx_return(); + rx_provide(); + } + + /* + * Delay calling into the kernel to ack the IRQ until the next loop + * in the event handler loop. + */ + sddf_deferred_irq_ack(ch); + } else if (ch == config.virt_tx.id) { + tx_provide(); + } else if (ch == config.virt_rx.id) { + rx_provide(); + } + } +} diff --git a/drivers/network/ixgbe/ethernet.h b/drivers/network/ixgbe/ethernet.h new file mode 100644 index 000000000..64297c871 --- /dev/null +++ b/drivers/network/ixgbe/ethernet.h @@ -0,0 +1,345 @@ +/* + * Copyright 2026, UNSW + * SPDX-License-Identifier: BSD-2-Clause + * + * Intel Ethernet Controller X550 datasheet: + * https://www.intel.com/content/www/us/en/content-details/333369/intel-ethernet-controller-x550-datasheet.html + */ +#pragma once +#include +#include + +// #define DEBUG_DRIVER + +#ifdef DEBUG_DRIVER +#define LOG_DRIVER(...) do{ sddf_dprintf("ETH DRIVER|INFO: "); sddf_dprintf(__VA_ARGS__); }while(0) +#else +#define LOG_DRIVER(...) do{}while(0) +#endif + +#define LOG_DRIVER_ERR(...) do{ sddf_printf("ETH DRIVER|ERROR: "); sddf_printf(__VA_ARGS__); }while(0) + +#define IXGBE_CTRL_LNK_RST 0x00000008 /* Link Reset. Resets everything. */ +#define IXGBE_CTRL_RST 0x04000000 /* Reset (SW) */ +#define IXGBE_CTRL_RST_MASK (IXGBE_CTRL_LNK_RST | IXGBE_CTRL_RST) +#define IXGBE_CTRL_PCIE_MASTER_DISABLE (1 << 2) + +#define IXGBE_STATUS_PCIE_MASTER_STATUS (1 << 19) +#define IXGBE_CTRL_EXT_DRV_LOAD (1 << 28) + +#define IXGBE_EEC_ARD 0x00000200 /* EEPROM Auto Read Done */ +#define IXGBE_RDRXCTL_DMAIDONE 0x00000008 /* DMA init cycle done */ + +#define IXGBE_AUTOC_LMS_SHIFT 13 +#define IXGBE_AUTOC_LMS_MASK (0x7 << IXGBE_AUTOC_LMS_SHIFT) +#define IXGBE_AUTOC_LMS_10G_SERIAL (0x3 << IXGBE_AUTOC_LMS_SHIFT) +#define IXGBE_AUTOC_10G_PMA_PMD_MASK 0x00000180 +#define IXGBE_AUTOC_10G_PMA_PMD_SHIFT 7 +#define IXGBE_AUTOC_10G_XAUI (0x0 << IXGBE_AUTOC_10G_PMA_PMD_SHIFT) +#define IXGBE_AUTOC_AN_RESTART 0x00001000 + +#define IXGBE_RXCTRL_RXEN 0x00000001 /* Enable Receiver */ + +#define IXGBE_RXPBSIZE_128KB 0x00020000 /* 128KB Packet Buffer */ + +#define IXGBE_HLREG0_RXCRCSTRP 0x00000002 /* bit 1 */ +#define IXGBE_HLREG0_LPBK (1 << 15) +#define IXGBE_RDRXCTL_CRCSTRIP 0x00000002 /* CRC Strip */ + +#define IXGBE_FCTRL_BAM 0x00000400 /* Broadcast Accept Mode */ + +#define IXGBE_CTRL_EXT_NS_DIS 0x00010000 /* No Snoop disable */ + +#define IXGBE_HLREG0_TXCRCEN 0x00000001 /* bit 0 */ +#define IXGBE_HLREG0_TXPADEN 0x00000400 /* bit 10 */ + +#define IXGBE_TXPBSIZE_40KB 0x0000A000 /* 40KB Packet Buffer */ +#define IXGBE_RTTDCS_ARBDIS 0x00000040 /* DCB arbiter disable */ + +#define IXGBE_DMATXCTL_TE 0x1 /* Transmit Enable */ +#define IXGBE_RXDCTL_ENABLE 0x02000000 /* Ena specific Rx Queue, bit 25 */ +#define IXGBE_TXDCTL_ENABLE 0x02000000 /* Ena specific Tx Queue, bit 25 */ +#define IXGBE_RSCINT_RSCEN 0x00000001 /* RSC Enable */ +#define IXGBE_RSCCTL_RSCEN 0x00000001 /* RSC Enable */ +/* RSCCTL bit 3:2 Maximum descriptors per large receive */ +#define IXGBE_RSCCTL_MAXDESC_1 0x0 /* 00b = Maximum Descriptors 1 */ +#define IXGBE_RSCCTL_MAXDESC_4 0x4 /* 01b = Maximum Descriptors 4 */ +#define IXGBE_RSCCTL_MAXDESC_8 0x8 /* 10b = Maximum Descriptors 8 */ +#define IXGBE_RSCCTL_MAXDESC_16 0xc /* 11b = Maximum Descriptors 16 */ +#define IXGBE_EITR_ITR_INTERVAL 0x00000008 /* bit 3 */ + +#define IXGBE_FCTRL_MPE 0x00000100 /* Multicast Promiscuous Ena*/ +#define IXGBE_FCTRL_UPE 0x00000200 /* Unicast Promiscuous Ena */ + +#define IXGBE_LINKS_UP 0x40000000 +#define IXGBE_LINKS_SPEED_82599 0x30000000 +#define IXGBE_LINKS_SPEED_100_82599 0x10000000 +#define IXGBE_LINKS_SPEED_1G_82599 0x20000000 +#define IXGBE_LINKS_SPEED_10G_82599 0x30000000 + +#define IXGBE_IVAR_ALLOC_VAL 0x80 /* Interrupt Allocation valid */ +#define IXGBE_EICR_RTX_QUEUE 0x0000FFFF /* RTx Queue Interrupt */ + +/* Interrupt clear mask */ +#define IXGBE_IRQ_CLEAR_MASK 0xFFFFFFFF + +#define IXGBE_GPIE_MSIX_MODE 0x00000010 /* MSI-X mode */ +#define IXGBE_GPIE_OCD 0x00000020 /* Other Clear Disable */ +#define IXGBE_GPIE_EIMEN 0x00000040 /* Immediate Interrupt Enable */ +#define IXGBE_GPIE_EIAME 0x40000000 +#define IXGBE_GPIE_PBA_SUPPORT 0x80000000 + +#define SRRCTL_BSIZEHEADER_MASK 0x3F00 +#define IXGBE_SRRCTL_DESCTYPE_MASK 0x0E000000 +#define IXGBE_SRRCTL_DESCTYPE_ADV_ONEBUF 0x02000000 +#define IXGBE_SRRCTL_DROP_EN 0x10000000 + +#define IXGBE_RXD_STAT_DD 0x01 /* Descriptor Done */ +#define IXGBE_RXD_STAT_EOP 0x02 /* End of Packet */ +#define IXGBE_RXDADV_STAT_DD IXGBE_RXD_STAT_DD /* Done */ +#define IXGBE_RXDADV_STAT_EOP IXGBE_RXD_STAT_EOP /* End of Packet */ + +#define IXGBE_ADVTXD_PAYLEN_SHIFT 14 /* Adv desc PAYLEN shift */ +#define IXGBE_TXD_CMD_EOP 0x01000000 /* End of Packet */ +#define IXGBE_ADVTXD_DCMD_EOP IXGBE_TXD_CMD_EOP /* End of Packet */ +#define IXGBE_TXD_CMD_RS 0x08000000 /* Report Status */ +#define IXGBE_ADVTXD_DCMD_RS IXGBE_TXD_CMD_RS /* Report Status */ +#define IXGBE_TXD_CMD_IFCS 0x02000000 /* Insert FCS (Ethernet CRC) */ +#define IXGBE_ADVTXD_DCMD_IFCS IXGBE_TXD_CMD_IFCS /* Insert FCS */ +#define IXGBE_TXD_CMD_DEXT 0x20000000 /* Desc extension (0 = legacy) */ +#define IXGBE_ADVTXD_DTYP_DATA 0x00300000 /* Adv Data Descriptor */ +#define IXGBE_ADVTXD_DCMD_DEXT IXGBE_TXD_CMD_DEXT /* Desc ext 1=Adv */ +#define IXGBE_TXD_STAT_DD 0x00000001 /* Descriptor Done */ +#define IXGBE_ADVTXD_STAT_DD IXGBE_TXD_STAT_DD /* Descriptor Done */ + +#define IXGBE_TXPBSIZE_MAX 0x00028000 /* 160KB, section 7.2.1.2.2 */ + +// bit 15:0, Receive/Transmit Queue Interrupts, activated on receive/transmit +// events.The mapping of queue to the RTxQ bits is done by the IVAR registers +#define IXGBE_EICR_RTXQ_BASE 1 +// Missed packet interrupt is activated for each received packet that +// overflows the Rx packet buffer (overrun) +#define IXGBE_EICR_RX_MISS (1 << 17) + +typedef struct { + uint64_t pkt_addr; // Packet buffer address + uint64_t hdr_addr; // Header buffer address +} ixgbe_adv_rx_desc_read_t; + +/* Receive Descriptor - Advanced */ +typedef struct { + uint16_t pkt_info; // RSS, Pkt type + uint16_t hdr_info; // Splithdr, hdrlen +} ixgbe_adv_rx_desc_wb_lower_lo_dword_hs_rss_t; + +typedef union { + uint32_t data; + ixgbe_adv_rx_desc_wb_lower_lo_dword_hs_rss_t hs_rss; +} ixgbe_adv_rx_desc_wb_lower_lo_dword_t; + +typedef struct { + uint16_t ip_id; // IP id + uint16_t csum; // Packet Checksum +} ixgbe_adv_rx_desc_wb_lower_hi_dword_csum_ip_t; + +typedef union { + uint32_t rss; // RSS Hash + ixgbe_adv_rx_desc_wb_lower_hi_dword_csum_ip_t csum_ip; +} ixgbe_adv_rx_desc_wb_lower_hi_dword_t; + +typedef struct { + ixgbe_adv_rx_desc_wb_lower_lo_dword_t lo_dword; + ixgbe_adv_rx_desc_wb_lower_hi_dword_t hi_dword; +} ixgbe_adv_rx_desc_wb_lower_t; + +typedef struct { + uint32_t status_error; // ext status/error + uint16_t length; // Packet length + uint16_t vlan; // VLAN tag +} ixgbe_adv_rx_desc_wb_upper_t; + +typedef struct { + ixgbe_adv_rx_desc_wb_lower_t lower; + ixgbe_adv_rx_desc_wb_upper_t upper; +} ixgbe_adv_rx_desc_wb_t; + +typedef union { + ixgbe_adv_rx_desc_read_t read; + ixgbe_adv_rx_desc_wb_t wb; // writeback +} ixgbe_adv_rx_desc_t; + +/* Transmit Descriptor - Advanced */ +typedef struct { + uint64_t buffer_addr; // Address of descriptor's data buf + uint32_t cmd_type_len; + uint32_t olinfo_status; +} ixgbe_adv_tx_desc_read_t; + +typedef struct { + uint64_t rsvd; // Reserved + uint32_t nxtseq_seed; + uint32_t status; +} ixgbe_adv_tx_desc_wb_t; + +typedef union { + ixgbe_adv_tx_desc_read_t read; + ixgbe_adv_tx_desc_wb_t wb; +} ixgbe_adv_tx_desc_t; + +typedef struct { + uint32_t lo; + uint32_t hi; +} rx_addr_t; + +typedef struct { + uint32_t rdbal; // 0x00001000 + 0x40*n Receive Descriptor Base Address Low + uint32_t rdbah; // 0x00001004 + 0x40*n Receive Descriptor Base Address High + uint32_t rdlen; // 0x00001008 + 0x40*n Receive Descriptor Length + uint8_t unused1[4]; // 0x0000100C + 0x40*n + uint32_t rdh; // 0x00001010 + 0x40*n Receive Descriptor Head + uint32_t srrctl; // 0x00001014 + 0x40*n Split Receive Control Registers + uint32_t rdt; // 0x00001018 + 0x40*n Receive Descriptor Tail + uint8_t unused2[12]; // 0x0000101C + 0x40*n + uint32_t rxdctl; // 0x00001028 + 0x40*n Receive Descriptor Control + uint32_t rscctl; // 0x0000102C + 0x40*n RSC Control + uint8_t unused3[16]; // 0x00001030 + 0x40*n +} rx_dma_regs_t; + +typedef struct { + uint32_t tdbal; // 0x00006000 + 0x40*n Transmit Descriptor Base Address Low + uint32_t tdbah; // 0x00006004 + 0x40*n Transmit Descriptor Base Address High + uint32_t tdlen; // 0x00006008 + 0x40*n Transmit Descriptor Length + uint8_t unused1[4]; // 0x0000600C + 0x40*n + uint32_t tdh; // 0x00006010 + 0x40*n Transmit Descriptor Head + uint8_t unused2[4]; // 0x00006014 + 0x40*n + uint32_t tdt; // 0x00006018 + 0x40*n Transmit Descriptor Tail + uint8_t unused3[12]; // 0x0000601C + 0x40*n + uint32_t txdctl; // 0x00006028 + 0x40*n Transmit Descriptor Control + uint8_t unused4[12]; // 0x0000602C + 0x40*n + uint32_t tdwbal; // 0x00006038 + 0x40*n Tx Descriptor Completion Write Back Address Low + uint32_t tdwbah; // 0x0000603C + 0x40*n Tx Descriptor Completion Write Back Address High +} tx_dma_regs_t; + +typedef struct { + uint32_t ctrl; // 0x00000 Device Control Register + uint8_t unused1[4]; // 0x00004 + uint32_t status; // 0x00008 Device Status Register + uint8_t unused2[12]; // 0x0000C + uint32_t ctrl_ext; // 0x00018 Extended Device Control Register + uint8_t unused3[2020]; // 0x0001C + + uint32_t eicr; // 0x00800 Extended Interrupt Cause Register + uint8_t unused4[4]; // 0x00804 + uint32_t eics; // 0x00808 Extended Interrupt Cause Set Register + uint8_t unused5[4]; // 0x0080C + uint32_t eiac; // 0x00810 Extended Interrupt Auto Clear Register + uint8_t unused6[12]; // 0x00814 + + uint32_t eitr[24]; // 0x00820 + 0x4*n Extended Interrupt Throttle Registers + uint32_t eims; // 0x00880 Extended Interrupt Mask Set/Read Register + uint8_t unused7[4]; // 0x00884 + uint32_t eimc; // 0x00888 Extended Interrupt Mask Clear Register + uint8_t unused8[12]; // 0x0088C + uint32_t gpie; // 0x00898 General Purpose Interrupt Enable + uint8_t unused9[100]; // 0x0089C + + uint32_t ivar[64]; // 0x00900 + 0x4*n Interrupt Vector Allocation Registers + uint8_t unused10[1536]; // 0x00A00 + + rx_dma_regs_t rx_dma[64]; // 0x01000 Receive DMA Registers + uint8_t unused11[768]; // 0x02000 + + uint32_t rqsmr[32]; // 0x02300 + 0x4*n Receive Queue Statistic Mapping Registers + uint8_t unused12[2944]; // 0x02380 + + uint32_t rdrxctl; // 0x02F00 Receive DMA Control Register + uint8_t unused13[252]; // 0x02F04 + + uint32_t rxctrl; // 0x03000 Receive Control Register + uint8_t unused14[3068]; // 0x03004 + + uint32_t rxpbsize[8]; // 0x03C00 + 0x4*n Receive Packet Buffer Size + uint8_t unused15[1108]; // 0x03C20 + + uint32_t gprc; // 0x04074 Good Packets Received Count + uint8_t unused16[8]; // 0x04078 + uint32_t gptc; // 0x04080 Good Packets Transmitted Count + uint8_t unused17[4]; // 0x04084 + uint32_t gorcl; // 0x04088 Good Octets Received Count Low + uint32_t gorch; // 0x0408C Good Octets Received Count High + uint32_t gotcl; // 0x04090 Good Octets Transmitted Count Low + uint32_t gotch; // 0x04094 Good Octets Transmitted Count High + uint8_t unused18[424]; // 0x04098 + + uint32_t hlreg0; // 0x04240 Highlander Control 0 Register + uint8_t unused19[96]; // 0x04244 + uint32_t links; // 0x042A4 Link Status Register + uint8_t unused20[1704]; // 0x042A8 + + uint32_t txpbthresh[8]; // 0x04950 + 0x4*n Tx Packet Buffer Threshold + uint8_t unused21[272]; // 0x04970 + + uint32_t dmatxctl; // 0x04A80 DMA Tx Control + uint8_t unused22[1532]; // 0x04A84 + + uint32_t fctrl; // 0x05080 Filter Control Register + uint8_t unused23[3964]; // 0x05084 + + tx_dma_regs_t tx_dma[64]; // 0x06000 Transmite Registers + uint8_t unused24[4352]; // 0x07000 + + uint32_t dtxmxszrq; // 0x08100 DMA Tx TCP Max Allow Size Requests + uint8_t unused25[1692]; // 0x08104 + + uint32_t txdgpc; // 0x087A0 DMA Good Tx Packet Counter + uint32_t txdgbcl; // 0x087A4 DMA Good Tx Byte Counter Low + uint32_t txdgbch; // 0x087A8 DMA Good Tx Byte Counter High + uint8_t unused26[6740]; // 0x087AC + + rx_addr_t rx_addr[128]; // 0x0A200 + 0x8*n Receive Address + uint8_t unused27[9728]; // 0x0A600 + + uint32_t txpbsize[8]; // 0x0CC00 + 0x4*n Transmit Packet Buffer Size + uint8_t unused28[13296]; // 0x0CC20 + + uint32_t eec; // 0x10010 EEPROM Mode Control Register + uint8_t unused29[316]; // 0x10014 + uint32_t factps; // 0x10150 Function Active and Power State to Manageability +} eth_regs_t; + +struct pci_config_space { + // Device Identification + uint16_t vendor_id; // 0x00: Vendor ID + uint16_t device_id; // 0x02: Device ID + uint16_t command; // 0x04: Command Register + uint16_t status; // 0x06: Status Register + uint8_t revision_id; // 0x08: Revision ID + uint8_t prog_if; // 0x09: Programming Interface + uint8_t subclass; // 0x0A: Sub Class Code + uint8_t class_code; // 0x0B: Base Class Code + uint8_t cache_line_size; // 0x0C: Cache Line Size + uint8_t latency_timer; // 0x0D: Latency Timer + uint8_t header_type; // 0x0E: Header Type + uint8_t bist; // 0x0F: Built-in Self Test + + // Base Address Registers (BARs) + uint32_t bar[6]; // 0x10-0x27: Base Address Registers + + // Subsystem Information + uint32_t cardbus_cis_ptr; // 0x28: CardBus CIS Pointer + uint16_t subsystem_vendor_id; // 0x2C: Subsystem Vendor ID + uint16_t subsystem_device_id; // 0x2E: Subsystem Device ID + uint32_t expansion_rom_addr; // 0x30: Expansion ROM Base Address + + // Capabilities and Interrupts + uint8_t cap_ptr; // 0x34: Capabilities Pointer + uint8_t reserved1[3]; // 0x35-0x37: Reserved + uint32_t reserved2; // 0x38-0x3B: Reserved + uint8_t interrupt_line; // 0x3C: Interrupt Line + uint8_t interrupt_pin; // 0x3D: Interrupt Pin + uint8_t min_gnt; // 0x3E: Min_Gnt + uint8_t max_lat; // 0x3F: Max_Lat + + // Capability list + uint8_t cap_data[192]; +}; diff --git a/examples/echo_server/echo.mk b/examples/echo_server/echo.mk index eb9fa749d..7be965025 100644 --- a/examples/echo_server/echo.mk +++ b/examples/echo_server/echo.mk @@ -97,7 +97,7 @@ ifneq ($(strip $(DTS)),) $(if $(BENCH_PMU_EVENTS), --bench_pmu_events $(BENCH_PMU_EVENTS)) else $(PYTHON)\ - $(METAPROGRAM) --sddf $(SDDF) --board $(MICROKIT_BOARD) \ + $(METAPROGRAM) --sddf $(SDDF) --board $(X86_BOARD) \ --output . --sdf $(SYSTEM_FILE) --objcopy $(OBJCOPY) --smp $(SMP_CONFIG) \ $(if $(BENCH_PMU_EVENTS), --bench_pmu_events $(BENCH_PMU_EVENTS)) endif diff --git a/examples/echo_server/include/echo.h b/examples/echo_server/include/echo.h index ef2dd8f73..0f51c89c4 100644 --- a/examples/echo_server/include/echo.h +++ b/examples/echo_server/include/echo.h @@ -11,7 +11,7 @@ #define TCP_ECHO_PORT 1236 #define UTILIZATION_PORT 1237 -#define TCP_ECHO_MAX_CONNS 4 +#define TCP_ECHO_MAX_CONNS 10 int setup_udp_socket(void); int setup_utilization_socket(void *benchmark_config); diff --git a/examples/echo_server/include/lwip/lwipopts.h b/examples/echo_server/include/lwip/lwipopts.h index 1254b4613..fb0084f4d 100644 --- a/examples/echo_server/include/lwip/lwipopts.h +++ b/examples/echo_server/include/lwip/lwipopts.h @@ -222,4 +222,4 @@ * while after closing. Increase the max number of concurrent streams to allow * for a few of these while the next benchmark runs. */ -#define MEMP_NUM_TCP_PCB 10 +#define MEMP_NUM_TCP_PCB 20 diff --git a/examples/echo_server/meta.py b/examples/echo_server/meta.py index 0699dfa3b..48871b872 100644 --- a/examples/echo_server/meta.py +++ b/examples/echo_server/meta.py @@ -18,6 +18,7 @@ MemoryRegion = SystemDescription.MemoryRegion Map = SystemDescription.Map Channel = SystemDescription.Channel +IrqIoapic = SystemDescription.IrqIoapic """ @@ -234,7 +235,7 @@ def generate( ) if board.arch == SystemDescription.Arch.X86_64: - serial_port = SystemDescription.IoPort(0x3F8, 8, 0) + serial_port = SystemDescription.IoPort(board.serial, 8, 0) uart_driver.add_ioport(serial_port) ethernet_driver = ProtectionDomain( @@ -273,7 +274,7 @@ def generate( sdf.add_mr(mbox) ethernet_driver.add_map(Map(mbox, 0x3000000, perms="rw", cached=False)) - if board.arch == SystemDescription.Arch.X86_64: + if board.name == "qemu_virt_x86": hw_net_rings = SystemDescription.MemoryRegion( sdf, "hw_net_rings", 65536, paddr=0x7A000000 ) @@ -301,6 +302,43 @@ def generate( pci_config_data_port = SystemDescription.IoPort(0xCFC, 4, 2) ethernet_driver.add_ioport(pci_config_data_port) + if board.name == "vb_105" or board.name == "viscous": + # Ethernet driver requires timer access to wait for reconfiguration + timer_system.add_client(ethernet_driver) + + ixgbe_regs = MemoryRegion( + sdf, name="eth_region_0", size=0x100000, paddr=board.ethernet + ) + sdf.add_mr(ixgbe_regs) + ethernet_driver.add_map( + Map(ixgbe_regs, vaddr=0x2000000, perms="rw", cached=False) + ) + + # We can use `write-back` caching (i.e. cached=True) on x86 because the bus + # will perform cache snooping in hardware, making it DMA coherent. + hw_rx_ring_buffer = MemoryRegion( + sdf, name="hw_rx_ring_buffer", size=0x4000, paddr=0x10000000 + ) + sdf.add_mr(hw_rx_ring_buffer) + ethernet_driver.add_map(Map(hw_rx_ring_buffer, vaddr=0x2400000, perms="rw")) + + hw_tx_ring_buffer = MemoryRegion( + sdf, name="hw_tx_ring_buffer", size=0x4000, paddr=0x10004000 + ) + sdf.add_mr(hw_tx_ring_buffer) + ethernet_driver.add_map(Map(hw_tx_ring_buffer, vaddr=0x2404000, perms="rw")) + + # Legacy I/O APIC + eth_irq = SystemDescription.IrqIoapic( + ioapic_id=0, + pin=16, + vector=8, + trigger=IrqIoapic.Trigger.LEVEL, + polarity=IrqIoapic.Polarity.ACTIVELOW, + id=16, + ) + ethernet_driver.add_irq(eth_irq) + net_virt_tx = ProtectionDomain( "net_virt_tx", "network_virt_tx.elf", @@ -484,7 +522,7 @@ def generate( assert client1_lib_sddf_lwip.connect() assert client1_lib_sddf_lwip.serialise_config(output_dir) - if board.name == "rpi4b_1gb": + if board.name == "rpi4b_1gb" or board.name == "vb_105" or board.name == "viscous": update_elf_section( "eth_driver.elf", "timer_client_config", "timer_client_ethernet_driver" ) diff --git a/include/sddf/benchmark/config.h b/include/sddf/benchmark/config.h index a36d9391f..9408c033c 100644 --- a/include/sddf/benchmark/config.h +++ b/include/sddf/benchmark/config.h @@ -15,7 +15,7 @@ * on non-benchmarking configurations. * This defines whether we actually try to benchmark, setup the PMU etc. */ -#if defined(CONFIG_ENABLE_BENCHMARKS) && (defined(CONFIG_ARCH_ARM) || defined(CONFIG_ARCH_RISCV)) +#if defined(CONFIG_ENABLE_BENCHMARKS) #define ENABLE_BENCHMARKING 1 #else #define ENABLE_BENCHMARKING 0 diff --git a/tools/make/board/x86_64_generic.mk b/tools/make/board/x86_64_generic.mk index de67d78a0..6c61a9b41 100644 --- a/tools/make/board/x86_64_generic.mk +++ b/tools/make/board/x86_64_generic.mk @@ -14,19 +14,41 @@ UART_DRIV_DIR ?= pc99 CPU := generic -SEL4_64B := $(MICROKIT_SDK)/board/$(MICROKIT_BOARD)/$(MICROKIT_CONFIG)/elf/sel4.elf -SEL4_32B := $(MICROKIT_SDK)/board/$(MICROKIT_BOARD)/$(MICROKIT_CONFIG)/elf/sel4_32.elf - -QEMU := qemu-system-x86_64 -QEMU_ARCH_ARGS := -machine q35 \ - -kernel $(SEL4_32B) \ - -m size=2G \ - -serial mon:stdio \ - -cpu qemu64,+fsgsbase,+pdpe1gb,+pcid,+invpcid,+xsave,+xsaves,+xsaveopt \ - -initrd $(IMAGE_FILE) - -# The PCI slot is hard-coded in the virtIO drivers for now, so we have to -# specify the slot with QEMU as well. -# See https://github.com/au-ts/sddf/issues/607 for details. -QEMU_NET_ARGS ?= -device virtio-net-pci,netdev=netdev0,addr=0x2.0 -QEMU_BLK_ARGS ?= -device virtio-blk-pci,drive=hd,addr=0x3.0 +ifeq (${X86_BOARD},) + X86_BOARD := qemu_virt_x86 +endif + +ifeq (${X86_BOARD},qemu_virt_x86) + BLK_DRIV_DIR ?= virtio/pci + NET_DRIV_DIR ?= virtio/pci + ETH_DRIV ?= eth_driver_virtio.elf + UART_DRIV_DIR ?= pc99 + + SEL4_64B := $(MICROKIT_SDK)/board/$(MICROKIT_BOARD)/$(MICROKIT_CONFIG)/elf/sel4.elf + SEL4_32B := $(MICROKIT_SDK)/board/$(MICROKIT_BOARD)/$(MICROKIT_CONFIG)/elf/sel4_32.elf + + QEMU := qemu-system-x86_64 + QEMU_ARCH_ARGS := -machine q35 \ + -kernel $(SEL4_32B) \ + -m size=2G \ + -serial mon:stdio \ + -cpu qemu64,+fsgsbase,+pdpe1gb,+pcid,+invpcid,+xsave,+xsaves,+xsaveopt \ + -initrd $(IMAGE_FILE) + + # The PCI slot is hard-coded in the virtIO drivers for now, so we have to + # specify the slot with QEMU as well. + # See https://github.com/au-ts/sddf/issues/607 for details. + QEMU_NET_ARGS ?= -device virtio-net-pci,netdev=netdev0,addr=0x2.0 + QEMU_BLK_ARGS ?= -device virtio-blk-pci,drive=hd,addr=0x3.0 + +else ifeq ($(X86_BOARD), $(filter ${X86_BOARD},makatea vb_105 viscous)) + NET_DRIV_DIR := ixgbe + ETH_DRIV := eth_driver_ixgbe.elf + UART_DRIV_DIR := pc99 + + DTS := + SEL4_64B = $(MICROKIT_SDK)/board/$(MICROKIT_BOARD)/$(MICROKIT_CONFIG)/elf/sel4.elf + SEL4_32B := $(MICROKIT_SDK)/board/$(MICROKIT_BOARD)/$(MICROKIT_CONFIG)/elf/sel4_32.elf +else +$(error Unsupported X86_BOARD given) +endif diff --git a/tools/make/board/x86_64_generic_vtx.mk b/tools/make/board/x86_64_generic_vtx.mk index e9e1f61c3..5548a0a16 100644 --- a/tools/make/board/x86_64_generic_vtx.mk +++ b/tools/make/board/x86_64_generic_vtx.mk @@ -6,27 +6,49 @@ # Set up variables for the x86_64_generic_vtx # Should be included _before_ toolchain makefile. -BLK_DRIV_DIR := virtio/pci -I2C_DRIV_DIR := -NET_DRIV_DIR := virtio/pci -ETH_DRIV := eth_driver_virtio.elf -TIMER_DRIV_DIR := tsc_hpet -UART_DRIV_DIR := pc99 +BLK_DRIV_DIR ?= virtio/pci +NET_DRIV_DIR ?= virtio/pci +ETH_DRIV ?= eth_driver_virtio.elf +TIMER_DRIV_DIR ?= tsc_hpet +UART_DRIV_DIR ?= pc99 CPU := generic -SEL4_64B := $(MICROKIT_SDK)/board/$(MICROKIT_BOARD)/$(MICROKIT_CONFIG)/elf/sel4.elf -SEL4_32B := $(MICROKIT_SDK)/board/$(MICROKIT_BOARD)/$(MICROKIT_CONFIG)/elf/sel4_32.elf - -QEMU := qemu-system-x86_64 -QEMU_ARCH_ARGS := -accel kvm -cpu host,+sse,+sse2,+fsgsbase,+pdpe1gb,+xsaveopt,+xsave,+vmx,+vme \ - -kernel $(SEL4_32B) \ - -m size=8G \ - -serial mon:stdio \ - -initrd $(IMAGE_FILE) - -# The PCI slot is hard-coded in the virtIO drivers for now, so we have to -# specify the slot with QEMU as well. -# See https://github.com/au-ts/sddf/issues/607 for details. -QEMU_NET_ARGS := -device virtio-net-pci,netdev=netdev0,addr=0x2.0 -QEMU_BLK_ARGS := -device virtio-blk-pci,drive=hd,addr=0x3.0 +ifeq (${X86_BOARD},) + X86_BOARD := qemu_virt_x86 +endif + +ifeq (${X86_BOARD},qemu_virt_x86) + BLK_DRIV_DIR ?= virtio/pci + NET_DRIV_DIR ?= virtio/pci + ETH_DRIV ?= eth_driver_virtio.elf + UART_DRIV_DIR ?= pc99 + + SEL4_64B := $(MICROKIT_SDK)/board/$(MICROKIT_BOARD)/$(MICROKIT_CONFIG)/elf/sel4.elf + SEL4_32B := $(MICROKIT_SDK)/board/$(MICROKIT_BOARD)/$(MICROKIT_CONFIG)/elf/sel4_32.elf + + QEMU := qemu-system-x86_64 + QEMU_ARCH_ARGS := -machine q35 \ + -kernel $(SEL4_32B) \ + -m size=2G \ + -serial mon:stdio \ + -cpu qemu64,+fsgsbase,+pdpe1gb,+pcid,+invpcid,+xsave,+xsaves,+xsaveopt \ + -initrd $(IMAGE_FILE) + + # The PCI slot is hard-coded in the virtIO drivers for now, so we have to + # specify the slot with QEMU as well. + # See https://github.com/au-ts/sddf/issues/607 for details. + QEMU_NET_ARGS ?= -device virtio-net-pci,netdev=netdev0,addr=0x2.0 + QEMU_BLK_ARGS ?= -device virtio-blk-pci,drive=hd,addr=0x3.0 + +else ifeq ($(X86_BOARD), $(filter ${X86_BOARD},makatea vb_105 viscous)) + NET_DRIV_DIR := ixgbe + ETH_DRIV := eth_driver_ixgbe.elf + UART_DRIV_DIR := pc99 + + DTS := + SEL4_64B = $(MICROKIT_SDK)/board/$(MICROKIT_BOARD)/$(MICROKIT_CONFIG)/elf/sel4.elf + SEL4_32B := $(MICROKIT_SDK)/board/$(MICROKIT_BOARD)/$(MICROKIT_CONFIG)/elf/sel4_32.elf +else +$(error Unsupported X86_BOARD given) +endif diff --git a/tools/meta/board.py b/tools/meta/board.py index eb233e29a..81aa485c8 100644 --- a/tools/meta/board.py +++ b/tools/meta/board.py @@ -40,9 +40,9 @@ class Board: name: str arch: SystemDescription.Arch paddr_top: int - serial: Optional[str] = None - ethernet: Optional[str] = None - timer: Optional[str] = None + serial: Optional[str | int] = None + ethernet: Optional[str | int] = None + timer: Optional[str | int] = None i2c: Optional[str] = None partition: int = 0 blk: Optional[str] = None @@ -208,4 +208,28 @@ class Board: timer=None, serial=None, ), + Board( + name="qemu_virt_x86", + arch=SystemDescription.Arch.X86_64, + paddr_top=0x70000000, + serial=0x3F8, + timer=0xFED00000, + ethernet=0xFE000000, + ), + Board( + name="vb_105", + arch=SystemDescription.Arch.X86_64, + paddr_top=0x70000000, + serial=0x3F8, + timer=0xFED00000, + ethernet=0x6000C00000, + ), + Board( + name="viscous", + arch=SystemDescription.Arch.X86_64, + paddr_top=0x70000000, + serial=0x3F8, + timer=0xFED00000, + ethernet=0x90200000, + ), ]