diff options
Diffstat (limited to '')
27 files changed, 559 insertions, 263 deletions
diff --git a/src/core/debugger/gdbstub.cpp b/src/core/debugger/gdbstub.cpp index 82964f0a1..2076aa8a2 100644 --- a/src/core/debugger/gdbstub.cpp +++ b/src/core/debugger/gdbstub.cpp @@ -822,11 +822,13 @@ void GDBStub::HandleRcmd(const std::vector<u8>& command) { const char i = True(mem_info.attribute & MemoryAttribute::IpcLocked) ? 'I' : '-'; const char d = True(mem_info.attribute & MemoryAttribute::DeviceShared) ? 'D' : '-'; const char u = True(mem_info.attribute & MemoryAttribute::Uncached) ? 'U' : '-'; + const char p = + True(mem_info.attribute & MemoryAttribute::PermissionLocked) ? 'P' : '-'; - reply += - fmt::format(" {:#012x} - {:#012x} {} {} {}{}{}{} [{}, {}]\n", - mem_info.base_address, mem_info.base_address + mem_info.size - 1, - perm, state, l, i, d, u, mem_info.ipc_count, mem_info.device_count); + reply += fmt::format(" {:#012x} - {:#012x} {} {} {}{}{}{}{} [{}, {}]\n", + mem_info.base_address, + mem_info.base_address + mem_info.size - 1, perm, state, l, i, + d, u, p, mem_info.ipc_count, mem_info.device_count); } const uintptr_t next_address = mem_info.base_address + mem_info.size; diff --git a/src/core/hle/kernel/init/init_slab_setup.cpp b/src/core/hle/kernel/init/init_slab_setup.cpp index 1f2db673c..a0e20bbbb 100644 --- a/src/core/hle/kernel/init/init_slab_setup.cpp +++ b/src/core/hle/kernel/init/init_slab_setup.cpp @@ -106,7 +106,7 @@ static_assert(KernelPageBufferAdditionalSize == /// memory. static KPhysicalAddress TranslateSlabAddrToPhysical(KMemoryLayout& memory_layout, KVirtualAddress slab_addr) { - slab_addr -= GetInteger(memory_layout.GetSlabRegionAddress()); + slab_addr -= memory_layout.GetSlabRegion().GetAddress(); return GetInteger(slab_addr) + Core::DramMemoryMap::SlabHeapBase; } @@ -196,7 +196,12 @@ void InitializeSlabHeaps(Core::System& system, KMemoryLayout& memory_layout) { auto& kernel = system.Kernel(); // Get the start of the slab region, since that's where we'll be working. - KVirtualAddress address = memory_layout.GetSlabRegionAddress(); + const KMemoryRegion& slab_region = memory_layout.GetSlabRegion(); + KVirtualAddress address = slab_region.GetAddress(); + + // Clear the slab region. + // TODO: implement access to kernel VAs. + // std::memset(device_ptr, 0, slab_region.GetSize()); // Initialize slab type array to be in sorted order. std::array<KSlabType, KSlabType_Count> slab_types; diff --git a/src/core/hle/kernel/initial_process.h b/src/core/hle/kernel/initial_process.h index 82195f4f7..2c95269fc 100644 --- a/src/core/hle/kernel/initial_process.h +++ b/src/core/hle/kernel/initial_process.h @@ -19,4 +19,8 @@ static inline KPhysicalAddress GetInitialProcessBinaryPhysicalAddress() { MainMemoryAddress); } +static inline size_t GetInitialProcessBinarySize() { + return InitialProcessBinarySizeMax; +} + } // namespace Kernel diff --git a/src/core/hle/kernel/k_memory_block.h b/src/core/hle/kernel/k_memory_block.h index 41a29da24..ef3f61321 100644 --- a/src/core/hle/kernel/k_memory_block.h +++ b/src/core/hle/kernel/k_memory_block.h @@ -36,6 +36,7 @@ enum class KMemoryState : u32 { FlagCanChangeAttribute = (1 << 24), FlagCanCodeMemory = (1 << 25), FlagLinearMapped = (1 << 26), + FlagCanPermissionLock = (1 << 27), FlagsData = FlagCanReprotect | FlagCanUseIpc | FlagCanUseNonDeviceIpc | FlagCanUseNonSecureIpc | FlagMapped | FlagCanAlias | FlagCanTransfer | FlagCanQueryPhysical | @@ -50,12 +51,16 @@ enum class KMemoryState : u32 { FlagLinearMapped, Free = static_cast<u32>(Svc::MemoryState::Free), - Io = static_cast<u32>(Svc::MemoryState::Io) | FlagMapped | FlagCanDeviceMap | - FlagCanAlignedDeviceMap, + + IoMemory = static_cast<u32>(Svc::MemoryState::Io) | FlagMapped | FlagCanDeviceMap | + FlagCanAlignedDeviceMap, + IoRegister = + static_cast<u32>(Svc::MemoryState::Io) | FlagCanDeviceMap | FlagCanAlignedDeviceMap, + Static = static_cast<u32>(Svc::MemoryState::Static) | FlagMapped | FlagCanQueryPhysical, Code = static_cast<u32>(Svc::MemoryState::Code) | FlagsCode | FlagCanMapProcess, CodeData = static_cast<u32>(Svc::MemoryState::CodeData) | FlagsData | FlagCanMapProcess | - FlagCanCodeMemory, + FlagCanCodeMemory | FlagCanPermissionLock, Normal = static_cast<u32>(Svc::MemoryState::Normal) | FlagsData | FlagCanCodeMemory, Shared = static_cast<u32>(Svc::MemoryState::Shared) | FlagMapped | FlagReferenceCounted | FlagLinearMapped, @@ -65,7 +70,8 @@ enum class KMemoryState : u32 { AliasCode = static_cast<u32>(Svc::MemoryState::AliasCode) | FlagsCode | FlagCanMapProcess | FlagCanCodeAlias, AliasCodeData = static_cast<u32>(Svc::MemoryState::AliasCodeData) | FlagsData | - FlagCanMapProcess | FlagCanCodeAlias | FlagCanCodeMemory, + FlagCanMapProcess | FlagCanCodeAlias | FlagCanCodeMemory | + FlagCanPermissionLock, Ipc = static_cast<u32>(Svc::MemoryState::Ipc) | FlagsMisc | FlagCanAlignedDeviceMap | FlagCanUseIpc | FlagCanUseNonSecureIpc | FlagCanUseNonDeviceIpc, @@ -73,7 +79,7 @@ enum class KMemoryState : u32 { Stack = static_cast<u32>(Svc::MemoryState::Stack) | FlagsMisc | FlagCanAlignedDeviceMap | FlagCanUseIpc | FlagCanUseNonSecureIpc | FlagCanUseNonDeviceIpc, - ThreadLocal = static_cast<u32>(Svc::MemoryState::ThreadLocal) | FlagMapped | FlagLinearMapped, + ThreadLocal = static_cast<u32>(Svc::MemoryState::ThreadLocal) | FlagLinearMapped, Transfered = static_cast<u32>(Svc::MemoryState::Transfered) | FlagsMisc | FlagCanAlignedDeviceMap | FlagCanChangeAttribute | FlagCanUseIpc | @@ -94,7 +100,7 @@ enum class KMemoryState : u32 { NonDeviceIpc = static_cast<u32>(Svc::MemoryState::NonDeviceIpc) | FlagsMisc | FlagCanUseNonDeviceIpc, - Kernel = static_cast<u32>(Svc::MemoryState::Kernel) | FlagMapped, + Kernel = static_cast<u32>(Svc::MemoryState::Kernel), GeneratedCode = static_cast<u32>(Svc::MemoryState::GeneratedCode) | FlagMapped | FlagReferenceCounted | FlagCanDebug | FlagLinearMapped, @@ -105,34 +111,36 @@ enum class KMemoryState : u32 { Insecure = static_cast<u32>(Svc::MemoryState::Insecure) | FlagMapped | FlagReferenceCounted | FlagLinearMapped | FlagCanChangeAttribute | FlagCanDeviceMap | - FlagCanAlignedDeviceMap | FlagCanUseNonSecureIpc | FlagCanUseNonDeviceIpc, + FlagCanAlignedDeviceMap | FlagCanQueryPhysical | FlagCanUseNonSecureIpc | + FlagCanUseNonDeviceIpc, }; DECLARE_ENUM_FLAG_OPERATORS(KMemoryState); static_assert(static_cast<u32>(KMemoryState::Free) == 0x00000000); -static_assert(static_cast<u32>(KMemoryState::Io) == 0x00182001); +static_assert(static_cast<u32>(KMemoryState::IoMemory) == 0x00182001); +static_assert(static_cast<u32>(KMemoryState::IoRegister) == 0x00180001); static_assert(static_cast<u32>(KMemoryState::Static) == 0x00042002); static_assert(static_cast<u32>(KMemoryState::Code) == 0x04DC7E03); -static_assert(static_cast<u32>(KMemoryState::CodeData) == 0x07FEBD04); +static_assert(static_cast<u32>(KMemoryState::CodeData) == 0x0FFEBD04); static_assert(static_cast<u32>(KMemoryState::Normal) == 0x077EBD05); static_assert(static_cast<u32>(KMemoryState::Shared) == 0x04402006); static_assert(static_cast<u32>(KMemoryState::AliasCode) == 0x04DD7E08); -static_assert(static_cast<u32>(KMemoryState::AliasCodeData) == 0x07FFBD09); +static_assert(static_cast<u32>(KMemoryState::AliasCodeData) == 0x0FFFBD09); static_assert(static_cast<u32>(KMemoryState::Ipc) == 0x045C3C0A); static_assert(static_cast<u32>(KMemoryState::Stack) == 0x045C3C0B); -static_assert(static_cast<u32>(KMemoryState::ThreadLocal) == 0x0400200C); +static_assert(static_cast<u32>(KMemoryState::ThreadLocal) == 0x0400000C); static_assert(static_cast<u32>(KMemoryState::Transfered) == 0x055C3C0D); static_assert(static_cast<u32>(KMemoryState::SharedTransfered) == 0x045C380E); static_assert(static_cast<u32>(KMemoryState::SharedCode) == 0x0440380F); static_assert(static_cast<u32>(KMemoryState::Inaccessible) == 0x00000010); static_assert(static_cast<u32>(KMemoryState::NonSecureIpc) == 0x045C3811); static_assert(static_cast<u32>(KMemoryState::NonDeviceIpc) == 0x044C2812); -static_assert(static_cast<u32>(KMemoryState::Kernel) == 0x00002013); +static_assert(static_cast<u32>(KMemoryState::Kernel) == 0x00000013); static_assert(static_cast<u32>(KMemoryState::GeneratedCode) == 0x04402214); static_assert(static_cast<u32>(KMemoryState::CodeOut) == 0x04402015); static_assert(static_cast<u32>(KMemoryState::Coverage) == 0x00002016); -static_assert(static_cast<u32>(KMemoryState::Insecure) == 0x05583817); +static_assert(static_cast<u32>(KMemoryState::Insecure) == 0x055C3817); enum class KMemoryPermission : u8 { None = 0, @@ -182,8 +190,9 @@ enum class KMemoryAttribute : u8 { IpcLocked = static_cast<u8>(Svc::MemoryAttribute::IpcLocked), DeviceShared = static_cast<u8>(Svc::MemoryAttribute::DeviceShared), Uncached = static_cast<u8>(Svc::MemoryAttribute::Uncached), + PermissionLocked = static_cast<u8>(Svc::MemoryAttribute::PermissionLocked), - SetMask = Uncached, + SetMask = Uncached | PermissionLocked, }; DECLARE_ENUM_FLAG_OPERATORS(KMemoryAttribute); @@ -261,6 +270,10 @@ struct KMemoryInfo { return m_state; } + constexpr Svc::MemoryState GetSvcState() const { + return static_cast<Svc::MemoryState>(m_state & KMemoryState::Mask); + } + constexpr KMemoryPermission GetPermission() const { return m_permission; } @@ -326,6 +339,10 @@ public: return this->GetEndAddress() - 1; } + constexpr KMemoryState GetState() const { + return m_memory_state; + } + constexpr u16 GetIpcLockCount() const { return m_ipc_lock_count; } @@ -443,6 +460,13 @@ public: } } + constexpr void UpdateAttribute(KMemoryAttribute mask, KMemoryAttribute attr) { + ASSERT(False(mask & KMemoryAttribute::IpcLocked)); + ASSERT(False(mask & KMemoryAttribute::DeviceShared)); + + m_attribute = (m_attribute & ~mask) | attr; + } + constexpr void Split(KMemoryBlock* block, KProcessAddress addr) { ASSERT(this->GetAddress() < addr); ASSERT(this->Contains(addr)); diff --git a/src/core/hle/kernel/k_memory_block_manager.cpp b/src/core/hle/kernel/k_memory_block_manager.cpp index ab75f550e..58a1e7216 100644 --- a/src/core/hle/kernel/k_memory_block_manager.cpp +++ b/src/core/hle/kernel/k_memory_block_manager.cpp @@ -160,8 +160,8 @@ void KMemoryBlockManager::Update(KMemoryBlockManagerUpdateAllocator* allocator, } // Update block state. - it->Update(state, perm, attr, cur_address == address, static_cast<u8>(set_disable_attr), - static_cast<u8>(clear_disable_attr)); + it->Update(state, perm, attr, it->GetAddress() == address, + static_cast<u8>(set_disable_attr), static_cast<u8>(clear_disable_attr)); cur_address += cur_info.GetSize(); remaining_pages -= cur_info.GetNumPages(); } @@ -175,7 +175,9 @@ void KMemoryBlockManager::UpdateIfMatch(KMemoryBlockManagerUpdateAllocator* allo KProcessAddress address, size_t num_pages, KMemoryState test_state, KMemoryPermission test_perm, KMemoryAttribute test_attr, KMemoryState state, - KMemoryPermission perm, KMemoryAttribute attr) { + KMemoryPermission perm, KMemoryAttribute attr, + KMemoryBlockDisableMergeAttribute set_disable_attr, + KMemoryBlockDisableMergeAttribute clear_disable_attr) { // Ensure for auditing that we never end up with an invalid tree. KScopedMemoryBlockManagerAuditor auditor(this); ASSERT(Common::IsAligned(GetInteger(address), PageSize)); @@ -214,7 +216,8 @@ void KMemoryBlockManager::UpdateIfMatch(KMemoryBlockManagerUpdateAllocator* allo } // Update block state. - it->Update(state, perm, attr, false, 0, 0); + it->Update(state, perm, attr, false, static_cast<u8>(set_disable_attr), + static_cast<u8>(clear_disable_attr)); cur_address += cur_info.GetSize(); remaining_pages -= cur_info.GetNumPages(); } else { @@ -284,6 +287,65 @@ void KMemoryBlockManager::UpdateLock(KMemoryBlockManagerUpdateAllocator* allocat this->CoalesceForUpdate(allocator, address, num_pages); } +void KMemoryBlockManager::UpdateAttribute(KMemoryBlockManagerUpdateAllocator* allocator, + KProcessAddress address, size_t num_pages, + KMemoryAttribute mask, KMemoryAttribute attr) { + // Ensure for auditing that we never end up with an invalid tree. + KScopedMemoryBlockManagerAuditor auditor(this); + ASSERT(Common::IsAligned(GetInteger(address), PageSize)); + + KProcessAddress cur_address = address; + size_t remaining_pages = num_pages; + iterator it = this->FindIterator(address); + + while (remaining_pages > 0) { + const size_t remaining_size = remaining_pages * PageSize; + KMemoryInfo cur_info = it->GetMemoryInfo(); + + if ((it->GetAttribute() & mask) != attr) { + // If we need to, create a new block before and insert it. + if (cur_info.GetAddress() != GetInteger(cur_address)) { + KMemoryBlock* new_block = allocator->Allocate(); + + it->Split(new_block, cur_address); + it = m_memory_block_tree.insert(*new_block); + it++; + + cur_info = it->GetMemoryInfo(); + cur_address = cur_info.GetAddress(); + } + + // If we need to, create a new block after and insert it. + if (cur_info.GetSize() > remaining_size) { + KMemoryBlock* new_block = allocator->Allocate(); + + it->Split(new_block, cur_address + remaining_size); + it = m_memory_block_tree.insert(*new_block); + + cur_info = it->GetMemoryInfo(); + } + + // Update block state. + it->UpdateAttribute(mask, attr); + cur_address += cur_info.GetSize(); + remaining_pages -= cur_info.GetNumPages(); + } else { + // If we already have the right attributes, just advance. + if (cur_address + remaining_size < cur_info.GetEndAddress()) { + remaining_pages = 0; + cur_address += remaining_size; + } else { + remaining_pages = + (cur_address + remaining_size - cur_info.GetEndAddress()) / PageSize; + cur_address = cur_info.GetEndAddress(); + } + } + it++; + } + + this->CoalesceForUpdate(allocator, address, num_pages); +} + // Debug. bool KMemoryBlockManager::CheckState() const { // Loop over every block, ensuring that we are sorted and coalesced. diff --git a/src/core/hle/kernel/k_memory_block_manager.h b/src/core/hle/kernel/k_memory_block_manager.h index 96496e990..cb7b6f430 100644 --- a/src/core/hle/kernel/k_memory_block_manager.h +++ b/src/core/hle/kernel/k_memory_block_manager.h @@ -115,7 +115,11 @@ public: void UpdateIfMatch(KMemoryBlockManagerUpdateAllocator* allocator, KProcessAddress address, size_t num_pages, KMemoryState test_state, KMemoryPermission test_perm, KMemoryAttribute test_attr, KMemoryState state, KMemoryPermission perm, - KMemoryAttribute attr); + KMemoryAttribute attr, KMemoryBlockDisableMergeAttribute set_disable_attr, + KMemoryBlockDisableMergeAttribute clear_disable_attr); + + void UpdateAttribute(KMemoryBlockManagerUpdateAllocator* allocator, KProcessAddress address, + size_t num_pages, KMemoryAttribute mask, KMemoryAttribute attr); iterator FindIterator(KProcessAddress address) const { return m_memory_block_tree.find(KMemoryBlock( diff --git a/src/core/hle/kernel/k_memory_layout.h b/src/core/hle/kernel/k_memory_layout.h index 54a71df56..c8122644f 100644 --- a/src/core/hle/kernel/k_memory_layout.h +++ b/src/core/hle/kernel/k_memory_layout.h @@ -137,11 +137,9 @@ public: return GetStackTopAddress(core_id, KMemoryRegionType_KernelMiscExceptionStack); } - KVirtualAddress GetSlabRegionAddress() const { - return Dereference(GetVirtualMemoryRegionTree().FindByType(KMemoryRegionType_KernelSlab)) - .GetAddress(); + const KMemoryRegion& GetSlabRegion() const { + return Dereference(GetVirtualMemoryRegionTree().FindByType(KMemoryRegionType_KernelSlab)); } - const KMemoryRegion& GetDeviceRegion(KMemoryRegionType type) const { return Dereference(GetPhysicalMemoryRegionTree().FindFirstDerived(type)); } diff --git a/src/core/hle/kernel/k_memory_manager.cpp b/src/core/hle/kernel/k_memory_manager.cpp index 74d8169e0..637558e10 100644 --- a/src/core/hle/kernel/k_memory_manager.cpp +++ b/src/core/hle/kernel/k_memory_manager.cpp @@ -119,7 +119,8 @@ void KMemoryManager::Initialize(KVirtualAddress management_region, size_t manage // Free each region to its corresponding heap. size_t reserved_sizes[MaxManagerCount] = {}; const KPhysicalAddress ini_start = GetInitialProcessBinaryPhysicalAddress(); - const KPhysicalAddress ini_end = ini_start + InitialProcessBinarySizeMax; + const size_t ini_size = GetInitialProcessBinarySize(); + const KPhysicalAddress ini_end = ini_start + ini_size; const KPhysicalAddress ini_last = ini_end - 1; for (const auto& it : m_system.Kernel().MemoryLayout().GetPhysicalMemoryRegionTree()) { if (it.IsDerivedFrom(KMemoryRegionType_DramUserPool)) { @@ -137,13 +138,13 @@ void KMemoryManager::Initialize(KVirtualAddress management_region, size_t manage } // Open/reserve the ini memory. - manager.OpenFirst(ini_start, InitialProcessBinarySizeMax / PageSize); - reserved_sizes[it.GetAttributes()] += InitialProcessBinarySizeMax; + manager.OpenFirst(ini_start, ini_size / PageSize); + reserved_sizes[it.GetAttributes()] += ini_size; // Free memory after the ini to the heap. if (ini_last != cur_last) { ASSERT(cur_end != 0); - manager.Free(ini_end, cur_end - ini_end); + manager.Free(ini_end, (cur_end - ini_end) / PageSize); } } else { // Ensure there's no partial overlap with the ini image. diff --git a/src/core/hle/kernel/k_memory_region_type.h b/src/core/hle/kernel/k_memory_region_type.h index e5630c1ac..bcbf450f0 100644 --- a/src/core/hle/kernel/k_memory_region_type.h +++ b/src/core/hle/kernel/k_memory_region_type.h @@ -190,9 +190,15 @@ static_assert(KMemoryRegionType_DramKernelInitPt.GetValue() == constexpr inline auto KMemoryRegionType_DramKernelSecureAppletMemory = KMemoryRegionType_DramKernelBase.DeriveSparse(1, 3, 0).SetAttribute( KMemoryRegionAttr_LinearMapped); +constexpr inline const auto KMemoryRegionType_DramKernelSecureUnknown = + KMemoryRegionType_DramKernelBase.DeriveSparse(1, 3, 1).SetAttribute( + KMemoryRegionAttr_LinearMapped); static_assert(KMemoryRegionType_DramKernelSecureAppletMemory.GetValue() == (0x18E | KMemoryRegionAttr_CarveoutProtected | KMemoryRegionAttr_NoUserMap | KMemoryRegionAttr_LinearMapped)); +static_assert(KMemoryRegionType_DramKernelSecureUnknown.GetValue() == + (0x28E | KMemoryRegionAttr_CarveoutProtected | KMemoryRegionAttr_NoUserMap | + KMemoryRegionAttr_LinearMapped)); constexpr inline auto KMemoryRegionType_DramReservedEarly = KMemoryRegionType_DramReservedBase.DeriveAttribute(KMemoryRegionAttr_NoUserMap); @@ -217,16 +223,18 @@ constexpr inline auto KMemoryRegionType_DramPoolPartition = static_assert(KMemoryRegionType_DramPoolPartition.GetValue() == (0x26 | KMemoryRegionAttr_LinearMapped | KMemoryRegionAttr_NoUserMap)); -constexpr inline auto KMemoryRegionType_DramPoolManagement = - KMemoryRegionType_DramPoolPartition.DeriveTransition(0, 2).DeriveTransition().SetAttribute( +// UNUSED: .Derive(4, 1); +// UNUSED: .Derive(4, 2); +constexpr inline const auto KMemoryRegionType_DramPoolManagement = + KMemoryRegionType_DramPoolPartition.Derive(4, 0).SetAttribute( KMemoryRegionAttr_CarveoutProtected); -constexpr inline auto KMemoryRegionType_DramUserPool = - KMemoryRegionType_DramPoolPartition.DeriveTransition(1, 2).DeriveTransition(); +constexpr inline const auto KMemoryRegionType_DramUserPool = + KMemoryRegionType_DramPoolPartition.Derive(4, 3); static_assert(KMemoryRegionType_DramPoolManagement.GetValue() == - (0x166 | KMemoryRegionAttr_LinearMapped | KMemoryRegionAttr_NoUserMap | + (0xE6 | KMemoryRegionAttr_LinearMapped | KMemoryRegionAttr_NoUserMap | KMemoryRegionAttr_CarveoutProtected)); static_assert(KMemoryRegionType_DramUserPool.GetValue() == - (0x1A6 | KMemoryRegionAttr_LinearMapped | KMemoryRegionAttr_NoUserMap)); + (0x266 | KMemoryRegionAttr_LinearMapped | KMemoryRegionAttr_NoUserMap)); constexpr inline auto KMemoryRegionType_DramApplicationPool = KMemoryRegionType_DramUserPool.Derive(4, 0); @@ -237,60 +245,63 @@ constexpr inline auto KMemoryRegionType_DramSystemNonSecurePool = constexpr inline auto KMemoryRegionType_DramSystemPool = KMemoryRegionType_DramUserPool.Derive(4, 3).SetAttribute(KMemoryRegionAttr_CarveoutProtected); static_assert(KMemoryRegionType_DramApplicationPool.GetValue() == - (0x7A6 | KMemoryRegionAttr_LinearMapped | KMemoryRegionAttr_NoUserMap)); + (0xE66 | KMemoryRegionAttr_LinearMapped | KMemoryRegionAttr_NoUserMap)); static_assert(KMemoryRegionType_DramAppletPool.GetValue() == - (0xBA6 | KMemoryRegionAttr_LinearMapped | KMemoryRegionAttr_NoUserMap)); + (0x1666 | KMemoryRegionAttr_LinearMapped | KMemoryRegionAttr_NoUserMap)); static_assert(KMemoryRegionType_DramSystemNonSecurePool.GetValue() == - (0xDA6 | KMemoryRegionAttr_LinearMapped | KMemoryRegionAttr_NoUserMap)); + (0x1A66 | KMemoryRegionAttr_LinearMapped | KMemoryRegionAttr_NoUserMap)); static_assert(KMemoryRegionType_DramSystemPool.GetValue() == - (0x13A6 | KMemoryRegionAttr_LinearMapped | KMemoryRegionAttr_NoUserMap | + (0x2666 | KMemoryRegionAttr_LinearMapped | KMemoryRegionAttr_NoUserMap | KMemoryRegionAttr_CarveoutProtected)); constexpr inline auto KMemoryRegionType_VirtualDramHeapBase = - KMemoryRegionType_Dram.DeriveSparse(1, 3, 0); + KMemoryRegionType_Dram.DeriveSparse(1, 4, 0); constexpr inline auto KMemoryRegionType_VirtualDramKernelPtHeap = - KMemoryRegionType_Dram.DeriveSparse(1, 3, 1); + KMemoryRegionType_Dram.DeriveSparse(1, 4, 1); constexpr inline auto KMemoryRegionType_VirtualDramKernelTraceBuffer = - KMemoryRegionType_Dram.DeriveSparse(1, 3, 2); + KMemoryRegionType_Dram.DeriveSparse(1, 4, 2); static_assert(KMemoryRegionType_VirtualDramHeapBase.GetValue() == 0x1A); static_assert(KMemoryRegionType_VirtualDramKernelPtHeap.GetValue() == 0x2A); static_assert(KMemoryRegionType_VirtualDramKernelTraceBuffer.GetValue() == 0x4A); -// UNUSED: .DeriveSparse(2, 2, 0); -constexpr inline auto KMemoryRegionType_VirtualDramUnknownDebug = - KMemoryRegionType_Dram.DeriveSparse(2, 2, 1); -static_assert(KMemoryRegionType_VirtualDramUnknownDebug.GetValue() == (0x52)); - -constexpr inline auto KMemoryRegionType_VirtualDramKernelSecureAppletMemory = - KMemoryRegionType_Dram.DeriveSparse(3, 1, 0); -static_assert(KMemoryRegionType_VirtualDramKernelSecureAppletMemory.GetValue() == (0x62)); - -constexpr inline auto KMemoryRegionType_VirtualDramKernelInitPt = - KMemoryRegionType_VirtualDramHeapBase.Derive(3, 0); -constexpr inline auto KMemoryRegionType_VirtualDramPoolManagement = - KMemoryRegionType_VirtualDramHeapBase.Derive(3, 1); -constexpr inline auto KMemoryRegionType_VirtualDramUserPool = - KMemoryRegionType_VirtualDramHeapBase.Derive(3, 2); -static_assert(KMemoryRegionType_VirtualDramKernelInitPt.GetValue() == 0x19A); -static_assert(KMemoryRegionType_VirtualDramPoolManagement.GetValue() == 0x29A); -static_assert(KMemoryRegionType_VirtualDramUserPool.GetValue() == 0x31A); +// UNUSED: .Derive(4, 2); +constexpr inline const auto KMemoryRegionType_VirtualDramUnknownDebug = + KMemoryRegionType_Dram.Advance(2).Derive(4, 0); +constexpr inline const auto KMemoryRegionType_VirtualDramKernelSecureAppletMemory = + KMemoryRegionType_Dram.Advance(2).Derive(4, 1); +constexpr inline const auto KMemoryRegionType_VirtualDramKernelSecureUnknown = + KMemoryRegionType_Dram.Advance(2).Derive(4, 3); +static_assert(KMemoryRegionType_VirtualDramUnknownDebug.GetValue() == (0x32)); +static_assert(KMemoryRegionType_VirtualDramKernelSecureAppletMemory.GetValue() == (0x52)); +static_assert(KMemoryRegionType_VirtualDramKernelSecureUnknown.GetValue() == (0x92)); + +// UNUSED: .Derive(4, 3); +constexpr inline const auto KMemoryRegionType_VirtualDramKernelInitPt = + KMemoryRegionType_VirtualDramHeapBase.Derive(4, 0); +constexpr inline const auto KMemoryRegionType_VirtualDramPoolManagement = + KMemoryRegionType_VirtualDramHeapBase.Derive(4, 1); +constexpr inline const auto KMemoryRegionType_VirtualDramUserPool = + KMemoryRegionType_VirtualDramHeapBase.Derive(4, 2); +static_assert(KMemoryRegionType_VirtualDramKernelInitPt.GetValue() == 0x31A); +static_assert(KMemoryRegionType_VirtualDramPoolManagement.GetValue() == 0x51A); +static_assert(KMemoryRegionType_VirtualDramUserPool.GetValue() == 0x61A); // NOTE: For unknown reason, the pools are derived out-of-order here. // It's worth eventually trying to understand why Nintendo made this choice. // UNUSED: .Derive(6, 0); // UNUSED: .Derive(6, 1); -constexpr inline auto KMemoryRegionType_VirtualDramAppletPool = - KMemoryRegionType_VirtualDramUserPool.Derive(6, 2); -constexpr inline auto KMemoryRegionType_VirtualDramApplicationPool = - KMemoryRegionType_VirtualDramUserPool.Derive(6, 3); -constexpr inline auto KMemoryRegionType_VirtualDramSystemNonSecurePool = - KMemoryRegionType_VirtualDramUserPool.Derive(6, 4); -constexpr inline auto KMemoryRegionType_VirtualDramSystemPool = - KMemoryRegionType_VirtualDramUserPool.Derive(6, 5); -static_assert(KMemoryRegionType_VirtualDramAppletPool.GetValue() == 0x1B1A); -static_assert(KMemoryRegionType_VirtualDramApplicationPool.GetValue() == 0x271A); -static_assert(KMemoryRegionType_VirtualDramSystemNonSecurePool.GetValue() == 0x2B1A); -static_assert(KMemoryRegionType_VirtualDramSystemPool.GetValue() == 0x331A); +constexpr inline const auto KMemoryRegionType_VirtualDramApplicationPool = + KMemoryRegionType_VirtualDramUserPool.Derive(4, 0); +constexpr inline const auto KMemoryRegionType_VirtualDramAppletPool = + KMemoryRegionType_VirtualDramUserPool.Derive(4, 1); +constexpr inline const auto KMemoryRegionType_VirtualDramSystemNonSecurePool = + KMemoryRegionType_VirtualDramUserPool.Derive(4, 2); +constexpr inline const auto KMemoryRegionType_VirtualDramSystemPool = + KMemoryRegionType_VirtualDramUserPool.Derive(4, 3); +static_assert(KMemoryRegionType_VirtualDramApplicationPool.GetValue() == 0x361A); +static_assert(KMemoryRegionType_VirtualDramAppletPool.GetValue() == 0x561A); +static_assert(KMemoryRegionType_VirtualDramSystemNonSecurePool.GetValue() == 0x661A); +static_assert(KMemoryRegionType_VirtualDramSystemPool.GetValue() == 0x961A); constexpr inline auto KMemoryRegionType_ArchDeviceBase = KMemoryRegionType_Kernel.DeriveTransition(0, 1).SetSparseOnly(); @@ -354,12 +365,14 @@ constexpr inline auto KMemoryRegionType_KernelTemp = static_assert(KMemoryRegionType_KernelTemp.GetValue() == 0x31); constexpr KMemoryRegionType GetTypeForVirtualLinearMapping(u32 type_id) { - if (KMemoryRegionType_KernelTraceBuffer.IsAncestorOf(type_id)) { - return KMemoryRegionType_VirtualDramKernelTraceBuffer; - } else if (KMemoryRegionType_DramKernelPtHeap.IsAncestorOf(type_id)) { + if (KMemoryRegionType_DramKernelPtHeap.IsAncestorOf(type_id)) { return KMemoryRegionType_VirtualDramKernelPtHeap; } else if (KMemoryRegionType_DramKernelSecureAppletMemory.IsAncestorOf(type_id)) { return KMemoryRegionType_VirtualDramKernelSecureAppletMemory; + } else if (KMemoryRegionType_DramKernelSecureUnknown.IsAncestorOf(type_id)) { + return KMemoryRegionType_VirtualDramKernelSecureUnknown; + } else if (KMemoryRegionType_KernelTraceBuffer.IsAncestorOf(type_id)) { + return KMemoryRegionType_VirtualDramKernelTraceBuffer; } else if ((type_id | KMemoryRegionAttr_ShouldKernelMap) == type_id) { return KMemoryRegionType_VirtualDramUnknownDebug; } else { diff --git a/src/core/hle/kernel/k_page_group.h b/src/core/hle/kernel/k_page_group.h index b32909f05..de9d63a8d 100644 --- a/src/core/hle/kernel/k_page_group.h +++ b/src/core/hle/kernel/k_page_group.h @@ -183,12 +183,17 @@ private: class KScopedPageGroup { public: - explicit KScopedPageGroup(const KPageGroup* gp) : m_pg(gp) { + explicit KScopedPageGroup(const KPageGroup* gp, bool not_first = true) : m_pg(gp) { if (m_pg) { - m_pg->Open(); + if (not_first) { + m_pg->Open(); + } else { + m_pg->OpenFirst(); + } } } - explicit KScopedPageGroup(const KPageGroup& gp) : KScopedPageGroup(std::addressof(gp)) {} + explicit KScopedPageGroup(const KPageGroup& gp, bool not_first = true) + : KScopedPageGroup(std::addressof(gp), not_first) {} ~KScopedPageGroup() { if (m_pg) { m_pg->Close(); diff --git a/src/core/hle/kernel/k_page_table.cpp b/src/core/hle/kernel/k_page_table.cpp index 0b0cef984..217ccbae3 100644 --- a/src/core/hle/kernel/k_page_table.cpp +++ b/src/core/hle/kernel/k_page_table.cpp @@ -505,7 +505,7 @@ Result KPageTable::UnmapCodeMemory(KProcessAddress dst_address, KProcessAddress R_TRY(this->CheckMemoryStateContiguous( std::addressof(num_dst_allocator_blocks), dst_address, size, KMemoryState::FlagCanCodeAlias, KMemoryState::FlagCanCodeAlias, KMemoryPermission::None, KMemoryPermission::None, - KMemoryAttribute::All, KMemoryAttribute::None)); + KMemoryAttribute::All & ~KMemoryAttribute::PermissionLocked, KMemoryAttribute::None)); // Determine whether any pages being unmapped are code. bool any_code_pages = false; @@ -1724,29 +1724,43 @@ Result KPageTable::MapPhysicalMemory(KProcessAddress address, size_t size) { PageSize; // While we have pages to map, map them. - while (map_pages > 0) { - // Check if we're at the end of the physical block. - if (pg_pages == 0) { - // Ensure there are more pages to map. - ASSERT(pg_it != pg.end()); - - // Advance our physical block. - ++pg_it; - pg_phys_addr = pg_it->GetAddress(); - pg_pages = pg_it->GetNumPages(); + { + // Create a page group for the current mapping range. + KPageGroup cur_pg(m_kernel, m_block_info_manager); + { + ON_RESULT_FAILURE_2 { + cur_pg.OpenFirst(); + cur_pg.Close(); + }; + + size_t remain_pages = map_pages; + while (remain_pages > 0) { + // Check if we're at the end of the physical block. + if (pg_pages == 0) { + // Ensure there are more pages to map. + ASSERT(pg_it != pg.end()); + + // Advance our physical block. + ++pg_it; + pg_phys_addr = pg_it->GetAddress(); + pg_pages = pg_it->GetNumPages(); + } + + // Add whatever we can to the current block. + const size_t cur_pages = std::min(pg_pages, remain_pages); + R_TRY(cur_pg.AddBlock(pg_phys_addr + + ((pg_pages - cur_pages) * PageSize), + cur_pages)); + + // Advance. + remain_pages -= cur_pages; + pg_pages -= cur_pages; + } } - // Map whatever we can. - const size_t cur_pages = std::min(pg_pages, map_pages); - R_TRY(Operate(cur_address, cur_pages, KMemoryPermission::UserReadWrite, - OperationType::MapFirst, pg_phys_addr)); - - // Advance. - cur_address += cur_pages * PageSize; - map_pages -= cur_pages; - - pg_phys_addr += cur_pages * PageSize; - pg_pages -= cur_pages; + // Map the pages. + R_TRY(this->Operate(cur_address, map_pages, cur_pg, + OperationType::MapFirstGroup)); } } @@ -1770,7 +1784,11 @@ Result KPageTable::MapPhysicalMemory(KProcessAddress address, size_t size) { m_memory_block_manager.UpdateIfMatch( std::addressof(allocator), address, size / PageSize, KMemoryState::Free, KMemoryPermission::None, KMemoryAttribute::None, KMemoryState::Normal, - KMemoryPermission::UserReadWrite, KMemoryAttribute::None); + KMemoryPermission::UserReadWrite, KMemoryAttribute::None, + address == this->GetAliasRegionStart() + ? KMemoryBlockDisableMergeAttribute::Normal + : KMemoryBlockDisableMergeAttribute::None, + KMemoryBlockDisableMergeAttribute::None); R_SUCCEED(); } @@ -1868,6 +1886,13 @@ Result KPageTable::UnmapPhysicalMemory(KProcessAddress address, size_t size) { // Iterate over the memory, unmapping as we go. auto it = m_memory_block_manager.FindIterator(cur_address); + + const auto clear_merge_attr = + (it->GetState() == KMemoryState::Normal && + it->GetAddress() == this->GetAliasRegionStart() && it->GetAddress() == address) + ? KMemoryBlockDisableMergeAttribute::Normal + : KMemoryBlockDisableMergeAttribute::None; + while (true) { // Check that the iterator is valid. ASSERT(it != m_memory_block_manager.end()); @@ -1905,7 +1930,7 @@ Result KPageTable::UnmapPhysicalMemory(KProcessAddress address, size_t size) { m_memory_block_manager.Update(std::addressof(allocator), address, size / PageSize, KMemoryState::Free, KMemoryPermission::None, KMemoryAttribute::None, KMemoryBlockDisableMergeAttribute::None, - KMemoryBlockDisableMergeAttribute::None); + clear_merge_attr); // We succeeded. R_SUCCEED(); @@ -2379,8 +2404,7 @@ Result KPageTable::MapPageGroup(KProcessAddress* out_addr, const KPageGroup& pg, KScopedPageTableUpdater updater(this); // Perform mapping operation. - const KPageProperties properties = {perm, state == KMemoryState::Io, false, - DisableMergeAttribute::DisableHead}; + const KPageProperties properties = {perm, false, false, DisableMergeAttribute::DisableHead}; R_TRY(this->MapPageGroupImpl(updater.GetPageList(), addr, pg, properties, false)); // Update the blocks. @@ -2422,8 +2446,7 @@ Result KPageTable::MapPageGroup(KProcessAddress addr, const KPageGroup& pg, KMem KScopedPageTableUpdater updater(this); // Perform mapping operation. - const KPageProperties properties = {perm, state == KMemoryState::Io, false, - DisableMergeAttribute::DisableHead}; + const KPageProperties properties = {perm, false, false, DisableMergeAttribute::DisableHead}; R_TRY(this->MapPageGroupImpl(updater.GetPageList(), addr, pg, properties, false)); // Update the blocks. @@ -2652,11 +2675,18 @@ Result KPageTable::SetMemoryAttribute(KProcessAddress addr, size_t size, u32 mas 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, - AttributeTestMask, KMemoryAttribute::None, ~AttributeTestMask)); + const KMemoryState state_test_mask = + static_cast<KMemoryState>(((mask & static_cast<u32>(KMemoryAttribute::Uncached)) + ? static_cast<u32>(KMemoryState::FlagCanChangeAttribute) + : 0) | + ((mask & static_cast<u32>(KMemoryAttribute::PermissionLocked)) + ? static_cast<u32>(KMemoryState::FlagCanPermissionLock) + : 0)); + R_TRY(this->CheckMemoryState(std::addressof(old_state), std::addressof(old_perm), + std::addressof(old_attr), std::addressof(num_allocator_blocks), + addr, size, state_test_mask, state_test_mask, + KMemoryPermission::None, KMemoryPermission::None, + AttributeTestMask, KMemoryAttribute::None, ~AttributeTestMask)); // Create an update allocator. Result allocator_result{ResultSuccess}; @@ -2664,18 +2694,17 @@ Result KPageTable::SetMemoryAttribute(KProcessAddress addr, size_t size, u32 mas m_memory_block_slab_manager, num_allocator_blocks); R_TRY(allocator_result); - // Determine the new attribute. - const KMemoryAttribute new_attr = - static_cast<KMemoryAttribute>(((old_attr & static_cast<KMemoryAttribute>(~mask)) | - static_cast<KMemoryAttribute>(attr & mask))); - - // Perform operation. - this->Operate(addr, num_pages, old_perm, OperationType::ChangePermissionsAndRefresh); + // If we need to, perform a change attribute operation. + if (True(KMemoryAttribute::Uncached & static_cast<KMemoryAttribute>(mask))) { + // Perform operation. + R_TRY(this->Operate(addr, num_pages, old_perm, + OperationType::ChangePermissionsAndRefreshAndFlush, 0)); + } // Update the blocks. - m_memory_block_manager.Update(std::addressof(allocator), addr, num_pages, old_state, old_perm, - new_attr, KMemoryBlockDisableMergeAttribute::None, - KMemoryBlockDisableMergeAttribute::None); + m_memory_block_manager.UpdateAttribute(std::addressof(allocator), addr, num_pages, + static_cast<KMemoryAttribute>(mask), + static_cast<KMemoryAttribute>(attr)); R_SUCCEED(); } @@ -2863,7 +2892,8 @@ Result KPageTable::LockForMapDeviceAddressSpace(bool* out_is_io, KProcessAddress &KMemoryBlock::ShareToDevice, KMemoryPermission::None); // Set whether the locked memory was io. - *out_is_io = old_state == KMemoryState::Io; + *out_is_io = + static_cast<Svc::MemoryState>(old_state & KMemoryState::Mask) == Svc::MemoryState::Io; R_SUCCEED(); } @@ -3021,9 +3051,10 @@ Result KPageTable::Operate(KProcessAddress addr, size_t num_pages, const KPageGr ASSERT(num_pages == page_group.GetNumPages()); switch (operation) { - case OperationType::MapGroup: { + case OperationType::MapGroup: + case OperationType::MapFirstGroup: { // We want to maintain a new reference to every page in the group. - KScopedPageGroup spg(page_group); + KScopedPageGroup spg(page_group, operation != OperationType::MapFirstGroup); for (const auto& node : page_group) { const size_t size{node.GetNumPages() * PageSize}; @@ -3065,7 +3096,6 @@ Result KPageTable::Operate(KProcessAddress addr, size_t num_pages, KMemoryPermis m_memory->UnmapRegion(*m_page_table_impl, addr, num_pages * PageSize); break; } - case OperationType::MapFirst: case OperationType::Map: { ASSERT(map_addr); ASSERT(Common::IsAligned(GetInteger(map_addr), PageSize)); @@ -3073,11 +3103,7 @@ Result KPageTable::Operate(KProcessAddress addr, size_t num_pages, KMemoryPermis // Open references to pages, if we should. if (IsHeapPhysicalAddress(m_kernel.MemoryLayout(), map_addr)) { - if (operation == OperationType::MapFirst) { - m_kernel.MemoryManager().OpenFirst(map_addr, num_pages); - } else { - m_kernel.MemoryManager().Open(map_addr, num_pages); - } + m_kernel.MemoryManager().Open(map_addr, num_pages); } break; } @@ -3087,6 +3113,7 @@ Result KPageTable::Operate(KProcessAddress addr, size_t num_pages, KMemoryPermis } case OperationType::ChangePermissions: case OperationType::ChangePermissionsAndRefresh: + case OperationType::ChangePermissionsAndRefreshAndFlush: break; default: ASSERT(false); @@ -3106,79 +3133,79 @@ void KPageTable::FinalizeUpdate(PageLinkedList* page_list) { } } -KProcessAddress KPageTable::GetRegionAddress(KMemoryState state) const { +KProcessAddress KPageTable::GetRegionAddress(Svc::MemoryState state) const { switch (state) { - case KMemoryState::Free: - case KMemoryState::Kernel: + case Svc::MemoryState::Free: + case Svc::MemoryState::Kernel: return m_address_space_start; - case KMemoryState::Normal: + case Svc::MemoryState::Normal: return m_heap_region_start; - case KMemoryState::Ipc: - case KMemoryState::NonSecureIpc: - case KMemoryState::NonDeviceIpc: + case Svc::MemoryState::Ipc: + case Svc::MemoryState::NonSecureIpc: + case Svc::MemoryState::NonDeviceIpc: return m_alias_region_start; - case KMemoryState::Stack: + case Svc::MemoryState::Stack: return m_stack_region_start; - case KMemoryState::Static: - case KMemoryState::ThreadLocal: + case Svc::MemoryState::Static: + case Svc::MemoryState::ThreadLocal: return m_kernel_map_region_start; - case KMemoryState::Io: - case KMemoryState::Shared: - case KMemoryState::AliasCode: - case KMemoryState::AliasCodeData: - case KMemoryState::Transfered: - case KMemoryState::SharedTransfered: - case KMemoryState::SharedCode: - case KMemoryState::GeneratedCode: - case KMemoryState::CodeOut: - case KMemoryState::Coverage: - case KMemoryState::Insecure: + case Svc::MemoryState::Io: + case Svc::MemoryState::Shared: + case Svc::MemoryState::AliasCode: + case Svc::MemoryState::AliasCodeData: + case Svc::MemoryState::Transfered: + case Svc::MemoryState::SharedTransfered: + case Svc::MemoryState::SharedCode: + case Svc::MemoryState::GeneratedCode: + case Svc::MemoryState::CodeOut: + case Svc::MemoryState::Coverage: + case Svc::MemoryState::Insecure: return m_alias_code_region_start; - case KMemoryState::Code: - case KMemoryState::CodeData: + case Svc::MemoryState::Code: + case Svc::MemoryState::CodeData: return m_code_region_start; default: UNREACHABLE(); } } -size_t KPageTable::GetRegionSize(KMemoryState state) const { +size_t KPageTable::GetRegionSize(Svc::MemoryState state) const { switch (state) { - case KMemoryState::Free: - case KMemoryState::Kernel: + case Svc::MemoryState::Free: + case Svc::MemoryState::Kernel: return m_address_space_end - m_address_space_start; - case KMemoryState::Normal: + case Svc::MemoryState::Normal: return m_heap_region_end - m_heap_region_start; - case KMemoryState::Ipc: - case KMemoryState::NonSecureIpc: - case KMemoryState::NonDeviceIpc: + case Svc::MemoryState::Ipc: + case Svc::MemoryState::NonSecureIpc: + case Svc::MemoryState::NonDeviceIpc: return m_alias_region_end - m_alias_region_start; - case KMemoryState::Stack: + case Svc::MemoryState::Stack: return m_stack_region_end - m_stack_region_start; - case KMemoryState::Static: - case KMemoryState::ThreadLocal: + case Svc::MemoryState::Static: + case Svc::MemoryState::ThreadLocal: return m_kernel_map_region_end - m_kernel_map_region_start; - case KMemoryState::Io: - case KMemoryState::Shared: - case KMemoryState::AliasCode: - case KMemoryState::AliasCodeData: - case KMemoryState::Transfered: - case KMemoryState::SharedTransfered: - case KMemoryState::SharedCode: - case KMemoryState::GeneratedCode: - case KMemoryState::CodeOut: - case KMemoryState::Coverage: - case KMemoryState::Insecure: + case Svc::MemoryState::Io: + case Svc::MemoryState::Shared: + case Svc::MemoryState::AliasCode: + case Svc::MemoryState::AliasCodeData: + case Svc::MemoryState::Transfered: + case Svc::MemoryState::SharedTransfered: + case Svc::MemoryState::SharedCode: + case Svc::MemoryState::GeneratedCode: + case Svc::MemoryState::CodeOut: + case Svc::MemoryState::Coverage: + case Svc::MemoryState::Insecure: return m_alias_code_region_end - m_alias_code_region_start; - case KMemoryState::Code: - case KMemoryState::CodeData: + case Svc::MemoryState::Code: + case Svc::MemoryState::CodeData: return m_code_region_end - m_code_region_start; default: UNREACHABLE(); } } -bool KPageTable::CanContain(KProcessAddress addr, size_t size, KMemoryState state) const { +bool KPageTable::CanContain(KProcessAddress addr, size_t size, Svc::MemoryState state) const { const KProcessAddress end = addr + size; const KProcessAddress last = end - 1; @@ -3192,32 +3219,32 @@ bool KPageTable::CanContain(KProcessAddress addr, size_t size, KMemoryState stat const bool is_in_alias = !(end <= m_alias_region_start || m_alias_region_end <= addr || m_alias_region_start == m_alias_region_end); switch (state) { - case KMemoryState::Free: - case KMemoryState::Kernel: + case Svc::MemoryState::Free: + case Svc::MemoryState::Kernel: return is_in_region; - case KMemoryState::Io: - case KMemoryState::Static: - case KMemoryState::Code: - case KMemoryState::CodeData: - case KMemoryState::Shared: - case KMemoryState::AliasCode: - case KMemoryState::AliasCodeData: - case KMemoryState::Stack: - case KMemoryState::ThreadLocal: - case KMemoryState::Transfered: - case KMemoryState::SharedTransfered: - case KMemoryState::SharedCode: - case KMemoryState::GeneratedCode: - case KMemoryState::CodeOut: - case KMemoryState::Coverage: - case KMemoryState::Insecure: + case Svc::MemoryState::Io: + case Svc::MemoryState::Static: + case Svc::MemoryState::Code: + case Svc::MemoryState::CodeData: + case Svc::MemoryState::Shared: + case Svc::MemoryState::AliasCode: + case Svc::MemoryState::AliasCodeData: + case Svc::MemoryState::Stack: + case Svc::MemoryState::ThreadLocal: + case Svc::MemoryState::Transfered: + case Svc::MemoryState::SharedTransfered: + case Svc::MemoryState::SharedCode: + case Svc::MemoryState::GeneratedCode: + case Svc::MemoryState::CodeOut: + case Svc::MemoryState::Coverage: + case Svc::MemoryState::Insecure: return is_in_region && !is_in_heap && !is_in_alias; - case KMemoryState::Normal: + case Svc::MemoryState::Normal: ASSERT(is_in_heap); return is_in_region && !is_in_alias; - case KMemoryState::Ipc: - case KMemoryState::NonSecureIpc: - case KMemoryState::NonDeviceIpc: + case Svc::MemoryState::Ipc: + case Svc::MemoryState::NonSecureIpc: + case Svc::MemoryState::NonDeviceIpc: ASSERT(is_in_alias); return is_in_region && !is_in_heap; default: @@ -3281,21 +3308,16 @@ Result KPageTable::CheckMemoryStateContiguous(size_t* out_blocks_needed, KProces Result KPageTable::CheckMemoryState(KMemoryState* out_state, KMemoryPermission* out_perm, KMemoryAttribute* out_attr, size_t* out_blocks_needed, - KProcessAddress addr, size_t size, KMemoryState state_mask, + KMemoryBlockManager::const_iterator it, + KProcessAddress last_addr, KMemoryState state_mask, KMemoryState state, KMemoryPermission perm_mask, KMemoryPermission perm, KMemoryAttribute attr_mask, KMemoryAttribute attr, KMemoryAttribute ignore_attr) const { ASSERT(this->IsLockedByCurrentThread()); // Get information about the first block. - const KProcessAddress last_addr = addr + size - 1; - KMemoryBlockManager::const_iterator it = m_memory_block_manager.FindIterator(addr); KMemoryInfo info = it->GetMemoryInfo(); - // If the start address isn't aligned, we need a block. - const size_t blocks_for_start_align = - (Common::AlignDown(GetInteger(addr), PageSize) != info.GetAddress()) ? 1 : 0; - // Validate all blocks in the range have correct state. const KMemoryState first_state = info.m_state; const KMemoryPermission first_perm = info.m_permission; @@ -3321,10 +3343,6 @@ Result KPageTable::CheckMemoryState(KMemoryState* out_state, KMemoryPermission* info = it->GetMemoryInfo(); } - // If the end address isn't aligned, we need a block. - const size_t blocks_for_end_align = - (Common::AlignUp(GetInteger(addr) + size, PageSize) != info.GetEndAddress()) ? 1 : 0; - // Write output state. if (out_state != nullptr) { *out_state = first_state; @@ -3335,9 +3353,39 @@ Result KPageTable::CheckMemoryState(KMemoryState* out_state, KMemoryPermission* if (out_attr != nullptr) { *out_attr = static_cast<KMemoryAttribute>(first_attr & ~ignore_attr); } + + // If the end address isn't aligned, we need a block. if (out_blocks_needed != nullptr) { - *out_blocks_needed = blocks_for_start_align + blocks_for_end_align; + const size_t blocks_for_end_align = + (Common::AlignDown(GetInteger(last_addr), PageSize) + PageSize != info.GetEndAddress()) + ? 1 + : 0; + *out_blocks_needed = blocks_for_end_align; + } + + R_SUCCEED(); +} + +Result KPageTable::CheckMemoryState(KMemoryState* out_state, KMemoryPermission* out_perm, + KMemoryAttribute* out_attr, size_t* out_blocks_needed, + KProcessAddress addr, size_t size, KMemoryState state_mask, + KMemoryState state, KMemoryPermission perm_mask, + KMemoryPermission perm, KMemoryAttribute attr_mask, + KMemoryAttribute attr, KMemoryAttribute ignore_attr) const { + ASSERT(this->IsLockedByCurrentThread()); + + // Check memory state. + const KProcessAddress last_addr = addr + size - 1; + KMemoryBlockManager::const_iterator it = m_memory_block_manager.FindIterator(addr); + R_TRY(this->CheckMemoryState(out_state, out_perm, out_attr, out_blocks_needed, it, last_addr, + state_mask, state, perm_mask, perm, attr_mask, attr, ignore_attr)); + + // If the start address isn't aligned, we need a block. + if (out_blocks_needed != nullptr && + Common::AlignDown(GetInteger(addr), PageSize) != it->GetAddress()) { + ++(*out_blocks_needed); } + R_SUCCEED(); } diff --git a/src/core/hle/kernel/k_page_table.h b/src/core/hle/kernel/k_page_table.h index 7da675f27..3d64b6fb0 100644 --- a/src/core/hle/kernel/k_page_table.h +++ b/src/core/hle/kernel/k_page_table.h @@ -126,8 +126,6 @@ public: return m_block_info_manager; } - bool CanContain(KProcessAddress addr, size_t size, KMemoryState state) const; - Result MapPages(KProcessAddress* out_addr, size_t num_pages, size_t alignment, KPhysicalAddress phys_addr, KProcessAddress region_start, size_t region_num_pages, KMemoryState state, KMemoryPermission perm) { @@ -162,6 +160,21 @@ public: void RemapPageGroup(PageLinkedList* page_list, KProcessAddress address, size_t size, const KPageGroup& pg); + KProcessAddress GetRegionAddress(Svc::MemoryState state) const; + size_t GetRegionSize(Svc::MemoryState state) const; + bool CanContain(KProcessAddress addr, size_t size, Svc::MemoryState state) const; + + KProcessAddress GetRegionAddress(KMemoryState state) const { + return this->GetRegionAddress(static_cast<Svc::MemoryState>(state & KMemoryState::Mask)); + } + size_t GetRegionSize(KMemoryState state) const { + return this->GetRegionSize(static_cast<Svc::MemoryState>(state & KMemoryState::Mask)); + } + bool CanContain(KProcessAddress addr, size_t size, KMemoryState state) const { + return this->CanContain(addr, size, + static_cast<Svc::MemoryState>(state & KMemoryState::Mask)); + } + protected: struct PageLinkedList { private: @@ -204,12 +217,13 @@ protected: private: enum class OperationType : u32 { Map = 0, - MapFirst = 1, - MapGroup = 2, + MapGroup = 1, + MapFirstGroup = 2, Unmap = 3, ChangePermissions = 4, ChangePermissionsAndRefresh = 5, - Separate = 6, + ChangePermissionsAndRefreshAndFlush = 6, + Separate = 7, }; static constexpr KMemoryAttribute DefaultMemoryIgnoreAttr = @@ -228,8 +242,6 @@ private: Result Operate(KProcessAddress addr, size_t num_pages, KMemoryPermission perm, OperationType operation, KPhysicalAddress map_addr = 0); void FinalizeUpdate(PageLinkedList* page_list); - KProcessAddress GetRegionAddress(KMemoryState state) const; - size_t GetRegionSize(KMemoryState state) const; KProcessAddress FindFreeArea(KProcessAddress region_start, size_t region_num_pages, size_t num_pages, size_t alignment, size_t offset, @@ -252,6 +264,13 @@ private: KMemoryAttribute attr_mask, KMemoryAttribute attr) const; Result CheckMemoryState(KMemoryState* out_state, KMemoryPermission* out_perm, KMemoryAttribute* out_attr, size_t* out_blocks_needed, + KMemoryBlockManager::const_iterator it, KProcessAddress last_addr, + KMemoryState state_mask, KMemoryState state, + KMemoryPermission perm_mask, KMemoryPermission perm, + KMemoryAttribute attr_mask, KMemoryAttribute attr, + KMemoryAttribute ignore_attr = DefaultMemoryIgnoreAttr) const; + Result CheckMemoryState(KMemoryState* out_state, KMemoryPermission* out_perm, + KMemoryAttribute* out_attr, size_t* out_blocks_needed, KProcessAddress addr, size_t size, KMemoryState state_mask, KMemoryState state, KMemoryPermission perm_mask, KMemoryPermission perm, KMemoryAttribute attr_mask, KMemoryAttribute attr, diff --git a/src/core/hle/kernel/k_process.cpp b/src/core/hle/kernel/k_process.cpp index 4a099286b..7fa34d693 100644 --- a/src/core/hle/kernel/k_process.cpp +++ b/src/core/hle/kernel/k_process.cpp @@ -149,7 +149,7 @@ u64 KProcess::GetTotalPhysicalMemoryUsed() { } u64 KProcess::GetTotalPhysicalMemoryUsedWithoutSystemResource() { - return this->GetTotalPhysicalMemoryUsed() - this->GetSystemResourceUsage(); + return this->GetTotalPhysicalMemoryUsed() - this->GetSystemResourceSize(); } bool KProcess::ReleaseUserException(KThread* thread) { diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp index cb025c3d6..24433d32b 100644 --- a/src/core/hle/kernel/kernel.cpp +++ b/src/core/hle/kernel/kernel.cpp @@ -623,14 +623,33 @@ struct KernelCore::Impl { ASSERT(memory_layout->GetPhysicalMemoryRegionTree().Insert( GetInteger(slab_start_phys_addr), slab_region_size, KMemoryRegionType_DramKernelSlab)); + // Insert a physical region for the secure applet memory. + const auto secure_applet_end_phys_addr = + slab_end_phys_addr + KSystemControl::SecureAppletMemorySize; + if constexpr (KSystemControl::SecureAppletMemorySize > 0) { + ASSERT(memory_layout->GetPhysicalMemoryRegionTree().Insert( + GetInteger(slab_end_phys_addr), KSystemControl::SecureAppletMemorySize, + KMemoryRegionType_DramKernelSecureAppletMemory)); + } + + // Insert a physical region for the unknown debug2 region. + constexpr size_t SecureUnknownRegionSize = 0; + const size_t secure_unknown_size = SecureUnknownRegionSize; + const auto secure_unknown_end_phys_addr = secure_applet_end_phys_addr + secure_unknown_size; + if constexpr (SecureUnknownRegionSize > 0) { + ASSERT(memory_layout->GetPhysicalMemoryRegionTree().Insert( + GetInteger(secure_applet_end_phys_addr), secure_unknown_size, + KMemoryRegionType_DramKernelSecureUnknown)); + } + // Determine size available for kernel page table heaps, requiring > 8 MB. const KPhysicalAddress resource_end_phys_addr = slab_start_phys_addr + resource_region_size; - const size_t page_table_heap_size = resource_end_phys_addr - slab_end_phys_addr; + const size_t page_table_heap_size = resource_end_phys_addr - secure_unknown_end_phys_addr; ASSERT(page_table_heap_size / 4_MiB > 2); // Insert a physical region for the kernel page table heap region ASSERT(memory_layout->GetPhysicalMemoryRegionTree().Insert( - GetInteger(slab_end_phys_addr), page_table_heap_size, + GetInteger(secure_unknown_end_phys_addr), page_table_heap_size, KMemoryRegionType_DramKernelPtHeap)); // All DRAM regions that we haven't tagged by this point will be mapped under the linear diff --git a/src/core/hle/kernel/svc/svc_memory.cpp b/src/core/hle/kernel/svc/svc_memory.cpp index 2cab74127..97f1210de 100644 --- a/src/core/hle/kernel/svc/svc_memory.cpp +++ b/src/core/hle/kernel/svc/svc_memory.cpp @@ -76,7 +76,7 @@ Result MapUnmapMemorySanityChecks(const KPageTable& manager, u64 dst_addr, u64 s } // namespace Result SetMemoryPermission(Core::System& system, u64 address, u64 size, MemoryPermission perm) { - LOG_DEBUG(Kernel_SVC, "called, address=0x{:016X}, size=0x{:X}, perm=0x{:08X", address, size, + LOG_DEBUG(Kernel_SVC, "called, address=0x{:016X}, size=0x{:X}, perm=0x{:08X}", address, size, perm); // Validate address / size. @@ -108,10 +108,16 @@ Result SetMemoryAttribute(Core::System& system, u64 address, u64 size, u32 mask, R_UNLESS((address < address + size), ResultInvalidCurrentMemory); // Validate the attribute and mask. - constexpr u32 SupportedMask = static_cast<u32>(MemoryAttribute::Uncached); + constexpr u32 SupportedMask = + static_cast<u32>(MemoryAttribute::Uncached | MemoryAttribute::PermissionLocked); R_UNLESS((mask | attr) == mask, ResultInvalidCombination); R_UNLESS((mask | attr | SupportedMask) == SupportedMask, ResultInvalidCombination); + // Check that permission locked is either being set or not masked. + R_UNLESS((static_cast<Svc::MemoryAttribute>(mask) & Svc::MemoryAttribute::PermissionLocked) == + (static_cast<Svc::MemoryAttribute>(attr) & Svc::MemoryAttribute::PermissionLocked), + ResultInvalidCombination); + // Validate that the region is in range for the current process. auto& page_table{GetCurrentProcess(system.Kernel()).GetPageTable()}; R_UNLESS(page_table.Contains(address, size), ResultInvalidCurrentMemory); diff --git a/src/core/hle/kernel/svc_types.h b/src/core/hle/kernel/svc_types.h index 7f380ca4f..251e6013c 100644 --- a/src/core/hle/kernel/svc_types.h +++ b/src/core/hle/kernel/svc_types.h @@ -46,6 +46,7 @@ enum class MemoryAttribute : u32 { IpcLocked = (1 << 1), DeviceShared = (1 << 2), Uncached = (1 << 3), + PermissionLocked = (1 << 4), }; DECLARE_ENUM_FLAG_OPERATORS(MemoryAttribute); diff --git a/src/core/hle/service/nvnflinger/fb_share_buffer_manager.cpp b/src/core/hle/service/nvnflinger/fb_share_buffer_manager.cpp index 469a53244..2e29bc848 100644 --- a/src/core/hle/service/nvnflinger/fb_share_buffer_manager.cpp +++ b/src/core/hle/service/nvnflinger/fb_share_buffer_manager.cpp @@ -46,7 +46,7 @@ Result AllocateIoForProcessAddressSpace(Common::ProcessAddress* out_map_address, // Get bounds of where mapping is possible. const VAddr alias_code_begin = GetInteger(page_table.GetAliasCodeRegionStart()); const VAddr alias_code_size = page_table.GetAliasCodeRegionSize() / YUZU_PAGESIZE; - const auto state = Kernel::KMemoryState::Io; + const auto state = Kernel::KMemoryState::IoMemory; const auto perm = Kernel::KMemoryPermission::UserReadWrite; std::mt19937_64 rng{process->GetRandomEntropy(0)}; diff --git a/src/shader_recompiler/backend/spirv/emit_spirv_context_get_set.cpp b/src/shader_recompiler/backend/spirv/emit_spirv_context_get_set.cpp index 2868fc57d..1d77426e0 100644 --- a/src/shader_recompiler/backend/spirv/emit_spirv_context_get_set.cpp +++ b/src/shader_recompiler/backend/spirv/emit_spirv_context_get_set.cpp @@ -111,16 +111,33 @@ Id GetCbuf(EmitContext& ctx, Id result_type, Id UniformDefinitions::*member_ptr, } else if (element_size > 1) { const u32 log2_element_size{static_cast<u32>(std::countr_zero(element_size))}; const Id shift{ctx.Const(log2_element_size)}; - buffer_offset = ctx.OpShiftRightArithmetic(ctx.U32[1], ctx.Def(offset), shift); + buffer_offset = ctx.OpShiftRightLogical(ctx.U32[1], ctx.Def(offset), shift); } else { buffer_offset = ctx.Def(offset); } if (!binding.IsImmediate()) { return ctx.OpFunctionCall(result_type, indirect_func, ctx.Def(binding), buffer_offset); } + const Id cbuf{ctx.cbufs[binding.U32()].*member_ptr}; const Id access_chain{ctx.OpAccessChain(uniform_type, cbuf, ctx.u32_zero_value, buffer_offset)}; - return ctx.OpLoad(result_type, access_chain); + const Id val = ctx.OpLoad(result_type, access_chain); + + if (offset.IsImmediate() || !ctx.profile.has_broken_robust) { + return val; + } + + const auto is_float = UniformDefinitions::IsFloat(member_ptr); + const auto num_elements = UniformDefinitions::NumElements(member_ptr); + const std::array zero_vec{ + is_float ? ctx.Const(0.0f) : ctx.Const(0u), + is_float ? ctx.Const(0.0f) : ctx.Const(0u), + is_float ? ctx.Const(0.0f) : ctx.Const(0u), + is_float ? ctx.Const(0.0f) : ctx.Const(0u), + }; + const Id cond = ctx.OpULessThanEqual(ctx.TypeBool(), buffer_offset, ctx.Const(0xFFFFu)); + const Id zero = ctx.OpCompositeConstruct(result_type, std::span(zero_vec.data(), num_elements)); + return ctx.OpSelect(result_type, cond, val, zero); } Id GetCbufU32(EmitContext& ctx, const IR::Value& binding, const IR::Value& offset) { @@ -138,7 +155,7 @@ Id GetCbufElement(EmitContext& ctx, Id vector, const IR::Value& offset, u32 inde const u32 element{(offset.U32() / 4) % 4 + index_offset}; return ctx.OpCompositeExtract(ctx.U32[1], vector, element); } - const Id shift{ctx.OpShiftRightArithmetic(ctx.U32[1], ctx.Def(offset), ctx.Const(2u))}; + const Id shift{ctx.OpShiftRightLogical(ctx.U32[1], ctx.Def(offset), ctx.Const(2u))}; Id element{ctx.OpBitwiseAnd(ctx.U32[1], shift, ctx.Const(3u))}; if (index_offset > 0) { element = ctx.OpIAdd(ctx.U32[1], element, ctx.Const(index_offset)); diff --git a/src/shader_recompiler/backend/spirv/spirv_emit_context.h b/src/shader_recompiler/backend/spirv/spirv_emit_context.h index 7c49fd504..1aa79863d 100644 --- a/src/shader_recompiler/backend/spirv/spirv_emit_context.h +++ b/src/shader_recompiler/backend/spirv/spirv_emit_context.h @@ -64,6 +64,42 @@ struct UniformDefinitions { Id F32{}; Id U32x2{}; Id U32x4{}; + + constexpr static size_t NumElements(Id UniformDefinitions::*member_ptr) { + if (member_ptr == &UniformDefinitions::U8) { + return 1; + } + if (member_ptr == &UniformDefinitions::S8) { + return 1; + } + if (member_ptr == &UniformDefinitions::U16) { + return 1; + } + if (member_ptr == &UniformDefinitions::S16) { + return 1; + } + if (member_ptr == &UniformDefinitions::U32) { + return 1; + } + if (member_ptr == &UniformDefinitions::F32) { + return 1; + } + if (member_ptr == &UniformDefinitions::U32x2) { + return 2; + } + if (member_ptr == &UniformDefinitions::U32x4) { + return 4; + } + ASSERT(false); + return 1; + } + + constexpr static bool IsFloat(Id UniformDefinitions::*member_ptr) { + if (member_ptr == &UniformDefinitions::F32) { + return true; + } + return false; + } }; struct StorageTypeDefinition { diff --git a/src/shader_recompiler/profile.h b/src/shader_recompiler/profile.h index 9ca97f6a4..38d820db2 100644 --- a/src/shader_recompiler/profile.h +++ b/src/shader_recompiler/profile.h @@ -9,7 +9,6 @@ namespace Shader { struct Profile { u32 supported_spirv{0x00010000}; - bool unified_descriptor_binding{}; bool support_descriptor_aliasing{}; bool support_int8{}; @@ -82,6 +81,9 @@ struct Profile { bool has_broken_spirv_subgroup_mask_vector_extract_dynamic{}; u32 gl_max_compute_smem_size{}; + + /// Maxwell and earlier nVidia architectures have broken robust support + bool has_broken_robust{}; }; } // namespace Shader diff --git a/src/video_core/fence_manager.h b/src/video_core/fence_manager.h index 805a89900..c0e6471fe 100644 --- a/src/video_core/fence_manager.h +++ b/src/video_core/fence_manager.h @@ -86,7 +86,10 @@ public: uncommitted_operations.emplace_back(std::move(func)); } pending_operations.emplace_back(std::move(uncommitted_operations)); - QueueFence(new_fence); + { + std::scoped_lock lock{buffer_cache.mutex, texture_cache.mutex}; + QueueFence(new_fence); + } if (!delay_fence) { func(); } diff --git a/src/video_core/renderer_vulkan/renderer_vulkan.cpp b/src/video_core/renderer_vulkan/renderer_vulkan.cpp index c4c30d807..7e7a80740 100644 --- a/src/video_core/renderer_vulkan/renderer_vulkan.cpp +++ b/src/video_core/renderer_vulkan/renderer_vulkan.cpp @@ -132,12 +132,16 @@ void RendererVulkan::SwapBuffers(const Tegra::FramebufferConfig* framebuffer) { const bool use_accelerated = rasterizer.AccelerateDisplay(*framebuffer, framebuffer_addr, framebuffer->stride); const bool is_srgb = use_accelerated && screen_info.is_srgb; - RenderScreenshot(*framebuffer, use_accelerated); - Frame* frame = present_manager.GetRenderFrame(); - blit_screen.DrawToSwapchain(frame, *framebuffer, use_accelerated, is_srgb); - scheduler.Flush(*frame->render_ready); - present_manager.Present(frame); + { + std::scoped_lock lock{rasterizer.LockCaches()}; + RenderScreenshot(*framebuffer, use_accelerated); + + Frame* frame = present_manager.GetRenderFrame(); + blit_screen.DrawToSwapchain(frame, *framebuffer, use_accelerated, is_srgb); + scheduler.Flush(*frame->render_ready); + present_manager.Present(frame); + } gpu.RendererFrameEndNotify(); rasterizer.TickFrame(); diff --git a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp index a1ec1a100..804b95989 100644 --- a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp +++ b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp @@ -356,7 +356,11 @@ PipelineCache::PipelineCache(RasterizerVulkan& rasterizer_, const Device& device .has_broken_fp16_float_controls = driver_id == VK_DRIVER_ID_NVIDIA_PROPRIETARY, .ignore_nan_fp_comparisons = false, .has_broken_spirv_subgroup_mask_vector_extract_dynamic = - driver_id == VK_DRIVER_ID_QUALCOMM_PROPRIETARY}; + driver_id == VK_DRIVER_ID_QUALCOMM_PROPRIETARY, + .has_broken_robust = + device.IsNvidia() && device.GetNvidiaArch() <= NvidiaArchitecture::Arch_Maxwell, + }; + host_info = Shader::HostTranslateInfo{ .support_float64 = device.IsFloat64Supported(), .support_float16 = device.IsFloat16Supported(), diff --git a/src/video_core/renderer_vulkan/vk_rasterizer.cpp b/src/video_core/renderer_vulkan/vk_rasterizer.cpp index 61d03daae..465eac37e 100644 --- a/src/video_core/renderer_vulkan/vk_rasterizer.cpp +++ b/src/video_core/renderer_vulkan/vk_rasterizer.cpp @@ -198,7 +198,7 @@ void RasterizerVulkan::PrepareDraw(bool is_indexed, Func&& draw_func) { if (!pipeline) { return; } - std::scoped_lock lock{buffer_cache.mutex, texture_cache.mutex}; + std::scoped_lock lock{LockCaches()}; // update engine as channel may be different. pipeline->SetEngine(maxwell3d, gpu_memory); pipeline->Configure(is_indexed); @@ -708,6 +708,7 @@ void RasterizerVulkan::TiledCacheBarrier() { } void RasterizerVulkan::FlushCommands() { + std::scoped_lock lock{LockCaches()}; if (draw_counter == 0) { return; } @@ -805,6 +806,7 @@ void RasterizerVulkan::FlushWork() { if ((++draw_counter & 7) != 7) { return; } + std::scoped_lock lock{LockCaches()}; if (draw_counter < DRAWS_TO_DISPATCH) { // Send recorded tasks to the worker thread scheduler.DispatchWork(); @@ -1499,7 +1501,7 @@ void RasterizerVulkan::UpdateVertexInput(Tegra::Engines::Maxwell3D::Regs& regs) void RasterizerVulkan::InitializeChannel(Tegra::Control::ChannelState& channel) { CreateChannel(channel); { - std::scoped_lock lock{buffer_cache.mutex, texture_cache.mutex}; + std::scoped_lock lock{LockCaches()}; texture_cache.CreateChannel(channel); buffer_cache.CreateChannel(channel); } @@ -1512,7 +1514,7 @@ void RasterizerVulkan::BindChannel(Tegra::Control::ChannelState& channel) { const s32 channel_id = channel.bind_id; BindToChannel(channel_id); { - std::scoped_lock lock{buffer_cache.mutex, texture_cache.mutex}; + std::scoped_lock lock{LockCaches()}; texture_cache.BindToChannel(channel_id); buffer_cache.BindToChannel(channel_id); } @@ -1525,7 +1527,7 @@ void RasterizerVulkan::BindChannel(Tegra::Control::ChannelState& channel) { void RasterizerVulkan::ReleaseChannel(s32 channel_id) { EraseChannel(channel_id); { - std::scoped_lock lock{buffer_cache.mutex, texture_cache.mutex}; + std::scoped_lock lock{LockCaches()}; texture_cache.EraseChannel(channel_id); buffer_cache.EraseChannel(channel_id); } diff --git a/src/video_core/renderer_vulkan/vk_rasterizer.h b/src/video_core/renderer_vulkan/vk_rasterizer.h index ad069556c..ce3dfbaab 100644 --- a/src/video_core/renderer_vulkan/vk_rasterizer.h +++ b/src/video_core/renderer_vulkan/vk_rasterizer.h @@ -133,6 +133,10 @@ public: void ReleaseChannel(s32 channel_id) override; + std::scoped_lock<std::recursive_mutex, std::recursive_mutex> LockCaches() { + return std::scoped_lock{buffer_cache.mutex, texture_cache.mutex}; + } + private: static constexpr size_t MAX_TEXTURES = 192; static constexpr size_t MAX_IMAGES = 48; diff --git a/src/video_core/vulkan_common/vulkan_device.cpp b/src/video_core/vulkan_common/vulkan_device.cpp index 876cec2e8..e518756d2 100644 --- a/src/video_core/vulkan_common/vulkan_device.cpp +++ b/src/video_core/vulkan_common/vulkan_device.cpp @@ -83,15 +83,6 @@ constexpr std::array VK_FORMAT_A4B4G4R4_UNORM_PACK16{ } // namespace Alternatives -enum class NvidiaArchitecture { - KeplerOrOlder, - Maxwell, - Pascal, - Volta, - Turing, - AmpereOrNewer, -}; - template <typename T> void SetNext(void**& next, T& data) { *next = &data; @@ -326,9 +317,9 @@ NvidiaArchitecture GetNvidiaArchitecture(vk::PhysicalDevice physical, if (shading_rate_props.primitiveFragmentShadingRateWithMultipleViewports) { // Only Ampere and newer support this feature // TODO: Find a way to differentiate Ampere and Ada - return NvidiaArchitecture::AmpereOrNewer; + return NvidiaArchitecture::Arch_AmpereOrNewer; } - return NvidiaArchitecture::Turing; + return NvidiaArchitecture::Arch_Turing; } if (exts.contains(VK_EXT_BLEND_OPERATION_ADVANCED_EXTENSION_NAME)) { @@ -340,7 +331,7 @@ NvidiaArchitecture GetNvidiaArchitecture(vk::PhysicalDevice physical, physical_properties.pNext = &advanced_blending_props; physical.GetProperties2(physical_properties); if (advanced_blending_props.advancedBlendMaxColorAttachments == 1) { - return NvidiaArchitecture::Maxwell; + return NvidiaArchitecture::Arch_Maxwell; } if (exts.contains(VK_EXT_CONSERVATIVE_RASTERIZATION_EXTENSION_NAME)) { @@ -350,13 +341,13 @@ NvidiaArchitecture GetNvidiaArchitecture(vk::PhysicalDevice physical, physical_properties.pNext = &conservative_raster_props; physical.GetProperties2(physical_properties); if (conservative_raster_props.degenerateLinesRasterized) { - return NvidiaArchitecture::Volta; + return NvidiaArchitecture::Arch_Volta; } - return NvidiaArchitecture::Pascal; + return NvidiaArchitecture::Arch_Pascal; } } - return NvidiaArchitecture::KeplerOrOlder; + return NvidiaArchitecture::Arch_KeplerOrOlder; } std::vector<const char*> ExtensionListForVulkan( @@ -436,6 +427,10 @@ Device::Device(VkInstance instance_, vk::PhysicalDevice physical_, VkSurfaceKHR throw vk::Exception(VK_ERROR_INCOMPATIBLE_DRIVER); } + if (is_nvidia) { + nvidia_arch = GetNvidiaArchitecture(physical, supported_extensions); + } + SetupFamilies(surface); const auto queue_cis = GetDeviceQueueCreateInfos(); @@ -532,11 +527,11 @@ Device::Device(VkInstance instance_, vk::PhysicalDevice physical_, VkSurfaceKHR if (is_nvidia) { const u32 nv_major_version = (properties.properties.driverVersion >> 22) & 0x3ff; - const auto arch = GetNvidiaArchitecture(physical, supported_extensions); - if (arch >= NvidiaArchitecture::AmpereOrNewer) { + const auto arch = GetNvidiaArch(); + if (arch >= NvidiaArchitecture::Arch_AmpereOrNewer) { LOG_WARNING(Render_Vulkan, "Ampere and newer have broken float16 math"); features.shader_float16_int8.shaderFloat16 = false; - } else if (arch <= NvidiaArchitecture::Volta) { + } else if (arch <= NvidiaArchitecture::Arch_Volta) { if (nv_major_version < 527) { LOG_WARNING(Render_Vulkan, "Volta and older have broken VK_KHR_push_descriptor"); RemoveExtension(extensions.push_descriptor, VK_KHR_PUSH_DESCRIPTOR_EXTENSION_NAME); @@ -686,8 +681,8 @@ Device::Device(VkInstance instance_, vk::PhysicalDevice physical_, VkSurfaceKHR RemoveExtension(extensions.push_descriptor, VK_KHR_PUSH_DESCRIPTOR_EXTENSION_NAME); } } else if (extensions.push_descriptor && is_nvidia) { - const auto arch = GetNvidiaArchitecture(physical, supported_extensions); - if (arch <= NvidiaArchitecture::Pascal) { + const auto arch = GetNvidiaArch(); + if (arch <= NvidiaArchitecture::Arch_Pascal) { LOG_WARNING(Render_Vulkan, "Pascal and older architectures have broken VK_KHR_push_descriptor"); RemoveExtension(extensions.push_descriptor, VK_KHR_PUSH_DESCRIPTOR_EXTENSION_NAME); diff --git a/src/video_core/vulkan_common/vulkan_device.h b/src/video_core/vulkan_common/vulkan_device.h index 282a2925d..b213ed7dd 100644 --- a/src/video_core/vulkan_common/vulkan_device.h +++ b/src/video_core/vulkan_common/vulkan_device.h @@ -177,6 +177,15 @@ enum class FormatType { Linear, Optimal, Buffer }; /// Subgroup size of the guest emulated hardware (Nvidia has 32 threads per subgroup). const u32 GuestWarpSize = 32; +enum class NvidiaArchitecture { + Arch_KeplerOrOlder, + Arch_Maxwell, + Arch_Pascal, + Arch_Volta, + Arch_Turing, + Arch_AmpereOrNewer, +}; + /// Handles data specific to a physical device. class Device { public: @@ -670,6 +679,14 @@ public: return false; } + bool IsNvidia() const noexcept { + return properties.driver.driverID == VK_DRIVER_ID_NVIDIA_PROPRIETARY; + } + + NvidiaArchitecture GetNvidiaArch() const noexcept { + return nvidia_arch; + } + private: /// Checks if the physical device is suitable and configures the object state /// with all necessary info about its properties. @@ -788,6 +805,7 @@ private: bool supports_conditional_barriers{}; ///< Allows barriers in conditional control flow. u64 device_access_memory{}; ///< Total size of device local memory in bytes. u32 sets_per_pool{}; ///< Sets per Description Pool + NvidiaArchitecture nvidia_arch{NvidiaArchitecture::Arch_AmpereOrNewer}; // Telemetry parameters std::set<std::string, std::less<>> supported_extensions; ///< Reported Vulkan extensions. |