Thanks for reviewing and applying couple of these pretty long patches. I am 
tiny surprised how painless it has been. I must have gotten better with my 
coding skills. In any case I am not complaining ;-)

I will actually send a small patch to enable passing extra arguments to 
run.py from test.py so we can actually run all unit tests with "--virtio 
modern". I tried this by manually changing test.py and all the tests passed.

On Wednesday, February 6, 2019 at 4:46:34 PM UTC-5, Nadav Har'El wrote:
>
> 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] <javascript:>
>
>
> On Wed, Feb 6, 2019 at 3:29 PM Waldemar Kozaczuk <[email protected] 
> <javascript:>> 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] <javascript:>>
>> ---
>>  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] <javascript:>.
>> 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