diff options
| author | 2020-01-30 22:39:07 -0500 | |
|---|---|---|
| committer | 2020-02-05 23:06:54 -0500 | |
| commit | ba53543da6126b5fe7b3f26e2688272cf11024a3 (patch) | |
| tree | 6056b75468249a9841a0e521d7a381efd087e0f2 /src/core/hle/kernel | |
| parent | wait_object: Make wait behavior only require one object to signal. (diff) | |
| download | yuzu-ba53543da6126b5fe7b3f26e2688272cf11024a3.tar.gz yuzu-ba53543da6126b5fe7b3f26e2688272cf11024a3.tar.xz yuzu-ba53543da6126b5fe7b3f26e2688272cf11024a3.zip | |
kernel: transfer_memory: Properly reserve and reset memory region.
Diffstat (limited to 'src/core/hle/kernel')
| -rw-r--r-- | src/core/hle/kernel/svc.cpp | 8 | ||||
| -rw-r--r-- | src/core/hle/kernel/transfer_memory.cpp | 66 | ||||
| -rw-r--r-- | src/core/hle/kernel/transfer_memory.h | 19 | ||||
| -rw-r--r-- | src/core/hle/kernel/vm_manager.cpp | 3 | ||||
| -rw-r--r-- | src/core/hle/kernel/vm_manager.h | 60 |
5 files changed, 116 insertions, 40 deletions
diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp index 1d99bf7a2..9cae5c73d 100644 --- a/src/core/hle/kernel/svc.cpp +++ b/src/core/hle/kernel/svc.cpp | |||
| @@ -1863,10 +1863,14 @@ static ResultCode CreateTransferMemory(Core::System& system, Handle* handle, VAd | |||
| 1863 | } | 1863 | } |
| 1864 | 1864 | ||
| 1865 | auto& kernel = system.Kernel(); | 1865 | auto& kernel = system.Kernel(); |
| 1866 | auto transfer_mem_handle = TransferMemory::Create(kernel, addr, size, perms); | 1866 | auto transfer_mem_handle = TransferMemory::Create(kernel, system.Memory(), addr, size, perms); |
| 1867 | |||
| 1868 | if (const auto reserve_result{transfer_mem_handle->Reserve()}; reserve_result.IsError()) { | ||
| 1869 | return reserve_result; | ||
| 1870 | } | ||
| 1867 | 1871 | ||
| 1868 | auto& handle_table = kernel.CurrentProcess()->GetHandleTable(); | 1872 | auto& handle_table = kernel.CurrentProcess()->GetHandleTable(); |
| 1869 | const auto result = handle_table.Create(std::move(transfer_mem_handle)); | 1873 | const auto result{handle_table.Create(std::move(transfer_mem_handle))}; |
| 1870 | if (result.Failed()) { | 1874 | if (result.Failed()) { |
| 1871 | return result.Code(); | 1875 | return result.Code(); |
| 1872 | } | 1876 | } |
diff --git a/src/core/hle/kernel/transfer_memory.cpp b/src/core/hle/kernel/transfer_memory.cpp index f0e73f57b..f2d3f8b49 100644 --- a/src/core/hle/kernel/transfer_memory.cpp +++ b/src/core/hle/kernel/transfer_memory.cpp | |||
| @@ -8,15 +8,23 @@ | |||
| 8 | #include "core/hle/kernel/shared_memory.h" | 8 | #include "core/hle/kernel/shared_memory.h" |
| 9 | #include "core/hle/kernel/transfer_memory.h" | 9 | #include "core/hle/kernel/transfer_memory.h" |
| 10 | #include "core/hle/result.h" | 10 | #include "core/hle/result.h" |
| 11 | #include "core/memory.h" | ||
| 11 | 12 | ||
| 12 | namespace Kernel { | 13 | namespace Kernel { |
| 13 | 14 | ||
| 14 | TransferMemory::TransferMemory(KernelCore& kernel) : Object{kernel} {} | 15 | TransferMemory::TransferMemory(KernelCore& kernel, Memory::Memory& memory) |
| 15 | TransferMemory::~TransferMemory() = default; | 16 | : Object{kernel}, memory{memory} {} |
| 16 | 17 | ||
| 17 | std::shared_ptr<TransferMemory> TransferMemory::Create(KernelCore& kernel, VAddr base_address, | 18 | TransferMemory::~TransferMemory() { |
| 18 | u64 size, MemoryPermission permissions) { | 19 | // Release memory region when transfer memory is destroyed |
| 19 | std::shared_ptr<TransferMemory> transfer_memory{std::make_shared<TransferMemory>(kernel)}; | 20 | Reset(); |
| 21 | } | ||
| 22 | |||
| 23 | std::shared_ptr<TransferMemory> TransferMemory::Create(KernelCore& kernel, Memory::Memory& memory, | ||
| 24 | VAddr base_address, u64 size, | ||
| 25 | MemoryPermission permissions) { | ||
| 26 | std::shared_ptr<TransferMemory> transfer_memory{ | ||
| 27 | std::make_shared<TransferMemory>(kernel, memory)}; | ||
| 20 | 28 | ||
| 21 | transfer_memory->base_address = base_address; | 29 | transfer_memory->base_address = base_address; |
| 22 | transfer_memory->memory_size = size; | 30 | transfer_memory->memory_size = size; |
| @@ -27,7 +35,7 @@ std::shared_ptr<TransferMemory> TransferMemory::Create(KernelCore& kernel, VAddr | |||
| 27 | } | 35 | } |
| 28 | 36 | ||
| 29 | const u8* TransferMemory::GetPointer() const { | 37 | const u8* TransferMemory::GetPointer() const { |
| 30 | return backing_block.get()->data(); | 38 | return memory.GetPointer(base_address); |
| 31 | } | 39 | } |
| 32 | 40 | ||
| 33 | u64 TransferMemory::GetSize() const { | 41 | u64 TransferMemory::GetSize() const { |
| @@ -62,6 +70,52 @@ ResultCode TransferMemory::MapMemory(VAddr address, u64 size, MemoryPermission p | |||
| 62 | return RESULT_SUCCESS; | 70 | return RESULT_SUCCESS; |
| 63 | } | 71 | } |
| 64 | 72 | ||
| 73 | ResultCode TransferMemory::Reserve() { | ||
| 74 | auto& vm_manager{owner_process->VMManager()}; | ||
| 75 | const auto check_range_result{vm_manager.CheckRangeState( | ||
| 76 | base_address, memory_size, MemoryState::FlagTransfer | MemoryState::FlagMemoryPoolAllocated, | ||
| 77 | MemoryState::FlagTransfer | MemoryState::FlagMemoryPoolAllocated, VMAPermission::All, | ||
| 78 | VMAPermission::ReadWrite, MemoryAttribute::Mask, MemoryAttribute::None, | ||
| 79 | MemoryAttribute::IpcAndDeviceMapped)}; | ||
| 80 | |||
| 81 | if (check_range_result.Failed()) { | ||
| 82 | return check_range_result.Code(); | ||
| 83 | } | ||
| 84 | |||
| 85 | auto [state_, permissions_, attribute] = *check_range_result; | ||
| 86 | |||
| 87 | if (const auto result{vm_manager.ReprotectRange( | ||
| 88 | base_address, memory_size, SharedMemory::ConvertPermissions(owner_permissions))}; | ||
| 89 | result.IsError()) { | ||
| 90 | return result; | ||
| 91 | } | ||
| 92 | |||
| 93 | return vm_manager.SetMemoryAttribute(base_address, memory_size, MemoryAttribute::Mask, | ||
| 94 | attribute | MemoryAttribute::Locked); | ||
| 95 | } | ||
| 96 | |||
| 97 | ResultCode TransferMemory::Reset() { | ||
| 98 | auto& vm_manager{owner_process->VMManager()}; | ||
| 99 | if (const auto result{vm_manager.CheckRangeState( | ||
| 100 | base_address, memory_size, | ||
| 101 | MemoryState::FlagTransfer | MemoryState::FlagMemoryPoolAllocated, | ||
| 102 | MemoryState::FlagTransfer | MemoryState::FlagMemoryPoolAllocated, VMAPermission::None, | ||
| 103 | VMAPermission::None, MemoryAttribute::Mask, MemoryAttribute::Locked, | ||
| 104 | MemoryAttribute::IpcAndDeviceMapped)}; | ||
| 105 | result.Failed()) { | ||
| 106 | return result.Code(); | ||
| 107 | } | ||
| 108 | |||
| 109 | if (const auto result{ | ||
| 110 | vm_manager.ReprotectRange(base_address, memory_size, VMAPermission::ReadWrite)}; | ||
| 111 | result.IsError()) { | ||
| 112 | return result; | ||
| 113 | } | ||
| 114 | |||
| 115 | return vm_manager.SetMemoryAttribute(base_address, memory_size, MemoryAttribute::Mask, | ||
| 116 | MemoryAttribute::None); | ||
| 117 | } | ||
| 118 | |||
| 65 | ResultCode TransferMemory::UnmapMemory(VAddr address, u64 size) { | 119 | ResultCode TransferMemory::UnmapMemory(VAddr address, u64 size) { |
| 66 | if (memory_size != size) { | 120 | if (memory_size != size) { |
| 67 | return ERR_INVALID_SIZE; | 121 | return ERR_INVALID_SIZE; |
diff --git a/src/core/hle/kernel/transfer_memory.h b/src/core/hle/kernel/transfer_memory.h index 0a6e15d18..6e388536a 100644 --- a/src/core/hle/kernel/transfer_memory.h +++ b/src/core/hle/kernel/transfer_memory.h | |||
| @@ -11,6 +11,10 @@ | |||
| 11 | 11 | ||
| 12 | union ResultCode; | 12 | union ResultCode; |
| 13 | 13 | ||
| 14 | namespace Memory { | ||
| 15 | class Memory; | ||
| 16 | } | ||
| 17 | |||
| 14 | namespace Kernel { | 18 | namespace Kernel { |
| 15 | 19 | ||
| 16 | class KernelCore; | 20 | class KernelCore; |
| @@ -26,12 +30,13 @@ enum class MemoryPermission : u32; | |||
| 26 | /// | 30 | /// |
| 27 | class TransferMemory final : public Object { | 31 | class TransferMemory final : public Object { |
| 28 | public: | 32 | public: |
| 29 | explicit TransferMemory(KernelCore& kernel); | 33 | explicit TransferMemory(KernelCore& kernel, Memory::Memory& memory); |
| 30 | ~TransferMemory() override; | 34 | ~TransferMemory() override; |
| 31 | 35 | ||
| 32 | static constexpr HandleType HANDLE_TYPE = HandleType::TransferMemory; | 36 | static constexpr HandleType HANDLE_TYPE = HandleType::TransferMemory; |
| 33 | 37 | ||
| 34 | static std::shared_ptr<TransferMemory> Create(KernelCore& kernel, VAddr base_address, u64 size, | 38 | static std::shared_ptr<TransferMemory> Create(KernelCore& kernel, Memory::Memory& memory, |
| 39 | VAddr base_address, u64 size, | ||
| 35 | MemoryPermission permissions); | 40 | MemoryPermission permissions); |
| 36 | 41 | ||
| 37 | TransferMemory(const TransferMemory&) = delete; | 42 | TransferMemory(const TransferMemory&) = delete; |
| @@ -80,6 +85,14 @@ public: | |||
| 80 | /// | 85 | /// |
| 81 | ResultCode UnmapMemory(VAddr address, u64 size); | 86 | ResultCode UnmapMemory(VAddr address, u64 size); |
| 82 | 87 | ||
| 88 | /// Reserves the region to be used for the transfer memory, called after the transfer memory is | ||
| 89 | /// created. | ||
| 90 | ResultCode Reserve(); | ||
| 91 | |||
| 92 | /// Resets the region previously used for the transfer memory, called after the transfer memory | ||
| 93 | /// is closed. | ||
| 94 | ResultCode Reset(); | ||
| 95 | |||
| 83 | private: | 96 | private: |
| 84 | /// Memory block backing this instance. | 97 | /// Memory block backing this instance. |
| 85 | std::shared_ptr<PhysicalMemory> backing_block; | 98 | std::shared_ptr<PhysicalMemory> backing_block; |
| @@ -98,6 +111,8 @@ private: | |||
| 98 | 111 | ||
| 99 | /// Whether or not this transfer memory instance has mapped memory. | 112 | /// Whether or not this transfer memory instance has mapped memory. |
| 100 | bool is_mapped = false; | 113 | bool is_mapped = false; |
| 114 | |||
| 115 | Memory::Memory& memory; | ||
| 101 | }; | 116 | }; |
| 102 | 117 | ||
| 103 | } // namespace Kernel | 118 | } // namespace Kernel |
diff --git a/src/core/hle/kernel/vm_manager.cpp b/src/core/hle/kernel/vm_manager.cpp index 0b3500fce..024c22901 100644 --- a/src/core/hle/kernel/vm_manager.cpp +++ b/src/core/hle/kernel/vm_manager.cpp | |||
| @@ -544,7 +544,8 @@ MemoryInfo VMManager::QueryMemory(VAddr address) const { | |||
| 544 | 544 | ||
| 545 | ResultCode VMManager::SetMemoryAttribute(VAddr address, u64 size, MemoryAttribute mask, | 545 | ResultCode VMManager::SetMemoryAttribute(VAddr address, u64 size, MemoryAttribute mask, |
| 546 | MemoryAttribute attribute) { | 546 | MemoryAttribute attribute) { |
| 547 | constexpr auto ignore_mask = MemoryAttribute::Uncached | MemoryAttribute::DeviceMapped; | 547 | constexpr auto ignore_mask = |
| 548 | MemoryAttribute::Uncached | MemoryAttribute::DeviceMapped | MemoryAttribute::Locked; | ||
| 548 | constexpr auto attribute_mask = ~ignore_mask; | 549 | constexpr auto attribute_mask = ~ignore_mask; |
| 549 | 550 | ||
| 550 | const auto result = CheckRangeState( | 551 | const auto result = CheckRangeState( |
diff --git a/src/core/hle/kernel/vm_manager.h b/src/core/hle/kernel/vm_manager.h index 850a7ebc3..90b4b006a 100644 --- a/src/core/hle/kernel/vm_manager.h +++ b/src/core/hle/kernel/vm_manager.h | |||
| @@ -98,6 +98,8 @@ enum class MemoryAttribute : u32 { | |||
| 98 | DeviceMapped = 4, | 98 | DeviceMapped = 4, |
| 99 | /// Uncached memory | 99 | /// Uncached memory |
| 100 | Uncached = 8, | 100 | Uncached = 8, |
| 101 | |||
| 102 | IpcAndDeviceMapped = LockedForIPC | DeviceMapped, | ||
| 101 | }; | 103 | }; |
| 102 | 104 | ||
| 103 | constexpr MemoryAttribute operator|(MemoryAttribute lhs, MemoryAttribute rhs) { | 105 | constexpr MemoryAttribute operator|(MemoryAttribute lhs, MemoryAttribute rhs) { |
| @@ -654,6 +656,35 @@ public: | |||
| 654 | /// is scheduled. | 656 | /// is scheduled. |
| 655 | Common::PageTable page_table{Memory::PAGE_BITS}; | 657 | Common::PageTable page_table{Memory::PAGE_BITS}; |
| 656 | 658 | ||
| 659 | using CheckResults = ResultVal<std::tuple<MemoryState, VMAPermission, MemoryAttribute>>; | ||
| 660 | |||
| 661 | /// Checks if an address range adheres to the specified states provided. | ||
| 662 | /// | ||
| 663 | /// @param address The starting address of the address range. | ||
| 664 | /// @param size The size of the address range. | ||
| 665 | /// @param state_mask The memory state mask. | ||
| 666 | /// @param state The state to compare the individual VMA states against, | ||
| 667 | /// which is done in the form of: (vma.state & state_mask) != state. | ||
| 668 | /// @param permission_mask The memory permissions mask. | ||
| 669 | /// @param permissions The permission to compare the individual VMA permissions against, | ||
| 670 | /// which is done in the form of: | ||
| 671 | /// (vma.permission & permission_mask) != permission. | ||
| 672 | /// @param attribute_mask The memory attribute mask. | ||
| 673 | /// @param attribute The memory attributes to compare the individual VMA attributes | ||
| 674 | /// against, which is done in the form of: | ||
| 675 | /// (vma.attributes & attribute_mask) != attribute. | ||
| 676 | /// @param ignore_mask The memory attributes to ignore during the check. | ||
| 677 | /// | ||
| 678 | /// @returns If successful, returns a tuple containing the memory attributes | ||
| 679 | /// (with ignored bits specified by ignore_mask unset), memory permissions, and | ||
| 680 | /// memory state across the memory range. | ||
| 681 | /// @returns If not successful, returns ERR_INVALID_ADDRESS_STATE. | ||
| 682 | /// | ||
| 683 | CheckResults CheckRangeState(VAddr address, u64 size, MemoryState state_mask, MemoryState state, | ||
| 684 | VMAPermission permission_mask, VMAPermission permissions, | ||
| 685 | MemoryAttribute attribute_mask, MemoryAttribute attribute, | ||
| 686 | MemoryAttribute ignore_mask) const; | ||
| 687 | |||
| 657 | private: | 688 | private: |
| 658 | using VMAIter = VMAMap::iterator; | 689 | using VMAIter = VMAMap::iterator; |
| 659 | 690 | ||
| @@ -707,35 +738,6 @@ private: | |||
| 707 | /// Clears out the page table | 738 | /// Clears out the page table |
| 708 | void ClearPageTable(); | 739 | void ClearPageTable(); |
| 709 | 740 | ||
| 710 | using CheckResults = ResultVal<std::tuple<MemoryState, VMAPermission, MemoryAttribute>>; | ||
| 711 | |||
| 712 | /// Checks if an address range adheres to the specified states provided. | ||
| 713 | /// | ||
| 714 | /// @param address The starting address of the address range. | ||
| 715 | /// @param size The size of the address range. | ||
| 716 | /// @param state_mask The memory state mask. | ||
| 717 | /// @param state The state to compare the individual VMA states against, | ||
| 718 | /// which is done in the form of: (vma.state & state_mask) != state. | ||
| 719 | /// @param permission_mask The memory permissions mask. | ||
| 720 | /// @param permissions The permission to compare the individual VMA permissions against, | ||
| 721 | /// which is done in the form of: | ||
| 722 | /// (vma.permission & permission_mask) != permission. | ||
| 723 | /// @param attribute_mask The memory attribute mask. | ||
| 724 | /// @param attribute The memory attributes to compare the individual VMA attributes | ||
| 725 | /// against, which is done in the form of: | ||
| 726 | /// (vma.attributes & attribute_mask) != attribute. | ||
| 727 | /// @param ignore_mask The memory attributes to ignore during the check. | ||
| 728 | /// | ||
| 729 | /// @returns If successful, returns a tuple containing the memory attributes | ||
| 730 | /// (with ignored bits specified by ignore_mask unset), memory permissions, and | ||
| 731 | /// memory state across the memory range. | ||
| 732 | /// @returns If not successful, returns ERR_INVALID_ADDRESS_STATE. | ||
| 733 | /// | ||
| 734 | CheckResults CheckRangeState(VAddr address, u64 size, MemoryState state_mask, MemoryState state, | ||
| 735 | VMAPermission permission_mask, VMAPermission permissions, | ||
| 736 | MemoryAttribute attribute_mask, MemoryAttribute attribute, | ||
| 737 | MemoryAttribute ignore_mask) const; | ||
| 738 | |||
| 739 | /// Gets the amount of memory currently mapped (state != Unmapped) in a range. | 741 | /// Gets the amount of memory currently mapped (state != Unmapped) in a range. |
| 740 | ResultVal<std::size_t> SizeOfAllocatedVMAsInRange(VAddr address, std::size_t size) const; | 742 | ResultVal<std::size_t> SizeOfAllocatedVMAsInRange(VAddr address, std::size_t size) const; |
| 741 | 743 | ||