aboutsummaryrefslogtreecommitdiff
path: root/kernel/src/test_support/simulated_memory.cpp
blob: 03dac1d4080cfed6089726177419bb2cec7246bc (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
#include "kernel/test_support/simulated_memory.hpp"

#include "kapi/memory.hpp"

#include <kstd/units>

#include <cerrno>
#include <cstddef>
#include <cstring>
#include <format>
#include <stdexcept>
#include <sys/mman.h>
#include <sys/types.h>
#include <unistd.h>

namespace kernel::tests
{

  simulated_memory::simulated_memory(kstd::units::bytes physical_size, kstd::units::bytes virtual_size)
      : m_descriptor{memfd_create("teachos_simulated_memory", 0)}
      , m_physical_size{physical_size}
      , m_virtual_size{virtual_size}
  {
    if (m_descriptor < 0)
    {
      auto error = std::format("Failed to allocate backing memory: {}", strerror(errno));
      throw std::runtime_error(error);
    }

    if (ftruncate(m_descriptor, static_cast<off_t>(m_physical_size.value)) < 0)
    {
      auto error = std::format("Failed to reserve backing memory: {}", strerror(errno));
      throw std::runtime_error(error);
    }

    auto physical_storage = mmap(nullptr, m_physical_size.value, PROT_READ | PROT_WRITE, MAP_SHARED, m_descriptor, 0);
    if (physical_storage == MAP_FAILED)
    {
      auto error = std::format("Failed to map backing memory: {}", strerror(errno));
      throw std::runtime_error(error);
    }

    auto virtual_pointer = mmap(nullptr, virtual_size.value, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
    if (virtual_pointer == MAP_FAILED)
    {
      auto error = std::format("Failed to reserve virtual memory: {}", strerror(errno));
      throw std::runtime_error(error);
    }

    m_physical_base = static_cast<std::byte *>(physical_storage);
    m_virtual_base = static_cast<std::byte *>(virtual_pointer);

    clear();
  }

  simulated_memory::~simulated_memory()
  {
    munmap(m_virtual_base, m_virtual_size.value);
    munmap(m_physical_base, m_physical_size.value);
    close(m_descriptor);
  }

  auto simulated_memory::clear() -> void
  {
    std::memset(m_physical_base, 0, m_physical_size.value);
  }

  auto simulated_memory::physical_base() noexcept -> std::byte *
  {
    return m_physical_base;
  }

  auto simulated_memory::physical_base() const noexcept -> std::byte const *
  {
    return m_physical_base;
  }

  auto simulated_memory::physical_size() const noexcept -> kstd::units::bytes
  {
    return m_physical_size;
  }

  auto simulated_memory::virtual_base() const noexcept -> kapi::memory::linear_address
  {
    return kapi::memory::linear_address{m_virtual_base};
  }

  auto simulated_memory::virtual_size() const noexcept -> kstd::units::bytes
  {
    return m_virtual_size;
  }

  auto simulated_memory::map(kstd::units::bytes size, std::byte * to, off_t offset) -> std::byte *
  {
    auto mapped_ptr = mmap(to, size.value, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_FIXED, m_descriptor, offset);
    if (mapped_ptr == MAP_FAILED)
    {
      auto error = std::format("Failed to map page: {}", strerror(errno));
      throw std::runtime_error(error);
    }

    return static_cast<std::byte *>(mapped_ptr);
  }

}  // namespace kernel::tests