Also for whatever reason these patches did not trigger osv-build run. The 
nightly one just completed successfully. Is something wrong with the commit 
hook?

On Wednesday, February 6, 2019 at 4:55:51 PM UTC-5, Waldek Kozaczuk wrote:
>
> 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]
>>
>>
>> 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