mirror of
https://github.com/citra-emu/citra.git
synced 2024-12-18 17:20:10 +00:00
Tests: Added some tests for the VMManager class.
Covering basic operations like mapping, unmapping, reprotecting and changing memory state.
This commit is contained in:
parent
e4f35f70ac
commit
07089cfb3c
@ -7,6 +7,7 @@ add_executable(tests
|
|||||||
core/file_sys/path_parser.cpp
|
core/file_sys/path_parser.cpp
|
||||||
core/hle/kernel/hle_ipc.cpp
|
core/hle/kernel/hle_ipc.cpp
|
||||||
core/memory/memory.cpp
|
core/memory/memory.cpp
|
||||||
|
core/memory/vm_manager.cpp
|
||||||
glad.cpp
|
glad.cpp
|
||||||
tests.cpp
|
tests.cpp
|
||||||
)
|
)
|
||||||
|
138
src/tests/core/memory/vm_manager.cpp
Normal file
138
src/tests/core/memory/vm_manager.cpp
Normal file
@ -0,0 +1,138 @@
|
|||||||
|
// Copyright 2017 Citra Emulator Project
|
||||||
|
// Licensed under GPLv2 or any later version
|
||||||
|
// Refer to the license.txt file included.
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
#include <catch.hpp>
|
||||||
|
#include "core/hle/kernel/errors.h"
|
||||||
|
#include "core/hle/kernel/memory.h"
|
||||||
|
#include "core/hle/kernel/vm_manager.h"
|
||||||
|
#include "core/memory.h"
|
||||||
|
|
||||||
|
TEST_CASE("Memory Basics", "[kernel][memory]") {
|
||||||
|
auto block = std::make_shared<std::vector<u8>>(Memory::PAGE_SIZE);
|
||||||
|
SECTION("mapping memory") {
|
||||||
|
// Because of the PageTable, Kernel::VMManager is too big to be created on the stack.
|
||||||
|
auto manager = std::make_unique<Kernel::VMManager>();
|
||||||
|
auto result = manager->MapMemoryBlock(Memory::HEAP_VADDR, block, 0, block->size(),
|
||||||
|
Kernel::MemoryState::Private);
|
||||||
|
REQUIRE(result.Code() == RESULT_SUCCESS);
|
||||||
|
|
||||||
|
auto vma = manager->FindVMA(Memory::HEAP_VADDR);
|
||||||
|
CHECK(vma != manager->vma_map.end());
|
||||||
|
CHECK(vma->second.size == block->size());
|
||||||
|
CHECK(vma->second.type == Kernel::VMAType::AllocatedMemoryBlock);
|
||||||
|
CHECK(vma->second.backing_block == block);
|
||||||
|
CHECK(vma->second.meminfo_state == Kernel::MemoryState::Private);
|
||||||
|
}
|
||||||
|
|
||||||
|
SECTION("unmapping memory") {
|
||||||
|
// Because of the PageTable, Kernel::VMManager is too big to be created on the stack.
|
||||||
|
auto manager = std::make_unique<Kernel::VMManager>();
|
||||||
|
auto result = manager->MapMemoryBlock(Memory::HEAP_VADDR, block, 0, block->size(),
|
||||||
|
Kernel::MemoryState::Private);
|
||||||
|
REQUIRE(result.Code() == RESULT_SUCCESS);
|
||||||
|
|
||||||
|
ResultCode code = manager->UnmapRange(Memory::HEAP_VADDR, block->size());
|
||||||
|
REQUIRE(code == RESULT_SUCCESS);
|
||||||
|
|
||||||
|
auto vma = manager->FindVMA(Memory::HEAP_VADDR);
|
||||||
|
CHECK(vma != manager->vma_map.end());
|
||||||
|
CHECK(vma->second.type == Kernel::VMAType::Free);
|
||||||
|
CHECK(vma->second.backing_block == nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
SECTION("changing memory permissions") {
|
||||||
|
// Because of the PageTable, Kernel::VMManager is too big to be created on the stack.
|
||||||
|
auto manager = std::make_unique<Kernel::VMManager>();
|
||||||
|
auto result = manager->MapMemoryBlock(Memory::HEAP_VADDR, block, 0, block->size(),
|
||||||
|
Kernel::MemoryState::Private);
|
||||||
|
REQUIRE(result.Code() == RESULT_SUCCESS);
|
||||||
|
|
||||||
|
ResultCode code = manager->ReprotectRange(Memory::HEAP_VADDR, block->size(),
|
||||||
|
Kernel::VMAPermission::Execute);
|
||||||
|
CHECK(code == RESULT_SUCCESS);
|
||||||
|
|
||||||
|
auto vma = manager->FindVMA(Memory::HEAP_VADDR);
|
||||||
|
CHECK(vma != manager->vma_map.end());
|
||||||
|
CHECK(vma->second.permissions == Kernel::VMAPermission::Execute);
|
||||||
|
|
||||||
|
code = manager->UnmapRange(Memory::HEAP_VADDR, block->size());
|
||||||
|
REQUIRE(code == RESULT_SUCCESS);
|
||||||
|
}
|
||||||
|
|
||||||
|
SECTION("changing memory state") {
|
||||||
|
// Because of the PageTable, Kernel::VMManager is too big to be created on the stack.
|
||||||
|
auto manager = std::make_unique<Kernel::VMManager>();
|
||||||
|
auto result = manager->MapMemoryBlock(Memory::HEAP_VADDR, block, 0, block->size(),
|
||||||
|
Kernel::MemoryState::Private);
|
||||||
|
REQUIRE(result.Code() == RESULT_SUCCESS);
|
||||||
|
|
||||||
|
ResultCode code = manager->ReprotectRange(Memory::HEAP_VADDR, block->size(),
|
||||||
|
Kernel::VMAPermission::ReadWrite);
|
||||||
|
REQUIRE(code == RESULT_SUCCESS);
|
||||||
|
|
||||||
|
SECTION("with invalid address") {
|
||||||
|
ResultCode code = manager->ChangeMemoryState(
|
||||||
|
0xFFFFFFFF, block->size(), Kernel::MemoryState::Locked,
|
||||||
|
Kernel::VMAPermission::ReadWrite, Kernel::MemoryState::Aliased,
|
||||||
|
Kernel::VMAPermission::Execute);
|
||||||
|
CHECK(code == Kernel::ERR_INVALID_ADDRESS);
|
||||||
|
}
|
||||||
|
|
||||||
|
SECTION("ignoring the original permissions") {
|
||||||
|
ResultCode code = manager->ChangeMemoryState(
|
||||||
|
Memory::HEAP_VADDR, block->size(), Kernel::MemoryState::Private,
|
||||||
|
Kernel::VMAPermission::None, Kernel::MemoryState::Locked,
|
||||||
|
Kernel::VMAPermission::Write);
|
||||||
|
CHECK(code == RESULT_SUCCESS);
|
||||||
|
|
||||||
|
auto vma = manager->FindVMA(Memory::HEAP_VADDR);
|
||||||
|
CHECK(vma != manager->vma_map.end());
|
||||||
|
CHECK(vma->second.permissions == Kernel::VMAPermission::Write);
|
||||||
|
CHECK(vma->second.meminfo_state == Kernel::MemoryState::Locked);
|
||||||
|
}
|
||||||
|
|
||||||
|
SECTION("enforcing the original permissions with correct expectations") {
|
||||||
|
ResultCode code = manager->ChangeMemoryState(
|
||||||
|
Memory::HEAP_VADDR, block->size(), Kernel::MemoryState::Private,
|
||||||
|
Kernel::VMAPermission::ReadWrite, Kernel::MemoryState::Aliased,
|
||||||
|
Kernel::VMAPermission::Execute);
|
||||||
|
CHECK(code == RESULT_SUCCESS);
|
||||||
|
|
||||||
|
auto vma = manager->FindVMA(Memory::HEAP_VADDR);
|
||||||
|
CHECK(vma != manager->vma_map.end());
|
||||||
|
CHECK(vma->second.permissions == Kernel::VMAPermission::Execute);
|
||||||
|
CHECK(vma->second.meminfo_state == Kernel::MemoryState::Aliased);
|
||||||
|
}
|
||||||
|
|
||||||
|
SECTION("with incorrect permission expectations") {
|
||||||
|
ResultCode code = manager->ChangeMemoryState(
|
||||||
|
Memory::HEAP_VADDR, block->size(), Kernel::MemoryState::Private,
|
||||||
|
Kernel::VMAPermission::Execute, Kernel::MemoryState::Aliased,
|
||||||
|
Kernel::VMAPermission::Execute);
|
||||||
|
CHECK(code == Kernel::ERR_INVALID_ADDRESS_STATE);
|
||||||
|
|
||||||
|
auto vma = manager->FindVMA(Memory::HEAP_VADDR);
|
||||||
|
CHECK(vma != manager->vma_map.end());
|
||||||
|
CHECK(vma->second.permissions == Kernel::VMAPermission::ReadWrite);
|
||||||
|
CHECK(vma->second.meminfo_state == Kernel::MemoryState::Private);
|
||||||
|
}
|
||||||
|
|
||||||
|
SECTION("with incorrect state expectations") {
|
||||||
|
ResultCode code = manager->ChangeMemoryState(
|
||||||
|
Memory::HEAP_VADDR, block->size(), Kernel::MemoryState::Locked,
|
||||||
|
Kernel::VMAPermission::ReadWrite, Kernel::MemoryState::Aliased,
|
||||||
|
Kernel::VMAPermission::Execute);
|
||||||
|
CHECK(code == Kernel::ERR_INVALID_ADDRESS_STATE);
|
||||||
|
|
||||||
|
auto vma = manager->FindVMA(Memory::HEAP_VADDR);
|
||||||
|
CHECK(vma != manager->vma_map.end());
|
||||||
|
CHECK(vma->second.permissions == Kernel::VMAPermission::ReadWrite);
|
||||||
|
CHECK(vma->second.meminfo_state == Kernel::MemoryState::Private);
|
||||||
|
}
|
||||||
|
|
||||||
|
code = manager->UnmapRange(Memory::HEAP_VADDR, block->size());
|
||||||
|
REQUIRE(code == RESULT_SUCCESS);
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user