summaryrefslogtreecommitdiff
path: root/src/core/hle/kernel
diff options
context:
space:
mode:
Diffstat (limited to 'src/core/hle/kernel')
-rw-r--r--src/core/hle/kernel/hle_ipc.cpp99
-rw-r--r--src/core/hle/kernel/hle_ipc.h54
2 files changed, 150 insertions, 3 deletions
diff --git a/src/core/hle/kernel/hle_ipc.cpp b/src/core/hle/kernel/hle_ipc.cpp
index a60b8ef00..6cf1886cf 100644
--- a/src/core/hle/kernel/hle_ipc.cpp
+++ b/src/core/hle/kernel/hle_ipc.cpp
@@ -5,8 +5,10 @@
5#include <boost/range/algorithm_ext/erase.hpp> 5#include <boost/range/algorithm_ext/erase.hpp>
6#include "common/assert.h" 6#include "common/assert.h"
7#include "common/common_types.h" 7#include "common/common_types.h"
8#include "core/hle/kernel/handle_table.h"
8#include "core/hle/kernel/hle_ipc.h" 9#include "core/hle/kernel/hle_ipc.h"
9#include "core/hle/kernel/kernel.h" 10#include "core/hle/kernel/kernel.h"
11#include "core/hle/kernel/process.h"
10#include "core/hle/kernel/server_session.h" 12#include "core/hle/kernel/server_session.h"
11 13
12namespace Kernel { 14namespace Kernel {
@@ -23,4 +25,101 @@ void SessionRequestHandler::ClientDisconnected(SharedPtr<ServerSession> server_s
23 25
24HLERequestContext::~HLERequestContext() = default; 26HLERequestContext::~HLERequestContext() = default;
25 27
28SharedPtr<Object> HLERequestContext::GetIncomingHandle(u32 id_from_cmdbuf) const {
29 ASSERT(id_from_cmdbuf < request_handles.size());
30 return request_handles[id_from_cmdbuf];
31}
32
33u32 HLERequestContext::AddOutgoingHandle(SharedPtr<Object> object) {
34 request_handles.push_back(std::move(object));
35 return request_handles.size() - 1;
36}
37
38void HLERequestContext::ClearIncomingObjects() {
39 request_handles.clear();
40}
41
42ResultCode HLERequestContext::PopulateFromIncomingCommandBuffer(const u32_le* src_cmdbuf,
43 Process& src_process,
44 HandleTable& src_table) {
45 IPC::Header header{src_cmdbuf[0]};
46
47 size_t untranslated_size = 1u + header.normal_params_size;
48 size_t command_size = untranslated_size + header.translate_params_size;
49 ASSERT(command_size <= IPC::COMMAND_BUFFER_LENGTH); // TODO(yuriks): Return error
50
51 std::copy_n(src_cmdbuf, untranslated_size, cmd_buf.begin());
52
53 size_t i = untranslated_size;
54 while (i < command_size) {
55 u32 descriptor = cmd_buf[i] = src_cmdbuf[i];
56 i += 1;
57
58 switch (IPC::GetDescriptorType(descriptor)) {
59 case IPC::DescriptorType::CopyHandle:
60 case IPC::DescriptorType::MoveHandle: {
61 u32 num_handles = IPC::HandleNumberFromDesc(descriptor);
62 ASSERT(i + num_handles <= command_size); // TODO(yuriks): Return error
63 for (u32 j = 0; j < num_handles; ++j) {
64 Handle handle = src_cmdbuf[i];
65 SharedPtr<Object> object = src_table.GetGeneric(handle);
66 ASSERT(object != nullptr); // TODO(yuriks): Return error
67 if (descriptor == IPC::DescriptorType::MoveHandle) {
68 src_table.Close(handle);
69 }
70
71 cmd_buf[i++] = AddOutgoingHandle(std::move(object));
72 }
73 break;
74 }
75 case IPC::DescriptorType::CallingPid: {
76 cmd_buf[i++] = src_process.process_id;
77 break;
78 }
79 default:
80 UNIMPLEMENTED_MSG("Unsupported handle translation: 0x%08X", descriptor);
81 }
82 }
83
84 return RESULT_SUCCESS;
85}
86
87ResultCode HLERequestContext::WriteToOutgoingCommandBuffer(u32_le* dst_cmdbuf, Process& dst_process,
88 HandleTable& dst_table) const {
89 IPC::Header header{cmd_buf[0]};
90
91 size_t untranslated_size = 1u + header.normal_params_size;
92 size_t command_size = untranslated_size + header.translate_params_size;
93 ASSERT(command_size <= IPC::COMMAND_BUFFER_LENGTH);
94
95 std::copy_n(cmd_buf.begin(), untranslated_size, dst_cmdbuf);
96
97 size_t i = untranslated_size;
98 while (i < command_size) {
99 u32 descriptor = dst_cmdbuf[i] = cmd_buf[i];
100 i += 1;
101
102 switch (IPC::GetDescriptorType(descriptor)) {
103 case IPC::DescriptorType::CopyHandle:
104 case IPC::DescriptorType::MoveHandle: {
105 // HLE services don't use handles, so we treat both CopyHandle and MoveHandle equally
106 u32 num_handles = IPC::HandleNumberFromDesc(descriptor);
107 ASSERT(i + num_handles <= command_size);
108 for (u32 j = 0; j < num_handles; ++j) {
109 SharedPtr<Object> object = GetIncomingHandle(cmd_buf[i]);
110
111 // TODO(yuriks): Figure out the proper error handling for if this fails
112 Handle handle = dst_table.Create(object).Unwrap();
113 dst_cmdbuf[i++] = handle;
114 }
115 break;
116 }
117 default:
118 UNIMPLEMENTED_MSG("Unsupported handle translation: 0x%08X", descriptor);
119 }
120 }
121
122 return RESULT_SUCCESS;
123}
124
26} // namespace Kernel 125} // namespace Kernel
diff --git a/src/core/hle/kernel/hle_ipc.h b/src/core/hle/kernel/hle_ipc.h
index c30184eab..cbb109d8f 100644
--- a/src/core/hle/kernel/hle_ipc.h
+++ b/src/core/hle/kernel/hle_ipc.h
@@ -4,8 +4,13 @@
4 4
5#pragma once 5#pragma once
6 6
7#include <array>
7#include <memory> 8#include <memory>
8#include <vector> 9#include <vector>
10#include <boost/container/small_vector.hpp>
11#include "common/common_types.h"
12#include "common/swap.h"
13#include "core/hle/ipc.h"
9#include "core/hle/kernel/kernel.h" 14#include "core/hle/kernel/kernel.h"
10#include "core/hle/kernel/server_session.h" 15#include "core/hle/kernel/server_session.h"
11 16
@@ -15,6 +20,9 @@ class ServiceFrameworkBase;
15 20
16namespace Kernel { 21namespace Kernel {
17 22
23class HandleTable;
24class Process;
25
18/** 26/**
19 * Interface implemented by HLE Session handlers. 27 * Interface implemented by HLE Session handlers.
20 * This can be provided to a ServerSession in order to hook into several relevant events 28 * This can be provided to a ServerSession in order to hook into several relevant events
@@ -59,14 +67,28 @@ protected:
59 * Class containing information about an in-flight IPC request being handled by an HLE service 67 * Class containing information about an in-flight IPC request being handled by an HLE service
60 * implementation. Services should avoid using old global APIs (e.g. Kernel::GetCommandBuffer()) and 68 * implementation. Services should avoid using old global APIs (e.g. Kernel::GetCommandBuffer()) and
61 * when possible use the APIs in this class to service the request. 69 * when possible use the APIs in this class to service the request.
70 *
71 * HLE handle protocol
72 * ===================
73 *
74 * To avoid needing HLE services to keep a separate handle table, or having to directly modify the
75 * requester's table, a tweaked protocol is used to receive and send handles in requests. The kernel
76 * will decode the incoming handles into object pointers and insert a id in the buffer where the
77 * handle would normally be. The service then calls GetIncomingHandle() with that id to get the
78 * pointer to the object. Similarly, instead of inserting a handle into the command buffer, the
79 * service calls AddOutgoingHandle() and stores the returned id where the handle would normally go.
80 *
81 * The end result is similar to just giving services their own real handle tables, but since these
82 * ids are local to a specific context, it avoids requiring services to manage handles for objects
83 * across multiple calls and ensuring that unneeded handles are cleaned up.
62 */ 84 */
63class HLERequestContext { 85class HLERequestContext {
64public: 86public:
65 ~HLERequestContext(); 87 ~HLERequestContext();
66 88
67 /// Returns a pointer to the IPC command buffer for this request. 89 /// Returns a pointer to the IPC command buffer for this request.
68 u32* CommandBuffer() const { 90 u32* CommandBuffer() {
69 return cmd_buf; 91 return cmd_buf.data();
70 } 92 }
71 93
72 /** 94 /**
@@ -77,11 +99,37 @@ public:
77 return session; 99 return session;
78 } 100 }
79 101
102 /**
103 * Resolves a object id from the request command buffer into a pointer to an object. See the
104 * "HLE handle protocol" section in the class documentation for more details.
105 */
106 SharedPtr<Object> GetIncomingHandle(u32 id_from_cmdbuf) const;
107
108 /**
109 * Adds an outgoing object to the response, returning the id which should be used to reference
110 * it. See the "HLE handle protocol" section in the class documentation for more details.
111 */
112 u32 AddOutgoingHandle(SharedPtr<Object> object);
113
114 /**
115 * Discards all Objects from the context, invalidating all ids. This may be called after reading
116 * out all incoming objects, so that the buffer memory can be re-used for outgoing handles, but
117 * this is not required.
118 */
119 void ClearIncomingObjects();
120
80private: 121private:
81 friend class Service::ServiceFrameworkBase; 122 friend class Service::ServiceFrameworkBase;
82 123
83 u32* cmd_buf = nullptr; 124 ResultCode PopulateFromIncomingCommandBuffer(const u32_le* src_cmdbuf, Process& src_process,
125 HandleTable& src_table);
126 ResultCode WriteToOutgoingCommandBuffer(u32_le* dst_cmdbuf, Process& dst_process,
127 HandleTable& dst_table) const;
128
129 std::array<u32, IPC::COMMAND_BUFFER_LENGTH> cmd_buf;
84 SharedPtr<ServerSession> session; 130 SharedPtr<ServerSession> session;
131 // TODO(yuriks): Check common usage of this and optimize size accordingly
132 boost::container::small_vector<SharedPtr<Object>, 8> request_handles;
85}; 133};
86 134
87} // namespace Kernel 135} // namespace Kernel