summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/core/hle/kernel/hle_ipc.cpp94
-rw-r--r--src/core/hle/kernel/hle_ipc.h37
-rw-r--r--src/core/hle/service/service.cpp17
3 files changed, 130 insertions, 18 deletions
diff --git a/src/core/hle/kernel/hle_ipc.cpp b/src/core/hle/kernel/hle_ipc.cpp
index 5a74645c7..656405dd6 100644
--- a/src/core/hle/kernel/hle_ipc.cpp
+++ b/src/core/hle/kernel/hle_ipc.cpp
@@ -8,6 +8,7 @@
8#include "core/hle/kernel/handle_table.h" 8#include "core/hle/kernel/handle_table.h"
9#include "core/hle/kernel/hle_ipc.h" 9#include "core/hle/kernel/hle_ipc.h"
10#include "core/hle/kernel/kernel.h" 10#include "core/hle/kernel/kernel.h"
11#include "core/hle/kernel/process.h"
11#include "core/hle/kernel/server_session.h" 12#include "core/hle/kernel/server_session.h"
12 13
13namespace Kernel { 14namespace Kernel {
@@ -24,12 +25,97 @@ void SessionRequestHandler::ClientDisconnected(SharedPtr<ServerSession> server_s
24 25
25HLERequestContext::~HLERequestContext() = default; 26HLERequestContext::~HLERequestContext() = default;
26 27
27SharedPtr<Object> HLERequestContext::GetIncomingHandle(Handle id_from_cmdbuf) const { 28SharedPtr<Object> HLERequestContext::GetIncomingHandle(u32 id_from_cmdbuf) const {
28 return Kernel::g_handle_table.GetGeneric(id_from_cmdbuf); 29 ASSERT(id_from_cmdbuf < request_handles.size());
30 return request_handles[id_from_cmdbuf];
29} 31}
30 32
31Handle HLERequestContext::AddOutgoingHandle(SharedPtr<Object> object) { 33u32 HLERequestContext::AddOutgoingHandle(SharedPtr<Object> object) {
32 return Kernel::g_handle_table.Create(object).Unwrap(); 34 request_handles.push_back(std::move(object));
35 return request_handles.size() - 1;
36}
37
38ResultCode HLERequestContext::PopulateFromIncomingCommandBuffer(const u32_le* src_cmdbuf,
39 Process& src_process,
40 HandleTable& src_table) {
41 IPC::Header header{src_cmdbuf[0]};
42
43 size_t untranslated_size = 1u + header.normal_params_size;
44 size_t command_size = untranslated_size + header.translate_params_size;
45 ASSERT(command_size <= IPC::COMMAND_BUFFER_LENGTH); // TODO(yuriks): Return error
46
47 std::copy_n(src_cmdbuf, untranslated_size, cmd_buf.begin());
48
49 size_t i = untranslated_size;
50 while (i < command_size) {
51 u32 descriptor = cmd_buf[i] = src_cmdbuf[i];
52 i += 1;
53
54 switch (IPC::GetDescriptorType(descriptor)) {
55 case IPC::DescriptorType::CopyHandle:
56 case IPC::DescriptorType::MoveHandle: {
57 u32 num_handles = IPC::HandleNumberFromDesc(descriptor);
58 ASSERT(i + num_handles <= command_size); // TODO(yuriks): Return error
59 for (u32 j = 0; j < num_handles; ++j) {
60 Handle handle = src_cmdbuf[i];
61 SharedPtr<Object> object = src_table.GetGeneric(handle);
62 ASSERT(object != nullptr); // TODO(yuriks): Return error
63 if (descriptor == IPC::DescriptorType::MoveHandle) {
64 src_table.Close(handle);
65 }
66
67 cmd_buf[i++] = AddOutgoingHandle(std::move(object));
68 }
69 break;
70 }
71 case IPC::DescriptorType::CallingPid: {
72 cmd_buf[i++] = src_process.process_id;
73 break;
74 }
75 default:
76 UNIMPLEMENTED_MSG("Unsupported handle translation: 0x%08X", descriptor);
77 }
78 }
79
80 return RESULT_SUCCESS;
81}
82
83ResultCode HLERequestContext::WriteToOutgoingCommandBuffer(u32_le* dst_cmdbuf, Process& dst_process,
84 HandleTable& dst_table) const {
85 IPC::Header header{cmd_buf[0]};
86
87 size_t untranslated_size = 1u + header.normal_params_size;
88 size_t command_size = untranslated_size + header.translate_params_size;
89 ASSERT(command_size <= IPC::COMMAND_BUFFER_LENGTH);
90
91 std::copy_n(cmd_buf.begin(), untranslated_size, dst_cmdbuf);
92
93 size_t i = untranslated_size;
94 while (i < command_size) {
95 u32 descriptor = dst_cmdbuf[i] = cmd_buf[i];
96 i += 1;
97
98 switch (IPC::GetDescriptorType(descriptor)) {
99 case IPC::DescriptorType::CopyHandle:
100 case IPC::DescriptorType::MoveHandle: {
101 // HLE services don't use handles, so we treat both CopyHandle and MoveHandle equally
102 u32 num_handles = IPC::HandleNumberFromDesc(descriptor);
103 ASSERT(i + num_handles <= command_size);
104 for (u32 j = 0; j < num_handles; ++j) {
105 SharedPtr<Object> object = GetIncomingHandle(cmd_buf[i]);
106
107 // TODO(yuriks): Figure out the proper error handling for if this fails
108 Handle handle = dst_table.Create(object).Unwrap();
109 dst_cmdbuf[i++] = handle;
110 }
111 break;
112 }
113 default:
114 UNIMPLEMENTED_MSG("Unsupported handle translation: 0x%08X", descriptor);
115 }
116 }
117
118 return RESULT_SUCCESS;
33} 119}
34 120
35} // namespace Kernel 121} // namespace Kernel
diff --git a/src/core/hle/kernel/hle_ipc.h b/src/core/hle/kernel/hle_ipc.h
index f23daa7ea..d6ebf113c 100644
--- a/src/core/hle/kernel/hle_ipc.h
+++ b/src/core/hle/kernel/hle_ipc.h
@@ -8,6 +8,7 @@
8#include <memory> 8#include <memory>
9#include <vector> 9#include <vector>
10#include "common/common_types.h" 10#include "common/common_types.h"
11#include "common/swap.h"
11#include "core/hle/ipc.h" 12#include "core/hle/ipc.h"
12#include "core/hle/kernel/kernel.h" 13#include "core/hle/kernel/kernel.h"
13#include "core/hle/kernel/server_session.h" 14#include "core/hle/kernel/server_session.h"
@@ -18,6 +19,9 @@ class ServiceFrameworkBase;
18 19
19namespace Kernel { 20namespace Kernel {
20 21
22class HandleTable;
23class Process;
24
21/** 25/**
22 * Interface implemented by HLE Session handlers. 26 * Interface implemented by HLE Session handlers.
23 * This can be provided to a ServerSession in order to hook into several relevant events 27 * This can be provided to a ServerSession in order to hook into several relevant events
@@ -62,6 +66,20 @@ protected:
62 * Class containing information about an in-flight IPC request being handled by an HLE service 66 * Class containing information about an in-flight IPC request being handled by an HLE service
63 * implementation. Services should avoid using old global APIs (e.g. Kernel::GetCommandBuffer()) and 67 * implementation. Services should avoid using old global APIs (e.g. Kernel::GetCommandBuffer()) and
64 * when possible use the APIs in this class to service the request. 68 * when possible use the APIs in this class to service the request.
69 *
70 * HLE handle protocol
71 * ===================
72 *
73 * To avoid needing HLE services to keep a separate handle table, or having to directly modify the
74 * requester's table, a tweaked protocol is used to receive and send handles in requests. The kernel
75 * will decode the incoming handles into object pointers and insert a id in the buffer where the
76 * handle would normally be. The service then calls GetIncomingHandle() with that id to get the
77 * pointer to the object. Similarly, instead of inserting a handle into the command buffer, the
78 * service calls AddOutgoingHandle() and stores the returned id where the handle would normally go.
79 *
80 * The end result is similar to just giving services their own real handle tables, but since these
81 * ids are local to a specific context, it avoids requiring services to manage handles for objects
82 * across multiple calls and ensuring that unneeded handles are cleaned up.
65 */ 83 */
66class HLERequestContext { 84class HLERequestContext {
67public: 85public:
@@ -80,14 +98,29 @@ public:
80 return session; 98 return session;
81 } 99 }
82 100
83 SharedPtr<Object> GetIncomingHandle(Handle id_from_cmdbuf) const; 101 /**
84 Handle AddOutgoingHandle(SharedPtr<Object> object); 102 * Resolves a object id from the request command buffer into a pointer to an object. See the
103 * "HLE handle protocol" section in the class documentation for more details.
104 */
105 SharedPtr<Object> GetIncomingHandle(u32 id_from_cmdbuf) const;
106
107 /**
108 * Adds an outgoing object to the response, returning the id which should be used to reference
109 * it. See the "HLE handle protocol" section in the class documentation for more details.
110 */
111 u32 AddOutgoingHandle(SharedPtr<Object> object);
85 112
86private: 113private:
87 friend class Service::ServiceFrameworkBase; 114 friend class Service::ServiceFrameworkBase;
88 115
116 ResultCode PopulateFromIncomingCommandBuffer(const u32_le* src_cmdbuf, Process& src_process,
117 HandleTable& src_table);
118 ResultCode WriteToOutgoingCommandBuffer(u32_le* dst_cmdbuf, Process& dst_process,
119 HandleTable& dst_table) const;
120
89 std::array<u32, IPC::COMMAND_BUFFER_LENGTH> cmd_buf; 121 std::array<u32, IPC::COMMAND_BUFFER_LENGTH> cmd_buf;
90 SharedPtr<ServerSession> session; 122 SharedPtr<ServerSession> session;
123 std::vector<SharedPtr<Object>> request_handles;
91}; 124};
92 125
93} // namespace Kernel 126} // namespace Kernel
diff --git a/src/core/hle/service/service.cpp b/src/core/hle/service/service.cpp
index 35582b0ff..791a65c19 100644
--- a/src/core/hle/service/service.cpp
+++ b/src/core/hle/service/service.cpp
@@ -9,6 +9,7 @@
9#include "common/string_util.h" 9#include "common/string_util.h"
10#include "core/hle/ipc.h" 10#include "core/hle/ipc.h"
11#include "core/hle/kernel/client_port.h" 11#include "core/hle/kernel/client_port.h"
12#include "core/hle/kernel/process.h"
12#include "core/hle/kernel/server_port.h" 13#include "core/hle/kernel/server_port.h"
13#include "core/hle/kernel/server_session.h" 14#include "core/hle/kernel/server_session.h"
14#include "core/hle/service/ac/ac.h" 15#include "core/hle/service/ac/ac.h"
@@ -172,24 +173,16 @@ void ServiceFrameworkBase::HandleSyncRequest(SharedPtr<ServerSession> server_ses
172 173
173 // TODO(yuriks): The kernel should be the one handling this as part of translation after 174 // TODO(yuriks): The kernel should be the one handling this as part of translation after
174 // everything else is migrated 175 // everything else is migrated
175 IPC::Header request_header{cmd_buf[0]};
176 size_t request_size =
177 1 + request_header.normal_params_size + request_header.translate_params_size;
178 ASSERT(request_size <= IPC::COMMAND_BUFFER_LENGTH); // TODO(yuriks): Return error
179
180 Kernel::HLERequestContext context; 176 Kernel::HLERequestContext context;
181 std::copy_n(cmd_buf, request_size, context.cmd_buf.begin());
182 context.session = std::move(server_session); 177 context.session = std::move(server_session);
178 context.PopulateFromIncomingCommandBuffer(cmd_buf, *Kernel::g_current_process,
179 Kernel::g_handle_table);
183 180
184 LOG_TRACE(Service, "%s", 181 LOG_TRACE(Service, "%s",
185 MakeFunctionString(info->name, GetServiceName().c_str(), cmd_buf).c_str()); 182 MakeFunctionString(info->name, GetServiceName().c_str(), cmd_buf).c_str());
186 handler_invoker(this, info->handler_callback, context); 183 handler_invoker(this, info->handler_callback, context);
187 184 context.WriteToOutgoingCommandBuffer(cmd_buf, *Kernel::g_current_process,
188 IPC::Header response_header{context.cmd_buf[0]}; 185 Kernel::g_handle_table);
189 size_t response_size =
190 1 + response_header.normal_params_size + response_header.translate_params_size;
191 ASSERT(response_size <= IPC::COMMAND_BUFFER_LENGTH);
192 std::copy_n(context.cmd_buf.begin(), response_size, cmd_buf);
193} 186}
194 187
195//////////////////////////////////////////////////////////////////////////////////////////////////// 188////////////////////////////////////////////////////////////////////////////////////////////////////