~satchmo/libvmm

099da1882e5d5946d4d2a51503ab2397bb8ededc — Jason Phan 4 months ago 10b277d
memory: Initial Address/GuestAddress pass
A tests/memory/address.cpp => tests/memory/address.cpp +8 -0
@@ 0,0 1,8 @@
#define CATCH_CONFIG_MAIN

#include <catch2/catch.hpp>

#include "vmm/memory/address.hpp"

TEST_CASE("vCPU creation") {
}

A tests/memory/guest.cpp => tests/memory/guest.cpp +8 -0
@@ 0,0 1,8 @@
#define CATCH_CONFIG_MAIN

#include <catch2/catch.hpp>

#include "vmm/memory/guest.hpp"

TEST_CASE("vCPU creation") {
}

A tests/memory/meson.build => tests/memory/meson.build +6 -0
@@ 0,0 1,6 @@
memory_test_suite = {
  'Memory address' : files('address.cpp'),
  'Memory guest' : files('guest.cpp'),
}

test_suites += {'memory': memory_test_suite}

M tests/meson.build => tests/meson.build +2 -1
@@ 1,5 1,6 @@
test_dep = dependency('catch2')

subdir('kvm')
subdir('virtio')
subdir('memory')
subdir('types')
subdir('virtio')

A vmm/memory/address.hpp => vmm/memory/address.hpp +13 -0
@@ 0,0 1,13 @@
#pragma once

//#include "vmm/memory/detail/address.hpp"

//namespace vmm::memory {

//template<typename T>
//using AddressValue = vmm::memory::detail::AddressValue<T>;

//template<typename T, typename S>
//using Address = vmm::memory::detail::Address<T, S>;

//}  // vmm::memory

A vmm/memory/detail/address.hpp => vmm/memory/detail/address.hpp +171 -0
@@ 0,0 1,171 @@
//
// address.hpp -
//

#pragma once

namespace vmm::memory::detail {

// An address within some address space.
//
// NOTE: The operators (+, -, &, |, etc.) are not supported, meaning clients
//       must explicitly invoke the corresponding methods. However, there are
//       exceptions: `Address` (BitAnd|BitOr) `AddressValue` are supported.
template<typename Concrete, typename Size>
class Address
{
    public:
        Address() = default;
        virtual ~Address() = default;

        Address(const Address&) = default;
        Address& operator=(const Address&) = default;
        Address(Address&&) = default;
        Address& operator=(Address&&) = default;

        // Returns the raw value of the address.
        virtual auto data() const noexcept -> Size = 0;

        // Returns a bitwise AND of the address and a mask.
        virtual auto mask(const Size) const noexcept -> Size = 0;

        // Adds `other` to the address' value.
        virtual auto operator+(const Size) const noexcept -> Concrete = 0;
        virtual auto operator+(const Concrete&) const noexcept -> Concrete = 0;

        // Subtracts `other` from the address' value.
        virtual auto operator-(const Size) const noexcept -> Concrete = 0;
        virtual auto operator-(const Concrete&) const noexcept -> Concrete = 0;

        // Adds `other` to the address' value.
        //
        // Returns a pair consisting of the sum and a boolean indicating
        // whether an overflow would have occurred. If an overflow would have
        // occurred, the wrapped address is returned.
        virtual auto add(const Size) const -> Concrete = 0;
        virtual auto add(const Concrete&) const -> Concrete = 0;

        // Subtracts `other` from the address' value.
        //
        // Returns a pair containing the difference and a boolean indicating
        // whether an arithmetic underflow would have occurred. If an overflow
        // would have occurred, then the wrapped address is returned.
        virtual auto subtract(const Size) const -> Concrete = 0;
        virtual auto subtract(const Concrete&) const -> Concrete = 0;

        // Aligns the address to a power of 2.
        virtual auto align_up(const Size) noexcept -> void = 0;
        virtual auto checked_align_up(const Size) -> void = 0;
};

//template<typename Derived>
//class EnableDownCast
//{
    //using Base = EnableDownCast;

    //protected:
        //// Disable deletion of Derived* through Base*.
        //// Enable deletion of Base* through Derived*.
        //~EnableDownCast() = default;
    //public:
        //[[nodiscard]] constexpr auto self() const noexcept -> const Derived*
        //{
            //return static_cast<const Derived*>(this);
        //}

        //constexpr auto self() noexcept -> Derived*
        //{
            //return static_cast<Derived*>(this);
        //}
//};

//template<typename Concrete, typename Size>
//class Address : EnableDownCast<Concrete>
//{
    //using EnableDownCast<Concrete>::self;

    //public:
        ////Address() = default;
        ////~Address() = default;

