diff options
| author | 2023-11-17 21:43:15 +0200 | |
|---|---|---|
| committer | 2023-11-25 00:46:15 -0500 | |
| commit | 5938a9582a238d7679eb15f9812f8a85bfdb1cc3 (patch) | |
| tree | 935356a1cc03fea528e349d5027f2d885537272a /src | |
| parent | host_memory: Switch to FreeRegionManager (diff) | |
| download | yuzu-5938a9582a238d7679eb15f9812f8a85bfdb1cc3.tar.gz yuzu-5938a9582a238d7679eb15f9812f8a85bfdb1cc3.tar.xz yuzu-5938a9582a238d7679eb15f9812f8a85bfdb1cc3.zip | |
core: Respect memory permissions in Map
Diffstat (limited to 'src')
| -rw-r--r-- | src/common/host_memory.cpp | 45 | ||||
| -rw-r--r-- | src/common/host_memory.h | 13 | ||||
| -rw-r--r-- | src/core/hle/kernel/k_page_table_base.cpp | 32 | ||||
| -rw-r--r-- | src/core/memory.cpp | 8 | ||||
| -rw-r--r-- | src/core/memory.h | 6 | ||||
| -rw-r--r-- | src/tests/common/host_memory.cpp | 71 |
6 files changed, 117 insertions, 58 deletions
diff --git a/src/common/host_memory.cpp b/src/common/host_memory.cpp index a66fc49e2..3e4b34de6 100644 --- a/src/common/host_memory.cpp +++ b/src/common/host_memory.cpp | |||
| @@ -144,7 +144,7 @@ public: | |||
| 144 | Release(); | 144 | Release(); |
| 145 | } | 145 | } |
| 146 | 146 | ||
| 147 | void Map(size_t virtual_offset, size_t host_offset, size_t length) { | 147 | void Map(size_t virtual_offset, size_t host_offset, size_t length, MemoryPermission perms) { |
| 148 | std::unique_lock lock{placeholder_mutex}; | 148 | std::unique_lock lock{placeholder_mutex}; |
| 149 | if (!IsNiechePlaceholder(virtual_offset, length)) { | 149 | if (!IsNiechePlaceholder(virtual_offset, length)) { |
| 150 | Split(virtual_offset, length); | 150 | Split(virtual_offset, length); |
| @@ -163,7 +163,7 @@ public: | |||
| 163 | } | 163 | } |
| 164 | } | 164 | } |
| 165 | 165 | ||
| 166 | void Protect(size_t virtual_offset, size_t length, bool read, bool write) { | 166 | void Protect(size_t virtual_offset, size_t length, bool read, bool write, bool execute) { |
| 167 | DWORD new_flags{}; | 167 | DWORD new_flags{}; |
| 168 | if (read && write) { | 168 | if (read && write) { |
| 169 | new_flags = PAGE_READWRITE; | 169 | new_flags = PAGE_READWRITE; |
| @@ -494,15 +494,29 @@ public: | |||
| 494 | Release(); | 494 | Release(); |
| 495 | } | 495 | } |
| 496 | 496 | ||
| 497 | void Map(size_t virtual_offset, size_t host_offset, size_t length) { | 497 | void Map(size_t virtual_offset, size_t host_offset, size_t length, MemoryPermission perms) { |
| 498 | // Intersect the range with our address space. | 498 | // Intersect the range with our address space. |
| 499 | AdjustMap(&virtual_offset, &length); | 499 | AdjustMap(&virtual_offset, &length); |
| 500 | 500 | ||
| 501 | // We are removing a placeholder. | 501 | // We are removing a placeholder. |
| 502 | free_manager.AllocateBlock(virtual_base + virtual_offset, length); | 502 | free_manager.AllocateBlock(virtual_base + virtual_offset, length); |
| 503 | 503 | ||
| 504 | void* ret = mmap(virtual_base + virtual_offset, length, PROT_READ | PROT_WRITE, | 504 | // Deduce mapping protection flags. |
| 505 | MAP_SHARED | MAP_FIXED, fd, host_offset); | 505 | int flags = PROT_NONE; |
| 506 | if (True(perms & MemoryPermission::Read)) { | ||
| 507 | flags |= PROT_READ; | ||
| 508 | } | ||
| 509 | if (True(perms & MemoryPermission::Write)) { | ||
| 510 | flags |= PROT_WRITE; | ||
| 511 | } | ||
| 512 | #ifdef ARCHITECTURE_arm64 | ||
| 513 | if (True(perms & MemoryPermission::Execute)) { | ||
| 514 | flags |= PROT_EXEC; | ||
| 515 | } | ||
| 516 | #endif | ||
| 517 | |||
| 518 | void* ret = mmap(virtual_base + virtual_offset, length, flags, MAP_SHARED | MAP_FIXED, fd, | ||
| 519 | host_offset); | ||
| 506 | ASSERT_MSG(ret != MAP_FAILED, "mmap failed: {}", strerror(errno)); | 520 | ASSERT_MSG(ret != MAP_FAILED, "mmap failed: {}", strerror(errno)); |
| 507 | } | 521 | } |
| 508 | 522 | ||
| @@ -522,7 +536,7 @@ public: | |||
| 522 | ASSERT_MSG(ret != MAP_FAILED, "mmap failed: {}", strerror(errno)); | 536 | ASSERT_MSG(ret != MAP_FAILED, "mmap failed: {}", strerror(errno)); |
| 523 | } | 537 | } |
| 524 | 538 | ||
| 525 | void Protect(size_t virtual_offset, size_t length, bool read, bool write) { | 539 | void Protect(size_t virtual_offset, size_t length, bool read, bool write, bool execute) { |
| 526 | // Intersect the range with our address space. | 540 | // Intersect the range with our address space. |
| 527 | AdjustMap(&virtual_offset, &length); | 541 | AdjustMap(&virtual_offset, &length); |
| 528 | 542 | ||
| @@ -533,6 +547,11 @@ public: | |||
| 533 | if (write) { | 547 | if (write) { |
| 534 | flags |= PROT_WRITE; | 548 | flags |= PROT_WRITE; |
| 535 | } | 549 | } |
| 550 | #ifdef ARCHITECTURE_arm64 | ||
| 551 | if (execute) { | ||
| 552 | flags |= PROT_EXEC; | ||
| 553 | } | ||
| 554 | #endif | ||
| 536 | int ret = mprotect(virtual_base + virtual_offset, length, flags); | 555 | int ret = mprotect(virtual_base + virtual_offset, length, flags); |
| 537 | ASSERT_MSG(ret == 0, "mprotect failed: {}", strerror(errno)); | 556 | ASSERT_MSG(ret == 0, "mprotect failed: {}", strerror(errno)); |
| 538 | } | 557 | } |
| @@ -602,11 +621,11 @@ public: | |||
| 602 | throw std::bad_alloc{}; | 621 | throw std::bad_alloc{}; |
| 603 | } | 622 | } |
| 604 | 623 | ||
| 605 | void Map(size_t virtual_offset, size_t host_offset, size_t length) {} | 624 | void Map(size_t virtual_offset, size_t host_offset, size_t length, MemoryPermission perm) {} |
| 606 | 625 | ||
| 607 | void Unmap(size_t virtual_offset, size_t length) {} | 626 | void Unmap(size_t virtual_offset, size_t length) {} |
| 608 | 627 | ||
| 609 | void Protect(size_t virtual_offset, size_t length, bool read, bool write) {} | 628 | void Protect(size_t virtual_offset, size_t length, bool read, bool write, bool execute) {} |
| 610 | 629 | ||
| 611 | u8* backing_base{nullptr}; | 630 | u8* backing_base{nullptr}; |
| 612 | u8* virtual_base{nullptr}; | 631 | u8* virtual_base{nullptr}; |
| @@ -647,7 +666,8 @@ HostMemory::HostMemory(HostMemory&&) noexcept = default; | |||
| 647 | 666 | ||
| 648 | HostMemory& HostMemory::operator=(HostMemory&&) noexcept = default; | 667 | HostMemory& HostMemory::operator=(HostMemory&&) noexcept = default; |
| 649 | 668 | ||
| 650 | void HostMemory::Map(size_t virtual_offset, size_t host_offset, size_t length) { | 669 | void HostMemory::Map(size_t virtual_offset, size_t host_offset, size_t length, |
| 670 | MemoryPermission perms) { | ||
| 651 | ASSERT(virtual_offset % PageAlignment == 0); | 671 | ASSERT(virtual_offset % PageAlignment == 0); |
| 652 | ASSERT(host_offset % PageAlignment == 0); | 672 | ASSERT(host_offset % PageAlignment == 0); |
| 653 | ASSERT(length % PageAlignment == 0); | 673 | ASSERT(length % PageAlignment == 0); |
| @@ -656,7 +676,7 @@ void HostMemory::Map(size_t virtual_offset, size_t host_offset, size_t length) { | |||
| 656 | if (length == 0 || !virtual_base || !impl) { | 676 | if (length == 0 || !virtual_base || !impl) { |
| 657 | return; | 677 | return; |
| 658 | } | 678 | } |
| 659 | impl->Map(virtual_offset + virtual_base_offset, host_offset, length); | 679 | impl->Map(virtual_offset + virtual_base_offset, host_offset, length, perms); |
| 660 | } | 680 | } |
| 661 | 681 | ||
| 662 | void HostMemory::Unmap(size_t virtual_offset, size_t length) { | 682 | void HostMemory::Unmap(size_t virtual_offset, size_t length) { |
| @@ -669,14 +689,15 @@ void HostMemory::Unmap(size_t virtual_offset, size_t length) { | |||
| 669 | impl->Unmap(virtual_offset + virtual_base_offset, length); | 689 | impl->Unmap(virtual_offset + virtual_base_offset, length); |
| 670 | } | 690 | } |
| 671 | 691 | ||
| 672 | void HostMemory::Protect(size_t virtual_offset, size_t length, bool read, bool write) { | 692 | void HostMemory::Protect(size_t virtual_offset, size_t length, bool read, bool write, |
| 693 | bool execute) { | ||
| 673 | ASSERT(virtual_offset % PageAlignment == 0); | 694 | ASSERT(virtual_offset % PageAlignment == 0); |
| 674 | ASSERT(length % PageAlignment == 0); | 695 | ASSERT(length % PageAlignment == 0); |
| 675 | ASSERT(virtual_offset + length <= virtual_size); | 696 | ASSERT(virtual_offset + length <= virtual_size); |
| 676 | if (length == 0 || !virtual_base || !impl) { | 697 | if (length == 0 || !virtual_base || !impl) { |
| 677 | return; | 698 | return; |
| 678 | } | 699 | } |
| 679 | impl->Protect(virtual_offset + virtual_base_offset, length, read, write); | 700 | impl->Protect(virtual_offset + virtual_base_offset, length, read, write, execute); |
| 680 | } | 701 | } |
| 681 | 702 | ||
| 682 | void HostMemory::EnableDirectMappedAddress() { | 703 | void HostMemory::EnableDirectMappedAddress() { |
diff --git a/src/common/host_memory.h b/src/common/host_memory.h index 4014a1962..cebfacab2 100644 --- a/src/common/host_memory.h +++ b/src/common/host_memory.h | |||
| @@ -4,11 +4,20 @@ | |||
| 4 | #pragma once | 4 | #pragma once |
| 5 | 5 | ||
| 6 | #include <memory> | 6 | #include <memory> |
| 7 | #include "common/common_funcs.h" | ||
| 7 | #include "common/common_types.h" | 8 | #include "common/common_types.h" |
| 8 | #include "common/virtual_buffer.h" | 9 | #include "common/virtual_buffer.h" |
| 9 | 10 | ||
| 10 | namespace Common { | 11 | namespace Common { |
| 11 | 12 | ||
| 13 | enum class MemoryPermission : u32 { | ||
| 14 | Read = 1 << 0, | ||
| 15 | Write = 1 << 1, | ||
| 16 | ReadWrite = Read | Write, | ||
| 17 | Execute = 1 << 2, | ||
| 18 | }; | ||
| 19 | DECLARE_ENUM_FLAG_OPERATORS(MemoryPermission) | ||
| 20 | |||
| 12 | /** | 21 | /** |
| 13 | * A low level linear memory buffer, which supports multiple mappings | 22 | * A low level linear memory buffer, which supports multiple mappings |
| 14 | * Its purpose is to rebuild a given sparse memory layout, including mirrors. | 23 | * Its purpose is to rebuild a given sparse memory layout, including mirrors. |
| @@ -31,11 +40,11 @@ public: | |||
| 31 | HostMemory(HostMemory&& other) noexcept; | 40 | HostMemory(HostMemory&& other) noexcept; |
| 32 | HostMemory& operator=(HostMemory&& other) noexcept; | 41 | HostMemory& operator=(HostMemory&& other) noexcept; |
| 33 | 42 | ||
| 34 | void Map(size_t virtual_offset, size_t host_offset, size_t length); | 43 | void Map(size_t virtual_offset, size_t host_offset, size_t length, MemoryPermission perms); |
| 35 | 44 | ||
| 36 | void Unmap(size_t virtual_offset, size_t length); | 45 | void Unmap(size_t virtual_offset, size_t length); |
| 37 | 46 | ||
| 38 | void Protect(size_t virtual_offset, size_t length, bool read, bool write); | 47 | void Protect(size_t virtual_offset, size_t length, bool read, bool write, bool execute = false); |
| 39 | 48 | ||
| 40 | void EnableDirectMappedAddress(); | 49 | void EnableDirectMappedAddress(); |
| 41 | 50 | ||
diff --git a/src/core/hle/kernel/k_page_table_base.cpp b/src/core/hle/kernel/k_page_table_base.cpp index 47dc8fd35..dc6524146 100644 --- a/src/core/hle/kernel/k_page_table_base.cpp +++ b/src/core/hle/kernel/k_page_table_base.cpp | |||
| @@ -88,6 +88,20 @@ Result FlushDataCache(AddressType addr, u64 size) { | |||
| 88 | R_SUCCEED(); | 88 | R_SUCCEED(); |
| 89 | } | 89 | } |
| 90 | 90 | ||
| 91 | constexpr Common::MemoryPermission ConvertToMemoryPermission(KMemoryPermission perm) { | ||
| 92 | Common::MemoryPermission perms{}; | ||
| 93 | if (True(perm & KMemoryPermission::UserRead)) { | ||
| 94 | perms |= Common::MemoryPermission::Read; | ||
| 95 | } | ||
| 96 | if (True(perm & KMemoryPermission::UserWrite)) { | ||
| 97 | perms |= Common::MemoryPermission::Write; | ||
| 98 | } | ||
| 99 | if (True(perm & KMemoryPermission::UserExecute)) { | ||
| 100 | perms |= Common::MemoryPermission::Execute; | ||
| 101 | } | ||
| 102 | return perms; | ||
| 103 | } | ||
| 104 | |||
| 91 | } // namespace | 105 | } // namespace |
| 92 | 106 | ||
| 93 | void KPageTableBase::MemoryRange::Open() { | 107 | void KPageTableBase::MemoryRange::Open() { |
| @@ -5643,7 +5657,8 @@ Result KPageTableBase::Operate(PageLinkedList* page_list, KProcessAddress virt_a | |||
| 5643 | case OperationType::Map: { | 5657 | case OperationType::Map: { |
| 5644 | ASSERT(virt_addr != 0); | 5658 | ASSERT(virt_addr != 0); |
| 5645 | ASSERT(Common::IsAligned(GetInteger(virt_addr), PageSize)); | 5659 | ASSERT(Common::IsAligned(GetInteger(virt_addr), PageSize)); |
| 5646 | m_memory->MapMemoryRegion(*m_impl, virt_addr, num_pages * PageSize, phys_addr); | 5660 | m_memory->MapMemoryRegion(*m_impl, virt_addr, num_pages * PageSize, phys_addr, |
| 5661 | ConvertToMemoryPermission(properties.perm)); | ||
| 5647 | 5662 | ||
| 5648 | // Open references to pages, if we should. | 5663 | // Open references to pages, if we should. |
| 5649 | if (this->IsHeapPhysicalAddress(phys_addr)) { | 5664 | if (this->IsHeapPhysicalAddress(phys_addr)) { |
| @@ -5658,8 +5673,18 @@ Result KPageTableBase::Operate(PageLinkedList* page_list, KProcessAddress virt_a | |||
| 5658 | } | 5673 | } |
| 5659 | case OperationType::ChangePermissions: | 5674 | case OperationType::ChangePermissions: |
| 5660 | case OperationType::ChangePermissionsAndRefresh: | 5675 | case OperationType::ChangePermissionsAndRefresh: |
| 5661 | case OperationType::ChangePermissionsAndRefreshAndFlush: | 5676 | case OperationType::ChangePermissionsAndRefreshAndFlush: { |
| 5677 | const bool read = True(properties.perm & Kernel::KMemoryPermission::UserRead); | ||
| 5678 | const bool write = True(properties.perm & Kernel::KMemoryPermission::UserWrite); | ||
| 5679 | // todo: this doesn't really belong here and should go into m_memory to handle rasterizer | ||
| 5680 | // access todo: ignore exec on non-direct-mapped case | ||
| 5681 | const bool exec = True(properties.perm & Kernel::KMemoryPermission::UserExecute); | ||
| 5682 | if (Settings::IsFastmemEnabled()) { | ||
| 5683 | m_system.DeviceMemory().buffer.Protect(GetInteger(virt_addr), num_pages * PageSize, | ||
| 5684 | read, write, exec); | ||
| 5685 | } | ||
| 5662 | R_SUCCEED(); | 5686 | R_SUCCEED(); |
| 5687 | } | ||
| 5663 | default: | 5688 | default: |
| 5664 | UNREACHABLE(); | 5689 | UNREACHABLE(); |
| 5665 | } | 5690 | } |
| @@ -5687,7 +5712,8 @@ Result KPageTableBase::Operate(PageLinkedList* page_list, KProcessAddress virt_a | |||
| 5687 | const size_t size{node.GetNumPages() * PageSize}; | 5712 | const size_t size{node.GetNumPages() * PageSize}; |
| 5688 | 5713 | ||
| 5689 | // Map the pages. | 5714 | // Map the pages. |
| 5690 | m_memory->MapMemoryRegion(*m_impl, virt_addr, size, node.GetAddress()); | 5715 | m_memory->MapMemoryRegion(*m_impl, virt_addr, size, node.GetAddress(), |
| 5716 | ConvertToMemoryPermission(properties.perm)); | ||
| 5691 | 5717 | ||
| 5692 | virt_addr += size; | 5718 | virt_addr += size; |
| 5693 | } | 5719 | } |
diff --git a/src/core/memory.cpp b/src/core/memory.cpp index a3431772a..14db64f9d 100644 --- a/src/core/memory.cpp +++ b/src/core/memory.cpp | |||
| @@ -53,7 +53,7 @@ struct Memory::Impl { | |||
| 53 | } | 53 | } |
| 54 | 54 | ||
| 55 | void MapMemoryRegion(Common::PageTable& page_table, Common::ProcessAddress base, u64 size, | 55 | void MapMemoryRegion(Common::PageTable& page_table, Common::ProcessAddress base, u64 size, |
| 56 | Common::PhysicalAddress target) { | 56 | Common::PhysicalAddress target, Common::MemoryPermission perms) { |
| 57 | ASSERT_MSG((size & YUZU_PAGEMASK) == 0, "non-page aligned size: {:016X}", size); | 57 | ASSERT_MSG((size & YUZU_PAGEMASK) == 0, "non-page aligned size: {:016X}", size); |
| 58 | ASSERT_MSG((base & YUZU_PAGEMASK) == 0, "non-page aligned base: {:016X}", GetInteger(base)); | 58 | ASSERT_MSG((base & YUZU_PAGEMASK) == 0, "non-page aligned base: {:016X}", GetInteger(base)); |
| 59 | ASSERT_MSG(target >= DramMemoryMap::Base, "Out of bounds target: {:016X}", | 59 | ASSERT_MSG(target >= DramMemoryMap::Base, "Out of bounds target: {:016X}", |
| @@ -63,7 +63,7 @@ struct Memory::Impl { | |||
| 63 | 63 | ||
| 64 | if (Settings::IsFastmemEnabled()) { | 64 | if (Settings::IsFastmemEnabled()) { |
| 65 | system.DeviceMemory().buffer.Map(GetInteger(base), | 65 | system.DeviceMemory().buffer.Map(GetInteger(base), |
| 66 | GetInteger(target) - DramMemoryMap::Base, size); | 66 | GetInteger(target) - DramMemoryMap::Base, size, perms); |
| 67 | } | 67 | } |
| 68 | } | 68 | } |
| 69 | 69 | ||
| @@ -831,8 +831,8 @@ void Memory::SetCurrentPageTable(Kernel::KProcess& process, u32 core_id) { | |||
| 831 | } | 831 | } |
| 832 | 832 | ||
| 833 | void Memory::MapMemoryRegion(Common::PageTable& page_table, Common::ProcessAddress base, u64 size, | 833 | void Memory::MapMemoryRegion(Common::PageTable& page_table, Common::ProcessAddress base, u64 size, |
| 834 | Common::PhysicalAddress target) { | 834 | Common::PhysicalAddress target, Common::MemoryPermission perms) { |
| 835 | impl->MapMemoryRegion(page_table, base, size, target); | 835 | impl->MapMemoryRegion(page_table, base, size, target, perms); |
| 836 | } | 836 | } |
| 837 | 837 | ||
| 838 | void Memory::UnmapRegion(Common::PageTable& page_table, Common::ProcessAddress base, u64 size) { | 838 | void Memory::UnmapRegion(Common::PageTable& page_table, Common::ProcessAddress base, u64 size) { |
diff --git a/src/core/memory.h b/src/core/memory.h index 13047a545..73195549f 100644 --- a/src/core/memory.h +++ b/src/core/memory.h | |||
| @@ -15,8 +15,9 @@ | |||
| 15 | #include "core/hle/result.h" | 15 | #include "core/hle/result.h" |
| 16 | 16 | ||
| 17 | namespace Common { | 17 | namespace Common { |
| 18 | enum class MemoryPermission : u32; | ||
| 18 | struct PageTable; | 19 | struct PageTable; |
| 19 | } | 20 | } // namespace Common |
| 20 | 21 | ||
| 21 | namespace Core { | 22 | namespace Core { |
| 22 | class System; | 23 | class System; |
| @@ -82,9 +83,10 @@ public: | |||
| 82 | * @param size The amount of bytes to map. Must be page-aligned. | 83 | * @param size The amount of bytes to map. Must be page-aligned. |
| 83 | * @param target Buffer with the memory backing the mapping. Must be of length at least | 84 | * @param target Buffer with the memory backing the mapping. Must be of length at least |
| 84 | * `size`. | 85 | * `size`. |
| 86 | * @param perms The permissions to map the memory with. | ||
| 85 | */ | 87 | */ |
| 86 | void MapMemoryRegion(Common::PageTable& page_table, Common::ProcessAddress base, u64 size, | 88 | void MapMemoryRegion(Common::PageTable& page_table, Common::ProcessAddress base, u64 size, |
| 87 | Common::PhysicalAddress target); | 89 | Common::PhysicalAddress target, Common::MemoryPermission perms); |
| 88 | 90 | ||
| 89 | /** | 91 | /** |
| 90 | * Unmaps a region of the emulated process address space. | 92 | * Unmaps a region of the emulated process address space. |
diff --git a/src/tests/common/host_memory.cpp b/src/tests/common/host_memory.cpp index 1b014b632..1a28e862b 100644 --- a/src/tests/common/host_memory.cpp +++ b/src/tests/common/host_memory.cpp | |||
| @@ -11,6 +11,7 @@ using namespace Common::Literals; | |||
| 11 | 11 | ||
| 12 | static constexpr size_t VIRTUAL_SIZE = 1ULL << 39; | 12 | static constexpr size_t VIRTUAL_SIZE = 1ULL << 39; |
| 13 | static constexpr size_t BACKING_SIZE = 4_GiB; | 13 | static constexpr size_t BACKING_SIZE = 4_GiB; |
| 14 | static constexpr auto PERMS = Common::MemoryPermission::ReadWrite; | ||
| 14 | 15 | ||
| 15 | TEST_CASE("HostMemory: Initialize and deinitialize", "[common]") { | 16 | TEST_CASE("HostMemory: Initialize and deinitialize", "[common]") { |
| 16 | { HostMemory mem(BACKING_SIZE, VIRTUAL_SIZE); } | 17 | { HostMemory mem(BACKING_SIZE, VIRTUAL_SIZE); } |
| @@ -19,7 +20,7 @@ TEST_CASE("HostMemory: Initialize and deinitialize", "[common]") { | |||
| 19 | 20 | ||
| 20 | TEST_CASE("HostMemory: Simple map", "[common]") { | 21 | TEST_CASE("HostMemory: Simple map", "[common]") { |
| 21 | HostMemory mem(BACKING_SIZE, VIRTUAL_SIZE); | 22 | HostMemory mem(BACKING_SIZE, VIRTUAL_SIZE); |
| 22 | mem.Map(0x5000, 0x8000, 0x1000); | 23 | mem.Map(0x5000, 0x8000, 0x1000, PERMS); |
| 23 | 24 | ||
| 24 | volatile u8* const data = mem.VirtualBasePointer() + 0x5000; | 25 | volatile u8* const data = mem.VirtualBasePointer() + 0x5000; |
| 25 | data[0] = 50; | 26 | data[0] = 50; |
| @@ -28,8 +29,8 @@ TEST_CASE("HostMemory: Simple map", "[common]") { | |||
| 28 | 29 | ||
| 29 | TEST_CASE("HostMemory: Simple mirror map", "[common]") { | 30 | TEST_CASE("HostMemory: Simple mirror map", "[common]") { |
| 30 | HostMemory mem(BACKING_SIZE, VIRTUAL_SIZE); | 31 | HostMemory mem(BACKING_SIZE, VIRTUAL_SIZE); |
| 31 | mem.Map(0x5000, 0x3000, 0x2000); | 32 | mem.Map(0x5000, 0x3000, 0x2000, PERMS); |
| 32 | mem.Map(0x8000, 0x4000, 0x1000); | 33 | mem.Map(0x8000, 0x4000, 0x1000, PERMS); |
| 33 | 34 | ||
| 34 | volatile u8* const mirror_a = mem.VirtualBasePointer() + 0x5000; | 35 | volatile u8* const mirror_a = mem.VirtualBasePointer() + 0x5000; |
| 35 | volatile u8* const mirror_b = mem.VirtualBasePointer() + 0x8000; | 36 | volatile u8* const mirror_b = mem.VirtualBasePointer() + 0x8000; |
| @@ -39,7 +40,7 @@ TEST_CASE("HostMemory: Simple mirror map", "[common]") { | |||
| 39 | 40 | ||
| 40 | TEST_CASE("HostMemory: Simple unmap", "[common]") { | 41 | TEST_CASE("HostMemory: Simple unmap", "[common]") { |
| 41 | HostMemory mem(BACKING_SIZE, VIRTUAL_SIZE); | 42 | HostMemory mem(BACKING_SIZE, VIRTUAL_SIZE); |
| 42 | mem.Map(0x5000, 0x3000, 0x2000); | 43 | mem.Map(0x5000, 0x3000, 0x2000, PERMS); |
| 43 | 44 | ||
| 44 | volatile u8* const data = mem.VirtualBasePointer() + 0x5000; | 45 | volatile u8* const data = mem.VirtualBasePointer() + 0x5000; |
| 45 | data[75] = 50; | 46 | data[75] = 50; |
| @@ -50,7 +51,7 @@ TEST_CASE("HostMemory: Simple unmap", "[common]") { | |||
| 50 | 51 | ||
| 51 | TEST_CASE("HostMemory: Simple unmap and remap", "[common]") { | 52 | TEST_CASE("HostMemory: Simple unmap and remap", "[common]") { |
| 52 | HostMemory mem(BACKING_SIZE, VIRTUAL_SIZE); | 53 | HostMemory mem(BACKING_SIZE, VIRTUAL_SIZE); |
| 53 | mem.Map(0x5000, 0x3000, 0x2000); | 54 | mem.Map(0x5000, 0x3000, 0x2000, PERMS); |
| 54 | 55 | ||
| 55 | volatile u8* const data = mem.VirtualBasePointer() + 0x5000; | 56 | volatile u8* const data = mem.VirtualBasePointer() + 0x5000; |
| 56 | data[0] = 50; | 57 | data[0] = 50; |
| @@ -58,79 +59,79 @@ TEST_CASE("HostMemory: Simple unmap and remap", "[common]") { | |||
| 58 | 59 | ||
| 59 | mem.Unmap(0x5000, 0x2000); | 60 | mem.Unmap(0x5000, 0x2000); |
| 60 | 61 | ||
| 61 | mem.Map(0x5000, 0x3000, 0x2000); | 62 | mem.Map(0x5000, 0x3000, 0x2000, PERMS); |
| 62 | REQUIRE(data[0] == 50); | 63 | REQUIRE(data[0] == 50); |
| 63 | 64 | ||
| 64 | mem.Map(0x7000, 0x2000, 0x5000); | 65 | mem.Map(0x7000, 0x2000, 0x5000, PERMS); |
| 65 | REQUIRE(data[0x3000] == 50); | 66 | REQUIRE(data[0x3000] == 50); |
| 66 | } | 67 | } |
| 67 | 68 | ||
| 68 | TEST_CASE("HostMemory: Nieche allocation", "[common]") { | 69 | TEST_CASE("HostMemory: Nieche allocation", "[common]") { |
| 69 | HostMemory mem(BACKING_SIZE, VIRTUAL_SIZE); | 70 | HostMemory mem(BACKING_SIZE, VIRTUAL_SIZE); |
| 70 | mem.Map(0x0000, 0, 0x20000); | 71 | mem.Map(0x0000, 0, 0x20000, PERMS); |
| 71 | mem.Unmap(0x0000, 0x4000); | 72 | mem.Unmap(0x0000, 0x4000); |
| 72 | mem.Map(0x1000, 0, 0x2000); | 73 | mem.Map(0x1000, 0, 0x2000, PERMS); |
| 73 | mem.Map(0x3000, 0, 0x1000); | 74 | mem.Map(0x3000, 0, 0x1000, PERMS); |
| 74 | mem.Map(0, 0, 0x1000); | 75 | mem.Map(0, 0, 0x1000, PERMS); |
| 75 | } | 76 | } |
| 76 | 77 | ||
| 77 | TEST_CASE("HostMemory: Full unmap", "[common]") { | 78 | TEST_CASE("HostMemory: Full unmap", "[common]") { |
| 78 | HostMemory mem(BACKING_SIZE, VIRTUAL_SIZE); | 79 | HostMemory mem(BACKING_SIZE, VIRTUAL_SIZE); |
| 79 | mem.Map(0x8000, 0, 0x4000); | 80 | mem.Map(0x8000, 0, 0x4000, PERMS); |
| 80 | mem.Unmap(0x8000, 0x4000); | 81 | mem.Unmap(0x8000, 0x4000); |
| 81 | mem.Map(0x6000, 0, 0x16000); | 82 | mem.Map(0x6000, 0, 0x16000, PERMS); |
| 82 | } | 83 | } |
| 83 | 84 | ||
| 84 | TEST_CASE("HostMemory: Right out of bounds unmap", "[common]") { | 85 | TEST_CASE("HostMemory: Right out of bounds unmap", "[common]") { |
| 85 | HostMemory mem(BACKING_SIZE, VIRTUAL_SIZE); | 86 | HostMemory mem(BACKING_SIZE, VIRTUAL_SIZE); |
| 86 | mem.Map(0x0000, 0, 0x4000); | 87 | mem.Map(0x0000, 0, 0x4000, PERMS); |
| 87 | mem.Unmap(0x2000, 0x4000); | 88 | mem.Unmap(0x2000, 0x4000); |
| 88 | mem.Map(0x2000, 0x80000, 0x4000); | 89 | mem.Map(0x2000, 0x80000, 0x4000, PERMS); |
| 89 | } | 90 | } |
| 90 | 91 | ||
| 91 | TEST_CASE("HostMemory: Left out of bounds unmap", "[common]") { | 92 | TEST_CASE("HostMemory: Left out of bounds unmap", "[common]") { |
| 92 | HostMemory mem(BACKING_SIZE, VIRTUAL_SIZE); | 93 | HostMemory mem(BACKING_SIZE, VIRTUAL_SIZE); |
| 93 | mem.Map(0x8000, 0, 0x4000); | 94 | mem.Map(0x8000, 0, 0x4000, PERMS); |
| 94 | mem.Unmap(0x6000, 0x4000); | 95 | mem.Unmap(0x6000, 0x4000); |
| 95 | mem.Map(0x8000, 0, 0x2000); | 96 | mem.Map(0x8000, 0, 0x2000, PERMS); |
| 96 | } | 97 | } |
| 97 | 98 | ||
| 98 | TEST_CASE("HostMemory: Multiple placeholder unmap", "[common]") { | 99 | TEST_CASE("HostMemory: Multiple placeholder unmap", "[common]") { |
| 99 | HostMemory mem(BACKING_SIZE, VIRTUAL_SIZE); | 100 | HostMemory mem(BACKING_SIZE, VIRTUAL_SIZE); |
| 100 | mem.Map(0x0000, 0, 0x4000); | 101 | mem.Map(0x0000, 0, 0x4000, PERMS); |
| 101 | mem.Map(0x4000, 0, 0x1b000); | 102 | mem.Map(0x4000, 0, 0x1b000, PERMS); |
| 102 | mem.Unmap(0x3000, 0x1c000); | 103 | mem.Unmap(0x3000, 0x1c000); |
| 103 | mem.Map(0x3000, 0, 0x20000); | 104 | mem.Map(0x3000, 0, 0x20000, PERMS); |
| 104 | } | 105 | } |
| 105 | 106 | ||
| 106 | TEST_CASE("HostMemory: Unmap between placeholders", "[common]") { | 107 | TEST_CASE("HostMemory: Unmap between placeholders", "[common]") { |
| 107 | HostMemory mem(BACKING_SIZE, VIRTUAL_SIZE); | 108 | HostMemory mem(BACKING_SIZE, VIRTUAL_SIZE); |
| 108 | mem.Map(0x0000, 0, 0x4000); | 109 | mem.Map(0x0000, 0, 0x4000, PERMS); |
| 109 | mem.Map(0x4000, 0, 0x4000); | 110 | mem.Map(0x4000, 0, 0x4000, PERMS); |
| 110 | mem.Unmap(0x2000, 0x4000); | 111 | mem.Unmap(0x2000, 0x4000); |
| 111 | mem.Map(0x2000, 0, 0x4000); | 112 | mem.Map(0x2000, 0, 0x4000, PERMS); |
| 112 | } | 113 | } |
| 113 | 114 | ||
| 114 | TEST_CASE("HostMemory: Unmap to origin", "[common]") { | 115 | TEST_CASE("HostMemory: Unmap to origin", "[common]") { |
| 115 | HostMemory mem(BACKING_SIZE, VIRTUAL_SIZE); | 116 | HostMemory mem(BACKING_SIZE, VIRTUAL_SIZE); |
| 116 | mem.Map(0x4000, 0, 0x4000); | 117 | mem.Map(0x4000, 0, 0x4000, PERMS); |
| 117 | mem.Map(0x8000, 0, 0x4000); | 118 | mem.Map(0x8000, 0, 0x4000, PERMS); |
| 118 | mem.Unmap(0x4000, 0x4000); | 119 | mem.Unmap(0x4000, 0x4000); |
| 119 | mem.Map(0, 0, 0x4000); | 120 | mem.Map(0, 0, 0x4000, PERMS); |
| 120 | mem.Map(0x4000, 0, 0x4000); | 121 | mem.Map(0x4000, 0, 0x4000, PERMS); |
| 121 | } | 122 | } |
| 122 | 123 | ||
| 123 | TEST_CASE("HostMemory: Unmap to right", "[common]") { | 124 | TEST_CASE("HostMemory: Unmap to right", "[common]") { |
| 124 | HostMemory mem(BACKING_SIZE, VIRTUAL_SIZE); | 125 | HostMemory mem(BACKING_SIZE, VIRTUAL_SIZE); |
| 125 | mem.Map(0x4000, 0, 0x4000); | 126 | mem.Map(0x4000, 0, 0x4000, PERMS); |
| 126 | mem.Map(0x8000, 0, 0x4000); | 127 | mem.Map(0x8000, 0, 0x4000, PERMS); |
| 127 | mem.Unmap(0x8000, 0x4000); | 128 | mem.Unmap(0x8000, 0x4000); |
| 128 | mem.Map(0x8000, 0, 0x4000); | 129 | mem.Map(0x8000, 0, 0x4000, PERMS); |
| 129 | } | 130 | } |
| 130 | 131 | ||
| 131 | TEST_CASE("HostMemory: Partial right unmap check bindings", "[common]") { | 132 | TEST_CASE("HostMemory: Partial right unmap check bindings", "[common]") { |
| 132 | HostMemory mem(BACKING_SIZE, VIRTUAL_SIZE); | 133 | HostMemory mem(BACKING_SIZE, VIRTUAL_SIZE); |
| 133 | mem.Map(0x4000, 0x10000, 0x4000); | 134 | mem.Map(0x4000, 0x10000, 0x4000, PERMS); |
| 134 | 135 | ||
| 135 | volatile u8* const ptr = mem.VirtualBasePointer() + 0x4000; | 136 | volatile u8* const ptr = mem.VirtualBasePointer() + 0x4000; |
| 136 | ptr[0x1000] = 17; | 137 | ptr[0x1000] = 17; |
| @@ -142,7 +143,7 @@ TEST_CASE("HostMemory: Partial right unmap check bindings", "[common]") { | |||
| 142 | 143 | ||
| 143 | TEST_CASE("HostMemory: Partial left unmap check bindings", "[common]") { | 144 | TEST_CASE("HostMemory: Partial left unmap check bindings", "[common]") { |
| 144 | HostMemory mem(BACKING_SIZE, VIRTUAL_SIZE); | 145 | HostMemory mem(BACKING_SIZE, VIRTUAL_SIZE); |
| 145 | mem.Map(0x4000, 0x10000, 0x4000); | 146 | mem.Map(0x4000, 0x10000, 0x4000, PERMS); |
| 146 | 147 | ||
| 147 | volatile u8* const ptr = mem.VirtualBasePointer() + 0x4000; | 148 | volatile u8* const ptr = mem.VirtualBasePointer() + 0x4000; |
| 148 | ptr[0x3000] = 19; | 149 | ptr[0x3000] = 19; |
| @@ -156,7 +157,7 @@ TEST_CASE("HostMemory: Partial left unmap check bindings", "[common]") { | |||
| 156 | 157 | ||
| 157 | TEST_CASE("HostMemory: Partial middle unmap check bindings", "[common]") { | 158 | TEST_CASE("HostMemory: Partial middle unmap check bindings", "[common]") { |
| 158 | HostMemory mem(BACKING_SIZE, VIRTUAL_SIZE); | 159 | HostMemory mem(BACKING_SIZE, VIRTUAL_SIZE); |
| 159 | mem.Map(0x4000, 0x10000, 0x4000); | 160 | mem.Map(0x4000, 0x10000, 0x4000, PERMS); |
| 160 | 161 | ||
| 161 | volatile u8* const ptr = mem.VirtualBasePointer() + 0x4000; | 162 | volatile u8* const ptr = mem.VirtualBasePointer() + 0x4000; |
| 162 | ptr[0x0000] = 19; | 163 | ptr[0x0000] = 19; |
| @@ -170,8 +171,8 @@ TEST_CASE("HostMemory: Partial middle unmap check bindings", "[common]") { | |||
| 170 | 171 | ||
| 171 | TEST_CASE("HostMemory: Partial sparse middle unmap and check bindings", "[common]") { | 172 | TEST_CASE("HostMemory: Partial sparse middle unmap and check bindings", "[common]") { |
| 172 | HostMemory mem(BACKING_SIZE, VIRTUAL_SIZE); | 173 | HostMemory mem(BACKING_SIZE, VIRTUAL_SIZE); |
| 173 | mem.Map(0x4000, 0x10000, 0x2000); | 174 | mem.Map(0x4000, 0x10000, 0x2000, PERMS); |
| 174 | mem.Map(0x6000, 0x20000, 0x2000); | 175 | mem.Map(0x6000, 0x20000, 0x2000, PERMS); |
| 175 | 176 | ||
| 176 | volatile u8* const ptr = mem.VirtualBasePointer() + 0x4000; | 177 | volatile u8* const ptr = mem.VirtualBasePointer() + 0x4000; |
| 177 | ptr[0x0000] = 19; | 178 | ptr[0x0000] = 19; |