|
|
@ -1,6 +1,7 @@
|
|
|
|
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
|
|
|
|
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
|
|
|
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
|
|
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#include "common/scope_exit.h"
|
|
|
|
#include "core/hle/kernel/k_process.h"
|
|
|
|
#include "core/hle/kernel/k_process.h"
|
|
|
|
#include "core/hle/kernel/k_resource_limit.h"
|
|
|
|
#include "core/hle/kernel/k_resource_limit.h"
|
|
|
|
#include "core/hle/kernel/k_transfer_memory.h"
|
|
|
|
#include "core/hle/kernel/k_transfer_memory.h"
|
|
|
@ -9,28 +10,50 @@
|
|
|
|
namespace Kernel {
|
|
|
|
namespace Kernel {
|
|
|
|
|
|
|
|
|
|
|
|
KTransferMemory::KTransferMemory(KernelCore& kernel)
|
|
|
|
KTransferMemory::KTransferMemory(KernelCore& kernel)
|
|
|
|
: KAutoObjectWithSlabHeapAndContainer{kernel} {}
|
|
|
|
: KAutoObjectWithSlabHeapAndContainer{kernel}, m_lock{kernel} {}
|
|
|
|
|
|
|
|
|
|
|
|
KTransferMemory::~KTransferMemory() = default;
|
|
|
|
KTransferMemory::~KTransferMemory() = default;
|
|
|
|
|
|
|
|
|
|
|
|
Result KTransferMemory::Initialize(KProcessAddress address, std::size_t size,
|
|
|
|
Result KTransferMemory::Initialize(KProcessAddress addr, std::size_t size,
|
|
|
|
Svc::MemoryPermission owner_perm) {
|
|
|
|
Svc::MemoryPermission own_perm) {
|
|
|
|
// Set members.
|
|
|
|
// Set members.
|
|
|
|
m_owner = GetCurrentProcessPointer(m_kernel);
|
|
|
|
m_owner = GetCurrentProcessPointer(m_kernel);
|
|
|
|
|
|
|
|
|
|
|
|
// TODO(bunnei): Lock for transfer memory
|
|
|
|
// Get the owner page table.
|
|
|
|
|
|
|
|
auto& page_table = m_owner->GetPageTable();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Construct the page group, guarding to make sure our state is valid on exit.
|
|
|
|
|
|
|
|
m_page_group.emplace(m_kernel, page_table.GetBlockInfoManager());
|
|
|
|
|
|
|
|
auto pg_guard = SCOPE_GUARD({ m_page_group.reset(); });
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Lock the memory.
|
|
|
|
|
|
|
|
R_TRY(page_table.LockForTransferMemory(std::addressof(*m_page_group), addr, size,
|
|
|
|
|
|
|
|
ConvertToKMemoryPermission(own_perm)));
|
|
|
|
|
|
|
|
|
|
|
|
// Set remaining tracking members.
|
|
|
|
// Set remaining tracking members.
|
|
|
|
m_owner->Open();
|
|
|
|
m_owner->Open();
|
|
|
|
m_owner_perm = owner_perm;
|
|
|
|
m_owner_perm = own_perm;
|
|
|
|
m_address = address;
|
|
|
|
m_address = addr;
|
|
|
|
m_size = size;
|
|
|
|
|
|
|
|
m_is_initialized = true;
|
|
|
|
m_is_initialized = true;
|
|
|
|
|
|
|
|
m_is_mapped = false;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// We succeeded.
|
|
|
|
|
|
|
|
pg_guard.Cancel();
|
|
|
|
R_SUCCEED();
|
|
|
|
R_SUCCEED();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void KTransferMemory::Finalize() {}
|
|
|
|
void KTransferMemory::Finalize() {
|
|
|
|
|
|
|
|
// Unlock.
|
|
|
|
|
|
|
|
if (!m_is_mapped) {
|
|
|
|
|
|
|
|
const size_t size = m_page_group->GetNumPages() * PageSize;
|
|
|
|
|
|
|
|
ASSERT(R_SUCCEEDED(
|
|
|
|
|
|
|
|
m_owner->GetPageTable().UnlockForTransferMemory(m_address, size, *m_page_group)));
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Close the page group.
|
|
|
|
|
|
|
|
m_page_group->Close();
|
|
|
|
|
|
|
|
m_page_group->Finalize();
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void KTransferMemory::PostDestroy(uintptr_t arg) {
|
|
|
|
void KTransferMemory::PostDestroy(uintptr_t arg) {
|
|
|
|
KProcess* owner = reinterpret_cast<KProcess*>(arg);
|
|
|
|
KProcess* owner = reinterpret_cast<KProcess*>(arg);
|
|
|
@ -38,4 +61,54 @@ void KTransferMemory::PostDestroy(uintptr_t arg) {
|
|
|
|
owner->Close();
|
|
|
|
owner->Close();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Result KTransferMemory::Map(KProcessAddress address, size_t size, Svc::MemoryPermission map_perm) {
|
|
|
|
|
|
|
|
// Validate the size.
|
|
|
|
|
|
|
|
R_UNLESS(m_page_group->GetNumPages() == Common::DivideUp(size, PageSize), ResultInvalidSize);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Validate the permission.
|
|
|
|
|
|
|
|
R_UNLESS(m_owner_perm == map_perm, ResultInvalidState);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Lock ourselves.
|
|
|
|
|
|
|
|
KScopedLightLock lk(m_lock);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Ensure we're not already mapped.
|
|
|
|
|
|
|
|
R_UNLESS(!m_is_mapped, ResultInvalidState);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Map the memory.
|
|
|
|
|
|
|
|
const KMemoryState state = (m_owner_perm == Svc::MemoryPermission::None)
|
|
|
|
|
|
|
|
? KMemoryState::Transfered
|
|
|
|
|
|
|
|
: KMemoryState::SharedTransfered;
|
|
|
|
|
|
|
|
R_TRY(GetCurrentProcess(m_kernel).GetPageTable().MapPageGroup(
|
|
|
|
|
|
|
|
address, *m_page_group, state, KMemoryPermission::UserReadWrite));
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Mark ourselves as mapped.
|
|
|
|
|
|
|
|
m_is_mapped = true;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
R_SUCCEED();
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Result KTransferMemory::Unmap(KProcessAddress address, size_t size) {
|
|
|
|
|
|
|
|
// Validate the size.
|
|
|
|
|
|
|
|
R_UNLESS(m_page_group->GetNumPages() == Common::DivideUp(size, PageSize), ResultInvalidSize);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Lock ourselves.
|
|
|
|
|
|
|
|
KScopedLightLock lk(m_lock);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Unmap the memory.
|
|
|
|
|
|
|
|
const KMemoryState state = (m_owner_perm == Svc::MemoryPermission::None)
|
|
|
|
|
|
|
|
? KMemoryState::Transfered
|
|
|
|
|
|
|
|
: KMemoryState::SharedTransfered;
|
|
|
|
|
|
|
|
R_TRY(GetCurrentProcess(m_kernel).GetPageTable().UnmapPageGroup(address, *m_page_group, state));
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Mark ourselves as unmapped.
|
|
|
|
|
|
|
|
ASSERT(m_is_mapped);
|
|
|
|
|
|
|
|
m_is_mapped = false;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
R_SUCCEED();
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
size_t KTransferMemory::GetSize() const {
|
|
|
|
|
|
|
|
return m_is_initialized ? m_page_group->GetNumPages() * PageSize : 0;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
} // namespace Kernel
|
|
|
|
} // namespace Kernel
|
|
|
|