diff options
Diffstat (limited to 'src/core/hle/kernel/vm_manager.cpp')
-rw-r--r-- | src/core/hle/kernel/vm_manager.cpp | 131 |
1 files changed, 122 insertions, 9 deletions
diff --git a/src/core/hle/kernel/vm_manager.cpp b/src/core/hle/kernel/vm_manager.cpp index 100f8f6bf..10ad94aa6 100644 --- a/src/core/hle/kernel/vm_manager.cpp +++ b/src/core/hle/kernel/vm_manager.cpp @@ -25,19 +25,19 @@ static const char* GetMemoryStateName(MemoryState state) { "CodeMutable", "Heap", "Shared", "Unknown1", "ModuleCodeStatic", "ModuleCodeMutable", - "IpcBuffer0", "Mapped", + "IpcBuffer0", "Stack", "ThreadLocal", "TransferMemoryIsolated", "TransferMemory", "ProcessMemory", - "Unknown2", "IpcBuffer1", + "Inaccessible", "IpcBuffer1", "IpcBuffer3", "KernelStack", }; - return names[static_cast<int>(state)]; + return names[ToSvcMemoryState(state)]; } bool VirtualMemoryArea::CanBeMergedWith(const VirtualMemoryArea& next) const { ASSERT(base + size == next.base); - if (permissions != next.permissions || meminfo_state != next.meminfo_state || + if (permissions != next.permissions || state != next.state || attribute != next.attribute || type != next.type) { return false; } @@ -87,6 +87,10 @@ VMManager::VMAHandle VMManager::FindVMA(VAddr target) const { } } +bool VMManager::IsValidHandle(VMAHandle handle) const { + return handle != vma_map.cend(); +} + ResultVal<VMManager::VMAHandle> VMManager::MapMemoryBlock(VAddr target, std::shared_ptr<std::vector<u8>> block, std::size_t offset, u64 size, @@ -111,7 +115,7 @@ ResultVal<VMManager::VMAHandle> VMManager::MapMemoryBlock(VAddr target, final_vma.type = VMAType::AllocatedMemoryBlock; final_vma.permissions = VMAPermission::ReadWrite; - final_vma.meminfo_state = state; + final_vma.state = state; final_vma.backing_block = std::move(block); final_vma.offset = offset; UpdatePageTableForVMA(final_vma); @@ -136,7 +140,7 @@ ResultVal<VMManager::VMAHandle> VMManager::MapBackingMemory(VAddr target, u8* me final_vma.type = VMAType::BackingMemory; final_vma.permissions = VMAPermission::ReadWrite; - final_vma.meminfo_state = state; + final_vma.state = state; final_vma.backing_memory = memory; UpdatePageTableForVMA(final_vma); @@ -173,7 +177,7 @@ ResultVal<VMManager::VMAHandle> VMManager::MapMMIO(VAddr target, PAddr paddr, u6 final_vma.type = VMAType::MMIO; final_vma.permissions = VMAPermission::ReadWrite; - final_vma.meminfo_state = state; + final_vma.state = state; final_vma.paddr = paddr; final_vma.mmio_handler = std::move(mmio_handler); UpdatePageTableForVMA(final_vma); @@ -185,7 +189,8 @@ VMManager::VMAIter VMManager::Unmap(VMAIter vma_handle) { VirtualMemoryArea& vma = vma_handle->second; vma.type = VMAType::Free; vma.permissions = VMAPermission::None; - vma.meminfo_state = MemoryState::Unmapped; + vma.state = MemoryState::Unmapped; + vma.attribute = MemoryAttribute::None; vma.backing_block = nullptr; vma.offset = 0; @@ -298,6 +303,54 @@ ResultCode VMManager::HeapFree(VAddr target, u64 size) { return RESULT_SUCCESS; } +MemoryInfo VMManager::QueryMemory(VAddr address) const { + const auto vma = FindVMA(address); + MemoryInfo memory_info{}; + + if (IsValidHandle(vma)) { + memory_info.base_address = vma->second.base; + memory_info.attributes = ToSvcMemoryAttribute(vma->second.attribute); + memory_info.permission = static_cast<u32>(vma->second.permissions); + memory_info.size = vma->second.size; + memory_info.state = ToSvcMemoryState(vma->second.state); + } else { + memory_info.base_address = address_space_end; + memory_info.permission = static_cast<u32>(VMAPermission::None); + memory_info.size = 0 - address_space_end; + memory_info.state = static_cast<u32>(MemoryState::Inaccessible); + } + + return memory_info; +} + +ResultCode VMManager::SetMemoryAttribute(VAddr address, u64 size, MemoryAttribute mask, + MemoryAttribute attribute) { + constexpr auto ignore_mask = MemoryAttribute::Uncached | MemoryAttribute::DeviceMapped; + constexpr auto attribute_mask = ~ignore_mask; + + const auto result = CheckRangeState( + address, size, MemoryState::FlagUncached, MemoryState::FlagUncached, VMAPermission::None, + VMAPermission::None, attribute_mask, MemoryAttribute::None, ignore_mask); + + if (result.Failed()) { + return result.Code(); + } + + const auto [prev_state, prev_permissions, prev_attributes] = *result; + const auto new_attribute = (prev_attributes & ~mask) | (mask & attribute); + + const auto carve_result = CarveVMARange(address, size); + if (carve_result.Failed()) { + return carve_result.Code(); + } + + auto vma_iter = *carve_result; + vma_iter->second.attribute = new_attribute; + + MergeAdjacent(vma_iter); + return RESULT_SUCCESS; +} + ResultCode VMManager::MirrorMemory(VAddr dst_addr, VAddr src_addr, u64 size, MemoryState state) { const auto vma = FindVMA(src_addr); @@ -341,7 +394,7 @@ void VMManager::LogLayout() const { (u8)vma.permissions & (u8)VMAPermission::Read ? 'R' : '-', (u8)vma.permissions & (u8)VMAPermission::Write ? 'W' : '-', (u8)vma.permissions & (u8)VMAPermission::Execute ? 'X' : '-', - GetMemoryStateName(vma.meminfo_state)); + GetMemoryStateName(vma.state)); } } @@ -568,6 +621,66 @@ void VMManager::ClearPageTable() { Memory::PageType::Unmapped); } +VMManager::CheckResults VMManager::CheckRangeState(VAddr address, u64 size, MemoryState state_mask, + MemoryState state, VMAPermission permission_mask, + VMAPermission permissions, + MemoryAttribute attribute_mask, + MemoryAttribute attribute, + MemoryAttribute ignore_mask) const { + auto iter = FindVMA(address); + + // If we don't have a valid VMA handle at this point, then it means this is + // being called with an address outside of the address space, which is definitely + // indicative of a bug, as this function only operates on mapped memory regions. + DEBUG_ASSERT(IsValidHandle(iter)); + + const VAddr end_address = address + size - 1; + const MemoryAttribute initial_attributes = iter->second.attribute; + const VMAPermission initial_permissions = iter->second.permissions; + const MemoryState initial_state = iter->second.state; + + while (true) { + // The iterator should be valid throughout the traversal. Hitting the end of + // the mapped VMA regions is unquestionably indicative of a bug. + DEBUG_ASSERT(IsValidHandle(iter)); + + const auto& vma = iter->second; + + if (vma.state != initial_state) { + return ERR_INVALID_ADDRESS_STATE; + } + + if ((vma.state & state_mask) != state) { + return ERR_INVALID_ADDRESS_STATE; + } + + if (vma.permissions != initial_permissions) { + return ERR_INVALID_ADDRESS_STATE; + } + + if ((vma.permissions & permission_mask) != permissions) { + return ERR_INVALID_ADDRESS_STATE; + } + + if ((vma.attribute | ignore_mask) != (initial_attributes | ignore_mask)) { + return ERR_INVALID_ADDRESS_STATE; + } + + if ((vma.attribute & attribute_mask) != attribute) { + return ERR_INVALID_ADDRESS_STATE; + } + + if (end_address <= vma.EndAddress()) { + break; + } + + ++iter; + } + + return MakeResult( + std::make_tuple(initial_state, initial_permissions, initial_attributes & ~ignore_mask)); +} + u64 VMManager::GetTotalMemoryUsage() const { LOG_WARNING(Kernel, "(STUBBED) called"); return 0xF8000000; |