        ////Address(const Address&) = default;
        ////Address& operator=(const Address&) = default;
        ////Address(Address&&) = default;
        ////Address& operator=(Address&&) = default;

        //// Returns the raw value of the address.
        //auto data() const noexcept -> Size
        //{
            //return self()->data();
        //}

        //// Returns a bitwise AND of the address and a mask.
        //auto mask() const noexcept -> Size
        //{
            //return self()->mask();
        //}

        //// Adds `other` to the address' value.
        //auto operator+(const Size offset) const noexcept -> Concrete
        //{
            //return self()->operator+(offset);
        //}

        //// Subtracts `other` from the address' value.
        //auto operator-(const Size value) const noexcept -> Concrete
        //{
            //return self()->operator-(value);
        //}

        //auto operator-(const Concrete& addr) const noexcept -> Concrete
        //{
            //return self()->operator-(addr);
        //}

        //// Adds `other` to the address' value.
        ////
        //// Returns a pair consisting of the sum and a boolean indicating
        //// whether an overflow would have occurred. If an overflow would have
        //// occurred, the wrapped address is returned.
        //auto add(const Size offset) const -> Concrete
        //{
            //return self()->add(offset);
        //}

        //auto add(const Concrete& addr) const -> Concrete
        //{
            //return self()->add(addr);
        //}

            //// Subtracts `other` from the address' value.
            ////
            //// Returns a pair containing the difference and a boolean indicating
            //// whether an arithmetic underflow would have occurred. If an overflow
            //// would have occurred, then the wrapped address is returned.
        //auto subtract(const Size value) const -> Concrete
        //{
            //return self()->subtract(value);
        //}

        //auto subtract(const Concrete& addr) const -> Concrete
        //{
            //return self()->subtract(addr);
        //}

        //// Returns the offset from `m_addr` to `base`.
        ////virtual auto offset_from(const Concrete&) const noexcept -> Concrete;
        ////virtual auto checked_offset_from(const Concrete&) const -> Concrete;

        //// Aligns the address to a power of 2.
        //auto align_up(const Size alignment) noexcept -> void
        //{
            //return self()->align_up(alignment);
        //}

        ////auto checked_align_up(const Size alignment) -> void
        ////{
            ////return self()->checked_align_up(alignment);
        ////}
//};

}  // vmm::memory::detail

A vmm/memory/detail/guest.cpp => vmm/memory/detail/guest.cpp +82 -0
@@ 0,0 1,82 @@
#include "vmm/memory/detail/guest.hpp"
#include "vmm/types/detail/exceptions.hpp"
#include <stdexcept>
#include <string>

namespace vmm::memory::detail {

auto GuestAddress::data() const noexcept -> size_type
{
    return m_addr;
}

auto GuestAddress::mask(const size_type mask) const noexcept -> size_type
{
    return m_addr & mask;
}

auto GuestAddress::operator+(const size_type val) const noexcept -> value_type
{
    return GuestAddress{m_addr + val};
}

auto GuestAddress::operator+(const_reference addr) const noexcept -> value_type
{
    return *this + addr.data();
}

auto GuestAddress::operator-(const size_type val) const noexcept -> value_type
{
    return GuestAddress{m_addr - val};
}

auto GuestAddress::operator-(const_reference addr) const noexcept -> value_type
{
    return *this - addr.data();
}

auto GuestAddress::add(const size_type val) const -> value_type
{
    if (m_addr > std::numeric_limits<size_type>::max() - val) {
        VMM_THROW(std::overflow_error(std::to_string(m_addr) + " + " + std::to_string(val) + " results in overflow."));
    }

    return *this + val;
}

auto GuestAddress::add(const_reference addr) const -> value_type
{
    return add(addr.data());
}

auto GuestAddress::subtract(const size_type val) const -> value_type
{
    if (m_addr < std::numeric_limits<size_type>::min() + val) {
        VMM_THROW(std::underflow_error(std::to_string(m_addr) + " - " + std::to_string(val) + " results in underflow."));
    }

    return *this - val;
}

auto GuestAddress::subtract(const_reference addr) const -> value_type
{
    return subtract(addr.data());
}

auto GuestAddress::align_up(const size_type alignment) noexcept -> void
{
    const auto mask = alignment - 1;
    m_addr = (*this + mask).data() & !mask;
}

auto GuestAddress::checked_align_up(const size_type alignment) -> void
{
    const auto mask = alignment - 1;

    assert(alignment);
    assert(!(alignment & mask));

    m_addr = add(mask).data() & !mask;
}

}  // vmm::memory::detail

A vmm/memory/detail/guest.hpp => vmm/memory/detail/guest.hpp +89 -0
@@ 0,0 1,89 @@
//
// guest.hpp -
//

