Hmm, I think I have accidentally committed an older version of this patch... Can you please check and incrementally commit the differences between the versions? Sorry about that.
-- Nadav Har'El [email protected] On Mon, Mar 4, 2019 at 12:15 AM Waldemar Kozaczuk <[email protected]> wrote: > Adds implementation of virtio mmio devices > needed to support block and networking devices > on firecracker. > > Signed-off-by: Waldemar Kozaczuk <[email protected]> > --- > Makefile | 1 + > arch/x64/arch-setup.cc | 5 + > drivers/virtio-mmio.cc | 216 +++++++++++++++++++++++++++++++++++++++++ > drivers/virtio-mmio.hh | 154 +++++++++++++++++++++++++++++ > 4 files changed, 376 insertions(+) > create mode 100644 drivers/virtio-mmio.cc > create mode 100644 drivers/virtio-mmio.hh > > diff --git a/Makefile b/Makefile > index 377e93e9..3f560807 100644 > --- a/Makefile > +++ b/Makefile > @@ -821,6 +821,7 @@ drivers += arch/$(arch)/pvclock-abi.o > drivers += drivers/virtio.o > drivers += drivers/virtio-pci-device.o > drivers += drivers/virtio-vring.o > +drivers += drivers/virtio-mmio.o > drivers += drivers/virtio-net.o > drivers += drivers/vmxnet3.o > drivers += drivers/vmxnet3-queues.o > diff --git a/arch/x64/arch-setup.cc b/arch/x64/arch-setup.cc > index 7350714c..9317dd25 100644 > --- a/arch/x64/arch-setup.cc > +++ b/arch/x64/arch-setup.cc > @@ -24,9 +24,11 @@ > > osv_multiboot_info_type* osv_multiboot_info; > > +#include "drivers/virtio-mmio.hh" > void parse_cmdline(multiboot_info_type& mb) > { > auto p = reinterpret_cast<char*>(mb.cmdline); > + virtio::parse_mmio_device_configuration(p); > osv::parse_cmdline(p); > } > > @@ -246,6 +248,9 @@ void arch_init_drivers() > boot_time.event("pci enumerated"); > } > > + // Register any parsed virtio-mmio devices > + virtio::register_mmio_devices(device_manager::instance()); > + > // Initialize all drivers > hw::driver_manager* drvman = hw::driver_manager::instance(); > drvman->register_driver(virtio::blk::probe); > diff --git a/drivers/virtio-mmio.cc b/drivers/virtio-mmio.cc > new file mode 100644 > index 00000000..12bf3413 > --- /dev/null > +++ b/drivers/virtio-mmio.cc > @@ -0,0 +1,216 @@ > +/* > + * Copyright (C) 2019 Waldemar Kozaczuk > + * > + * This work is open source software, licensed under the terms of the > + * BSD license as described in the LICENSE file in the top-level > directory. > + */ > + > +#include <vector> > +#include <osv/debug.hh> > +#include "virtio-mmio.hh" > + > +namespace virtio { > + > +// This implements virtio-io mmio device (transport layer, modeled after > PSI). > +// Read here - > https://www.kraxel.org/virtio/virtio-v1.0-cs03-virtio-gpu.html#x1-1080002 > +hw_device_id mmio_device::get_id() > +{ > + return hw_device_id(0x1af4, _device_id); > +} > + > +u8 mmio_device::get_status() > +{ > + return mmio_getl(_addr_mmio + VIRTIO_MMIO_STATUS) & 0xff; > +} > + > +void mmio_device::set_status(u8 status) > +{ > + mmio_setl(_addr_mmio + VIRTIO_MMIO_STATUS, status); > +} > + > +u64 mmio_device::get_available_features() > +{ > + u64 features; > + > + mmio_setl(_addr_mmio + VIRTIO_MMIO_DEVICE_FEATURES_SEL, 1); > + features = mmio_getl(_addr_mmio + VIRTIO_MMIO_DEVICE_FEATURES); > + features <<= 32; > + > + mmio_setl(_addr_mmio + VIRTIO_MMIO_DEVICE_FEATURES_SEL, 0); > + features |= mmio_getl(_addr_mmio + VIRTIO_MMIO_DEVICE_FEATURES); > + > + return features; > +} > + > +void mmio_device::set_enabled_features(u64 features) > +{ > + mmio_setl(_addr_mmio + VIRTIO_MMIO_DRIVER_FEATURES_SEL, 1); > + mmio_setl(_addr_mmio + VIRTIO_MMIO_DRIVER_FEATURES, (u32)(features >> > 32)); > + > + mmio_setl(_addr_mmio + VIRTIO_MMIO_DRIVER_FEATURES_SEL, 0); > + mmio_setl(_addr_mmio + VIRTIO_MMIO_DRIVER_FEATURES, (u32)features); > +} > + > +void mmio_device::kick_queue(int queue_num) > +{ > + mmio_setl(_addr_mmio + VIRTIO_MMIO_QUEUE_NOTIFY, queue_num); > +} > + > +void mmio_device::select_queue(int queue_num) > +{ > + mmio_setl(_addr_mmio + VIRTIO_MMIO_QUEUE_SEL, queue_num); > + assert(!mmio_getl(_addr_mmio + VIRTIO_MMIO_QUEUE_READY)); > +} > + > +u16 mmio_device::get_queue_size() > +{ > + return mmio_getl(_addr_mmio + VIRTIO_MMIO_QUEUE_NUM_MAX) & 0xffff; > +} > + > +void mmio_device::setup_queue(vring* queue) > +{ > + // Set size > + mmio_setl(_addr_mmio + VIRTIO_MMIO_QUEUE_NUM, queue->size()); > + // > + // Pass addresses > + mmio_setl(_addr_mmio + VIRTIO_MMIO_QUEUE_DESC_LOW, > (u32)queue->get_desc_addr()); > + mmio_setl(_addr_mmio + VIRTIO_MMIO_QUEUE_DESC_HIGH, > (u32)(queue->get_desc_addr() >> 32)); > + > + mmio_setl(_addr_mmio + VIRTIO_MMIO_QUEUE_AVAIL_LOW, > (u32)queue->get_avail_addr()); > + mmio_setl(_addr_mmio + VIRTIO_MMIO_QUEUE_AVAIL_HIGH, > (u32)(queue->get_avail_addr() >> 32)); > + > + mmio_setl(_addr_mmio + VIRTIO_MMIO_QUEUE_USED_LOW, > (u32)queue->get_used_addr()); > + mmio_setl(_addr_mmio + VIRTIO_MMIO_QUEUE_USED_HIGH, > (u32)(queue->get_used_addr() >> 32)); > +} > + > +void mmio_device::activate_queue(int queue) > +{ // > + // Make it ready > + select_queue(queue); > + mmio_setl(_addr_mmio + VIRTIO_MMIO_QUEUE_READY, 1 ); > +} > + > +u8 mmio_device::read_and_ack_isr() > +{ > + unsigned long status = mmio_getl(_addr_mmio + > VIRTIO_MMIO_INTERRUPT_STATUS); > + mmio_setl(_addr_mmio + VIRTIO_MMIO_INTERRUPT_ACK, status); > + return (status & VIRTIO_MMIO_INT_VRING); > +} > + > +u8 mmio_device::read_config(u32 offset) > +{ > + return mmio_getb(_addr_mmio + VIRTIO_MMIO_CONFIG + offset); > +} > + > +void mmio_device::register_interrupt(interrupt_factory irq_factory) > +{ > + _irq.reset(irq_factory.create_gsi_edge_interrupt()); > +} > + > +bool mmio_device::parse_config() > +{ > + _addr_mmio = mmio_map(_dev_info._address, _dev_info._size); > + > + u32 magic = mmio_getl(_addr_mmio + VIRTIO_MMIO_MAGIC_VALUE); > + if (magic != ('v' | 'i' << 8 | 'r' << 16 | 't' << 24)) { > + return false; > + } > + > + // Check device version > + u32 version = mmio_getl(_addr_mmio + VIRTIO_MMIO_VERSION); > + if (version < 1 || version > 2) { > + debugf( "Version %ld not supported!\n", version); > + return false; > + } > + > + _device_id = mmio_getl(_addr_mmio + VIRTIO_MMIO_DEVICE_ID); > + if (_device_id == 0) { > + // > + // virtio-mmio device with an ID 0 is a (dummy) placeholder > + // with no function. End probing now with no error reported. > + debug( "Dummy virtio-mmio device detected!\n"); > + return false; > + } > + _vendor_id = mmio_getl(_addr_mmio + VIRTIO_MMIO_VENDOR_ID); > + > + debugf("Detected virtio-mmio device: (%ld,%ld)\n", _device_id, > _vendor_id); > + return true; > +} > + > +#define VIRTIO_MMIO_DEVICE_CMDLINE_PREFIX "virtio_mmio.device=" > +static mmio_device_info* parse_mmio_device_info(char *cmdline) > +{ // > + // Parse virtio mmio device information from command line > + // appended/prepended by VMMs like firecracker. After successfully > + // parsing any found mmio device info, remove it from the commandline. > + // > + // [virtio_mmio.]device=<size>@<baseaddr>:<irq>[:<id>] > + char *prefix_pos = strstr(cmdline,VIRTIO_MMIO_DEVICE_CMDLINE_PREFIX); > + if (!prefix_pos) > + return nullptr; > + > + u64 size = 0; > + char *size_pos = prefix_pos + > strlen(VIRTIO_MMIO_DEVICE_CMDLINE_PREFIX); > + if (sscanf(size_pos,"%ld", &size) != 1) > + return nullptr; > + > + char *at_pos = strstr(size_pos,"@"); > + if (!at_pos) > + return nullptr; > + > + switch(*(at_pos - 1)) { > + case 'k': > + case 'K': > + size *= 1024; > + break; > + case 'm': > + case 'M': > + size *= (1024 * 1024); > + break; > + default: > + break; > + } > + > + u64 irq = 0, address = 0; > + if (sscanf(at_pos, "@%lli:%u", &address, &irq) != 2) > + return nullptr; > + > + // Find first white-character or null as an end of device description > + auto desc_end_pos = at_pos; > + while (*desc_end_pos != 0 && !isspace(*desc_end_pos)) > + desc_end_pos++; > + > + // Remove conf info part from cmdline by copying over remaining part > + do { > + *prefix_pos = *desc_end_pos++; > + } while (*prefix_pos++); > + > + return new mmio_device_info(address, size, irq); > +} > + > +static std::vector<struct mmio_device_info> *mmio_device_info_entries = 0; > + > +void parse_mmio_device_configuration(char *cmdline) > +{ // > + // We are assuming the mmio devices information is appended to the > + // command line (at least it is the case with the firecracker) so > + // once we parse those we strip it away so only plain OSv command > line is left > + mmio_device_info_entries = new std::vector<struct mmio_device_info>(); > + for( auto device_info = parse_mmio_device_info(cmdline); device_info > != nullptr; device_info = parse_mmio_device_info(cmdline)) > + mmio_device_info_entries->push_back(*device_info); > +} > + > +void register_mmio_devices(hw::device_manager *dev_manager) > +{ > + for (auto info : *mmio_device_info_entries) { > + auto device = new mmio_device(info); > + if (device->parse_config()) { > + dev_manager->register_device(device); > + } > + else { > + delete device; > + } > + } > +} > + > +} > diff --git a/drivers/virtio-mmio.hh b/drivers/virtio-mmio.hh > new file mode 100644 > index 00000000..024190ac > --- /dev/null > +++ b/drivers/virtio-mmio.hh > @@ -0,0 +1,154 @@ > +/* > + * Copyright (C) 2019 Waldemar Kozaczuk > + * > + * This work is open source software, licensed under the terms of the > + * BSD license as described in the LICENSE file in the top-level > directory. > + */ > + > +#ifndef VIRTIO_MMIO_DEVICE_HH > +#define VIRTIO_MMIO_DEVICE_HH > + > +#include <osv/types.h> > +#include <osv/mmio.hh> > +#include "virtio-device.hh" > +#include "virtio-vring.hh" > + > +using namespace hw; > + > +/* Magic value ("virt" string) - Read Only */ > +#define VIRTIO_MMIO_MAGIC_VALUE 0x000 > + > +/* Virtio device version - Read Only */ > +#define VIRTIO_MMIO_VERSION 0x004 > + > +/* Virtio device ID - Read Only */ > +#define VIRTIO_MMIO_DEVICE_ID 0x008 > + > +/* Virtio vendor ID - Read Only */ > +#define VIRTIO_MMIO_VENDOR_ID 0x00c > + > +/* Bitmask of the features supported by the device (host) > + * (32 bits per set) - Read Only */ > +#define VIRTIO_MMIO_DEVICE_FEATURES 0x010 > + > +/* Device (host) features set selector - Write Only */ > +#define VIRTIO_MMIO_DEVICE_FEATURES_SEL 0x014 > + > +/* Bitmask of features activated by the driver (guest) > + * (32 bits per set) - Write Only */ > +#define VIRTIO_MMIO_DRIVER_FEATURES 0x020 > + > +/* Activated features set selector - Write Only */ > +#define VIRTIO_MMIO_DRIVER_FEATURES_SEL 0x024 > + > +/* Queue selector - Write Only */ > +#define VIRTIO_MMIO_QUEUE_SEL 0x030 > + > +/* Maximum size of the currently selected queue - Read Only */ > +#define VIRTIO_MMIO_QUEUE_NUM_MAX 0x034 > + > +/* Queue size for the currently selected queue - Write Only */ > +#define VIRTIO_MMIO_QUEUE_NUM 0x038 > + > +/* Ready bit for the currently selected queue - Read Write */ > +#define VIRTIO_MMIO_QUEUE_READY 0x044 > + > +/* Queue notifier - Write Only */ > +#define VIRTIO_MMIO_QUEUE_NOTIFY 0x050 > + > +/* Interrupt status - Read Only */ > +#define VIRTIO_MMIO_INTERRUPT_STATUS 0x060 > + > +/* Interrupt acknowledge - Write Only */ > +#define VIRTIO_MMIO_INTERRUPT_ACK 0x064 > + > +/* Device status register - Read Write */ > +#define VIRTIO_MMIO_STATUS 0x070 > + > +/* Selected queue's Descriptor Table address, 64 bits in two halves */ > +#define VIRTIO_MMIO_QUEUE_DESC_LOW 0x080 > +#define VIRTIO_MMIO_QUEUE_DESC_HIGH 0x084 > + > +/* Selected queue's Available Ring address, 64 bits in two halves */ > +#define VIRTIO_MMIO_QUEUE_AVAIL_LOW 0x090 > +#define VIRTIO_MMIO_QUEUE_AVAIL_HIGH 0x094 > + > +/* Selected queue's Used Ring address, 64 bits in two halves */ > +#define VIRTIO_MMIO_QUEUE_USED_LOW 0x0a0 > +#define VIRTIO_MMIO_QUEUE_USED_HIGH 0x0a4 > + > +/* Configuration atomicity value */ > +#define VIRTIO_MMIO_CONFIG_GENERATION 0x0fc > + > +/* The config space is defined by each driver as > + * the per-driver configuration space - Read Write */ > +#define VIRTIO_MMIO_CONFIG 0x100 > + > +#define VIRTIO_MMIO_INT_VRING (1 << 0) > +#define VIRTIO_MMIO_INT_CONFIG (1 << 1) > + > +namespace virtio { > + > +struct mmio_device_info { > + mmio_device_info(u64 address, u64 size, unsigned int irq) : > + _address(address), _size(size), _irq_no(irq) {} > + > + u64 _address; > + u64 _size; > + unsigned int _irq_no; > +}; > + > +class mmio_device : public virtio_device { > +public: > + mmio_device(mmio_device_info dev_info) : > + _dev_info(dev_info), _vendor_id(0), _device_id(0), _addr_mmio(0) > {} > + > + virtual ~mmio_device() {} > + > + virtual hw_device_id get_id(); > + > + virtual void init() {} > + virtual void print() {} > + virtual void reset() {} > + > + virtual unsigned get_irq() { return _dev_info._irq_no; } > + virtual u8 read_and_ack_isr(); > + virtual void register_interrupt(interrupt_factory irq_factory); > + > + virtual void select_queue(int queue); > + virtual u16 get_queue_size(); > + virtual void setup_queue(vring *queue); > + virtual void activate_queue(int queue); > + virtual void kick_queue(int queue); > + > + virtual u64 get_available_features(); > + virtual void set_enabled_features(u64 features); > + > + virtual u8 get_status(); > + virtual void set_status(u8 status); > + > + virtual u8 read_config(u32 offset); > + > + virtual void dump_config() {} > + > + virtual bool is_modern() { return true; }; > + virtual size_t get_vring_alignment() { return PAGE_SIZE; } > + > + bool parse_config(); > + > +private: > + mmio_device_info _dev_info; > + //u64 _id; > + u16 _vendor_id; > + u16 _device_id; > + > + mmioaddr_t _addr_mmio; > + std::unique_ptr<gsi_edge_interrupt> _irq; > +}; > + > +void parse_mmio_device_configuration(char *cmdline); > +void register_mmio_devices(hw::device_manager *dev_manager); > + > +} > + > +#endif //VIRTIO_MMIO_DEVICE_HH > -- > 2.19.1 > > -- > You received this message because you are subscribed to the Google Groups > "OSv Development" group. > To unsubscribe from this group and stop receiving emails from it, send an > email to [email protected]. > For more options, visit https://groups.google.com/d/optout. > -- You received this message because you are subscribed to the Google Groups "OSv Development" group. To unsubscribe from this group and stop receiving emails from it, send an email to [email protected]. For more options, visit https://groups.google.com/d/optout.
