summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/core/hle/kernel/hle_ipc.cpp5
-rw-r--r--src/core/hle/kernel/hle_ipc.h7
-rw-r--r--src/core/hle/service/nwm/nwm_uds.cpp36
-rw-r--r--src/core/hle/service/service.cpp3
-rw-r--r--src/tests/CMakeLists.txt5
-rw-r--r--src/tests/core/hle/kernel/hle_ipc.cpp193
6 files changed, 242 insertions, 7 deletions
diff --git a/src/core/hle/kernel/hle_ipc.cpp b/src/core/hle/kernel/hle_ipc.cpp
index 6cf1886cf..1cac1d0c9 100644
--- a/src/core/hle/kernel/hle_ipc.cpp
+++ b/src/core/hle/kernel/hle_ipc.cpp
@@ -23,6 +23,11 @@ void SessionRequestHandler::ClientDisconnected(SharedPtr<ServerSession> server_s
23 boost::range::remove_erase(connected_sessions, server_session); 23 boost::range::remove_erase(connected_sessions, server_session);
24} 24}
25 25
26HLERequestContext::HLERequestContext(SharedPtr<ServerSession> session)
27 : session(std::move(session)) {
28 cmd_buf[0] = 0;
29}
30
26HLERequestContext::~HLERequestContext() = default; 31HLERequestContext::~HLERequestContext() = default;
27 32
28SharedPtr<Object> HLERequestContext::GetIncomingHandle(u32 id_from_cmdbuf) const { 33SharedPtr<Object> HLERequestContext::GetIncomingHandle(u32 id_from_cmdbuf) const {
diff --git a/src/core/hle/kernel/hle_ipc.h b/src/core/hle/kernel/hle_ipc.h
index cbb109d8f..35795fc1d 100644
--- a/src/core/hle/kernel/hle_ipc.h
+++ b/src/core/hle/kernel/hle_ipc.h
@@ -84,6 +84,7 @@ protected:
84 */ 84 */
85class HLERequestContext { 85class HLERequestContext {
86public: 86public:
87 HLERequestContext(SharedPtr<ServerSession> session);
87 ~HLERequestContext(); 88 ~HLERequestContext();
88 89
89 /// Returns a pointer to the IPC command buffer for this request. 90 /// Returns a pointer to the IPC command buffer for this request.
@@ -118,14 +119,14 @@ public:
118 */ 119 */
119 void ClearIncomingObjects(); 120 void ClearIncomingObjects();
120 121
121private: 122 /// Populates this context with data from the requesting process/thread.
122 friend class Service::ServiceFrameworkBase;
123
124 ResultCode PopulateFromIncomingCommandBuffer(const u32_le* src_cmdbuf, Process& src_process, 123 ResultCode PopulateFromIncomingCommandBuffer(const u32_le* src_cmdbuf, Process& src_process,
125 HandleTable& src_table); 124 HandleTable& src_table);
125 /// Writes data from this context back to the requesting process/thread.
126 ResultCode WriteToOutgoingCommandBuffer(u32_le* dst_cmdbuf, Process& dst_process, 126 ResultCode WriteToOutgoingCommandBuffer(u32_le* dst_cmdbuf, Process& dst_process,
127 HandleTable& dst_table) const; 127 HandleTable& dst_table) const;
128 128
129private:
129 std::array<u32, IPC::COMMAND_BUFFER_LENGTH> cmd_buf; 130 std::array<u32, IPC::COMMAND_BUFFER_LENGTH> cmd_buf;
130 SharedPtr<ServerSession> session; 131 SharedPtr<ServerSession> session;
131 // TODO(yuriks): Check common usage of this and optimize size accordingly 132 // TODO(yuriks): Check common usage of this and optimize size accordingly
diff --git a/src/core/hle/service/nwm/nwm_uds.cpp b/src/core/hle/service/nwm/nwm_uds.cpp
index 193c1a4c8..a7149c9e8 100644
--- a/src/core/hle/service/nwm/nwm_uds.cpp
+++ b/src/core/hle/service/nwm/nwm_uds.cpp
@@ -543,6 +543,42 @@ static void BeaconBroadcastCallback(u64 userdata, int cycles_late) {
543 beacon_broadcast_event, 0); 543 beacon_broadcast_event, 0);
544} 544}
545 545
546/*
547 * Returns an available index in the nodes array for the
548 * currently-hosted UDS network.
549 */
550static u32 GetNextAvailableNodeId() {
551 ASSERT_MSG(connection_status.status == static_cast<u32>(NetworkStatus::ConnectedAsHost),
552 "Can not accept clients if we're not hosting a network");
553
554 for (unsigned index = 0; index < connection_status.max_nodes; ++index) {
555 if ((connection_status.node_bitmask & (1 << index)) == 0)
556 return index;
557 }
558
559 // Any connection attempts to an already full network should have been refused.
560 ASSERT_MSG(false, "No available connection slots in the network");
561}
562
563/*
564 * Called when a client connects to an UDS network we're hosting,
565 * updates the connection status and signals the update event.
566 * @param network_node_id Network Node Id of the connecting client.
567 */
568void OnClientConnected(u16 network_node_id) {
569 ASSERT_MSG(connection_status.status == static_cast<u32>(NetworkStatus::ConnectedAsHost),
570 "Can not accept clients if we're not hosting a network");
571 ASSERT_MSG(connection_status.total_nodes < connection_status.max_nodes,
572 "Can not accept connections on a full network");
573
574 u32 node_id = GetNextAvailableNodeId();
575 connection_status.node_bitmask |= 1 << node_id;
576 connection_status.changed_nodes |= 1 << node_id;
577 connection_status.nodes[node_id] = network_node_id;
578 connection_status.total_nodes++;
579 connection_status_event->Signal();
580}
581
546const Interface::FunctionInfo FunctionTable[] = { 582const Interface::FunctionInfo FunctionTable[] = {
547 {0x00010442, nullptr, "Initialize (deprecated)"}, 583 {0x00010442, nullptr, "Initialize (deprecated)"},
548 {0x00020000, nullptr, "Scrap"}, 584 {0x00020000, nullptr, "Scrap"},
diff --git a/src/core/hle/service/service.cpp b/src/core/hle/service/service.cpp
index 04056d942..aad950e50 100644
--- a/src/core/hle/service/service.cpp
+++ b/src/core/hle/service/service.cpp
@@ -173,8 +173,7 @@ void ServiceFrameworkBase::HandleSyncRequest(SharedPtr<ServerSession> server_ses
173 173
174 // 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
175 // everything else is migrated 175 // everything else is migrated
176 Kernel::HLERequestContext context; 176 Kernel::HLERequestContext context(std::move(server_session));
177 context.session = std::move(server_session);
178 context.PopulateFromIncomingCommandBuffer(cmd_buf, *Kernel::g_current_process, 177 context.PopulateFromIncomingCommandBuffer(cmd_buf, *Kernel::g_current_process,
179 Kernel::g_handle_table); 178 Kernel::g_handle_table);
180 179
diff --git a/src/tests/CMakeLists.txt b/src/tests/CMakeLists.txt
index 00d7c636a..a14df325a 100644
--- a/src/tests/CMakeLists.txt
+++ b/src/tests/CMakeLists.txt
@@ -1,8 +1,9 @@
1set(SRCS 1set(SRCS
2 glad.cpp
3 tests.cpp
4 common/param_package.cpp 2 common/param_package.cpp
5 core/file_sys/path_parser.cpp 3 core/file_sys/path_parser.cpp
4 core/hle/kernel/hle_ipc.cpp
5 glad.cpp
6 tests.cpp
6 ) 7 )
7 8
8set(HEADERS 9set(HEADERS
diff --git a/src/tests/core/hle/kernel/hle_ipc.cpp b/src/tests/core/hle/kernel/hle_ipc.cpp
new file mode 100644
index 000000000..e07a28c5b
--- /dev/null
+++ b/src/tests/core/hle/kernel/hle_ipc.cpp
@@ -0,0 +1,193 @@
1// Copyright 2017 Citra Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include <catch.hpp>
6#include "core/hle/ipc.h"
7#include "core/hle/kernel/client_port.h"
8#include "core/hle/kernel/client_session.h"
9#include "core/hle/kernel/event.h"
10#include "core/hle/kernel/handle_table.h"
11#include "core/hle/kernel/hle_ipc.h"
12#include "core/hle/kernel/process.h"
13#include "core/hle/kernel/server_session.h"
14
15namespace Kernel {
16
17static SharedPtr<Object> MakeObject() {
18 return Event::Create(ResetType::OneShot);
19}
20
21TEST_CASE("HLERequestContext::PopoulateFromIncomingCommandBuffer", "[core][kernel]") {
22 auto session = std::get<SharedPtr<ServerSession>>(ServerSession::CreateSessionPair());
23 HLERequestContext context(std::move(session));
24
25 auto process = Process::Create(CodeSet::Create("", 0));
26 HandleTable handle_table;
27
28 SECTION("works with empty cmdbuf") {
29 const u32_le input[]{
30 IPC::MakeHeader(0x1234, 0, 0),
31 };
32
33 context.PopulateFromIncomingCommandBuffer(input, *process, handle_table);
34
35 REQUIRE(context.CommandBuffer()[0] == 0x12340000);
36 }
37
38 SECTION("translates regular params") {
39 const u32_le input[]{
40 IPC::MakeHeader(0, 3, 0), 0x12345678, 0x21122112, 0xAABBCCDD,
41 };
42
43 context.PopulateFromIncomingCommandBuffer(input, *process, handle_table);
44
45 auto* output = context.CommandBuffer();
46 REQUIRE(output[1] == 0x12345678);
47 REQUIRE(output[2] == 0x21122112);
48 REQUIRE(output[3] == 0xAABBCCDD);
49 }
50
51 SECTION("translates move handles") {
52 auto a = MakeObject();
53 Handle a_handle = handle_table.Create(a).Unwrap();
54 const u32_le input[]{
55 IPC::MakeHeader(0, 0, 2), IPC::MoveHandleDesc(1), a_handle,
56 };
57
58 context.PopulateFromIncomingCommandBuffer(input, *process, handle_table);
59
60 auto* output = context.CommandBuffer();
61 REQUIRE(context.GetIncomingHandle(output[2]) == a);
62 REQUIRE(handle_table.GetGeneric(a_handle) == nullptr);
63 }
64
65 SECTION("translates copy handles") {
66 auto a = MakeObject();
67 Handle a_handle = handle_table.Create(a).Unwrap();
68 const u32_le input[]{
69 IPC::MakeHeader(0, 0, 2), IPC::CopyHandleDesc(1), a_handle,
70 };
71
72 context.PopulateFromIncomingCommandBuffer(input, *process, handle_table);
73
74 auto* output = context.CommandBuffer();
75 REQUIRE(context.GetIncomingHandle(output[2]) == a);
76 REQUIRE(handle_table.GetGeneric(a_handle) == a);
77 }
78
79 SECTION("translates multi-handle descriptors") {
80 auto a = MakeObject();
81 auto b = MakeObject();
82 auto c = MakeObject();
83 const u32_le input[]{
84 IPC::MakeHeader(0, 0, 5), IPC::MoveHandleDesc(2),
85 handle_table.Create(a).Unwrap(), handle_table.Create(b).Unwrap(),
86 IPC::MoveHandleDesc(1), handle_table.Create(c).Unwrap(),
87 };
88
89 context.PopulateFromIncomingCommandBuffer(input, *process, handle_table);
90
91 auto* output = context.CommandBuffer();
92 REQUIRE(context.GetIncomingHandle(output[2]) == a);
93 REQUIRE(context.GetIncomingHandle(output[3]) == b);
94 REQUIRE(context.GetIncomingHandle(output[5]) == c);
95 }
96
97 SECTION("translates CallingPid descriptors") {
98 const u32_le input[]{
99 IPC::MakeHeader(0, 0, 2), IPC::CallingPidDesc(), 0x98989898,
100 };
101
102 context.PopulateFromIncomingCommandBuffer(input, *process, handle_table);
103
104 REQUIRE(context.CommandBuffer()[2] == process->process_id);
105 }
106
107 SECTION("translates mixed params") {
108 auto a = MakeObject();
109 const u32_le input[]{
110 IPC::MakeHeader(0, 2, 4),
111 0x12345678,
112 0xABCDEF00,
113 IPC::MoveHandleDesc(1),
114 handle_table.Create(a).Unwrap(),
115 IPC::CallingPidDesc(),
116 0,
117 };
118
119 context.PopulateFromIncomingCommandBuffer(input, *process, handle_table);
120
121 auto* output = context.CommandBuffer();
122 REQUIRE(output[1] == 0x12345678);
123 REQUIRE(output[2] == 0xABCDEF00);
124 REQUIRE(context.GetIncomingHandle(output[4]) == a);
125 REQUIRE(output[6] == process->process_id);
126 }
127}
128
129TEST_CASE("HLERequestContext::WriteToOutgoingCommandBuffer", "[core][kernel]") {
130 auto session = std::get<SharedPtr<ServerSession>>(ServerSession::CreateSessionPair());
131 HLERequestContext context(std::move(session));
132
133 auto process = Process::Create(CodeSet::Create("", 0));
134 HandleTable handle_table;
135 auto* input = context.CommandBuffer();
136 u32_le output[IPC::COMMAND_BUFFER_LENGTH];
137
138 SECTION("works with empty cmdbuf") {
139 input[0] = IPC::MakeHeader(0x1234, 0, 0);
140
141 context.WriteToOutgoingCommandBuffer(output, *process, handle_table);
142
143 REQUIRE(output[0] == 0x12340000);
144 }
145
146 SECTION("translates regular params") {
147 input[0] = IPC::MakeHeader(0, 3, 0);
148 input[1] = 0x12345678;
149 input[2] = 0x21122112;
150 input[3] = 0xAABBCCDD;
151
152 context.WriteToOutgoingCommandBuffer(output, *process, handle_table);
153
154 REQUIRE(output[1] == 0x12345678);
155 REQUIRE(output[2] == 0x21122112);
156 REQUIRE(output[3] == 0xAABBCCDD);
157 }
158
159 SECTION("translates move/copy handles") {
160 auto a = MakeObject();
161 auto b = MakeObject();
162 input[0] = IPC::MakeHeader(0, 0, 4);
163 input[1] = IPC::MoveHandleDesc(1);
164 input[2] = context.AddOutgoingHandle(a);
165 input[3] = IPC::CopyHandleDesc(1);
166 input[4] = context.AddOutgoingHandle(b);
167
168 context.WriteToOutgoingCommandBuffer(output, *process, handle_table);
169
170 REQUIRE(handle_table.GetGeneric(output[2]) == a);
171 REQUIRE(handle_table.GetGeneric(output[4]) == b);
172 }
173
174 SECTION("translates multi-handle descriptors") {
175 auto a = MakeObject();
176 auto b = MakeObject();
177 auto c = MakeObject();
178 input[0] = IPC::MakeHeader(0, 0, 5);
179 input[1] = IPC::MoveHandleDesc(2);
180 input[2] = context.AddOutgoingHandle(a);
181 input[3] = context.AddOutgoingHandle(b);
182 input[4] = IPC::CopyHandleDesc(1);
183 input[5] = context.AddOutgoingHandle(c);
184
185 context.WriteToOutgoingCommandBuffer(output, *process, handle_table);
186
187 REQUIRE(handle_table.GetGeneric(output[2]) == a);
188 REQUIRE(handle_table.GetGeneric(output[3]) == b);
189 REQUIRE(handle_table.GetGeneric(output[5]) == c);
190 }
191}
192
193} // namespace Kernel