summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/core/hle/kernel/k_page_table.cpp17
-rw-r--r--src/core/hle/kernel/k_page_table.h3
-rw-r--r--src/core/hle/kernel/k_transfer_memory.cpp89
-rw-r--r--src/core/hle/kernel/k_transfer_memory.h14
-rw-r--r--src/core/hle/kernel/svc/svc_transfer_memory.cpp54
5 files changed, 160 insertions, 17 deletions
diff --git a/src/core/hle/kernel/k_page_table.cpp b/src/core/hle/kernel/k_page_table.cpp
index 5b51edf30..1fbfbf31f 100644
--- a/src/core/hle/kernel/k_page_table.cpp
+++ b/src/core/hle/kernel/k_page_table.cpp
@@ -2949,6 +2949,23 @@ Result KPageTable::UnlockForIpcUserBuffer(KProcessAddress address, size_t size)
2949 KMemoryAttribute::Locked, nullptr)); 2949 KMemoryAttribute::Locked, nullptr));
2950} 2950}
2951 2951
2952Result KPageTable::LockForTransferMemory(KPageGroup* out, KProcessAddress address, size_t size,
2953 KMemoryPermission perm) {
2954 R_RETURN(this->LockMemoryAndOpen(out, nullptr, address, size, KMemoryState::FlagCanTransfer,
2955 KMemoryState::FlagCanTransfer, KMemoryPermission::All,
2956 KMemoryPermission::UserReadWrite, KMemoryAttribute::All,
2957 KMemoryAttribute::None, perm, KMemoryAttribute::Locked));
2958}
2959
2960Result KPageTable::UnlockForTransferMemory(KProcessAddress address, size_t size,
2961 const KPageGroup& pg) {
2962 R_RETURN(this->UnlockMemory(address, size, KMemoryState::FlagCanTransfer,
2963 KMemoryState::FlagCanTransfer, KMemoryPermission::None,
2964 KMemoryPermission::None, KMemoryAttribute::All,
2965 KMemoryAttribute::Locked, KMemoryPermission::UserReadWrite,
2966 KMemoryAttribute::Locked, std::addressof(pg)));
2967}
2968
2952Result KPageTable::LockForCodeMemory(KPageGroup* out, KProcessAddress addr, size_t size) { 2969Result KPageTable::LockForCodeMemory(KPageGroup* out, KProcessAddress addr, size_t size) {
2953 R_RETURN(this->LockMemoryAndOpen( 2970 R_RETURN(this->LockMemoryAndOpen(
2954 out, nullptr, addr, size, KMemoryState::FlagCanCodeMemory, KMemoryState::FlagCanCodeMemory, 2971 out, nullptr, addr, size, KMemoryState::FlagCanCodeMemory, KMemoryState::FlagCanCodeMemory,
diff --git a/src/core/hle/kernel/k_page_table.h b/src/core/hle/kernel/k_page_table.h
index b9e8c6042..7da675f27 100644
--- a/src/core/hle/kernel/k_page_table.h
+++ b/src/core/hle/kernel/k_page_table.h
@@ -104,6 +104,9 @@ public:
104 Result CleanupForIpcServer(KProcessAddress address, size_t size, KMemoryState dst_state); 104 Result CleanupForIpcServer(KProcessAddress address, size_t size, KMemoryState dst_state);
105 Result CleanupForIpcClient(KProcessAddress address, size_t size, KMemoryState dst_state); 105 Result CleanupForIpcClient(KProcessAddress address, size_t size, KMemoryState dst_state);
106 106
107 Result LockForTransferMemory(KPageGroup* out, KProcessAddress address, size_t size,
108 KMemoryPermission perm);
109 Result UnlockForTransferMemory(KProcessAddress address, size_t size, const KPageGroup& pg);
107 Result LockForCodeMemory(KPageGroup* out, KProcessAddress addr, size_t size); 110 Result LockForCodeMemory(KPageGroup* out, KProcessAddress addr, size_t size);
108 Result UnlockForCodeMemory(KProcessAddress addr, size_t size, const KPageGroup& pg); 111 Result UnlockForCodeMemory(KProcessAddress addr, size_t size, const KPageGroup& pg);
109 Result MakeAndOpenPageGroup(KPageGroup* out, KProcessAddress address, size_t num_pages, 112 Result MakeAndOpenPageGroup(KPageGroup* out, KProcessAddress address, size_t num_pages,
diff --git a/src/core/hle/kernel/k_transfer_memory.cpp b/src/core/hle/kernel/k_transfer_memory.cpp
index 13d34125c..0e2e11743 100644
--- a/src/core/hle/kernel/k_transfer_memory.cpp
+++ b/src/core/hle/kernel/k_transfer_memory.cpp
@@ -1,6 +1,7 @@
1// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project 1// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later 2// SPDX-License-Identifier: GPL-2.0-or-later
3 3
4#include "common/scope_exit.h"
4#include "core/hle/kernel/k_process.h" 5#include "core/hle/kernel/k_process.h"
5#include "core/hle/kernel/k_resource_limit.h" 6#include "core/hle/kernel/k_resource_limit.h"
6#include "core/hle/kernel/k_transfer_memory.h" 7#include "core/hle/kernel/k_transfer_memory.h"
@@ -9,28 +10,50 @@
9namespace Kernel { 10namespace Kernel {
10 11
11KTransferMemory::KTransferMemory(KernelCore& kernel) 12KTransferMemory::KTransferMemory(KernelCore& kernel)
12 : KAutoObjectWithSlabHeapAndContainer{kernel} {} 13 : KAutoObjectWithSlabHeapAndContainer{kernel}, m_lock{kernel} {}
13 14
14KTransferMemory::~KTransferMemory() = default; 15KTransferMemory::~KTransferMemory() = default;
15 16
16Result KTransferMemory::Initialize(KProcessAddress address, std::size_t size, 17Result KTransferMemory::Initialize(KProcessAddress addr, std::size_t size,
17 Svc::MemoryPermission owner_perm) { 18 Svc::MemoryPermission own_perm) {
18 // Set members. 19 // Set members.
19 m_owner = GetCurrentProcessPointer(m_kernel); 20 m_owner = GetCurrentProcessPointer(m_kernel);
20 21
21 // TODO(bunnei): Lock for transfer memory 22 // Get the owner page table.
23 auto& page_table = m_owner->GetPageTable();
24
25 // Construct the page group, guarding to make sure our state is valid on exit.
26 m_page_group.emplace(m_kernel, page_table.GetBlockInfoManager());
27 auto pg_guard = SCOPE_GUARD({ m_page_group.reset(); });
28
29 // Lock the memory.
30 R_TRY(page_table.LockForTransferMemory(std::addressof(*m_page_group), addr, size,
31 ConvertToKMemoryPermission(own_perm)));
22 32
23 // Set remaining tracking members. 33 // Set remaining tracking members.
24 m_owner->Open(); 34 m_owner->Open();
25 m_owner_perm = owner_perm; 35 m_owner_perm = own_perm;
26 m_address = address; 36 m_address = addr;
27 m_size = size;
28 m_is_initialized = true; 37 m_is_initialized = true;
38 m_is_mapped = false;
29 39
40 // We succeeded.
41 pg_guard.Cancel();
30 R_SUCCEED(); 42 R_SUCCEED();
31} 43}
32 44
33void KTransferMemory::Finalize() {} 45void KTransferMemory::Finalize() {
46 // Unlock.
47 if (!m_is_mapped) {
48 const size_t size = m_page_group->GetNumPages() * PageSize;
49 ASSERT(R_SUCCEEDED(
50 m_owner->GetPageTable().UnlockForTransferMemory(m_address, size, *m_page_group)));
51 }
52
53 // Close the page group.
54 m_page_group->Close();
55 m_page_group->Finalize();
56}
34 57
35void KTransferMemory::PostDestroy(uintptr_t arg) { 58void KTransferMemory::PostDestroy(uintptr_t arg) {
36 KProcess* owner = reinterpret_cast<KProcess*>(arg); 59 KProcess* owner = reinterpret_cast<KProcess*>(arg);
@@ -38,4 +61,54 @@ void KTransferMemory::PostDestroy(uintptr_t arg) {
38 owner->Close(); 61 owner->Close();
39} 62}
40 63
64Result KTransferMemory::Map(KProcessAddress address, size_t size, Svc::MemoryPermission map_perm) {
65 // Validate the size.
66 R_UNLESS(m_page_group->GetNumPages() == Common::DivideUp(size, PageSize), ResultInvalidSize);
67
68 // Validate the permission.
69 R_UNLESS(m_owner_perm == map_perm, ResultInvalidState);
70
71 // Lock ourselves.
72 KScopedLightLock lk(m_lock);
73
74 // Ensure we're not already mapped.
75 R_UNLESS(!m_is_mapped, ResultInvalidState);
76
77 // Map the memory.
78 const KMemoryState state = (m_owner_perm == Svc::MemoryPermission::None)
79 ? KMemoryState::Transfered
80 : KMemoryState::SharedTransfered;
81 R_TRY(GetCurrentProcess(m_kernel).GetPageTable().MapPageGroup(
82 address, *m_page_group, state, KMemoryPermission::UserReadWrite));
83
84 // Mark ourselves as mapped.
85 m_is_mapped = true;
86
87 R_SUCCEED();
88}
89
90Result KTransferMemory::Unmap(KProcessAddress address, size_t size) {
91 // Validate the size.
92 R_UNLESS(m_page_group->GetNumPages() == Common::DivideUp(size, PageSize), ResultInvalidSize);
93
94 // Lock ourselves.
95 KScopedLightLock lk(m_lock);
96
97 // Unmap the memory.
98 const KMemoryState state = (m_owner_perm == Svc::MemoryPermission::None)
99 ? KMemoryState::Transfered
100 : KMemoryState::SharedTransfered;
101 R_TRY(GetCurrentProcess(m_kernel).GetPageTable().UnmapPageGroup(address, *m_page_group, state));
102
103 // Mark ourselves as unmapped.
104 ASSERT(m_is_mapped);
105 m_is_mapped = false;
106
107 R_SUCCEED();
108}
109
110size_t KTransferMemory::GetSize() const {
111 return m_is_initialized ? m_page_group->GetNumPages() * PageSize : 0;
112}
113
41} // namespace Kernel 114} // namespace Kernel
diff --git a/src/core/hle/kernel/k_transfer_memory.h b/src/core/hle/kernel/k_transfer_memory.h
index 54f97ccb4..8a0b08761 100644
--- a/src/core/hle/kernel/k_transfer_memory.h
+++ b/src/core/hle/kernel/k_transfer_memory.h
@@ -3,6 +3,9 @@
3 3
4#pragma once 4#pragma once
5 5
6#include <optional>
7
8#include "core/hle/kernel/k_page_group.h"
6#include "core/hle/kernel/slab_helpers.h" 9#include "core/hle/kernel/slab_helpers.h"
7#include "core/hle/kernel/svc_types.h" 10#include "core/hle/kernel/svc_types.h"
8#include "core/hle/result.h" 11#include "core/hle/result.h"
@@ -48,16 +51,19 @@ public:
48 return m_address; 51 return m_address;
49 } 52 }
50 53
51 size_t GetSize() const { 54 size_t GetSize() const;
52 return m_is_initialized ? m_size : 0; 55
53 } 56 Result Map(KProcessAddress address, size_t size, Svc::MemoryPermission map_perm);
57 Result Unmap(KProcessAddress address, size_t size);
54 58
55private: 59private:
60 std::optional<KPageGroup> m_page_group{};
56 KProcess* m_owner{}; 61 KProcess* m_owner{};
57 KProcessAddress m_address{}; 62 KProcessAddress m_address{};
63 KLightLock m_lock;
58 Svc::MemoryPermission m_owner_perm{}; 64 Svc::MemoryPermission m_owner_perm{};
59 size_t m_size{};
60 bool m_is_initialized{}; 65 bool m_is_initialized{};
66 bool m_is_mapped{};
61}; 67};
62 68
63} // namespace Kernel 69} // namespace Kernel
diff --git a/src/core/hle/kernel/svc/svc_transfer_memory.cpp b/src/core/hle/kernel/svc/svc_transfer_memory.cpp
index 7d94e7f09..1f97121b3 100644
--- a/src/core/hle/kernel/svc/svc_transfer_memory.cpp
+++ b/src/core/hle/kernel/svc/svc_transfer_memory.cpp
@@ -71,15 +71,59 @@ Result CreateTransferMemory(Core::System& system, Handle* out, u64 address, u64
71} 71}
72 72
73Result MapTransferMemory(Core::System& system, Handle trmem_handle, uint64_t address, uint64_t size, 73Result MapTransferMemory(Core::System& system, Handle trmem_handle, uint64_t address, uint64_t size,
74 MemoryPermission owner_perm) { 74 MemoryPermission map_perm) {
75 UNIMPLEMENTED(); 75 // Validate the address/size.
76 R_THROW(ResultNotImplemented); 76 R_UNLESS(Common::IsAligned(address, PageSize), ResultInvalidAddress);
77 R_UNLESS(Common::IsAligned(size, PageSize), ResultInvalidSize);
78 R_UNLESS(size > 0, ResultInvalidSize);
79 R_UNLESS((address < address + size), ResultInvalidCurrentMemory);
80
81 // Validate the permission.
82 R_UNLESS(IsValidTransferMemoryPermission(map_perm), ResultInvalidState);
83
84 // Get the transfer memory.
85 KScopedAutoObject trmem = GetCurrentProcess(system.Kernel())
86 .GetHandleTable()
87 .GetObject<KTransferMemory>(trmem_handle);
88 R_UNLESS(trmem.IsNotNull(), ResultInvalidHandle);
89
90 // Verify that the mapping is in range.
91 R_UNLESS(GetCurrentProcess(system.Kernel())
92 .GetPageTable()
93 .CanContain(address, size, KMemoryState::Transfered),
94 ResultInvalidMemoryRegion);
95
96 // Map the transfer memory.
97 R_TRY(trmem->Map(address, size, map_perm));
98
99 // We succeeded.
100 R_SUCCEED();
77} 101}
78 102
79Result UnmapTransferMemory(Core::System& system, Handle trmem_handle, uint64_t address, 103Result UnmapTransferMemory(Core::System& system, Handle trmem_handle, uint64_t address,
80 uint64_t size) { 104 uint64_t size) {
81 UNIMPLEMENTED(); 105 // Validate the address/size.
82 R_THROW(ResultNotImplemented); 106 R_UNLESS(Common::IsAligned(address, PageSize), ResultInvalidAddress);
107 R_UNLESS(Common::IsAligned(size, PageSize), ResultInvalidSize);
108 R_UNLESS(size > 0, ResultInvalidSize);
109 R_UNLESS((address < address + size), ResultInvalidCurrentMemory);
110
111 // Get the transfer memory.
112 KScopedAutoObject trmem = GetCurrentProcess(system.Kernel())
113 .GetHandleTable()
114 .GetObject<KTransferMemory>(trmem_handle);
115 R_UNLESS(trmem.IsNotNull(), ResultInvalidHandle);
116
117 // Verify that the mapping is in range.
118 R_UNLESS(GetCurrentProcess(system.Kernel())
119 .GetPageTable()
120 .CanContain(address, size, KMemoryState::Transfered),
121 ResultInvalidMemoryRegion);
122
123 // Unmap the transfer memory.
124 R_TRY(trmem->Unmap(address, size));
125
126 R_SUCCEED();
83} 127}
84 128
85Result MapTransferMemory64(Core::System& system, Handle trmem_handle, uint64_t address, 129Result MapTransferMemory64(Core::System& system, Handle trmem_handle, uint64_t address,