diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/core/hle/kernel/k_memory_block.h | 36 | ||||
| -rw-r--r-- | src/core/hle/kernel/k_page_table.cpp | 237 | ||||
| -rw-r--r-- | src/core/hle/kernel/k_page_table.h | 47 | ||||
| -rw-r--r-- | src/core/hle/kernel/svc.cpp | 50 | ||||
| -rw-r--r-- | src/core/hle/kernel/svc_types.h | 1 |
5 files changed, 211 insertions, 160 deletions
diff --git a/src/core/hle/kernel/k_memory_block.h b/src/core/hle/kernel/k_memory_block.h index 9e51c33ce..dcca47f1b 100644 --- a/src/core/hle/kernel/k_memory_block.h +++ b/src/core/hle/kernel/k_memory_block.h | |||
| @@ -70,12 +70,12 @@ enum class KMemoryState : u32 { | |||
| 70 | ThreadLocal = | 70 | ThreadLocal = |
| 71 | static_cast<u32>(Svc::MemoryState::ThreadLocal) | FlagMapped | FlagReferenceCounted, | 71 | static_cast<u32>(Svc::MemoryState::ThreadLocal) | FlagMapped | FlagReferenceCounted, |
| 72 | 72 | ||
| 73 | Transferred = static_cast<u32>(Svc::MemoryState::Transferred) | FlagsMisc | | 73 | Transfered = static_cast<u32>(Svc::MemoryState::Transferred) | FlagsMisc | |
| 74 | FlagCanAlignedDeviceMap | FlagCanChangeAttribute | FlagCanUseIpc | | 74 | FlagCanAlignedDeviceMap | FlagCanChangeAttribute | FlagCanUseIpc | |
| 75 | FlagCanUseNonSecureIpc | FlagCanUseNonDeviceIpc, | 75 | FlagCanUseNonSecureIpc | FlagCanUseNonDeviceIpc, |
| 76 | 76 | ||
| 77 | SharedTransferred = static_cast<u32>(Svc::MemoryState::SharedTransferred) | FlagsMisc | | 77 | SharedTransfered = static_cast<u32>(Svc::MemoryState::SharedTransferred) | FlagsMisc | |
| 78 | FlagCanAlignedDeviceMap | FlagCanUseNonSecureIpc | FlagCanUseNonDeviceIpc, | 78 | FlagCanAlignedDeviceMap | FlagCanUseNonSecureIpc | FlagCanUseNonDeviceIpc, |
| 79 | 79 | ||
| 80 | SharedCode = static_cast<u32>(Svc::MemoryState::SharedCode) | FlagMapped | | 80 | SharedCode = static_cast<u32>(Svc::MemoryState::SharedCode) | FlagMapped | |
| 81 | FlagReferenceCounted | FlagCanUseNonSecureIpc | FlagCanUseNonDeviceIpc, | 81 | FlagReferenceCounted | FlagCanUseNonSecureIpc | FlagCanUseNonDeviceIpc, |
| @@ -93,6 +93,8 @@ enum class KMemoryState : u32 { | |||
| 93 | GeneratedCode = static_cast<u32>(Svc::MemoryState::GeneratedCode) | FlagMapped | | 93 | GeneratedCode = static_cast<u32>(Svc::MemoryState::GeneratedCode) | FlagMapped | |
| 94 | FlagReferenceCounted | FlagCanDebug, | 94 | FlagReferenceCounted | FlagCanDebug, |
| 95 | CodeOut = static_cast<u32>(Svc::MemoryState::CodeOut) | FlagMapped | FlagReferenceCounted, | 95 | CodeOut = static_cast<u32>(Svc::MemoryState::CodeOut) | FlagMapped | FlagReferenceCounted, |
| 96 | |||
| 97 | Coverage = static_cast<u32>(Svc::MemoryState::Coverage) | FlagMapped, | ||
| 96 | }; | 98 | }; |
| 97 | DECLARE_ENUM_FLAG_OPERATORS(KMemoryState); | 99 | DECLARE_ENUM_FLAG_OPERATORS(KMemoryState); |
| 98 | 100 | ||
| @@ -108,8 +110,8 @@ static_assert(static_cast<u32>(KMemoryState::AliasCodeData) == 0x03FFBD09); | |||
| 108 | static_assert(static_cast<u32>(KMemoryState::Ipc) == 0x005C3C0A); | 110 | static_assert(static_cast<u32>(KMemoryState::Ipc) == 0x005C3C0A); |
| 109 | static_assert(static_cast<u32>(KMemoryState::Stack) == 0x005C3C0B); | 111 | static_assert(static_cast<u32>(KMemoryState::Stack) == 0x005C3C0B); |
| 110 | static_assert(static_cast<u32>(KMemoryState::ThreadLocal) == 0x0040200C); | 112 | static_assert(static_cast<u32>(KMemoryState::ThreadLocal) == 0x0040200C); |
| 111 | static_assert(static_cast<u32>(KMemoryState::Transferred) == 0x015C3C0D); | 113 | static_assert(static_cast<u32>(KMemoryState::Transfered) == 0x015C3C0D); |
| 112 | static_assert(static_cast<u32>(KMemoryState::SharedTransferred) == 0x005C380E); | 114 | static_assert(static_cast<u32>(KMemoryState::SharedTransfered) == 0x005C380E); |
| 113 | static_assert(static_cast<u32>(KMemoryState::SharedCode) == 0x0040380F); | 115 | static_assert(static_cast<u32>(KMemoryState::SharedCode) == 0x0040380F); |
| 114 | static_assert(static_cast<u32>(KMemoryState::Inaccessible) == 0x00000010); | 116 | static_assert(static_cast<u32>(KMemoryState::Inaccessible) == 0x00000010); |
| 115 | static_assert(static_cast<u32>(KMemoryState::NonSecureIpc) == 0x005C3811); | 117 | static_assert(static_cast<u32>(KMemoryState::NonSecureIpc) == 0x005C3811); |
| @@ -117,6 +119,7 @@ static_assert(static_cast<u32>(KMemoryState::NonDeviceIpc) == 0x004C2812); | |||
| 117 | static_assert(static_cast<u32>(KMemoryState::Kernel) == 0x00002013); | 119 | static_assert(static_cast<u32>(KMemoryState::Kernel) == 0x00002013); |
| 118 | static_assert(static_cast<u32>(KMemoryState::GeneratedCode) == 0x00402214); | 120 | static_assert(static_cast<u32>(KMemoryState::GeneratedCode) == 0x00402214); |
| 119 | static_assert(static_cast<u32>(KMemoryState::CodeOut) == 0x00402015); | 121 | static_assert(static_cast<u32>(KMemoryState::CodeOut) == 0x00402015); |
| 122 | static_assert(static_cast<u32>(KMemoryState::Coverage) == 0x00002016); | ||
| 120 | 123 | ||
| 121 | enum class KMemoryPermission : u8 { | 124 | enum class KMemoryPermission : u8 { |
| 122 | None = 0, | 125 | None = 0, |
| @@ -155,7 +158,13 @@ enum class KMemoryPermission : u8 { | |||
| 155 | DECLARE_ENUM_FLAG_OPERATORS(KMemoryPermission); | 158 | DECLARE_ENUM_FLAG_OPERATORS(KMemoryPermission); |
| 156 | 159 | ||
| 157 | constexpr KMemoryPermission ConvertToKMemoryPermission(Svc::MemoryPermission perm) { | 160 | constexpr KMemoryPermission ConvertToKMemoryPermission(Svc::MemoryPermission perm) { |
| 158 | return static_cast<KMemoryPermission>(perm); | 161 | return static_cast<KMemoryPermission>( |
| 162 | (static_cast<KMemoryPermission>(perm) & KMemoryPermission::UserMask) | | ||
| 163 | KMemoryPermission::KernelRead | | ||
| 164 | ((static_cast<KMemoryPermission>(perm) & KMemoryPermission::UserWrite) | ||
| 165 | << KMemoryPermission::KernelShift) | | ||
| 166 | (perm == Svc::MemoryPermission::None ? KMemoryPermission::NotMapped | ||
| 167 | : KMemoryPermission::None)); | ||
| 159 | } | 168 | } |
| 160 | 169 | ||
| 161 | enum class KMemoryAttribute : u8 { | 170 | enum class KMemoryAttribute : u8 { |
| @@ -169,6 +178,8 @@ enum class KMemoryAttribute : u8 { | |||
| 169 | DeviceShared = static_cast<u8>(Svc::MemoryAttribute::DeviceShared), | 178 | DeviceShared = static_cast<u8>(Svc::MemoryAttribute::DeviceShared), |
| 170 | Uncached = static_cast<u8>(Svc::MemoryAttribute::Uncached), | 179 | Uncached = static_cast<u8>(Svc::MemoryAttribute::Uncached), |
| 171 | 180 | ||
| 181 | SetMask = Uncached, | ||
| 182 | |||
| 172 | IpcAndDeviceMapped = IpcLocked | DeviceShared, | 183 | IpcAndDeviceMapped = IpcLocked | DeviceShared, |
| 173 | LockedAndIpcLocked = Locked | IpcLocked, | 184 | LockedAndIpcLocked = Locked | IpcLocked, |
| 174 | DeviceSharedAndUncached = DeviceShared | Uncached | 185 | DeviceSharedAndUncached = DeviceShared | Uncached |
| @@ -215,6 +226,15 @@ struct KMemoryInfo { | |||
| 215 | constexpr VAddr GetLastAddress() const { | 226 | constexpr VAddr GetLastAddress() const { |
| 216 | return GetEndAddress() - 1; | 227 | return GetEndAddress() - 1; |
| 217 | } | 228 | } |
| 229 | constexpr KMemoryState GetState() const { | ||
| 230 | return state; | ||
| 231 | } | ||
| 232 | constexpr KMemoryAttribute GetAttribute() const { | ||
| 233 | return attribute; | ||
| 234 | } | ||
| 235 | constexpr KMemoryPermission GetPermission() const { | ||
| 236 | return perm; | ||
| 237 | } | ||
| 218 | }; | 238 | }; |
| 219 | 239 | ||
| 220 | class KMemoryBlock final { | 240 | class KMemoryBlock final { |
diff --git a/src/core/hle/kernel/k_page_table.cpp b/src/core/hle/kernel/k_page_table.cpp index 4da509224..6077985b5 100644 --- a/src/core/hle/kernel/k_page_table.cpp +++ b/src/core/hle/kernel/k_page_table.cpp | |||
| @@ -305,8 +305,8 @@ ResultCode KPageTable::MapProcessCodeMemory(VAddr dst_addr, VAddr src_addr, std: | |||
| 305 | 305 | ||
| 306 | KMemoryState state{}; | 306 | KMemoryState state{}; |
| 307 | KMemoryPermission perm{}; | 307 | KMemoryPermission perm{}; |
| 308 | CASCADE_CODE(CheckMemoryState(&state, &perm, nullptr, src_addr, size, KMemoryState::All, | 308 | CASCADE_CODE(CheckMemoryState(&state, &perm, nullptr, nullptr, src_addr, size, |
| 309 | KMemoryState::Normal, KMemoryPermission::All, | 309 | KMemoryState::All, KMemoryState::Normal, KMemoryPermission::All, |
| 310 | KMemoryPermission::ReadAndWrite, KMemoryAttribute::Mask, | 310 | KMemoryPermission::ReadAndWrite, KMemoryAttribute::Mask, |
| 311 | KMemoryAttribute::None, KMemoryAttribute::IpcAndDeviceMapped)); | 311 | KMemoryAttribute::None, KMemoryAttribute::IpcAndDeviceMapped)); |
| 312 | 312 | ||
| @@ -344,14 +344,14 @@ ResultCode KPageTable::UnmapProcessCodeMemory(VAddr dst_addr, VAddr src_addr, st | |||
| 344 | 344 | ||
| 345 | const std::size_t num_pages{size / PageSize}; | 345 | const std::size_t num_pages{size / PageSize}; |
| 346 | 346 | ||
| 347 | CASCADE_CODE(CheckMemoryState(nullptr, nullptr, nullptr, src_addr, size, KMemoryState::All, | 347 | CASCADE_CODE(CheckMemoryState(nullptr, nullptr, nullptr, nullptr, src_addr, size, |
| 348 | KMemoryState::Normal, KMemoryPermission::None, | 348 | KMemoryState::All, KMemoryState::Normal, KMemoryPermission::None, |
| 349 | KMemoryPermission::None, KMemoryAttribute::Mask, | 349 | KMemoryPermission::None, KMemoryAttribute::Mask, |
| 350 | KMemoryAttribute::Locked, KMemoryAttribute::IpcAndDeviceMapped)); | 350 | KMemoryAttribute::Locked, KMemoryAttribute::IpcAndDeviceMapped)); |
| 351 | 351 | ||
| 352 | KMemoryState state{}; | 352 | KMemoryState state{}; |
| 353 | CASCADE_CODE(CheckMemoryState( | 353 | CASCADE_CODE(CheckMemoryState( |
| 354 | &state, nullptr, nullptr, dst_addr, PageSize, KMemoryState::FlagCanCodeAlias, | 354 | &state, nullptr, nullptr, nullptr, dst_addr, PageSize, KMemoryState::FlagCanCodeAlias, |
| 355 | KMemoryState::FlagCanCodeAlias, KMemoryPermission::None, KMemoryPermission::None, | 355 | KMemoryState::FlagCanCodeAlias, KMemoryPermission::None, KMemoryPermission::None, |
| 356 | KMemoryAttribute::Mask, KMemoryAttribute::None, KMemoryAttribute::IpcAndDeviceMapped)); | 356 | KMemoryAttribute::Mask, KMemoryAttribute::None, KMemoryAttribute::IpcAndDeviceMapped)); |
| 357 | CASCADE_CODE(CheckMemoryState(dst_addr, size, KMemoryState::All, state, KMemoryPermission::None, | 357 | CASCADE_CODE(CheckMemoryState(dst_addr, size, KMemoryState::All, state, KMemoryPermission::None, |
| @@ -553,7 +553,7 @@ ResultCode KPageTable::Map(VAddr dst_addr, VAddr src_addr, std::size_t size) { | |||
| 553 | 553 | ||
| 554 | KMemoryState src_state{}; | 554 | KMemoryState src_state{}; |
| 555 | CASCADE_CODE(CheckMemoryState( | 555 | CASCADE_CODE(CheckMemoryState( |
| 556 | &src_state, nullptr, nullptr, src_addr, size, KMemoryState::FlagCanAlias, | 556 | &src_state, nullptr, nullptr, nullptr, src_addr, size, KMemoryState::FlagCanAlias, |
| 557 | KMemoryState::FlagCanAlias, KMemoryPermission::All, KMemoryPermission::ReadAndWrite, | 557 | KMemoryState::FlagCanAlias, KMemoryPermission::All, KMemoryPermission::ReadAndWrite, |
| 558 | KMemoryAttribute::Mask, KMemoryAttribute::None, KMemoryAttribute::IpcAndDeviceMapped)); | 558 | KMemoryAttribute::Mask, KMemoryAttribute::None, KMemoryAttribute::IpcAndDeviceMapped)); |
| 559 | 559 | ||
| @@ -592,13 +592,13 @@ ResultCode KPageTable::Unmap(VAddr dst_addr, VAddr src_addr, std::size_t size) { | |||
| 592 | 592 | ||
| 593 | KMemoryState src_state{}; | 593 | KMemoryState src_state{}; |
| 594 | CASCADE_CODE(CheckMemoryState( | 594 | CASCADE_CODE(CheckMemoryState( |
| 595 | &src_state, nullptr, nullptr, src_addr, size, KMemoryState::FlagCanAlias, | 595 | &src_state, nullptr, nullptr, nullptr, src_addr, size, KMemoryState::FlagCanAlias, |
| 596 | KMemoryState::FlagCanAlias, KMemoryPermission::All, KMemoryPermission::None, | 596 | KMemoryState::FlagCanAlias, KMemoryPermission::All, KMemoryPermission::None, |
| 597 | KMemoryAttribute::Mask, KMemoryAttribute::Locked, KMemoryAttribute::IpcAndDeviceMapped)); | 597 | KMemoryAttribute::Mask, KMemoryAttribute::Locked, KMemoryAttribute::IpcAndDeviceMapped)); |
| 598 | 598 | ||
| 599 | KMemoryPermission dst_perm{}; | 599 | KMemoryPermission dst_perm{}; |
| 600 | CASCADE_CODE(CheckMemoryState(nullptr, &dst_perm, nullptr, dst_addr, size, KMemoryState::All, | 600 | CASCADE_CODE(CheckMemoryState(nullptr, &dst_perm, nullptr, nullptr, dst_addr, size, |
| 601 | KMemoryState::Stack, KMemoryPermission::None, | 601 | KMemoryState::All, KMemoryState::Stack, KMemoryPermission::None, |
| 602 | KMemoryPermission::None, KMemoryAttribute::Mask, | 602 | KMemoryPermission::None, KMemoryAttribute::Mask, |
| 603 | KMemoryAttribute::None, KMemoryAttribute::IpcAndDeviceMapped)); | 603 | KMemoryAttribute::None, KMemoryAttribute::IpcAndDeviceMapped)); |
| 604 | 604 | ||
| @@ -721,7 +721,7 @@ ResultCode KPageTable::SetProcessMemoryPermission(VAddr addr, std::size_t size, | |||
| 721 | KMemoryPermission prev_perm{}; | 721 | KMemoryPermission prev_perm{}; |
| 722 | 722 | ||
| 723 | CASCADE_CODE(CheckMemoryState( | 723 | CASCADE_CODE(CheckMemoryState( |
| 724 | &prev_state, &prev_perm, nullptr, addr, size, KMemoryState::FlagCode, | 724 | &prev_state, &prev_perm, nullptr, nullptr, addr, size, KMemoryState::FlagCode, |
| 725 | KMemoryState::FlagCode, KMemoryPermission::None, KMemoryPermission::None, | 725 | KMemoryState::FlagCode, KMemoryPermission::None, KMemoryPermission::None, |
| 726 | KMemoryAttribute::Mask, KMemoryAttribute::None, KMemoryAttribute::IpcAndDeviceMapped)); | 726 | KMemoryAttribute::Mask, KMemoryAttribute::None, KMemoryAttribute::IpcAndDeviceMapped)); |
| 727 | 727 | ||
| @@ -782,7 +782,7 @@ ResultCode KPageTable::ReserveTransferMemory(VAddr addr, std::size_t size, KMemo | |||
| 782 | KMemoryAttribute attribute{}; | 782 | KMemoryAttribute attribute{}; |
| 783 | 783 | ||
| 784 | CASCADE_CODE(CheckMemoryState( | 784 | CASCADE_CODE(CheckMemoryState( |
| 785 | &state, nullptr, &attribute, addr, size, | 785 | &state, nullptr, &attribute, nullptr, addr, size, |
| 786 | KMemoryState::FlagCanTransfer | KMemoryState::FlagReferenceCounted, | 786 | KMemoryState::FlagCanTransfer | KMemoryState::FlagReferenceCounted, |
| 787 | KMemoryState::FlagCanTransfer | KMemoryState::FlagReferenceCounted, KMemoryPermission::All, | 787 | KMemoryState::FlagCanTransfer | KMemoryState::FlagReferenceCounted, KMemoryPermission::All, |
| 788 | KMemoryPermission::ReadAndWrite, KMemoryAttribute::Mask, KMemoryAttribute::None, | 788 | KMemoryPermission::ReadAndWrite, KMemoryAttribute::Mask, KMemoryAttribute::None, |
| @@ -799,7 +799,7 @@ ResultCode KPageTable::ResetTransferMemory(VAddr addr, std::size_t size) { | |||
| 799 | KMemoryState state{}; | 799 | KMemoryState state{}; |
| 800 | 800 | ||
| 801 | CASCADE_CODE( | 801 | CASCADE_CODE( |
| 802 | CheckMemoryState(&state, nullptr, nullptr, addr, size, | 802 | CheckMemoryState(&state, nullptr, nullptr, nullptr, addr, size, |
| 803 | KMemoryState::FlagCanTransfer | KMemoryState::FlagReferenceCounted, | 803 | KMemoryState::FlagCanTransfer | KMemoryState::FlagReferenceCounted, |
| 804 | KMemoryState::FlagCanTransfer | KMemoryState::FlagReferenceCounted, | 804 | KMemoryState::FlagCanTransfer | KMemoryState::FlagReferenceCounted, |
| 805 | KMemoryPermission::None, KMemoryPermission::None, KMemoryAttribute::Mask, | 805 | KMemoryPermission::None, KMemoryPermission::None, KMemoryAttribute::Mask, |
| @@ -820,7 +820,7 @@ ResultCode KPageTable::SetMemoryPermission(VAddr addr, std::size_t size, | |||
| 820 | KMemoryState old_state; | 820 | KMemoryState old_state; |
| 821 | KMemoryPermission old_perm; | 821 | KMemoryPermission old_perm; |
| 822 | R_TRY(this->CheckMemoryState( | 822 | R_TRY(this->CheckMemoryState( |
| 823 | std::addressof(old_state), std::addressof(old_perm), nullptr, addr, size, | 823 | std::addressof(old_state), std::addressof(old_perm), nullptr, nullptr, addr, size, |
| 824 | KMemoryState::FlagCanReprotect, KMemoryState::FlagCanReprotect, KMemoryPermission::None, | 824 | KMemoryState::FlagCanReprotect, KMemoryState::FlagCanReprotect, KMemoryPermission::None, |
| 825 | KMemoryPermission::None, KMemoryAttribute::All, KMemoryAttribute::None)); | 825 | KMemoryPermission::None, KMemoryAttribute::All, KMemoryAttribute::None)); |
| 826 | 826 | ||
| @@ -837,24 +837,36 @@ ResultCode KPageTable::SetMemoryPermission(VAddr addr, std::size_t size, | |||
| 837 | return ResultSuccess; | 837 | return ResultSuccess; |
| 838 | } | 838 | } |
| 839 | 839 | ||
| 840 | ResultCode KPageTable::SetMemoryAttribute(VAddr addr, std::size_t size, KMemoryAttribute mask, | 840 | ResultCode KPageTable::SetMemoryAttribute(VAddr addr, std::size_t size, u32 mask, u32 attr) { |
| 841 | KMemoryAttribute value) { | 841 | const size_t num_pages = size / PageSize; |
| 842 | std::lock_guard lock{page_table_lock}; | 842 | ASSERT((static_cast<KMemoryAttribute>(mask) | KMemoryAttribute::SetMask) == |
| 843 | KMemoryAttribute::SetMask); | ||
| 843 | 844 | ||
| 844 | KMemoryState state{}; | 845 | // Lock the table. |
| 845 | KMemoryPermission perm{}; | 846 | std::lock_guard lock{page_table_lock}; |
| 846 | KMemoryAttribute attribute{}; | ||
| 847 | 847 | ||
| 848 | CASCADE_CODE(CheckMemoryState( | 848 | // Verify we can change the memory attribute. |
| 849 | &state, &perm, &attribute, addr, size, KMemoryState::FlagCanChangeAttribute, | 849 | KMemoryState old_state; |
| 850 | KMemoryPermission old_perm; | ||
| 851 | KMemoryAttribute old_attr; | ||
| 852 | size_t num_allocator_blocks; | ||
| 853 | constexpr auto AttributeTestMask = | ||
| 854 | ~(KMemoryAttribute::SetMask | KMemoryAttribute::DeviceShared); | ||
| 855 | R_TRY(this->CheckMemoryState( | ||
| 856 | std::addressof(old_state), std::addressof(old_perm), std::addressof(old_attr), | ||
| 857 | std::addressof(num_allocator_blocks), addr, size, KMemoryState::FlagCanChangeAttribute, | ||
| 850 | KMemoryState::FlagCanChangeAttribute, KMemoryPermission::None, KMemoryPermission::None, | 858 | KMemoryState::FlagCanChangeAttribute, KMemoryPermission::None, KMemoryPermission::None, |
| 851 | KMemoryAttribute::LockedAndIpcLocked, KMemoryAttribute::None, | 859 | AttributeTestMask, KMemoryAttribute::None, ~AttributeTestMask)); |
| 852 | KMemoryAttribute::DeviceSharedAndUncached)); | 860 | |
| 861 | // Determine the new attribute. | ||
| 862 | const auto new_attr = ((old_attr & static_cast<KMemoryAttribute>(~mask)) | | ||
| 863 | static_cast<KMemoryAttribute>(attr & mask)); | ||
| 853 | 864 | ||
| 854 | attribute = attribute & ~mask; | 865 | // Perform operation. |
| 855 | attribute = attribute | (mask & value); | 866 | this->Operate(addr, num_pages, old_perm, OperationType::ChangePermissionsAndRefresh); |
| 856 | 867 | ||
| 857 | block_manager->Update(addr, size / PageSize, state, perm, attribute); | 868 | // Update the blocks. |
| 869 | block_manager->Update(addr, num_pages, old_state, old_perm, new_attr); | ||
| 858 | 870 | ||
| 859 | return ResultSuccess; | 871 | return ResultSuccess; |
| 860 | } | 872 | } |
| @@ -1019,7 +1031,7 @@ ResultCode KPageTable::LockForDeviceAddressSpace(VAddr addr, std::size_t size) { | |||
| 1019 | 1031 | ||
| 1020 | KMemoryPermission perm{}; | 1032 | KMemoryPermission perm{}; |
| 1021 | if (const ResultCode result{CheckMemoryState( | 1033 | if (const ResultCode result{CheckMemoryState( |
| 1022 | nullptr, &perm, nullptr, addr, size, KMemoryState::FlagCanChangeAttribute, | 1034 | nullptr, &perm, nullptr, nullptr, addr, size, KMemoryState::FlagCanChangeAttribute, |
| 1023 | KMemoryState::FlagCanChangeAttribute, KMemoryPermission::None, KMemoryPermission::None, | 1035 | KMemoryState::FlagCanChangeAttribute, KMemoryPermission::None, KMemoryPermission::None, |
| 1024 | KMemoryAttribute::LockedAndIpcLocked, KMemoryAttribute::None, | 1036 | KMemoryAttribute::LockedAndIpcLocked, KMemoryAttribute::None, |
| 1025 | KMemoryAttribute::DeviceSharedAndUncached)}; | 1037 | KMemoryAttribute::DeviceSharedAndUncached)}; |
| @@ -1042,7 +1054,7 @@ ResultCode KPageTable::UnlockForDeviceAddressSpace(VAddr addr, std::size_t size) | |||
| 1042 | 1054 | ||
| 1043 | KMemoryPermission perm{}; | 1055 | KMemoryPermission perm{}; |
| 1044 | if (const ResultCode result{CheckMemoryState( | 1056 | if (const ResultCode result{CheckMemoryState( |
| 1045 | nullptr, &perm, nullptr, addr, size, KMemoryState::FlagCanChangeAttribute, | 1057 | nullptr, &perm, nullptr, nullptr, addr, size, KMemoryState::FlagCanChangeAttribute, |
| 1046 | KMemoryState::FlagCanChangeAttribute, KMemoryPermission::None, KMemoryPermission::None, | 1058 | KMemoryState::FlagCanChangeAttribute, KMemoryPermission::None, KMemoryPermission::None, |
| 1047 | KMemoryAttribute::LockedAndIpcLocked, KMemoryAttribute::None, | 1059 | KMemoryAttribute::LockedAndIpcLocked, KMemoryAttribute::None, |
| 1048 | KMemoryAttribute::DeviceSharedAndUncached)}; | 1060 | KMemoryAttribute::DeviceSharedAndUncached)}; |
| @@ -1068,7 +1080,7 @@ ResultCode KPageTable::LockForCodeMemory(VAddr addr, std::size_t size) { | |||
| 1068 | KMemoryPermission old_perm{}; | 1080 | KMemoryPermission old_perm{}; |
| 1069 | 1081 | ||
| 1070 | if (const ResultCode result{CheckMemoryState( | 1082 | if (const ResultCode result{CheckMemoryState( |
| 1071 | nullptr, &old_perm, nullptr, addr, size, KMemoryState::FlagCanCodeMemory, | 1083 | nullptr, &old_perm, nullptr, nullptr, addr, size, KMemoryState::FlagCanCodeMemory, |
| 1072 | KMemoryState::FlagCanCodeMemory, KMemoryPermission::All, | 1084 | KMemoryState::FlagCanCodeMemory, KMemoryPermission::All, |
| 1073 | KMemoryPermission::UserReadWrite, KMemoryAttribute::All, KMemoryAttribute::None)}; | 1085 | KMemoryPermission::UserReadWrite, KMemoryAttribute::All, KMemoryAttribute::None)}; |
| 1074 | result.IsError()) { | 1086 | result.IsError()) { |
| @@ -1095,7 +1107,7 @@ ResultCode KPageTable::UnlockForCodeMemory(VAddr addr, std::size_t size) { | |||
| 1095 | KMemoryPermission old_perm{}; | 1107 | KMemoryPermission old_perm{}; |
| 1096 | 1108 | ||
| 1097 | if (const ResultCode result{CheckMemoryState( | 1109 | if (const ResultCode result{CheckMemoryState( |
| 1098 | nullptr, &old_perm, nullptr, addr, size, KMemoryState::FlagCanCodeMemory, | 1110 | nullptr, &old_perm, nullptr, nullptr, addr, size, KMemoryState::FlagCanCodeMemory, |
| 1099 | KMemoryState::FlagCanCodeMemory, KMemoryPermission::None, KMemoryPermission::None, | 1111 | KMemoryState::FlagCanCodeMemory, KMemoryPermission::None, KMemoryPermission::None, |
| 1100 | KMemoryAttribute::All, KMemoryAttribute::Locked)}; | 1112 | KMemoryAttribute::All, KMemoryAttribute::Locked)}; |
| 1101 | result.IsError()) { | 1113 | result.IsError()) { |
| @@ -1225,18 +1237,19 @@ constexpr VAddr KPageTable::GetRegionAddress(KMemoryState state) const { | |||
| 1225 | return alias_region_start; | 1237 | return alias_region_start; |
| 1226 | case KMemoryState::Stack: | 1238 | case KMemoryState::Stack: |
| 1227 | return stack_region_start; | 1239 | return stack_region_start; |
| 1228 | case KMemoryState::Io: | ||
| 1229 | case KMemoryState::Static: | 1240 | case KMemoryState::Static: |
| 1230 | case KMemoryState::ThreadLocal: | 1241 | case KMemoryState::ThreadLocal: |
| 1231 | return kernel_map_region_start; | 1242 | return kernel_map_region_start; |
| 1243 | case KMemoryState::Io: | ||
| 1232 | case KMemoryState::Shared: | 1244 | case KMemoryState::Shared: |
| 1233 | case KMemoryState::AliasCode: | 1245 | case KMemoryState::AliasCode: |
| 1234 | case KMemoryState::AliasCodeData: | 1246 | case KMemoryState::AliasCodeData: |
| 1235 | case KMemoryState::Transferred: | 1247 | case KMemoryState::Transfered: |
| 1236 | case KMemoryState::SharedTransferred: | 1248 | case KMemoryState::SharedTransfered: |
| 1237 | case KMemoryState::SharedCode: | 1249 | case KMemoryState::SharedCode: |
| 1238 | case KMemoryState::GeneratedCode: | 1250 | case KMemoryState::GeneratedCode: |
| 1239 | case KMemoryState::CodeOut: | 1251 | case KMemoryState::CodeOut: |
| 1252 | case KMemoryState::Coverage: | ||
| 1240 | return alias_code_region_start; | 1253 | return alias_code_region_start; |
| 1241 | case KMemoryState::Code: | 1254 | case KMemoryState::Code: |
| 1242 | case KMemoryState::CodeData: | 1255 | case KMemoryState::CodeData: |
| @@ -1260,18 +1273,19 @@ constexpr std::size_t KPageTable::GetRegionSize(KMemoryState state) const { | |||
| 1260 | return alias_region_end - alias_region_start; | 1273 | return alias_region_end - alias_region_start; |
| 1261 | case KMemoryState::Stack: | 1274 | case KMemoryState::Stack: |
| 1262 | return stack_region_end - stack_region_start; | 1275 | return stack_region_end - stack_region_start; |
| 1263 | case KMemoryState::Io: | ||
| 1264 | case KMemoryState::Static: | 1276 | case KMemoryState::Static: |
| 1265 | case KMemoryState::ThreadLocal: | 1277 | case KMemoryState::ThreadLocal: |
| 1266 | return kernel_map_region_end - kernel_map_region_start; | 1278 | return kernel_map_region_end - kernel_map_region_start; |
| 1279 | case KMemoryState::Io: | ||
| 1267 | case KMemoryState::Shared: | 1280 | case KMemoryState::Shared: |
| 1268 | case KMemoryState::AliasCode: | 1281 | case KMemoryState::AliasCode: |
| 1269 | case KMemoryState::AliasCodeData: | 1282 | case KMemoryState::AliasCodeData: |
| 1270 | case KMemoryState::Transferred: | 1283 | case KMemoryState::Transfered: |
| 1271 | case KMemoryState::SharedTransferred: | 1284 | case KMemoryState::SharedTransfered: |
| 1272 | case KMemoryState::SharedCode: | 1285 | case KMemoryState::SharedCode: |
| 1273 | case KMemoryState::GeneratedCode: | 1286 | case KMemoryState::GeneratedCode: |
| 1274 | case KMemoryState::CodeOut: | 1287 | case KMemoryState::CodeOut: |
| 1288 | case KMemoryState::Coverage: | ||
| 1275 | return alias_code_region_end - alias_code_region_start; | 1289 | return alias_code_region_end - alias_code_region_start; |
| 1276 | case KMemoryState::Code: | 1290 | case KMemoryState::Code: |
| 1277 | case KMemoryState::CodeData: | 1291 | case KMemoryState::CodeData: |
| @@ -1283,15 +1297,18 @@ constexpr std::size_t KPageTable::GetRegionSize(KMemoryState state) const { | |||
| 1283 | } | 1297 | } |
| 1284 | 1298 | ||
| 1285 | bool KPageTable::CanContain(VAddr addr, std::size_t size, KMemoryState state) const { | 1299 | bool KPageTable::CanContain(VAddr addr, std::size_t size, KMemoryState state) const { |
| 1286 | const VAddr end{addr + size}; | 1300 | const VAddr end = addr + size; |
| 1287 | const VAddr last{end - 1}; | 1301 | const VAddr last = end - 1; |
| 1288 | const VAddr region_start{GetRegionAddress(state)}; | 1302 | |
| 1289 | const std::size_t region_size{GetRegionSize(state)}; | 1303 | const VAddr region_start = this->GetRegionAddress(state); |
| 1290 | const bool is_in_region{region_start <= addr && addr < end && | 1304 | const size_t region_size = this->GetRegionSize(state); |
| 1291 | last <= region_start + region_size - 1}; | 1305 | |
| 1292 | const bool is_in_heap{!(end <= heap_region_start || heap_region_end <= addr)}; | 1306 | const bool is_in_region = |
| 1293 | const bool is_in_alias{!(end <= alias_region_start || alias_region_end <= addr)}; | 1307 | region_start <= addr && addr < end && last <= region_start + region_size - 1; |
| 1294 | 1308 | const bool is_in_heap = !(end <= heap_region_start || heap_region_end <= addr || | |
| 1309 | heap_region_start == heap_region_end); | ||
| 1310 | const bool is_in_alias = !(end <= alias_region_start || alias_region_end <= addr || | ||
| 1311 | alias_region_start == alias_region_end); | ||
| 1295 | switch (state) { | 1312 | switch (state) { |
| 1296 | case KMemoryState::Free: | 1313 | case KMemoryState::Free: |
| 1297 | case KMemoryState::Kernel: | 1314 | case KMemoryState::Kernel: |
| @@ -1305,11 +1322,12 @@ bool KPageTable::CanContain(VAddr addr, std::size_t size, KMemoryState state) co | |||
| 1305 | case KMemoryState::AliasCodeData: | 1322 | case KMemoryState::AliasCodeData: |
| 1306 | case KMemoryState::Stack: | 1323 | case KMemoryState::Stack: |
| 1307 | case KMemoryState::ThreadLocal: | 1324 | case KMemoryState::ThreadLocal: |
| 1308 | case KMemoryState::Transferred: | 1325 | case KMemoryState::Transfered: |
| 1309 | case KMemoryState::SharedTransferred: | 1326 | case KMemoryState::SharedTransfered: |
| 1310 | case KMemoryState::SharedCode: | 1327 | case KMemoryState::SharedCode: |
| 1311 | case KMemoryState::GeneratedCode: | 1328 | case KMemoryState::GeneratedCode: |
| 1312 | case KMemoryState::CodeOut: | 1329 | case KMemoryState::CodeOut: |
| 1330 | case KMemoryState::Coverage: | ||
| 1313 | return is_in_region && !is_in_heap && !is_in_alias; | 1331 | return is_in_region && !is_in_heap && !is_in_alias; |
| 1314 | case KMemoryState::Normal: | 1332 | case KMemoryState::Normal: |
| 1315 | ASSERT(is_in_heap); | 1333 | ASSERT(is_in_heap); |
| @@ -1324,100 +1342,91 @@ bool KPageTable::CanContain(VAddr addr, std::size_t size, KMemoryState state) co | |||
| 1324 | } | 1342 | } |
| 1325 | } | 1343 | } |
| 1326 | 1344 | ||
| 1327 | constexpr ResultCode KPageTable::CheckMemoryState(const KMemoryInfo& info, KMemoryState state_mask, | 1345 | ResultCode KPageTable::CheckMemoryState(const KMemoryInfo& info, KMemoryState state_mask, |
| 1328 | KMemoryState state, KMemoryPermission perm_mask, | 1346 | KMemoryState state, KMemoryPermission perm_mask, |
| 1329 | KMemoryPermission perm, | 1347 | KMemoryPermission perm, KMemoryAttribute attr_mask, |
| 1330 | KMemoryAttribute attr_mask, | 1348 | KMemoryAttribute attr) const { |
| 1331 | KMemoryAttribute attr) const { | 1349 | // Validate the states match expectation. |
| 1332 | // Validate the states match expectation | 1350 | R_UNLESS((info.state & state_mask) == state, ResultInvalidCurrentMemory); |
| 1333 | if ((info.state & state_mask) != state) { | 1351 | R_UNLESS((info.perm & perm_mask) == perm, ResultInvalidCurrentMemory); |
| 1334 | return ResultInvalidCurrentMemory; | 1352 | R_UNLESS((info.attribute & attr_mask) == attr, ResultInvalidCurrentMemory); |
| 1335 | } | ||
| 1336 | if ((info.perm & perm_mask) != perm) { | ||
| 1337 | return ResultInvalidCurrentMemory; | ||
| 1338 | } | ||
| 1339 | if ((info.attribute & attr_mask) != attr) { | ||
| 1340 | return ResultInvalidCurrentMemory; | ||
| 1341 | } | ||
| 1342 | 1353 | ||
| 1343 | return ResultSuccess; | 1354 | return ResultSuccess; |
| 1344 | } | 1355 | } |
| 1345 | 1356 | ||
| 1346 | ResultCode KPageTable::CheckMemoryState(KMemoryState* out_state, KMemoryPermission* out_perm, | 1357 | ResultCode KPageTable::CheckMemoryStateContiguous(std::size_t* out_blocks_needed, VAddr addr, |
| 1347 | KMemoryAttribute* out_attr, VAddr addr, std::size_t size, | 1358 | std::size_t size, KMemoryState state_mask, |
| 1348 | KMemoryState state_mask, KMemoryState state, | 1359 | KMemoryState state, KMemoryPermission perm_mask, |
| 1349 | KMemoryPermission perm_mask, KMemoryPermission perm, | 1360 | KMemoryPermission perm, |
| 1350 | KMemoryAttribute attr_mask, KMemoryAttribute attr, | 1361 | KMemoryAttribute attr_mask, |
| 1351 | KMemoryAttribute ignore_attr) { | 1362 | KMemoryAttribute attr) const { |
| 1352 | std::lock_guard lock{page_table_lock}; | 1363 | ASSERT(this->IsLockedByCurrentThread()); |
| 1353 | 1364 | ||
| 1354 | // Get information about the first block | 1365 | // Get information about the first block. |
| 1355 | const VAddr last_addr{addr + size - 1}; | 1366 | const VAddr last_addr = addr + size - 1; |
| 1356 | KMemoryBlockManager::const_iterator it{block_manager->FindIterator(addr)}; | 1367 | KMemoryBlockManager::const_iterator it = block_manager->FindIterator(addr); |
| 1357 | KMemoryInfo info{it->GetMemoryInfo()}; | 1368 | KMemoryInfo info = it->GetMemoryInfo(); |
| 1358 | 1369 | ||
| 1359 | // Validate all blocks in the range have correct state | 1370 | // If the start address isn't aligned, we need a block. |
| 1360 | const KMemoryState first_state{info.state}; | 1371 | const size_t blocks_for_start_align = |
| 1361 | const KMemoryPermission first_perm{info.perm}; | 1372 | (Common::AlignDown(addr, PageSize) != info.GetAddress()) ? 1 : 0; |
| 1362 | const KMemoryAttribute first_attr{info.attribute}; | ||
| 1363 | 1373 | ||
| 1364 | while (true) { | 1374 | while (true) { |
| 1365 | // Validate the current block | 1375 | // Validate against the provided masks. |
| 1366 | if (!(info.state == first_state)) { | 1376 | R_TRY(this->CheckMemoryState(info, state_mask, state, perm_mask, perm, attr_mask, attr)); |
| 1367 | return ResultInvalidCurrentMemory; | ||
| 1368 | } | ||
| 1369 | if (!(info.perm == first_perm)) { | ||
| 1370 | return ResultInvalidCurrentMemory; | ||
| 1371 | } | ||
| 1372 | if (!((info.attribute | static_cast<KMemoryAttribute>(ignore_attr)) == | ||
| 1373 | (first_attr | static_cast<KMemoryAttribute>(ignore_attr)))) { | ||
| 1374 | return ResultInvalidCurrentMemory; | ||
| 1375 | } | ||
| 1376 | |||
| 1377 | // Validate against the provided masks | ||
| 1378 | CASCADE_CODE(CheckMemoryState(info, state_mask, state, perm_mask, perm, attr_mask, attr)); | ||
| 1379 | 1377 | ||
| 1380 | // Break once we're done | 1378 | // Break once we're done. |
| 1381 | if (last_addr <= info.GetLastAddress()) { | 1379 | if (last_addr <= info.GetLastAddress()) { |
| 1382 | break; | 1380 | break; |
| 1383 | } | 1381 | } |
| 1384 | 1382 | ||
| 1385 | // Advance our iterator | 1383 | // Advance our iterator. |
| 1386 | it++; | 1384 | it++; |
| 1387 | ASSERT(it != block_manager->cend()); | 1385 | ASSERT(it != block_manager->cend()); |
| 1388 | info = it->GetMemoryInfo(); | 1386 | info = it->GetMemoryInfo(); |
| 1389 | } | 1387 | } |
| 1390 | 1388 | ||
| 1391 | // Write output state | 1389 | // If the end address isn't aligned, we need a block. |
| 1392 | if (out_state) { | 1390 | const size_t blocks_for_end_align = |
| 1393 | *out_state = first_state; | 1391 | (Common::AlignUp(addr + size, PageSize) != info.GetEndAddress()) ? 1 : 0; |
| 1394 | } | 1392 | |
| 1395 | if (out_perm) { | 1393 | if (out_blocks_needed != nullptr) { |
| 1396 | *out_perm = first_perm; | 1394 | *out_blocks_needed = blocks_for_start_align + blocks_for_end_align; |
| 1397 | } | ||
| 1398 | if (out_attr) { | ||
| 1399 | *out_attr = first_attr & static_cast<KMemoryAttribute>(~ignore_attr); | ||
| 1400 | } | 1395 | } |
| 1401 | 1396 | ||
| 1402 | return ResultSuccess; | 1397 | return ResultSuccess; |
| 1403 | } | 1398 | } |
| 1404 | 1399 | ||
| 1405 | ResultCode KPageTable::CheckMemoryState(size_t* out_blocks_needed, VAddr addr, size_t size, | 1400 | ResultCode KPageTable::CheckMemoryState(KMemoryState* out_state, KMemoryPermission* out_perm, |
| 1406 | KMemoryState state_mask, KMemoryState state, | 1401 | KMemoryAttribute* out_attr, std::size_t* out_blocks_needed, |
| 1407 | KMemoryPermission perm_mask, KMemoryPermission perm, | 1402 | VAddr addr, std::size_t size, KMemoryState state_mask, |
| 1408 | KMemoryAttribute attr_mask, KMemoryAttribute attr) const { | 1403 | KMemoryState state, KMemoryPermission perm_mask, |
| 1404 | KMemoryPermission perm, KMemoryAttribute attr_mask, | ||
| 1405 | KMemoryAttribute attr, KMemoryAttribute ignore_attr) const { | ||
| 1406 | ASSERT(this->IsLockedByCurrentThread()); | ||
| 1407 | |||
| 1409 | // Get information about the first block. | 1408 | // Get information about the first block. |
| 1410 | const VAddr last_addr = addr + size - 1; | 1409 | const VAddr last_addr = addr + size - 1; |
| 1411 | KMemoryBlockManager::const_iterator it{block_manager->FindIterator(addr)}; | 1410 | KMemoryBlockManager::const_iterator it = block_manager->FindIterator(addr); |
| 1412 | KMemoryInfo info = it->GetMemoryInfo(); | 1411 | KMemoryInfo info = it->GetMemoryInfo(); |
| 1413 | 1412 | ||
| 1414 | // If the start address isn't aligned, we need a block. | 1413 | // If the start address isn't aligned, we need a block. |
| 1415 | const size_t blocks_for_start_align = | 1414 | const size_t blocks_for_start_align = |
| 1416 | (Common::AlignDown(addr, PageSize) != info.GetAddress()) ? 1 : 0; | 1415 | (Common::AlignDown(addr, PageSize) != info.GetAddress()) ? 1 : 0; |
| 1417 | 1416 | ||
| 1417 | // Validate all blocks in the range have correct state. | ||
| 1418 | const KMemoryState first_state = info.state; | ||
| 1419 | const KMemoryPermission first_perm = info.perm; | ||
| 1420 | const KMemoryAttribute first_attr = info.attribute; | ||
| 1418 | while (true) { | 1421 | while (true) { |
| 1422 | // Validate the current block. | ||
| 1423 | R_UNLESS(info.state == first_state, ResultInvalidCurrentMemory); | ||
| 1424 | R_UNLESS(info.perm == first_perm, ResultInvalidCurrentMemory); | ||
| 1425 | R_UNLESS((info.attribute | ignore_attr) == (first_attr | ignore_attr), | ||
| 1426 | ResultInvalidCurrentMemory); | ||
| 1427 | |||
| 1419 | // Validate against the provided masks. | 1428 | // Validate against the provided masks. |
| 1420 | R_TRY(CheckMemoryState(info, state_mask, state, perm_mask, perm, attr_mask, attr)); | 1429 | R_TRY(this->CheckMemoryState(info, state_mask, state, perm_mask, perm, attr_mask, attr)); |
| 1421 | 1430 | ||
| 1422 | // Break once we're done. | 1431 | // Break once we're done. |
| 1423 | if (last_addr <= info.GetLastAddress()) { | 1432 | if (last_addr <= info.GetLastAddress()) { |
| @@ -1426,6 +1435,7 @@ ResultCode KPageTable::CheckMemoryState(size_t* out_blocks_needed, VAddr addr, s | |||
| 1426 | 1435 | ||
| 1427 | // Advance our iterator. | 1436 | // Advance our iterator. |
| 1428 | it++; | 1437 | it++; |
| 1438 | ASSERT(it != block_manager->cend()); | ||
| 1429 | info = it->GetMemoryInfo(); | 1439 | info = it->GetMemoryInfo(); |
| 1430 | } | 1440 | } |
| 1431 | 1441 | ||
| @@ -1433,10 +1443,19 @@ ResultCode KPageTable::CheckMemoryState(size_t* out_blocks_needed, VAddr addr, s | |||
| 1433 | const size_t blocks_for_end_align = | 1443 | const size_t blocks_for_end_align = |
| 1434 | (Common::AlignUp(addr + size, PageSize) != info.GetEndAddress()) ? 1 : 0; | 1444 | (Common::AlignUp(addr + size, PageSize) != info.GetEndAddress()) ? 1 : 0; |
| 1435 | 1445 | ||
| 1446 | // Write output state. | ||
| 1447 | if (out_state != nullptr) { | ||
| 1448 | *out_state = first_state; | ||
| 1449 | } | ||
| 1450 | if (out_perm != nullptr) { | ||
| 1451 | *out_perm = first_perm; | ||
| 1452 | } | ||
| 1453 | if (out_attr != nullptr) { | ||
| 1454 | *out_attr = static_cast<KMemoryAttribute>(first_attr & ~ignore_attr); | ||
| 1455 | } | ||
| 1436 | if (out_blocks_needed != nullptr) { | 1456 | if (out_blocks_needed != nullptr) { |
| 1437 | *out_blocks_needed = blocks_for_start_align + blocks_for_end_align; | 1457 | *out_blocks_needed = blocks_for_start_align + blocks_for_end_align; |
| 1438 | } | 1458 | } |
| 1439 | |||
| 1440 | return ResultSuccess; | 1459 | return ResultSuccess; |
| 1441 | } | 1460 | } |
| 1442 | 1461 | ||
diff --git a/src/core/hle/kernel/k_page_table.h b/src/core/hle/kernel/k_page_table.h index 564410dca..9235b822a 100644 --- a/src/core/hle/kernel/k_page_table.h +++ b/src/core/hle/kernel/k_page_table.h | |||
| @@ -48,8 +48,7 @@ public: | |||
| 48 | ResultCode ReserveTransferMemory(VAddr addr, std::size_t size, KMemoryPermission perm); | 48 | ResultCode ReserveTransferMemory(VAddr addr, std::size_t size, KMemoryPermission perm); |
| 49 | ResultCode ResetTransferMemory(VAddr addr, std::size_t size); | 49 | ResultCode ResetTransferMemory(VAddr addr, std::size_t size); |
| 50 | ResultCode SetMemoryPermission(VAddr addr, std::size_t size, Svc::MemoryPermission perm); | 50 | ResultCode SetMemoryPermission(VAddr addr, std::size_t size, Svc::MemoryPermission perm); |
| 51 | ResultCode SetMemoryAttribute(VAddr addr, std::size_t size, KMemoryAttribute mask, | 51 | ResultCode SetMemoryAttribute(VAddr addr, std::size_t size, u32 mask, u32 attr); |
| 52 | KMemoryAttribute value); | ||
| 53 | ResultCode SetMaxHeapSize(std::size_t size); | 52 | ResultCode SetMaxHeapSize(std::size_t size); |
| 54 | ResultCode SetHeapSize(VAddr* out, std::size_t size); | 53 | ResultCode SetHeapSize(VAddr* out, std::size_t size); |
| 55 | ResultVal<VAddr> AllocateAndMapMemory(std::size_t needed_num_pages, std::size_t align, | 54 | ResultVal<VAddr> AllocateAndMapMemory(std::size_t needed_num_pages, std::size_t align, |
| @@ -102,28 +101,50 @@ private: | |||
| 102 | constexpr VAddr GetRegionAddress(KMemoryState state) const; | 101 | constexpr VAddr GetRegionAddress(KMemoryState state) const; |
| 103 | constexpr std::size_t GetRegionSize(KMemoryState state) const; | 102 | constexpr std::size_t GetRegionSize(KMemoryState state) const; |
| 104 | 103 | ||
| 105 | constexpr ResultCode CheckMemoryState(const KMemoryInfo& info, KMemoryState state_mask, | 104 | ResultCode CheckMemoryStateContiguous(std::size_t* out_blocks_needed, VAddr addr, |
| 105 | std::size_t size, KMemoryState state_mask, | ||
| 106 | KMemoryState state, KMemoryPermission perm_mask, | 106 | KMemoryState state, KMemoryPermission perm_mask, |
| 107 | KMemoryPermission perm, KMemoryAttribute attr_mask, | 107 | KMemoryPermission perm, KMemoryAttribute attr_mask, |
| 108 | KMemoryAttribute attr) const; | 108 | KMemoryAttribute attr) const; |
| 109 | ResultCode CheckMemoryStateContiguous(VAddr addr, std::size_t size, KMemoryState state_mask, | ||
| 110 | KMemoryState state, KMemoryPermission perm_mask, | ||
| 111 | KMemoryPermission perm, KMemoryAttribute attr_mask, | ||
| 112 | KMemoryAttribute attr) const { | ||
| 113 | return this->CheckMemoryStateContiguous(nullptr, addr, size, state_mask, state, perm_mask, | ||
| 114 | perm, attr_mask, attr); | ||
| 115 | } | ||
| 116 | |||
| 117 | ResultCode CheckMemoryState(const KMemoryInfo& info, KMemoryState state_mask, | ||
| 118 | KMemoryState state, KMemoryPermission perm_mask, | ||
| 119 | KMemoryPermission perm, KMemoryAttribute attr_mask, | ||
| 120 | KMemoryAttribute attr) const; | ||
| 109 | ResultCode CheckMemoryState(KMemoryState* out_state, KMemoryPermission* out_perm, | 121 | ResultCode CheckMemoryState(KMemoryState* out_state, KMemoryPermission* out_perm, |
| 110 | KMemoryAttribute* out_attr, VAddr addr, std::size_t size, | 122 | KMemoryAttribute* out_attr, std::size_t* out_blocks_needed, |
| 123 | VAddr addr, std::size_t size, KMemoryState state_mask, | ||
| 124 | KMemoryState state, KMemoryPermission perm_mask, | ||
| 125 | KMemoryPermission perm, KMemoryAttribute attr_mask, | ||
| 126 | KMemoryAttribute attr, | ||
| 127 | KMemoryAttribute ignore_attr = DefaultMemoryIgnoreAttr) const; | ||
| 128 | ResultCode CheckMemoryState(std::size_t* out_blocks_needed, VAddr addr, std::size_t size, | ||
| 111 | KMemoryState state_mask, KMemoryState state, | 129 | KMemoryState state_mask, KMemoryState state, |
| 112 | KMemoryPermission perm_mask, KMemoryPermission perm, | 130 | KMemoryPermission perm_mask, KMemoryPermission perm, |
| 113 | KMemoryAttribute attr_mask, KMemoryAttribute attr, | 131 | KMemoryAttribute attr_mask, KMemoryAttribute attr, |
| 114 | KMemoryAttribute ignore_attr = DefaultMemoryIgnoreAttr); | 132 | KMemoryAttribute ignore_attr = DefaultMemoryIgnoreAttr) const { |
| 115 | ResultCode CheckMemoryState(VAddr addr, std::size_t size, KMemoryState state_mask, | 133 | return CheckMemoryState(nullptr, nullptr, nullptr, out_blocks_needed, addr, size, |
| 134 | state_mask, state, perm_mask, perm, attr_mask, attr, ignore_attr); | ||
| 135 | } | ||
| 136 | ResultCode CheckMemoryState(VAddr addr, size_t size, KMemoryState state_mask, | ||
| 116 | KMemoryState state, KMemoryPermission perm_mask, | 137 | KMemoryState state, KMemoryPermission perm_mask, |
| 117 | KMemoryPermission perm, KMemoryAttribute attr_mask, | 138 | KMemoryPermission perm, KMemoryAttribute attr_mask, |
| 118 | KMemoryAttribute attr, | 139 | KMemoryAttribute attr, |
| 119 | KMemoryAttribute ignore_attr = DefaultMemoryIgnoreAttr) { | 140 | KMemoryAttribute ignore_attr = DefaultMemoryIgnoreAttr) const { |
| 120 | return CheckMemoryState(nullptr, nullptr, nullptr, addr, size, state_mask, state, perm_mask, | 141 | return this->CheckMemoryState(nullptr, addr, size, state_mask, state, perm_mask, perm, |
| 121 | perm, attr_mask, attr, ignore_attr); | 142 | attr_mask, attr, ignore_attr); |
| 143 | } | ||
| 144 | |||
| 145 | bool IsLockedByCurrentThread() const { | ||
| 146 | return true; | ||
| 122 | } | 147 | } |
| 123 | ResultCode CheckMemoryState(size_t* out_blocks_needed, VAddr addr, size_t size, | ||
| 124 | KMemoryState state_mask, KMemoryState state, | ||
| 125 | KMemoryPermission perm_mask, KMemoryPermission perm, | ||
| 126 | KMemoryAttribute attr_mask, KMemoryAttribute attr) const; | ||
| 127 | 148 | ||
| 128 | std::recursive_mutex page_table_lock; | 149 | std::recursive_mutex page_table_lock; |
| 129 | std::unique_ptr<KMemoryBlockManager> block_manager; | 150 | std::unique_ptr<KMemoryBlockManager> block_manager; |
diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp index 250ef9042..4362508a3 100644 --- a/src/core/hle/kernel/svc.cpp +++ b/src/core/hle/kernel/svc.cpp | |||
| @@ -168,6 +168,9 @@ constexpr bool IsValidSetMemoryPermission(MemoryPermission perm) { | |||
| 168 | 168 | ||
| 169 | static ResultCode SetMemoryPermission(Core::System& system, VAddr address, u64 size, | 169 | static ResultCode SetMemoryPermission(Core::System& system, VAddr address, u64 size, |
| 170 | MemoryPermission perm) { | 170 | MemoryPermission perm) { |
| 171 | LOG_DEBUG(Kernel_SVC, "called, address=0x{:016X}, size=0x{:X}, perm=0x{:08X", address, size, | ||
| 172 | perm); | ||
| 173 | |||
| 171 | // Validate address / size. | 174 | // Validate address / size. |
| 172 | R_UNLESS(Common::IsAligned(address, PageSize), ResultInvalidAddress); | 175 | R_UNLESS(Common::IsAligned(address, PageSize), ResultInvalidAddress); |
| 173 | R_UNLESS(Common::IsAligned(size, PageSize), ResultInvalidSize); | 176 | R_UNLESS(Common::IsAligned(size, PageSize), ResultInvalidSize); |
| @@ -186,46 +189,33 @@ static ResultCode SetMemoryPermission(Core::System& system, VAddr address, u64 s | |||
| 186 | } | 189 | } |
| 187 | 190 | ||
| 188 | static ResultCode SetMemoryAttribute(Core::System& system, VAddr address, u64 size, u32 mask, | 191 | static ResultCode SetMemoryAttribute(Core::System& system, VAddr address, u64 size, u32 mask, |
| 189 | u32 attribute) { | 192 | u32 attr) { |
| 190 | LOG_DEBUG(Kernel_SVC, | 193 | LOG_DEBUG(Kernel_SVC, |
| 191 | "called, address=0x{:016X}, size=0x{:X}, mask=0x{:08X}, attribute=0x{:08X}", address, | 194 | "called, address=0x{:016X}, size=0x{:X}, mask=0x{:08X}, attribute=0x{:08X}", address, |
| 192 | size, mask, attribute); | 195 | size, mask, attr); |
| 193 | |||
| 194 | if (!Common::Is4KBAligned(address)) { | ||
| 195 | LOG_ERROR(Kernel_SVC, "Address not page aligned (0x{:016X})", address); | ||
| 196 | return ResultInvalidAddress; | ||
| 197 | } | ||
| 198 | 196 | ||
| 199 | if (size == 0 || !Common::Is4KBAligned(size)) { | 197 | // Validate address / size. |
| 200 | LOG_ERROR(Kernel_SVC, "Invalid size (0x{:X}). Size must be non-zero and page aligned.", | 198 | R_UNLESS(Common::IsAligned(address, PageSize), ResultInvalidAddress); |
| 201 | size); | 199 | R_UNLESS(Common::IsAligned(size, PageSize), ResultInvalidSize); |
| 202 | return ResultInvalidAddress; | 200 | R_UNLESS(size > 0, ResultInvalidSize); |
| 203 | } | 201 | R_UNLESS((address < address + size), ResultInvalidCurrentMemory); |
| 204 | |||
| 205 | if (!IsValidAddressRange(address, size)) { | ||
| 206 | LOG_ERROR(Kernel_SVC, "Address range overflowed (Address: 0x{:016X}, Size: 0x{:016X})", | ||
| 207 | address, size); | ||
| 208 | return ResultInvalidCurrentMemory; | ||
| 209 | } | ||
| 210 | 202 | ||
| 211 | const auto attributes{static_cast<MemoryAttribute>(mask | attribute)}; | 203 | // Validate the attribute and mask. |
| 212 | if (attributes != static_cast<MemoryAttribute>(mask) || | 204 | constexpr u32 SupportedMask = static_cast<u32>(MemoryAttribute::Uncached); |
| 213 | (attributes | MemoryAttribute::Uncached) != MemoryAttribute::Uncached) { | 205 | R_UNLESS((mask | attr) == mask, ResultInvalidCombination); |
| 214 | LOG_ERROR(Kernel_SVC, | 206 | R_UNLESS((mask | attr | SupportedMask) == SupportedMask, ResultInvalidCombination); |
| 215 | "Memory attribute doesn't match the given mask (Attribute: 0x{:X}, Mask: {:X}", | ||
| 216 | attribute, mask); | ||
| 217 | return ResultInvalidCombination; | ||
| 218 | } | ||
| 219 | 207 | ||
| 208 | // Validate that the region is in range for the current process. | ||
| 220 | auto& page_table{system.Kernel().CurrentProcess()->PageTable()}; | 209 | auto& page_table{system.Kernel().CurrentProcess()->PageTable()}; |
| 210 | R_UNLESS(page_table.Contains(address, size), ResultInvalidCurrentMemory); | ||
| 221 | 211 | ||
| 222 | return page_table.SetMemoryAttribute(address, size, static_cast<KMemoryAttribute>(mask), | 212 | // Set the memory attribute. |
| 223 | static_cast<KMemoryAttribute>(attribute)); | 213 | return page_table.SetMemoryAttribute(address, size, mask, attr); |
| 224 | } | 214 | } |
| 225 | 215 | ||
| 226 | static ResultCode SetMemoryAttribute32(Core::System& system, u32 address, u32 size, u32 mask, | 216 | static ResultCode SetMemoryAttribute32(Core::System& system, u32 address, u32 size, u32 mask, |
| 227 | u32 attribute) { | 217 | u32 attr) { |
| 228 | return SetMemoryAttribute(system, address, size, mask, attribute); | 218 | return SetMemoryAttribute(system, address, size, mask, attr); |
| 229 | } | 219 | } |
| 230 | 220 | ||
| 231 | /// Maps a memory range into a different range. | 221 | /// Maps a memory range into a different range. |
diff --git a/src/core/hle/kernel/svc_types.h b/src/core/hle/kernel/svc_types.h index ec463b97c..365e22e4e 100644 --- a/src/core/hle/kernel/svc_types.h +++ b/src/core/hle/kernel/svc_types.h | |||
| @@ -32,6 +32,7 @@ enum class MemoryState : u32 { | |||
| 32 | Kernel = 0x13, | 32 | Kernel = 0x13, |
| 33 | GeneratedCode = 0x14, | 33 | GeneratedCode = 0x14, |
| 34 | CodeOut = 0x15, | 34 | CodeOut = 0x15, |
| 35 | Coverage = 0x16, | ||
| 35 | }; | 36 | }; |
| 36 | DECLARE_ENUM_FLAG_OPERATORS(MemoryState); | 37 | DECLARE_ENUM_FLAG_OPERATORS(MemoryState); |
| 37 | 38 | ||