Thanks! I tried scripts/run.py --virtio modern with network and disk, and
it seems to be working, so I've committed this series.

--
Nadav Har'El
n...@scylladb.com


On Wed, Feb 6, 2019 at 3:29 PM Waldemar Kozaczuk <jwkozac...@gmail.com>
wrote:

> This patch implements modern virtio PCI device
> and makes necessary changes to virtio drivers
> to behave slighlt differently whether it is
> a modern or legacy device.
>
> Please note that QEMU can emulate virtio device
> as legacy, modern or transitional (default) one. The transitional
> means that device can act as either legacy or modern.
> Currently OSv would detect transitional device
> as legacy one and use it as such. In the future
> we may change OSv to do the opposite once we feel
> comfortable that modern virtio PCI implementation
> in OSv is correct.
>
> You can run OSv with modern, legacy or transitional
> devices simulated by QEMU by passing correct
> value of a new '--virtio' parameter to scripts/run.py.
>
> Signed-off-by: Waldemar Kozaczuk <jwkozac...@gmail.com>
> ---
>  drivers/pci-function.cc      |  16 ++-
>  drivers/pci-function.hh      |   2 +
>  drivers/virtio-blk.cc        |  22 ++++-
>  drivers/virtio-device.hh     |   1 +
>  drivers/virtio-net.cc        |  21 +++-
>  drivers/virtio-pci-device.cc | 184 ++++++++++++++++++++++++++++++++++-
>  drivers/virtio-pci-device.hh | 161 ++++++++++++++++++++++++++++++
>  drivers/virtio-vring.cc      |  15 +++
>  drivers/virtio-vring.hh      |   4 +
>  drivers/virtio.cc            |   7 ++
>  drivers/virtio.hh            |   3 +
>  11 files changed, 424 insertions(+), 12 deletions(-)
>
> diff --git a/drivers/pci-function.cc b/drivers/pci-function.cc
> index eb12c452..ac585bc6 100644
> --- a/drivers/pci-function.cc
> +++ b/drivers/pci-function.cc
> @@ -100,6 +100,11 @@ namespace pci {
>          }
>      }
>
> +    bool bar::is_mapped()
> +    {
> +        return _addr_mmio != mmio_nullptr;
> +    }
> +
>      mmioaddr_t bar::get_mmio()
>      {
>          return _addr_mmio;
> @@ -808,6 +813,11 @@ namespace pci {
>      }
>
>      u8 function::find_capability(u8 cap_id)
> +    {
> +        return this->find_capability(cap_id, [](function *fun, u8 off) {
> return true; } );
> +    }
> +
> +    u8 function::find_capability(u8 cap_id, std::function<bool
> (function*, u8)> predicate)
>      {
>          u8 capabilities_base = pci_readb(PCI_CAPABILITIES_PTR);
>          u8 off = capabilities_base;
> @@ -818,7 +828,7 @@ namespace pci {
>          while (off != 0) {
>              // Read capability
>              u8 capability = pci_readb(off + PCI_CAP_OFF_ID);
> -            if (capability == cap_id) {
> +            if (capability == cap_id && predicate(this, off)) {
>                  return off;
>              }
>
> @@ -858,9 +868,9 @@ namespace pci {
>          for (int bar_idx = 1; bar_idx <= 6; bar_idx++) {
>              bar *bar = get_bar(bar_idx);
>              if (bar) {
> -                pci_d("    bar[%d]: %sbits addr=%p size=%x",
> +                pci_d("    bar[%d]: %sbits addr=%p size=%x, mmio=%d",
>                      bar_idx, (bar->is_64() ? "64" : "32"),
> -                    bar->get_addr64(), bar->get_size());
> +                    bar->get_addr64(), bar->get_size(), bar->is_mmio());
>              }
>          }
>
> diff --git a/drivers/pci-function.hh b/drivers/pci-function.hh
> index 13a9aa01..06ec96f6 100644
> --- a/drivers/pci-function.hh
> +++ b/drivers/pci-function.hh
> @@ -73,6 +73,7 @@ namespace pci {
>          // map mmio region
>          void map();
>          void unmap();
> +        bool is_mapped();
>          mmioaddr_t get_mmio();
>
>          // Access the pio or mmio bar
> @@ -343,6 +344,7 @@ namespace pci {
>
>          // Capability parsing
>          u8 find_capability(u8 cap_id);
> +        u8 find_capability(u8 cap_id, std::function<bool (function*, u8)>
> predicate);
>
>          bar * get_bar(int idx);
>          void add_bar(int idx, bar* bar);
> diff --git a/drivers/virtio-blk.cc b/drivers/virtio-blk.cc
> index 6b439ada..0bc6fb0f 100644
> --- a/drivers/virtio-blk.cc
> +++ b/drivers/virtio-blk.cc
> @@ -174,8 +174,17 @@ blk::~blk()
>
>  void blk::read_config()
>  {
> -    //read all of the block config (including size, mce, topology,..) in
> one shot
> -    virtio_conf_read(0, &_config, sizeof(_config));
> +    if (_dev.is_modern()) {
> +        //TODO: It may to do with legacy vs non-legacy device
> +        //but at least with latest spec we should check if individual
> +        //config fields are available vs reading whole config struct. For
> example
> +        //firecracker reports memory read violation warnings
> +        virtio_conf_read(0, &_config, sizeof(_config.capacity));
> +    }
> +    else {
> +        //read all of the block config (including size, mce, topology,..)
> in one shot
> +        virtio_conf_read(0, &_config, sizeof(_config));
> +    }
>
>      trace_virtio_blk_read_config_capacity(_config.capacity);
>
> @@ -251,9 +260,12 @@ int blk::make_request(struct bio* bio)
>
>          if (!bio) return EIO;
>
> -        if (bio->bio_bcount/mmu::page_size + 1 > _config.seg_max) {
> -            trace_virtio_blk_make_request_seg_max(bio->bio_bcount,
> _config.seg_max);
> -            return EIO;
> +        // TODO: Check if seg_max is unavailable if modern ...
> +        if (!_dev.is_modern()) {
> +            if (bio->bio_bcount/mmu::page_size + 1 > _config.seg_max) {
> +                trace_virtio_blk_make_request_seg_max(bio->bio_bcount,
> _config.seg_max);
> +                return EIO;
> +            }
>          }
>
>          auto* queue = get_virt_queue(0);
> diff --git a/drivers/virtio-device.hh b/drivers/virtio-device.hh
> index 93f65a4b..c4a9f180 100644
> --- a/drivers/virtio-device.hh
> +++ b/drivers/virtio-device.hh
> @@ -59,6 +59,7 @@ public:
>      virtual void select_queue(int queue) = 0;
>      virtual u16 get_queue_size() = 0;
>      virtual void setup_queue(vring *queue) = 0;
> +    virtual void activate_queue(int queue) = 0;
>      virtual void kick_queue(int queue) = 0;
>
>      virtual u64 get_available_features() = 0;
> diff --git a/drivers/virtio-net.cc b/drivers/virtio-net.cc
> index 3f75cea5..ef2dff66 100644
> --- a/drivers/virtio-net.cc
> +++ b/drivers/virtio-net.cc
> @@ -250,7 +250,13 @@ net::net(virtio_device& dev)
>
>      poll_task->set_priority(sched::thread::priority_infinity);
>
> -    _hdr_size = _mergeable_bufs ? sizeof(net_hdr_mrg_rxbuf) :
> sizeof(net_hdr);
> +    if (_dev.is_modern()) {
> +        //TODO: Legacy vs non-legacy -> the non-legacy header includes
> one more field
> +        _hdr_size = sizeof(net_hdr_mrg_rxbuf);
> +    }
> +    else {
> +        _hdr_size = _mergeable_bufs ? sizeof(net_hdr_mrg_rxbuf) :
> sizeof(net_hdr);
> +    }
>
>      //initialize the BSD interface _if
>      _ifn = if_alloc(IFT_ETHER);
> @@ -335,8 +341,17 @@ net::~net()
>
>  void net::read_config()
>  {
> -    //read all of the net config  in one shot
> -    virtio_conf_read(0, &_config, sizeof(_config));
> +    if (_dev.is_modern()) {
> +        //TODO: It may to do with legacy vs non-legacy device
> +        //but at least with latest spec we should check if individual
> +        //config fields are available vs reading whole config struct. For
> example
> +        //firecracker reports memory read violation warnings
> +        virtio_conf_read(0, &(_config.mac[0]), sizeof(_config.mac));
> +    }
> +    else {
> +        //read all of the net config  in one shot
> +        virtio_conf_read(0, &_config, sizeof(_config));
> +    }
>
>      if (get_guest_feature_bit(VIRTIO_NET_F_MAC))
>          net_i("The mac addr of the device is %x:%x:%x:%x:%x:%x",
> diff --git a/drivers/virtio-pci-device.cc b/drivers/virtio-pci-device.cc
> index bfd20a04..dc444757 100644
> --- a/drivers/virtio-pci-device.cc
> +++ b/drivers/virtio-pci-device.cc
> @@ -163,8 +163,190 @@ bool virtio_legacy_pci_device::parse_pci_config()
>      return true;
>  }
>
> +virtio_modern_pci_device::virtio_modern_pci_device(pci::device *dev)
> +    : virtio_pci_device(dev)
> +{
> +}
> +
> +void virtio_modern_pci_device::dump_config()
> +{
> +    virtio_pci_device::dump_config();
> +
> +    _common_cfg->print("  common cfg:");
> +    _isr_cfg->print("  isr cfg:");
> +    _notify_cfg->print("  notify cfg:");
> +    _device_cfg->print("  device cfg:");
> +}
> +
> +void virtio_modern_pci_device::kick_queue(int queue)
> +{
> +    auto offset = _notify_offset_multiplier *
> _queues_notify_offsets[queue];
> +    _notify_cfg->virtio_conf_writew(offset, queue);
> +}
> +
> +void virtio_modern_pci_device::setup_queue(vring *queue)
> +{
> +    auto queue_index = queue->index();
> +
> +    if (_dev->is_msix()) {
> +        // Setup queue_id:entry_id 1:1 correlation...
> +
> _common_cfg->virtio_conf_writew(COMMON_CFG_OFFSET_OF(queue_msix_vector),
> queue_index);
> +        if
> (_common_cfg->virtio_conf_readw(COMMON_CFG_OFFSET_OF(queue_msix_vector) !=
> queue_index)) {
> +            virtio_e("Setting MSIx entry for queue %d failed.",
> queue_index);
> +            return;
> +        }
> +    }
> +
> +    _queues_notify_offsets[queue_index] =
> +
> _common_cfg->virtio_conf_readw(COMMON_CFG_OFFSET_OF(queue_notify_off));
> +
> +    _common_cfg->virtio_conf_writew(COMMON_CFG_OFFSET_OF(queue_size),
> queue->size());
> +    //
> +    // Pass addresses
> +    _common_cfg->virtio_conf_writel(COMMON_CFG_OFFSET_OF(queue_desc_lo),
> (u32)queue->get_desc_addr());
> +    _common_cfg->virtio_conf_writel(COMMON_CFG_OFFSET_OF(queue_desc_hi),
> (u32)(queue->get_desc_addr() >> 32));
> +
> +    _common_cfg->virtio_conf_writel(COMMON_CFG_OFFSET_OF(queue_avail_lo),
> (u32)queue->get_avail_addr());
> +    _common_cfg->virtio_conf_writel(COMMON_CFG_OFFSET_OF(queue_avail_hi),
> (u32)(queue->get_avail_addr() >> 32));
> +
> +    _common_cfg->virtio_conf_writel(COMMON_CFG_OFFSET_OF(queue_used_lo),
> (u32)queue->get_used_addr());
> +    _common_cfg->virtio_conf_writel(COMMON_CFG_OFFSET_OF(queue_used_hi),
> (u32)(queue->get_used_addr() >> 32));
> +}
> +
> +void virtio_modern_pci_device::activate_queue(int queue)
> +{
> +    select_queue(queue);
> +    _common_cfg->virtio_conf_writew(COMMON_CFG_OFFSET_OF(queue_enable),
> 1);
> +}
> +
> +void virtio_modern_pci_device::select_queue(int queue)
> +{
> +    _common_cfg->virtio_conf_writew(COMMON_CFG_OFFSET_OF(queue_select),
> queue);
> +}
> +
> +u16 virtio_modern_pci_device::get_queue_size()
> +{
> +    return
> _common_cfg->virtio_conf_readw(COMMON_CFG_OFFSET_OF(queue_size));
> +}
> +
> +u64 virtio_modern_pci_device::get_available_features()
> +{
> +    u64 features;
> +
> +
> _common_cfg->virtio_conf_writel(COMMON_CFG_OFFSET_OF(device_feature_select),
> 0);
> +    features =
> _common_cfg->virtio_conf_readl(COMMON_CFG_OFFSET_OF(device_feature));
> +
> _common_cfg->virtio_conf_writel(COMMON_CFG_OFFSET_OF(device_feature_select),
> 1);
> +    features |=
> ((u64)_common_cfg->virtio_conf_readl(COMMON_CFG_OFFSET_OF(device_feature))
> << 32);
> +
> +    return features;
> +}
> +
> +bool virtio_modern_pci_device::get_available_feature_bit(int bit)
> +{
> +    return 0 != (get_available_features() & (1 << bit));
> +}
> +
> +void virtio_modern_pci_device::set_enabled_features(u64 features)
> +{
> +
> _common_cfg->virtio_conf_writel(COMMON_CFG_OFFSET_OF(driver_feature_select),
> 0);
> +    _common_cfg->virtio_conf_writel(COMMON_CFG_OFFSET_OF(driver_feature),
> (u32)features);
> +
> _common_cfg->virtio_conf_writel(COMMON_CFG_OFFSET_OF(driver_feature_select),
> 1);
> +    _common_cfg->virtio_conf_writel(COMMON_CFG_OFFSET_OF(driver_feature),
> features >> 32);
> +}
> +
> +u64 virtio_modern_pci_device::get_enabled_features()
> +{
> +    u64 features;
> +
> +
> _common_cfg->virtio_conf_writel(COMMON_CFG_OFFSET_OF(driver_feature_select),
> 0);
> +    features =
> _common_cfg->virtio_conf_readl(COMMON_CFG_OFFSET_OF(driver_feature));
> +
> _common_cfg->virtio_conf_writel(COMMON_CFG_OFFSET_OF(driver_feature_select),
> 1);
> +    features |=
> ((u64)_common_cfg->virtio_conf_readl(COMMON_CFG_OFFSET_OF(driver_feature))
> << 32);
> +
> +    return features;
> +}
> +
> +bool virtio_modern_pci_device::get_enabled_feature_bit(int bit)
> +{
> +    return 0 != (get_enabled_features() & (1 << bit));
> +}
> +
> +u8 virtio_modern_pci_device::get_status()
> +{
> +    return
> _common_cfg->virtio_conf_readb(COMMON_CFG_OFFSET_OF(device_status));
> +}
> +
> +void virtio_modern_pci_device::set_status(u8 status)
> +{
> +    _common_cfg->virtio_conf_writeb(COMMON_CFG_OFFSET_OF(device_status),
> status);
> +}
> +
> +u8 virtio_modern_pci_device::read_config(u32 offset)
> +{
> +    return _device_cfg->virtio_conf_readb(offset);
> +}
> +
> +u8 virtio_modern_pci_device::read_and_ack_isr()
> +{
> +    return _isr_cfg->virtio_conf_readb(0);
> +}
> +
> +bool virtio_modern_pci_device::parse_pci_config()
> +{
> +    // Check ABI version
> +    u8 rev = _dev->get_revision_id();
> +    if (rev < VIRTIO_PCI_MODERN_ABI_VERSION) {
> +        virtio_e("Wrong virtio revision=%x", rev);
> +        return false;
> +    }
> +
> +    // Check device ID
> +    u16 dev_id = _dev->get_device_id();
> +    if ((dev_id < VIRTIO_PCI_MODERN_ID_MIN) || (dev_id >
> VIRTIO_PCI_MODERN_ID_MAX)) {
> +        virtio_e("Wrong virtio dev id %x", dev_id);
> +        return false;
> +    }
> +
> +    parse_virtio_capability(_common_cfg, VIRTIO_PCI_CAP_COMMON_CFG);
> +    parse_virtio_capability(_isr_cfg, VIRTIO_PCI_CAP_ISR_CFG);
> +    parse_virtio_capability(_notify_cfg, VIRTIO_PCI_CAP_NOTIFY_CFG);
> +    parse_virtio_capability(_device_cfg, VIRTIO_PCI_CAP_DEVICE_CFG);
> +
> +    if (_notify_cfg) {
> +        _notify_offset_multiplier
> =_dev->pci_readl(_notify_cfg->get_cfg_offset() +
> +                offsetof(virtio_pci_notify_cap,
> notify_offset_multiplier));
> +    }
> +
> +    return _common_cfg && _isr_cfg && _notify_cfg && _device_cfg;
> +}
> +
> +void
> virtio_modern_pci_device::parse_virtio_capability(std::unique_ptr<virtio_capability>
> &ptr, u8 type)
> +{
> +    u8 cfg_offset = _dev->find_capability(pci::function::PCI_CAP_VENDOR,
> [type] (pci::function *fun, u8 offset) {
> +        u8 cfg_type = fun->pci_readb(offset + offsetof(struct
> virtio_pci_cap, cfg_type));
> +        return type == cfg_type;
> +    });
> +
> +    if (cfg_offset != 0xFF) {
> +        u8 bar_index = _dev->pci_readb(cfg_offset + offsetof(struct
> virtio_pci_cap, bar));
> +        u32 offset = _dev->pci_readl(cfg_offset + offsetof(struct
> virtio_pci_cap, offset));
> +        u32 length = _dev->pci_readl(cfg_offset + offsetof(struct
> virtio_pci_cap, length));
> +
> +        auto bar_no = bar_index + 1;
> +        auto bar = _dev->get_bar(bar_no);
> +        if (bar && bar->is_mmio() && !bar->is_mapped()) {
> +            bar->map();
> +        }
> +
> +        ptr.reset(new
> virtio_modern_pci_device::virtio_capability(cfg_offset, bar, bar_no,
> offset, length));
> +    }
> +}
> +
>  virtio_device* create_virtio_pci_device(pci::device *dev) {
> -    return new virtio_legacy_pci_device(dev);
> +    if (dev->get_device_id() >= VIRTIO_PCI_MODERN_ID_MIN &&
> dev->get_device_id() <= VIRTIO_PCI_MODERN_ID_MAX)
> +        return new virtio_modern_pci_device(dev);
> +    else
> +        return new virtio_legacy_pci_device(dev);
>  }
>
>  }
> diff --git a/drivers/virtio-pci-device.hh b/drivers/virtio-pci-device.hh
> index 42b14934..e9554558 100644
> --- a/drivers/virtio-pci-device.hh
> +++ b/drivers/virtio-pci-device.hh
> @@ -57,6 +57,9 @@ enum VIRTIO_PCI_CONFIG {
>      VIRTIO_PCI_VRING_ALIGN = 4096,
>      VIRTIO_PCI_LEGACY_ID_MIN = 0x1000,
>      VIRTIO_PCI_LEGACY_ID_MAX = 0x103f,
> +    VIRTIO_PCI_MODERN_ABI_VERSION = 1,
> +    VIRTIO_PCI_MODERN_ID_MIN = 0x1040,
> +    VIRTIO_PCI_MODERN_ID_MAX = 0x107f,
>  };
>
>  class virtio_pci_device : public virtio_device {
> @@ -100,6 +103,7 @@ public:
>      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();
> @@ -134,6 +138,163 @@ private:
>      pci::bar* _bar1;
>  };
>
> +enum VIRTIO_MODERN_PCI_CONFIG {
> +    /* Common configuration */
> +    VIRTIO_PCI_CAP_COMMON_CFG = 1,
> +    /* Notifications */
> +    VIRTIO_PCI_CAP_NOTIFY_CFG = 2,
> +    /* ISR Status */
> +    VIRTIO_PCI_CAP_ISR_CFG = 3,
> +    /* Device specific configuration */
> +    VIRTIO_PCI_CAP_DEVICE_CFG = 4,
> +    /* PCI configuration access */
> +    VIRTIO_PCI_CAP_PCI_CFG = 5,
> +};
> +
> +/* This is the PCI capability header: */
> +struct virtio_pci_cap {
> +    u8 cap_vndr;    /* Generic PCI field: PCI_CAP_ID_VNDR */
> +    u8 cap_next;    /* Generic PCI field: next ptr. */
> +    u8 cap_len;     /* Generic PCI field: capability length */
> +    u8 cfg_type;    /* Identifies the structure. */
> +    u8 bar;         /* Where to find it. */
> +    u8 padding[3];  /* Pad to full dword. */
> +    u32 offset;     /* Offset within bar. */
> +    u32 length;     /* Length of the structure, in bytes. */
> +};
> +
> +/* The notification location is found using the VIRTIO_PCI_CAP_NOTIFY_CFG
> capability.
> + * This capability is immediately followed by an additional field, like
> so:*/
> +struct virtio_pci_notify_cap {
> +    struct virtio_pci_cap cap;
> +    u32 notify_offset_multiplier;  /* Multiplier for queue_notify_off. */
> +};
> +
> +/* The common configuration structure is found at the bar and offset
> within
> + * the VIRTIO_PCI_CAP_COMMON_CFG capability; its layout is below. */
> +struct virtio_pci_common_cfg {
> +    /* About the whole device. */
> +    u32 device_feature_select;     /* read-write */
> +    u32 device_feature;            /* read-only for driver */
> +    u32 driver_feature_select;     /* read-write */
> +    u32 driver_feature;            /* read-write */
> +    u16 msix_config;               /* read-write */
> +    u16 num_queues;                /* read-only for driver */
> +    u8 device_status;              /* read-write */
> +    u8 config_generation;          /* read-only for driver */
> +
> +    /* About a specific virtqueue. */
> +    u16 queue_select;              /* read-write */
> +    u16 queue_size;                /* read-write, power of 2, or 0. */
> +    u16 queue_msix_vector;         /* read-write */
> +    u16 queue_enable;              /* read-write */
> +    u16 queue_notify_off;          /* read-only for driver */
> +    u32 queue_desc_lo;             /* read-write */
> +    u32 queue_desc_hi;             /* read-write */
> +    u32 queue_avail_lo;            /* read-write */
> +    u32 queue_avail_hi;            /* read-write */
> +    u32 queue_used_lo;             /* read-write */
> +    u32 queue_used_hi;             /* read-write */
> +};
> +
> +#define COMMON_CFG_OFFSET_OF(field) offsetof(struct
> virtio_pci_common_cfg, field)
> +
> +class virtio_modern_pci_device : public virtio_pci_device {
> +public:
> +    struct virtio_capability {
> +        virtio_capability(u32 cfg_offset, pci::bar* bar, u32 bar_no, u32
> bar_offset, u32 length) :
> +            _cfg_offset(cfg_offset),
> +            _bar(bar),
> +            _bar_no(bar_no),
> +            _bar_offset(bar_offset),
> +            _length(length) {
> +            assert(_length > 0 && _bar_offset >= 0 && _bar_offset +
> _length <= _bar->get_size());
> +        }
> +
> +        u8 virtio_conf_readb(u32 offset) {
> +            verify_offset(offset, sizeof(u8));
> +            return _bar->readb(_bar_offset + offset);
> +        };
> +        u16 virtio_conf_readw(u32 offset) {
> +            verify_offset(offset, sizeof(u16));
> +            return _bar->readw(_bar_offset + offset);
> +        };
> +        u32 virtio_conf_readl(u32 offset) {
> +            verify_offset(offset, sizeof(u32));
> +            return _bar->readl(_bar_offset + offset);
> +        };
> +        void virtio_conf_writeb(u32 offset, u8 val) {
> +            verify_offset(offset, sizeof(u8));
> +            _bar->writeb(_bar_offset + offset, val);
> +        };
> +        void virtio_conf_writew(u32 offset, u16 val) {
> +            verify_offset(offset, sizeof(u16));
> +            _bar->writew(_bar_offset + offset, val);
> +        };
> +        void virtio_conf_writel(u32 offset, u32 val) {
> +            verify_offset(offset, sizeof(u32));
> +            _bar->writel(_bar_offset + offset, val);
> +        };
> +        u32 get_cfg_offset() { return _cfg_offset; }
> +
> +        void print(const char *prefix) {
> +            virtio_d("%s bar=%d, offset=%x, size=%x", prefix, _bar_no,
> _bar_offset, _length);
> +        }
> +    private:
> +        inline void verify_offset(u32 offset, u32 size) {
> +            assert(offset >= 0 && offset + size <= _length);
> +        }
> +
> +        u32 _cfg_offset;
> +        pci::bar* _bar;
> +        u32 _bar_no;
> +        u32 _bar_offset;
> +        u32 _length;
> +    };
> +
> +    explicit virtio_modern_pci_device(pci::device *dev);
> +    ~virtio_modern_pci_device() {}
> +
> +    virtual const char *get_version() { return "modern"; }
> +    virtual u16 get_type_id() { return _dev->get_device_id() -
> VIRTIO_PCI_MODERN_ID_MIN; };
> +
> +    virtual void dump_config();
> +
> +    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 bool get_available_feature_bit(int bit);
> +
> +    virtual void set_enabled_features(u64 features);
> +    virtual u64 get_enabled_features();
> +    virtual bool get_enabled_feature_bit(int bit);
> +
> +    virtual u8 get_status();
> +    virtual void set_status(u8 status);
> +
> +    virtual u8 read_config(u32 offset);
> +    virtual u8 read_and_ack_isr();
> +
> +    virtual bool is_modern() { return true; };
> +
> +protected:
> +    virtual bool parse_pci_config();
> +private:
> +    void parse_virtio_capability(std::unique_ptr<virtio_capability> &ptr,
> u8 type);
> +
> +    std::unique_ptr<virtio_capability> _common_cfg;
> +    std::unique_ptr<virtio_capability> _isr_cfg;
> +    std::unique_ptr<virtio_capability> _notify_cfg;
> +    std::unique_ptr<virtio_capability> _device_cfg;
> +
> +    u32 _notify_offset_multiplier;
> +    u32 _queues_notify_offsets[64];
> +};
> +
>  // Creates appropriate instance of virtio_pci_device
>  // by reading configuration from PCI device
>  virtio_device* create_virtio_pci_device(pci::device *dev);
> diff --git a/drivers/virtio-vring.cc b/drivers/virtio-vring.cc
> index 3f0e7e25..e619ef06 100644
> --- a/drivers/virtio-vring.cc
> +++ b/drivers/virtio-vring.cc
> @@ -87,6 +87,21 @@ namespace virtio {
>          return mmu::virt_to_phys(_vring_ptr);
>      }
>
> +    u64 vring::get_desc_addr()
> +    {
> +        return mmu::virt_to_phys(_desc);
> +    }
> +
> +    u64 vring::get_avail_addr()
> +    {
> +        return mmu::virt_to_phys(_avail);
> +    }
> +
> +    u64 vring::get_used_addr()
> +    {
> +        return mmu::virt_to_phys(_used);
> +    }
> +
>      unsigned vring::get_size(unsigned int num, unsigned long align)
>      {
>          return (((sizeof(vring_desc) * num + sizeof(u16) * (3 + num)
> diff --git a/drivers/virtio-vring.hh b/drivers/virtio-vring.hh
> index 74c4d8a1..59ad88c6 100644
> --- a/drivers/virtio-vring.hh
> +++ b/drivers/virtio-vring.hh
> @@ -128,6 +128,10 @@ class virtio_driver;
>          u64 get_paddr();
>          static unsigned get_size(unsigned int num, unsigned long align);
>
> +        u64 get_desc_addr();
> +        u64 get_avail_addr();
> +        u64 get_used_addr();
> +
>          // Ring operations
>          bool add_buf(void* cookie);
>          // Get the top item from the used ring
> diff --git a/drivers/virtio.cc b/drivers/virtio.cc
> index ef929820..5ef0f94d 100644
> --- a/drivers/virtio.cc
> +++ b/drivers/virtio.cc
> @@ -66,6 +66,10 @@ void virtio_driver::setup_features()
>              set_event_idx_cap(true);
>
>      set_guest_features(subset);
> +
> +    // Step 5 - confirm features (only applies to modern devices)
> +    if (_dev.is_modern())
> +        add_dev_status(VIRTIO_CONFIG_S_FEATURES_OK);
>  }
>
>  void virtio_driver::dump_config()
> @@ -127,6 +131,9 @@ void virtio_driver::probe_virt_queues()
>          virtio_d("Queue[%d] -> size %d, paddr %x", (_num_queues-1),
> qsize, queue->get_paddr());
>
>      } while (true);
> +
> +    for (u32 _q = 0; _q < _num_queues; _q++)
> +        _dev.activate_queue(_q);
>  }
>
>  vring* virtio_driver::get_virt_queue(unsigned idx)
> diff --git a/drivers/virtio.hh b/drivers/virtio.hh
> index 4718f286..ef915e1c 100644
> --- a/drivers/virtio.hh
> +++ b/drivers/virtio.hh
> @@ -23,6 +23,9 @@ enum VIRTIO_CONFIG {
>      VIRTIO_CONFIG_S_DRIVER = 2,
>      /* Driver has used its parts of the config, and is happy */
>      VIRTIO_CONFIG_S_DRIVER_OK = 4,
> +    /* Indicates that the driver has acknowledged all the features it
> understands,
> +     * and feature negotiation is complete */
> +    VIRTIO_CONFIG_S_FEATURES_OK = 8,
>      /* We've given up on this device. */
>      VIRTIO_CONFIG_S_FAILED = 0x80,
>      /* Some virtio feature bits (currently bits 28 through 31) are
> reserved for the
> --
> 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 osv-dev+unsubscr...@googlegroups.com.
> 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 osv-dev+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Reply via email to