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.
