~satchmo/libvmm

10b277d75ef92ac5a731b1fc7334c5f11f583e60 — Jason Phan 4 months ago 4f6af4b
virtio: First pass at implementing virtio descriptors

For now, GuestAddress is in the same file, but should later on be moved to a
dedicated memory module
3 files changed, 127 insertions(+), 1 deletions(-)

A vmm/virtio/detail/queue.cpp
M vmm/virtio/detail/queue.hpp
M vmm/virtio/virtio.hpp
A vmm/virtio/detail/queue.cpp => vmm/virtio/detail/queue.cpp +14 -0
@@ 0,0 1,14 @@
//
// queue.cpp - Virtio queue
//

#include "vmm/virtio/detail/queue.hpp"

namespace vmm::virtio::detail {

auto Descriptor::addr() const noexcept -> GuestAddress
{
    return m_addr;
}

}  // namespace vmm::virtio::detail

M vmm/virtio/detail/queue.hpp => vmm/virtio/detail/queue.hpp +110 -1
@@ 4,9 4,118 @@

#pragma once

#include <bitset> // bitset
#include <cstdint> // uint*_t
#include <iostream> // ostream

namespace vmm::virtio::detail {

class VirtQueue
enum class VirtqueueDescriptorFlag : uint16_t {
    Next,
    Write,
    Indirect,
};

class GuestAddress
{
    private:
        uint64_t m_addr;
    public:
        GuestAddress(uint64_t addr) : m_addr{addr} {}

        friend auto operator<<(std::ostream& os,
                               const GuestAddress& ga) -> std::ostream&
        {
            os << ga.m_addr;
            return os;
        }
};

// Virtio descriptor constraints with C representation
//
// TODO:
//
//  * Implement ByteValued interface.
//
// REFERENCE:
//
//     #define VIRTQ_DESC_F_NEXT       1 // Marks a buffer as continuing via the `next` field.
//     #define VIRTQ_DESC_F_WRITE      2 // Marks a buffer as device write-only (otherwise device read-only).
//     #define VIRTQ_DESC_F_INDIRECT   4 // Means the buffer contains a list of buffer descriptors.
//
//     struct virtq_desc {
//         le64 addr;
//         le32 len;
//         le16 flags; // The flags as indicated above.
//         le16 next; // Next field if flags & NEXT.
//     };

class Descriptor
{
    private:
        // Guest's physical address of device specific data
        //uint64_t m_addr;
        GuestAddress m_addr;

        // Length of device-specific data
        uint32_t m_len;

        // Includes next, write, and indirect bits
        std::bitset<16> m_flags;

        // Index into the descriptor table of the next descriptor if `flags`
        // has the `next` bit set
        uint16_t m_next;
    public:
        // Returns the guest physical address of descriptor buffer.
        [[nodiscard]] auto addr() const noexcept -> GuestAddress;

        // Returns the length of descriptor buffer.
        [[nodiscard]] constexpr auto len() const noexcept -> uint32_t
        {
            return m_len;
        }

        // Returns the descriptor's flags, including the next, write and
        // indirect bits.
        [[nodiscard]] constexpr auto flags() const noexcept -> std::bitset<16>
        {
            return m_flags;
        }

        // Returns the value stored in the `next` field of the descriptor.
        [[nodiscard]] constexpr auto next() const noexcept -> uint16_t
        {
            return m_next;
        }

        // Checks if the `VIRTQ_DESC_F_NEXT` flag is set.
        [[nodiscard]] constexpr auto has_next() const noexcept -> bool
        {
            return m_flags[static_cast<std::size_t>(VirtqueueDescriptorFlag::Next)];
        }

        // Checks if the driver designated this as a write only descriptor.
        //
        // If false, the descriptor is read-only. Write-only means the
        // emulated device can write and the driver can read.
        [[nodiscard]] constexpr auto is_write_only() const noexcept -> bool
        {
            return m_flags[static_cast<std::size_t>(VirtqueueDescriptorFlag::Write)];
        }

        // Checks if the descriptor is an indirect descriptor.
        //
        // TODO: There are a couple of restrictions in terms of which flags
        // combinations are actually valid for indirect descriptors. Implement
        // those checks as well somewhere.
        [[nodiscard]] constexpr auto is_indirect() const noexcept -> bool
        {
            return m_flags[static_cast<std::size_t>(VirtqueueDescriptorFlag::Indirect)];
        }
};

struct VirtQueue
{
};


M vmm/virtio/virtio.hpp => vmm/virtio/virtio.hpp +3 -0
@@ 12,4 12,7 @@ namespace vmm::virtio {
using VirtDevice = vmm::virtio::detail::VirtDevice;
using VirtQueue = vmm::virtio::detail::VirtQueue;

using GuestAddress = vmm::virtio::detail::GuestAddress;
using Descriptor = vmm::virtio::detail::Descriptor;

}  // namespace vmm::virtio