summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorbunnei <bunneidev@gmail.com>2022-01-08 12:16:59 +0100
committerbunnei <bunneidev@gmail.com>2022-01-08 21:18:14 +0100
commitaf4696657c5401b3cf352d34e2515d45ead2144d (patch)
tree7a7d0a7849364668cb4083cccc9ecaee9e73b2a6
parentcore: hle: kernel: k_page_table: Update CheckMemoryState. (diff)
downloadyuzu-af4696657c5401b3cf352d34e2515d45ead2144d.tar
yuzu-af4696657c5401b3cf352d34e2515d45ead2144d.tar.gz
yuzu-af4696657c5401b3cf352d34e2515d45ead2144d.tar.bz2
yuzu-af4696657c5401b3cf352d34e2515d45ead2144d.tar.lz
yuzu-af4696657c5401b3cf352d34e2515d45ead2144d.tar.xz
yuzu-af4696657c5401b3cf352d34e2515d45ead2144d.tar.zst
yuzu-af4696657c5401b3cf352d34e2515d45ead2144d.zip
-rw-r--r--src/core/hle/kernel/k_page_table.cpp38
-rw-r--r--src/core/hle/kernel/k_page_table.h3
-rw-r--r--src/core/hle/kernel/svc.cpp50
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.