summaryrefslogtreecommitdiff
path: root/src/core/hle/kernel
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/kernel
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/kernel')
-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/kernel/session.h218
10 files changed, 355 insertions, 241 deletions
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/kernel/session.h b/src/core/hle/kernel/session.h
deleted file mode 100644
index ec025f732..000000000
--- a/src/core/hle/kernel/session.h
+++ /dev/null
@@ -1,218 +0,0 @@
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/memory.h"
14
15namespace IPC {
16
17enum DescriptorType : u32 {
18 // Buffer related desciptors types (mask : 0x0F)
19 StaticBuffer = 0x02,
20 PXIBuffer = 0x04,
21 MappedBuffer = 0x08,
22 // Handle related descriptors types (mask : 0x30, but need to check for buffer related
23 // descriptors first )
24 CopyHandle = 0x00,
25 MoveHandle = 0x10,
26 CallingPid = 0x20,
27};
28
29/**
30 * @brief Creates a command header to be used for IPC
31 * @param command_id ID of the command to create a header for.
32 * @param normal_params Size of the normal parameters in words. Up to 63.
33 * @param translate_params_size Size of the translate parameters in words. Up to 63.
34 * @return The created IPC header.
35 *
36 * Normal parameters are sent directly to the process while the translate parameters might go
37 * through modifications and checks by the kernel.
38 * The translate parameters are described by headers generated with the IPC::*Desc functions.
39 *
40 * @note While #normal_params is equivalent to the number of normal parameters,
41 * #translate_params_size includes the size occupied by the translate parameters headers.
42 */
43constexpr u32 MakeHeader(u16 command_id, unsigned int normal_params,
44 unsigned int translate_params_size) {
45 return (u32(command_id) << 16) | ((u32(normal_params) & 0x3F) << 6) |
46 (u32(translate_params_size) & 0x3F);
47}
48
49union Header {
50 u32 raw;
51 BitField<0, 6, u32> translate_params_size;
52 BitField<6, 6, u32> normal_params;
53 BitField<16, 16, u32> command_id;
54};
55
56inline Header ParseHeader(u32 header) {
57 return {header};
58}
59
60constexpr u32 MoveHandleDesc(u32 num_handles = 1) {
61 return MoveHandle | ((num_handles - 1) << 26);
62}
63
64constexpr u32 CopyHandleDesc(u32 num_handles = 1) {
65 return CopyHandle | ((num_handles - 1) << 26);
66}
67
68constexpr u32 CallingPidDesc() {
69 return CallingPid;
70}
71
72constexpr bool isHandleDescriptor(u32 descriptor) {
73 return (descriptor & 0xF) == 0x0;
74}
75
76constexpr u32 HandleNumberFromDesc(u32 handle_descriptor) {
77 return (handle_descriptor >> 26) + 1;
78}
79
80constexpr u32 StaticBufferDesc(u32 size, u8 buffer_id) {
81 return StaticBuffer | (size << 14) | ((buffer_id & 0xF) << 10);
82}
83
84union StaticBufferDescInfo {
85 u32 raw;
86 BitField<10, 4, u32> buffer_id;
87 BitField<14, 18, u32> size;
88};
89
90inline StaticBufferDescInfo ParseStaticBufferDesc(const u32 desc) {
91 return {desc};
92}
93
94/**
95 * @brief Creates a header describing a buffer to be sent over PXI.
96 * @param size Size of the buffer. Max 0x00FFFFFF.
97 * @param buffer_id The Id of the buffer. Max 0xF.
98 * @param is_read_only true if the buffer is read-only. If false, the buffer is considered to have
99 * read-write access.
100 * @return The created PXI buffer header.
101 *
102 * The next value is a phys-address of a table located in the BASE memregion.
103 */
104inline u32 PXIBufferDesc(u32 size, unsigned buffer_id, bool is_read_only) {
105 u32 type = PXIBuffer;
106 if (is_read_only)
107 type |= 0x2;
108 return type | (size << 8) | ((buffer_id & 0xF) << 4);
109}
110
111enum MappedBufferPermissions {
112 R = 1,
113 W = 2,
114 RW = R | W,
115};
116
117constexpr u32 MappedBufferDesc(u32 size, MappedBufferPermissions perms) {
118 return MappedBuffer | (size << 4) | (u32(perms) << 1);
119}
120
121union MappedBufferDescInfo {
122 u32 raw;
123 BitField<4, 28, u32> size;
124 BitField<1, 2, MappedBufferPermissions> perms;
125};
126
127inline MappedBufferDescInfo ParseMappedBufferDesc(const u32 desc) {
128 return {desc};
129}
130
131inline DescriptorType GetDescriptorType(u32 descriptor) {
132 // Note: Those checks must be done in this order
133 if (isHandleDescriptor(descriptor))
134 return (DescriptorType)(descriptor & 0x30);
135
136 // handle the fact that the following descriptors can have rights
137 if (descriptor & MappedBuffer)
138 return MappedBuffer;
139
140 if (descriptor & PXIBuffer)
141 return PXIBuffer;
142
143 return StaticBuffer;
144}
145
146} // 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}