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')