summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/core/hle/kernel/svc.cpp8
-rw-r--r--src/core/hle/kernel/transfer_memory.cpp66
-rw-r--r--src/core/hle/kernel/transfer_memory.h19
-rw-r--r--src/core/hle/kernel/vm_manager.cpp3
-rw-r--r--src/core/hle/kernel/vm_manager.h60
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;