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
[email protected]


On Wed, Feb 6, 2019 at 3:29 PM Waldemar Kozaczuk <[email protected]>
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 <[email protected]>
> ---
>  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 [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.

Reply via email to