diff --git a/src/core/hle/kernel/k_page_table.cpp b/src/core/hle/kernel/k_page_table.cpp
index e86ded58be..6077985b55 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) {
+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);
+
+    // Lock the table.
     std::lock_guard lock{page_table_lock};
 
-    KMemoryState state{};
-    KMemoryPermission perm{};
-    KMemoryAttribute attribute{};
-
-    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));
 
-    attribute = attribute & ~mask;
-    attribute = attribute | (mask & value);
+    // Determine the new attribute.
+    const auto new_attr = ((old_attr & static_cast<KMemoryAttribute>(~mask)) |
+                           static_cast<KMemoryAttribute>(attr & mask));
 
-    block_manager->Update(addr, size / PageSize, state, perm, attribute);
+    // Perform operation.
+    this->Operate(addr, num_pages, old_perm, OperationType::ChangePermissionsAndRefresh);
+
+    // 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 07c1d18acb..9235b822a5 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 250ef9042d..4362508a3a 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);
+              size, mask, attr);
 
-    if (!Common::Is4KBAligned(address)) {
-        LOG_ERROR(Kernel_SVC, "Address not page aligned (0x{:016X})", address);
-        return ResultInvalidAddress;
-    }
+    // 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);
 
-    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;
-    }
-
-    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.