core: Respect memory permissions in Map

This commit is contained in:
GPUCode 2023-11-17 21:43:15 +02:00 committed by t895
parent 4766baddf3
commit 5938a9582a
6 changed files with 117 additions and 58 deletions

View file

@ -144,7 +144,7 @@ public:
Release(); Release();
} }
void Map(size_t virtual_offset, size_t host_offset, size_t length) { void Map(size_t virtual_offset, size_t host_offset, size_t length, MemoryPermission perms) {
std::unique_lock lock{placeholder_mutex}; std::unique_lock lock{placeholder_mutex};
if (!IsNiechePlaceholder(virtual_offset, length)) { if (!IsNiechePlaceholder(virtual_offset, length)) {
Split(virtual_offset, length); Split(virtual_offset, length);
@ -163,7 +163,7 @@ public:
} }
} }
void Protect(size_t virtual_offset, size_t length, bool read, bool write) { void Protect(size_t virtual_offset, size_t length, bool read, bool write, bool execute) {
DWORD new_flags{}; DWORD new_flags{};
if (read && write) { if (read && write) {
new_flags = PAGE_READWRITE; new_flags = PAGE_READWRITE;
@ -494,15 +494,29 @@ public:
Release(); Release();
} }
void Map(size_t virtual_offset, size_t host_offset, size_t length) { void Map(size_t virtual_offset, size_t host_offset, size_t length, MemoryPermission perms) {
// Intersect the range with our address space. // Intersect the range with our address space.
AdjustMap(&virtual_offset, &length); AdjustMap(&virtual_offset, &length);
// We are removing a placeholder. // We are removing a placeholder.
free_manager.AllocateBlock(virtual_base + virtual_offset, length); free_manager.AllocateBlock(virtual_base + virtual_offset, length);
void* ret = mmap(virtual_base + virtual_offset, length, PROT_READ | PROT_WRITE, // Deduce mapping protection flags.
MAP_SHARED | MAP_FIXED, fd, host_offset); int flags = PROT_NONE;
if (True(perms & MemoryPermission::Read)) {
flags |= PROT_READ;
}
if (True(perms & MemoryPermission::Write)) {
flags |= PROT_WRITE;
}
#ifdef ARCHITECTURE_arm64
if (True(perms & MemoryPermission::Execute)) {
flags |= PROT_EXEC;
}
#endif
void* ret = mmap(virtual_base + virtual_offset, length, flags, MAP_SHARED | MAP_FIXED, fd,
host_offset);
ASSERT_MSG(ret != MAP_FAILED, "mmap failed: {}", strerror(errno)); ASSERT_MSG(ret != MAP_FAILED, "mmap failed: {}", strerror(errno));
} }
@ -522,7 +536,7 @@ public:
ASSERT_MSG(ret != MAP_FAILED, "mmap failed: {}", strerror(errno)); ASSERT_MSG(ret != MAP_FAILED, "mmap failed: {}", strerror(errno));
} }
void Protect(size_t virtual_offset, size_t length, bool read, bool write) { void Protect(size_t virtual_offset, size_t length, bool read, bool write, bool execute) {
// Intersect the range with our address space. // Intersect the range with our address space.
AdjustMap(&virtual_offset, &length); AdjustMap(&virtual_offset, &length);
@ -533,6 +547,11 @@ public:
if (write) { if (write) {
flags |= PROT_WRITE; flags |= PROT_WRITE;
} }
#ifdef ARCHITECTURE_arm64
if (execute) {
flags |= PROT_EXEC;
}
#endif
int ret = mprotect(virtual_base + virtual_offset, length, flags); int ret = mprotect(virtual_base + virtual_offset, length, flags);
ASSERT_MSG(ret == 0, "mprotect failed: {}", strerror(errno)); ASSERT_MSG(ret == 0, "mprotect failed: {}", strerror(errno));
} }
@ -602,11 +621,11 @@ public:
throw std::bad_alloc{}; throw std::bad_alloc{};
} }
void Map(size_t virtual_offset, size_t host_offset, size_t length) {} void Map(size_t virtual_offset, size_t host_offset, size_t length, MemoryPermission perm) {}
void Unmap(size_t virtual_offset, size_t length) {} void Unmap(size_t virtual_offset, size_t length) {}
void Protect(size_t virtual_offset, size_t length, bool read, bool write) {} void Protect(size_t virtual_offset, size_t length, bool read, bool write, bool execute) {}
u8* backing_base{nullptr}; u8* backing_base{nullptr};
u8* virtual_base{nullptr}; u8* virtual_base{nullptr};
@ -647,7 +666,8 @@ HostMemory::HostMemory(HostMemory&&) noexcept = default;
HostMemory& HostMemory::operator=(HostMemory&&) noexcept = default; HostMemory& HostMemory::operator=(HostMemory&&) noexcept = default;
void HostMemory::Map(size_t virtual_offset, size_t host_offset, size_t length) { void HostMemory::Map(size_t virtual_offset, size_t host_offset, size_t length,
MemoryPermission perms) {
ASSERT(virtual_offset % PageAlignment == 0); ASSERT(virtual_offset % PageAlignment == 0);
ASSERT(host_offset % PageAlignment == 0); ASSERT(host_offset % PageAlignment == 0);
ASSERT(length % PageAlignment == 0); ASSERT(length % PageAlignment == 0);
@ -656,7 +676,7 @@ void HostMemory::Map(size_t virtual_offset, size_t host_offset, size_t length) {
if (length == 0 || !virtual_base || !impl) { if (length == 0 || !virtual_base || !impl) {
return; return;
} }
impl->Map(virtual_offset + virtual_base_offset, host_offset, length); impl->Map(virtual_offset + virtual_base_offset, host_offset, length, perms);
} }
void HostMemory::Unmap(size_t virtual_offset, size_t length) { void HostMemory::Unmap(size_t virtual_offset, size_t length) {
@ -669,14 +689,15 @@ void HostMemory::Unmap(size_t virtual_offset, size_t length) {
impl->Unmap(virtual_offset + virtual_base_offset, length); impl->Unmap(virtual_offset + virtual_base_offset, length);
} }
void HostMemory::Protect(size_t virtual_offset, size_t length, bool read, bool write) { void HostMemory::Protect(size_t virtual_offset, size_t length, bool read, bool write,
bool execute) {
ASSERT(virtual_offset % PageAlignment == 0); ASSERT(virtual_offset % PageAlignment == 0);
ASSERT(length % PageAlignment == 0); ASSERT(length % PageAlignment == 0);
ASSERT(virtual_offset + length <= virtual_size); ASSERT(virtual_offset + length <= virtual_size);
if (length == 0 || !virtual_base || !impl) { if (length == 0 || !virtual_base || !impl) {
return; return;
} }
impl->Protect(virtual_offset + virtual_base_offset, length, read, write); impl->Protect(virtual_offset + virtual_base_offset, length, read, write, execute);
} }
void HostMemory::EnableDirectMappedAddress() { void HostMemory::EnableDirectMappedAddress() {

View file

@ -4,11 +4,20 @@
#pragma once #pragma once
#include <memory> #include <memory>
#include "common/common_funcs.h"
#include "common/common_types.h" #include "common/common_types.h"
#include "common/virtual_buffer.h" #include "common/virtual_buffer.h"
namespace Common { namespace Common {
enum class MemoryPermission : u32 {
Read = 1 << 0,
Write = 1 << 1,
ReadWrite = Read | Write,
Execute = 1 << 2,
};
DECLARE_ENUM_FLAG_OPERATORS(MemoryPermission)
/** /**
* A low level linear memory buffer, which supports multiple mappings * A low level linear memory buffer, which supports multiple mappings
* Its purpose is to rebuild a given sparse memory layout, including mirrors. * Its purpose is to rebuild a given sparse memory layout, including mirrors.
@ -31,11 +40,11 @@ public:
HostMemory(HostMemory&& other) noexcept; HostMemory(HostMemory&& other) noexcept;
HostMemory& operator=(HostMemory&& other) noexcept; HostMemory& operator=(HostMemory&& other) noexcept;
void Map(size_t virtual_offset, size_t host_offset, size_t length); void Map(size_t virtual_offset, size_t host_offset, size_t length, MemoryPermission perms);
void Unmap(size_t virtual_offset, size_t length); void Unmap(size_t virtual_offset, size_t length);
void Protect(size_t virtual_offset, size_t length, bool read, bool write); void Protect(size_t virtual_offset, size_t length, bool read, bool write, bool execute = false);
void EnableDirectMappedAddress(); void EnableDirectMappedAddress();

View file

@ -88,6 +88,20 @@ Result FlushDataCache(AddressType addr, u64 size) {
R_SUCCEED(); R_SUCCEED();
} }
constexpr Common::MemoryPermission ConvertToMemoryPermission(KMemoryPermission perm) {
Common::MemoryPermission perms{};
if (True(perm & KMemoryPermission::UserRead)) {
perms |= Common::MemoryPermission::Read;
}
if (True(perm & KMemoryPermission::UserWrite)) {
perms |= Common::MemoryPermission::Write;
}
if (True(perm & KMemoryPermission::UserExecute)) {
perms |= Common::MemoryPermission::Execute;
}
return perms;
}
} // namespace } // namespace
void KPageTableBase::MemoryRange::Open() { void KPageTableBase::MemoryRange::Open() {
@ -5643,7 +5657,8 @@ Result KPageTableBase::Operate(PageLinkedList* page_list, KProcessAddress virt_a
case OperationType::Map: { case OperationType::Map: {
ASSERT(virt_addr != 0); ASSERT(virt_addr != 0);
ASSERT(Common::IsAligned(GetInteger(virt_addr), PageSize)); ASSERT(Common::IsAligned(GetInteger(virt_addr), PageSize));
m_memory->MapMemoryRegion(*m_impl, virt_addr, num_pages * PageSize, phys_addr); m_memory->MapMemoryRegion(*m_impl, virt_addr, num_pages * PageSize, phys_addr,
ConvertToMemoryPermission(properties.perm));
// Open references to pages, if we should. // Open references to pages, if we should.
if (this->IsHeapPhysicalAddress(phys_addr)) { if (this->IsHeapPhysicalAddress(phys_addr)) {
@ -5658,8 +5673,18 @@ Result KPageTableBase::Operate(PageLinkedList* page_list, KProcessAddress virt_a
} }
case OperationType::ChangePermissions: case OperationType::ChangePermissions:
case OperationType::ChangePermissionsAndRefresh: case OperationType::ChangePermissionsAndRefresh:
case OperationType::ChangePermissionsAndRefreshAndFlush: case OperationType::ChangePermissionsAndRefreshAndFlush: {
const bool read = True(properties.perm & Kernel::KMemoryPermission::UserRead);
const bool write = True(properties.perm & Kernel::KMemoryPermission::UserWrite);
// todo: this doesn't really belong here and should go into m_memory to handle rasterizer
// access todo: ignore exec on non-direct-mapped case
const bool exec = True(properties.perm & Kernel::KMemoryPermission::UserExecute);
if (Settings::IsFastmemEnabled()) {
m_system.DeviceMemory().buffer.Protect(GetInteger(virt_addr), num_pages * PageSize,
read, write, exec);
}
R_SUCCEED(); R_SUCCEED();
}
default: default:
UNREACHABLE(); UNREACHABLE();
} }
@ -5687,7 +5712,8 @@ Result KPageTableBase::Operate(PageLinkedList* page_list, KProcessAddress virt_a
const size_t size{node.GetNumPages() * PageSize}; const size_t size{node.GetNumPages() * PageSize};
// Map the pages. // Map the pages.
m_memory->MapMemoryRegion(*m_impl, virt_addr, size, node.GetAddress()); m_memory->MapMemoryRegion(*m_impl, virt_addr, size, node.GetAddress(),
ConvertToMemoryPermission(properties.perm));
virt_addr += size; virt_addr += size;
} }

View file

@ -53,7 +53,7 @@ struct Memory::Impl {
} }
void MapMemoryRegion(Common::PageTable& page_table, Common::ProcessAddress base, u64 size, void MapMemoryRegion(Common::PageTable& page_table, Common::ProcessAddress base, u64 size,
Common::PhysicalAddress target) { Common::PhysicalAddress target, Common::MemoryPermission perms) {
ASSERT_MSG((size & YUZU_PAGEMASK) == 0, "non-page aligned size: {:016X}", size); ASSERT_MSG((size & YUZU_PAGEMASK) == 0, "non-page aligned size: {:016X}", size);
ASSERT_MSG((base & YUZU_PAGEMASK) == 0, "non-page aligned base: {:016X}", GetInteger(base)); ASSERT_MSG((base & YUZU_PAGEMASK) == 0, "non-page aligned base: {:016X}", GetInteger(base));
ASSERT_MSG(target >= DramMemoryMap::Base, "Out of bounds target: {:016X}", ASSERT_MSG(target >= DramMemoryMap::Base, "Out of bounds target: {:016X}",
@ -63,7 +63,7 @@ struct Memory::Impl {
if (Settings::IsFastmemEnabled()) { if (Settings::IsFastmemEnabled()) {
system.DeviceMemory().buffer.Map(GetInteger(base), system.DeviceMemory().buffer.Map(GetInteger(base),
GetInteger(target) - DramMemoryMap::Base, size); GetInteger(target) - DramMemoryMap::Base, size, perms);
} }
} }
@ -831,8 +831,8 @@ void Memory::SetCurrentPageTable(Kernel::KProcess& process, u32 core_id) {
} }
void Memory::MapMemoryRegion(Common::PageTable& page_table, Common::ProcessAddress base, u64 size, void Memory::MapMemoryRegion(Common::PageTable& page_table, Common::ProcessAddress base, u64 size,
Common::PhysicalAddress target) { Common::PhysicalAddress target, Common::MemoryPermission perms) {
impl->MapMemoryRegion(page_table, base, size, target); impl->MapMemoryRegion(page_table, base, size, target, perms);
} }
void Memory::UnmapRegion(Common::PageTable& page_table, Common::ProcessAddress base, u64 size) { void Memory::UnmapRegion(Common::PageTable& page_table, Common::ProcessAddress base, u64 size) {

View file

@ -15,8 +15,9 @@
#include "core/hle/result.h" #include "core/hle/result.h"
namespace Common { namespace Common {
enum class MemoryPermission : u32;
struct PageTable; struct PageTable;
} } // namespace Common
namespace Core { namespace Core {
class System; class System;
@ -82,9 +83,10 @@ public:
* @param size The amount of bytes to map. Must be page-aligned. * @param size The amount of bytes to map. Must be page-aligned.
* @param target Buffer with the memory backing the mapping. Must be of length at least * @param target Buffer with the memory backing the mapping. Must be of length at least
* `size`. * `size`.
* @param perms The permissions to map the memory with.
*/ */
void MapMemoryRegion(Common::PageTable& page_table, Common::ProcessAddress base, u64 size, void MapMemoryRegion(Common::PageTable& page_table, Common::ProcessAddress base, u64 size,
Common::PhysicalAddress target); Common::PhysicalAddress target, Common::MemoryPermission perms);
/** /**
* Unmaps a region of the emulated process address space. * Unmaps a region of the emulated process address space.

View file

@ -11,6 +11,7 @@ using namespace Common::Literals;
static constexpr size_t VIRTUAL_SIZE = 1ULL << 39; static constexpr size_t VIRTUAL_SIZE = 1ULL << 39;
static constexpr size_t BACKING_SIZE = 4_GiB; static constexpr size_t BACKING_SIZE = 4_GiB;
static constexpr auto PERMS = Common::MemoryPermission::ReadWrite;
TEST_CASE("HostMemory: Initialize and deinitialize", "[common]") { TEST_CASE("HostMemory: Initialize and deinitialize", "[common]") {
{ HostMemory mem(BACKING_SIZE, VIRTUAL_SIZE); } { HostMemory mem(BACKING_SIZE, VIRTUAL_SIZE); }
@ -19,7 +20,7 @@ TEST_CASE("HostMemory: Initialize and deinitialize", "[common]") {
TEST_CASE("HostMemory: Simple map", "[common]") { TEST_CASE("HostMemory: Simple map", "[common]") {
HostMemory mem(BACKING_SIZE, VIRTUAL_SIZE); HostMemory mem(BACKING_SIZE, VIRTUAL_SIZE);
mem.Map(0x5000, 0x8000, 0x1000); mem.Map(0x5000, 0x8000, 0x1000, PERMS);
volatile u8* const data = mem.VirtualBasePointer() + 0x5000; volatile u8* const data = mem.VirtualBasePointer() + 0x5000;
data[0] = 50; data[0] = 50;
@ -28,8 +29,8 @@ TEST_CASE("HostMemory: Simple map", "[common]") {
TEST_CASE("HostMemory: Simple mirror map", "[common]") { TEST_CASE("HostMemory: Simple mirror map", "[common]") {
HostMemory mem(BACKING_SIZE, VIRTUAL_SIZE); HostMemory mem(BACKING_SIZE, VIRTUAL_SIZE);
mem.Map(0x5000, 0x3000, 0x2000); mem.Map(0x5000, 0x3000, 0x2000, PERMS);
mem.Map(0x8000, 0x4000, 0x1000); mem.Map(0x8000, 0x4000, 0x1000, PERMS);
volatile u8* const mirror_a = mem.VirtualBasePointer() + 0x5000; volatile u8* const mirror_a = mem.VirtualBasePointer() + 0x5000;
volatile u8* const mirror_b = mem.VirtualBasePointer() + 0x8000; volatile u8* const mirror_b = mem.VirtualBasePointer() + 0x8000;
@ -39,7 +40,7 @@ TEST_CASE("HostMemory: Simple mirror map", "[common]") {
TEST_CASE("HostMemory: Simple unmap", "[common]") { TEST_CASE("HostMemory: Simple unmap", "[common]") {
HostMemory mem(BACKING_SIZE, VIRTUAL_SIZE); HostMemory mem(BACKING_SIZE, VIRTUAL_SIZE);
mem.Map(0x5000, 0x3000, 0x2000); mem.Map(0x5000, 0x3000, 0x2000, PERMS);
volatile u8* const data = mem.VirtualBasePointer() + 0x5000; volatile u8* const data = mem.VirtualBasePointer() + 0x5000;
data[75] = 50; data[75] = 50;
@ -50,7 +51,7 @@ TEST_CASE("HostMemory: Simple unmap", "[common]") {
TEST_CASE("HostMemory: Simple unmap and remap", "[common]") { TEST_CASE("HostMemory: Simple unmap and remap", "[common]") {
HostMemory mem(BACKING_SIZE, VIRTUAL_SIZE); HostMemory mem(BACKING_SIZE, VIRTUAL_SIZE);
mem.Map(0x5000, 0x3000, 0x2000); mem.Map(0x5000, 0x3000, 0x2000, PERMS);
volatile u8* const data = mem.VirtualBasePointer() + 0x5000; volatile u8* const data = mem.VirtualBasePointer() + 0x5000;
data[0] = 50; data[0] = 50;
@ -58,79 +59,79 @@ TEST_CASE("HostMemory: Simple unmap and remap", "[common]") {
mem.Unmap(0x5000, 0x2000); mem.Unmap(0x5000, 0x2000);
mem.Map(0x5000, 0x3000, 0x2000); mem.Map(0x5000, 0x3000, 0x2000, PERMS);
REQUIRE(data[0] == 50); REQUIRE(data[0] == 50);
mem.Map(0x7000, 0x2000, 0x5000); mem.Map(0x7000, 0x2000, 0x5000, PERMS);
REQUIRE(data[0x3000] == 50); REQUIRE(data[0x3000] == 50);
} }
TEST_CASE("HostMemory: Nieche allocation", "[common]") { TEST_CASE("HostMemory: Nieche allocation", "[common]") {
HostMemory mem(BACKING_SIZE, VIRTUAL_SIZE); HostMemory mem(BACKING_SIZE, VIRTUAL_SIZE);
mem.Map(0x0000, 0, 0x20000); mem.Map(0x0000, 0, 0x20000, PERMS);
mem.Unmap(0x0000, 0x4000); mem.Unmap(0x0000, 0x4000);
mem.Map(0x1000, 0, 0x2000); mem.Map(0x1000, 0, 0x2000, PERMS);
mem.Map(0x3000, 0, 0x1000); mem.Map(0x3000, 0, 0x1000, PERMS);
mem.Map(0, 0, 0x1000); mem.Map(0, 0, 0x1000, PERMS);
} }
TEST_CASE("HostMemory: Full unmap", "[common]") { TEST_CASE("HostMemory: Full unmap", "[common]") {
HostMemory mem(BACKING_SIZE, VIRTUAL_SIZE); HostMemory mem(BACKING_SIZE, VIRTUAL_SIZE);
mem.Map(0x8000, 0, 0x4000); mem.Map(0x8000, 0, 0x4000, PERMS);
mem.Unmap(0x8000, 0x4000); mem.Unmap(0x8000, 0x4000);
mem.Map(0x6000, 0, 0x16000); mem.Map(0x6000, 0, 0x16000, PERMS);
} }
TEST_CASE("HostMemory: Right out of bounds unmap", "[common]") { TEST_CASE("HostMemory: Right out of bounds unmap", "[common]") {
HostMemory mem(BACKING_SIZE, VIRTUAL_SIZE); HostMemory mem(BACKING_SIZE, VIRTUAL_SIZE);
mem.Map(0x0000, 0, 0x4000); mem.Map(0x0000, 0, 0x4000, PERMS);
mem.Unmap(0x2000, 0x4000); mem.Unmap(0x2000, 0x4000);
mem.Map(0x2000, 0x80000, 0x4000); mem.Map(0x2000, 0x80000, 0x4000, PERMS);
} }
TEST_CASE("HostMemory: Left out of bounds unmap", "[common]") { TEST_CASE("HostMemory: Left out of bounds unmap", "[common]") {
HostMemory mem(BACKING_SIZE, VIRTUAL_SIZE); HostMemory mem(BACKING_SIZE, VIRTUAL_SIZE);
mem.Map(0x8000, 0, 0x4000); mem.Map(0x8000, 0, 0x4000, PERMS);
mem.Unmap(0x6000, 0x4000); mem.Unmap(0x6000, 0x4000);
mem.Map(0x8000, 0, 0x2000); mem.Map(0x8000, 0, 0x2000, PERMS);
} }
TEST_CASE("HostMemory: Multiple placeholder unmap", "[common]") { TEST_CASE("HostMemory: Multiple placeholder unmap", "[common]") {
HostMemory mem(BACKING_SIZE, VIRTUAL_SIZE); HostMemory mem(BACKING_SIZE, VIRTUAL_SIZE);
mem.Map(0x0000, 0, 0x4000); mem.Map(0x0000, 0, 0x4000, PERMS);
mem.Map(0x4000, 0, 0x1b000); mem.Map(0x4000, 0, 0x1b000, PERMS);
mem.Unmap(0x3000, 0x1c000); mem.Unmap(0x3000, 0x1c000);
mem.Map(0x3000, 0, 0x20000); mem.Map(0x3000, 0, 0x20000, PERMS);
} }
TEST_CASE("HostMemory: Unmap between placeholders", "[common]") { TEST_CASE("HostMemory: Unmap between placeholders", "[common]") {
HostMemory mem(BACKING_SIZE, VIRTUAL_SIZE); HostMemory mem(BACKING_SIZE, VIRTUAL_SIZE);
mem.Map(0x0000, 0, 0x4000); mem.Map(0x0000, 0, 0x4000, PERMS);
mem.Map(0x4000, 0, 0x4000); mem.Map(0x4000, 0, 0x4000, PERMS);
mem.Unmap(0x2000, 0x4000); mem.Unmap(0x2000, 0x4000);
mem.Map(0x2000, 0, 0x4000); mem.Map(0x2000, 0, 0x4000, PERMS);
} }
TEST_CASE("HostMemory: Unmap to origin", "[common]") { TEST_CASE("HostMemory: Unmap to origin", "[common]") {
HostMemory mem(BACKING_SIZE, VIRTUAL_SIZE); HostMemory mem(BACKING_SIZE, VIRTUAL_SIZE);
mem.Map(0x4000, 0, 0x4000); mem.Map(0x4000, 0, 0x4000, PERMS);
mem.Map(0x8000, 0, 0x4000); mem.Map(0x8000, 0, 0x4000, PERMS);
mem.Unmap(0x4000, 0x4000); mem.Unmap(0x4000, 0x4000);
mem.Map(0, 0, 0x4000); mem.Map(0, 0, 0x4000, PERMS);
mem.Map(0x4000, 0, 0x4000); mem.Map(0x4000, 0, 0x4000, PERMS);
} }
TEST_CASE("HostMemory: Unmap to right", "[common]") { TEST_CASE("HostMemory: Unmap to right", "[common]") {
HostMemory mem(BACKING_SIZE, VIRTUAL_SIZE); HostMemory mem(BACKING_SIZE, VIRTUAL_SIZE);
mem.Map(0x4000, 0, 0x4000); mem.Map(0x4000, 0, 0x4000, PERMS);
mem.Map(0x8000, 0, 0x4000); mem.Map(0x8000, 0, 0x4000, PERMS);
mem.Unmap(0x8000, 0x4000); mem.Unmap(0x8000, 0x4000);
mem.Map(0x8000, 0, 0x4000); mem.Map(0x8000, 0, 0x4000, PERMS);
} }
TEST_CASE("HostMemory: Partial right unmap check bindings", "[common]") { TEST_CASE("HostMemory: Partial right unmap check bindings", "[common]") {
HostMemory mem(BACKING_SIZE, VIRTUAL_SIZE); HostMemory mem(BACKING_SIZE, VIRTUAL_SIZE);
mem.Map(0x4000, 0x10000, 0x4000); mem.Map(0x4000, 0x10000, 0x4000, PERMS);
volatile u8* const ptr = mem.VirtualBasePointer() + 0x4000; volatile u8* const ptr = mem.VirtualBasePointer() + 0x4000;
ptr[0x1000] = 17; ptr[0x1000] = 17;
@ -142,7 +143,7 @@ TEST_CASE("HostMemory: Partial right unmap check bindings", "[common]") {
TEST_CASE("HostMemory: Partial left unmap check bindings", "[common]") { TEST_CASE("HostMemory: Partial left unmap check bindings", "[common]") {
HostMemory mem(BACKING_SIZE, VIRTUAL_SIZE); HostMemory mem(BACKING_SIZE, VIRTUAL_SIZE);
mem.Map(0x4000, 0x10000, 0x4000); mem.Map(0x4000, 0x10000, 0x4000, PERMS);
volatile u8* const ptr = mem.VirtualBasePointer() + 0x4000; volatile u8* const ptr = mem.VirtualBasePointer() + 0x4000;
ptr[0x3000] = 19; ptr[0x3000] = 19;
@ -156,7 +157,7 @@ TEST_CASE("HostMemory: Partial left unmap check bindings", "[common]") {
TEST_CASE("HostMemory: Partial middle unmap check bindings", "[common]") { TEST_CASE("HostMemory: Partial middle unmap check bindings", "[common]") {
HostMemory mem(BACKING_SIZE, VIRTUAL_SIZE); HostMemory mem(BACKING_SIZE, VIRTUAL_SIZE);
mem.Map(0x4000, 0x10000, 0x4000); mem.Map(0x4000, 0x10000, 0x4000, PERMS);
volatile u8* const ptr = mem.VirtualBasePointer() + 0x4000; volatile u8* const ptr = mem.VirtualBasePointer() + 0x4000;
ptr[0x0000] = 19; ptr[0x0000] = 19;
@ -170,8 +171,8 @@ TEST_CASE("HostMemory: Partial middle unmap check bindings", "[common]") {
TEST_CASE("HostMemory: Partial sparse middle unmap and check bindings", "[common]") { TEST_CASE("HostMemory: Partial sparse middle unmap and check bindings", "[common]") {
HostMemory mem(BACKING_SIZE, VIRTUAL_SIZE); HostMemory mem(BACKING_SIZE, VIRTUAL_SIZE);
mem.Map(0x4000, 0x10000, 0x2000); mem.Map(0x4000, 0x10000, 0x2000, PERMS);
mem.Map(0x6000, 0x20000, 0x2000); mem.Map(0x6000, 0x20000, 0x2000, PERMS);
volatile u8* const ptr = mem.VirtualBasePointer() + 0x4000; volatile u8* const ptr = mem.VirtualBasePointer() + 0x4000;
ptr[0x0000] = 19; ptr[0x0000] = 19;