summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to '')
-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
boost::range::remove_erase(connected_sessions, server_session);
}
+HLERequestContext::HLERequestContext(SharedPtr<ServerSession> session)
+ : session(std::move(session)) {
+ cmd_buf[0] = 0;
+}
+
HLERequestContext::~HLERequestContext() = default;
SharedPtr<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:
*/
class HLERequestContext {
public:
+ HLERequestContext(SharedPtr<ServerSession> session);
~HLERequestContext();
/// Returns a pointer to the IPC command buffer for this request.
@@ -118,14 +119,14 @@ public:
*/
void ClearIncomingObjects();
-private:
- friend class Service::ServiceFrameworkBase;
-
+ /// Populates this context with data from the requesting process/thread.
ResultCode PopulateFromIncomingCommandBuffer(const u32_le* src_cmdbuf, Process& src_process,
HandleTable& src_table);
+ /// Writes data from this context back to the requesting process/thread.
ResultCode WriteToOutgoingCommandBuffer(u32_le* dst_cmdbuf, Process& dst_process,
HandleTable& dst_table) const;
+private:
std::array<u32, IPC::COMMAND_BUFFER_LENGTH> cmd_buf;
SharedPtr<ServerSession> session;
// 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) {
beacon_broadcast_event, 0);
}
+/*
+ * Returns an available index in the nodes array for the
+ * currently-hosted UDS network.
+ */
+static u32 GetNextAvailableNodeId() {
+ ASSERT_MSG(connection_status.status == static_cast<u32>(NetworkStatus::ConnectedAsHost),
+ "Can not accept clients if we're not hosting a network");
+
+ for (unsigned index = 0; index < connection_status.max_nodes; ++index) {
+ if ((connection_status.node_bitmask & (1 << index)) == 0)
+ return index;
+ }
+
+ // Any connection attempts to an already full network should have been refused.
+ ASSERT_MSG(false, "No available connection slots in the network");
+}
+
+/*
+ * Called when a client connects to an UDS network we're hosting,
+ * updates the connection status and signals the update event.
+ * @param network_node_id Network Node Id of the connecting client.
+ */
+void OnClientConnected(u16 network_node_id) {
+ ASSERT_MSG(connection_status.status == static_cast<u32>(NetworkStatus::ConnectedAsHost),
+ "Can not accept clients if we're not hosting a network");
+ ASSERT_MSG(connection_status.total_nodes < connection_status.max_nodes,
+ "Can not accept connections on a full network");
+
+ u32 node_id = GetNextAvailableNodeId();
+ connection_status.node_bitmask |= 1 << node_id;
+ connection_status.changed_nodes |= 1 << node_id;
+ connection_status.nodes[node_id] = network_node_id;
+ connection_status.total_nodes++;
+ connection_status_event->Signal();
+}
+
const Interface::FunctionInfo FunctionTable[] = {
{0x00010442, nullptr, "Initialize (deprecated)"},
{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
// TODO(yuriks): The kernel should be the one handling this as part of translation after
// everything else is migrated
- Kernel::HLERequestContext context;
- context.session = std::move(server_session);
+ Kernel::HLERequestContext context(std::move(server_session));
context.PopulateFromIncomingCommandBuffer(cmd_buf, *Kernel::g_current_process,
Kernel::g_handle_table);
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 @@
set(SRCS
- glad.cpp
- tests.cpp
common/param_package.cpp
core/file_sys/path_parser.cpp
+ core/hle/kernel/hle_ipc.cpp
+ glad.cpp
+ tests.cpp
)
set(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 @@
+// Copyright 2017 Citra Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include <catch.hpp>
+#include "core/hle/ipc.h"
+#include "core/hle/kernel/client_port.h"
+#include "core/hle/kernel/client_session.h"
+#include "core/hle/kernel/event.h"
+#include "core/hle/kernel/handle_table.h"
+#include "core/hle/kernel/hle_ipc.h"
+#include "core/hle/kernel/process.h"
+#include "core/hle/kernel/server_session.h"
+
+namespace Kernel {
+
+static SharedPtr<Object> MakeObject() {
+ return Event::Create(ResetType::OneShot);
+}
+
+TEST_CASE("HLERequestContext::PopoulateFromIncomingCommandBuffer", "[core][kernel]") {
+ auto session = std::get<SharedPtr<ServerSession>>(ServerSession::CreateSessionPair());
+ HLERequestContext context(std::move(session));
+
+ auto process = Process::Create(CodeSet::Create("", 0));
+ HandleTable handle_table;
+
+ SECTION("works with empty cmdbuf") {
+ const u32_le input[]{
+ IPC::MakeHeader(0x1234, 0, 0),
+ };
+
+ context.PopulateFromIncomingCommandBuffer(input, *process, handle_table);
+
+ REQUIRE(context.CommandBuffer()[0] == 0x12340000);
+ }
+
+ SECTION("translates regular params") {
+ const u32_le input[]{
+ IPC::MakeHeader(0, 3, 0), 0x12345678, 0x21122112, 0xAABBCCDD,
+ };
+
+ context.PopulateFromIncomingCommandBuffer(input, *process, handle_table);
+
+ auto* output = context.CommandBuffer();
+ REQUIRE(output[1] == 0x12345678);
+ REQUIRE(output[2] == 0x21122112);
+ REQUIRE(output[3] == 0xAABBCCDD);
+ }
+
+ SECTION("translates move handles") {
+ auto a = MakeObject();
+ Handle a_handle = handle_table.Create(a).Unwrap();
+ const u32_le input[]{
+ IPC::MakeHeader(0, 0, 2), IPC::MoveHandleDesc(1), a_handle,
+ };
+
+ context.PopulateFromIncomingCommandBuffer(input, *process, handle_table);
+
+ auto* output = context.CommandBuffer();
+ REQUIRE(context.GetIncomingHandle(output[2]) == a);
+ REQUIRE(handle_table.GetGeneric(a_handle) == nullptr);
+ }
+
+ SECTION("translates copy handles") {
+ auto a = MakeObject();
+ Handle a_handle = handle_table.Create(a).Unwrap();
+ const u32_le input[]{
+ IPC::MakeHeader(0, 0, 2), IPC::CopyHandleDesc(1), a_handle,
+ };
+
+ context.PopulateFromIncomingCommandBuffer(input, *process, handle_table);
+
+ auto* output = context.CommandBuffer();
+ REQUIRE(context.GetIncomingHandle(output[2]) == a);
+ REQUIRE(handle_table.GetGeneric(a_handle) == a);
+ }
+
+ SECTION("translates multi-handle descriptors") {
+ auto a = MakeObject();
+ auto b = MakeObject();
+ auto c = MakeObject();
+ const u32_le input[]{
+ IPC::MakeHeader(0, 0, 5), IPC::MoveHandleDesc(2),
+ handle_table.Create(a).Unwrap(), handle_table.Create(b).Unwrap(),
+ IPC::MoveHandleDesc(1), handle_table.Create(c).Unwrap(),
+ };
+
+ context.PopulateFromIncomingCommandBuffer(input, *process, handle_table);
+
+ auto* output = context.CommandBuffer();
+ REQUIRE(context.GetIncomingHandle(output[2]) == a);
+ REQUIRE(context.GetIncomingHandle(output[3]) == b);
+ REQUIRE(context.GetIncomingHandle(output[5]) == c);
+ }
+
+ SECTION("translates CallingPid descriptors") {
+ const u32_le input[]{
+ IPC::MakeHeader(0, 0, 2), IPC::CallingPidDesc(), 0x98989898,
+ };
+
+ context.PopulateFromIncomingCommandBuffer(input, *process, handle_table);
+
+ REQUIRE(context.CommandBuffer()[2] == process->process_id);
+ }
+
+ SECTION("translates mixed params") {
+ auto a = MakeObject();
+ const u32_le input[]{
+ IPC::MakeHeader(0, 2, 4),
+ 0x12345678,
+ 0xABCDEF00,
+ IPC::MoveHandleDesc(1),
+ handle_table.Create(a).Unwrap(),
+ IPC::CallingPidDesc(),
+ 0,
+ };
+
+ context.PopulateFromIncomingCommandBuffer(input, *process, handle_table);
+
+ auto* output = context.CommandBuffer();
+ REQUIRE(output[1] == 0x12345678);
+ REQUIRE(output[2] == 0xABCDEF00);
+ REQUIRE(context.GetIncomingHandle(output[4]) == a);
+ REQUIRE(output[6] == process->process_id);
+ }
+}
+
+TEST_CASE("HLERequestContext::WriteToOutgoingCommandBuffer", "[core][kernel]") {
+ auto session = std::get<SharedPtr<ServerSession>>(ServerSession::CreateSessionPair());
+ HLERequestContext context(std::move(session));
+
+ auto process = Process::Create(CodeSet::Create("", 0));
+ HandleTable handle_table;
+ auto* input = context.CommandBuffer();
+ u32_le output[IPC::COMMAND_BUFFER_LENGTH];
+
+ SECTION("works with empty cmdbuf") {
+ input[0] = IPC::MakeHeader(0x1234, 0, 0);
+
+ context.WriteToOutgoingCommandBuffer(output, *process, handle_table);
+
+ REQUIRE(output[0] == 0x12340000);
+ }
+
+ SECTION("translates regular params") {
+ input[0] = IPC::MakeHeader(0, 3, 0);
+ input[1] = 0x12345678;
+ input[2] = 0x21122112;
+ input[3] = 0xAABBCCDD;
+
+ context.WriteToOutgoingCommandBuffer(output, *process, handle_table);
+
+ REQUIRE(output[1] == 0x12345678);
+ REQUIRE(output[2] == 0x21122112);
+ REQUIRE(output[3] == 0xAABBCCDD);
+ }
+
+ SECTION("translates move/copy handles") {
+ auto a = MakeObject();
+ auto b = MakeObject();
+ input[0] = IPC::MakeHeader(0, 0, 4);
+ input[1] = IPC::MoveHandleDesc(1);
+ input[2] = context.AddOutgoingHandle(a);
+ input[3] = IPC::CopyHandleDesc(1);
+ input[4] = context.AddOutgoingHandle(b);
+
+ context.WriteToOutgoingCommandBuffer(output, *process, handle_table);
+
+ REQUIRE(handle_table.GetGeneric(output[2]) == a);
+ REQUIRE(handle_table.GetGeneric(output[4]) == b);
+ }
+
+ SECTION("translates multi-handle descriptors") {
+ auto a = MakeObject();
+ auto b = MakeObject();
+ auto c = MakeObject();
+ input[0] = IPC::MakeHeader(0, 0, 5);
+ input[1] = IPC::MoveHandleDesc(2);
+ input[2] = context.AddOutgoingHandle(a);
+ input[3] = context.AddOutgoingHandle(b);
+ input[4] = IPC::CopyHandleDesc(1);
+ input[5] = context.AddOutgoingHandle(c);
+
+ context.WriteToOutgoingCommandBuffer(output, *process, handle_table);
+
+ REQUIRE(handle_table.GetGeneric(output[2]) == a);
+ REQUIRE(handle_table.GetGeneric(output[3]) == b);
+ REQUIRE(handle_table.GetGeneric(output[5]) == c);
+ }
+}
+
+} // namespace Kernel