mirror of
				https://git.suyu.dev/suyu/suyu
				synced 2025-10-30 23:49:01 -05:00 
			
		
		
		
	kernel: transfer_memory: Properly reserve and reset memory region.
This commit is contained in:
		| @@ -1863,10 +1863,14 @@ static ResultCode CreateTransferMemory(Core::System& system, Handle* handle, VAd | |||||||
|     } |     } | ||||||
|  |  | ||||||
|     auto& kernel = system.Kernel(); |     auto& kernel = system.Kernel(); | ||||||
|     auto transfer_mem_handle = TransferMemory::Create(kernel, addr, size, perms); |     auto transfer_mem_handle = TransferMemory::Create(kernel, system.Memory(), addr, size, perms); | ||||||
|  |  | ||||||
|  |     if (const auto reserve_result{transfer_mem_handle->Reserve()}; reserve_result.IsError()) { | ||||||
|  |         return reserve_result; | ||||||
|  |     } | ||||||
|  |  | ||||||
|     auto& handle_table = kernel.CurrentProcess()->GetHandleTable(); |     auto& handle_table = kernel.CurrentProcess()->GetHandleTable(); | ||||||
|     const auto result = handle_table.Create(std::move(transfer_mem_handle)); |     const auto result{handle_table.Create(std::move(transfer_mem_handle))}; | ||||||
|     if (result.Failed()) { |     if (result.Failed()) { | ||||||
|         return result.Code(); |         return result.Code(); | ||||||
|     } |     } | ||||||
|   | |||||||
| @@ -8,15 +8,23 @@ | |||||||
| #include "core/hle/kernel/shared_memory.h" | #include "core/hle/kernel/shared_memory.h" | ||||||
| #include "core/hle/kernel/transfer_memory.h" | #include "core/hle/kernel/transfer_memory.h" | ||||||
| #include "core/hle/result.h" | #include "core/hle/result.h" | ||||||
|  | #include "core/memory.h" | ||||||
|  |  | ||||||
| namespace Kernel { | namespace Kernel { | ||||||
|  |  | ||||||
| TransferMemory::TransferMemory(KernelCore& kernel) : Object{kernel} {} | TransferMemory::TransferMemory(KernelCore& kernel, Memory::Memory& memory) | ||||||
| TransferMemory::~TransferMemory() = default; |     : Object{kernel}, memory{memory} {} | ||||||
|  |  | ||||||
| std::shared_ptr<TransferMemory> TransferMemory::Create(KernelCore& kernel, VAddr base_address, | TransferMemory::~TransferMemory() { | ||||||
|                                                        u64 size, MemoryPermission permissions) { |     // Release memory region when transfer memory is destroyed | ||||||
|     std::shared_ptr<TransferMemory> transfer_memory{std::make_shared<TransferMemory>(kernel)}; |     Reset(); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | std::shared_ptr<TransferMemory> TransferMemory::Create(KernelCore& kernel, Memory::Memory& memory, | ||||||
|  |                                                        VAddr base_address, u64 size, | ||||||
|  |                                                        MemoryPermission permissions) { | ||||||
|  |     std::shared_ptr<TransferMemory> transfer_memory{ | ||||||
|  |         std::make_shared<TransferMemory>(kernel, memory)}; | ||||||
|  |  | ||||||
|     transfer_memory->base_address = base_address; |     transfer_memory->base_address = base_address; | ||||||
|     transfer_memory->memory_size = size; |     transfer_memory->memory_size = size; | ||||||
| @@ -27,7 +35,7 @@ std::shared_ptr<TransferMemory> TransferMemory::Create(KernelCore& kernel, VAddr | |||||||
| } | } | ||||||
|  |  | ||||||
| const u8* TransferMemory::GetPointer() const { | const u8* TransferMemory::GetPointer() const { | ||||||
|     return backing_block.get()->data(); |     return memory.GetPointer(base_address); | ||||||
| } | } | ||||||
|  |  | ||||||
| u64 TransferMemory::GetSize() const { | u64 TransferMemory::GetSize() const { | ||||||
| @@ -62,6 +70,52 @@ ResultCode TransferMemory::MapMemory(VAddr address, u64 size, MemoryPermission p | |||||||
|     return RESULT_SUCCESS; |     return RESULT_SUCCESS; | ||||||
| } | } | ||||||
|  |  | ||||||
|  | ResultCode TransferMemory::Reserve() { | ||||||
|  |     auto& vm_manager{owner_process->VMManager()}; | ||||||
|  |     const auto check_range_result{vm_manager.CheckRangeState( | ||||||
|  |         base_address, memory_size, MemoryState::FlagTransfer | MemoryState::FlagMemoryPoolAllocated, | ||||||
|  |         MemoryState::FlagTransfer | MemoryState::FlagMemoryPoolAllocated, VMAPermission::All, | ||||||
|  |         VMAPermission::ReadWrite, MemoryAttribute::Mask, MemoryAttribute::None, | ||||||
|  |         MemoryAttribute::IpcAndDeviceMapped)}; | ||||||
|  |  | ||||||
|  |     if (check_range_result.Failed()) { | ||||||
|  |         return check_range_result.Code(); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     auto [state_, permissions_, attribute] = *check_range_result; | ||||||
|  |  | ||||||
|  |     if (const auto result{vm_manager.ReprotectRange( | ||||||
|  |             base_address, memory_size, SharedMemory::ConvertPermissions(owner_permissions))}; | ||||||
|  |         result.IsError()) { | ||||||
|  |         return result; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     return vm_manager.SetMemoryAttribute(base_address, memory_size, MemoryAttribute::Mask, | ||||||
|  |                                          attribute | MemoryAttribute::Locked); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | ResultCode TransferMemory::Reset() { | ||||||
|  |     auto& vm_manager{owner_process->VMManager()}; | ||||||
|  |     if (const auto result{vm_manager.CheckRangeState( | ||||||
|  |             base_address, memory_size, | ||||||
|  |             MemoryState::FlagTransfer | MemoryState::FlagMemoryPoolAllocated, | ||||||
|  |             MemoryState::FlagTransfer | MemoryState::FlagMemoryPoolAllocated, VMAPermission::None, | ||||||
|  |             VMAPermission::None, MemoryAttribute::Mask, MemoryAttribute::Locked, | ||||||
|  |             MemoryAttribute::IpcAndDeviceMapped)}; | ||||||
|  |         result.Failed()) { | ||||||
|  |         return result.Code(); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     if (const auto result{ | ||||||
|  |             vm_manager.ReprotectRange(base_address, memory_size, VMAPermission::ReadWrite)}; | ||||||
|  |         result.IsError()) { | ||||||
|  |         return result; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     return vm_manager.SetMemoryAttribute(base_address, memory_size, MemoryAttribute::Mask, | ||||||
|  |                                          MemoryAttribute::None); | ||||||
|  | } | ||||||
|  |  | ||||||
| ResultCode TransferMemory::UnmapMemory(VAddr address, u64 size) { | ResultCode TransferMemory::UnmapMemory(VAddr address, u64 size) { | ||||||
|     if (memory_size != size) { |     if (memory_size != size) { | ||||||
|         return ERR_INVALID_SIZE; |         return ERR_INVALID_SIZE; | ||||||
|   | |||||||
| @@ -11,6 +11,10 @@ | |||||||
|  |  | ||||||
| union ResultCode; | union ResultCode; | ||||||
|  |  | ||||||
|  | namespace Memory { | ||||||
|  | class Memory; | ||||||
|  | } | ||||||
|  |  | ||||||
| namespace Kernel { | namespace Kernel { | ||||||
|  |  | ||||||
| class KernelCore; | class KernelCore; | ||||||
| @@ -26,12 +30,13 @@ enum class MemoryPermission : u32; | |||||||
| /// | /// | ||||||
| class TransferMemory final : public Object { | class TransferMemory final : public Object { | ||||||
| public: | public: | ||||||
|     explicit TransferMemory(KernelCore& kernel); |     explicit TransferMemory(KernelCore& kernel, Memory::Memory& memory); | ||||||
|     ~TransferMemory() override; |     ~TransferMemory() override; | ||||||
|  |  | ||||||
|     static constexpr HandleType HANDLE_TYPE = HandleType::TransferMemory; |     static constexpr HandleType HANDLE_TYPE = HandleType::TransferMemory; | ||||||
|  |  | ||||||
|     static std::shared_ptr<TransferMemory> Create(KernelCore& kernel, VAddr base_address, u64 size, |     static std::shared_ptr<TransferMemory> Create(KernelCore& kernel, Memory::Memory& memory, | ||||||
|  |                                                   VAddr base_address, u64 size, | ||||||
|                                                   MemoryPermission permissions); |                                                   MemoryPermission permissions); | ||||||
|  |  | ||||||
|     TransferMemory(const TransferMemory&) = delete; |     TransferMemory(const TransferMemory&) = delete; | ||||||
| @@ -80,6 +85,14 @@ public: | |||||||
|     /// |     /// | ||||||
|     ResultCode UnmapMemory(VAddr address, u64 size); |     ResultCode UnmapMemory(VAddr address, u64 size); | ||||||
|  |  | ||||||
|  |     /// Reserves the region to be used for the transfer memory, called after the transfer memory is | ||||||
|  |     /// created. | ||||||
|  |     ResultCode Reserve(); | ||||||
|  |  | ||||||
|  |     /// Resets the region previously used for the transfer memory, called after the transfer memory | ||||||
|  |     /// is closed. | ||||||
|  |     ResultCode Reset(); | ||||||
|  |  | ||||||
| private: | private: | ||||||
|     /// Memory block backing this instance. |     /// Memory block backing this instance. | ||||||
|     std::shared_ptr<PhysicalMemory> backing_block; |     std::shared_ptr<PhysicalMemory> backing_block; | ||||||
| @@ -98,6 +111,8 @@ private: | |||||||
|  |  | ||||||
|     /// Whether or not this transfer memory instance has mapped memory. |     /// Whether or not this transfer memory instance has mapped memory. | ||||||
|     bool is_mapped = false; |     bool is_mapped = false; | ||||||
|  |  | ||||||
|  |     Memory::Memory& memory; | ||||||
| }; | }; | ||||||
|  |  | ||||||
| } // namespace Kernel | } // namespace Kernel | ||||||
|   | |||||||
| @@ -544,7 +544,8 @@ MemoryInfo VMManager::QueryMemory(VAddr address) const { | |||||||
|  |  | ||||||
| ResultCode VMManager::SetMemoryAttribute(VAddr address, u64 size, MemoryAttribute mask, | ResultCode VMManager::SetMemoryAttribute(VAddr address, u64 size, MemoryAttribute mask, | ||||||
|                                          MemoryAttribute attribute) { |                                          MemoryAttribute attribute) { | ||||||
|     constexpr auto ignore_mask = MemoryAttribute::Uncached | MemoryAttribute::DeviceMapped; |     constexpr auto ignore_mask = | ||||||
|  |         MemoryAttribute::Uncached | MemoryAttribute::DeviceMapped | MemoryAttribute::Locked; | ||||||
|     constexpr auto attribute_mask = ~ignore_mask; |     constexpr auto attribute_mask = ~ignore_mask; | ||||||
|  |  | ||||||
|     const auto result = CheckRangeState( |     const auto result = CheckRangeState( | ||||||
|   | |||||||
| @@ -98,6 +98,8 @@ enum class MemoryAttribute : u32 { | |||||||
|     DeviceMapped = 4, |     DeviceMapped = 4, | ||||||
|     /// Uncached memory |     /// Uncached memory | ||||||
|     Uncached = 8, |     Uncached = 8, | ||||||
|  |  | ||||||
|  |     IpcAndDeviceMapped = LockedForIPC | DeviceMapped, | ||||||
| }; | }; | ||||||
|  |  | ||||||
| constexpr MemoryAttribute operator|(MemoryAttribute lhs, MemoryAttribute rhs) { | constexpr MemoryAttribute operator|(MemoryAttribute lhs, MemoryAttribute rhs) { | ||||||
| @@ -654,6 +656,35 @@ public: | |||||||
|     /// is scheduled. |     /// is scheduled. | ||||||
|     Common::PageTable page_table{Memory::PAGE_BITS}; |     Common::PageTable page_table{Memory::PAGE_BITS}; | ||||||
|  |  | ||||||
|  |     using CheckResults = ResultVal<std::tuple<MemoryState, VMAPermission, MemoryAttribute>>; | ||||||
|  |  | ||||||
|  |     /// Checks if an address range adheres to the specified states provided. | ||||||
|  |     /// | ||||||
|  |     /// @param address         The starting address of the address range. | ||||||
|  |     /// @param size            The size of the address range. | ||||||
|  |     /// @param state_mask      The memory state mask. | ||||||
|  |     /// @param state           The state to compare the individual VMA states against, | ||||||
|  |     ///                        which is done in the form of: (vma.state & state_mask) != state. | ||||||
|  |     /// @param permission_mask The memory permissions mask. | ||||||
|  |     /// @param permissions     The permission to compare the individual VMA permissions against, | ||||||
|  |     ///                        which is done in the form of: | ||||||
|  |     ///                        (vma.permission & permission_mask) != permission. | ||||||
|  |     /// @param attribute_mask  The memory attribute mask. | ||||||
|  |     /// @param attribute       The memory attributes to compare the individual VMA attributes | ||||||
|  |     ///                        against, which is done in the form of: | ||||||
|  |     ///                        (vma.attributes & attribute_mask) != attribute. | ||||||
|  |     /// @param ignore_mask     The memory attributes to ignore during the check. | ||||||
|  |     /// | ||||||
|  |     /// @returns If successful, returns a tuple containing the memory attributes | ||||||
|  |     ///          (with ignored bits specified by ignore_mask unset), memory permissions, and | ||||||
|  |     ///          memory state across the memory range. | ||||||
|  |     /// @returns If not successful, returns ERR_INVALID_ADDRESS_STATE. | ||||||
|  |     /// | ||||||
|  |     CheckResults CheckRangeState(VAddr address, u64 size, MemoryState state_mask, MemoryState state, | ||||||
|  |                                  VMAPermission permission_mask, VMAPermission permissions, | ||||||
|  |                                  MemoryAttribute attribute_mask, MemoryAttribute attribute, | ||||||
|  |                                  MemoryAttribute ignore_mask) const; | ||||||
|  |  | ||||||
| private: | private: | ||||||
|     using VMAIter = VMAMap::iterator; |     using VMAIter = VMAMap::iterator; | ||||||
|  |  | ||||||
| @@ -707,35 +738,6 @@ private: | |||||||
|     /// Clears out the page table |     /// Clears out the page table | ||||||
|     void ClearPageTable(); |     void ClearPageTable(); | ||||||
|  |  | ||||||
|     using CheckResults = ResultVal<std::tuple<MemoryState, VMAPermission, MemoryAttribute>>; |  | ||||||
|  |  | ||||||
|     /// Checks if an address range adheres to the specified states provided. |  | ||||||
|     /// |  | ||||||
|     /// @param address         The starting address of the address range. |  | ||||||
|     /// @param size            The size of the address range. |  | ||||||
|     /// @param state_mask      The memory state mask. |  | ||||||
|     /// @param state           The state to compare the individual VMA states against, |  | ||||||
|     ///                        which is done in the form of: (vma.state & state_mask) != state. |  | ||||||
|     /// @param permission_mask The memory permissions mask. |  | ||||||
|     /// @param permissions     The permission to compare the individual VMA permissions against, |  | ||||||
|     ///                        which is done in the form of: |  | ||||||
|     ///                        (vma.permission & permission_mask) != permission. |  | ||||||
|     /// @param attribute_mask  The memory attribute mask. |  | ||||||
|     /// @param attribute       The memory attributes to compare the individual VMA attributes |  | ||||||
|     ///                        against, which is done in the form of: |  | ||||||
|     ///                        (vma.attributes & attribute_mask) != attribute. |  | ||||||
|     /// @param ignore_mask     The memory attributes to ignore during the check. |  | ||||||
|     /// |  | ||||||
|     /// @returns If successful, returns a tuple containing the memory attributes |  | ||||||
|     ///          (with ignored bits specified by ignore_mask unset), memory permissions, and |  | ||||||
|     ///          memory state across the memory range. |  | ||||||
|     /// @returns If not successful, returns ERR_INVALID_ADDRESS_STATE. |  | ||||||
|     /// |  | ||||||
|     CheckResults CheckRangeState(VAddr address, u64 size, MemoryState state_mask, MemoryState state, |  | ||||||
|                                  VMAPermission permission_mask, VMAPermission permissions, |  | ||||||
|                                  MemoryAttribute attribute_mask, MemoryAttribute attribute, |  | ||||||
|                                  MemoryAttribute ignore_mask) const; |  | ||||||
|  |  | ||||||
|     /// Gets the amount of memory currently mapped (state != Unmapped) in a range. |     /// Gets the amount of memory currently mapped (state != Unmapped) in a range. | ||||||
|     ResultVal<std::size_t> SizeOfAllocatedVMAsInRange(VAddr address, std::size_t size) const; |     ResultVal<std::size_t> SizeOfAllocatedVMAsInRange(VAddr address, std::size_t size) const; | ||||||
|  |  | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user
	 bunnei
					bunnei