Hmm, I think I have accidentally committed an older version of this
patch... Can you please check and incrementally commit the differences
between the versions? Sorry about that.

--
Nadav Har'El
[email protected]


On Mon, Mar 4, 2019 at 12:15 AM Waldemar Kozaczuk <[email protected]>
wrote:

> Adds implementation of virtio mmio devices
> needed to support block and networking devices
> on firecracker.
>
> Signed-off-by: Waldemar Kozaczuk <[email protected]>
> ---
>  Makefile               |   1 +
>  arch/x64/arch-setup.cc |   5 +
>  drivers/virtio-mmio.cc | 216 +++++++++++++++++++++++++++++++++++++++++
>  drivers/virtio-mmio.hh | 154 +++++++++++++++++++++++++++++
>  4 files changed, 376 insertions(+)
>  create mode 100644 drivers/virtio-mmio.cc
>  create mode 100644 drivers/virtio-mmio.hh
>
> diff --git a/Makefile b/Makefile
> index 377e93e9..3f560807 100644
> --- a/Makefile
> +++ b/Makefile
> @@ -821,6 +821,7 @@ drivers += arch/$(arch)/pvclock-abi.o
>  drivers += drivers/virtio.o
>  drivers += drivers/virtio-pci-device.o
>  drivers += drivers/virtio-vring.o
> +drivers += drivers/virtio-mmio.o
>  drivers += drivers/virtio-net.o
>  drivers += drivers/vmxnet3.o
>  drivers += drivers/vmxnet3-queues.o
> diff --git a/arch/x64/arch-setup.cc b/arch/x64/arch-setup.cc
> index 7350714c..9317dd25 100644
> --- a/arch/x64/arch-setup.cc
> +++ b/arch/x64/arch-setup.cc
> @@ -24,9 +24,11 @@
>
>  osv_multiboot_info_type* osv_multiboot_info;
>
> +#include "drivers/virtio-mmio.hh"
>  void parse_cmdline(multiboot_info_type& mb)
>  {
>      auto p = reinterpret_cast<char*>(mb.cmdline);
> +    virtio::parse_mmio_device_configuration(p);
>      osv::parse_cmdline(p);
>  }
>
> @@ -246,6 +248,9 @@ void arch_init_drivers()
>          boot_time.event("pci enumerated");
>      }
>
> +    // Register any parsed virtio-mmio devices
> +    virtio::register_mmio_devices(device_manager::instance());
> +
>      // Initialize all drivers
>      hw::driver_manager* drvman = hw::driver_manager::instance();
>      drvman->register_driver(virtio::blk::probe);
> diff --git a/drivers/virtio-mmio.cc b/drivers/virtio-mmio.cc
> new file mode 100644
> index 00000000..12bf3413
> --- /dev/null
> +++ b/drivers/virtio-mmio.cc
> @@ -0,0 +1,216 @@
> +/*
> + * Copyright (C) 2019 Waldemar Kozaczuk
> + *
> + * This work is open source software, licensed under the terms of the
> + * BSD license as described in the LICENSE file in the top-level
> directory.
> + */
> +
> +#include <vector>
> +#include <osv/debug.hh>
> +#include "virtio-mmio.hh"
> +
> +namespace virtio {
> +
> +// This implements virtio-io mmio device (transport layer, modeled after
> PSI).
> +// Read here -
> https://www.kraxel.org/virtio/virtio-v1.0-cs03-virtio-gpu.html#x1-1080002
> +hw_device_id mmio_device::get_id()
> +{
> +    return hw_device_id(0x1af4, _device_id);
> +}
> +
> +u8 mmio_device::get_status()
> +{
> +    return mmio_getl(_addr_mmio + VIRTIO_MMIO_STATUS) & 0xff;
> +}
> +
> +void mmio_device::set_status(u8 status)
> +{
> +    mmio_setl(_addr_mmio + VIRTIO_MMIO_STATUS, status);
> +}
> +
> +u64 mmio_device::get_available_features()
> +{
> +    u64 features;
> +
> +    mmio_setl(_addr_mmio + VIRTIO_MMIO_DEVICE_FEATURES_SEL, 1);
> +    features = mmio_getl(_addr_mmio + VIRTIO_MMIO_DEVICE_FEATURES);
> +    features <<= 32;
> +
> +    mmio_setl(_addr_mmio + VIRTIO_MMIO_DEVICE_FEATURES_SEL, 0);
> +    features |= mmio_getl(_addr_mmio + VIRTIO_MMIO_DEVICE_FEATURES);
> +
> +    return features;
> +}
> +
> +void mmio_device::set_enabled_features(u64 features)
> +{
> +    mmio_setl(_addr_mmio + VIRTIO_MMIO_DRIVER_FEATURES_SEL, 1);
> +    mmio_setl(_addr_mmio + VIRTIO_MMIO_DRIVER_FEATURES, (u32)(features >>
> 32));
> +
> +    mmio_setl(_addr_mmio + VIRTIO_MMIO_DRIVER_FEATURES_SEL, 0);
> +    mmio_setl(_addr_mmio + VIRTIO_MMIO_DRIVER_FEATURES, (u32)features);
> +}
> +
> +void mmio_device::kick_queue(int queue_num)
> +{
> +    mmio_setl(_addr_mmio + VIRTIO_MMIO_QUEUE_NOTIFY, queue_num);
> +}
> +
> +void mmio_device::select_queue(int queue_num)
> +{
> +    mmio_setl(_addr_mmio + VIRTIO_MMIO_QUEUE_SEL, queue_num);
> +    assert(!mmio_getl(_addr_mmio + VIRTIO_MMIO_QUEUE_READY));
> +}
> +
> +u16 mmio_device::get_queue_size()
> +{
> +    return mmio_getl(_addr_mmio + VIRTIO_MMIO_QUEUE_NUM_MAX) & 0xffff;
> +}
> +
> +void mmio_device::setup_queue(vring* queue)
> +{
> +    // Set size
> +    mmio_setl(_addr_mmio + VIRTIO_MMIO_QUEUE_NUM, queue->size());
> +    //
> +    // Pass addresses
> +    mmio_setl(_addr_mmio + VIRTIO_MMIO_QUEUE_DESC_LOW,
> (u32)queue->get_desc_addr());
> +    mmio_setl(_addr_mmio + VIRTIO_MMIO_QUEUE_DESC_HIGH,
> (u32)(queue->get_desc_addr() >> 32));
> +
> +    mmio_setl(_addr_mmio + VIRTIO_MMIO_QUEUE_AVAIL_LOW,
> (u32)queue->get_avail_addr());
> +    mmio_setl(_addr_mmio + VIRTIO_MMIO_QUEUE_AVAIL_HIGH,
> (u32)(queue->get_avail_addr() >> 32));
> +
> +    mmio_setl(_addr_mmio + VIRTIO_MMIO_QUEUE_USED_LOW,
> (u32)queue->get_used_addr());
> +    mmio_setl(_addr_mmio + VIRTIO_MMIO_QUEUE_USED_HIGH,
> (u32)(queue->get_used_addr() >> 32));
> +}
> +
> +void mmio_device::activate_queue(int queue)
> +{   //
> +    // Make it ready
> +    select_queue(queue);
> +    mmio_setl(_addr_mmio + VIRTIO_MMIO_QUEUE_READY, 1 );
> +}
> +
> +u8 mmio_device::read_and_ack_isr()
> +{
> +    unsigned long status = mmio_getl(_addr_mmio +
> VIRTIO_MMIO_INTERRUPT_STATUS);
> +    mmio_setl(_addr_mmio + VIRTIO_MMIO_INTERRUPT_ACK, status);
> +    return (status & VIRTIO_MMIO_INT_VRING);
> +}
> +
> +u8 mmio_device::read_config(u32 offset)
> +{
> +    return mmio_getb(_addr_mmio + VIRTIO_MMIO_CONFIG + offset);
> +}
> +
> +void mmio_device::register_interrupt(interrupt_factory irq_factory)
> +{
> +    _irq.reset(irq_factory.create_gsi_edge_interrupt());
> +}
> +
> +bool mmio_device::parse_config()
> +{
> +    _addr_mmio = mmio_map(_dev_info._address, _dev_info._size);
> +
> +    u32 magic = mmio_getl(_addr_mmio + VIRTIO_MMIO_MAGIC_VALUE);
> +    if (magic != ('v' | 'i' << 8 | 'r' << 16 | 't' << 24)) {
> +        return false;
> +    }
> +
> +    // Check device version
> +    u32 version = mmio_getl(_addr_mmio + VIRTIO_MMIO_VERSION);
> +    if (version < 1 || version > 2) {
> +        debugf( "Version %ld not supported!\n", version);
> +        return false;
> +    }
> +
> +    _device_id = mmio_getl(_addr_mmio + VIRTIO_MMIO_DEVICE_ID);
> +    if (_device_id == 0) {
> +        //
> +        // virtio-mmio device with an ID 0 is a (dummy) placeholder
> +        // with no function. End probing now with no error reported.
> +        debug( "Dummy virtio-mmio device detected!\n");
> +        return false;
> +    }
> +    _vendor_id = mmio_getl(_addr_mmio + VIRTIO_MMIO_VENDOR_ID);
> +
> +    debugf("Detected virtio-mmio device: (%ld,%ld)\n", _device_id,
> _vendor_id);
> +    return true;
> +}
> +
> +#define VIRTIO_MMIO_DEVICE_CMDLINE_PREFIX "virtio_mmio.device="
> +static mmio_device_info* parse_mmio_device_info(char *cmdline)
> +{   //
> +    // Parse virtio mmio device information from command line
> +    // appended/prepended by VMMs like firecracker. After successfully
> +    // parsing any found mmio device info, remove it from the commandline.
> +    //
> +    // [virtio_mmio.]device=<size>@<baseaddr>:<irq>[:<id>]
> +    char *prefix_pos = strstr(cmdline,VIRTIO_MMIO_DEVICE_CMDLINE_PREFIX);
> +    if (!prefix_pos)
> +        return nullptr;
> +
> +    u64 size = 0;
> +    char *size_pos = prefix_pos +
> strlen(VIRTIO_MMIO_DEVICE_CMDLINE_PREFIX);
> +    if (sscanf(size_pos,"%ld", &size) != 1)
> +        return nullptr;
> +
> +    char *at_pos = strstr(size_pos,"@");
> +    if (!at_pos)
> +        return nullptr;
> +
> +    switch(*(at_pos - 1)) {
> +        case 'k':
> +        case 'K':
> +            size *= 1024;
> +            break;
> +        case 'm':
> +        case 'M':
> +            size *= (1024 * 1024);
> +            break;
> +        default:
> +            break;
> +    }
> +
> +    u64 irq = 0, address = 0;
> +    if (sscanf(at_pos, "@%lli:%u", &address, &irq) != 2)
> +        return nullptr;
> +
> +    // Find first white-character or null as an end of device description
> +    auto desc_end_pos = at_pos;
> +    while (*desc_end_pos != 0 && !isspace(*desc_end_pos))
> +        desc_end_pos++;
> +
> +    // Remove conf info part from cmdline by copying over remaining part
> +    do {
> +       *prefix_pos = *desc_end_pos++;
> +    } while (*prefix_pos++);
> +
> +    return new mmio_device_info(address, size, irq);
> +}
> +
> +static std::vector<struct mmio_device_info> *mmio_device_info_entries = 0;
> +
> +void parse_mmio_device_configuration(char *cmdline)
> +{   //
> +    // We are assuming the mmio devices information is appended to the
> +    // command line (at least it is the case with the firecracker) so
> +    // once we parse those we strip it away so only plain OSv command
> line is left
> +    mmio_device_info_entries = new std::vector<struct mmio_device_info>();
> +    for( auto device_info = parse_mmio_device_info(cmdline); device_info
> != nullptr; device_info = parse_mmio_device_info(cmdline))
> +        mmio_device_info_entries->push_back(*device_info);
> +}
> +
> +void register_mmio_devices(hw::device_manager *dev_manager)
> +{
> +    for (auto info : *mmio_device_info_entries) {
> +        auto device = new mmio_device(info);
> +        if (device->parse_config()) {
> +            dev_manager->register_device(device);
> +        }
> +        else {
> +            delete device;
> +        }
> +    }
> +}
> +
> +}
> diff --git a/drivers/virtio-mmio.hh b/drivers/virtio-mmio.hh
> new file mode 100644
> index 00000000..024190ac
> --- /dev/null
> +++ b/drivers/virtio-mmio.hh
> @@ -0,0 +1,154 @@
> +/*
> + * Copyright (C) 2019 Waldemar Kozaczuk
> + *
> + * This work is open source software, licensed under the terms of the
> + * BSD license as described in the LICENSE file in the top-level
> directory.
> + */
> +
> +#ifndef VIRTIO_MMIO_DEVICE_HH
> +#define VIRTIO_MMIO_DEVICE_HH
> +
> +#include <osv/types.h>
> +#include <osv/mmio.hh>
> +#include "virtio-device.hh"
> +#include "virtio-vring.hh"
> +
> +using namespace hw;
> +
> +/* Magic value ("virt" string) - Read Only */
> +#define VIRTIO_MMIO_MAGIC_VALUE                0x000
> +
> +/* Virtio device version - Read Only */
> +#define VIRTIO_MMIO_VERSION            0x004
> +
> +/* Virtio device ID - Read Only */
> +#define VIRTIO_MMIO_DEVICE_ID          0x008
> +
> +/* Virtio vendor ID - Read Only */
> +#define VIRTIO_MMIO_VENDOR_ID          0x00c
> +
> +/* Bitmask of the features supported by the device (host)
> + * (32 bits per set) - Read Only */
> +#define VIRTIO_MMIO_DEVICE_FEATURES    0x010
> +
> +/* Device (host) features set selector - Write Only */
> +#define VIRTIO_MMIO_DEVICE_FEATURES_SEL        0x014
> +
> +/* Bitmask of features activated by the driver (guest)
> + * (32 bits per set) - Write Only */
> +#define VIRTIO_MMIO_DRIVER_FEATURES    0x020
> +
> +/* Activated features set selector - Write Only */
> +#define VIRTIO_MMIO_DRIVER_FEATURES_SEL        0x024
> +
> +/* Queue selector - Write Only */
> +#define VIRTIO_MMIO_QUEUE_SEL          0x030
> +
> +/* Maximum size of the currently selected queue - Read Only */
> +#define VIRTIO_MMIO_QUEUE_NUM_MAX      0x034
> +
> +/* Queue size for the currently selected queue - Write Only */
> +#define VIRTIO_MMIO_QUEUE_NUM          0x038
> +
> +/* Ready bit for the currently selected queue - Read Write */
> +#define VIRTIO_MMIO_QUEUE_READY                0x044
> +
> +/* Queue notifier - Write Only */
> +#define VIRTIO_MMIO_QUEUE_NOTIFY       0x050
> +
> +/* Interrupt status - Read Only */
> +#define VIRTIO_MMIO_INTERRUPT_STATUS   0x060
> +
> +/* Interrupt acknowledge - Write Only */
> +#define VIRTIO_MMIO_INTERRUPT_ACK      0x064
> +
> +/* Device status register - Read Write */
> +#define VIRTIO_MMIO_STATUS             0x070
> +
> +/* Selected queue's Descriptor Table address, 64 bits in two halves */
> +#define VIRTIO_MMIO_QUEUE_DESC_LOW     0x080
> +#define VIRTIO_MMIO_QUEUE_DESC_HIGH    0x084
> +
> +/* Selected queue's Available Ring address, 64 bits in two halves */
> +#define VIRTIO_MMIO_QUEUE_AVAIL_LOW    0x090
> +#define VIRTIO_MMIO_QUEUE_AVAIL_HIGH   0x094
> +
> +/* Selected queue's Used Ring address, 64 bits in two halves */
> +#define VIRTIO_MMIO_QUEUE_USED_LOW     0x0a0
> +#define VIRTIO_MMIO_QUEUE_USED_HIGH    0x0a4
> +
> +/* Configuration atomicity value */
> +#define VIRTIO_MMIO_CONFIG_GENERATION  0x0fc
> +
> +/* The config space is defined by each driver as
> + * the per-driver configuration space - Read Write */
> +#define VIRTIO_MMIO_CONFIG             0x100
> +
> +#define VIRTIO_MMIO_INT_VRING          (1 << 0)
> +#define VIRTIO_MMIO_INT_CONFIG         (1 << 1)
> +
> +namespace virtio {
> +
> +struct mmio_device_info {
> +    mmio_device_info(u64 address, u64 size, unsigned int irq) :
> +        _address(address), _size(size), _irq_no(irq) {}
> +
> +    u64 _address;
> +    u64 _size;
> +    unsigned int _irq_no;
> +};
> +
> +class mmio_device : public virtio_device {
> +public:
> +    mmio_device(mmio_device_info dev_info) :
> +        _dev_info(dev_info), _vendor_id(0), _device_id(0), _addr_mmio(0)
> {}
> +
> +    virtual ~mmio_device() {}
> +
> +    virtual hw_device_id get_id();
> +
> +    virtual void init() {}
> +    virtual void print() {}
> +    virtual void reset() {}
> +
> +    virtual unsigned get_irq() { return _dev_info._irq_no; }
> +    virtual u8 read_and_ack_isr();
> +    virtual void register_interrupt(interrupt_factory irq_factory);
> +
> +    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 void set_enabled_features(u64 features);
> +
> +    virtual u8 get_status();
> +    virtual void set_status(u8 status);
> +
> +    virtual u8 read_config(u32 offset);
> +
> +    virtual void dump_config() {}
> +
> +    virtual bool is_modern() { return true; };
> +    virtual size_t get_vring_alignment() { return PAGE_SIZE; }
> +
> +    bool parse_config();
> +
> +private:
> +    mmio_device_info _dev_info;
> +    //u64 _id;
> +    u16 _vendor_id;
> +    u16 _device_id;
> +
> +    mmioaddr_t _addr_mmio;
> +    std::unique_ptr<gsi_edge_interrupt> _irq;
> +};
> +
> +void parse_mmio_device_configuration(char *cmdline);
> +void register_mmio_devices(hw::device_manager *dev_manager);
> +
> +}
> +
> +#endif //VIRTIO_MMIO_DEVICE_HH
> --
> 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