core/hle/kernel: Split transfer memory handling out into its own class
Within the kernel, shared memory and transfer memory facilities exist as completely different kernel objects. They also have different validity checking as well. Therefore, we shouldn't be treating the two as the same kind of memory. They also differ in terms of their behavioral aspect as well. Shared memory is intended for sharing memory between processes, while transfer memory is intended to be for transferring memory to other processes. This breaks out the handling for transfer memory into its own class and treats it as its own kernel object. This is also important when we consider resource limits as well. Particularly because transfer memory is limited by the resource limit value set for it. While we currently don't handle resource limit testing against objects yet (but we do allow setting them), this will make implementing that behavior much easier in the future, as we don't need to distinguish between shared memory and transfer memory allocations in the same place.
This commit is contained in:
parent
3bfd199497
commit
cb198d7985
|
@ -140,6 +140,8 @@ add_library(core STATIC
|
||||||
hle/kernel/svc_wrap.h
|
hle/kernel/svc_wrap.h
|
||||||
hle/kernel/thread.cpp
|
hle/kernel/thread.cpp
|
||||||
hle/kernel/thread.h
|
hle/kernel/thread.h
|
||||||
|
hle/kernel/transfer_memory.cpp
|
||||||
|
hle/kernel/transfer_memory.h
|
||||||
hle/kernel/vm_manager.cpp
|
hle/kernel/vm_manager.cpp
|
||||||
hle/kernel/vm_manager.h
|
hle/kernel/vm_manager.h
|
||||||
hle/kernel/wait_object.cpp
|
hle/kernel/wait_object.cpp
|
||||||
|
|
|
@ -23,6 +23,7 @@ bool Object::IsWaitable() const {
|
||||||
case HandleType::Unknown:
|
case HandleType::Unknown:
|
||||||
case HandleType::WritableEvent:
|
case HandleType::WritableEvent:
|
||||||
case HandleType::SharedMemory:
|
case HandleType::SharedMemory:
|
||||||
|
case HandleType::TransferMemory:
|
||||||
case HandleType::AddressArbiter:
|
case HandleType::AddressArbiter:
|
||||||
case HandleType::ResourceLimit:
|
case HandleType::ResourceLimit:
|
||||||
case HandleType::ClientPort:
|
case HandleType::ClientPort:
|
||||||
|
|
|
@ -22,6 +22,7 @@ enum class HandleType : u32 {
|
||||||
WritableEvent,
|
WritableEvent,
|
||||||
ReadableEvent,
|
ReadableEvent,
|
||||||
SharedMemory,
|
SharedMemory,
|
||||||
|
TransferMemory,
|
||||||
Thread,
|
Thread,
|
||||||
Process,
|
Process,
|
||||||
AddressArbiter,
|
AddressArbiter,
|
||||||
|
|
|
@ -32,6 +32,7 @@
|
||||||
#include "core/hle/kernel/svc.h"
|
#include "core/hle/kernel/svc.h"
|
||||||
#include "core/hle/kernel/svc_wrap.h"
|
#include "core/hle/kernel/svc_wrap.h"
|
||||||
#include "core/hle/kernel/thread.h"
|
#include "core/hle/kernel/thread.h"
|
||||||
|
#include "core/hle/kernel/transfer_memory.h"
|
||||||
#include "core/hle/kernel/writable_event.h"
|
#include "core/hle/kernel/writable_event.h"
|
||||||
#include "core/hle/lock.h"
|
#include "core/hle/lock.h"
|
||||||
#include "core/hle/result.h"
|
#include "core/hle/result.h"
|
||||||
|
@ -1577,11 +1578,15 @@ static ResultCode CreateTransferMemory(Handle* handle, VAddr addr, u64 size, u32
|
||||||
}
|
}
|
||||||
|
|
||||||
auto& kernel = Core::System::GetInstance().Kernel();
|
auto& kernel = Core::System::GetInstance().Kernel();
|
||||||
auto process = kernel.CurrentProcess();
|
auto transfer_mem_handle = TransferMemory::Create(kernel, addr, size, perms);
|
||||||
auto& handle_table = process->GetHandleTable();
|
|
||||||
const auto shared_mem_handle = SharedMemory::Create(kernel, process, size, perms, perms, addr);
|
|
||||||
|
|
||||||
CASCADE_RESULT(*handle, handle_table.Create(shared_mem_handle));
|
auto& handle_table = kernel.CurrentProcess()->GetHandleTable();
|
||||||
|
const auto result = handle_table.Create(std::move(transfer_mem_handle));
|
||||||
|
if (result.Failed()) {
|
||||||
|
return result.Code();
|
||||||
|
}
|
||||||
|
|
||||||
|
*handle = *result;
|
||||||
return RESULT_SUCCESS;
|
return RESULT_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,73 @@
|
||||||
|
// Copyright 2019 yuzu emulator team
|
||||||
|
// Licensed under GPLv2 or any later version
|
||||||
|
// Refer to the license.txt file included.
|
||||||
|
|
||||||
|
#include "core/hle/kernel/errors.h"
|
||||||
|
#include "core/hle/kernel/kernel.h"
|
||||||
|
#include "core/hle/kernel/process.h"
|
||||||
|
#include "core/hle/kernel/shared_memory.h"
|
||||||
|
#include "core/hle/kernel/transfer_memory.h"
|
||||||
|
#include "core/hle/result.h"
|
||||||
|
|
||||||
|
namespace Kernel {
|
||||||
|
|
||||||
|
TransferMemory::TransferMemory(KernelCore& kernel) : Object{kernel} {}
|
||||||
|
TransferMemory::~TransferMemory() = default;
|
||||||
|
|
||||||
|
SharedPtr<TransferMemory> TransferMemory::Create(KernelCore& kernel, VAddr base_address,
|
||||||
|
size_t size, MemoryPermission permissions) {
|
||||||
|
SharedPtr<TransferMemory> transfer_memory{new TransferMemory(kernel)};
|
||||||
|
|
||||||
|
transfer_memory->base_address = base_address;
|
||||||
|
transfer_memory->memory_size = size;
|
||||||
|
transfer_memory->owner_permissions = permissions;
|
||||||
|
transfer_memory->owner_process = kernel.CurrentProcess();
|
||||||
|
|
||||||
|
return transfer_memory;
|
||||||
|
}
|
||||||
|
|
||||||
|
ResultCode TransferMemory::MapMemory(VAddr address, size_t size, MemoryPermission permissions) {
|
||||||
|
if (memory_size != size) {
|
||||||
|
return ERR_INVALID_SIZE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (owner_permissions != permissions) {
|
||||||
|
return ERR_INVALID_STATE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (is_mapped) {
|
||||||
|
return ERR_INVALID_STATE;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto map_state = owner_permissions == MemoryPermission::None
|
||||||
|
? MemoryState::TransferMemoryIsolated
|
||||||
|
: MemoryState::TransferMemory;
|
||||||
|
auto& vm_manager = owner_process->VMManager();
|
||||||
|
const auto map_result = vm_manager.MapMemoryBlock(
|
||||||
|
address, std::make_shared<std::vector<u8>>(size), 0, size, map_state);
|
||||||
|
|
||||||
|
if (map_result.Failed()) {
|
||||||
|
return map_result.Code();
|
||||||
|
}
|
||||||
|
|
||||||
|
is_mapped = true;
|
||||||
|
return RESULT_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
ResultCode TransferMemory::UnmapMemory(VAddr address, size_t size) {
|
||||||
|
if (memory_size != size) {
|
||||||
|
return ERR_INVALID_SIZE;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto& vm_manager = owner_process->VMManager();
|
||||||
|
const auto result = vm_manager.UnmapRange(address, size);
|
||||||
|
|
||||||
|
if (result.IsError()) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
is_mapped = false;
|
||||||
|
return RESULT_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace Kernel
|
|
@ -0,0 +1,91 @@
|
||||||
|
// Copyright 2019 yuzu emulator team
|
||||||
|
// Licensed under GPLv2 or any later version
|
||||||
|
// Refer to the license.txt file included.
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "core/hle/kernel/object.h"
|
||||||
|
|
||||||
|
union ResultCode;
|
||||||
|
|
||||||
|
namespace Kernel {
|
||||||
|
|
||||||
|
class KernelCore;
|
||||||
|
class Process;
|
||||||
|
|
||||||
|
enum class MemoryPermission : u32;
|
||||||
|
|
||||||
|
/// Defines the interface for transfer memory objects.
|
||||||
|
///
|
||||||
|
/// Transfer memory is typically used for the purpose of
|
||||||
|
/// transferring memory between separate process instances,
|
||||||
|
/// thus the name.
|
||||||
|
///
|
||||||
|
class TransferMemory final : public Object {
|
||||||
|
public:
|
||||||
|
static constexpr HandleType HANDLE_TYPE = HandleType::TransferMemory;
|
||||||
|
|
||||||
|
static SharedPtr<TransferMemory> Create(KernelCore& kernel, VAddr base_address, size_t size,
|
||||||
|
MemoryPermission permissions);
|
||||||
|
|
||||||
|
TransferMemory(const TransferMemory&) = delete;
|
||||||
|
TransferMemory& operator=(const TransferMemory&) = delete;
|
||||||
|
|
||||||
|
TransferMemory(TransferMemory&&) = delete;
|
||||||
|
TransferMemory& operator=(TransferMemory&&) = delete;
|
||||||
|
|
||||||
|
std::string GetTypeName() const override {
|
||||||
|
return "TransferMemory";
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string GetName() const override {
|
||||||
|
return GetTypeName();
|
||||||
|
}
|
||||||
|
|
||||||
|
HandleType GetHandleType() const override {
|
||||||
|
return HANDLE_TYPE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Attempts to map transfer memory with the given range and memory permissions.
|
||||||
|
///
|
||||||
|
/// @param address The base address to being mapping memory at.
|
||||||
|
/// @param size The size of the memory to map, in bytes.
|
||||||
|
/// @param permissions The memory permissions to check against when mapping memory.
|
||||||
|
///
|
||||||
|
/// @pre The given address, size, and memory permissions must all match
|
||||||
|
/// the same values that were given when creating the transfer memory
|
||||||
|
/// instance.
|
||||||
|
///
|
||||||
|
ResultCode MapMemory(VAddr address, size_t size, MemoryPermission permissions);
|
||||||
|
|
||||||
|
/// Unmaps the transfer memory with the given range
|
||||||
|
///
|
||||||
|
/// @param address The base address to begin unmapping memory at.
|
||||||
|
/// @param size The size of the memory to unmap, in bytes.
|
||||||
|
///
|
||||||
|
/// @pre The given address and size must be the same as the ones used
|
||||||
|
/// to create the transfer memory instance.
|
||||||
|
///
|
||||||
|
ResultCode UnmapMemory(VAddr address, size_t size);
|
||||||
|
|
||||||
|
private:
|
||||||
|
explicit TransferMemory(KernelCore& kernel);
|
||||||
|
~TransferMemory() override;
|
||||||
|
|
||||||
|
/// The base address for the memory managed by this instance.
|
||||||
|
VAddr base_address = 0;
|
||||||
|
|
||||||
|
/// Size of the memory, in bytes, that this instance manages.
|
||||||
|
size_t memory_size = 0;
|
||||||
|
|
||||||
|
/// The memory permissions that are applied to this instance.
|
||||||
|
MemoryPermission owner_permissions{};
|
||||||
|
|
||||||
|
/// The process that this transfer memory instance was created under.
|
||||||
|
Process* owner_process = nullptr;
|
||||||
|
|
||||||
|
/// Whether or not this transfer memory instance has mapped memory.
|
||||||
|
bool is_mapped = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace Kernel
|
Reference in New Issue