From ad5f5297895e0b1ada8478098373ba1699ffadb9 Mon Sep 17 00:00:00 2001 From: Travis Geiselbrecht Date: Sat, 23 Mar 2024 00:45:43 -0700 Subject: [PATCH] [dev][virtio][pci] PCI based virtio First pass at PCI based virtio. Added a PCI based virtio-bus layer that abstracts the details from the device layer. Only wired up for virtio-blk at the moment. IRQs are wired up in legacy mode (no MSI-X support in PCI yet). --- arch/x86/include/arch/arch_ops.h | 1 - dev/bus/pci/bus_mgr/bus_mgr.cpp | 12 + dev/bus/pci/bus_mgr/device.cpp | 42 +- dev/bus/pci/bus_mgr/device.h | 1 + dev/bus/pci/debug.cpp | 5 +- dev/bus/pci/drivers/rules.mk | 4 +- dev/bus/pci/include/dev/bus/pci.h | 3 + dev/virtio/9p/virtio-9p.cpp | 1 + dev/virtio/block/virtio-block.cpp | 1 + dev/virtio/gpu/virtio-gpu.cpp | 1 + dev/virtio/include/dev/virtio/virtio-bus.h | 20 + dev/virtio/include/dev/virtio/virtio-device.h | 21 +- .../include/dev/virtio/virtio-pci-bus.h | 82 ++++ dev/virtio/net/virtio-net.cpp | 3 +- dev/virtio/rules.mk | 3 +- dev/virtio/virtio-device.cpp | 1 + dev/virtio/virtio-mmio-bus.cpp | 72 +-- dev/virtio/virtio-pci-bus.cpp | 423 ++++++++++++++++++ dev/virtio/virtio.cpp | 21 + dev/virtio/virtio_priv.h | 27 +- scripts/do-qemuarm | 36 +- scripts/do-qemuriscv | 33 +- 22 files changed, 726 insertions(+), 87 deletions(-) create mode 100644 dev/virtio/include/dev/virtio/virtio-pci-bus.h create mode 100644 dev/virtio/virtio-pci-bus.cpp diff --git a/arch/x86/include/arch/arch_ops.h b/arch/x86/include/arch/arch_ops.h index b3092d602..0f10feb35 100644 --- a/arch/x86/include/arch/arch_ops.h +++ b/arch/x86/include/arch/arch_ops.h @@ -91,5 +91,4 @@ static inline uint arch_curr_cpu_num(void) { #define smp_rmb() CF #endif - #endif // !ASSEMBLY diff --git a/dev/bus/pci/bus_mgr/bus_mgr.cpp b/dev/bus/pci/bus_mgr/bus_mgr.cpp index 9c9756afe..75e46d823 100644 --- a/dev/bus/pci/bus_mgr/bus_mgr.cpp +++ b/dev/bus/pci/bus_mgr/bus_mgr.cpp @@ -323,6 +323,18 @@ status_t pci_bus_mgr_allocate_irq(const pci_location_t loc, uint *irqbase) { return d->allocate_irq(irqbase); } +ssize_t pci_read_vendor_capability(const pci_location_t loc, size_t index, void *buf, size_t buflen) { + char str[14]; + LTRACEF("%s\n", pci_loc_string(loc, str)); + + device *d = lookup_device_by_loc(loc); + if (!d) { + return ERR_NOT_FOUND; + } + + return d->read_vendor_capability(index, buf, buflen); +} + void pci_dump_bar(const pci_bar_t *bar, int index) { if (bar->addr >= UINT32_MAX || bar->size >= UINT32_MAX) { printf("BAR %d: addr %-#16llx size %-#16zx io %d 64b %d pref %d\n", diff --git a/dev/bus/pci/bus_mgr/device.cpp b/dev/bus/pci/bus_mgr/device.cpp index ac071d634..ec5242b9c 100644 --- a/dev/bus/pci/bus_mgr/device.cpp +++ b/dev/bus/pci/bus_mgr/device.cpp @@ -133,6 +133,14 @@ void device::dump(size_t indent) { pci_dump_bar(bars_ + b, b); } } + + capability *cap; + list_for_every_entry(&capability_list_, cap, capability, node) { + for (size_t i = 0; i < indent + 2; i++) { + printf(" "); + } + printf("capability: offset %#x id %#x\n", cap->config_offset, cap->id); + } } status_t device::enable() { @@ -220,6 +228,27 @@ status_t device::probe_capabilities() { return NO_ERROR; } +ssize_t device::read_vendor_capability(size_t index, void *buf, size_t buflen) { + const capability *cap; + list_for_every_entry(&capability_list_, cap, capability, node) { + if (cap->id == 0x9) { // vendor specific + if (index == 0) { + uint8_t len; + pci_read_config_byte(loc(), cap->config_offset + 2, &len); + + const size_t readlen = MIN(len, buflen); + for (size_t i = 0; i < readlen; i++) { + pci_read_config_byte(loc(), cap->config_offset + i, static_cast(buf) + i); + } + return len; + } + index--; + } + } + + return ERR_NOT_FOUND; +} + status_t device::init_msi_capability(capability *cap) { LTRACE_ENTRY; @@ -256,16 +285,21 @@ status_t device::init_msix_capability(capability *cap) { status_t device::allocate_irq(uint *irq) { LTRACE_ENTRY; - uint8_t interrupt_line; - status_t err = pci_read_config_byte(loc(), PCI_CONFIG_INTERRUPT_LINE, &interrupt_line); + uint8_t interrupt_pin; + status_t err = pci_read_config_byte(loc(), PCI_CONFIG_INTERRUPT_PIN, &interrupt_pin); if (err != NO_ERROR) return err; - if (interrupt_line == 0) { + if (interrupt_pin == 0) { return ERR_NO_RESOURCES; } // map the irq number in config space to platform vector space - err = platform_pci_int_to_vector(interrupt_line, irq); + err = platform_pci_int_to_vector(interrupt_pin, irq); + if (err != NO_ERROR) return err; + + // write it back to the pci config in the interrupt line offset + pci_write_config_byte(loc(), PCI_CONFIG_INTERRUPT_LINE, *irq); + return err; } diff --git a/dev/bus/pci/bus_mgr/device.h b/dev/bus/pci/bus_mgr/device.h index ae2b9f28c..df2a6d576 100644 --- a/dev/bus/pci/bus_mgr/device.h +++ b/dev/bus/pci/bus_mgr/device.h @@ -90,6 +90,7 @@ class device { uint8_t header_type() const { return config_.header_type & PCI_HEADER_TYPE_MASK; } status_t read_bars(pci_bar_t bar[6]); + ssize_t read_vendor_capability(size_t index, void *buf, size_t buflen); bool has_msi() const { return msi_cap_; } bool has_msix() const { return msix_cap_; } diff --git a/dev/bus/pci/debug.cpp b/dev/bus/pci/debug.cpp index 066128933..ad227ae6a 100644 --- a/dev/bus/pci/debug.cpp +++ b/dev/bus/pci/debug.cpp @@ -54,10 +54,11 @@ static void pci_list(void) { if (config.vendor_id != 0xffff) { printf("%04x:%02x:%02x.%0x vendor_id=%04x device_id=%04x, header_type=%02x " - "base_class=%02x, sub_class=%02x, interface=%02x, irq=%u\n", + "base_class=%02x, sub_class=%02x, interface=%02x, irq_line=%u, irq_pin=%u\n", state.segment, state.bus, state.dev, state.fn, config.vendor_id, config.device_id, config.header_type, config.base_class, - config.sub_class, config.program_interface, config.type0.interrupt_line); + config.sub_class, config.program_interface, config.type0.interrupt_line, + config.type0.interrupt_pin); devices++; lines++; } diff --git a/dev/bus/pci/drivers/rules.mk b/dev/bus/pci/drivers/rules.mk index 6a3ac16c5..ea86441d3 100644 --- a/dev/bus/pci/drivers/rules.mk +++ b/dev/bus/pci/drivers/rules.mk @@ -1,5 +1,7 @@ # Fake module that just declares deps on all the PCI drivers in the system. # MODULES += dev/bus/pci - MODULES += dev/net/e1000 +MODULES += dev/virtio/block +MODULES += dev/virtio/net +MODULES += dev/virtio/gpu diff --git a/dev/bus/pci/include/dev/bus/pci.h b/dev/bus/pci/include/dev/bus/pci.h index 0368205e3..b99a05cea 100644 --- a/dev/bus/pci/include/dev/bus/pci.h +++ b/dev/bus/pci/include/dev/bus/pci.h @@ -98,6 +98,9 @@ status_t pci_bus_mgr_allocate_msi(const pci_location_t loc, size_t num_requested // allocate a regular irq for this device and return it in irqbase status_t pci_bus_mgr_allocate_irq(const pci_location_t loc, uint *irqbase); +// XXX sort this nicely +ssize_t pci_read_vendor_capability(const pci_location_t loc, size_t index, void *buf, size_t buflen); + // return a pointer to a formatted string const char *pci_loc_string(pci_location_t loc, char out_str[14]); diff --git a/dev/virtio/9p/virtio-9p.cpp b/dev/virtio/9p/virtio-9p.cpp index 31eb2e7e1..bcdba85b8 100644 --- a/dev/virtio/9p/virtio-9p.cpp +++ b/dev/virtio/9p/virtio-9p.cpp @@ -95,6 +95,7 @@ status_t virtio_9p_init(virtio_device *dev, uint32_t host_features) /* set our irq handler */ dev->set_irq_callbacks(&virtio_9p_irq_driver_callback, nullptr); + dev->bus()->unmask_interrupt(); /* set DRIVER_OK */ dev->bus()->virtio_status_driver_ok(); diff --git a/dev/virtio/block/virtio-block.cpp b/dev/virtio/block/virtio-block.cpp index 3411bbdaa..2be8b8cc8 100644 --- a/dev/virtio/block/virtio-block.cpp +++ b/dev/virtio/block/virtio-block.cpp @@ -218,6 +218,7 @@ status_t virtio_block_init(virtio_device *dev, uint32_t host_features) { /* set our irq handler */ dev->set_irq_callbacks(&virtio_block_irq_driver_callback, nullptr); + dev->bus()->unmask_interrupt(); /* set DRIVER_OK */ dev->bus()->virtio_status_driver_ok(); diff --git a/dev/virtio/gpu/virtio-gpu.cpp b/dev/virtio/gpu/virtio-gpu.cpp index b5c4a282a..bf7838837 100644 --- a/dev/virtio/gpu/virtio-gpu.cpp +++ b/dev/virtio/gpu/virtio-gpu.cpp @@ -454,6 +454,7 @@ status_t virtio_gpu_init(virtio_device *dev, uint32_t host_features) { /* set our irq handler */ dev->set_irq_callbacks(&virtio_gpu_irq_driver_callback, &virtio_gpu_config_change_callback); + dev->bus()->unmask_interrupt(); /* set DRIVER_OK */ dev->bus()->virtio_status_driver_ok(); diff --git a/dev/virtio/include/dev/virtio/virtio-bus.h b/dev/virtio/include/dev/virtio/virtio-bus.h index 96c364fbb..b9fba5374 100644 --- a/dev/virtio/include/dev/virtio/virtio-bus.h +++ b/dev/virtio/include/dev/virtio/virtio-bus.h @@ -8,6 +8,7 @@ #pragma once #include +#include class virtio_bus { public: @@ -21,4 +22,23 @@ class virtio_bus { virtual void virtio_status_driver_ok() = 0; virtual void virtio_kick(uint16_t ring_index) = 0; virtual void register_ring(uint32_t page_size, uint32_t queue_sel, uint32_t queue_num, uint32_t queue_align, uint32_t queue_pfn) = 0; + + uint64_t virtio_read_host_feature_word_64(uint32_t word) { + return virtio_read_host_feature_word(word) | static_cast(virtio_read_host_feature_word(word + 1)) << 32; + } + + // A simple set of routines to handle a single IRQ. + // TODO: rethink where this goes in a more complicated MSI based solution. + void set_irq(uint32_t irq) { irq_ = irq; } + + void mask_interrupt() { + ::mask_interrupt(irq_); + } + + void unmask_interrupt() { + ::unmask_interrupt(irq_); + } + +private: + uint32_t irq_ {}; }; \ No newline at end of file diff --git a/dev/virtio/include/dev/virtio/virtio-device.h b/dev/virtio/include/dev/virtio/virtio-device.h index c7baff33f..e8f2793cc 100644 --- a/dev/virtio/include/dev/virtio/virtio-device.h +++ b/dev/virtio/include/dev/virtio/virtio-device.h @@ -13,6 +13,7 @@ #include #include #include +#include class virtio_device { public: @@ -52,6 +53,7 @@ class virtio_device { void *get_config_ptr() { return config_ptr_; } const void *get_config_ptr() const { return config_ptr_; } + void set_config_ptr(void *ptr) { config_ptr_ = ptr; } using irq_driver_callback = enum handler_return (*)(virtio_device *dev, uint ring, const vring_used_elem *e); using config_change_callback = enum handler_return (*)(virtio_device *dev); @@ -61,7 +63,8 @@ class virtio_device { config_change_callback_ = config; } - // From low level bus layer + // Interrupt handler callbacks from the bus layer, which is responsible + // for the first layer of IRQ handling handler_return handle_queue_interrupt(); handler_return handle_config_interrupt(); @@ -69,25 +72,17 @@ class virtio_device { static const size_t MAX_VIRTIO_RINGS = 4; private: - friend class virtio_bus; - - // XXX move this into constructor - friend int virtio_mmio_detect(void *ptr, uint count, const uint irqs[], size_t stride); - // mmio or pci virtio_bus *bus_ = {}; // points into bus's configuration spot - // TODO: is this feasible for both PCI and mmio? void *config_ptr_ = {}; - void *priv_ = {}; /* a place for the driver to put private data */ - - bool valid_ = {}; - - uint index_ = {}; - uint irq_ = {}; + // a place for the driver to put private data, usually a pointer to device + // specific details. + void *priv_ = {}; + // interrupt handlers that the device-specific layer registers with our layer irq_driver_callback irq_driver_callback_ = {}; config_change_callback config_change_callback_ = {}; diff --git a/dev/virtio/include/dev/virtio/virtio-pci-bus.h b/dev/virtio/include/dev/virtio/virtio-pci-bus.h new file mode 100644 index 000000000..aa7ccc9ed --- /dev/null +++ b/dev/virtio/include/dev/virtio/virtio-pci-bus.h @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2024 Travis Geiselbrecht + * + * Use of this source code is governed by a MIT-style + * license that can be found in the LICENSE file or at + * https://opensource.org/licenses/MIT + */ +#pragma once + +#include +#include + +#include + +#include + +struct virtio_pci_common_cfg; +class virtio_device; + +class virtio_pci_bus final : public virtio_bus { +public: + virtio_pci_bus() = default; + ~virtio_pci_bus() override = default; + + status_t init(virtio_device *dev, pci_location_t loc, size_t index); + + void virtio_reset_device() override; + void virtio_status_acknowledge_driver() override; + uint32_t virtio_read_host_feature_word(uint32_t word) override; + void virtio_set_guest_features(uint32_t word, uint32_t features) override; + void virtio_status_driver_ok() override; + void virtio_kick(uint16_t ring_index) override; + void register_ring(uint32_t page_size, uint32_t queue_sel, uint32_t queue_num, uint32_t queue_align, uint32_t queue_pfn) override; + + volatile virtio_pci_common_cfg *common_config() { + return reinterpret_cast(config_ptr(common_cfg_)); + } + + void *device_config() { + return reinterpret_cast(config_ptr(device_cfg_)); + } + +private: + static handler_return virtio_pci_irq(void *arg); + + struct config_pointer { + bool valid; + int bar; + size_t offset; + size_t length; + }; + + struct mapped_bars { + bool mapped; + uint8_t *vaddr; + }; + + virtio_device *dev_ = {}; + + pci_location_t loc_ = {}; + + mapped_bars bar_map_[6] = {}; + + config_pointer common_cfg_ = {}; + config_pointer notify_cfg_ = {}; + config_pointer isr_cfg_ = {}; + config_pointer device_cfg_ = {}; + config_pointer pci_cfg_ = {}; + + uint32_t notify_offset_multiplier_ = {}; + + // Given one of the config_pointer structs, return a uint8_t * pointer + // to its mapping. + uint8_t *config_ptr(const config_pointer &cfg) { + if (!cfg.valid) { + return nullptr; + } + + auto &bar = bar_map_[cfg.bar]; + return bar.vaddr + cfg.offset; + } +}; \ No newline at end of file diff --git a/dev/virtio/net/virtio-net.cpp b/dev/virtio/net/virtio-net.cpp index 40b2400a9..04dca5985 100644 --- a/dev/virtio/net/virtio-net.cpp +++ b/dev/virtio/net/virtio-net.cpp @@ -195,11 +195,12 @@ status_t virtio_net_init(virtio_device *dev) { dev->bus()->virtio_status_acknowledge_driver(); // XXX check features bits and ack/nak them - uint64_t host_features = dev->bus()->virtio_read_host_feature_word(0) | (uint64_t)dev->bus()->virtio_read_host_feature_word(1) << 32; + uint64_t host_features = dev->bus()->virtio_read_host_feature_word_64(0); dump_feature_bits(host_features); /* set our irq handler */ dev->set_irq_callbacks(&virtio_net_irq_driver_callback, nullptr); + dev->bus()->unmask_interrupt(); /* set DRIVER_OK */ dev->bus()->virtio_status_driver_ok(); diff --git a/dev/virtio/rules.mk b/dev/virtio/rules.mk index 5c192788a..4df8f2d35 100644 --- a/dev/virtio/rules.mk +++ b/dev/virtio/rules.mk @@ -2,9 +2,10 @@ LOCAL_DIR := $(GET_LOCAL_DIR) MODULE := $(LOCAL_DIR) -MODULE_SRCS += $(LOCAL_DIR)/virtio.cpp MODULE_SRCS += $(LOCAL_DIR)/virtio-bus.cpp MODULE_SRCS += $(LOCAL_DIR)/virtio-device.cpp MODULE_SRCS += $(LOCAL_DIR)/virtio-mmio-bus.cpp +MODULE_SRCS += $(LOCAL_DIR)/virtio-pci-bus.cpp +MODULE_SRCS += $(LOCAL_DIR)/virtio.cpp include make/module.mk diff --git a/dev/virtio/virtio-device.cpp b/dev/virtio/virtio-device.cpp index 7ea0f10d1..62c814b1e 100644 --- a/dev/virtio/virtio-device.cpp +++ b/dev/virtio/virtio-device.cpp @@ -192,6 +192,7 @@ handler_return virtio_device::handle_queue_interrupt() { vring &ring = ring_[r]; + LTRACEF("desc %p, avail %p, used %p\n", ring.desc, ring.avail, ring.used); LTRACEF("ring %u: used flags 0x%hx idx 0x%hx last_used %u\n", r, ring.used->flags, ring.used->idx, ring.last_used); uint cur_idx = ring.used->idx; diff --git a/dev/virtio/virtio-mmio-bus.cpp b/dev/virtio/virtio-mmio-bus.cpp index 221d56064..5d42b6e8b 100644 --- a/dev/virtio/virtio-mmio-bus.cpp +++ b/dev/virtio/virtio-mmio-bus.cpp @@ -79,13 +79,6 @@ STATIC_ASSERT(sizeof(struct virtio_mmio_config) == 0x100); #define VIRTIO_MMIO_MAGIC 0x74726976 // 'virt' -#define VIRTIO_STATUS_ACKNOWLEDGE (1<<0) -#define VIRTIO_STATUS_DRIVER (1<<1) -#define VIRTIO_STATUS_DRIVER_OK (1<<2) -#define VIRTIO_STATUS_FEATURES_OK (1<<3) -#define VIRTIO_STATUS_DEVICE_NEEDS_RESET (1<<6) -#define VIRTIO_STATUS_FAILED (1<<7) - // TODO: switch to using reg.h mmio_ accessors void virtio_mmio_bus::virtio_reset_device() { mmio_config_->status = 0; @@ -193,43 +186,43 @@ int virtio_mmio_detect(void *ptr, uint count, const uint irqs[], size_t stride) for (uint i = 0; i < count; i++) { volatile auto *mmio = reinterpret_cast(static_cast(ptr) + i * stride); - auto *bus = new virtio_mmio_bus(mmio); - auto *dev = new virtio_device(bus); - devices[i] = dev; - - dev->index_ = i; - dev->irq_ = irqs[i]; - dev->config_ptr_ = (void *)mmio->config; - - mask_interrupt(irqs[i]); - register_int_handler(irqs[i], &virtio_mmio_bus::virtio_mmio_irq, static_cast(dev)); - - LTRACEF("looking at %p: magic 0x%x version 0x%x did 0x%x vid 0x%x\n", - mmio, mmio->magic, mmio->version, mmio->device_id, mmio->vendor_id); - if (mmio->magic != VIRTIO_MMIO_MAGIC) { continue; } - // TODO: handle version 2 - if (LOCAL_TRACE) { if (mmio->device_id != 0) { dump_mmio_config(mmio); } } + // TODO: handle version 2 + // Unclear how to get QEMU to handle version 2 mmio interfaces + if (mmio->version != 1) { + printf("skipping virtio mmio version 2 device\n"); + continue; + } + + auto *bus = new virtio_mmio_bus(mmio); + auto *dev = new virtio_device(bus); + devices[i] = dev; + + dev->set_config_ptr((void *)mmio->config); + + bus->set_irq(irqs[i]); + bus->mask_interrupt(); + register_int_handler(irqs[i], &virtio_mmio_bus::virtio_mmio_irq, static_cast(dev)); + + LTRACEF("looking at %p: magic 0x%x version 0x%x did 0x%x vid 0x%x\n", + mmio, mmio->magic, mmio->version, mmio->device_id, mmio->vendor_id); + #if WITH_DEV_VIRTIO_BLOCK if (mmio->device_id == 2) { // block device LTRACEF("found block device\n"); status_t err = virtio_block_init(dev, bus->virtio_read_host_feature_word(0)); if (err >= 0) { - // good device - dev->valid_ = true; - - if (dev->irq_driver_callback_) - unmask_interrupt(dev->irq_); + found++; } } #endif // WITH_DEV_VIRTIO_BLOCK @@ -239,11 +232,7 @@ int virtio_mmio_detect(void *ptr, uint count, const uint irqs[], size_t stride) status_t err = virtio_net_init(dev); if (err >= 0) { - // good device - dev->valid_ = true; - - if (dev->irq_driver_callback_) - unmask_interrupt(dev->irq_); + found++; } } #endif // WITH_DEV_VIRTIO_NET @@ -253,12 +242,7 @@ int virtio_mmio_detect(void *ptr, uint count, const uint irqs[], size_t stride) status_t err = virtio_9p_init(dev, bus->virtio_read_host_feature_word((0))); if (err >= 0) { - // good device - dev->valid_ = true; - - if (dev->irq_driver_callback_) - unmask_interrupt(dev->irq_); - + found++; virtio_9p_start(dev); } } @@ -269,19 +253,11 @@ int virtio_mmio_detect(void *ptr, uint count, const uint irqs[], size_t stride) status_t err = virtio_gpu_init(dev, bus->virtio_read_host_feature_word( 0)); if (err >= 0) { - // good device - dev->valid_ = true; - - if (dev->irq_driver_callback_) - unmask_interrupt(dev->irq_); - + found++; virtio_gpu_start(dev); } } #endif // WITH_DEV_VIRTIO_GPU - - if (dev->valid_) - found++; } return found; diff --git a/dev/virtio/virtio-pci-bus.cpp b/dev/virtio/virtio-pci-bus.cpp new file mode 100644 index 000000000..e1946d652 --- /dev/null +++ b/dev/virtio/virtio-pci-bus.cpp @@ -0,0 +1,423 @@ +/* + * Copyright (c) 2024 Travis Geiselbrecht + * + * Use of this source code is governed by a MIT-style + * license that can be found in the LICENSE file or at + * https://opensource.org/licenses/MIT + */ +#include "lk/debug.h" +#if WITH_DEV_BUS_PCI + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#if WITH_KERNEL_VM +#include +#endif +#if WITH_DEV_VIRTIO_BLOCK +#include +#endif + +#define LOCAL_TRACE 0 + +#include + +#include "virtio_priv.h" + +struct virtio_pci_devices { + uint16_t device_id; + bool legacy; + status_t (*init)(pci_location_t loc, const virtio_pci_devices &dev_table_entry, size_t index); +}; + +static status_t init_block(pci_location_t loc, const virtio_pci_devices &dev_table_entry, size_t index); + +const virtio_pci_devices devices[] = { + { 0x1000, true, nullptr }, // transitional network + { 0x1001, true, &init_block }, // transitional block + { 0x1009, true, nullptr }, // legacy virtio 9p + { 0x1041, false, nullptr }, // non-transitional network + { 0x1042, false, &init_block }, // non-transitional block + { 0x1043, false, nullptr }, // non-transitional console + { 0x1050, false, nullptr }, // non-transitional gpu + { 0x1052, false, nullptr }, // non-transitional input +}; + +struct virtio_pci_cap { + uint8_t cap_vndr; + uint8_t cap_next; + uint8_t cap_len; + /* Common configuration */ +#define VIRTIO_PCI_CAP_COMMON_CFG 1 + /* Notifications */ +#define VIRTIO_PCI_CAP_NOTIFY_CFG 2 + /* ISR Status */ +#define VIRTIO_PCI_CAP_ISR_CFG 3 + /* Device specific configuration */ +#define VIRTIO_PCI_CAP_DEVICE_CFG 4 + /* PCI configuration access */ +#define VIRTIO_PCI_CAP_PCI_CFG 5 + /* Shared memory region */ +#define VIRTIO_PCI_CAP_SHARED_MEMORY_CFG 8 + /* Vendor-specific data */ +#define VIRTIO_PCI_CAP_VENDOR_CFG 9 + uint8_t cfg_type; + uint8_t bar; + uint8_t id; + uint8_t padding[2]; + uint32_t offset; + uint32_t length; +}; + +STATIC_ASSERT(sizeof(virtio_pci_cap) == 16); + +static void dump_pci_cap(const virtio_pci_cap *cap) { + const char *type; + + switch (cap->cfg_type) { + case VIRTIO_PCI_CAP_COMMON_CFG: type = "common"; break; + case VIRTIO_PCI_CAP_NOTIFY_CFG: type = "notify"; break; + case VIRTIO_PCI_CAP_ISR_CFG: type = "isr"; break; + case VIRTIO_PCI_CAP_DEVICE_CFG: type = "device"; break; + case VIRTIO_PCI_CAP_PCI_CFG: type = "pci"; break; + case VIRTIO_PCI_CAP_SHARED_MEMORY_CFG: type = "shared mem"; break; + case VIRTIO_PCI_CAP_VENDOR_CFG: type = "vendor"; break; + default: type = "unknown"; break; + } + + printf("PCI capability: vendor %#hhx next %#hhx len %#hhx type %#hhx (%s) bar %#hhx id %#hhx offset %#x length %#x\n", + cap->cap_vndr, cap->cap_next, cap->cap_len, cap->cfg_type, type, cap->bar, cap->id, cap->offset, cap->length); +} + +struct virtio_pci_notify_cap { + virtio_pci_cap cap; + uint32_t notify_off_multiplier; +}; + +STATIC_ASSERT(sizeof(virtio_pci_notify_cap) == 20); + +struct virtio_pci_common_cfg { + /* About the whole device. */ + uint32_t device_feature_select; /* read-write */ + uint32_t device_feature; /* read-only for driver */ + uint32_t driver_feature_select; /* read-write */ + uint32_t driver_feature; /* read-write */ + uint16_t config_msix_vector; /* read-write */ + uint16_t num_queues; /* read-only for driver */ + uint8_t device_status; /* read-write */ + uint8_t config_generation; /* read-only for driver */ + + /* About a specific virtqueue. */ + uint16_t queue_select; /* read-write */ + uint16_t queue_size; /* read-write */ + uint16_t queue_msix_vector; /* read-write */ + uint16_t queue_enable; /* read-write */ + uint16_t queue_notify_off; /* read-only for driver */ + uint64_t queue_desc; /* read-write */ + uint64_t queue_driver; /* read-write */ + uint64_t queue_device; /* read-write */ + uint16_t queue_notif_config_data; /* read-only for driver */ + uint16_t queue_reset; /* read-write */ + + /* About the administration virtqueue. */ + uint16_t admin_queue_index; /* read-only for driver */ + uint16_t admin_queue_num; /* read-only for driver */ + + void dump() volatile const { + printf("PCI common config @%p:\n", this); + printf("\tdevice feature select %#x features %#x\n", device_feature_select, device_feature); + printf("\tdriver feature select %#x features %#x\n", driver_feature_select, driver_feature); + printf("\tmsix vector %#x num queues %#x status %#x config gen %#x\n", config_msix_vector, num_queues, + device_status, config_generation); + } +}; + +STATIC_ASSERT(sizeof(virtio_pci_common_cfg) == 64); + +void virtio_pci_bus::virtio_reset_device() { + common_config()->device_status = 0; + while (common_config()->device_status != 0) + ; +} + +void virtio_pci_bus::virtio_status_acknowledge_driver() { + common_config()->device_status |= VIRTIO_STATUS_ACKNOWLEDGE | VIRTIO_STATUS_DRIVER; +} + +void virtio_pci_bus::virtio_status_driver_ok() { + common_config()->device_status |= VIRTIO_STATUS_DRIVER_OK; +} + +uint32_t virtio_pci_bus::virtio_read_host_feature_word(uint32_t word) { + common_config()->device_feature_select = word; + return common_config()->device_feature; +} + +void virtio_pci_bus::virtio_set_guest_features(uint32_t word, uint32_t features) { + common_config()->driver_feature_select = word; + common_config()->driver_feature = features; +} + +void virtio_pci_bus::virtio_kick(uint16_t ring_index) { + auto *notify = reinterpret_cast(config_ptr(notify_cfg_) + static_cast(ring_index * notify_offset_multiplier_)); + + LTRACEF("notify ring %u ptr %p\n", ring_index, notify); + + *notify = ring_index; + mb(); +} + +void virtio_pci_bus::register_ring(uint32_t page_size, uint32_t queue_sel, uint32_t queue_num, uint32_t queue_align, uint32_t queue_pfn) { + auto *ccfg = common_config(); + + // Using legacy split virtqueues packing strategy + uint64_t ring_descriptor_paddr = static_cast(queue_pfn) * page_size; + uint64_t ring_available_paddr = ALIGN(ring_descriptor_paddr + static_cast(16 * queue_num), 2); + uint64_t ring_used_paddr = ALIGN(ring_available_paddr + 6 + static_cast(2 * queue_num), queue_align); + + LTRACEF("queue %u size %u pfn %#x paddr (%#" PRIx64 ", %#" PRIx64 ", %#" PRIx64 ")\n", + queue_sel, queue_num, queue_pfn, ring_descriptor_paddr, ring_available_paddr, ring_used_paddr); + + ccfg->queue_select = queue_sel; + + LTRACEF("existing queue_size %u\n", ccfg->queue_size); + LTRACEF("existin notify off %u\n", ccfg->queue_notify_off); + + ccfg->queue_size = queue_num; + ccfg->queue_desc = ring_descriptor_paddr; + ccfg->queue_driver = ring_available_paddr; + ccfg->queue_device = ring_used_paddr; + ccfg->queue_enable = 1; +} + +handler_return virtio_pci_bus::virtio_pci_irq(void *arg) { + auto *bus = reinterpret_cast(arg); + + LTRACEF("dev %p, bus %p\n", bus->dev_, bus); + + volatile uint8_t *isr_status = bus->config_ptr(bus->isr_cfg_); + LTRACEF("isr status register %p\n", isr_status); + + // reading status implicitly acks it and resets to 0 + uint32_t irq_status = *isr_status; + LTRACEF("status %#x\n", irq_status); + + enum handler_return ret = INT_NO_RESCHEDULE; + if (irq_status & 0x1) { /* used ring update */ + auto _ret = bus->dev_->handle_queue_interrupt(); + if (_ret == INT_RESCHEDULE) { + ret = _ret; + } + + } + if (irq_status & 0x2) { /* config change */ + auto _ret = bus->dev_->handle_config_interrupt(); + if (_ret == INT_RESCHEDULE) { + ret = _ret; + } + } + + LTRACEF("exiting irq\n"); + + return ret;; +} + +status_t virtio_pci_bus::init(virtio_device *dev, pci_location_t loc, size_t index) { + LTRACE_ENTRY; + + DEBUG_ASSERT(!dev_ && dev); + + dev_ = dev; + loc_ = loc; + + // read all of the capabilities for this virtio device + bool map_bars[6] = {}; + for (size_t i = 0;; i++) { + virtio_pci_cap cap; + ssize_t err = pci_read_vendor_capability(loc, i, &cap, sizeof(cap)); + if (err < NO_ERROR || static_cast(err) < sizeof(cap)) { + break; + } + if (LOCAL_TRACE) dump_pci_cap(&cap); + + // save off the bar + range of all of the capabilities we care about + virtio_pci_bus::config_pointer *cfg; + switch (cap.cfg_type) { + case VIRTIO_PCI_CAP_COMMON_CFG: + cfg = &common_cfg_; + goto common; + case VIRTIO_PCI_CAP_NOTIFY_CFG: { + // read in the extra 32bit offset multiplier + virtio_pci_notify_cap cap2; + err = pci_read_vendor_capability(loc, i, &cap2, sizeof(cap2)); + if (err < NO_ERROR || static_cast(err) < sizeof(cap2)) { + break; + } + LTRACEF("notify offset multiplier %u\n", cap2.notify_off_multiplier); + notify_offset_multiplier_ = cap2.notify_off_multiplier; + + cfg = ¬ify_cfg_; + } + goto common; + case VIRTIO_PCI_CAP_ISR_CFG: + cfg = &isr_cfg_; + goto common; + case VIRTIO_PCI_CAP_DEVICE_CFG: + cfg = &device_cfg_; + goto common; + case VIRTIO_PCI_CAP_PCI_CFG: + cfg = &pci_cfg_; + // fallthrough +common: + DEBUG_ASSERT(cfg); + cfg->valid = true; + cfg->bar = cap.bar; + cfg->offset = cap.offset; + cfg->length = cap.length; + if (cap.bar < 6) { + map_bars[cap.bar] = true; + } + } + } + + // check that at least the mandatory capabilities are present + if (!(common_cfg_.valid && notify_cfg_.valid && isr_cfg_.valid && pci_cfg_.valid)) { + return ERR_NOT_FOUND; + } + + // map in the bars we care about + pci_bar_t bars[6]; + status_t err = pci_bus_mgr_read_bars(loc, bars); + if (err != NO_ERROR) { + return err; + } + + LTRACEF("virtio-pci BARS:\n"); + if (LOCAL_TRACE) pci_dump_bars(bars, 6); + + for (int i = 0; i < 6; i++) { + if (map_bars[i] && !bars[i].io) { + auto &bar_map = bar_map_[i]; +#if WITH_KERNEL_VM + char str[32]; + snprintf(str, sizeof(str), "virtio%zu bar%d", index, i); + err = vmm_alloc_physical(vmm_get_kernel_aspace(), str, bars[i].size, reinterpret_cast(&bar_map.vaddr), 0, + bars[i].addr, /* vmm_flags */ 0, ARCH_MMU_FLAG_UNCACHED_DEVICE); + if (err != NO_ERROR) { + printf("error mapping bar %d\n", i); + continue; + } + bar_map.mapped = true; + LTRACEF("bar %d mapped at %p\n", i, bar_map.vaddr); +#else + // no need to map, it's already available at the physical address + if (sizeof(void *) < 8 && (bars[i].addr + bars[i].size) > UINT32_MAX) { + TRACEF("aborting due to 64bit BAR on 32bit arch\n"); + return ERR_NO_MEMORY; + } + bar_map.vaddr = (uint8_t *)(uintptr_t)bars[i].addr; +#endif + } + } + + // enable the device + pci_bus_mgr_enable_device(loc); + + // look at the common configuration + if (LOCAL_TRACE) common_config()->dump(); + + // read the device-independent feature bits + uint64_t features = virtio_read_host_feature_word_64(0); + virtio_dump_device_independent_features_bits(features); + + // accept mandatory features + if (features & VIRTIO_F_VERSION_1) { + virtio_set_guest_features(1, VIRTIO_F_VERSION_1 >> 32); + } + + uint irq_base; + err = pci_bus_mgr_allocate_msi(loc_, 1, &irq_base); + if (err != NO_ERROR) { + // fall back to regular IRQs + err = pci_bus_mgr_allocate_irq(loc_, &irq_base); + if (err != NO_ERROR) { + printf("block: unable to allocate IRQ\n"); + return err; + } + ::mask_interrupt(irq_base); + register_int_handler(irq_base, virtio_pci_irq, this); + } else { + ::mask_interrupt(irq_base); + register_int_handler_msi(irq_base, virtio_pci_irq, this, true); + } + set_irq(irq_base); + LTRACEF("IRQ number %#x\n", irq_base); + + return NO_ERROR; +} + +static status_t init_block(pci_location_t loc, const virtio_pci_devices &dev_table_entry, size_t index) { + LTRACE_ENTRY; + +#if WITH_DEV_VIRTIO_BLOCK + // create a virtio_pci_bus object and initialize it based on the location + auto *bus = new virtio_pci_bus(); + auto *dev = new virtio_device(bus); + + auto err = bus->init(dev, loc, index); + if (err != NO_ERROR) { + delete bus; + return err; + } + + // TODO: move the config pointer getter that devices use into the bus + dev->set_config_ptr(bus->device_config()); + + err = virtio_block_init(dev, bus->virtio_read_host_feature_word(0)); + if (err != NO_ERROR) { + PANIC_UNIMPLEMENTED; + } + + return err; +#else + return ERR_NOT_FOUND; +#endif +} + +static void virtio_pci_init(uint level) { + LTRACE_ENTRY; + + for (auto &dev: devices) { + for (size_t i = 0; ; i++) { + pci_location_t loc; + status_t err = pci_bus_mgr_find_device(&loc, dev.device_id, 0x1af4, i); + if (err != NO_ERROR) { + break; + } + + char str[14]; + printf("virtio-pci: looking at device at %s\n", pci_loc_string(loc, str)); + + // call the init routine + if (dev.init) { + dev.init(loc, dev, i); + } + } + } + + LTRACE_EXIT; +} + +LK_INIT_HOOK(virtio_pci, &virtio_pci_init, LK_INIT_LEVEL_PLATFORM + 1); + +#endif + diff --git a/dev/virtio/virtio.cpp b/dev/virtio/virtio.cpp index 843b7f7a4..bf7cb8e5f 100644 --- a/dev/virtio/virtio.cpp +++ b/dev/virtio/virtio.cpp @@ -10,6 +10,10 @@ #include #include +#include +#include + +#include "virtio_priv.h" void virtio_dump_desc(const vring_desc &desc) { printf("vring descriptor %p\n", &desc); @@ -19,6 +23,23 @@ void virtio_dump_desc(const vring_desc &desc) { printf("\tnext 0x%hx\n", desc.next); } +void virtio_dump_device_independent_features_bits(uint64_t feature) { + printf("virtio device independent features (%#" PRIx64 "):", feature); + if (feature & VIRTIO_F_INDIRECT_DESC) printf(" INDIRECT_DESC"); + if (feature & VIRTIO_F_EVENT_IDX) printf(" EVENT_IDX"); + if (feature & VIRTIO_F_VERSION_1) printf(" VERSION_1"); + if (feature & VIRTIO_F_ACCESS_PLATFORM) printf(" ACCESS_PLATFORM"); + if (feature & VIRTIO_F_RING_PACKED) printf(" RING_PACKED"); + if (feature & VIRTIO_F_IN_ORDER) printf(" IN_ORDER"); + if (feature & VIRTIO_F_ORDER_PLATFORM) printf(" ORDER_PLATFORM"); + if (feature & VIRTIO_F_SR_IOV) printf(" SR_IOV"); + if (feature & VIRTIO_F_NOTIFICATION_DATA) printf(" NOTIFICATION_DATA"); + if (feature & VIRTIO_F_NOTIF_CONFIG_DATA) printf(" NOTIF_CONFIG_DATA"); + if (feature & VIRTIO_F_RING_RESET) printf(" RING_RESET"); + if (feature & VIRTIO_F_ADMIN_VQ) printf(" ADMIN_VQ"); + printf("\n"); +} + static void virtio_init(uint level) { } diff --git a/dev/virtio/virtio_priv.h b/dev/virtio/virtio_priv.h index 7c238a215..d1231aeca 100644 --- a/dev/virtio/virtio_priv.h +++ b/dev/virtio/virtio_priv.h @@ -7,4 +7,29 @@ */ #pragma once -// TODO: remove if nothing needs to be here \ No newline at end of file +#include + +// status bits used by multiple transport busses +#define VIRTIO_STATUS_ACKNOWLEDGE (1<<0) +#define VIRTIO_STATUS_DRIVER (1<<1) +#define VIRTIO_STATUS_DRIVER_OK (1<<2) +#define VIRTIO_STATUS_FEATURES_OK (1<<3) +#define VIRTIO_STATUS_DEVICE_NEEDS_RESET (1<<6) +#define VIRTIO_STATUS_FAILED (1<<7) + +// device independent feature bits +#define VIRTIO_F_INDIRECT_DESC (1<<28) +#define VIRTIO_F_EVENT_IDX (1<<29) +#define VIRTIO_F_VERSION_1 (1ULL<<32) +#define VIRTIO_F_ACCESS_PLATFORM (1ULL<<33) +#define VIRTIO_F_RING_PACKED (1ULL<<34) +#define VIRTIO_F_IN_ORDER (1ULL<<35) +#define VIRTIO_F_ORDER_PLATFORM (1ULL<<36) +#define VIRTIO_F_SR_IOV (1ULL<<37) +#define VIRTIO_F_NOTIFICATION_DATA (1ULL<<38) +#define VIRTIO_F_NOTIF_CONFIG_DATA (1ULL<<39) +#define VIRTIO_F_RING_RESET (1ULL<<40) +#define VIRTIO_F_ADMIN_VQ (1ULL<<41) + +void virtio_dump_device_independent_features_bits(uint64_t feature); + diff --git a/scripts/do-qemuarm b/scripts/do-qemuarm index ede28d90e..537b048bf 100755 --- a/scripts/do-qemuarm +++ b/scripts/do-qemuarm @@ -4,6 +4,7 @@ DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" function HELP { echo "help:" + echo "-p : override LK project" echo "-6 : 64bit arm" echo "-3 : cortex-m3 based platform" echo "-v : boot kernel at EL2" @@ -19,6 +20,7 @@ function HELP { echo "-t : a virtio tap network device" echo "-g : a virtio display" echo "-f : a virtio 9p device with a host shared directory" + echo "-P : PCI based virtio devices" echo echo "-h for help" echo "all arguments after -- are passed to qemu directly" @@ -38,12 +40,13 @@ DO_CMPCTMALLOC=0 DO_MINIHEAP=0 DO_V9P=0 DO_V9P_DIR="" +DO_PCI_VIRTIO=0 SMP=1 MEMSIZE=512 SUDO="" PROJECT="" -while getopts cd:ghkm:Mnt36vp:s:f: FLAG; do +while getopts cd:ghkm:Mnt36vp:Ps:f: FLAG; do case $FLAG in c) DO_CMPCTMALLOC=1;; d) DO_DISK=1; DISK_IMAGE=$OPTARG;; @@ -59,6 +62,7 @@ while getopts cd:ghkm:Mnt36vp:s:f: FLAG; do m) MEMSIZE=$OPTARG;; s) SMP=$OPTARG;; p) PROJECT=$OPTARG;; + P) DO_PCI_VIRTIO=1;; h) HELP;; \?) echo unrecognized option @@ -100,14 +104,30 @@ fi ARGS=" -cpu $CPU -m $MEMSIZE -smp $SMP -machine $MACHINE -kernel build-${PROJECT}/lk.elf" +if (( $DO_PCI_VIRTIO )); then + VIRTIO_BLOCK_DEVICE="virtio-blk-pci" + VIRTIO_NET_DEVICE="virtio-net-pci" + VIRTIO_GPU_DEVICE="virtio-gpu-pci" + VIRTIO_KEYBOARD_DEVICE="virtio-keyboard-pci" + VIRTIO_MOUSE_DEVICE="virtio-mouse-pci" + VIRTIO_9P_DEVICE="virtio-9p-pci" +else + VIRTIO_BLOCK_DEVICE="virtio-blk-device" + VIRTIO_NET_DEVICE="virtio-net-device" + VIRTIO_GPU_DEVICE="virtio-gpu-device" + VIRTIO_KEYBOARD_DEVICE="virtio-keyboard-device" + VIRTIO_MOUSE_DEVICE="virtio-mouse-device" + VIRTIO_9P_DEVICE="virtio-9p-device" +fi + if (( $DO_DISK )); then ARGS+=" -drive if=none,file=${DISK_IMAGE},id=blk,format=raw" - ARGS+=" -device virtio-blk-device,drive=blk" + ARGS+=" -device ${VIRTIO_BLOCK_DEVICE},drive=blk" fi if (( $DO_NET )); then ARGS+=" -netdev user,id=vmnic,hostname=qemu " - ARGS+=" -device virtio-net-device,netdev=vmnic" + ARGS+=" -device ${VIRTIO_NET_DEVICE},netdev=vmnic" elif (( $DO_NET_TAP )); then # quick note to enable tap interface # IFNAME=qemu0 @@ -116,7 +136,7 @@ elif (( $DO_NET_TAP )); then # sudo ifconfig ${IFNAME} up # sudo ip link set ${IFNAME} master ${BRIDGE} ARGS+=" -netdev tap,id=vmnic,ifname=qemu0,script=no,downscript=no" - ARGS+=" -device virtio-net-device,netdev=vmnic" + ARGS+=" -device ${VIRTIO_NET_DEVICE},netdev=vmnic" #SUDO="sudo " else NO_NET_ARGS=" -net none" @@ -124,16 +144,16 @@ else fi if (( $DO_DISPLAY )); then - ARGS+=" -device virtio-gpu-device -serial stdio" - ARGS+=" -device virtio-keyboard-device" - ARGS+=" -device virtio-mouse-device" + ARGS+=" -device ${VIRTIO_GPU_DEVICE} -serial stdio" + ARGS+=" -device ${VIRTIO_KEYBOARD_DEVICE}" + ARGS+=" -device ${VIRTIO_MOUSE_DEVICE}" else ARGS+=" -nographic" fi if (( $DO_V9P )); then ARGS+=" -fsdev local,path=$DO_V9P_DIR,security_model=mapped,id=v9p0" - ARGS+=" -device virtio-9p-device,fsdev=v9p0,mount_tag=V9P0" + ARGS+=" -device ${VIRTIO_9P_DEVICE},fsdev=v9p0,mount_tag=V9P0" fi MAKE_VARS="" diff --git a/scripts/do-qemuriscv b/scripts/do-qemuriscv index ea341f9f0..6841ca79d 100755 --- a/scripts/do-qemuriscv +++ b/scripts/do-qemuriscv @@ -19,6 +19,7 @@ function HELP { echo "-n : a virtio network device" echo "-t : a virtio tap network device" echo "-g : a virtio display" + echo "-P : PCI based virtio devices" echo echo "-h for help" echo "all arguments after -- are passed to qemu directly" @@ -36,12 +37,13 @@ DO_DISPLAY=0 DO_CMPCTMALLOC=0 DO_MINIHEAP=0 DO_SUPERVISOR=0 +DO_PCI_VIRTIO=0 SMP=1 MEMSIZE=0 SUDO="" PROJECT="" -while getopts cd:ghm:Mmnteu6p:s:S FLAG; do +while getopts cd:ghm:Mmnteu6p:Ps:S FLAG; do case $FLAG in c) DO_CMPCTMALLOC=1;; d) DO_DISK=1; DISK_IMAGE=$OPTARG;; @@ -56,6 +58,7 @@ while getopts cd:ghm:Mmnteu6p:s:S FLAG; do s) SMP=$OPTARG;; S) DO_SUPERVISOR=1;; p) PROJECT=$OPTARG;; + P) DO_PCI_VIRTIO=1;; h) HELP;; \?) echo unrecognized option @@ -115,6 +118,22 @@ if [[ -z "$MEMSIZE" ]]; then PROJECT=$_MEMSIZE fi +if (( $DO_PCI_VIRTIO )); then + VIRTIO_BLOCK_DEVICE="virtio-blk-pci" + VIRTIO_NET_DEVICE="virtio-net-pci" + VIRTIO_GPU_DEVICE="virtio-gpu-pci" + VIRTIO_KEYBOARD_DEVICE="virtio-keyboard-pci" + VIRTIO_MOUSE_DEVICE="virtio-mouse-pci" + VIRTIO_9P_DEVICE="virtio-9p-pci" +else + VIRTIO_BLOCK_DEVICE="virtio-blk-device" + VIRTIO_NET_DEVICE="virtio-net-device" + VIRTIO_GPU_DEVICE="virtio-gpu-device" + VIRTIO_KEYBOARD_DEVICE="virtio-keyboard-device" + VIRTIO_MOUSE_DEVICE="virtio-mouse-device" + VIRTIO_9P_DEVICE="virtio-9p-device" +fi + # construct a list of args based on previous variables ARGS=" -machine $MACHINE" #ARGS+=",dumpdtb=riscv.dtb" # uncheck this to get a binary dump of the device tree for this config @@ -133,11 +152,11 @@ if [[ ! -z "$BIOS" ]]; then fi if (( $DO_DISK )); then ARGS+=" -drive if=none,file=${DISK_IMAGE},id=blk,format=raw" - ARGS+=" -device virtio-blk-device,drive=blk" + ARGS+=" -device ${VIRTIO_BLOCK_DEVICE},drive=blk" fi if (( $DO_NET )); then ARGS+=" -netdev user,id=vmnic,hostname=qemu" - ARGS+=" -device virtio-net-device,netdev=vmnic" + ARGS+=" -device ${VIRTIO_NET_DEVICE},netdev=vmnic" fi if (( $DO_NET_TAP )); then # quick note to enable tap interface @@ -147,13 +166,13 @@ if (( $DO_NET_TAP )); then # sudo ifconfig ${IFNAME} up # sudo ip link set ${IFNAME} master ${BRIDGE} ARGS+=" -netdev tap,id=vmnic,ifname=qemu0,script=no,downscript=no" - ARGS+=" -device virtio-net-device,netdev=vmnic" + ARGS+=" -device ${VIRTIO_NET_DEVICE},netdev=vmnic" #SUDO="sudo " fi if (( $DO_DISPLAY )); then - ARGS+=" -device virtio-gpu-device -serial stdio" - ARGS+=" -device virtio-keyboard-device" - ARGS+=" -device virtio-mouse-device" + ARGS+=" -device ${VIRTIO_GPU_DEVICE} -serial stdio" + ARGS+=" -device ${VIRTIO_KEYBOARD_DEVICE}" + ARGS+=" -device ${VIRTIO_MOUSE_DEVICE}" else ARGS+=" -nographic" fi