7#include <gmock/gmock.h>
8#include <gtest/gtest.h>
13#include <unordered_map>
24 static auto GetInstance() -> MockAllocator& {
25 static MockAllocator instance;
29 auto AlignedAlloc(
size_t alignment,
size_t size) ->
void* {
31 if (posix_memalign(&ptr, alignment, size) == 0) {
32 allocated_blocks_[ptr] = size;
38 void Free(
void* ptr) {
42 auto it = allocated_blocks_.find(ptr);
43 if (it != allocated_blocks_.end()) {
44 allocated_blocks_.erase(it);
50 for (
auto& [ptr, size] : allocated_blocks_) {
53 allocated_blocks_.clear();
56 [[nodiscard]]
auto GetAllocatedCount() const ->
size_t {
57 return allocated_blocks_.size();
61 MockAllocator() =
default;
62 std::unordered_map<void*, size_t> allocated_blocks_;
65extern "C" void*
aligned_alloc(
size_t alignment,
size_t size) {
66 return MockAllocator::GetInstance().AlignedAlloc(alignment, size);
70 MockAllocator::GetInstance().Free(ptr);
73class VirtualMemoryTest :
public ::testing::Test {
75 void SetUp()
override {
76 BasicInfoSingleton::create();
77 BasicInfoSingleton::instance().physical_memory_addr = 0x80000000;
78 BasicInfoSingleton::instance().physical_memory_size = 0x10000000;
79 MockAllocator::GetInstance().Reset();
81 env_state_.InitializeCores(1);
82 env_state_.SetCurrentThreadEnvironment();
83 env_state_.BindThreadToCore(std::this_thread::get_id(), 0);
86 void TearDown()
override {
87 MockAllocator::GetInstance().Reset();
88 env_state_.ClearCurrentThreadEnvironment();
89 BasicInfoSingleton::destroy();
95TEST_F(VirtualMemoryTest, MapPageBasic) {
100 ASSERT_NE(page_dir,
nullptr);
103 void* virt_addr =
reinterpret_cast<void*
>(0x1000);
104 void* phys_addr =
reinterpret_cast<void*
>(0x80001000);
107 auto result = vm.
MapPage(page_dir, virt_addr, phys_addr,
113 auto mapped = vm.
GetMapping(page_dir, virt_addr);
120TEST_F(VirtualMemoryTest, UnmapPage) {
125 ASSERT_NE(page_dir,
nullptr);
128 void* virt_addr =
reinterpret_cast<void*
>(0x1000);
129 void* phys_addr =
reinterpret_cast<void*
>(0x80001000);
132 (void)vm.
MapPage(page_dir, virt_addr, phys_addr,
136 auto result = vm.
UnmapPage(page_dir, virt_addr);
140 auto mapped = vm.
GetMapping(page_dir, virt_addr);
144TEST_F(VirtualMemoryTest, UnmapNonExistentPage) {
149 ASSERT_NE(page_dir,
nullptr);
152 void* virt_addr =
reinterpret_cast<void*
>(0x1000);
155 auto result = vm.
UnmapPage(page_dir, virt_addr);
159TEST_F(VirtualMemoryTest, GetMappingNonExistent) {
164 ASSERT_NE(page_dir,
nullptr);
167 void* virt_addr =
reinterpret_cast<void*
>(0x1000);
169 auto mapped = vm.
GetMapping(page_dir, virt_addr);
173TEST_F(VirtualMemoryTest, MapMultiplePages) {
178 ASSERT_NE(page_dir,
nullptr);
181 constexpr size_t kNumPages = 10;
182 constexpr size_t kPageSize = 0x1000;
185 for (
size_t i = 0; i < kNumPages; ++i) {
186 void* virt_addr =
reinterpret_cast<void*
>(0x10000 + i * kPageSize);
187 void* phys_addr =
reinterpret_cast<void*
>(0x80000000 + i * kPageSize);
189 auto result = vm.
MapPage(page_dir, virt_addr, phys_addr,
195 for (
size_t i = 0; i < kNumPages; ++i) {
196 void* virt_addr =
reinterpret_cast<void*
>(0x10000 + i * kPageSize);
197 void* phys_addr =
reinterpret_cast<void*
>(0x80000000 + i * kPageSize);
199 auto mapped = vm.
GetMapping(page_dir, virt_addr);
207TEST_F(VirtualMemoryTest, RemapPage) {
212 ASSERT_NE(page_dir,
nullptr);
215 void* virt_addr =
reinterpret_cast<void*
>(0x1000);
216 void* phys_addr1 =
reinterpret_cast<void*
>(0x80001000);
217 void* phys_addr2 =
reinterpret_cast<void*
>(0x80002000);
220 (void)vm.
MapPage(page_dir, virt_addr, phys_addr1,
224 auto result = vm.
MapPage(page_dir, virt_addr, phys_addr2,
229 auto mapped = vm.
GetMapping(page_dir, virt_addr);
236TEST_F(VirtualMemoryTest, DestroyPageDirectoryWithoutFreePages) {
241 ASSERT_NE(page_dir,
nullptr);
245 constexpr size_t kNumPages = 5;
246 constexpr size_t kPageSize = 0x1000;
248 for (
size_t i = 0; i < kNumPages; ++i) {
249 void* virt_addr =
reinterpret_cast<void*
>(0x10000 + i * kPageSize);
250 void* phys_addr =
reinterpret_cast<void*
>(0x80000000 + i * kPageSize);
251 (void)vm.
MapPage(page_dir, virt_addr, phys_addr,
255 size_t allocated_before = MockAllocator::GetInstance().GetAllocatedCount();
260 size_t allocated_after = MockAllocator::GetInstance().GetAllocatedCount();
263 EXPECT_LT(allocated_after, allocated_before);
266TEST_F(VirtualMemoryTest, ClonePageDirectoryWithMappings) {
271 ASSERT_NE(src_page_dir,
nullptr);
275 constexpr size_t kNumPages = 5;
276 constexpr size_t kPageSize = 0x1000;
278 for (
size_t i = 0; i < kNumPages; ++i) {
279 void* virt_addr =
reinterpret_cast<void*
>(0x10000 + i * kPageSize);
280 void* phys_addr =
reinterpret_cast<void*
>(0x80000000 + i * kPageSize);
281 (void)vm.
MapPage(src_page_dir, virt_addr, phys_addr,
287 ASSERT_TRUE(clone_result.has_value());
288 auto* dst_page_dir = clone_result.value();
292 for (
size_t i = 0; i < kNumPages; ++i) {
293 void* virt_addr =
reinterpret_cast<void*
>(0x10000 + i * kPageSize);
294 void* phys_addr =
reinterpret_cast<void*
>(0x80000000 + i * kPageSize);
296 auto src_mapped = vm.
GetMapping(src_page_dir, virt_addr);
297 auto dst_mapped = vm.
GetMapping(dst_page_dir, virt_addr);
302 if (src_mapped && dst_mapped) {
314TEST_F(VirtualMemoryTest, ClonePageDirectoryWithoutMappings) {
319 ASSERT_NE(src_page_dir,
nullptr);
323 constexpr size_t kNumPages = 3;
324 constexpr size_t kPageSize = 0x1000;
326 for (
size_t i = 0; i < kNumPages; ++i) {
327 void* virt_addr =
reinterpret_cast<void*
>(0x10000 + i * kPageSize);
328 void* phys_addr =
reinterpret_cast<void*
>(0x80000000 + i * kPageSize);
329 (void)vm.
MapPage(src_page_dir, virt_addr, phys_addr,
335 ASSERT_TRUE(clone_result.has_value());
336 auto* dst_page_dir = clone_result.value();
340 for (
size_t i = 0; i < kNumPages; ++i) {
341 void* virt_addr =
reinterpret_cast<void*
>(0x10000 + i * kPageSize);
343 auto src_mapped = vm.
GetMapping(src_page_dir, virt_addr);
344 auto dst_mapped = vm.
GetMapping(dst_page_dir, virt_addr);
355TEST_F(VirtualMemoryTest, CloneNullPageDirectory) {
359 GTEST_SKIP() <<
"ClonePageDirectory with nullptr triggers assertion";
362TEST_F(VirtualMemoryTest, DestroyNullPageDirectory) {
370TEST_F(VirtualMemoryTest, MemoryLeakCheck) {
380 ASSERT_NE(page_dir1,
nullptr);
381 ASSERT_NE(page_dir2,
nullptr);
382 ASSERT_NE(page_dir3,
nullptr);
387 size_t allocated_before = MockAllocator::GetInstance().GetAllocatedCount();
390 for (
size_t i = 0; i < 10; ++i) {
391 void* virt_addr =
reinterpret_cast<void*
>(0x10000 + i * 0x1000);
392 void* phys_addr =
reinterpret_cast<void*
>(0x80000000 + i * 0x1000);
393 (void)vm.
MapPage(page_dir1, virt_addr, phys_addr,
399 ASSERT_TRUE(clone_result.has_value());
400 auto* cloned = clone_result.value();
409 size_t allocated_after = MockAllocator::GetInstance().GetAllocatedCount();
410 EXPECT_LT(allocated_after, allocated_before);
auto DestroyPageDirectory(void *page_dir, bool free_pages=false) -> void
回收页表,释放所有映射和子页表
auto GetMapping(void *page_dir, void *virtual_addr) -> Expected< void * >
获取虚拟地址对应的物理地址映射
auto MapPage(void *page_dir, void *virtual_addr, void *physical_addr, uint32_t flags) -> Expected< void >
映射单个页面
auto ClonePageDirectory(void *src_page_dir, bool copy_mappings=true) -> Expected< void * >
复制页表
auto UnmapPage(void *page_dir, void *virtual_addr) -> Expected< void >
取消映射单个页面
TEST_F(KernelFdtTest, ConstructorTest)
static constexpr size_t kPageSize
auto GetUserPagePermissions(bool readable=true, bool writable=false, bool executable=false, bool global=false) -> uint64_t
void aligned_free(void *ptr)
void * aligned_alloc(size_t alignment, size_t size)
#define EXPECT_TRUE(cond, msg)
#define EXPECT_NE(val1, val2, msg)
#define EXPECT_LT(val1, val2, msg)
#define EXPECT_FALSE(cond, msg)
#define EXPECT_EQ(val1, val2, msg)