core: hle: kernel: svc: Updates to SetMemoryAttribute and SetMemoryPermission.

This commit is contained in:
bunnei 2022-01-08 03:16:59 -08:00
parent b9a313057e
commit af4696657c
3 changed files with 46 additions and 45 deletions

View File

@ -837,24 +837,36 @@ ResultCode KPageTable::SetMemoryPermission(VAddr addr, std::size_t size,
return ResultSuccess; return ResultSuccess;
} }
ResultCode KPageTable::SetMemoryAttribute(VAddr addr, std::size_t size, KMemoryAttribute mask, ResultCode KPageTable::SetMemoryAttribute(VAddr addr, std::size_t size, u32 mask, u32 attr) {
KMemoryAttribute value) { 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}; std::lock_guard lock{page_table_lock};
KMemoryState state{}; // Verify we can change the memory attribute.
KMemoryPermission perm{}; KMemoryState old_state;
KMemoryAttribute attribute{}; KMemoryPermission old_perm;
KMemoryAttribute old_attr;
CASCADE_CODE(CheckMemoryState( size_t num_allocator_blocks;
&state, &perm, &attribute, nullptr, addr, size, KMemoryState::FlagCanChangeAttribute, 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, KMemoryState::FlagCanChangeAttribute, KMemoryPermission::None, KMemoryPermission::None,
KMemoryAttribute::LockedAndIpcLocked, KMemoryAttribute::None, AttributeTestMask, KMemoryAttribute::None, ~AttributeTestMask));
KMemoryAttribute::DeviceSharedAndUncached));
attribute = attribute & ~mask; // Determine the new attribute.
attribute = attribute | (mask & value); 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; return ResultSuccess;
} }

View File

@ -48,8 +48,7 @@ public:
ResultCode ReserveTransferMemory(VAddr addr, std::size_t size, KMemoryPermission perm); ResultCode ReserveTransferMemory(VAddr addr, std::size_t size, KMemoryPermission perm);
ResultCode ResetTransferMemory(VAddr addr, std::size_t size); ResultCode ResetTransferMemory(VAddr addr, std::size_t size);
ResultCode SetMemoryPermission(VAddr addr, std::size_t size, Svc::MemoryPermission perm); ResultCode SetMemoryPermission(VAddr addr, std::size_t size, Svc::MemoryPermission perm);
ResultCode SetMemoryAttribute(VAddr addr, std::size_t size, KMemoryAttribute mask, ResultCode SetMemoryAttribute(VAddr addr, std::size_t size, u32 mask, u32 attr);
KMemoryAttribute value);
ResultCode SetMaxHeapSize(std::size_t size); ResultCode SetMaxHeapSize(std::size_t size);
ResultCode SetHeapSize(VAddr* out, 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, ResultVal<VAddr> AllocateAndMapMemory(std::size_t needed_num_pages, std::size_t align,

View File

@ -168,6 +168,9 @@ constexpr bool IsValidSetMemoryPermission(MemoryPermission perm) {
static ResultCode SetMemoryPermission(Core::System& system, VAddr address, u64 size, static ResultCode SetMemoryPermission(Core::System& system, VAddr address, u64 size,
MemoryPermission perm) { MemoryPermission perm) {
LOG_DEBUG(Kernel_SVC, "called, address=0x{:016X}, size=0x{:X}, perm=0x{:08X", address, size,
perm);
// Validate address / size. // Validate address / size.
R_UNLESS(Common::IsAligned(address, PageSize), ResultInvalidAddress); R_UNLESS(Common::IsAligned(address, PageSize), ResultInvalidAddress);
R_UNLESS(Common::IsAligned(size, PageSize), ResultInvalidSize); 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, static ResultCode SetMemoryAttribute(Core::System& system, VAddr address, u64 size, u32 mask,
u32 attribute) { u32 attr) {
LOG_DEBUG(Kernel_SVC, LOG_DEBUG(Kernel_SVC,
"called, address=0x{:016X}, size=0x{:X}, mask=0x{:08X}, attribute=0x{:08X}", address, "called, address=0x{:016X}, size=0x{:X}, mask=0x{:08X}, attribute=0x{:08X}", address,
size, mask, attribute); size, mask, attr);
if (!Common::Is4KBAligned(address)) { // Validate address / size.
LOG_ERROR(Kernel_SVC, "Address not page aligned (0x{:016X})", address); R_UNLESS(Common::IsAligned(address, PageSize), ResultInvalidAddress);
return 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)) { // Validate the attribute and mask.
LOG_ERROR(Kernel_SVC, "Invalid size (0x{:X}). Size must be non-zero and page aligned.", constexpr u32 SupportedMask = static_cast<u32>(MemoryAttribute::Uncached);
size); R_UNLESS((mask | attr) == mask, ResultInvalidCombination);
return ResultInvalidAddress; R_UNLESS((mask | attr | SupportedMask) == SupportedMask, ResultInvalidCombination);
}
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 that the region is in range for the current process.
auto& page_table{system.Kernel().CurrentProcess()->PageTable()}; 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), // Set the memory attribute.
static_cast<KMemoryAttribute>(attribute)); return page_table.SetMemoryAttribute(address, size, mask, attr);
} }
static ResultCode SetMemoryAttribute32(Core::System& system, u32 address, u32 size, u32 mask, static ResultCode SetMemoryAttribute32(Core::System& system, u32 address, u32 size, u32 mask,
u32 attribute) { u32 attr) {
return SetMemoryAttribute(system, address, size, mask, attribute); return SetMemoryAttribute(system, address, size, mask, attr);
} }
/// Maps a memory range into a different range. /// Maps a memory range into a different range.