diff --git a/libraries/libmesosphere/include/mesosphere/arch/arm64/kern_k_process_page_table.hpp b/libraries/libmesosphere/include/mesosphere/arch/arm64/kern_k_process_page_table.hpp index 4a8e48a21..0d074a6b2 100644 --- a/libraries/libmesosphere/include/mesosphere/arch/arm64/kern_k_process_page_table.hpp +++ b/libraries/libmesosphere/include/mesosphere/arch/arm64/kern_k_process_page_table.hpp @@ -98,8 +98,8 @@ namespace ams::kern::arch::arm64 { R_RETURN(m_page_table.MapIoRegion(dst_address, phys_addr, size, mapping, perm)); } - Result UnmapIoRegion(KProcessAddress dst_address, KPhysicalAddress phys_addr, size_t size) { - R_RETURN(m_page_table.UnmapIoRegion(dst_address, phys_addr, size)); + Result UnmapIoRegion(KProcessAddress dst_address, KPhysicalAddress phys_addr, size_t size, ams::svc::MemoryMapping mapping) { + R_RETURN(m_page_table.UnmapIoRegion(dst_address, phys_addr, size, mapping)); } Result MapStatic(KPhysicalAddress phys_addr, size_t size, KMemoryPermission perm) { diff --git a/libraries/libmesosphere/include/mesosphere/kern_k_page_table_base.hpp b/libraries/libmesosphere/include/mesosphere/kern_k_page_table_base.hpp index 83d82b615..13f0ec10d 100644 --- a/libraries/libmesosphere/include/mesosphere/kern_k_page_table_base.hpp +++ b/libraries/libmesosphere/include/mesosphere/kern_k_page_table_base.hpp @@ -363,7 +363,7 @@ namespace ams::kern { Result UnmapCodeMemory(KProcessAddress dst_address, KProcessAddress src_address, size_t size); Result MapIo(KPhysicalAddress phys_addr, size_t size, KMemoryPermission perm); Result MapIoRegion(KProcessAddress dst_address, KPhysicalAddress phys_addr, size_t size, ams::svc::MemoryMapping mapping, ams::svc::MemoryPermission perm); - Result UnmapIoRegion(KProcessAddress dst_address, KPhysicalAddress phys_addr, size_t size); + Result UnmapIoRegion(KProcessAddress dst_address, KPhysicalAddress phys_addr, size_t size, ams::svc::MemoryMapping mapping); Result MapStatic(KPhysicalAddress phys_addr, size_t size, KMemoryPermission perm); Result MapRegion(KMemoryRegionType region_type, KMemoryPermission perm); Result MapInsecureMemory(KProcessAddress address, size_t size); diff --git a/libraries/libmesosphere/source/kern_k_io_region.cpp b/libraries/libmesosphere/source/kern_k_io_region.cpp index 1c309af50..f27d17d10 100644 --- a/libraries/libmesosphere/source/kern_k_io_region.cpp +++ b/libraries/libmesosphere/source/kern_k_io_region.cpp @@ -85,7 +85,7 @@ namespace ams::kern { KScopedLightLock lk(m_lock); /* Unmap ourselves. */ - R_TRY(GetCurrentProcess().GetPageTable().UnmapIoRegion(address, m_physical_address, size)); + R_TRY(GetCurrentProcess().GetPageTable().UnmapIoRegion(address, m_physical_address, size, m_mapping)); /* Remove ourselves from the current process. */ GetCurrentProcess().RemoveIoRegion(this); diff --git a/libraries/libmesosphere/source/kern_k_page_table_base.cpp b/libraries/libmesosphere/source/kern_k_page_table_base.cpp index bccf01e04..155fd0091 100644 --- a/libraries/libmesosphere/source/kern_k_page_table_base.cpp +++ b/libraries/libmesosphere/source/kern_k_page_table_base.cpp @@ -2019,15 +2019,22 @@ namespace ams::kern { R_SUCCEED(); } - Result KPageTableBase::UnmapIoRegion(KProcessAddress dst_address, KPhysicalAddress phys_addr, size_t size) { + Result KPageTableBase::UnmapIoRegion(KProcessAddress dst_address, KPhysicalAddress phys_addr, size_t size, ams::svc::MemoryMapping mapping) { const size_t num_pages = size / PageSize; /* Lock the table. */ KScopedLightLock lk(m_general_lock); /* Validate the memory state. */ + KMemoryState old_state; + KMemoryPermission old_perm; + KMemoryAttribute old_attr; size_t num_allocator_blocks; - R_TRY(this->CheckMemoryState(std::addressof(num_allocator_blocks), dst_address, size, KMemoryState_All, KMemoryState_Io, KMemoryPermission_None, KMemoryPermission_None, KMemoryAttribute_All, KMemoryAttribute_Locked)); + R_TRY(this->CheckMemoryState(std::addressof(old_state), std::addressof(old_perm), std::addressof(old_attr), std::addressof(num_allocator_blocks), + dst_address, size, + KMemoryState_All, KMemoryState_Io, + KMemoryPermission_None, KMemoryPermission_None, + KMemoryAttribute_All, KMemoryAttribute_Locked)); /* Validate that the region being unmapped corresponds to the physical range described. */ { @@ -2060,9 +2067,23 @@ namespace ams::kern { /* We're going to perform an update, so create a helper. */ KScopedPageTableUpdater updater(this); + /* If the region being unmapped is Memory, synchronize. */ + if (mapping == ams::svc::MemoryMapping_Memory) { + /* Change the region to be uncached. */ + const KPageProperties properties = { old_perm, false, true, DisableMergeAttribute_None }; + MESOSPHERE_R_ABORT_UNLESS(this->Operate(updater.GetPageList(), dst_address, num_pages, Null, false, properties, OperationType_ChangePermissionsAndRefresh, false)); + + /* Temporarily unlock ourselves, so that other operations can occur while we flush the region. */ + m_general_lock.Unlock(); + ON_SCOPE_EXIT { m_general_lock.Lock(); }; + + /* Flush the region. */ + MESOSPHERE_R_ABORT_UNLESS(cpu::FlushDataCache(GetVoidPointer(dst_address), size)); + } + /* Perform the unmap. */ const KPageProperties unmap_properties = { KMemoryPermission_None, false, false, DisableMergeAttribute_None }; - R_TRY(this->Operate(updater.GetPageList(), dst_address, num_pages, Null, false, unmap_properties, OperationType_Unmap, false)); + MESOSPHERE_R_ABORT_UNLESS(this->Operate(updater.GetPageList(), dst_address, num_pages, Null, false, unmap_properties, OperationType_Unmap, false)); /* Update the blocks. */ m_memory_block_manager.Update(std::addressof(allocator), dst_address, num_pages, KMemoryState_Free, KMemoryPermission_None, KMemoryAttribute_None, KMemoryBlockDisableMergeAttribute_None, KMemoryBlockDisableMergeAttribute_Normal);