diff options
Diffstat (limited to 'src/core/hle/kernel')
-rw-r--r-- | src/core/hle/kernel/k_page_table.cpp | 38 | ||||
-rw-r--r-- | src/core/hle/kernel/k_page_table.h | 3 | ||||
-rw-r--r-- | src/core/hle/kernel/svc.cpp | 50 |
3 files changed, 46 insertions, 45 deletions
diff --git a/src/core/hle/kernel/k_page_table.cpp b/src/core/hle/kernel/k_page_table.cpp index e86ded58b..6077985b5 100644 --- a/src/core/hle/kernel/k_page_table.cpp +++ b/src/core/hle/kernel/k_page_table.cpp @@ -837,24 +837,36 @@ ResultCode KPageTable::SetMemoryPermission(VAddr addr, std::size_t size, return ResultSuccess; } -ResultCode KPageTable::SetMemoryAttribute(VAddr addr, std::size_t size, KMemoryAttribute mask, - KMemoryAttribute value) { - std::lock_guard lock{page_table_lock}; +ResultCode KPageTable::SetMemoryAttribute(VAddr addr, std::size_t size, u32 mask, u32 attr) { + const size_t num_pages = size / PageSize; + ASSERT((static_cast<KMemoryAttribute>(mask) | KMemoryAttribute::SetMask) == + KMemoryAttribute::SetMask); - KMemoryState state{}; - KMemoryPermission perm{}; - KMemoryAttribute attribute{}; + // Lock the table. + std::lock_guard lock{page_table_lock}; - CASCADE_CODE(CheckMemoryState( - &state, &perm, &attribute, nullptr, addr, size, KMemoryState::FlagCanChangeAttribute, + // Verify we can change the memory attribute. + KMemoryState old_state; + KMemoryPermission old_perm; + KMemoryAttribute old_attr; + size_t num_allocator_blocks; + constexpr auto AttributeTestMask = + ~(KMemoryAttribute::SetMask | KMemoryAttribute::DeviceShared); + R_TRY(this->CheckMemoryState( + std::addressof(old_state), std::addressof(old_perm), std::addressof(old_attr), + std::addressof(num_allocator_blocks), addr, size, KMemoryState::FlagCanChangeAttribute, KMemoryState::FlagCanChangeAttribute, KMemoryPermission::None, KMemoryPermission::None, - KMemoryAttribute::LockedAndIpcLocked, KMemoryAttribute::None, - KMemoryAttribute::DeviceSharedAndUncached)); + AttributeTestMask, KMemoryAttribute::None, ~AttributeTestMask)); + + // Determine the new attribute. + const auto new_attr = ((old_attr & static_cast<KMemoryAttribute>(~mask)) | + static_cast<KMemoryAttribute>(attr & mask)); - attribute = attribute & ~mask; - attribute = attribute | (mask & value); + // Perform operation. + this->Operate(addr, num_pages, old_perm, OperationType::ChangePermissionsAndRefresh); - block_manager->Update(addr, size / PageSize, state, perm, attribute); + // Update the blocks. + block_manager->Update(addr, num_pages, old_state, old_perm, new_attr); return ResultSuccess; } diff --git a/src/core/hle/kernel/k_page_table.h b/src/core/hle/kernel/k_page_table.h index 07c1d18ac..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: ResultCode ReserveTransferMemory(VAddr addr, std::size_t size, KMemoryPermission perm); ResultCode ResetTransferMemory(VAddr addr, std::size_t size); ResultCode SetMemoryPermission(VAddr addr, std::size_t size, Svc::MemoryPermission perm); - ResultCode SetMemoryAttribute(VAddr addr, std::size_t size, KMemoryAttribute mask, - KMemoryAttribute value); + ResultCode SetMemoryAttribute(VAddr addr, std::size_t size, u32 mask, u32 attr); ResultCode SetMaxHeapSize(std::size_t size); ResultCode SetHeapSize(VAddr* out, std::size_t size); ResultVal<VAddr> AllocateAndMapMemory(std::size_t needed_num_pages, std::size_t align, 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) { static ResultCode SetMemoryPermission(Core::System& system, VAddr address, u64 size, MemoryPermission perm) { + LOG_DEBUG(Kernel_SVC, "called, address=0x{:016X}, size=0x{:X}, perm=0x{:08X", address, size, + perm); + // Validate address / size. R_UNLESS(Common::IsAligned(address, PageSize), ResultInvalidAddress); R_UNLESS(Common::IsAligned(size, PageSize), ResultInvalidSize); @@ -186,46 +189,33 @@ static ResultCode SetMemoryPermission(Core::System& system, VAddr address, u64 s } static ResultCode SetMemoryAttribute(Core::System& system, VAddr address, u64 size, u32 mask, - u32 attribute) { + u32 attr) { LOG_DEBUG(Kernel_SVC, "called, address=0x{:016X}, size=0x{:X}, mask=0x{:08X}, attribute=0x{:08X}", address, - size, mask, attribute); - - if (!Common::Is4KBAligned(address)) { - LOG_ERROR(Kernel_SVC, "Address not page aligned (0x{:016X})", address); - return ResultInvalidAddress; - } + size, mask, attr); - if (size == 0 || !Common::Is4KBAligned(size)) { - LOG_ERROR(Kernel_SVC, "Invalid size (0x{:X}). Size must be non-zero and page aligned.", - size); - return ResultInvalidAddress; - } - - if (!IsValidAddressRange(address, size)) { - LOG_ERROR(Kernel_SVC, "Address range overflowed (Address: 0x{:016X}, Size: 0x{:016X})", - address, size); - return ResultInvalidCurrentMemory; - } + // Validate address / size. + R_UNLESS(Common::IsAligned(address, PageSize), ResultInvalidAddress); + R_UNLESS(Common::IsAligned(size, PageSize), ResultInvalidSize); + R_UNLESS(size > 0, ResultInvalidSize); + R_UNLESS((address < address + size), ResultInvalidCurrentMemory); - const auto attributes{static_cast<MemoryAttribute>(mask | attribute)}; - if (attributes != static_cast<MemoryAttribute>(mask) || - (attributes | MemoryAttribute::Uncached) != MemoryAttribute::Uncached) { - LOG_ERROR(Kernel_SVC, - "Memory attribute doesn't match the given mask (Attribute: 0x{:X}, Mask: {:X}", - attribute, mask); - return ResultInvalidCombination; - } + // Validate the attribute and mask. + constexpr u32 SupportedMask = static_cast<u32>(MemoryAttribute::Uncached); + R_UNLESS((mask | attr) == mask, ResultInvalidCombination); + R_UNLESS((mask | attr | SupportedMask) == SupportedMask, ResultInvalidCombination); + // Validate that the region is in range for the current process. auto& page_table{system.Kernel().CurrentProcess()->PageTable()}; + R_UNLESS(page_table.Contains(address, size), ResultInvalidCurrentMemory); - return page_table.SetMemoryAttribute(address, size, static_cast<KMemoryAttribute>(mask), - static_cast<KMemoryAttribute>(attribute)); + // Set the memory attribute. + return page_table.SetMemoryAttribute(address, size, mask, attr); } static ResultCode SetMemoryAttribute32(Core::System& system, u32 address, u32 size, u32 mask, - u32 attribute) { - return SetMemoryAttribute(system, address, size, mask, attribute); + u32 attr) { + return SetMemoryAttribute(system, address, size, mask, attr); } /// Maps a memory range into a different range. |