Sfoglia il codice sorgente

Merge pull request #2787 from yuriks/hle-ipc-tests

Kernel/IPC: Add tests for HLERequestContext buffer translation
Yuri Kunde Schlesner 9 anni fa
parent
commit
ecd332b1b7

+ 5 - 0
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);
     boost::range::remove_erase(connected_sessions, server_session);
 }
 }
 
 
+HLERequestContext::HLERequestContext(SharedPtr<ServerSession> session)
+    : session(std::move(session)) {
+    cmd_buf[0] = 0;
+}
+
 HLERequestContext::~HLERequestContext() = default;
 HLERequestContext::~HLERequestContext() = default;
 
 
 SharedPtr<Object> HLERequestContext::GetIncomingHandle(u32 id_from_cmdbuf) const {
 SharedPtr<Object> HLERequestContext::GetIncomingHandle(u32 id_from_cmdbuf) const {

+ 4 - 3
src/core/hle/kernel/hle_ipc.h

@@ -84,6 +84,7 @@ protected:
  */
  */
 class HLERequestContext {
 class HLERequestContext {
 public:
 public:
+    HLERequestContext(SharedPtr<ServerSession> session);
     ~HLERequestContext();
     ~HLERequestContext();
 
 
     /// Returns a pointer to the IPC command buffer for this request.
     /// Returns a pointer to the IPC command buffer for this request.
@@ -118,14 +119,14 @@ public:
      */
      */
     void ClearIncomingObjects();
     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,
     ResultCode PopulateFromIncomingCommandBuffer(const u32_le* src_cmdbuf, Process& src_process,
                                                  HandleTable& src_table);
                                                  HandleTable& src_table);
+    /// Writes data from this context back to the requesting process/thread.
     ResultCode WriteToOutgoingCommandBuffer(u32_le* dst_cmdbuf, Process& dst_process,
     ResultCode WriteToOutgoingCommandBuffer(u32_le* dst_cmdbuf, Process& dst_process,
                                             HandleTable& dst_table) const;
                                             HandleTable& dst_table) const;
 
 
+private:
     std::array<u32, IPC::COMMAND_BUFFER_LENGTH> cmd_buf;
     std::array<u32, IPC::COMMAND_BUFFER_LENGTH> cmd_buf;
     SharedPtr<ServerSession> session;
     SharedPtr<ServerSession> session;
     // TODO(yuriks): Check common usage of this and optimize size accordingly
     // TODO(yuriks): Check common usage of this and optimize size accordingly

+ 1 - 2
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
     // TODO(yuriks): The kernel should be the one handling this as part of translation after
     // everything else is migrated
     // 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,
     context.PopulateFromIncomingCommandBuffer(cmd_buf, *Kernel::g_current_process,
                                               Kernel::g_handle_table);
                                               Kernel::g_handle_table);
 
 

+ 3 - 2
src/tests/CMakeLists.txt

@@ -1,8 +1,9 @@
 set(SRCS
 set(SRCS
-            glad.cpp
-            tests.cpp
             common/param_package.cpp
             common/param_package.cpp
             core/file_sys/path_parser.cpp
             core/file_sys/path_parser.cpp
+            core/hle/kernel/hle_ipc.cpp
+            glad.cpp
+            tests.cpp
             )
             )
 
 
 set(HEADERS
 set(HEADERS

+ 193 - 0
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