summaryrefslogtreecommitdiff
path: root/src/core/hle
diff options
context:
space:
mode:
authorGravatar Yuri Kunde Schlesner2016-12-14 20:35:33 -0800
committerGravatar GitHub2016-12-14 20:35:33 -0800
commit905fc92ce1f7d99d8819a17b180a559b3a9f15de (patch)
treecc992764c2ea065d8d30dce2055cc1efe167bc59 /src/core/hle
parentMerge pull request #2166 from endrift/clang-detect (diff)
parentFixed the codestyle to match our clang-format rules. (diff)
downloadyuzu-905fc92ce1f7d99d8819a17b180a559b3a9f15de.tar.gz
yuzu-905fc92ce1f7d99d8819a17b180a559b3a9f15de.tar.xz
yuzu-905fc92ce1f7d99d8819a17b180a559b3a9f15de.zip
Merge pull request #2249 from Subv/sessions_v3
Kernel/IPC: Use Ports and Sessions as the fundamental building block of Inter Process Communication.
Diffstat (limited to 'src/core/hle')
-rw-r--r--src/core/hle/ipc.h (renamed from src/core/hle/kernel/session.h)96
-rw-r--r--src/core/hle/kernel/client_port.cpp32
-rw-r--r--src/core/hle/kernel/client_port.h13
-rw-r--r--src/core/hle/kernel/client_session.cpp40
-rw-r--r--src/core/hle/kernel/client_session.h65
-rw-r--r--src/core/hle/kernel/kernel.h37
-rw-r--r--src/core/hle/kernel/server_port.cpp4
-rw-r--r--src/core/hle/kernel/server_port.h14
-rw-r--r--src/core/hle/kernel/server_session.cpp79
-rw-r--r--src/core/hle/kernel/server_session.h94
-rw-r--r--src/core/hle/result.h1
-rw-r--r--src/core/hle/service/apt/apt.h3
-rw-r--r--src/core/hle/service/apt/apt_a.cpp2
-rw-r--r--src/core/hle/service/apt/apt_s.cpp2
-rw-r--r--src/core/hle/service/apt/apt_u.cpp2
-rw-r--r--src/core/hle/service/fs/archive.cpp40
-rw-r--r--src/core/hle/service/fs/archive.h32
-rw-r--r--src/core/hle/service/fs/fs_user.cpp33
-rw-r--r--src/core/hle/service/service.cpp42
-rw-r--r--src/core/hle/service/service.h88
-rw-r--r--src/core/hle/service/soc_u.cpp2
-rw-r--r--src/core/hle/service/srv.cpp14
-rw-r--r--src/core/hle/svc.cpp19
23 files changed, 586 insertions, 168 deletions
diff --git a/src/core/hle/kernel/session.h b/src/core/hle/ipc.h
index ec025f732..4e094faa7 100644
--- a/src/core/hle/kernel/session.h
+++ b/src/core/hle/ipc.h
@@ -1,17 +1,31 @@
1// Copyright 2014 Citra Emulator Project 1// Copyright 2016 Citra Emulator Project
2// Licensed under GPLv2 or any later version 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#pragma once 5#pragma once
6 6
7#include <string>
8#include "common/assert.h"
9#include "common/common_types.h" 7#include "common/common_types.h"
10#include "core/hle/kernel/kernel.h"
11#include "core/hle/kernel/thread.h" 8#include "core/hle/kernel/thread.h"
12#include "core/hle/result.h"
13#include "core/memory.h" 9#include "core/memory.h"
14 10
11namespace Kernel {
12
13static const int kCommandHeaderOffset = 0x80; ///< Offset into command buffer of header
14
15/**
16 * Returns a pointer to the command buffer in the current thread's TLS
17 * TODO(Subv): This is not entirely correct, the command buffer should be copied from
18 * the thread's TLS to an intermediate buffer in kernel memory, and then copied again to
19 * the service handler process' memory.
20 * @param offset Optional offset into command buffer
21 * @return Pointer to command buffer
22 */
23inline u32* GetCommandBuffer(const int offset = 0) {
24 return (u32*)Memory::GetPointer(GetCurrentThread()->GetTLSAddress() + kCommandHeaderOffset +
25 offset);
26}
27}
28
15namespace IPC { 29namespace IPC {
16 30
17enum DescriptorType : u32 { 31enum DescriptorType : u32 {
@@ -144,75 +158,3 @@ inline DescriptorType GetDescriptorType(u32 descriptor) {
144} 158}
145 159
146} // namespace IPC 160} // namespace IPC
147
148namespace Kernel {
149
150static const int kCommandHeaderOffset = 0x80; ///< Offset into command buffer of header
151
152/**
153 * Returns a pointer to the command buffer in the current thread's TLS
154 * TODO(Subv): This is not entirely correct, the command buffer should be copied from
155 * the thread's TLS to an intermediate buffer in kernel memory, and then copied again to
156 * the service handler process' memory.
157 * @param offset Optional offset into command buffer
158 * @return Pointer to command buffer
159 */
160inline u32* GetCommandBuffer(const int offset = 0) {
161 return (u32*)Memory::GetPointer(GetCurrentThread()->GetTLSAddress() + kCommandHeaderOffset +
162 offset);
163}
164
165/**
166 * Kernel object representing the client endpoint of an IPC session. Sessions are the basic CTR-OS
167 * primitive for communication between different processes, and are used to implement service calls
168 * to the various system services.
169 *
170 * To make a service call, the client must write the command header and parameters to the buffer
171 * located at offset 0x80 of the TLS (Thread-Local Storage) area, then execute a SendSyncRequest
172 * SVC call with its Session handle. The kernel will read the command header, using it to marshall
173 * the parameters to the process at the server endpoint of the session. After the server replies to
174 * the request, the response is marshalled back to the caller's TLS buffer and control is
175 * transferred back to it.
176 *
177 * In Citra, only the client endpoint is currently implemented and only HLE calls, where the IPC
178 * request is answered by C++ code in the emulator, are supported. When SendSyncRequest is called
179 * with the session handle, this class's SyncRequest method is called, which should read the TLS
180 * buffer and emulate the call accordingly. Since the code can directly read the emulated memory,
181 * no parameter marshalling is done.
182 *
183 * In the long term, this should be turned into the full-fledged IPC mechanism implemented by
184 * CTR-OS so that IPC calls can be optionally handled by the real implementations of processes, as
185 * opposed to HLE simulations.
186 */
187class Session : public WaitObject {
188public:
189 Session();
190 ~Session() override;
191
192 std::string GetTypeName() const override {
193 return "Session";
194 }
195
196 static const HandleType HANDLE_TYPE = HandleType::Session;
197 HandleType GetHandleType() const override {
198 return HANDLE_TYPE;
199 }
200
201 /**
202 * Handles a synchronous call to this session using HLE emulation. Emulated <-> emulated calls
203 * aren't supported yet.
204 */
205 virtual ResultVal<bool> SyncRequest() = 0;
206
207 // TODO(bunnei): These functions exist to satisfy a hardware test with a Session object
208 // passed into WaitSynchronization. Figure out the meaning of them.
209
210 bool ShouldWait() override {
211 return true;
212 }
213
214 void Acquire() override {
215 ASSERT_MSG(!ShouldWait(), "object unavailable!");
216 }
217};
218}
diff --git a/src/core/hle/kernel/client_port.cpp b/src/core/hle/kernel/client_port.cpp
index aedc6f989..22645f4ec 100644
--- a/src/core/hle/kernel/client_port.cpp
+++ b/src/core/hle/kernel/client_port.cpp
@@ -4,12 +4,44 @@
4 4
5#include "common/assert.h" 5#include "common/assert.h"
6#include "core/hle/kernel/client_port.h" 6#include "core/hle/kernel/client_port.h"
7#include "core/hle/kernel/client_session.h"
7#include "core/hle/kernel/kernel.h" 8#include "core/hle/kernel/kernel.h"
8#include "core/hle/kernel/server_port.h" 9#include "core/hle/kernel/server_port.h"
10#include "core/hle/kernel/server_session.h"
9 11
10namespace Kernel { 12namespace Kernel {
11 13
12ClientPort::ClientPort() {} 14ClientPort::ClientPort() {}
13ClientPort::~ClientPort() {} 15ClientPort::~ClientPort() {}
14 16
17ResultVal<SharedPtr<ClientSession>> ClientPort::Connect() {
18 // Note: Threads do not wait for the server endpoint to call
19 // AcceptSession before returning from this call.
20
21 if (active_sessions >= max_sessions) {
22 // TODO(Subv): Return an error code in this situation after session disconnection is
23 // implemented.
24 /*return ResultCode(ErrorDescription::MaxConnectionsReached,
25 ErrorModule::OS, ErrorSummary::WouldBlock,
26 ErrorLevel::Temporary);*/
27 }
28 active_sessions++;
29
30 // Create a new session pair, let the created sessions inherit the parent port's HLE handler.
31 auto sessions =
32 ServerSession::CreateSessionPair(server_port->GetName(), server_port->hle_handler);
33 auto client_session = std::get<SharedPtr<ClientSession>>(sessions);
34 auto server_session = std::get<SharedPtr<ServerSession>>(sessions);
35
36 if (server_port->hle_handler)
37 server_port->hle_handler->ClientConnected(server_session);
38
39 server_port->pending_sessions.push_back(std::move(server_session));
40
41 // Wake the threads waiting on the ServerPort
42 server_port->WakeupAllWaitingThreads();
43
44 return MakeResult<SharedPtr<ClientSession>>(std::move(client_session));
45}
46
15} // namespace 47} // namespace
diff --git a/src/core/hle/kernel/client_port.h b/src/core/hle/kernel/client_port.h
index d28147718..511490c7c 100644
--- a/src/core/hle/kernel/client_port.h
+++ b/src/core/hle/kernel/client_port.h
@@ -11,8 +11,9 @@
11namespace Kernel { 11namespace Kernel {
12 12
13class ServerPort; 13class ServerPort;
14class ClientSession;
14 15
15class ClientPort : public Object { 16class ClientPort final : public Object {
16public: 17public:
17 friend class ServerPort; 18 friend class ServerPort;
18 std::string GetTypeName() const override { 19 std::string GetTypeName() const override {
@@ -27,12 +28,20 @@ public:
27 return HANDLE_TYPE; 28 return HANDLE_TYPE;
28 } 29 }
29 30
31 /**
32 * Creates a new Session pair, adds the created ServerSession to the associated ServerPort's
33 * list of pending sessions, and signals the ServerPort, causing any threads
34 * waiting on it to awake.
35 * @returns ClientSession The client endpoint of the created Session pair, or error code.
36 */
37 ResultVal<SharedPtr<ClientSession>> Connect();
38
30 SharedPtr<ServerPort> server_port; ///< ServerPort associated with this client port. 39 SharedPtr<ServerPort> server_port; ///< ServerPort associated with this client port.
31 u32 max_sessions; ///< Maximum number of simultaneous sessions the port can have 40 u32 max_sessions; ///< Maximum number of simultaneous sessions the port can have
32 u32 active_sessions; ///< Number of currently open sessions to this port 41 u32 active_sessions; ///< Number of currently open sessions to this port
33 std::string name; ///< Name of client port (optional) 42 std::string name; ///< Name of client port (optional)
34 43
35protected: 44private:
36 ClientPort(); 45 ClientPort();
37 ~ClientPort() override; 46 ~ClientPort() override;
38}; 47};
diff --git a/src/core/hle/kernel/client_session.cpp b/src/core/hle/kernel/client_session.cpp
new file mode 100644
index 000000000..0331386ec
--- /dev/null
+++ b/src/core/hle/kernel/client_session.cpp
@@ -0,0 +1,40 @@
1// Copyright 2016 Citra Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include "common/assert.h"
6
7#include "core/hle/kernel/client_session.h"
8#include "core/hle/kernel/server_session.h"
9
10namespace Kernel {
11
12ClientSession::ClientSession() = default;
13ClientSession::~ClientSession() {
14 // This destructor will be called automatically when the last ClientSession handle is closed by
15 // the emulated application.
16
17 if (server_session->hle_handler)
18 server_session->hle_handler->ClientDisconnected(server_session);
19
20 // TODO(Subv): If the session is still open, set the connection status to 2 (Closed by client),
21 // wake up all the ServerSession's waiting threads and set the WaitSynchronization result to
22 // 0xC920181A.
23}
24
25ResultVal<SharedPtr<ClientSession>> ClientSession::Create(ServerSession* server_session,
26 std::string name) {
27 SharedPtr<ClientSession> client_session(new ClientSession);
28
29 client_session->name = std::move(name);
30 client_session->server_session = server_session;
31 client_session->session_status = SessionStatus::Open;
32 return MakeResult<SharedPtr<ClientSession>>(std::move(client_session));
33}
34
35ResultCode ClientSession::SendSyncRequest() {
36 // Signal the server session that new data is available
37 return server_session->HandleSyncRequest();
38}
39
40} // namespace
diff --git a/src/core/hle/kernel/client_session.h b/src/core/hle/kernel/client_session.h
new file mode 100644
index 000000000..ed468dec6
--- /dev/null
+++ b/src/core/hle/kernel/client_session.h
@@ -0,0 +1,65 @@
1// Copyright 2016 Citra Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include <memory>
8#include <string>
9
10#include "common/common_types.h"
11
12#include "core/hle/kernel/kernel.h"
13
14namespace Kernel {
15
16class ServerSession;
17
18enum class SessionStatus {
19 Open = 1,
20 ClosedByClient = 2,
21 ClosedBYServer = 3,
22};
23
24class ClientSession final : public Object {
25public:
26 friend class ServerSession;
27
28 std::string GetTypeName() const override {
29 return "ClientSession";
30 }
31
32 std::string GetName() const override {
33 return name;
34 }
35
36 static const HandleType HANDLE_TYPE = HandleType::ClientSession;
37 HandleType GetHandleType() const override {
38 return HANDLE_TYPE;
39 }
40
41 /**
42 * Sends an SyncRequest from the current emulated thread.
43 * @return ResultCode of the operation.
44 */
45 ResultCode SendSyncRequest();
46
47 std::string name; ///< Name of client port (optional)
48 ServerSession* server_session; ///< The server session associated with this client session.
49 SessionStatus session_status; ///< The session's current status.
50
51private:
52 ClientSession();
53 ~ClientSession() override;
54
55 /**
56 * Creates a client session.
57 * @param server_session The server session associated with this client session
58 * @param name Optional name of client session
59 * @return The created client session
60 */
61 static ResultVal<SharedPtr<ClientSession>> Create(ServerSession* server_session,
62 std::string name = "Unknown");
63};
64
65} // namespace
diff --git a/src/core/hle/kernel/kernel.h b/src/core/hle/kernel/kernel.h
index 231cf7b75..0b811c5a7 100644
--- a/src/core/hle/kernel/kernel.h
+++ b/src/core/hle/kernel/kernel.h
@@ -31,22 +31,21 @@ enum KernelHandle : Handle {
31}; 31};
32 32
33enum class HandleType : u32 { 33enum class HandleType : u32 {
34 Unknown = 0, 34 Unknown,
35 35 Event,
36 Session = 2, 36 Mutex,
37 Event = 3, 37 SharedMemory,
38 Mutex = 4, 38 Thread,
39 SharedMemory = 5, 39 Process,
40 Redirection = 6, 40 AddressArbiter,
41 Thread = 7, 41 Semaphore,
42 Process = 8, 42 Timer,
43 AddressArbiter = 9, 43 ResourceLimit,
44 Semaphore = 10, 44 CodeSet,
45 Timer = 11, 45 ClientPort,
46 ResourceLimit = 12, 46 ServerPort,
47 CodeSet = 13, 47 ClientSession,
48 ClientPort = 14, 48 ServerSession,
49 ServerPort = 15,
50}; 49};
51 50
52enum { 51enum {
@@ -82,23 +81,23 @@ public:
82 */ 81 */
83 bool IsWaitable() const { 82 bool IsWaitable() const {
84 switch (GetHandleType()) { 83 switch (GetHandleType()) {
85 case HandleType::Session:
86 case HandleType::ServerPort:
87 case HandleType::Event: 84 case HandleType::Event:
88 case HandleType::Mutex: 85 case HandleType::Mutex:
89 case HandleType::Thread: 86 case HandleType::Thread:
90 case HandleType::Semaphore: 87 case HandleType::Semaphore:
91 case HandleType::Timer: 88 case HandleType::Timer:
89 case HandleType::ServerPort:
90 case HandleType::ServerSession:
92 return true; 91 return true;
93 92
94 case HandleType::Unknown: 93 case HandleType::Unknown:
95 case HandleType::SharedMemory: 94 case HandleType::SharedMemory:
96 case HandleType::Redirection:
97 case HandleType::Process: 95 case HandleType::Process:
98 case HandleType::AddressArbiter: 96 case HandleType::AddressArbiter:
99 case HandleType::ResourceLimit: 97 case HandleType::ResourceLimit:
100 case HandleType::CodeSet: 98 case HandleType::CodeSet:
101 case HandleType::ClientPort: 99 case HandleType::ClientPort:
100 case HandleType::ClientSession:
102 return false; 101 return false;
103 } 102 }
104 } 103 }
diff --git a/src/core/hle/kernel/server_port.cpp b/src/core/hle/kernel/server_port.cpp
index 8e3ec8a14..6c19aa7c0 100644
--- a/src/core/hle/kernel/server_port.cpp
+++ b/src/core/hle/kernel/server_port.cpp
@@ -24,12 +24,14 @@ void ServerPort::Acquire() {
24} 24}
25 25
26std::tuple<SharedPtr<ServerPort>, SharedPtr<ClientPort>> ServerPort::CreatePortPair( 26std::tuple<SharedPtr<ServerPort>, SharedPtr<ClientPort>> ServerPort::CreatePortPair(
27 u32 max_sessions, std::string name) { 27 u32 max_sessions, std::string name,
28 std::shared_ptr<Service::SessionRequestHandler> hle_handler) {
28 29
29 SharedPtr<ServerPort> server_port(new ServerPort); 30 SharedPtr<ServerPort> server_port(new ServerPort);
30 SharedPtr<ClientPort> client_port(new ClientPort); 31 SharedPtr<ClientPort> client_port(new ClientPort);
31 32
32 server_port->name = name + "_Server"; 33 server_port->name = name + "_Server";
34 server_port->hle_handler = std::move(hle_handler);
33 client_port->name = name + "_Client"; 35 client_port->name = name + "_Client";
34 client_port->server_port = server_port; 36 client_port->server_port = server_port;
35 client_port->max_sessions = max_sessions; 37 client_port->max_sessions = max_sessions;
diff --git a/src/core/hle/kernel/server_port.h b/src/core/hle/kernel/server_port.h
index fa9448ca0..b0f8df62c 100644
--- a/src/core/hle/kernel/server_port.h
+++ b/src/core/hle/kernel/server_port.h
@@ -4,11 +4,16 @@
4 4
5#pragma once 5#pragma once
6 6
7#include <memory>
7#include <string> 8#include <string>
8#include <tuple> 9#include <tuple>
9#include "common/common_types.h" 10#include "common/common_types.h"
10#include "core/hle/kernel/kernel.h" 11#include "core/hle/kernel/kernel.h"
11 12
13namespace Service {
14class SessionRequestHandler;
15}
16
12namespace Kernel { 17namespace Kernel {
13 18
14class ClientPort; 19class ClientPort;
@@ -19,10 +24,13 @@ public:
19 * Creates a pair of ServerPort and an associated ClientPort. 24 * Creates a pair of ServerPort and an associated ClientPort.
20 * @param max_sessions Maximum number of sessions to the port 25 * @param max_sessions Maximum number of sessions to the port
21 * @param name Optional name of the ports 26 * @param name Optional name of the ports
27 * @param hle_handler Optional HLE handler template for the port,
28 * ServerSessions crated from this port will inherit a reference to this handler.
22 * @return The created port tuple 29 * @return The created port tuple
23 */ 30 */
24 static std::tuple<SharedPtr<ServerPort>, SharedPtr<ClientPort>> CreatePortPair( 31 static std::tuple<SharedPtr<ServerPort>, SharedPtr<ClientPort>> CreatePortPair(
25 u32 max_sessions, std::string name = "UnknownPort"); 32 u32 max_sessions, std::string name = "UnknownPort",
33 std::shared_ptr<Service::SessionRequestHandler> hle_handler = nullptr);
26 34
27 std::string GetTypeName() const override { 35 std::string GetTypeName() const override {
28 return "ServerPort"; 36 return "ServerPort";
@@ -41,6 +49,10 @@ public:
41 std::vector<SharedPtr<WaitObject>> 49 std::vector<SharedPtr<WaitObject>>
42 pending_sessions; ///< ServerSessions waiting to be accepted by the port 50 pending_sessions; ///< ServerSessions waiting to be accepted by the port
43 51
52 /// This session's HLE request handler template (optional)
53 /// ServerSessions created from this port inherit a reference to this handler.
54 std::shared_ptr<Service::SessionRequestHandler> hle_handler;
55
44 bool ShouldWait() override; 56 bool ShouldWait() override;
45 void Acquire() override; 57 void Acquire() override;
46 58
diff --git a/src/core/hle/kernel/server_session.cpp b/src/core/hle/kernel/server_session.cpp
new file mode 100644
index 000000000..146458c1c
--- /dev/null
+++ b/src/core/hle/kernel/server_session.cpp
@@ -0,0 +1,79 @@
1// Copyright 2016 Citra Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include <tuple>
6
7#include "core/hle/kernel/client_session.h"
8#include "core/hle/kernel/server_session.h"
9#include "core/hle/kernel/thread.h"
10
11namespace Kernel {
12
13ServerSession::ServerSession() = default;
14ServerSession::~ServerSession() {
15 // This destructor will be called automatically when the last ServerSession handle is closed by
16 // the emulated application.
17 // TODO(Subv): Reduce the ClientPort's connection count,
18 // if the session is still open, set the connection status to 3 (Closed by server),
19}
20
21ResultVal<SharedPtr<ServerSession>> ServerSession::Create(
22 std::string name, std::shared_ptr<Service::SessionRequestHandler> hle_handler) {
23 SharedPtr<ServerSession> server_session(new ServerSession);
24
25 server_session->name = std::move(name);
26 server_session->signaled = false;
27 server_session->hle_handler = std::move(hle_handler);
28
29 return MakeResult<SharedPtr<ServerSession>>(std::move(server_session));
30}
31
32bool ServerSession::ShouldWait() {
33 return !signaled;
34}
35
36void ServerSession::Acquire() {
37 ASSERT_MSG(!ShouldWait(), "object unavailable!");
38 signaled = false;
39}
40
41ResultCode ServerSession::HandleSyncRequest() {
42 // The ServerSession received a sync request, this means that there's new data available
43 // from its ClientSession, so wake up any threads that may be waiting on a svcReplyAndReceive or
44 // similar.
45
46 // If this ServerSession has an associated HLE handler, forward the request to it.
47 if (hle_handler != nullptr) {
48 // Attempt to translate the incoming request's command buffer.
49 ResultCode result = TranslateHLERequest(this);
50 if (result.IsError())
51 return result;
52 hle_handler->HandleSyncRequest(SharedPtr<ServerSession>(this));
53 // TODO(Subv): Translate the response command buffer.
54 }
55
56 // If this ServerSession does not have an HLE implementation, just wake up the threads waiting
57 // on it.
58 signaled = true;
59 WakeupAllWaitingThreads();
60 return RESULT_SUCCESS;
61}
62
63ServerSession::SessionPair ServerSession::CreateSessionPair(
64 const std::string& name, std::shared_ptr<Service::SessionRequestHandler> hle_handler) {
65 auto server_session =
66 ServerSession::Create(name + "_Server", std::move(hle_handler)).MoveFrom();
67 // We keep a non-owning pointer to the ServerSession in the ClientSession because we don't want
68 // to prevent the ServerSession's destructor from being called when the emulated
69 // application closes the last ServerSession handle.
70 auto client_session = ClientSession::Create(server_session.get(), name + "_Client").MoveFrom();
71
72 return std::make_tuple(std::move(server_session), std::move(client_session));
73}
74
75ResultCode TranslateHLERequest(ServerSession* server_session) {
76 // TODO(Subv): Implement this function once multiple concurrent processes are supported.
77 return RESULT_SUCCESS;
78}
79}
diff --git a/src/core/hle/kernel/server_session.h b/src/core/hle/kernel/server_session.h
new file mode 100644
index 000000000..458284a5d
--- /dev/null
+++ b/src/core/hle/kernel/server_session.h
@@ -0,0 +1,94 @@
1// Copyright 2014 Citra Emulator Project
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#include "common/assert.h"
9#include "common/common_types.h"
10#include "core/hle/kernel/kernel.h"
11#include "core/hle/kernel/thread.h"
12#include "core/hle/result.h"
13#include "core/hle/service/service.h"
14#include "core/memory.h"
15
16namespace Kernel {
17
18class ClientSession;
19
20/**
21 * Kernel object representing the server endpoint of an IPC session. Sessions are the basic CTR-OS
22 * primitive for communication between different processes, and are used to implement service calls
23 * to the various system services.
24 *
25 * To make a service call, the client must write the command header and parameters to the buffer
26 * located at offset 0x80 of the TLS (Thread-Local Storage) area, then execute a SendSyncRequest
27 * SVC call with its ClientSession handle. The kernel will read the command header, using it to
28 * marshall the parameters to the process at the server endpoint of the session.
29 * After the server replies to the request, the response is marshalled back to the caller's
30 * TLS buffer and control is transferred back to it.
31 */
32class ServerSession final : public WaitObject {
33public:
34 std::string GetTypeName() const override {
35 return "ServerSession";
36 }
37
38 static const HandleType HANDLE_TYPE = HandleType::ServerSession;
39 HandleType GetHandleType() const override {
40 return HANDLE_TYPE;
41 }
42
43 using SessionPair = std::tuple<SharedPtr<ServerSession>, SharedPtr<ClientSession>>;
44
45 /**
46 * Creates a pair of ServerSession and an associated ClientSession.
47 * @param name Optional name of the ports
48 * @return The created session tuple
49 */
50 static SessionPair CreateSessionPair(
51 const std::string& name = "Unknown",
52 std::shared_ptr<Service::SessionRequestHandler> hle_handler = nullptr);
53
54 /**
55 * Handle a sync request from the emulated application.
56 * @returns ResultCode from the operation.
57 */
58 ResultCode HandleSyncRequest();
59
60 bool ShouldWait() override;
61
62 void Acquire() override;
63
64 std::string name; ///< The name of this session (optional)
65 bool signaled; ///< Whether there's new data available to this ServerSession
66 std::shared_ptr<Service::SessionRequestHandler>
67 hle_handler; ///< This session's HLE request handler (optional)
68
69private:
70 ServerSession();
71 ~ServerSession() override;
72
73 /**
74 * Creates a server session. The server session can have an optional HLE handler,
75 * which will be invoked to handle the IPC requests that this session receives.
76 * @param name Optional name of the server session.
77 * @param hle_handler Optional HLE handler for this server session.
78 * @return The created server session
79 */
80 static ResultVal<SharedPtr<ServerSession>> Create(
81 std::string name = "Unknown",
82 std::shared_ptr<Service::SessionRequestHandler> hle_handler = nullptr);
83};
84
85/**
86 * Performs command buffer translation for an HLE IPC request.
87 * The command buffer from the ServerSession thread's TLS is copied into a
88 * buffer and all descriptors in the buffer are processed.
89 * TODO(Subv): Implement this function, currently we do not support multiple processes running at
90 * once, but once that is implemented we'll need to properly translate all descriptors
91 * in the command buffer.
92 */
93ResultCode TranslateHLERequest(ServerSession* server_session);
94}
diff --git a/src/core/hle/result.h b/src/core/hle/result.h
index 8d29117a8..53864a3a7 100644
--- a/src/core/hle/result.h
+++ b/src/core/hle/result.h
@@ -18,6 +18,7 @@ enum class ErrorDescription : u32 {
18 Success = 0, 18 Success = 0,
19 WrongPermission = 46, 19 WrongPermission = 46,
20 OS_InvalidBufferDescriptor = 48, 20 OS_InvalidBufferDescriptor = 48,
21 MaxConnectionsReached = 52,
21 WrongAddress = 53, 22 WrongAddress = 53,
22 FS_ArchiveNotMounted = 101, 23 FS_ArchiveNotMounted = 101,
23 FS_FileNotFound = 112, 24 FS_FileNotFound = 112,
diff --git a/src/core/hle/service/apt/apt.h b/src/core/hle/service/apt/apt.h
index e6a8be870..80325361f 100644
--- a/src/core/hle/service/apt/apt.h
+++ b/src/core/hle/service/apt/apt.h
@@ -14,6 +14,9 @@ class Interface;
14 14
15namespace APT { 15namespace APT {
16 16
17/// Each APT service can only have up to 2 sessions connected at the same time.
18static const u32 MaxAPTSessions = 2;
19
17/// Holds information about the parameters used in Send/Glance/ReceiveParameter 20/// Holds information about the parameters used in Send/Glance/ReceiveParameter
18struct MessageParameter { 21struct MessageParameter {
19 u32 sender_id = 0; 22 u32 sender_id = 0;
diff --git a/src/core/hle/service/apt/apt_a.cpp b/src/core/hle/service/apt/apt_a.cpp
index 6e35e1d29..62dc2d61d 100644
--- a/src/core/hle/service/apt/apt_a.cpp
+++ b/src/core/hle/service/apt/apt_a.cpp
@@ -102,7 +102,7 @@ const Interface::FunctionInfo FunctionTable[] = {
102 {0x01050100, nullptr, "IsTitleAllowed"}, 102 {0x01050100, nullptr, "IsTitleAllowed"},
103}; 103};
104 104
105APT_A_Interface::APT_A_Interface() { 105APT_A_Interface::APT_A_Interface() : Interface(MaxAPTSessions) {
106 Register(FunctionTable); 106 Register(FunctionTable);
107} 107}
108 108
diff --git a/src/core/hle/service/apt/apt_s.cpp b/src/core/hle/service/apt/apt_s.cpp
index 84019e6e5..effd23dce 100644
--- a/src/core/hle/service/apt/apt_s.cpp
+++ b/src/core/hle/service/apt/apt_s.cpp
@@ -102,7 +102,7 @@ const Interface::FunctionInfo FunctionTable[] = {
102 {0x01050100, nullptr, "IsTitleAllowed"}, 102 {0x01050100, nullptr, "IsTitleAllowed"},
103}; 103};
104 104
105APT_S_Interface::APT_S_Interface() { 105APT_S_Interface::APT_S_Interface() : Interface(MaxAPTSessions) {
106 Register(FunctionTable); 106 Register(FunctionTable);
107} 107}
108 108
diff --git a/src/core/hle/service/apt/apt_u.cpp b/src/core/hle/service/apt/apt_u.cpp
index a731c39f6..e06084a1e 100644
--- a/src/core/hle/service/apt/apt_u.cpp
+++ b/src/core/hle/service/apt/apt_u.cpp
@@ -99,7 +99,7 @@ const Interface::FunctionInfo FunctionTable[] = {
99 {0x01020000, CheckNew3DS, "CheckNew3DS"}, 99 {0x01020000, CheckNew3DS, "CheckNew3DS"},
100}; 100};
101 101
102APT_U_Interface::APT_U_Interface() { 102APT_U_Interface::APT_U_Interface() : Interface(MaxAPTSessions) {
103 Register(FunctionTable); 103 Register(FunctionTable);
104} 104}
105 105
diff --git a/src/core/hle/service/fs/archive.cpp b/src/core/hle/service/fs/archive.cpp
index bef75f5df..f21934108 100644
--- a/src/core/hle/service/fs/archive.cpp
+++ b/src/core/hle/service/fs/archive.cpp
@@ -24,6 +24,7 @@
24#include "core/file_sys/directory_backend.h" 24#include "core/file_sys/directory_backend.h"
25#include "core/file_sys/file_backend.h" 25#include "core/file_sys/file_backend.h"
26#include "core/hle/hle.h" 26#include "core/hle/hle.h"
27#include "core/hle/kernel/client_session.h"
27#include "core/hle/result.h" 28#include "core/hle/result.h"
28#include "core/hle/service/fs/archive.h" 29#include "core/hle/service/fs/archive.h"
29#include "core/hle/service/fs/fs_user.h" 30#include "core/hle/service/fs/fs_user.h"
@@ -93,7 +94,7 @@ File::File(std::unique_ptr<FileSys::FileBackend>&& backend, const FileSys::Path&
93 94
94File::~File() {} 95File::~File() {}
95 96
96ResultVal<bool> File::SyncRequest() { 97void File::HandleSyncRequest(Kernel::SharedPtr<Kernel::ServerSession> server_session) {
97 u32* cmd_buff = Kernel::GetCommandBuffer(); 98 u32* cmd_buff = Kernel::GetCommandBuffer();
98 FileCommand cmd = static_cast<FileCommand>(cmd_buff[0]); 99 FileCommand cmd = static_cast<FileCommand>(cmd_buff[0]);
99 switch (cmd) { 100 switch (cmd) {
@@ -116,7 +117,7 @@ ResultVal<bool> File::SyncRequest() {
116 ResultVal<size_t> read = backend->Read(offset, data.size(), data.data()); 117 ResultVal<size_t> read = backend->Read(offset, data.size(), data.data());
117 if (read.Failed()) { 118 if (read.Failed()) {
118 cmd_buff[1] = read.Code().raw; 119 cmd_buff[1] = read.Code().raw;
119 return read.Code(); 120 return;
120 } 121 }
121 Memory::WriteBlock(address, data.data(), *read); 122 Memory::WriteBlock(address, data.data(), *read);
122 cmd_buff[2] = static_cast<u32>(*read); 123 cmd_buff[2] = static_cast<u32>(*read);
@@ -137,7 +138,7 @@ ResultVal<bool> File::SyncRequest() {
137 ResultVal<size_t> written = backend->Write(offset, data.size(), flush != 0, data.data()); 138 ResultVal<size_t> written = backend->Write(offset, data.size(), flush != 0, data.data());
138 if (written.Failed()) { 139 if (written.Failed()) {
139 cmd_buff[1] = written.Code().raw; 140 cmd_buff[1] = written.Code().raw;
140 return written.Code(); 141 return;
141 } 142 }
142 cmd_buff[2] = static_cast<u32>(*written); 143 cmd_buff[2] = static_cast<u32>(*written);
143 break; 144 break;
@@ -173,7 +174,11 @@ ResultVal<bool> File::SyncRequest() {
173 174
174 case FileCommand::OpenLinkFile: { 175 case FileCommand::OpenLinkFile: {
175 LOG_WARNING(Service_FS, "(STUBBED) File command OpenLinkFile %s", GetName().c_str()); 176 LOG_WARNING(Service_FS, "(STUBBED) File command OpenLinkFile %s", GetName().c_str());
176 cmd_buff[3] = Kernel::g_handle_table.Create(this).ValueOr(INVALID_HANDLE); 177 auto sessions = Kernel::ServerSession::CreateSessionPair(GetName(), shared_from_this());
178 ClientConnected(std::get<Kernel::SharedPtr<Kernel::ServerSession>>(sessions));
179 cmd_buff[3] = Kernel::g_handle_table
180 .Create(std::get<Kernel::SharedPtr<Kernel::ClientSession>>(sessions))
181 .ValueOr(INVALID_HANDLE);
177 break; 182 break;
178 } 183 }
179 184
@@ -194,10 +199,9 @@ ResultVal<bool> File::SyncRequest() {
194 LOG_ERROR(Service_FS, "Unknown command=0x%08X!", cmd); 199 LOG_ERROR(Service_FS, "Unknown command=0x%08X!", cmd);
195 ResultCode error = UnimplementedFunction(ErrorModule::FS); 200 ResultCode error = UnimplementedFunction(ErrorModule::FS);
196 cmd_buff[1] = error.raw; // TODO(Link Mauve): use the correct error code for that. 201 cmd_buff[1] = error.raw; // TODO(Link Mauve): use the correct error code for that.
197 return error; 202 return;
198 } 203 }
199 cmd_buff[1] = RESULT_SUCCESS.raw; // No error 204 cmd_buff[1] = RESULT_SUCCESS.raw; // No error
200 return MakeResult<bool>(false);
201} 205}
202 206
203Directory::Directory(std::unique_ptr<FileSys::DirectoryBackend>&& backend, 207Directory::Directory(std::unique_ptr<FileSys::DirectoryBackend>&& backend,
@@ -206,11 +210,10 @@ Directory::Directory(std::unique_ptr<FileSys::DirectoryBackend>&& backend,
206 210
207Directory::~Directory() {} 211Directory::~Directory() {}
208 212
209ResultVal<bool> Directory::SyncRequest() { 213void Directory::HandleSyncRequest(Kernel::SharedPtr<Kernel::ServerSession> server_session) {
210 u32* cmd_buff = Kernel::GetCommandBuffer(); 214 u32* cmd_buff = Kernel::GetCommandBuffer();
211 DirectoryCommand cmd = static_cast<DirectoryCommand>(cmd_buff[0]); 215 DirectoryCommand cmd = static_cast<DirectoryCommand>(cmd_buff[0]);
212 switch (cmd) { 216 switch (cmd) {
213
214 // Read from directory... 217 // Read from directory...
215 case DirectoryCommand::Read: { 218 case DirectoryCommand::Read: {
216 u32 count = cmd_buff[1]; 219 u32 count = cmd_buff[1];
@@ -237,10 +240,9 @@ ResultVal<bool> Directory::SyncRequest() {
237 LOG_ERROR(Service_FS, "Unknown command=0x%08X!", cmd); 240 LOG_ERROR(Service_FS, "Unknown command=0x%08X!", cmd);
238 ResultCode error = UnimplementedFunction(ErrorModule::FS); 241 ResultCode error = UnimplementedFunction(ErrorModule::FS);
239 cmd_buff[1] = error.raw; // TODO(Link Mauve): use the correct error code for that. 242 cmd_buff[1] = error.raw; // TODO(Link Mauve): use the correct error code for that.
240 return MakeResult<bool>(false); 243 return;
241 } 244 }
242 cmd_buff[1] = RESULT_SUCCESS.raw; // No error 245 cmd_buff[1] = RESULT_SUCCESS.raw; // No error
243 return MakeResult<bool>(false);
244} 246}
245 247
246//////////////////////////////////////////////////////////////////////////////////////////////////// 248////////////////////////////////////////////////////////////////////////////////////////////////////
@@ -307,9 +309,9 @@ ResultCode RegisterArchiveType(std::unique_ptr<FileSys::ArchiveFactory>&& factor
307 return RESULT_SUCCESS; 309 return RESULT_SUCCESS;
308} 310}
309 311
310ResultVal<Kernel::SharedPtr<File>> OpenFileFromArchive(ArchiveHandle archive_handle, 312ResultVal<std::shared_ptr<File>> OpenFileFromArchive(ArchiveHandle archive_handle,
311 const FileSys::Path& path, 313 const FileSys::Path& path,
312 const FileSys::Mode mode) { 314 const FileSys::Mode mode) {
313 ArchiveBackend* archive = GetArchive(archive_handle); 315 ArchiveBackend* archive = GetArchive(archive_handle);
314 if (archive == nullptr) 316 if (archive == nullptr)
315 return ERR_INVALID_ARCHIVE_HANDLE; 317 return ERR_INVALID_ARCHIVE_HANDLE;
@@ -318,8 +320,8 @@ ResultVal<Kernel::SharedPtr<File>> OpenFileFromArchive(ArchiveHandle archive_han
318 if (backend.Failed()) 320 if (backend.Failed())
319 return backend.Code(); 321 return backend.Code();
320 322
321 auto file = Kernel::SharedPtr<File>(new File(backend.MoveFrom(), path)); 323 auto file = std::shared_ptr<File>(new File(backend.MoveFrom(), path));
322 return MakeResult<Kernel::SharedPtr<File>>(std::move(file)); 324 return MakeResult<std::shared_ptr<File>>(std::move(file));
323} 325}
324 326
325ResultCode DeleteFileFromArchive(ArchiveHandle archive_handle, const FileSys::Path& path) { 327ResultCode DeleteFileFromArchive(ArchiveHandle archive_handle, const FileSys::Path& path) {
@@ -398,8 +400,8 @@ ResultCode RenameDirectoryBetweenArchives(ArchiveHandle src_archive_handle,
398 } 400 }
399} 401}
400 402
401ResultVal<Kernel::SharedPtr<Directory>> OpenDirectoryFromArchive(ArchiveHandle archive_handle, 403ResultVal<std::shared_ptr<Directory>> OpenDirectoryFromArchive(ArchiveHandle archive_handle,
402 const FileSys::Path& path) { 404 const FileSys::Path& path) {
403 ArchiveBackend* archive = GetArchive(archive_handle); 405 ArchiveBackend* archive = GetArchive(archive_handle);
404 if (archive == nullptr) 406 if (archive == nullptr)
405 return ERR_INVALID_ARCHIVE_HANDLE; 407 return ERR_INVALID_ARCHIVE_HANDLE;
@@ -408,8 +410,8 @@ ResultVal<Kernel::SharedPtr<Directory>> OpenDirectoryFromArchive(ArchiveHandle a
408 if (backend.Failed()) 410 if (backend.Failed())
409 return backend.Code(); 411 return backend.Code();
410 412
411 auto directory = Kernel::SharedPtr<Directory>(new Directory(backend.MoveFrom(), path)); 413 auto directory = std::shared_ptr<Directory>(new Directory(backend.MoveFrom(), path));
412 return MakeResult<Kernel::SharedPtr<Directory>>(std::move(directory)); 414 return MakeResult<std::shared_ptr<Directory>>(std::move(directory));
413} 415}
414 416
415ResultVal<u64> GetFreeBytesInArchive(ArchiveHandle archive_handle) { 417ResultVal<u64> GetFreeBytesInArchive(ArchiveHandle archive_handle) {
diff --git a/src/core/hle/service/fs/archive.h b/src/core/hle/service/fs/archive.h
index 87089bd92..7ba62ede0 100644
--- a/src/core/hle/service/fs/archive.h
+++ b/src/core/hle/service/fs/archive.h
@@ -8,7 +8,7 @@
8#include <string> 8#include <string>
9#include "common/common_types.h" 9#include "common/common_types.h"
10#include "core/file_sys/archive_backend.h" 10#include "core/file_sys/archive_backend.h"
11#include "core/hle/kernel/session.h" 11#include "core/hle/kernel/server_session.h"
12#include "core/hle/result.h" 12#include "core/hle/result.h"
13 13
14namespace FileSys { 14namespace FileSys {
@@ -43,33 +43,37 @@ enum class MediaType : u32 { NAND = 0, SDMC = 1, GameCard = 2 };
43 43
44typedef u64 ArchiveHandle; 44typedef u64 ArchiveHandle;
45 45
46class File : public Kernel::Session { 46class File final : public SessionRequestHandler, public std::enable_shared_from_this<File> {
47public: 47public:
48 File(std::unique_ptr<FileSys::FileBackend>&& backend, const FileSys::Path& path); 48 File(std::unique_ptr<FileSys::FileBackend>&& backend, const FileSys::Path& path);
49 ~File(); 49 ~File();
50 50
51 std::string GetName() const override { 51 std::string GetName() const {
52 return "Path: " + path.DebugStr(); 52 return "Path: " + path.DebugStr();
53 } 53 }
54 ResultVal<bool> SyncRequest() override;
55 54
56 FileSys::Path path; ///< Path of the file 55 FileSys::Path path; ///< Path of the file
57 u32 priority; ///< Priority of the file. TODO(Subv): Find out what this means 56 u32 priority; ///< Priority of the file. TODO(Subv): Find out what this means
58 std::unique_ptr<FileSys::FileBackend> backend; ///< File backend interface 57 std::unique_ptr<FileSys::FileBackend> backend; ///< File backend interface
58
59protected:
60 void HandleSyncRequest(Kernel::SharedPtr<Kernel::ServerSession> server_session) override;
59}; 61};
60 62
61class Directory : public Kernel::Session { 63class Directory final : public SessionRequestHandler {
62public: 64public:
63 Directory(std::unique_ptr<FileSys::DirectoryBackend>&& backend, const FileSys::Path& path); 65 Directory(std::unique_ptr<FileSys::DirectoryBackend>&& backend, const FileSys::Path& path);
64 ~Directory(); 66 ~Directory();
65 67
66 std::string GetName() const override { 68 std::string GetName() const {
67 return "Directory: " + path.DebugStr(); 69 return "Directory: " + path.DebugStr();
68 } 70 }
69 ResultVal<bool> SyncRequest() override;
70 71
71 FileSys::Path path; ///< Path of the directory 72 FileSys::Path path; ///< Path of the directory
72 std::unique_ptr<FileSys::DirectoryBackend> backend; ///< File backend interface 73 std::unique_ptr<FileSys::DirectoryBackend> backend; ///< File backend interface
74
75protected:
76 void HandleSyncRequest(Kernel::SharedPtr<Kernel::ServerSession> server_session) override;
73}; 77};
74 78
75/** 79/**
@@ -99,11 +103,11 @@ ResultCode RegisterArchiveType(std::unique_ptr<FileSys::ArchiveFactory>&& factor
99 * @param archive_handle Handle to an open Archive object 103 * @param archive_handle Handle to an open Archive object
100 * @param path Path to the File inside of the Archive 104 * @param path Path to the File inside of the Archive
101 * @param mode Mode under which to open the File 105 * @param mode Mode under which to open the File
102 * @return The opened File object as a Session 106 * @return The opened File object
103 */ 107 */
104ResultVal<Kernel::SharedPtr<File>> OpenFileFromArchive(ArchiveHandle archive_handle, 108ResultVal<std::shared_ptr<File>> OpenFileFromArchive(ArchiveHandle archive_handle,
105 const FileSys::Path& path, 109 const FileSys::Path& path,
106 const FileSys::Mode mode); 110 const FileSys::Mode mode);
107 111
108/** 112/**
109 * Delete a File from an Archive 113 * Delete a File from an Archive
@@ -178,10 +182,10 @@ ResultCode RenameDirectoryBetweenArchives(ArchiveHandle src_archive_handle,
178 * Open a Directory from an Archive 182 * Open a Directory from an Archive
179 * @param archive_handle Handle to an open Archive object 183 * @param archive_handle Handle to an open Archive object
180 * @param path Path to the Directory inside of the Archive 184 * @param path Path to the Directory inside of the Archive
181 * @return The opened Directory object as a Session 185 * @return The opened Directory object
182 */ 186 */
183ResultVal<Kernel::SharedPtr<Directory>> OpenDirectoryFromArchive(ArchiveHandle archive_handle, 187ResultVal<std::shared_ptr<Directory>> OpenDirectoryFromArchive(ArchiveHandle archive_handle,
184 const FileSys::Path& path); 188 const FileSys::Path& path);
185 189
186/** 190/**
187 * Get the free space in an Archive 191 * Get the free space in an Archive
diff --git a/src/core/hle/service/fs/fs_user.cpp b/src/core/hle/service/fs/fs_user.cpp
index d6ab5b065..337da1387 100644
--- a/src/core/hle/service/fs/fs_user.cpp
+++ b/src/core/hle/service/fs/fs_user.cpp
@@ -8,6 +8,7 @@
8#include "common/logging/log.h" 8#include "common/logging/log.h"
9#include "common/scope_exit.h" 9#include "common/scope_exit.h"
10#include "common/string_util.h" 10#include "common/string_util.h"
11#include "core/hle/kernel/client_session.h"
11#include "core/hle/result.h" 12#include "core/hle/result.h"
12#include "core/hle/service/fs/archive.h" 13#include "core/hle/service/fs/archive.h"
13#include "core/hle/service/fs/fs_user.h" 14#include "core/hle/service/fs/fs_user.h"
@@ -17,7 +18,7 @@
17// Namespace FS_User 18// Namespace FS_User
18 19
19using Kernel::SharedPtr; 20using Kernel::SharedPtr;
20using Kernel::Session; 21using Kernel::ServerSession;
21 22
22namespace Service { 23namespace Service {
23namespace FS { 24namespace FS {
@@ -67,10 +68,16 @@ static void OpenFile(Service::Interface* self) {
67 LOG_DEBUG(Service_FS, "path=%s, mode=%u attrs=%u", file_path.DebugStr().c_str(), mode.hex, 68 LOG_DEBUG(Service_FS, "path=%s, mode=%u attrs=%u", file_path.DebugStr().c_str(), mode.hex,
68 attributes); 69 attributes);
69 70
70 ResultVal<SharedPtr<File>> file_res = OpenFileFromArchive(archive_handle, file_path, mode); 71 ResultVal<std::shared_ptr<File>> file_res =
72 OpenFileFromArchive(archive_handle, file_path, mode);
71 cmd_buff[1] = file_res.Code().raw; 73 cmd_buff[1] = file_res.Code().raw;
72 if (file_res.Succeeded()) { 74 if (file_res.Succeeded()) {
73 cmd_buff[3] = Kernel::g_handle_table.Create(*file_res).MoveFrom(); 75 std::shared_ptr<File> file = *file_res;
76 auto sessions = ServerSession::CreateSessionPair(file->GetName(), file);
77 file->ClientConnected(std::get<Kernel::SharedPtr<Kernel::ServerSession>>(sessions));
78 cmd_buff[3] = Kernel::g_handle_table
79 .Create(std::get<Kernel::SharedPtr<Kernel::ClientSession>>(sessions))
80 .MoveFrom();
74 } else { 81 } else {
75 cmd_buff[3] = 0; 82 cmd_buff[3] = 0;
76 LOG_ERROR(Service_FS, "failed to get a handle for file %s", file_path.DebugStr().c_str()); 83 LOG_ERROR(Service_FS, "failed to get a handle for file %s", file_path.DebugStr().c_str());
@@ -127,10 +134,16 @@ static void OpenFileDirectly(Service::Interface* self) {
127 } 134 }
128 SCOPE_EXIT({ CloseArchive(*archive_handle); }); 135 SCOPE_EXIT({ CloseArchive(*archive_handle); });
129 136
130 ResultVal<SharedPtr<File>> file_res = OpenFileFromArchive(*archive_handle, file_path, mode); 137 ResultVal<std::shared_ptr<File>> file_res =
138 OpenFileFromArchive(*archive_handle, file_path, mode);
131 cmd_buff[1] = file_res.Code().raw; 139 cmd_buff[1] = file_res.Code().raw;
132 if (file_res.Succeeded()) { 140 if (file_res.Succeeded()) {
133 cmd_buff[3] = Kernel::g_handle_table.Create(*file_res).MoveFrom(); 141 std::shared_ptr<File> file = *file_res;
142 auto sessions = ServerSession::CreateSessionPair(file->GetName(), file);
143 file->ClientConnected(std::get<Kernel::SharedPtr<Kernel::ServerSession>>(sessions));
144 cmd_buff[3] = Kernel::g_handle_table
145 .Create(std::get<Kernel::SharedPtr<Kernel::ClientSession>>(sessions))
146 .MoveFrom();
134 } else { 147 } else {
135 cmd_buff[3] = 0; 148 cmd_buff[3] = 0;
136 LOG_ERROR(Service_FS, "failed to get a handle for file %s mode=%u attributes=%u", 149 LOG_ERROR(Service_FS, "failed to get a handle for file %s mode=%u attributes=%u",
@@ -388,10 +401,16 @@ static void OpenDirectory(Service::Interface* self) {
388 LOG_DEBUG(Service_FS, "type=%u size=%u data=%s", static_cast<u32>(dirname_type), dirname_size, 401 LOG_DEBUG(Service_FS, "type=%u size=%u data=%s", static_cast<u32>(dirname_type), dirname_size,
389 dir_path.DebugStr().c_str()); 402 dir_path.DebugStr().c_str());
390 403
391 ResultVal<SharedPtr<Directory>> dir_res = OpenDirectoryFromArchive(archive_handle, dir_path); 404 ResultVal<std::shared_ptr<Directory>> dir_res =
405 OpenDirectoryFromArchive(archive_handle, dir_path);
392 cmd_buff[1] = dir_res.Code().raw; 406 cmd_buff[1] = dir_res.Code().raw;
393 if (dir_res.Succeeded()) { 407 if (dir_res.Succeeded()) {
394 cmd_buff[3] = Kernel::g_handle_table.Create(*dir_res).MoveFrom(); 408 std::shared_ptr<Directory> directory = *dir_res;
409 auto sessions = ServerSession::CreateSessionPair(directory->GetName(), directory);
410 directory->ClientConnected(std::get<Kernel::SharedPtr<Kernel::ServerSession>>(sessions));
411 cmd_buff[3] = Kernel::g_handle_table
412 .Create(std::get<Kernel::SharedPtr<Kernel::ClientSession>>(sessions))
413 .MoveFrom();
395 } else { 414 } else {
396 LOG_ERROR(Service_FS, "failed to get a handle for directory type=%d size=%d data=%s", 415 LOG_ERROR(Service_FS, "failed to get a handle for directory type=%d size=%d data=%s",
397 dirname_type, dirname_size, dir_path.DebugStr().c_str()); 416 dirname_type, dirname_size, dir_path.DebugStr().c_str());
diff --git a/src/core/hle/service/service.cpp b/src/core/hle/service/service.cpp
index effecc043..2bc3fdc82 100644
--- a/src/core/hle/service/service.cpp
+++ b/src/core/hle/service/service.cpp
@@ -2,8 +2,12 @@
2// Licensed under GPLv2 or any later version 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include <boost/range/algorithm_ext/erase.hpp>
6
5#include "common/logging/log.h" 7#include "common/logging/log.h"
6#include "common/string_util.h" 8#include "common/string_util.h"
9
10#include "core/hle/kernel/server_port.h"
7#include "core/hle/service/ac_u.h" 11#include "core/hle/service/ac_u.h"
8#include "core/hle/service/act_a.h" 12#include "core/hle/service/act_a.h"
9#include "core/hle/service/act_u.h" 13#include "core/hle/service/act_u.h"
@@ -44,8 +48,8 @@
44 48
45namespace Service { 49namespace Service {
46 50
47std::unordered_map<std::string, Kernel::SharedPtr<Interface>> g_kernel_named_ports; 51std::unordered_map<std::string, Kernel::SharedPtr<Kernel::ClientPort>> g_kernel_named_ports;
48std::unordered_map<std::string, Kernel::SharedPtr<Interface>> g_srv_services; 52std::unordered_map<std::string, Kernel::SharedPtr<Kernel::ClientPort>> g_srv_services;
49 53
50/** 54/**
51 * Creates a function string for logging, complete with the name (or header code, depending 55 * Creates a function string for logging, complete with the name (or header code, depending
@@ -64,7 +68,23 @@ static std::string MakeFunctionString(const char* name, const char* port_name,
64 return function_string; 68 return function_string;
65} 69}
66 70
67ResultVal<bool> Interface::SyncRequest() { 71void SessionRequestHandler::ClientConnected(
72 Kernel::SharedPtr<Kernel::ServerSession> server_session) {
73 connected_sessions.push_back(server_session);
74}
75
76void SessionRequestHandler::ClientDisconnected(
77 Kernel::SharedPtr<Kernel::ServerSession> server_session) {
78 boost::range::remove_erase(connected_sessions, server_session);
79}
80
81Interface::Interface(u32 max_sessions) : max_sessions(max_sessions) {}
82Interface::~Interface() = default;
83
84void Interface::HandleSyncRequest(Kernel::SharedPtr<Kernel::ServerSession> server_session) {
85 // TODO(Subv): Make use of the server_session in the HLE service handlers to distinguish which
86 // session triggered each command.
87
68 u32* cmd_buff = Kernel::GetCommandBuffer(); 88 u32* cmd_buff = Kernel::GetCommandBuffer();
69 auto itr = m_functions.find(cmd_buff[0]); 89 auto itr = m_functions.find(cmd_buff[0]);
70 90
@@ -78,14 +98,12 @@ ResultVal<bool> Interface::SyncRequest() {
78 98
79 // TODO(bunnei): Hack - ignore error 99 // TODO(bunnei): Hack - ignore error
80 cmd_buff[1] = 0; 100 cmd_buff[1] = 0;
81 return MakeResult<bool>(false); 101 return;
82 } 102 }
83 LOG_TRACE(Service, "%s", 103 LOG_TRACE(Service, "%s",
84 MakeFunctionString(itr->second.name, GetPortName().c_str(), cmd_buff).c_str()); 104 MakeFunctionString(itr->second.name, GetPortName().c_str(), cmd_buff).c_str());
85 105
86 itr->second.func(this); 106 itr->second.func(this);
87
88 return MakeResult<bool>(false); // TODO: Implement return from actual function
89} 107}
90 108
91void Interface::Register(const FunctionInfo* functions, size_t n) { 109void Interface::Register(const FunctionInfo* functions, size_t n) {
@@ -100,11 +118,19 @@ void Interface::Register(const FunctionInfo* functions, size_t n) {
100// Module interface 118// Module interface
101 119
102static void AddNamedPort(Interface* interface_) { 120static void AddNamedPort(Interface* interface_) {
103 g_kernel_named_ports.emplace(interface_->GetPortName(), interface_); 121 auto ports =
122 Kernel::ServerPort::CreatePortPair(interface_->GetMaxSessions(), interface_->GetPortName(),
123 std::shared_ptr<Interface>(interface_));
124 auto client_port = std::get<Kernel::SharedPtr<Kernel::ClientPort>>(ports);
125 g_kernel_named_ports.emplace(interface_->GetPortName(), std::move(client_port));
104} 126}
105 127
106void AddService(Interface* interface_) { 128void AddService(Interface* interface_) {
107 g_srv_services.emplace(interface_->GetPortName(), interface_); 129 auto ports =
130 Kernel::ServerPort::CreatePortPair(interface_->GetMaxSessions(), interface_->GetPortName(),
131 std::shared_ptr<Interface>(interface_));
132 auto client_port = std::get<Kernel::SharedPtr<Kernel::ClientPort>>(ports);
133 g_srv_services.emplace(interface_->GetPortName(), std::move(client_port));
108} 134}
109 135
110/// Initialize ServiceManager 136/// Initialize ServiceManager
diff --git a/src/core/hle/service/service.h b/src/core/hle/service/service.h
index 29daacfc4..a7ba7688f 100644
--- a/src/core/hle/service/service.h
+++ b/src/core/hle/service/service.h
@@ -9,8 +9,15 @@
9#include <unordered_map> 9#include <unordered_map>
10#include <boost/container/flat_map.hpp> 10#include <boost/container/flat_map.hpp>
11#include "common/common_types.h" 11#include "common/common_types.h"
12#include "core/hle/kernel/session.h" 12#include "core/hle/ipc.h"
13#include "core/hle/kernel/client_port.h"
14#include "core/hle/kernel/thread.h"
13#include "core/hle/result.h" 15#include "core/hle/result.h"
16#include "core/memory.h"
17
18namespace Kernel {
19class ServerSession;
20}
14 21
15//////////////////////////////////////////////////////////////////////////////////////////////////// 22////////////////////////////////////////////////////////////////////////////////////////////////////
16// Namespace Service 23// Namespace Service
@@ -18,14 +25,63 @@
18namespace Service { 25namespace Service {
19 26
20static const int kMaxPortSize = 8; ///< Maximum size of a port name (8 characters) 27static const int kMaxPortSize = 8; ///< Maximum size of a port name (8 characters)
28/// Arbitrary default number of maximum connections to an HLE service.
29static const u32 DefaultMaxSessions = 10;
30
31/**
32 * Interface implemented by HLE Session handlers.
33 * This can be provided to a ServerSession in order to hook into several relevant events
34 * (such as a new connection or a SyncRequest) so they can be implemented in the emulator.
35 */
36class SessionRequestHandler {
37public:
38 /**
39 * Handles a sync request from the emulated application.
40 * @param server_session The ServerSession that was triggered for this sync request,
41 * it should be used to differentiate which client (As in ClientSession) we're answering to.
42 * TODO(Subv): Use a wrapper structure to hold all the information relevant to
43 * this request (ServerSession, Originator thread, Translated command buffer, etc).
44 * @returns ResultCode the result code of the translate operation.
45 */
46 virtual void HandleSyncRequest(Kernel::SharedPtr<Kernel::ServerSession> server_session) = 0;
47
48 /**
49 * Signals that a client has just connected to this HLE handler and keeps the
50 * associated ServerSession alive for the duration of the connection.
51 * @param server_session Owning pointer to the ServerSession associated with the connection.
52 */
53 void ClientConnected(Kernel::SharedPtr<Kernel::ServerSession> server_session);
54
55 /**
56 * Signals that a client has just disconnected from this HLE handler and releases the
57 * associated ServerSession.
58 * @param server_session ServerSession associated with the connection.
59 */
60 void ClientDisconnected(Kernel::SharedPtr<Kernel::ServerSession> server_session);
21 61
22/// Interface to a CTROS service 62protected:
23class Interface : public Kernel::Session { 63 /// List of sessions that are connected to this handler.
24 // TODO(yuriks): An "Interface" being a Kernel::Object is mostly non-sense. Interface should be 64 /// A ServerSession whose server endpoint is an HLE implementation is kept alive by this list
25 // just something that encapsulates a session and acts as a helper to implement service 65 // for the duration of the connection.
26 // processes. 66 std::vector<Kernel::SharedPtr<Kernel::ServerSession>> connected_sessions;
67};
68
69/**
70 * Framework for implementing HLE service handlers which dispatch incoming SyncRequests based on a
71 * table mapping header ids to handler functions.
72 */
73class Interface : public SessionRequestHandler {
27public: 74public:
28 std::string GetName() const override { 75 /**
76 * Creates an HLE interface with the specified max sessions.
77 * @param max_sessions Maximum number of sessions that can be
78 * connected to this service at the same time.
79 */
80 Interface(u32 max_sessions = DefaultMaxSessions);
81
82 virtual ~Interface();
83
84 std::string GetName() const {
29 return GetPortName(); 85 return GetPortName();
30 } 86 }
31 87
@@ -33,6 +89,15 @@ public:
33 version.raw = raw_version; 89 version.raw = raw_version;
34 } 90 }
35 91
92 /**
93 * Gets the maximum allowed number of sessions that can be connected to this service
94 * at the same time.
95 * @returns The maximum number of connections allowed.
96 */
97 u32 GetMaxSessions() const {
98 return max_sessions;
99 }
100
36 typedef void (*Function)(Interface*); 101 typedef void (*Function)(Interface*);
37 102
38 struct FunctionInfo { 103 struct FunctionInfo {
@@ -49,9 +114,9 @@ public:
49 return "[UNKNOWN SERVICE PORT]"; 114 return "[UNKNOWN SERVICE PORT]";
50 } 115 }
51 116
52 ResultVal<bool> SyncRequest() override;
53
54protected: 117protected:
118 void HandleSyncRequest(Kernel::SharedPtr<Kernel::ServerSession> server_session) override;
119
55 /** 120 /**
56 * Registers the functions in the service 121 * Registers the functions in the service
57 */ 122 */
@@ -71,6 +136,7 @@ protected:
71 } version = {}; 136 } version = {};
72 137
73private: 138private:
139 u32 max_sessions; ///< Maximum number of concurrent sessions that this service can handle.
74 boost::container::flat_map<u32, FunctionInfo> m_functions; 140 boost::container::flat_map<u32, FunctionInfo> m_functions;
75}; 141};
76 142
@@ -81,9 +147,9 @@ void Init();
81void Shutdown(); 147void Shutdown();
82 148
83/// Map of named ports managed by the kernel, which can be retrieved using the ConnectToPort SVC. 149/// Map of named ports managed by the kernel, which can be retrieved using the ConnectToPort SVC.
84extern std::unordered_map<std::string, Kernel::SharedPtr<Interface>> g_kernel_named_ports; 150extern std::unordered_map<std::string, Kernel::SharedPtr<Kernel::ClientPort>> g_kernel_named_ports;
85/// Map of services registered with the "srv:" service, retrieved using GetServiceHandle. 151/// Map of services registered with the "srv:" service, retrieved using GetServiceHandle.
86extern std::unordered_map<std::string, Kernel::SharedPtr<Interface>> g_srv_services; 152extern std::unordered_map<std::string, Kernel::SharedPtr<Kernel::ClientPort>> g_srv_services;
87 153
88/// Adds a service to the services table 154/// Adds a service to the services table
89void AddService(Interface* interface_); 155void AddService(Interface* interface_);
diff --git a/src/core/hle/service/soc_u.cpp b/src/core/hle/service/soc_u.cpp
index fd251fc0a..c3918cdd0 100644
--- a/src/core/hle/service/soc_u.cpp
+++ b/src/core/hle/service/soc_u.cpp
@@ -11,7 +11,7 @@
11#include "common/common_types.h" 11#include "common/common_types.h"
12#include "common/logging/log.h" 12#include "common/logging/log.h"
13#include "common/scope_exit.h" 13#include "common/scope_exit.h"
14#include "core/hle/kernel/session.h" 14#include "core/hle/kernel/server_session.h"
15#include "core/hle/result.h" 15#include "core/hle/result.h"
16#include "core/hle/service/soc_u.h" 16#include "core/hle/service/soc_u.h"
17#include "core/memory.h" 17#include "core/memory.h"
diff --git a/src/core/hle/service/srv.cpp b/src/core/hle/service/srv.cpp
index f8df38c42..3bd787147 100644
--- a/src/core/hle/service/srv.cpp
+++ b/src/core/hle/service/srv.cpp
@@ -2,9 +2,13 @@
2// Licensed under GPLv2 or any later version 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include <tuple>
6
5#include "common/common_types.h" 7#include "common/common_types.h"
6#include "common/logging/log.h" 8#include "common/logging/log.h"
9#include "core/hle/kernel/client_session.h"
7#include "core/hle/kernel/event.h" 10#include "core/hle/kernel/event.h"
11#include "core/hle/kernel/server_session.h"
8#include "core/hle/service/srv.h" 12#include "core/hle/service/srv.h"
9 13
10namespace Service { 14namespace Service {
@@ -79,7 +83,15 @@ static void GetServiceHandle(Interface* self) {
79 auto it = Service::g_srv_services.find(port_name); 83 auto it = Service::g_srv_services.find(port_name);
80 84
81 if (it != Service::g_srv_services.end()) { 85 if (it != Service::g_srv_services.end()) {
82 cmd_buff[3] = Kernel::g_handle_table.Create(it->second).MoveFrom(); 86 auto client_port = it->second;
87
88 auto client_session = client_port->Connect();
89 res = client_session.Code();
90
91 if (client_session.Succeeded()) {
92 // Return the client session
93 cmd_buff[3] = Kernel::g_handle_table.Create(*client_session).MoveFrom();
94 }
83 LOG_TRACE(Service_SRV, "called port=%s, handle=0x%08X", port_name.c_str(), cmd_buff[3]); 95 LOG_TRACE(Service_SRV, "called port=%s, handle=0x%08X", port_name.c_str(), cmd_buff[3]);
84 } else { 96 } else {
85 LOG_ERROR(Service_SRV, "(UNIMPLEMENTED) called port=%s", port_name.c_str()); 97 LOG_ERROR(Service_SRV, "(UNIMPLEMENTED) called port=%s", port_name.c_str());
diff --git a/src/core/hle/svc.cpp b/src/core/hle/svc.cpp
index c6b80dc50..e5ba9a484 100644
--- a/src/core/hle/svc.cpp
+++ b/src/core/hle/svc.cpp
@@ -13,6 +13,7 @@
13#include "core/hle/function_wrappers.h" 13#include "core/hle/function_wrappers.h"
14#include "core/hle/kernel/address_arbiter.h" 14#include "core/hle/kernel/address_arbiter.h"
15#include "core/hle/kernel/client_port.h" 15#include "core/hle/kernel/client_port.h"
16#include "core/hle/kernel/client_session.h"
16#include "core/hle/kernel/event.h" 17#include "core/hle/kernel/event.h"
17#include "core/hle/kernel/memory.h" 18#include "core/hle/kernel/memory.h"
18#include "core/hle/kernel/mutex.h" 19#include "core/hle/kernel/mutex.h"
@@ -20,6 +21,7 @@
20#include "core/hle/kernel/resource_limit.h" 21#include "core/hle/kernel/resource_limit.h"
21#include "core/hle/kernel/semaphore.h" 22#include "core/hle/kernel/semaphore.h"
22#include "core/hle/kernel/server_port.h" 23#include "core/hle/kernel/server_port.h"
24#include "core/hle/kernel/server_session.h"
23#include "core/hle/kernel/shared_memory.h" 25#include "core/hle/kernel/shared_memory.h"
24#include "core/hle/kernel/thread.h" 26#include "core/hle/kernel/thread.h"
25#include "core/hle/kernel/timer.h" 27#include "core/hle/kernel/timer.h"
@@ -222,20 +224,29 @@ static ResultCode ConnectToPort(Handle* out_handle, const char* port_name) {
222 return ERR_NOT_FOUND; 224 return ERR_NOT_FOUND;
223 } 225 }
224 226
225 CASCADE_RESULT(*out_handle, Kernel::g_handle_table.Create(it->second)); 227 auto client_port = it->second;
228
229 SharedPtr<Kernel::ClientSession> client_session;
230 CASCADE_RESULT(client_session, client_port->Connect());
231
232 // Return the client session
233 CASCADE_RESULT(*out_handle, Kernel::g_handle_table.Create(client_session));
226 return RESULT_SUCCESS; 234 return RESULT_SUCCESS;
227} 235}
228 236
229/// Synchronize to an OS service 237/// Makes a blocking IPC call to an OS service.
230static ResultCode SendSyncRequest(Handle handle) { 238static ResultCode SendSyncRequest(Handle handle) {
231 SharedPtr<Kernel::Session> session = Kernel::g_handle_table.Get<Kernel::Session>(handle); 239 SharedPtr<Kernel::ClientSession> session =
240 Kernel::g_handle_table.Get<Kernel::ClientSession>(handle);
232 if (session == nullptr) { 241 if (session == nullptr) {
233 return ERR_INVALID_HANDLE; 242 return ERR_INVALID_HANDLE;
234 } 243 }
235 244
236 LOG_TRACE(Kernel_SVC, "called handle=0x%08X(%s)", handle, session->GetName().c_str()); 245 LOG_TRACE(Kernel_SVC, "called handle=0x%08X(%s)", handle, session->GetName().c_str());
237 246
238 return session->SyncRequest().Code(); 247 // TODO(Subv): svcSendSyncRequest should put the caller thread to sleep while the server
248 // responds and cause a reschedule.
249 return session->SendSyncRequest();
239} 250}
240 251
241/// Close a handle 252/// Close a handle