summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--README.md6
-rw-r--r--src/core/CMakeLists.txt2
-rw-r--r--src/core/hle/kernel/hle_ipc.cpp3
-rw-r--r--src/core/hle/kernel/k_auto_object.cpp9
-rw-r--r--src/core/hle/kernel/k_auto_object.h12
-rw-r--r--src/core/hle/kernel/k_process.cpp8
-rw-r--r--src/core/hle/kernel/k_server_session.cpp5
-rw-r--r--src/core/hle/kernel/kernel.cpp97
-rw-r--r--src/core/hle/kernel/kernel.h17
-rw-r--r--src/core/hle/kernel/svc.cpp6
-rw-r--r--src/core/hle/service/hid/controllers/npad.cpp13
-rw-r--r--src/core/hle/service/hid/controllers/npad.h8
-rw-r--r--src/core/hle/service/hid/hid.cpp14
-rw-r--r--src/core/hle/service/hid/hid.h13
-rw-r--r--src/core/hle/service/kernel_helpers.cpp62
-rw-r--r--src/core/hle/service/kernel_helpers.h35
-rw-r--r--src/core/hle/service/nvdrv/nvdrv.cpp11
-rw-r--r--src/core/hle/service/nvdrv/nvdrv.h3
-rw-r--r--src/core/hle/service/service.cpp11
-rw-r--r--src/core/hle/service/service.h7
-rw-r--r--src/core/hle/service/sm/sm.cpp65
-rw-r--r--src/core/hle/service/sm/sm.h14
-rw-r--r--src/video_core/buffer_cache/buffer_cache.h8
-rw-r--r--src/video_core/renderer_opengl/gl_buffer_cache.cpp2
24 files changed, 334 insertions, 97 deletions
diff --git a/README.md b/README.md
index a8821126f..2cb030aed 100644
--- a/README.md
+++ b/README.md
@@ -35,7 +35,7 @@ It is written in C++ with portability in mind, and we actively maintain builds f
35 35
36The emulator is capable of running most commercial games at full speed, provided you meet the [necessary hardware requirements](https://yuzu-emu.org/help/quickstart/#hardware-requirements). 36The emulator is capable of running most commercial games at full speed, provided you meet the [necessary hardware requirements](https://yuzu-emu.org/help/quickstart/#hardware-requirements).
37 37
38For a full list of games yuzu support, please visit our [Compatibility page](https://yuzu-emu.org/game/) 38For a full list of games yuzu support, please visit our [Compatibility page](https://yuzu-emu.org/game/)
39 39
40Check out our [website](https://yuzu-emu.org/) for the latest news on exciting features, monthly progress reports, and more! 40Check out our [website](https://yuzu-emu.org/) for the latest news on exciting features, monthly progress reports, and more!
41 41
@@ -43,7 +43,7 @@ Check out our [website](https://yuzu-emu.org/) for the latest news on exciting f
43 43
44Most of the development happens on GitHub. It's also where [our central repository](https://github.com/yuzu-emu/yuzu) is hosted. For development discussion, please join us on [Discord](https://discord.com/invite/u77vRWY). 44Most of the development happens on GitHub. It's also where [our central repository](https://github.com/yuzu-emu/yuzu) is hosted. For development discussion, please join us on [Discord](https://discord.com/invite/u77vRWY).
45 45
46If you want to contribute, please take a look at the [Contributor's Guide](https://github.com/yuzu-emu/yuzu/wiki/Contributing) and [Developer Information](https://github.com/yuzu-emu/yuzu/wiki/Developer-Information). 46If you want to contribute, please take a look at the [Contributor's Guide](https://github.com/yuzu-emu/yuzu/wiki/Contributing) and [Developer Information](https://github.com/yuzu-emu/yuzu/wiki/Developer-Information).
47You can also contact any of the developers on Discord in order to know about the current state of the emulator. 47You can also contact any of the developers on Discord in order to know about the current state of the emulator.
48 48
49If you want to contribute to the user interface translation project, please check out the [yuzu project on transifex](https://www.transifex.com/yuzu-emulator/yuzu). We centralize translation work there, and periodically upstream translations. 49If you want to contribute to the user interface translation project, please check out the [yuzu project on transifex](https://www.transifex.com/yuzu-emulator/yuzu). We centralize translation work there, and periodically upstream translations.
@@ -78,3 +78,5 @@ If you wish to support us a different way, please join our [Discord](https://dis
78## License 78## License
79 79
80yuzu is licensed under the GPLv2 (or any later version). Refer to the [license.txt](https://github.com/yuzu-emu/yuzu/blob/master/license.txt) file. 80yuzu is licensed under the GPLv2 (or any later version). Refer to the [license.txt](https://github.com/yuzu-emu/yuzu/blob/master/license.txt) file.
81
82The [Skyline-Emulator Team](https://github.com/skyline-emu/skyline) is exempt from GPLv2 for the contributions from all these contributors [FernandoS27](https://github.com/FernandoS27), [lioncash](https://github.com/lioncash), [bunnei](https://github.com/bunnei), [ReinUsesLisp](https://github.com/ReinUsesLisp), [Morph1984](https://github.com/Morph1984), [ogniK5377](https://github.com/ogniK5377), [german77](https://github.com/german77), [ameerj](https://github.com/ameerj), [Kelebek1](https://github.com/Kelebek1) and [lat9nq](https://github.com/lat9nq). They may only use the code from these contributors under Mozilla Public License, version 2.0.
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt
index c7b899131..5c99c00f5 100644
--- a/src/core/CMakeLists.txt
+++ b/src/core/CMakeLists.txt
@@ -517,6 +517,8 @@ add_library(core STATIC
517 hle/service/psc/psc.h 517 hle/service/psc/psc.h
518 hle/service/ptm/psm.cpp 518 hle/service/ptm/psm.cpp
519 hle/service/ptm/psm.h 519 hle/service/ptm/psm.h
520 hle/service/kernel_helpers.cpp
521 hle/service/kernel_helpers.h
520 hle/service/service.cpp 522 hle/service/service.cpp
521 hle/service/service.h 523 hle/service/service.h
522 hle/service/set/set.cpp 524 hle/service/set/set.cpp
diff --git a/src/core/hle/kernel/hle_ipc.cpp b/src/core/hle/kernel/hle_ipc.cpp
index 28ed6265a..ca68fc325 100644
--- a/src/core/hle/kernel/hle_ipc.cpp
+++ b/src/core/hle/kernel/hle_ipc.cpp
@@ -58,6 +58,9 @@ bool SessionRequestManager::HasSessionRequestHandler(const HLERequestContext& co
58 58
59void SessionRequestHandler::ClientConnected(KServerSession* session) { 59void SessionRequestHandler::ClientConnected(KServerSession* session) {
60 session->ClientConnected(shared_from_this()); 60 session->ClientConnected(shared_from_this());
61
62 // Ensure our server session is tracked globally.
63 kernel.RegisterServerSession(session);
61} 64}
62 65
63void SessionRequestHandler::ClientDisconnected(KServerSession* session) { 66void SessionRequestHandler::ClientDisconnected(KServerSession* session) {
diff --git a/src/core/hle/kernel/k_auto_object.cpp b/src/core/hle/kernel/k_auto_object.cpp
index dbe237f09..c99a9ebb7 100644
--- a/src/core/hle/kernel/k_auto_object.cpp
+++ b/src/core/hle/kernel/k_auto_object.cpp
@@ -3,6 +3,7 @@
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include "core/hle/kernel/k_auto_object.h" 5#include "core/hle/kernel/k_auto_object.h"
6#include "core/hle/kernel/kernel.h"
6 7
7namespace Kernel { 8namespace Kernel {
8 9
@@ -11,4 +12,12 @@ KAutoObject* KAutoObject::Create(KAutoObject* obj) {
11 return obj; 12 return obj;
12} 13}
13 14
15void KAutoObject::RegisterWithKernel() {
16 kernel.RegisterKernelObject(this);
17}
18
19void KAutoObject::UnregisterWithKernel() {
20 kernel.UnregisterKernelObject(this);
21}
22
14} // namespace Kernel 23} // namespace Kernel
diff --git a/src/core/hle/kernel/k_auto_object.h b/src/core/hle/kernel/k_auto_object.h
index 88a052f65..e4fcdbc67 100644
--- a/src/core/hle/kernel/k_auto_object.h
+++ b/src/core/hle/kernel/k_auto_object.h
@@ -85,8 +85,12 @@ private:
85 KERNEL_AUTOOBJECT_TRAITS(KAutoObject, KAutoObject); 85 KERNEL_AUTOOBJECT_TRAITS(KAutoObject, KAutoObject);
86 86
87public: 87public:
88 explicit KAutoObject(KernelCore& kernel_) : kernel(kernel_) {} 88 explicit KAutoObject(KernelCore& kernel_) : kernel(kernel_) {
89 virtual ~KAutoObject() = default; 89 RegisterWithKernel();
90 }
91 virtual ~KAutoObject() {
92 UnregisterWithKernel();
93 }
90 94
91 static KAutoObject* Create(KAutoObject* ptr); 95 static KAutoObject* Create(KAutoObject* ptr);
92 96
@@ -166,6 +170,10 @@ public:
166 } 170 }
167 } 171 }
168 172
173private:
174 void RegisterWithKernel();
175 void UnregisterWithKernel();
176
169protected: 177protected:
170 KernelCore& kernel; 178 KernelCore& kernel;
171 std::string name; 179 std::string name;
diff --git a/src/core/hle/kernel/k_process.cpp b/src/core/hle/kernel/k_process.cpp
index d1bd98051..8ead1a769 100644
--- a/src/core/hle/kernel/k_process.cpp
+++ b/src/core/hle/kernel/k_process.cpp
@@ -10,6 +10,7 @@
10#include "common/alignment.h" 10#include "common/alignment.h"
11#include "common/assert.h" 11#include "common/assert.h"
12#include "common/logging/log.h" 12#include "common/logging/log.h"
13#include "common/scope_exit.h"
13#include "common/settings.h" 14#include "common/settings.h"
14#include "core/core.h" 15#include "core/core.h"
15#include "core/device_memory.h" 16#include "core/device_memory.h"
@@ -43,6 +44,8 @@ void SetupMainThread(Core::System& system, KProcess& owner_process, u32 priority
43 ASSERT(owner_process.GetResourceLimit()->Reserve(LimitableResource::Threads, 1)); 44 ASSERT(owner_process.GetResourceLimit()->Reserve(LimitableResource::Threads, 1));
44 45
45 KThread* thread = KThread::Create(system.Kernel()); 46 KThread* thread = KThread::Create(system.Kernel());
47 SCOPE_EXIT({ thread->Close(); });
48
46 ASSERT(KThread::InitializeUserThread(system, thread, entry_point, 0, stack_top, priority, 49 ASSERT(KThread::InitializeUserThread(system, thread, entry_point, 0, stack_top, priority,
47 owner_process.GetIdealCoreId(), &owner_process) 50 owner_process.GetIdealCoreId(), &owner_process)
48 .IsSuccess()); 51 .IsSuccess());
@@ -162,7 +165,7 @@ void KProcess::DecrementThreadCount() {
162 ASSERT(num_threads > 0); 165 ASSERT(num_threads > 0);
163 166
164 if (const auto count = --num_threads; count == 0) { 167 if (const auto count = --num_threads; count == 0) {
165 UNIMPLEMENTED_MSG("Process termination is not implemented!"); 168 LOG_WARNING(Kernel, "Process termination is not fully implemented.");
166 } 169 }
167} 170}
168 171
@@ -406,6 +409,9 @@ void KProcess::Finalize() {
406 resource_limit->Close(); 409 resource_limit->Close();
407 } 410 }
408 411
412 // Finalize the handle table and close any open handles.
413 handle_table.Finalize();
414
409 // Perform inherited finalization. 415 // Perform inherited finalization.
410 KAutoObjectWithSlabHeapAndContainer<KProcess, KSynchronizationObject>::Finalize(); 416 KAutoObjectWithSlabHeapAndContainer<KProcess, KSynchronizationObject>::Finalize();
411} 417}
diff --git a/src/core/hle/kernel/k_server_session.cpp b/src/core/hle/kernel/k_server_session.cpp
index 5c3c13ce6..b9f24475c 100644
--- a/src/core/hle/kernel/k_server_session.cpp
+++ b/src/core/hle/kernel/k_server_session.cpp
@@ -28,7 +28,10 @@ namespace Kernel {
28 28
29KServerSession::KServerSession(KernelCore& kernel_) : KSynchronizationObject{kernel_} {} 29KServerSession::KServerSession(KernelCore& kernel_) : KSynchronizationObject{kernel_} {}
30 30
31KServerSession::~KServerSession() {} 31KServerSession::~KServerSession() {
32 // Ensure that the global list tracking server sessions does not hold on to a reference.
33 kernel.UnregisterServerSession(this);
34}
32 35
33void KServerSession::Initialize(KSession* parent_session_, std::string&& name_, 36void KServerSession::Initialize(KSession* parent_session_, std::string&& name_,
34 std::shared_ptr<SessionRequestManager> manager_) { 37 std::shared_ptr<SessionRequestManager> manager_) {
diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp
index 64bd0c494..92fbc5532 100644
--- a/src/core/hle/kernel/kernel.cpp
+++ b/src/core/hle/kernel/kernel.cpp
@@ -61,6 +61,7 @@ struct KernelCore::Impl {
61 void Initialize(KernelCore& kernel) { 61 void Initialize(KernelCore& kernel) {
62 global_scheduler_context = std::make_unique<Kernel::GlobalSchedulerContext>(kernel); 62 global_scheduler_context = std::make_unique<Kernel::GlobalSchedulerContext>(kernel);
63 global_handle_table = std::make_unique<Kernel::KHandleTable>(kernel); 63 global_handle_table = std::make_unique<Kernel::KHandleTable>(kernel);
64 global_handle_table->Initialize(KHandleTable::MaxTableSize);
64 65
65 is_phantom_mode_for_singlecore = false; 66 is_phantom_mode_for_singlecore = false;
66 67
@@ -90,9 +91,39 @@ struct KernelCore::Impl {
90 } 91 }
91 92
92 void Shutdown() { 93 void Shutdown() {
94 // Shutdown all processes.
95 if (current_process) {
96 current_process->Finalize();
97 current_process->Close();
98 current_process = nullptr;
99 }
93 process_list.clear(); 100 process_list.clear();
94 101
95 // Ensures all service threads gracefully shutdown 102 // Close all open server ports.
103 std::unordered_set<KServerPort*> server_ports_;
104 {
105 std::lock_guard lk(server_ports_lock);
106 server_ports_ = server_ports;
107 server_ports.clear();
108 }
109 for (auto* server_port : server_ports_) {
110 server_port->Close();
111 }
112 // Close all open server sessions.
113 std::unordered_set<KServerSession*> server_sessions_;
114 {
115 std::lock_guard lk(server_sessions_lock);
116 server_sessions_ = server_sessions;
117 server_sessions.clear();
118 }
119 for (auto* server_session : server_sessions_) {
120 server_session->Close();
121 }
122
123 // Ensure that the object list container is finalized and properly shutdown.
124 object_list_container.Finalize();
125
126 // Ensures all service threads gracefully shutdown.
96 service_threads.clear(); 127 service_threads.clear();
97 128
98 next_object_id = 0; 129 next_object_id = 0;
@@ -111,11 +142,7 @@ struct KernelCore::Impl {
111 142
112 cores.clear(); 143 cores.clear();
113 144
114 if (current_process) { 145 global_handle_table->Finalize();
115 current_process->Close();
116 current_process = nullptr;
117 }
118
119 global_handle_table.reset(); 146 global_handle_table.reset();
120 147
121 preemption_event = nullptr; 148 preemption_event = nullptr;
@@ -142,6 +169,16 @@ struct KernelCore::Impl {
142 169
143 // Next host thead ID to use, 0-3 IDs represent core threads, >3 represent others 170 // Next host thead ID to use, 0-3 IDs represent core threads, >3 represent others
144 next_host_thread_id = Core::Hardware::NUM_CPU_CORES; 171 next_host_thread_id = Core::Hardware::NUM_CPU_CORES;
172
173 // Track kernel objects that were not freed on shutdown
174 {
175 std::lock_guard lk(registered_objects_lock);
176 if (registered_objects.size()) {
177 LOG_WARNING(Kernel, "{} kernel objects were dangling on shutdown!",
178 registered_objects.size());
179 registered_objects.clear();
180 }
181 }
145 } 182 }
146 183
147 void InitializePhysicalCores() { 184 void InitializePhysicalCores() {
@@ -630,6 +667,21 @@ struct KernelCore::Impl {
630 user_slab_heap_size); 667 user_slab_heap_size);
631 } 668 }
632 669
670 KClientPort* CreateNamedServicePort(std::string name) {
671 auto search = service_interface_factory.find(name);
672 if (search == service_interface_factory.end()) {
673 UNIMPLEMENTED();
674 return {};
675 }
676
677 KClientPort* port = &search->second(system.ServiceManager(), system);
678 {
679 std::lock_guard lk(server_ports_lock);
680 server_ports.insert(&port->GetParent()->GetServerPort());
681 }
682 return port;
683 }
684
633 std::atomic<u32> next_object_id{0}; 685 std::atomic<u32> next_object_id{0};
634 std::atomic<u64> next_kernel_process_id{KProcess::InitialKIPIDMin}; 686 std::atomic<u64> next_kernel_process_id{KProcess::InitialKIPIDMin};
635 std::atomic<u64> next_user_process_id{KProcess::ProcessIDMin}; 687 std::atomic<u64> next_user_process_id{KProcess::ProcessIDMin};
@@ -656,6 +708,12 @@ struct KernelCore::Impl {
656 /// the ConnectToPort SVC. 708 /// the ConnectToPort SVC.
657 std::unordered_map<std::string, ServiceInterfaceFactory> service_interface_factory; 709 std::unordered_map<std::string, ServiceInterfaceFactory> service_interface_factory;
658 NamedPortTable named_ports; 710 NamedPortTable named_ports;
711 std::unordered_set<KServerPort*> server_ports;
712 std::unordered_set<KServerSession*> server_sessions;
713 std::unordered_set<KAutoObject*> registered_objects;
714 std::mutex server_ports_lock;
715 std::mutex server_sessions_lock;
716 std::mutex registered_objects_lock;
659 717
660 std::unique_ptr<Core::ExclusiveMonitor> exclusive_monitor; 718 std::unique_ptr<Core::ExclusiveMonitor> exclusive_monitor;
661 std::vector<Kernel::PhysicalCore> cores; 719 std::vector<Kernel::PhysicalCore> cores;
@@ -844,12 +902,27 @@ void KernelCore::RegisterNamedService(std::string name, ServiceInterfaceFactory&
844} 902}
845 903
846KClientPort* KernelCore::CreateNamedServicePort(std::string name) { 904KClientPort* KernelCore::CreateNamedServicePort(std::string name) {
847 auto search = impl->service_interface_factory.find(name); 905 return impl->CreateNamedServicePort(std::move(name));
848 if (search == impl->service_interface_factory.end()) { 906}
849 UNIMPLEMENTED(); 907
850 return {}; 908void KernelCore::RegisterServerSession(KServerSession* server_session) {
851 } 909 std::lock_guard lk(impl->server_sessions_lock);
852 return &search->second(impl->system.ServiceManager(), impl->system); 910 impl->server_sessions.insert(server_session);
911}
912
913void KernelCore::UnregisterServerSession(KServerSession* server_session) {
914 std::lock_guard lk(impl->server_sessions_lock);
915 impl->server_sessions.erase(server_session);
916}
917
918void KernelCore::RegisterKernelObject(KAutoObject* object) {
919 std::lock_guard lk(impl->registered_objects_lock);
920 impl->registered_objects.insert(object);
921}
922
923void KernelCore::UnregisterKernelObject(KAutoObject* object) {
924 std::lock_guard lk(impl->registered_objects_lock);
925 impl->registered_objects.erase(object);
853} 926}
854 927
855bool KernelCore::IsValidNamedPort(NamedPortTable::const_iterator port) const { 928bool KernelCore::IsValidNamedPort(NamedPortTable::const_iterator port) const {
diff --git a/src/core/hle/kernel/kernel.h b/src/core/hle/kernel/kernel.h
index 2d01e1ae0..3a6db0b1c 100644
--- a/src/core/hle/kernel/kernel.h
+++ b/src/core/hle/kernel/kernel.h
@@ -45,6 +45,7 @@ class KPort;
45class KProcess; 45class KProcess;
46class KResourceLimit; 46class KResourceLimit;
47class KScheduler; 47class KScheduler;
48class KServerSession;
48class KSession; 49class KSession;
49class KSharedMemory; 50class KSharedMemory;
50class KThread; 51class KThread;
@@ -185,6 +186,22 @@ public:
185 /// Opens a port to a service previously registered with RegisterNamedService. 186 /// Opens a port to a service previously registered with RegisterNamedService.
186 KClientPort* CreateNamedServicePort(std::string name); 187 KClientPort* CreateNamedServicePort(std::string name);
187 188
189 /// Registers a server session with the gobal emulation state, to be freed on shutdown. This is
190 /// necessary because we do not emulate processes for HLE sessions.
191 void RegisterServerSession(KServerSession* server_session);
192
193 /// Unregisters a server session previously registered with RegisterServerSession when it was
194 /// destroyed during the current emulation session.
195 void UnregisterServerSession(KServerSession* server_session);
196
197 /// Registers all kernel objects with the global emulation state, this is purely for tracking
198 /// leaks after emulation has been shutdown.
199 void RegisterKernelObject(KAutoObject* object);
200
201 /// Unregisters a kernel object previously registered with RegisterKernelObject when it was
202 /// destroyed during the current emulation session.
203 void UnregisterKernelObject(KAutoObject* object);
204
188 /// Determines whether or not the given port is a valid named port. 205 /// Determines whether or not the given port is a valid named port.
189 bool IsValidNamedPort(NamedPortTable::const_iterator port) const; 206 bool IsValidNamedPort(NamedPortTable::const_iterator port) const;
190 207
diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp
index 8339e11a0..2eb532472 100644
--- a/src/core/hle/kernel/svc.cpp
+++ b/src/core/hle/kernel/svc.cpp
@@ -298,6 +298,7 @@ static ResultCode ConnectToNamedPort(Core::System& system, Handle* out, VAddr po
298 // Create a session. 298 // Create a session.
299 KClientSession* session{}; 299 KClientSession* session{};
300 R_TRY(port->CreateSession(std::addressof(session))); 300 R_TRY(port->CreateSession(std::addressof(session)));
301 port->Close();
301 302
302 // Register the session in the table, close the extra reference. 303 // Register the session in the table, close the extra reference.
303 handle_table.Register(*out, session); 304 handle_table.Register(*out, session);
@@ -1439,11 +1440,6 @@ static void ExitProcess(Core::System& system) {
1439 LOG_INFO(Kernel_SVC, "Process {} exiting", current_process->GetProcessID()); 1440 LOG_INFO(Kernel_SVC, "Process {} exiting", current_process->GetProcessID());
1440 ASSERT_MSG(current_process->GetStatus() == ProcessStatus::Running, 1441 ASSERT_MSG(current_process->GetStatus() == ProcessStatus::Running,
1441 "Process has already exited"); 1442 "Process has already exited");
1442
1443 current_process->PrepareForTermination();
1444
1445 // Kill the current thread
1446 system.Kernel().CurrentScheduler()->GetCurrentThread()->Exit();
1447} 1443}
1448 1444
1449static void ExitProcess32(Core::System& system) { 1445static void ExitProcess32(Core::System& system) {
diff --git a/src/core/hle/service/hid/controllers/npad.cpp b/src/core/hle/service/hid/controllers/npad.cpp
index 6ce1360e3..b7f551e40 100644
--- a/src/core/hle/service/hid/controllers/npad.cpp
+++ b/src/core/hle/service/hid/controllers/npad.cpp
@@ -18,6 +18,7 @@
18#include "core/hle/kernel/k_writable_event.h" 18#include "core/hle/kernel/k_writable_event.h"
19#include "core/hle/kernel/kernel.h" 19#include "core/hle/kernel/kernel.h"
20#include "core/hle/service/hid/controllers/npad.h" 20#include "core/hle/service/hid/controllers/npad.h"
21#include "core/hle/service/kernel_helpers.h"
21 22
22namespace Service::HID { 23namespace Service::HID {
23constexpr s32 HID_JOYSTICK_MAX = 0x7fff; 24constexpr s32 HID_JOYSTICK_MAX = 0x7fff;
@@ -147,7 +148,9 @@ bool Controller_NPad::IsDeviceHandleValid(const DeviceHandle& device_handle) {
147 device_handle.device_index < DeviceIndex::MaxDeviceIndex; 148 device_handle.device_index < DeviceIndex::MaxDeviceIndex;
148} 149}
149 150
150Controller_NPad::Controller_NPad(Core::System& system_) : ControllerBase{system_} { 151Controller_NPad::Controller_NPad(Core::System& system_,
152 KernelHelpers::ServiceContext& service_context_)
153 : ControllerBase{system_}, service_context{service_context_} {
151 latest_vibration_values.fill({DEFAULT_VIBRATION_VALUE, DEFAULT_VIBRATION_VALUE}); 154 latest_vibration_values.fill({DEFAULT_VIBRATION_VALUE, DEFAULT_VIBRATION_VALUE});
152} 155}
153 156
@@ -251,10 +254,9 @@ void Controller_NPad::InitNewlyAddedController(std::size_t controller_idx) {
251} 254}
252 255
253void Controller_NPad::OnInit() { 256void Controller_NPad::OnInit() {
254 auto& kernel = system.Kernel();
255 for (std::size_t i = 0; i < styleset_changed_events.size(); ++i) { 257 for (std::size_t i = 0; i < styleset_changed_events.size(); ++i) {
256 styleset_changed_events[i] = Kernel::KEvent::Create(kernel); 258 styleset_changed_events[i] =
257 styleset_changed_events[i]->Initialize(fmt::format("npad:NpadStyleSetChanged_{}", i)); 259 service_context.CreateEvent(fmt::format("npad:NpadStyleSetChanged_{}", i));
258 } 260 }
259 261
260 if (!IsControllerActivated()) { 262 if (!IsControllerActivated()) {
@@ -344,8 +346,7 @@ void Controller_NPad::OnRelease() {
344 } 346 }
345 347
346 for (std::size_t i = 0; i < styleset_changed_events.size(); ++i) { 348 for (std::size_t i = 0; i < styleset_changed_events.size(); ++i) {
347 styleset_changed_events[i]->Close(); 349 service_context.CloseEvent(styleset_changed_events[i]);
348 styleset_changed_events[i] = nullptr;
349 } 350 }
350} 351}
351 352
diff --git a/src/core/hle/service/hid/controllers/npad.h b/src/core/hle/service/hid/controllers/npad.h
index 1409d82a2..4fcc6f93a 100644
--- a/src/core/hle/service/hid/controllers/npad.h
+++ b/src/core/hle/service/hid/controllers/npad.h
@@ -20,6 +20,10 @@ class KEvent;
20class KReadableEvent; 20class KReadableEvent;
21} // namespace Kernel 21} // namespace Kernel
22 22
23namespace Service::KernelHelpers {
24class ServiceContext;
25}
26
23namespace Service::HID { 27namespace Service::HID {
24 28
25constexpr u32 NPAD_HANDHELD = 32; 29constexpr u32 NPAD_HANDHELD = 32;
@@ -27,7 +31,8 @@ constexpr u32 NPAD_UNKNOWN = 16; // TODO(ogniK): What is this?
27 31
28class Controller_NPad final : public ControllerBase { 32class Controller_NPad final : public ControllerBase {
29public: 33public:
30 explicit Controller_NPad(Core::System& system_); 34 explicit Controller_NPad(Core::System& system_,
35 KernelHelpers::ServiceContext& service_context_);
31 ~Controller_NPad() override; 36 ~Controller_NPad() override;
32 37
33 // Called when the controller is initialized 38 // Called when the controller is initialized
@@ -566,6 +571,7 @@ private:
566 std::array<std::unique_ptr<Input::MotionDevice>, Settings::NativeMotion::NUM_MOTIONS_HID>, 571 std::array<std::unique_ptr<Input::MotionDevice>, Settings::NativeMotion::NUM_MOTIONS_HID>,
567 10>; 572 10>;
568 573
574 KernelHelpers::ServiceContext& service_context;
569 std::mutex mutex; 575 std::mutex mutex;
570 ButtonArray buttons; 576 ButtonArray buttons;
571 StickArray sticks; 577 StickArray sticks;
diff --git a/src/core/hle/service/hid/hid.cpp b/src/core/hle/service/hid/hid.cpp
index d68b023d0..b8b80570d 100644
--- a/src/core/hle/service/hid/hid.cpp
+++ b/src/core/hle/service/hid/hid.cpp
@@ -46,8 +46,9 @@ constexpr auto pad_update_ns = std::chrono::nanoseconds{1000 * 1000}; //
46constexpr auto motion_update_ns = std::chrono::nanoseconds{15 * 1000 * 1000}; // (15ms, 66.666Hz) 46constexpr auto motion_update_ns = std::chrono::nanoseconds{15 * 1000 * 1000}; // (15ms, 66.666Hz)
47constexpr std::size_t SHARED_MEMORY_SIZE = 0x40000; 47constexpr std::size_t SHARED_MEMORY_SIZE = 0x40000;
48 48
49IAppletResource::IAppletResource(Core::System& system_) 49IAppletResource::IAppletResource(Core::System& system_,
50 : ServiceFramework{system_, "IAppletResource"} { 50 KernelHelpers::ServiceContext& service_context_)
51 : ServiceFramework{system_, "IAppletResource"}, service_context{service_context_} {
51 static const FunctionInfo functions[] = { 52 static const FunctionInfo functions[] = {
52 {0, &IAppletResource::GetSharedMemoryHandle, "GetSharedMemoryHandle"}, 53 {0, &IAppletResource::GetSharedMemoryHandle, "GetSharedMemoryHandle"},
53 }; 54 };
@@ -63,7 +64,7 @@ IAppletResource::IAppletResource(Core::System& system_)
63 MakeController<Controller_Stubbed>(HidController::CaptureButton); 64 MakeController<Controller_Stubbed>(HidController::CaptureButton);
64 MakeController<Controller_Stubbed>(HidController::InputDetector); 65 MakeController<Controller_Stubbed>(HidController::InputDetector);
65 MakeController<Controller_Stubbed>(HidController::UniquePad); 66 MakeController<Controller_Stubbed>(HidController::UniquePad);
66 MakeController<Controller_NPad>(HidController::NPad); 67 MakeControllerWithServiceContext<Controller_NPad>(HidController::NPad);
67 MakeController<Controller_Gesture>(HidController::Gesture); 68 MakeController<Controller_Gesture>(HidController::Gesture);
68 MakeController<Controller_ConsoleSixAxis>(HidController::ConsoleSixAxisSensor); 69 MakeController<Controller_ConsoleSixAxis>(HidController::ConsoleSixAxisSensor);
69 70
@@ -191,13 +192,14 @@ private:
191 192
192std::shared_ptr<IAppletResource> Hid::GetAppletResource() { 193std::shared_ptr<IAppletResource> Hid::GetAppletResource() {
193 if (applet_resource == nullptr) { 194 if (applet_resource == nullptr) {
194 applet_resource = std::make_shared<IAppletResource>(system); 195 applet_resource = std::make_shared<IAppletResource>(system, service_context);
195 } 196 }
196 197
197 return applet_resource; 198 return applet_resource;
198} 199}
199 200
200Hid::Hid(Core::System& system_) : ServiceFramework{system_, "hid"} { 201Hid::Hid(Core::System& system_)
202 : ServiceFramework{system_, "hid"}, service_context{system_, service_name} {
201 // clang-format off 203 // clang-format off
202 static const FunctionInfo functions[] = { 204 static const FunctionInfo functions[] = {
203 {0, &Hid::CreateAppletResource, "CreateAppletResource"}, 205 {0, &Hid::CreateAppletResource, "CreateAppletResource"},
@@ -347,7 +349,7 @@ void Hid::CreateAppletResource(Kernel::HLERequestContext& ctx) {
347 LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id); 349 LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id);
348 350
349 if (applet_resource == nullptr) { 351 if (applet_resource == nullptr) {
350 applet_resource = std::make_shared<IAppletResource>(system); 352 applet_resource = std::make_shared<IAppletResource>(system, service_context);
351 } 353 }
352 354
353 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 355 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
diff --git a/src/core/hle/service/hid/hid.h b/src/core/hle/service/hid/hid.h
index 83fc2ea1d..9c5c7f252 100644
--- a/src/core/hle/service/hid/hid.h
+++ b/src/core/hle/service/hid/hid.h
@@ -7,6 +7,7 @@
7#include <chrono> 7#include <chrono>
8 8
9#include "core/hle/service/hid/controllers/controller_base.h" 9#include "core/hle/service/hid/controllers/controller_base.h"
10#include "core/hle/service/kernel_helpers.h"
10#include "core/hle/service/service.h" 11#include "core/hle/service/service.h"
11 12
12namespace Core::Timing { 13namespace Core::Timing {
@@ -39,7 +40,8 @@ enum class HidController : std::size_t {
39 40
40class IAppletResource final : public ServiceFramework<IAppletResource> { 41class IAppletResource final : public ServiceFramework<IAppletResource> {
41public: 42public:
42 explicit IAppletResource(Core::System& system_); 43 explicit IAppletResource(Core::System& system_,
44 KernelHelpers::ServiceContext& service_context_);
43 ~IAppletResource() override; 45 ~IAppletResource() override;
44 46
45 void ActivateController(HidController controller); 47 void ActivateController(HidController controller);
@@ -60,11 +62,18 @@ private:
60 void MakeController(HidController controller) { 62 void MakeController(HidController controller) {
61 controllers[static_cast<std::size_t>(controller)] = std::make_unique<T>(system); 63 controllers[static_cast<std::size_t>(controller)] = std::make_unique<T>(system);
62 } 64 }
65 template <typename T>
66 void MakeControllerWithServiceContext(HidController controller) {
67 controllers[static_cast<std::size_t>(controller)] =
68 std::make_unique<T>(system, service_context);
69 }
63 70
64 void GetSharedMemoryHandle(Kernel::HLERequestContext& ctx); 71 void GetSharedMemoryHandle(Kernel::HLERequestContext& ctx);
65 void UpdateControllers(std::uintptr_t user_data, std::chrono::nanoseconds ns_late); 72 void UpdateControllers(std::uintptr_t user_data, std::chrono::nanoseconds ns_late);
66 void UpdateMotion(std::uintptr_t user_data, std::chrono::nanoseconds ns_late); 73 void UpdateMotion(std::uintptr_t user_data, std::chrono::nanoseconds ns_late);
67 74
75 KernelHelpers::ServiceContext& service_context;
76
68 std::shared_ptr<Core::Timing::EventType> pad_update_event; 77 std::shared_ptr<Core::Timing::EventType> pad_update_event;
69 std::shared_ptr<Core::Timing::EventType> motion_update_event; 78 std::shared_ptr<Core::Timing::EventType> motion_update_event;
70 79
@@ -176,6 +185,8 @@ private:
176 static_assert(sizeof(VibrationDeviceInfo) == 0x8, "VibrationDeviceInfo has incorrect size."); 185 static_assert(sizeof(VibrationDeviceInfo) == 0x8, "VibrationDeviceInfo has incorrect size.");
177 186
178 std::shared_ptr<IAppletResource> applet_resource; 187 std::shared_ptr<IAppletResource> applet_resource;
188
189 KernelHelpers::ServiceContext service_context;
179}; 190};
180 191
181/// Reload input devices. Used when input configuration changed 192/// Reload input devices. Used when input configuration changed
diff --git a/src/core/hle/service/kernel_helpers.cpp b/src/core/hle/service/kernel_helpers.cpp
new file mode 100644
index 000000000..62f4cdfb2
--- /dev/null
+++ b/src/core/hle/service/kernel_helpers.cpp
@@ -0,0 +1,62 @@
1// Copyright 2021 yuzu emulator team
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include "core/core.h"
6#include "core/hle/kernel/k_event.h"
7#include "core/hle/kernel/k_process.h"
8#include "core/hle/kernel/k_readable_event.h"
9#include "core/hle/kernel/k_resource_limit.h"
10#include "core/hle/kernel/k_scoped_resource_reservation.h"
11#include "core/hle/kernel/k_writable_event.h"
12#include "core/hle/service/kernel_helpers.h"
13
14namespace Service::KernelHelpers {
15
16ServiceContext::ServiceContext(Core::System& system_, std::string name_)
17 : kernel(system_.Kernel()) {
18 process = Kernel::KProcess::Create(kernel);
19 ASSERT(Kernel::KProcess::Initialize(process, system_, std::move(name_),
20 Kernel::KProcess::ProcessType::Userland)
21 .IsSuccess());
22}
23
24ServiceContext::~ServiceContext() {
25 process->Close();
26 process = nullptr;
27}
28
29Kernel::KEvent* ServiceContext::CreateEvent(std::string&& name) {
30 // Reserve a new event from the process resource limit
31 Kernel::KScopedResourceReservation event_reservation(process,
32 Kernel::LimitableResource::Events);
33 if (!event_reservation.Succeeded()) {
34 LOG_CRITICAL(Service, "Resource limit reached!");
35 return {};
36 }
37
38 // Create a new event.
39 auto* event = Kernel::KEvent::Create(kernel);
40 if (!event) {
41 LOG_CRITICAL(Service, "Unable to create event!");
42 return {};
43 }
44
45 // Initialize the event.
46 event->Initialize(std::move(name));
47
48 // Commit the thread reservation.
49 event_reservation.Commit();
50
51 // Register the event.
52 Kernel::KEvent::Register(kernel, event);
53
54 return event;
55}
56
57void ServiceContext::CloseEvent(Kernel::KEvent* event) {
58 event->GetReadableEvent().Close();
59 event->GetWritableEvent().Close();
60}
61
62} // namespace Service::KernelHelpers
diff --git a/src/core/hle/service/kernel_helpers.h b/src/core/hle/service/kernel_helpers.h
new file mode 100644
index 000000000..4f3e95f67
--- /dev/null
+++ b/src/core/hle/service/kernel_helpers.h
@@ -0,0 +1,35 @@
1// Copyright 2021 yuzu emulator team
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include <string>
8
9namespace Core {
10class System;
11}
12
13namespace Kernel {
14class KernelCore;
15class KEvent;
16class KProcess;
17} // namespace Kernel
18
19namespace Service::KernelHelpers {
20
21class ServiceContext {
22public:
23 ServiceContext(Core::System& system_, std::string name_);
24 ~ServiceContext();
25
26 Kernel::KEvent* CreateEvent(std::string&& name);
27
28 void CloseEvent(Kernel::KEvent* event);
29
30private:
31 Kernel::KernelCore& kernel;
32 Kernel::KProcess* process{};
33};
34
35} // namespace Service::KernelHelpers
diff --git a/src/core/hle/service/nvdrv/nvdrv.cpp b/src/core/hle/service/nvdrv/nvdrv.cpp
index 03992af5e..ff405099a 100644
--- a/src/core/hle/service/nvdrv/nvdrv.cpp
+++ b/src/core/hle/service/nvdrv/nvdrv.cpp
@@ -39,11 +39,11 @@ void InstallInterfaces(SM::ServiceManager& service_manager, NVFlinger::NVFlinger
39 nvflinger.SetNVDrvInstance(module_); 39 nvflinger.SetNVDrvInstance(module_);
40} 40}
41 41
42Module::Module(Core::System& system) : syncpoint_manager{system.GPU()} { 42Module::Module(Core::System& system)
43 auto& kernel = system.Kernel(); 43 : syncpoint_manager{system.GPU()}, service_context{system, "nvdrv"} {
44 for (u32 i = 0; i < MaxNvEvents; i++) { 44 for (u32 i = 0; i < MaxNvEvents; i++) {
45 events_interface.events[i].event = Kernel::KEvent::Create(kernel); 45 events_interface.events[i].event =
46 events_interface.events[i].event->Initialize(fmt::format("NVDRV::NvEvent_{}", i)); 46 service_context.CreateEvent(fmt::format("NVDRV::NvEvent_{}", i));
47 events_interface.status[i] = EventState::Free; 47 events_interface.status[i] = EventState::Free;
48 events_interface.registered[i] = false; 48 events_interface.registered[i] = false;
49 } 49 }
@@ -65,8 +65,7 @@ Module::Module(Core::System& system) : syncpoint_manager{system.GPU()} {
65 65
66Module::~Module() { 66Module::~Module() {
67 for (u32 i = 0; i < MaxNvEvents; i++) { 67 for (u32 i = 0; i < MaxNvEvents; i++) {
68 events_interface.events[i].event->Close(); 68 service_context.CloseEvent(events_interface.events[i].event);
69 events_interface.events[i].event = nullptr;
70 } 69 }
71} 70}
72 71
diff --git a/src/core/hle/service/nvdrv/nvdrv.h b/src/core/hle/service/nvdrv/nvdrv.h
index a43ceb7ae..e2a1dde5b 100644
--- a/src/core/hle/service/nvdrv/nvdrv.h
+++ b/src/core/hle/service/nvdrv/nvdrv.h
@@ -9,6 +9,7 @@
9#include <vector> 9#include <vector>
10 10
11#include "common/common_types.h" 11#include "common/common_types.h"
12#include "core/hle/service/kernel_helpers.h"
12#include "core/hle/service/nvdrv/nvdata.h" 13#include "core/hle/service/nvdrv/nvdata.h"
13#include "core/hle/service/nvdrv/syncpoint_manager.h" 14#include "core/hle/service/nvdrv/syncpoint_manager.h"
14#include "core/hle/service/service.h" 15#include "core/hle/service/service.h"
@@ -154,6 +155,8 @@ private:
154 std::unordered_map<std::string, std::shared_ptr<Devices::nvdevice>> devices; 155 std::unordered_map<std::string, std::shared_ptr<Devices::nvdevice>> devices;
155 156
156 EventInterface events_interface; 157 EventInterface events_interface;
158
159 KernelHelpers::ServiceContext service_context;
157}; 160};
158 161
159/// Registers all NVDRV services with the specified service manager. 162/// Registers all NVDRV services with the specified service manager.
diff --git a/src/core/hle/service/service.cpp b/src/core/hle/service/service.cpp
index e6fba88b2..b3e50433b 100644
--- a/src/core/hle/service/service.cpp
+++ b/src/core/hle/service/service.cpp
@@ -104,23 +104,22 @@ ServiceFrameworkBase::~ServiceFrameworkBase() {
104void ServiceFrameworkBase::InstallAsService(SM::ServiceManager& service_manager) { 104void ServiceFrameworkBase::InstallAsService(SM::ServiceManager& service_manager) {
105 const auto guard = LockService(); 105 const auto guard = LockService();
106 106
107 ASSERT(!port_installed); 107 ASSERT(!service_registered);
108 108
109 auto port = service_manager.RegisterService(service_name, max_sessions).Unwrap(); 109 service_manager.RegisterService(service_name, max_sessions, shared_from_this());
110 port->SetSessionHandler(shared_from_this()); 110 service_registered = true;
111 port_installed = true;
112} 111}
113 112
114Kernel::KClientPort& ServiceFrameworkBase::CreatePort() { 113Kernel::KClientPort& ServiceFrameworkBase::CreatePort() {
115 const auto guard = LockService(); 114 const auto guard = LockService();
116 115
117 ASSERT(!port_installed); 116 ASSERT(!service_registered);
118 117
119 auto* port = Kernel::KPort::Create(kernel); 118 auto* port = Kernel::KPort::Create(kernel);
120 port->Initialize(max_sessions, false, service_name); 119 port->Initialize(max_sessions, false, service_name);
121 port->GetServerPort().SetSessionHandler(shared_from_this()); 120 port->GetServerPort().SetSessionHandler(shared_from_this());
122 121
123 port_installed = true; 122 service_registered = true;
124 123
125 return port->GetClientPort(); 124 return port->GetClientPort();
126} 125}
diff --git a/src/core/hle/service/service.h b/src/core/hle/service/service.h
index e078ac176..c9d6b879d 100644
--- a/src/core/hle/service/service.h
+++ b/src/core/hle/service/service.h
@@ -96,6 +96,9 @@ protected:
96 /// System context that the service operates under. 96 /// System context that the service operates under.
97 Core::System& system; 97 Core::System& system;
98 98
99 /// Identifier string used to connect to the service.
100 std::string service_name;
101
99private: 102private:
100 template <typename T> 103 template <typename T>
101 friend class ServiceFramework; 104 friend class ServiceFramework;
@@ -117,14 +120,12 @@ private:
117 void RegisterHandlersBaseTipc(const FunctionInfoBase* functions, std::size_t n); 120 void RegisterHandlersBaseTipc(const FunctionInfoBase* functions, std::size_t n);
118 void ReportUnimplementedFunction(Kernel::HLERequestContext& ctx, const FunctionInfoBase* info); 121 void ReportUnimplementedFunction(Kernel::HLERequestContext& ctx, const FunctionInfoBase* info);
119 122
120 /// Identifier string used to connect to the service.
121 std::string service_name;
122 /// Maximum number of concurrent sessions that this service can handle. 123 /// Maximum number of concurrent sessions that this service can handle.
123 u32 max_sessions; 124 u32 max_sessions;
124 125
125 /// Flag to store if a port was already create/installed to detect multiple install attempts, 126 /// Flag to store if a port was already create/installed to detect multiple install attempts,
126 /// which is not supported. 127 /// which is not supported.
127 bool port_installed = false; 128 bool service_registered = false;
128 129
129 /// Function used to safely up-cast pointers to the derived class before invoking a handler. 130 /// Function used to safely up-cast pointers to the derived class before invoking a handler.
130 InvokerFn* handler_invoker; 131 InvokerFn* handler_invoker;
diff --git a/src/core/hle/service/sm/sm.cpp b/src/core/hle/service/sm/sm.cpp
index 15034abed..ae4dc4a75 100644
--- a/src/core/hle/service/sm/sm.cpp
+++ b/src/core/hle/service/sm/sm.cpp
@@ -4,6 +4,7 @@
4 4
5#include <tuple> 5#include <tuple>
6#include "common/assert.h" 6#include "common/assert.h"
7#include "common/scope_exit.h"
7#include "core/core.h" 8#include "core/core.h"
8#include "core/hle/ipc_helpers.h" 9#include "core/hle/ipc_helpers.h"
9#include "core/hle/kernel/k_client_port.h" 10#include "core/hle/kernel/k_client_port.h"
@@ -40,17 +41,13 @@ static ResultCode ValidateServiceName(const std::string& name) {
40} 41}
41 42
42Kernel::KClientPort& ServiceManager::InterfaceFactory(ServiceManager& self, Core::System& system) { 43Kernel::KClientPort& ServiceManager::InterfaceFactory(ServiceManager& self, Core::System& system) {
43 ASSERT(self.sm_interface.expired()); 44 self.sm_interface = std::make_shared<SM>(self, system);
44
45 auto sm = std::make_shared<SM>(self, system);
46 self.sm_interface = sm;
47 self.controller_interface = std::make_unique<Controller>(system); 45 self.controller_interface = std::make_unique<Controller>(system);
48 46 return self.sm_interface->CreatePort();
49 return sm->CreatePort();
50} 47}
51 48
52ResultVal<Kernel::KServerPort*> ServiceManager::RegisterService(std::string name, 49ResultCode ServiceManager::RegisterService(std::string name, u32 max_sessions,
53 u32 max_sessions) { 50 Kernel::SessionRequestHandlerPtr handler) {
54 51
55 CASCADE_CODE(ValidateServiceName(name)); 52 CASCADE_CODE(ValidateServiceName(name));
56 53
@@ -59,12 +56,9 @@ ResultVal<Kernel::KServerPort*> ServiceManager::RegisterService(std::string name
59 return ERR_ALREADY_REGISTERED; 56 return ERR_ALREADY_REGISTERED;
60 } 57 }
61 58
62 auto* port = Kernel::KPort::Create(kernel); 59 registered_services.emplace(std::move(name), handler);
63 port->Initialize(max_sessions, false, name);
64 60
65 registered_services.emplace(std::move(name), port); 61 return ResultSuccess;
66
67 return MakeResult(&port->GetServerPort());
68} 62}
69 63
70ResultCode ServiceManager::UnregisterService(const std::string& name) { 64ResultCode ServiceManager::UnregisterService(const std::string& name) {
@@ -76,14 +70,11 @@ ResultCode ServiceManager::UnregisterService(const std::string& name) {
76 return ERR_SERVICE_NOT_REGISTERED; 70 return ERR_SERVICE_NOT_REGISTERED;
77 } 71 }
78 72
79 iter->second->Close();
80
81 registered_services.erase(iter); 73 registered_services.erase(iter);
82 return ResultSuccess; 74 return ResultSuccess;
83} 75}
84 76
85ResultVal<Kernel::KPort*> ServiceManager::GetServicePort(const std::string& name) { 77ResultVal<Kernel::KPort*> ServiceManager::GetServicePort(const std::string& name) {
86
87 CASCADE_CODE(ValidateServiceName(name)); 78 CASCADE_CODE(ValidateServiceName(name));
88 auto it = registered_services.find(name); 79 auto it = registered_services.find(name);
89 if (it == registered_services.end()) { 80 if (it == registered_services.end()) {
@@ -91,10 +82,13 @@ ResultVal<Kernel::KPort*> ServiceManager::GetServicePort(const std::string& name
91 return ERR_SERVICE_NOT_REGISTERED; 82 return ERR_SERVICE_NOT_REGISTERED;
92 } 83 }
93 84
94 return MakeResult(it->second); 85 auto* port = Kernel::KPort::Create(kernel);
95} 86 port->Initialize(ServerSessionCountMax, false, name);
87 auto handler = it->second;
88 port->GetServerPort().SetSessionHandler(std::move(handler));
96 89
97SM::~SM() = default; 90 return MakeResult(port);
91}
98 92
99/** 93/**
100 * SM::Initialize service function 94 * SM::Initialize service function
@@ -156,11 +150,15 @@ ResultVal<Kernel::KClientSession*> SM::GetServiceImpl(Kernel::HLERequestContext&
156 LOG_ERROR(Service_SM, "called service={} -> error 0x{:08X}", name, port_result.Code().raw); 150 LOG_ERROR(Service_SM, "called service={} -> error 0x{:08X}", name, port_result.Code().raw);
157 return port_result.Code(); 151 return port_result.Code();
158 } 152 }
159 auto& port = port_result.Unwrap()->GetClientPort(); 153 auto& port = port_result.Unwrap();
154 SCOPE_EXIT({ port->GetClientPort().Close(); });
155
156 server_ports.emplace_back(&port->GetServerPort());
160 157
161 // Create a new session. 158 // Create a new session.
162 Kernel::KClientSession* session{}; 159 Kernel::KClientSession* session{};
163 if (const auto result = port.CreateSession(std::addressof(session)); result.IsError()) { 160 if (const auto result = port->GetClientPort().CreateSession(std::addressof(session));
161 result.IsError()) {
164 LOG_ERROR(Service_SM, "called service={} -> error 0x{:08X}", name, result.raw); 162 LOG_ERROR(Service_SM, "called service={} -> error 0x{:08X}", name, result.raw);
165 return result; 163 return result;
166 } 164 }
@@ -180,20 +178,21 @@ void SM::RegisterService(Kernel::HLERequestContext& ctx) {
180 LOG_DEBUG(Service_SM, "called with name={}, max_session_count={}, is_light={}", name, 178 LOG_DEBUG(Service_SM, "called with name={}, max_session_count={}, is_light={}", name,
181 max_session_count, is_light); 179 max_session_count, is_light);
182 180
183 auto handle = service_manager.RegisterService(name, max_session_count); 181 if (const auto result = service_manager.RegisterService(name, max_session_count, nullptr);
184 if (handle.Failed()) { 182 result.IsError()) {
185 LOG_ERROR(Service_SM, "failed to register service with error_code={:08X}", 183 LOG_ERROR(Service_SM, "failed to register service with error_code={:08X}", result.raw);
186 handle.Code().raw);
187 IPC::ResponseBuilder rb{ctx, 2}; 184 IPC::ResponseBuilder rb{ctx, 2};
188 rb.Push(handle.Code()); 185 rb.Push(result);
189 return; 186 return;
190 } 187 }
191 188
192 IPC::ResponseBuilder rb{ctx, 2, 0, 1, IPC::ResponseBuilder::Flags::AlwaysMoveHandles}; 189 auto* port = Kernel::KPort::Create(kernel);
193 rb.Push(handle.Code()); 190 port->Initialize(ServerSessionCountMax, is_light, name);
191 SCOPE_EXIT({ port->GetClientPort().Close(); });
194 192
195 auto server_port = handle.Unwrap(); 193 IPC::ResponseBuilder rb{ctx, 2, 0, 1, IPC::ResponseBuilder::Flags::AlwaysMoveHandles};
196 rb.PushMoveObjects(server_port); 194 rb.Push(ResultSuccess);
195 rb.PushMoveObjects(port->GetServerPort());
197} 196}
198 197
199void SM::UnregisterService(Kernel::HLERequestContext& ctx) { 198void SM::UnregisterService(Kernel::HLERequestContext& ctx) {
@@ -225,4 +224,10 @@ SM::SM(ServiceManager& service_manager_, Core::System& system_)
225 }); 224 });
226} 225}
227 226
227SM::~SM() {
228 for (auto& server_port : server_ports) {
229 server_port->Close();
230 }
231}
232
228} // namespace Service::SM 233} // namespace Service::SM
diff --git a/src/core/hle/service/sm/sm.h b/src/core/hle/service/sm/sm.h
index ea37f11d4..068c78588 100644
--- a/src/core/hle/service/sm/sm.h
+++ b/src/core/hle/service/sm/sm.h
@@ -49,6 +49,7 @@ private:
49 ServiceManager& service_manager; 49 ServiceManager& service_manager;
50 bool is_initialized{}; 50 bool is_initialized{};
51 Kernel::KernelCore& kernel; 51 Kernel::KernelCore& kernel;
52 std::vector<Kernel::KServerPort*> server_ports;
52}; 53};
53 54
54class ServiceManager { 55class ServiceManager {
@@ -58,7 +59,8 @@ public:
58 explicit ServiceManager(Kernel::KernelCore& kernel_); 59 explicit ServiceManager(Kernel::KernelCore& kernel_);
59 ~ServiceManager(); 60 ~ServiceManager();
60 61
61 ResultVal<Kernel::KServerPort*> RegisterService(std::string name, u32 max_sessions); 62 ResultCode RegisterService(std::string name, u32 max_sessions,
63 Kernel::SessionRequestHandlerPtr handler);
62 ResultCode UnregisterService(const std::string& name); 64 ResultCode UnregisterService(const std::string& name);
63 ResultVal<Kernel::KPort*> GetServicePort(const std::string& name); 65 ResultVal<Kernel::KPort*> GetServicePort(const std::string& name);
64 66
@@ -69,21 +71,17 @@ public:
69 LOG_DEBUG(Service, "Can't find service: {}", service_name); 71 LOG_DEBUG(Service, "Can't find service: {}", service_name);
70 return nullptr; 72 return nullptr;
71 } 73 }
72 auto* port = service->second; 74 return std::static_pointer_cast<T>(service->second);
73 if (port == nullptr) {
74 return nullptr;
75 }
76 return std::static_pointer_cast<T>(port->GetServerPort().GetSessionRequestHandler());
77 } 75 }
78 76
79 void InvokeControlRequest(Kernel::HLERequestContext& context); 77 void InvokeControlRequest(Kernel::HLERequestContext& context);
80 78
81private: 79private:
82 std::weak_ptr<SM> sm_interface; 80 std::shared_ptr<SM> sm_interface;
83 std::unique_ptr<Controller> controller_interface; 81 std::unique_ptr<Controller> controller_interface;
84 82
85 /// Map of registered services, retrieved using GetServicePort. 83 /// Map of registered services, retrieved using GetServicePort.
86 std::unordered_map<std::string, Kernel::KPort*> registered_services; 84 std::unordered_map<std::string, Kernel::SessionRequestHandlerPtr> registered_services;
87 85
88 /// Kernel context 86 /// Kernel context
89 Kernel::KernelCore& kernel; 87 Kernel::KernelCore& kernel;
diff --git a/src/video_core/buffer_cache/buffer_cache.h b/src/video_core/buffer_cache/buffer_cache.h
index 7373cb62d..5a0b6f0c0 100644
--- a/src/video_core/buffer_cache/buffer_cache.h
+++ b/src/video_core/buffer_cache/buffer_cache.h
@@ -553,13 +553,9 @@ bool BufferCache<P>::DMAClear(GPUVAddr dst_address, u64 amount, u32 value) {
553 ClearDownload(subtract_interval); 553 ClearDownload(subtract_interval);
554 common_ranges.subtract(subtract_interval); 554 common_ranges.subtract(subtract_interval);
555 555
556 BufferId buffer; 556 const BufferId buffer = FindBuffer(*cpu_dst_address, static_cast<u32>(size));
557 do {
558 has_deleted_buffers = false;
559 buffer = FindBuffer(*cpu_dst_address, static_cast<u32>(size));
560 } while (has_deleted_buffers);
561 auto& dest_buffer = slot_buffers[buffer]; 557 auto& dest_buffer = slot_buffers[buffer];
562 const u32 offset = static_cast<u32>(*cpu_dst_address - dest_buffer.CpuAddr()); 558 const u32 offset = dest_buffer.Offset(*cpu_dst_address);
563 runtime.ClearBuffer(dest_buffer, offset, size, value); 559 runtime.ClearBuffer(dest_buffer, offset, size, value);
564 return true; 560 return true;
565} 561}
diff --git a/src/video_core/renderer_opengl/gl_buffer_cache.cpp b/src/video_core/renderer_opengl/gl_buffer_cache.cpp
index c4189fb60..a02a45e04 100644
--- a/src/video_core/renderer_opengl/gl_buffer_cache.cpp
+++ b/src/video_core/renderer_opengl/gl_buffer_cache.cpp
@@ -100,7 +100,7 @@ void BufferCacheRuntime::CopyBuffer(Buffer& dst_buffer, Buffer& src_buffer,
100 100
101void BufferCacheRuntime::ClearBuffer(Buffer& dest_buffer, u32 offset, size_t size, u32 value) { 101void BufferCacheRuntime::ClearBuffer(Buffer& dest_buffer, u32 offset, size_t size, u32 value) {
102 glClearNamedBufferSubData(dest_buffer.Handle(), GL_R32UI, static_cast<GLintptr>(offset), 102 glClearNamedBufferSubData(dest_buffer.Handle(), GL_R32UI, static_cast<GLintptr>(offset),
103 static_cast<GLsizeiptr>(size / sizeof(u32)), GL_RGBA, GL_UNSIGNED_INT, 103 static_cast<GLsizeiptr>(size / sizeof(u32)), GL_RED, GL_UNSIGNED_INT,
104 &value); 104 &value);
105} 105}
106 106