|
|
@@ -1,6 +1,7 @@
|
|
|
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
|
|
|
// 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_resource_limit.h"
|
|
|
#include "core/hle/kernel/k_transfer_memory.h"
|
|
|
@@ -9,28 +10,50 @@
|
|
|
namespace Kernel {
|
|
|
|
|
|
KTransferMemory::KTransferMemory(KernelCore& kernel)
|
|
|
- : KAutoObjectWithSlabHeapAndContainer{kernel} {}
|
|
|
+ : KAutoObjectWithSlabHeapAndContainer{kernel}, m_lock{kernel} {}
|
|
|
|
|
|
KTransferMemory::~KTransferMemory() = default;
|
|
|
|
|
|
-Result KTransferMemory::Initialize(KProcessAddress address, std::size_t size,
|
|
|
- Svc::MemoryPermission owner_perm) {
|
|
|
+Result KTransferMemory::Initialize(KProcessAddress addr, std::size_t size,
|
|
|
+ Svc::MemoryPermission own_perm) {
|
|
|
// Set members.
|
|
|
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.
|
|
|
m_owner->Open();
|
|
|
- m_owner_perm = owner_perm;
|
|
|
- m_address = address;
|
|
|
- m_size = size;
|
|
|
+ m_owner_perm = own_perm;
|
|
|
+ m_address = addr;
|
|
|
m_is_initialized = true;
|
|
|
+ m_is_mapped = false;
|
|
|
|
|
|
+ // We succeeded.
|
|
|
+ pg_guard.Cancel();
|
|
|
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) {
|
|
|
KProcess* owner = reinterpret_cast<KProcess*>(arg);
|
|
|
@@ -38,4 +61,54 @@ void KTransferMemory::PostDestroy(uintptr_t arg) {
|
|
|
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
|