diff options
| author | bunnei <bunneidev@gmail.com> | 2020-01-30 22:39:07 -0500 | 
|---|---|---|
| committer | bunnei <bunneidev@gmail.com> | 2020-02-05 23:06:54 -0500 | 
| commit | ba53543da6126b5fe7b3f26e2688272cf11024a3 (patch) | |
| tree | 6056b75468249a9841a0e521d7a381efd087e0f2 | |
| parent | 7a547b934201863bc11246844ea24ab3b67be65e (diff) | |
kernel: transfer_memory: Properly reserve and reset memory region.
| -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      }      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(); -    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()) {          return result.Code();      } 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 @@  #include "core/hle/kernel/shared_memory.h"  #include "core/hle/kernel/transfer_memory.h"  #include "core/hle/result.h" +#include "core/memory.h"  namespace Kernel { -TransferMemory::TransferMemory(KernelCore& kernel) : Object{kernel} {} -TransferMemory::~TransferMemory() = default; +TransferMemory::TransferMemory(KernelCore& kernel, Memory::Memory& memory) +    : Object{kernel}, memory{memory} {} -std::shared_ptr<TransferMemory> TransferMemory::Create(KernelCore& kernel, VAddr base_address, -                                                       u64 size, MemoryPermission permissions) { -    std::shared_ptr<TransferMemory> transfer_memory{std::make_shared<TransferMemory>(kernel)}; +TransferMemory::~TransferMemory() { +    // Release memory region when transfer memory is destroyed +    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->memory_size = size; @@ -27,7 +35,7 @@ std::shared_ptr<TransferMemory> TransferMemory::Create(KernelCore& kernel, VAddr  }  const u8* TransferMemory::GetPointer() const { -    return backing_block.get()->data(); +    return memory.GetPointer(base_address);  }  u64 TransferMemory::GetSize() const { @@ -62,6 +70,52 @@ ResultCode TransferMemory::MapMemory(VAddr address, u64 size, MemoryPermission p      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) {      if (memory_size != size) {          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 @@  union ResultCode; +namespace Memory { +class Memory; +} +  namespace Kernel {  class KernelCore; @@ -26,12 +30,13 @@ enum class MemoryPermission : u32;  ///  class TransferMemory final : public Object {  public: -    explicit TransferMemory(KernelCore& kernel); +    explicit TransferMemory(KernelCore& kernel, Memory::Memory& memory);      ~TransferMemory() override;      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);      TransferMemory(const TransferMemory&) = delete; @@ -80,6 +85,14 @@ public:      ///      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:      /// Memory block backing this instance.      std::shared_ptr<PhysicalMemory> backing_block; @@ -98,6 +111,8 @@ private:      /// Whether or not this transfer memory instance has mapped memory.      bool is_mapped = false; + +    Memory::Memory& memory;  };  } // 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 {  ResultCode VMManager::SetMemoryAttribute(VAddr address, u64 size, MemoryAttribute mask,                                           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;      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 {      DeviceMapped = 4,      /// Uncached memory      Uncached = 8, + +    IpcAndDeviceMapped = LockedForIPC | DeviceMapped,  };  constexpr MemoryAttribute operator|(MemoryAttribute lhs, MemoryAttribute rhs) { @@ -654,6 +656,35 @@ public:      /// is scheduled.      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:      using VMAIter = VMAMap::iterator; @@ -707,35 +738,6 @@ private:      /// Clears out the page table      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.      ResultVal<std::size_t> SizeOfAllocatedVMAsInRange(VAddr address, std::size_t size) const; | 
