summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/core/hle/kernel/k_memory_block.h36
-rw-r--r--src/core/hle/kernel/k_page_table.cpp237
-rw-r--r--src/core/hle/kernel/k_page_table.h47
-rw-r--r--src/core/hle/kernel/svc.cpp50
-rw-r--r--src/core/hle/kernel/svc_types.h1
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};
97DECLARE_ENUM_FLAG_OPERATORS(KMemoryState); 99DECLARE_ENUM_FLAG_OPERATORS(KMemoryState);
98 100
@@ -108,8 +110,8 @@ static_assert(static_cast<u32>(KMemoryState::AliasCodeData) == 0x03FFBD09);
108static_assert(static_cast<u32>(KMemoryState::Ipc) == 0x005C3C0A); 110static_assert(static_cast<u32>(KMemoryState::Ipc) == 0x005C3C0A);
109static_assert(static_cast<u32>(KMemoryState::Stack) == 0x005C3C0B); 111static_assert(static_cast<u32>(KMemoryState::Stack) == 0x005C3C0B);
110static_assert(static_cast<u32>(KMemoryState::ThreadLocal) == 0x0040200C); 112static_assert(static_cast<u32>(KMemoryState::ThreadLocal) == 0x0040200C);
111static_assert(static_cast<u32>(KMemoryState::Transferred) == 0x015C3C0D); 113static_assert(static_cast<u32>(KMemoryState::Transfered) == 0x015C3C0D);
112static_assert(static_cast<u32>(KMemoryState::SharedTransferred) == 0x005C380E); 114static_assert(static_cast<u32>(KMemoryState::SharedTransfered) == 0x005C380E);
113static_assert(static_cast<u32>(KMemoryState::SharedCode) == 0x0040380F); 115static_assert(static_cast<u32>(KMemoryState::SharedCode) == 0x0040380F);
114static_assert(static_cast<u32>(KMemoryState::Inaccessible) == 0x00000010); 116static_assert(static_cast<u32>(KMemoryState::Inaccessible) == 0x00000010);
115static_assert(static_cast<u32>(KMemoryState::NonSecureIpc) == 0x005C3811); 117static_assert(static_cast<u32>(KMemoryState::NonSecureIpc) == 0x005C3811);
@@ -117,6 +119,7 @@ static_assert(static_cast<u32>(KMemoryState::NonDeviceIpc) == 0x004C2812);
117static_assert(static_cast<u32>(KMemoryState::Kernel) == 0x00002013); 119static_assert(static_cast<u32>(KMemoryState::Kernel) == 0x00002013);
118static_assert(static_cast<u32>(KMemoryState::GeneratedCode) == 0x00402214); 120static_assert(static_cast<u32>(KMemoryState::GeneratedCode) == 0x00402214);
119static_assert(static_cast<u32>(KMemoryState::CodeOut) == 0x00402015); 121static_assert(static_cast<u32>(KMemoryState::CodeOut) == 0x00402015);
122static_assert(static_cast<u32>(KMemoryState::Coverage) == 0x00002016);
120 123
121enum class KMemoryPermission : u8 { 124enum class KMemoryPermission : u8 {
122 None = 0, 125 None = 0,
@@ -155,7 +158,13 @@ enum class KMemoryPermission : u8 {
155DECLARE_ENUM_FLAG_OPERATORS(KMemoryPermission); 158DECLARE_ENUM_FLAG_OPERATORS(KMemoryPermission);
156 159
157constexpr KMemoryPermission ConvertToKMemoryPermission(Svc::MemoryPermission perm) { 160constexpr 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
161enum class KMemoryAttribute : u8 { 170enum 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
220class KMemoryBlock final { 240class 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
840ResultCode KPageTable::SetMemoryAttribute(VAddr addr, std::size_t size, KMemoryAttribute mask, 840ResultCode 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
1285bool KPageTable::CanContain(VAddr addr, std::size_t size, KMemoryState state) const { 1299bool 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
1327constexpr ResultCode KPageTable::CheckMemoryState(const KMemoryInfo& info, KMemoryState state_mask, 1345ResultCode 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
1346ResultCode KPageTable::CheckMemoryState(KMemoryState* out_state, KMemoryPermission* out_perm, 1357ResultCode 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
1405ResultCode KPageTable::CheckMemoryState(size_t* out_blocks_needed, VAddr addr, size_t size, 1400ResultCode 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
169static ResultCode SetMemoryPermission(Core::System& system, VAddr address, u64 size, 169static 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
188static ResultCode SetMemoryAttribute(Core::System& system, VAddr address, u64 size, u32 mask, 191static 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
226static ResultCode SetMemoryAttribute32(Core::System& system, u32 address, u32 size, u32 mask, 216static 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};
36DECLARE_ENUM_FLAG_OPERATORS(MemoryState); 37DECLARE_ENUM_FLAG_OPERATORS(MemoryState);
37 38