#pragma once

#include <cassert> // assert
#include <cstdint> // uint*_t
#include <iostream> // ostream
#include <limits> // numeric_limits

#include "vmm/memory/detail/address.hpp" // Address, AddressValue

namespace vmm::memory::detail {

// A guest physical address.
//
// On aarch64, a 32-bit hypervisor may be used to support a 64-bit guest. For
// simplicity, uint64_t is used to store the raw value regardless of whether
// the guest is 32-bit or 64-bit.
class GuestAddress : public Address<GuestAddress, uint64_t>
{
    using value_type = GuestAddress;
    using size_type = uint64_t;
    using pointer = value_type*;
    using const_pointer = const value_type*;
    using reference = value_type&;
    using const_reference = const value_type&;
    using iterator = pointer;
    using const_iterator = const_pointer;

    private:
        size_type m_addr{};
    public:
        explicit GuestAddress(size_type addr=0) noexcept : m_addr{addr} {}

        // Returns the raw value of the address.
        auto data() const noexcept -> size_type override;

        // Returns the bitwise AND of the address and a mask.
        auto mask(const size_type mask) const noexcept -> size_type override;

        // Returns the address plus some value (sum is wrapped).
        auto operator+(const size_type val) const noexcept -> value_type override;

        // Returns the sum of the address and another address (sum is wrapped).
        auto operator+(const_reference addr) const noexcept -> value_type override;

        // Returns the address minus some value (difference is wrapped).
        auto operator-(const size_type val) const noexcept -> value_type override;

        // Returns the difference between the address and another address
        // (difference is wrapped).
        auto operator-(const_reference addr) const noexcept -> value_type override;

        // Returns the address plus some value.
        //
        // If an "overflow" occurs, an exception is thrown.
        auto add(const size_type val) const -> value_type override;

        // Returns the sum of the address and another address.
        //
        // If an "overflow" occurs, an exception is thrown.
        auto add(const_reference addr) const -> value_type override;

        // Returns the address minus some value.
        //
        // If an "underflow" occurs, an exception is thrown.
        auto subtract(const size_type val) const -> value_type override;

        // Returns the difference between the address and another address.
        //
        // If an "underflow" occurs, an exception is thrown.
        auto subtract(const_reference addr) const -> value_type override;

        // Returns the offset between `m_addr` to `base`.
        //auto offset_from(const_reference base) const noexcept -> value_type;
        //auto checked_offset_from(const_reference base) const -> value_type;

        // Aligns the address to a power of 2.
        auto align_up(const size_type alignment) noexcept -> void override;

        // Aligns the address to a power of 2.
        //
        // If an "overflow" occurs, an exception is thrown.
        auto checked_align_up(const size_type alignment) -> void;
};

}  // vmm::memory::detail

A vmm/memory/detail/meson.build => vmm/memory/detail/meson.build +13 -0
@@ 0,0 1,13 @@
memory_internal_headers = files(
  'guest.hpp',
  'address.hpp',
)

memory_internal_sources = files(
  'guest.cpp',
  #'address.cpp',
)

sources += memory_internal_sources

install_headers(memory_internal_headers, subdir: 'vmm/memory/detail')

A vmm/memory/guest.hpp => vmm/memory/guest.hpp +8 -0
@@ 0,0 1,8 @@
#pragma once

//#include "vmm/memory/detail/guest.hpp"

//namespace vmm::memory {


//}  // vmm::memory

A vmm/memory/memory.hpp => vmm/memory/memory.hpp +21 -0
@@ 0,0 1,21 @@
//
// memory.hpp - Public memory header
//

#pragma once

#include "vmm/memory/detail/address.hpp"
#include "vmm/memory/detail/guest.hpp"

namespace vmm::memory {

template<typename T>
using AddressValue = vmm::memory::detail::AddressValue<T>;

template<typename T, typename S>
using Address = vmm::memory::detail::Address<T, S>;

using GuestAddressValue = vmm::memory::detail::GuestAddressValue;
using GuestAddress = vmm::memory::detail::GuestAddress;

}  // vmm::memory

A vmm/memory/meson.build => vmm/memory/meson.build +9 -0
@@ 0,0 1,9 @@
subdir('detail')

memory_headers = files(
    #'address.hpp',
    #'guest.hpp',
    'memory.hpp',
)

install_headers(memory_headers, subdir: 'vmm')

M vmm/meson.build => vmm/meson.build +4 -2
@@ 1,9 1,11 @@
public_headers = include_directories(
  'types',
  'kvm',
  'memory',
  'types',
  'virtio'
)

subdir('types')
subdir('kvm')
subdir('memory')
subdir('types')
subdir('virtio')