diff --git a/repos/os/include/virtio/mmio_device.h b/repos/os/include/virtio/mmio_device.h new file mode 100644 index 0000000000..2217dd4bb6 --- /dev/null +++ b/repos/os/include/virtio/mmio_device.h @@ -0,0 +1,201 @@ +/* + * \brief VirtIO MMIO device + * \author Piotr Tworek + * \date 2019-09-27 + */ + +/* + * Copyright (C) 2020 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU Affero General Public License version 3. + */ + +#ifndef _INCLUDE__VIRTIO__MMIO_DEVICE_H_ +#define _INCLUDE__VIRTIO__MMIO_DEVICE_H_ + +#include +#include +#include +#include + + +namespace Virtio { + using namespace Genode; + class Device; +} + + +class Virtio::Device : Genode::Attached_dataspace, Genode::Mmio +{ + public: + + struct Invalid_device : Genode::Exception { }; + + enum Status : uint8_t + { + RESET = 0, + ACKNOWLEDGE = 1 << 0, + DRIVER = 1 << 1, + DRIVER_OK = 1 << 2, + FEATURES_OK = 1 << 3, + FAILED = 1 << 7, + }; + + enum Access_size : uint8_t + { + ACCESS_8BIT, + ACCESS_16BIT, + ACCESS_32BIT, + }; + + private: + + enum { VIRTIO_MMIO_MAGIC = 0x74726976 }; + + /** + * Some of the registers are actually 8 bits wide, but according to + * section 4.2.2.2 of VIRTIO 1.0 spec "The driver MUST use only 32 bit + * wide and aligned reads and writes". + */ + struct Magic : Register<0x000, 32> { }; + struct Version : Register<0x004, 32> { }; + struct DeviceID : Register<0x008, 32> { }; + struct VendorID : Register<0x00C, 32> { }; + struct DeviceFeatures : Register<0x010, 32> { }; + struct DeviceFeaturesSel : Register<0x014, 32> { }; + struct DriverFeatures : Register<0x020, 32> { }; + struct DriverFeaturesSel : Register<0x024, 32> { }; + struct QueueSel : Register<0x030, 32> { }; + struct QueueNumMax : Register<0x034, 32> { }; + struct QueueNum : Register<0x038, 32> { }; + struct QueueReady : Register<0x044, 32> { }; + struct QueueNotify : Register<0x050, 32> { }; + struct InterruptStatus : Register<0x060, 32> { }; + struct InterruptAck : Register<0x064, 32> { }; + struct StatusReg : Register<0x070, 32> { }; + struct QueueDescLow : Register<0x080, 32> { }; + struct QueueDescHigh : Register<0x084, 32> { }; + struct QueueAvailLow : Register<0x090, 32> { }; + struct QueueAvailHigh : Register<0x094, 32> { }; + struct QueueUsedLow : Register<0x0A0, 32> { }; + struct QueueUsedHigh : Register<0x0A4, 32> { }; + struct ConfigGeneration : Register<0x0FC, 32> { }; + + /** + * Different views on device configuration space. According to the + * VIRTIO 1.0 spec 64 bit wide registers are supposed to be read as + * two 32 bit values. + */ + struct Config_8 : Register_array<0x100, 8, 256, 8> { }; + struct Config_16 : Register_array<0x100, 16, 128, 16> { }; + struct Config_32 : Register_array<0x100, 32, 64, 32> { }; + + /* + * Noncopyable + */ + Device(Device const &) = delete; + Device &operator = (Device const &) = delete; + + public: + + Device(Genode::Env &env, + Genode::Io_mem_dataspace_capability io_mem_ds, + size_t offset) + : Attached_dataspace(env.rm(), io_mem_ds) + , Mmio((addr_t)local_addr() + offset) + { + if (read() != VIRTIO_MMIO_MAGIC) { + throw Invalid_device(); } + } + + uint32_t vendor_id() { return read(); } + uint32_t device_id() { return read(); } + uint8_t get_status() { return read() & 0xff; } + + bool set_status(uint8_t status) + { + write(status); + return read() == status; + } + + uint32_t get_features(uint32_t selection) + { + write(selection); + return read(); + } + + void set_features(uint32_t selection, uint32_t features) + { + write(selection); + write(features); + } + + uint8_t get_config_generation() { + return read() & 0xff; } + + uint16_t get_max_queue_size(uint16_t queue_index) + { + write(queue_index); + if (read() != 0) { + return 0; } + return read(); + } + + uint32_t read_config(uint8_t offset, Access_size size) + { + switch (size) { + case ACCESS_8BIT: return read(offset); + case ACCESS_16BIT: return read(offset >> 1); + case ACCESS_32BIT: return read(offset >> 2); + } + return 0; + } + + void write_config(uint8_t offset, Access_size size, uint32_t value) + { + switch (size) { + case ACCESS_8BIT: write(value, offset); break; + case ACCESS_16BIT: write(value, (offset >> 1)); break; + case ACCESS_32BIT: write(value, (offset >> 2)); break; + } + } + + bool configure_queue(uint16_t queue_index, + Virtio::Queue_description desc) + { + write(queue_index); + + if (read() != 0) + return false; + + write(desc.size); + + uint64_t addr = desc.desc; + write((uint32_t)addr); + write((uint32_t)(addr >> 32)); + + addr = desc.avail; + write((uint32_t)addr); + write((uint32_t)(addr >> 32)); + + addr = desc.used; + write((uint32_t)addr); + write((uint32_t)(addr >> 32)); + + write(1); + return read() != 0; + } + + void notify_buffers_available(uint16_t queue_index) { + write(queue_index); } + + uint32_t read_isr() + { + uint32_t isr = read(); + write(isr); + return isr; + } +}; + +#endif /* _INCLUDE__VIRTIO__MMIO_DEVICE_H_ */ diff --git a/repos/os/include/virtio/pci_device.h b/repos/os/include/virtio/pci_device.h new file mode 100644 index 0000000000..4c53d6b43c --- /dev/null +++ b/repos/os/include/virtio/pci_device.h @@ -0,0 +1,282 @@ +/* + * \brief VirtIO PCI device + * \author Piotr Tworek + * \date 2019-09-27 + */ + +/* + * Copyright (C) 2020 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU Affero General Public License version 3. + */ + +#ifndef _INCLUDE__VIRTIO__PCI_DEVICE_H_ +#define _INCLUDE__VIRTIO__PCI_DEVICE_H_ + +#include +#include +#include + +namespace Virtio { + using namespace Genode; + struct Device_mmio; + class Device; +} + +struct Virtio::Device_mmio : public Attached_mmio +{ + struct DeviceFeatureSelect : Register<0x00, 32> { }; + struct DeviceFeature : Register<0x04, 32> { }; + struct DriverFeatureSelect : Register<0x08, 32> { }; + struct DriverFeature : Register<0x0C, 32> { }; + struct MsiXConfig : Register<0x10, 16> { }; + struct NumQueues : Register<0x12, 16> { }; + struct DeviceStatus : Register<0x14, 8> { }; + struct ConfigGeneration : Register<0x15, 8> { }; + struct QueueSelect : Register<0x16, 16> { }; + struct QueueSize : Register<0x18, 16> { }; + struct QueueMsixVector : Register<0x1A, 16> { }; + struct QueueEnable : Register<0x1C, 16> { }; + struct QueueNotifyOff : Register<0x1E, 16> { }; + struct QueueDescLow : Register<0x20, 32> { }; + struct QueueDescHigh : Register<0x24, 32> { }; + struct QueueAvailLow : Register<0x28, 32> { }; + struct QueueAvailHigh : Register<0x2C, 32> { }; + struct QueueUsedLow : Register<0x30, 32> { }; + struct QueueUsedHigh : Register<0x34, 32> { }; + + struct Config_8 : Register_array<0x0, 8, 256, 8> { }; + struct Config_16 : Register_array<0x0, 16, 128, 16> { }; + struct Config_32 : Register_array<0x0, 32, 64, 32> { }; + + struct IrqReason : Register<0x0, 32> { }; + + Device_mmio(Genode::Env &env, + Genode::addr_t base, + Genode::size_t size) + : Attached_mmio(env, base, size, false) { } +}; + +class Virtio::Device +{ + public: + + struct Configuration_failed : Genode::Exception { }; + + enum Status : uint8_t + { + RESET = 0, + ACKNOWLEDGE = 1 << 0, + DRIVER = 1 << 1, + DRIVER_OK = 1 << 2, + FEATURES_OK = 1 << 3, + FAILED = 1 << 7, + }; + + enum Access_size : uint8_t + { + ACCESS_8BIT, + ACCESS_16BIT, + ACCESS_32BIT, + }; + + private: + + /* + * Noncopyable + */ + Device(Device const &) = delete; + Device &operator = (Device const &) = delete; + + enum { + VIRTIO_PCI_BASE_ID = 0x1040, + VIRTIO_MSI_NO_VECTOR = 0xffff + }; + + Genode::Env &_env; + Platform::Device_client &_device; + uint32_t _notify_offset_multiplier = 0; + Genode::Constructible _cfg_common { }; + Genode::Constructible _dev_config { }; + Genode::Constructible _notify { }; + Genode::Constructible _isr { }; + + + void _configure() + { + typedef Platform::Device Pdev; + + enum { PCI_STATUS = 0x6, PCI_CAPABILITIES = 0x34, }; + + auto status = _device.config_read(PCI_STATUS, Pdev::ACCESS_16BIT); + if (!(status & 0x10)) { + error("PCI capabilities missing according to device status!"); + throw Configuration_failed(); + } + + auto addr = _device.config_read(PCI_CAPABILITIES, Pdev::ACCESS_8BIT); + addr &= 0xFC; + + while (addr) { + enum { ID_VNDR = 0x09 }; + enum { CAP_ID = 0, CAP_LIST_NEXT = 1 }; + + auto const cap_id = _device.config_read(addr + CAP_ID, Pdev::ACCESS_8BIT); + auto const cap_next = _device.config_read(addr + CAP_LIST_NEXT, Pdev::ACCESS_8BIT); + + if (cap_id == ID_VNDR) { + enum { CFG_TYPE = 0x3, BAR = 0x4, OFFSET = 0x8, + LENGTH = 0xC, NOTIFY_OFFSET_MULT = 0x10 }; + enum { COMMON_CFG = 1, NOTIFY_CFG = 2, ISR_CFG = 3, + DEVICE_CFG = 4, PCI_CFG = 5 }; + + auto const cfg_type = _device.config_read(addr + CFG_TYPE, Pdev::ACCESS_8BIT); + auto const bar = _device.config_read(addr + BAR, Pdev::ACCESS_8BIT); + auto const off = _device.config_read(addr + OFFSET, Pdev::ACCESS_32BIT); + auto const len = _device.config_read(addr + LENGTH, Pdev::ACCESS_32BIT); + + if (cfg_type == COMMON_CFG) { + auto const r = _device.resource(bar); + _cfg_common.construct(_env, r.base() + off, len); + } else if (cfg_type == DEVICE_CFG) { + auto const r = _device.resource(bar); + _dev_config.construct(_env, r.base() + off, len); + } else if (cfg_type == NOTIFY_CFG) { + _notify_offset_multiplier = _device.config_read( + addr + NOTIFY_OFFSET_MULT, Pdev::ACCESS_32BIT); + auto const r = _device.resource(bar); + _notify.construct(_env, r.base() + off, len); + } else if (cfg_type == ISR_CFG) { + auto const r = _device.resource(bar); + _isr.construct(_env, r.base() + off, len); + } + } + + addr = cap_next; + } + + if (!_cfg_common.constructed() || !_dev_config.constructed() || + !_notify.constructed() || !_isr.constructed()) { + error("Required VirtIO PCI capabilities not found!"); + throw Configuration_failed(); + } + + _cfg_common->write(VIRTIO_MSI_NO_VECTOR); + } + + public: + + Device(Genode::Env &env, + Platform::Device_client device) + : _env(env), _device(device) + { + _configure(); + } + + uint32_t vendor_id() { return _device.vendor_id(); } + uint32_t device_id() { + return _device.device_id() - VIRTIO_PCI_BASE_ID; } + + uint8_t get_status() { + return _cfg_common->read(); } + + bool set_status(uint8_t status) + { + _cfg_common->write(status); + return _cfg_common->read() == status; + } + + uint32_t get_features(uint32_t selection) + { + _cfg_common->write(selection); + return _cfg_common->read(); + } + + void set_features(uint32_t selection, uint32_t features) + { + _cfg_common->write(selection); + _cfg_common->write(features); + } + + uint8_t get_config_generation() { + return _cfg_common->read(); } + + uint16_t get_max_queue_size(uint16_t queue_index) + { + _cfg_common->write(queue_index); + return _cfg_common->read(); + } + + uint32_t read_config(uint8_t offset, Access_size size) + { + switch (size) { + case Device::ACCESS_8BIT: + return _dev_config->read(offset); + case Device::ACCESS_16BIT: + return _dev_config->read(offset >> 1); + case Device::ACCESS_32BIT: + return _dev_config->read(offset >> 2); + } + return 0; + } + + void write_config(uint8_t offset, Access_size size, uint32_t value) + { + switch (size) { + case Device::ACCESS_8BIT: + _dev_config->write(value, offset); + break; + case Device::ACCESS_16BIT: + _dev_config->write(value, offset >> 1); + break; + case Device::ACCESS_32BIT: + _dev_config->write(value, offset >> 2); + break; + } + } + + bool configure_queue(uint16_t queue_index, Virtio::Queue_description desc) + { + _cfg_common->write(queue_index); + + if (_cfg_common->read()) { + warning("VirtIO queues can't be re-configured after being enabled!"); + return false; + } + + _cfg_common->write(VIRTIO_MSI_NO_VECTOR); + if (_cfg_common->read() != VIRTIO_MSI_NO_VECTOR) { + error("Failed to disable MSI-X for queue ", queue_index); + return false; + } + + _cfg_common->write(desc.size); + + uint64_t addr = desc.desc; + _cfg_common->write((uint32_t)addr); + _cfg_common->write((uint32_t)(addr >> 32)); + + addr = desc.avail; + _cfg_common->write((uint32_t)addr); + _cfg_common->write((uint32_t)(addr >> 32)); + + addr = desc.used; + _cfg_common->write((uint32_t)addr); + _cfg_common->write((uint32_t)(addr >> 32)); + _cfg_common->write(1); + return _cfg_common->read() != 0; + } + + void notify_buffers_available(uint16_t queue_index) { + _cfg_common->write(queue_index); + auto const offset = _cfg_common->read(); + auto const addr = (offset * _notify_offset_multiplier >> 1) + 1; + _notify->local_addr()[addr] = queue_index; + } + + uint32_t read_isr() { + return _isr->read(); } +}; + +#endif /* _INCLUDE__VIRTIO__PCI_DEVICE_H_ */ diff --git a/repos/os/include/virtio/queue.h b/repos/os/include/virtio/queue.h new file mode 100644 index 0000000000..397996884e --- /dev/null +++ b/repos/os/include/virtio/queue.h @@ -0,0 +1,382 @@ +/* + * \brief VirtIO queue implementation + * \author Piotr Tworek + * \date 2019-09-27 + */ + +/* + * Copyright (C) 2019 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU Affero General Public License version 3. + */ + +#ifndef _INCLUDE__VIRTIO__QUEUE_H_ +#define _INCLUDE__VIRTIO__QUEUE_H_ + +#include +#include +#include +#include + +namespace Virtio +{ + template class Queue; + struct Queue_default_traits; + struct Queue_description; +} + + +struct Virtio::Queue_description +{ + /** + * Physical address of the descriptor table. + */ + Genode::addr_t desc; + + /** + * Physical address of the available descriptor ring. + */ + Genode::addr_t avail; + + /** + * Physcical address of the used descriptor ring. + */ + Genode::addr_t used; + + /** + * The size of the descriptor table (number of elements). + */ + Genode::uint16_t size; +}; + + +struct Queue_default_traits +{ + /** + * The queue is only supposed to be written to by the device. + */ + static const bool device_write_only = false; + + /** + * Each queue event has additional data payload associated with it. + */ + static const bool has_data_payload = false; +}; + + +/** + * This class implements VirtIO queue interface as defined in section 2.4 of VirtIO 1.0 specification. + */ +template +class Virtio::Queue +{ + private: + + /* + * Noncopyable + */ + Queue(Queue const &); + Queue &operator = (Queue const &); + + protected: + + typedef HEADER_TYPE Header_type; + + struct Descriptor + { + enum Flags : Genode::uint16_t + { + NEXT = 1, + WRITE = 2, + }; + + Genode::uint64_t addr; + Genode::uint32_t len; + Genode::uint16_t flags; + Genode::uint16_t next; + } __attribute__((packed)); + + struct Avail + { + enum Flags : Genode::uint16_t { NO_INTERRUPT = 1 }; + Genode::uint16_t flags; + Genode::uint16_t idx; + Genode::uint16_t ring[]; + /* Genode::uint16_t used_event; */ + } __attribute__((packed)); + + struct Used + { + Genode::uint16_t flags; + Genode::uint16_t idx; + struct { + Genode::uint32_t id; + Genode::uint32_t len; + } ring[]; + /* Genode::uint16_t avail_event; */ + } __attribute__((packed)); + + Genode::uint16_t const _queue_size; + Genode::uint16_t const _buffer_size; + Genode::Attached_ram_dataspace _ram_ds; + Descriptor *_desc_table = nullptr; + Avail *_avail = nullptr; + Used *_used = nullptr; + Genode::addr_t _buffer_phys_base = 0; + Genode::addr_t _buffer_local_base = 0; + Genode::uint16_t _last_used_idx = 0; + Queue_description _description { 0, 0, 0, 0 }; + + + /* As defined in section 2.4 of VIRTIO 1.0 specification. */ + static Genode::size_t _desc_size(Genode::uint16_t queue_size) { + return 16 * queue_size; } + static Genode::size_t _avail_size(Genode::uint16_t queue_size) { + return 6 + 2 * queue_size; } + static Genode::size_t _used_size(Genode::uint16_t queue_size) { + return 6 + 8 * queue_size; } + + Genode::uint16_t _check_buffer_size(Genode::uint16_t buffer_size) + { + /** + * Each buffer in the queue should be big enough to hold + * at least VirtIO header. + */ + if (buffer_size < sizeof(Header_type)) + throw Invalid_buffer_size(); + return buffer_size; + } + + static Genode::size_t _ds_size(Genode::uint16_t queue_size, + Genode::uint16_t buffer_size) + { + Genode::size_t size = _desc_size(queue_size) + _avail_size(queue_size); + size = Genode::align_natural(size); + /* See section 2.4 of VirtIO 1.0 specification */ + size += _used_size(queue_size); + size = Genode::align_natural(size); + return size + (queue_size * Genode::align_natural(buffer_size)); + } + + void _init_tables() + { + using namespace Genode; + + Dataspace_client ram_ds_client(_ram_ds.cap()); + + uint8_t const *base_phys = (uint8_t *)ram_ds_client.phys_addr(); + uint8_t const *base_local = _ram_ds.local_addr(); + + size_t const avail_offset = _desc_size(_queue_size); + size_t const used_offset = align_natural(avail_offset + _avail_size(_queue_size)); + size_t const buff_offset = align_natural(used_offset + _used_size(_queue_size)); + + _desc_table = (Descriptor *)base_local; + _avail = (Avail *)(base_local + avail_offset); + _used = (Used *)(base_local + used_offset); + _buffer_local_base = (addr_t)(base_local + buff_offset); + _buffer_phys_base = (addr_t)(base_phys + buff_offset); + + _description.desc = (addr_t)base_phys; + _description.avail = (addr_t)(base_phys + avail_offset); + _description.used = (addr_t)(base_phys + used_offset); + _description.size = _queue_size; + } + + void _fill_descriptor_table() + { + const Genode::uint16_t flags = + TRAITS::device_write_only ? Descriptor::Flags::WRITE : 0; + + for (Genode::uint16_t idx = 0; idx < _queue_size; idx++) { + _desc_table[idx] = Descriptor { + _buffer_phys_base + idx * Genode::align_natural(_buffer_size), + _buffer_size, flags, 0 }; + _avail->ring[idx] = idx; + } + + /* Expose all available buffers to the device. */ + if (TRAITS::device_write_only) { + _avail->flags = 0; + _avail->idx = _queue_size; + } + } + + Genode::uint16_t _avail_capacity() const + { + auto const used_idx = _used->idx; + auto const avail_idx = _avail->idx; + if (avail_idx >= used_idx) { + return _queue_size - avail_idx + used_idx; + } else { + return used_idx - avail_idx; + } + } + + void *_buffer_local_addr(Descriptor const *d) { + return (void *)(_buffer_local_base + (d->addr - _buffer_phys_base)); } + + public: + + struct Invalid_buffer_size : Genode::Exception { }; + + Queue_description const description() const { return _description; } + + bool has_used_buffers() const { return _last_used_idx != _used->idx; } + + void ack_all_transfers() { _last_used_idx = _used->idx;} + + Genode::size_t size() const { return _ds_size(_queue_size, _buffer_size); } + + bool write_data(Header_type const &header, + char const *data, + Genode::size_t data_size, + bool request_irq = true) + { + static_assert(!TRAITS::device_write_only); + static_assert(TRAITS::has_data_payload); + + const int req_desc_count = 1 + (sizeof(header) + data_size) / _buffer_size; + + if (req_desc_count > _avail_capacity()) + return false; + + Genode::uint16_t avail_idx = _avail->idx; + auto *desc = &_desc_table[avail_idx % _queue_size]; + + Genode::memcpy(_buffer_local_addr(desc), (void *)&header, sizeof(header)); + desc->len = sizeof(header); + + Genode::size_t len = Genode::min(_buffer_size - sizeof(header), data_size); + Genode::memcpy((char *)_buffer_local_addr(desc) + desc->len, data, len); + desc->len += len; + + len = data_size + sizeof(header) - desc->len; + + avail_idx++; + + if (len == 0) { + desc->flags = 0; + desc->next = 0; + _avail->flags = request_irq ? 0 : Avail::Flags::NO_INTERRUPT; + _avail->idx = avail_idx; + return true; + } + + desc->flags = Descriptor::Flags::NEXT; + desc->next = avail_idx % _queue_size; + + Genode::size_t data_offset = desc->len; + do { + desc = &_desc_table[avail_idx % _queue_size]; + avail_idx++; + + Genode::size_t write_len = Genode::min(_buffer_size, len); + Genode::memcpy((char *)_buffer_local_addr(desc), data + data_offset, write_len); + + desc->len = write_len; + desc->flags = len > 0 ? Descriptor::Flags::NEXT : 0; + desc->next = len > 0 ? (avail_idx % _queue_size) : 0; + + len -= write_len; + data_offset += desc->len; + } while (len > 0); + + _avail->flags = request_irq ? 0 : Avail::Flags::NO_INTERRUPT; + _avail->idx = avail_idx; + + return true; + } + + bool write_data(Header_type const &header, bool request_irq = true) + { + static_assert(!TRAITS::device_write_only); + static_assert(!TRAITS::has_data_payload); + + if (_avail_capacity() == 0) + return false; + + Genode::uint16_t avail_idx = _avail->idx; + auto *desc = &_desc_table[avail_idx % _queue_size]; + + Genode::memcpy(_buffer_local_addr(desc), (void *)&header, sizeof(header)); + desc->len = sizeof(header); + desc->flags = 0; + desc->next = 0; + _avail->flags = request_irq ? 0 : Avail::Flags::NO_INTERRUPT; + _avail->idx = ++avail_idx; + + return true; + } + + template + void read_data(FN const &fn) + { + static_assert(TRAITS::has_data_payload); + + if (!has_used_buffers()) + return; + + Genode::uint16_t const idx = _last_used_idx % _queue_size; + Genode::uint32_t const len = _used->ring[idx].len; + + auto const *desc = &_desc_table[idx]; + char const *desc_data = (char *)_buffer_local_addr(desc); + Header_type const &header = *((Header_type *)(desc_data)); + char const *data = desc_data + sizeof(Header_type); + Genode::size_t const data_size = len - sizeof(Header_type); + + if (fn(header, data, data_size)) { + _last_used_idx++; + _avail->idx = _avail->idx + 1; + } + } + + Header_type read_data() + { + static_assert(!TRAITS::has_data_payload); + + if (!has_used_buffers()) + return Header_type(); + + Genode::uint16_t const idx = _last_used_idx % _queue_size; + + auto const *desc = &_desc_table[idx]; + char const *desc_data = (char *)_buffer_local_addr(desc); + Header_type const &header = *((Header_type *)(desc_data)); + + _last_used_idx++; + _avail->idx = _avail->idx + 1; + + return header; + } + + void print(Genode::Output& output) const + { + Genode::print(output, "avail idx: "); + Genode::print(output, _avail->idx); + Genode::print(output, ", used idx = "); + Genode::print(output, _used->idx); + Genode::print(output, ", last seen used idx = "); + Genode::print(output, _last_used_idx); + Genode::print(output, ", capacity = "); + Genode::print(output, _avail_capacity()); + Genode::print(output, ", size = "); + Genode::print(output, _queue_size); + } + + Queue(Genode::Ram_allocator &ram, + Genode::Region_map &rm, + Genode::uint16_t queue_size, + Genode::uint16_t buffer_size) + : _queue_size(queue_size), + _buffer_size(_check_buffer_size(buffer_size)), + _ram_ds(ram, rm, _ds_size(queue_size, buffer_size), Genode::UNCACHED) + { + _init_tables(); + _fill_descriptor_table(); + } +}; + +#endif /* _INCLUDE__VIRTIO__QUEUE_H_ */ diff --git a/repos/os/recipes/api/virtio/content.mk b/repos/os/recipes/api/virtio/content.mk new file mode 100644 index 0000000000..cad815aa0e --- /dev/null +++ b/repos/os/recipes/api/virtio/content.mk @@ -0,0 +1,3 @@ +MIRRORED_FROM_REP_DIR := include/virtio + +include $(REP_DIR)/recipes/api/session.inc diff --git a/repos/os/recipes/api/virtio/hash b/repos/os/recipes/api/virtio/hash new file mode 100644 index 0000000000..5d4f4b38fa --- /dev/null +++ b/repos/os/recipes/api/virtio/hash @@ -0,0 +1 @@ +2020-07-03 60db929b95df6142a34d6579a61c72592f7bdbcc