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.
