diff options
| author | 2020-03-07 18:59:42 -0400 | |
|---|---|---|
| committer | 2020-06-27 11:35:37 -0400 | |
| commit | cd1c38be8d15d3caf52f566a9e8dc20504c61068 (patch) | |
| tree | 2fed02ffd4f2151dfca14ddb33ef1939eaee2fba /src/core/memory.cpp | |
| parent | SVC: WaitSynchronization add Termination Pending Result. (diff) | |
| download | yuzu-cd1c38be8d15d3caf52f566a9e8dc20504c61068.tar.gz yuzu-cd1c38be8d15d3caf52f566a9e8dc20504c61068.tar.xz yuzu-cd1c38be8d15d3caf52f566a9e8dc20504c61068.zip | |
ARM/Memory: Correct Exclusive Monitor and Implement Exclusive Memory Writes.
Diffstat (limited to 'src/core/memory.cpp')
| -rw-r--r-- | src/core/memory.cpp | 98 |
1 files changed, 98 insertions, 0 deletions
diff --git a/src/core/memory.cpp b/src/core/memory.cpp index 66634596d..4cb5d05e5 100644 --- a/src/core/memory.cpp +++ b/src/core/memory.cpp | |||
| @@ -8,6 +8,7 @@ | |||
| 8 | #include <utility> | 8 | #include <utility> |
| 9 | 9 | ||
| 10 | #include "common/assert.h" | 10 | #include "common/assert.h" |
| 11 | #include "common/atomic_ops.h" | ||
| 11 | #include "common/common_types.h" | 12 | #include "common/common_types.h" |
| 12 | #include "common/logging/log.h" | 13 | #include "common/logging/log.h" |
| 13 | #include "common/page_table.h" | 14 | #include "common/page_table.h" |
| @@ -176,6 +177,22 @@ struct Memory::Impl { | |||
| 176 | } | 177 | } |
| 177 | } | 178 | } |
| 178 | 179 | ||
| 180 | bool WriteExclusive8(const VAddr addr, const u8 data, const u8 expected) { | ||
| 181 | return WriteExclusive<u8>(addr, data, expected); | ||
| 182 | } | ||
| 183 | |||
| 184 | bool WriteExclusive16(const VAddr addr, const u16 data, const u16 expected) { | ||
| 185 | return WriteExclusive<u16_le>(addr, data, expected); | ||
| 186 | } | ||
| 187 | |||
| 188 | bool WriteExclusive32(const VAddr addr, const u32 data, const u32 expected) { | ||
| 189 | return WriteExclusive<u32_le>(addr, data, expected); | ||
| 190 | } | ||
| 191 | |||
| 192 | bool WriteExclusive64(const VAddr addr, const u64 data, const u64 expected) { | ||
| 193 | return WriteExclusive<u64_le>(addr, data, expected); | ||
| 194 | } | ||
| 195 | |||
| 179 | std::string ReadCString(VAddr vaddr, std::size_t max_length) { | 196 | std::string ReadCString(VAddr vaddr, std::size_t max_length) { |
| 180 | std::string string; | 197 | std::string string; |
| 181 | string.reserve(max_length); | 198 | string.reserve(max_length); |
| @@ -679,6 +696,67 @@ struct Memory::Impl { | |||
| 679 | } | 696 | } |
| 680 | } | 697 | } |
| 681 | 698 | ||
| 699 | template <typename T> | ||
| 700 | bool WriteExclusive(const VAddr vaddr, const T data, const T expected) { | ||
| 701 | u8* page_pointer = current_page_table->pointers[vaddr >> PAGE_BITS]; | ||
| 702 | if (page_pointer != nullptr) { | ||
| 703 | // NOTE: Avoid adding any extra logic to this fast-path block | ||
| 704 | T volatile* pointer = reinterpret_cast<T volatile*>(&page_pointer[vaddr]); | ||
| 705 | return Common::AtomicCompareAndSwap(pointer, data, expected); | ||
| 706 | } | ||
| 707 | |||
| 708 | const Common::PageType type = current_page_table->attributes[vaddr >> PAGE_BITS]; | ||
| 709 | switch (type) { | ||
| 710 | case Common::PageType::Unmapped: | ||
| 711 | LOG_ERROR(HW_Memory, "Unmapped Write{} 0x{:08X} @ 0x{:016X}", sizeof(data) * 8, | ||
| 712 | static_cast<u32>(data), vaddr); | ||
| 713 | return true; | ||
| 714 | case Common::PageType::Memory: | ||
| 715 | ASSERT_MSG(false, "Mapped memory page without a pointer @ {:016X}", vaddr); | ||
| 716 | break; | ||
| 717 | case Common::PageType::RasterizerCachedMemory: { | ||
| 718 | u8* host_ptr{GetPointerFromVMA(vaddr)}; | ||
| 719 | system.GPU().InvalidateRegion(ToCacheAddr(host_ptr), sizeof(T)); | ||
| 720 | T volatile* pointer = reinterpret_cast<T volatile*>(&host_ptr); | ||
| 721 | return Common::AtomicCompareAndSwap(pointer, data, expected); | ||
| 722 | break; | ||
| 723 | } | ||
| 724 | default: | ||
| 725 | UNREACHABLE(); | ||
| 726 | } | ||
| 727 | return true; | ||
| 728 | } | ||
| 729 | |||
| 730 | bool WriteExclusive128(const VAddr vaddr, const u128 data, const u128 expected) { | ||
| 731 | u8* const page_pointer = current_page_table->pointers[vaddr >> PAGE_BITS]; | ||
| 732 | if (page_pointer != nullptr) { | ||
| 733 | // NOTE: Avoid adding any extra logic to this fast-path block | ||
| 734 | u64 volatile* pointer = reinterpret_cast<u64 volatile*>(&page_pointer[vaddr]); | ||
| 735 | return Common::AtomicCompareAndSwap(pointer, data, expected); | ||
| 736 | } | ||
| 737 | |||
| 738 | const Common::PageType type = current_page_table->attributes[vaddr >> PAGE_BITS]; | ||
| 739 | switch (type) { | ||
| 740 | case Common::PageType::Unmapped: | ||
| 741 | LOG_ERROR(HW_Memory, "Unmapped Write{} 0x{:08X} @ 0x{:016X}{:016X}", sizeof(data) * 8, | ||
| 742 | static_cast<u64>(data[1]), static_cast<u64>(data[0]), vaddr); | ||
| 743 | return true; | ||
| 744 | case Common::PageType::Memory: | ||
| 745 | ASSERT_MSG(false, "Mapped memory page without a pointer @ {:016X}", vaddr); | ||
| 746 | break; | ||
| 747 | case Common::PageType::RasterizerCachedMemory: { | ||
| 748 | u8* host_ptr{GetPointerFromVMA(vaddr)}; | ||
| 749 | system.GPU().InvalidateRegion(ToCacheAddr(host_ptr), sizeof(u128)); | ||
| 750 | u64 volatile* pointer = reinterpret_cast<u64 volatile*>(&host_ptr); | ||
| 751 | return Common::AtomicCompareAndSwap(pointer, data, expected); | ||
| 752 | break; | ||
| 753 | } | ||
| 754 | default: | ||
| 755 | UNREACHABLE(); | ||
| 756 | } | ||
| 757 | return true; | ||
| 758 | } | ||
| 759 | |||
| 682 | Common::PageTable* current_page_table = nullptr; | 760 | Common::PageTable* current_page_table = nullptr; |
| 683 | Core::System& system; | 761 | Core::System& system; |
| 684 | }; | 762 | }; |
| @@ -761,6 +839,26 @@ void Memory::Write64(VAddr addr, u64 data) { | |||
| 761 | impl->Write64(addr, data); | 839 | impl->Write64(addr, data); |
| 762 | } | 840 | } |
| 763 | 841 | ||
| 842 | bool Memory::WriteExclusive8(VAddr addr, u8 data, u8 expected) { | ||
| 843 | return impl->WriteExclusive8(addr, data, expected); | ||
| 844 | } | ||
| 845 | |||
| 846 | bool Memory::WriteExclusive16(VAddr addr, u16 data, u16 expected) { | ||
| 847 | return impl->WriteExclusive16(addr, data, expected); | ||
| 848 | } | ||
| 849 | |||
| 850 | bool Memory::WriteExclusive32(VAddr addr, u32 data, u32 expected) { | ||
| 851 | return impl->WriteExclusive32(addr, data, expected); | ||
| 852 | } | ||
| 853 | |||
| 854 | bool Memory::WriteExclusive64(VAddr addr, u64 data, u64 expected) { | ||
| 855 | return impl->WriteExclusive64(addr, data, expected); | ||
| 856 | } | ||
| 857 | |||
| 858 | bool Memory::WriteExclusive128(VAddr addr, u128 data, u128 expected) { | ||
| 859 | return impl->WriteExclusive128(addr, data, expected); | ||
| 860 | } | ||
| 861 | |||
| 764 | std::string Memory::ReadCString(VAddr vaddr, std::size_t max_length) { | 862 | std::string Memory::ReadCString(VAddr vaddr, std::size_t max_length) { |
| 765 | return impl->ReadCString(vaddr, max_length); | 863 | return impl->ReadCString(vaddr, max_length); |
| 766 | } | 864 | } |