diff options
Diffstat (limited to 'src/common')
| -rw-r--r-- | src/common/host_memory.cpp | 45 | ||||
| -rw-r--r-- | src/common/host_memory.h | 13 |
2 files changed, 44 insertions, 14 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 | ||