diff options
| author | bunnei <bunneidev@gmail.com> | 2018-01-24 23:09:03 -0500 | 
|---|---|---|
| committer | GitHub <noreply@github.com> | 2018-01-24 23:09:03 -0500 | 
| commit | 748c0de539674dc8ca4a5a8aadd2a61b0eabe652 (patch) | |
| tree | ae56efe8654d3aa3a5e75ec04bd9dfdcc06023a9 /src/core/hle/kernel | |
| parent | 44eb8402322a47a52f0401f9ef7473bea719e2bf (diff) | |
| parent | de177f66926a5170c1ad0621085494d27de8e2d4 (diff) | |
Merge pull request #137 from bunnei/improve-ipc
Improve IPC, unify Domains and Sessions, and add validation
Diffstat (limited to 'src/core/hle/kernel')
| -rw-r--r-- | src/core/hle/kernel/client_session.h | 6 | ||||
| -rw-r--r-- | src/core/hle/kernel/domain.cpp | 63 | ||||
| -rw-r--r-- | src/core/hle/kernel/domain.h | 45 | ||||
| -rw-r--r-- | src/core/hle/kernel/handle_table.cpp | 10 | ||||
| -rw-r--r-- | src/core/hle/kernel/handle_table.h | 7 | ||||
| -rw-r--r-- | src/core/hle/kernel/hle_ipc.cpp | 11 | ||||
| -rw-r--r-- | src/core/hle/kernel/hle_ipc.h | 27 | ||||
| -rw-r--r-- | src/core/hle/kernel/kernel.h | 16 | ||||
| -rw-r--r-- | src/core/hle/kernel/server_session.cpp | 47 | ||||
| -rw-r--r-- | src/core/hle/kernel/server_session.h | 18 | ||||
| -rw-r--r-- | src/core/hle/kernel/svc.cpp | 3 | ||||
| -rw-r--r-- | src/core/hle/kernel/sync_object.h | 35 | 
12 files changed, 79 insertions, 209 deletions
| diff --git a/src/core/hle/kernel/client_session.h b/src/core/hle/kernel/client_session.h index d6ab4f893..2258f95bc 100644 --- a/src/core/hle/kernel/client_session.h +++ b/src/core/hle/kernel/client_session.h @@ -7,7 +7,7 @@  #include <memory>  #include <string>  #include "common/common_types.h" -#include "core/hle/kernel/sync_object.h" +#include "core/hle/kernel/kernel.h"  #include "core/hle/result.h"  namespace Kernel { @@ -16,7 +16,7 @@ class ServerSession;  class Session;  class Thread; -class ClientSession final : public SyncObject { +class ClientSession final : public Object {  public:      friend class ServerSession; @@ -33,7 +33,7 @@ public:          return HANDLE_TYPE;      } -    ResultCode SendSyncRequest(SharedPtr<Thread> thread) override; +    ResultCode SendSyncRequest(SharedPtr<Thread> thread);      std::string name; ///< Name of client port (optional) diff --git a/src/core/hle/kernel/domain.cpp b/src/core/hle/kernel/domain.cpp deleted file mode 100644 index 5035e9c08..000000000 --- a/src/core/hle/kernel/domain.cpp +++ /dev/null @@ -1,63 +0,0 @@ -// Copyright 2018 yuzu emulator team -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#include "common/logging/log.h" -#include "core/hle/ipc_helpers.h" -#include "core/hle/kernel/client_port.h" -#include "core/hle/kernel/domain.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/session.h" -#include "core/hle/kernel/thread.h" - -namespace Kernel { - -ResultVal<SharedPtr<Domain>> Domain::Create(std::string name) { -    SharedPtr<Domain> domain(new Domain); -    domain->name = std::move(name); -    return MakeResult(std::move(domain)); -} - -ResultVal<SharedPtr<Domain>> Domain::CreateFromSession(const Session& session) { -    auto res = Create(session.port->GetName() + "_Domain"); -    auto& domain = res.Unwrap(); -    domain->request_handlers.push_back(std::move(session.server->hle_handler)); -    Kernel::g_handle_table.ConvertSessionToDomain(session, domain); -    return res; -} - -ResultCode Domain::SendSyncRequest(SharedPtr<Thread> thread) { -    Kernel::HLERequestContext context(this); -    u32* cmd_buf = (u32*)Memory::GetPointer(Kernel::GetCurrentThread()->GetTLSAddress()); -    context.PopulateFromIncomingCommandBuffer(cmd_buf, *Kernel::g_current_process, -                                              Kernel::g_handle_table); - -    auto& domain_message_header = context.GetDomainMessageHeader(); -    if (domain_message_header) { -        // If there is a DomainMessageHeader, then this is CommandType "Request" -        const u32 object_id{context.GetDomainMessageHeader()->object_id}; -        switch (domain_message_header->command) { -        case IPC::DomainMessageHeader::CommandType::SendMessage: -            return request_handlers[object_id - 1]->HandleSyncRequest(context); - -        case IPC::DomainMessageHeader::CommandType::CloseVirtualHandle: { -            LOG_DEBUG(IPC, "CloseVirtualHandle, object_id=0x%08X", object_id); - -            request_handlers[object_id - 1] = nullptr; - -            IPC::RequestBuilder rb{context, 2}; -            rb.Push(RESULT_SUCCESS); - -            return RESULT_SUCCESS; -        } -        } - -        LOG_CRITICAL(IPC, "Unknown domain command=%d", domain_message_header->command.Value()); -        UNIMPLEMENTED(); -    } -    return request_handlers.front()->HandleSyncRequest(context); -} - -} // namespace Kernel diff --git a/src/core/hle/kernel/domain.h b/src/core/hle/kernel/domain.h deleted file mode 100644 index 3fec3b0b2..000000000 --- a/src/core/hle/kernel/domain.h +++ /dev/null @@ -1,45 +0,0 @@ -// Copyright 2018 yuzu emulator team -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#pragma once - -#include <memory> -#include <string> -#include <vector> -#include "core/hle/kernel/sync_object.h" -#include "core/hle/result.h" - -namespace Kernel { - -class Session; -class SessionRequestHandler; - -class Domain final : public SyncObject { -public: -    std::string GetTypeName() const override { -        return "Domain"; -    } - -    static const HandleType HANDLE_TYPE = HandleType::Domain; -    HandleType GetHandleType() const override { -        return HANDLE_TYPE; -    } - -    static ResultVal<SharedPtr<Domain>> CreateFromSession(const Session& server); - -    ResultCode SendSyncRequest(SharedPtr<Thread> thread) override; - -    /// The name of this domain (optional) -    std::string name; - -    std::vector<std::shared_ptr<SessionRequestHandler>> request_handlers; - -private: -    Domain() = default; -    ~Domain() override = default; - -    static ResultVal<SharedPtr<Domain>> Create(std::string name = "Unknown"); -}; - -} // namespace Kernel diff --git a/src/core/hle/kernel/handle_table.cpp b/src/core/hle/kernel/handle_table.cpp index 74d3d0514..3beb55753 100644 --- a/src/core/hle/kernel/handle_table.cpp +++ b/src/core/hle/kernel/handle_table.cpp @@ -5,12 +5,10 @@  #include <utility>  #include "common/assert.h"  #include "common/logging/log.h" -#include "core/hle/kernel/client_session.h"  #include "core/hle/kernel/errors.h"  #include "core/hle/kernel/handle_table.h"  #include "core/hle/kernel/kernel.h"  #include "core/hle/kernel/process.h" -#include "core/hle/kernel/session.h"  #include "core/hle/kernel/thread.h"  namespace Kernel { @@ -55,14 +53,6 @@ ResultVal<Handle> HandleTable::Duplicate(Handle handle) {      return Create(std::move(object));  } -void HandleTable::ConvertSessionToDomain(const Session& session, SharedPtr<Object> domain) { -    for (auto& object : objects) { -        if (DynamicObjectCast<ClientSession>(object) == session.client) { -            object = domain; -        } -    } -} -  ResultCode HandleTable::Close(Handle handle) {      if (!IsValid(handle))          return ERR_INVALID_HANDLE; diff --git a/src/core/hle/kernel/handle_table.h b/src/core/hle/kernel/handle_table.h index 935cc22b5..ba968c666 100644 --- a/src/core/hle/kernel/handle_table.h +++ b/src/core/hle/kernel/handle_table.h @@ -17,8 +17,6 @@ enum KernelHandle : Handle {      CurrentProcess = 0xFFFF8001,  }; -class Session; -  /**   * This class allows the creation of Handles, which are references to objects that can be tested   * for validity and looked up. Here they are used to pass references to kernel objects to/from the @@ -62,11 +60,6 @@ public:      ResultVal<Handle> Duplicate(Handle handle);      /** -     * Convert all handles of the specified Session to the specified Domain. -     */ -    void ConvertSessionToDomain(const Session& session, SharedPtr<Object> domain); - -    /**       * Closes a handle, removing it from the table and decreasing the object's ref-count.       * @return `RESULT_SUCCESS` or one of the following errors:       *           - `ERR_INVALID_HANDLE`: an invalid handle was passed in. diff --git a/src/core/hle/kernel/hle_ipc.cpp b/src/core/hle/kernel/hle_ipc.cpp index ecf32c18a..db104e8a2 100644 --- a/src/core/hle/kernel/hle_ipc.cpp +++ b/src/core/hle/kernel/hle_ipc.cpp @@ -7,7 +7,6 @@  #include "common/common_funcs.h"  #include "common/common_types.h"  #include "core/hle/ipc_helpers.h" -#include "core/hle/kernel/domain.h"  #include "core/hle/kernel/handle_table.h"  #include "core/hle/kernel/hle_ipc.h"  #include "core/hle/kernel/kernel.h" @@ -26,10 +25,6 @@ void SessionRequestHandler::ClientDisconnected(SharedPtr<ServerSession> server_s      boost::range::remove_erase(connected_sessions, server_session);  } -HLERequestContext::HLERequestContext(SharedPtr<Kernel::Domain> domain) : domain(std::move(domain)) { -    cmd_buf[0] = 0; -} -  HLERequestContext::HLERequestContext(SharedPtr<Kernel::ServerSession> server_session)      : server_session(std::move(server_session)) {      cmd_buf[0] = 0; @@ -87,7 +82,7 @@ void HLERequestContext::ParseCommandBuffer(u32_le* src_cmdbuf, bool incoming) {      // Padding to align to 16 bytes      rp.AlignWithPadding(); -    if (IsDomain() && (command_header->type == IPC::CommandType::Request || !incoming)) { +    if (Session()->IsDomain() && (command_header->type == IPC::CommandType::Request || !incoming)) {          // If this is an incoming message, only CommandType "Request" has a domain header          // All outgoing domain messages have the domain header          domain_message_header = @@ -200,12 +195,12 @@ ResultCode HLERequestContext::WriteToOutgoingCommandBuffer(u32_le* dst_cmdbuf, P      // TODO(Subv): Translate the X/A/B/W buffers. -    if (IsDomain()) { +    if (Session()->IsDomain()) {          ASSERT(domain_message_header->num_objects == domain_objects.size());          // Write the domain objects to the command buffer, these go after the raw untranslated data.          // TODO(Subv): This completely ignores C buffers.          size_t domain_offset = size - domain_message_header->num_objects; -        auto& request_handlers = domain->request_handlers; +        auto& request_handlers = server_session->domain_request_handlers;          for (auto& object : domain_objects) {              request_handlers.emplace_back(object); diff --git a/src/core/hle/kernel/hle_ipc.h b/src/core/hle/kernel/hle_ipc.h index 80fa48d7f..da8335b35 100644 --- a/src/core/hle/kernel/hle_ipc.h +++ b/src/core/hle/kernel/hle_ipc.h @@ -86,7 +86,6 @@ protected:   */  class HLERequestContext {  public: -    HLERequestContext(SharedPtr<Kernel::Domain> domain);      HLERequestContext(SharedPtr<Kernel::ServerSession> session);      ~HLERequestContext(); @@ -96,17 +95,10 @@ public:      }      /** -     * Returns the domain through which this request was made. -     */ -    const SharedPtr<Kernel::Domain>& Domain() const { -        return domain; -    } - -    /**       * Returns the session through which this request was made. This can be used as a map key to       * access per-client data on services.       */ -    const SharedPtr<Kernel::ServerSession>& ServerSession() const { +    const SharedPtr<Kernel::ServerSession>& Session() const {          return server_session;      } @@ -151,10 +143,6 @@ public:          return domain_message_header;      } -    bool IsDomain() const { -        return domain != nullptr; -    } -      template <typename T>      SharedPtr<T> GetCopyObject(size_t index) {          ASSERT(index < copy_objects.size()); @@ -187,9 +175,20 @@ public:          domain_objects.clear();      } +    size_t NumMoveObjects() const { +        return move_objects.size(); +    } + +    size_t NumCopyObjects() const { +        return copy_objects.size(); +    } + +    size_t NumDomainObjects() const { +        return domain_objects.size(); +    } +  private:      std::array<u32, IPC::COMMAND_BUFFER_LENGTH> cmd_buf; -    SharedPtr<Kernel::Domain> domain;      SharedPtr<Kernel::ServerSession> server_session;      // TODO(yuriks): Check common usage of this and optimize size accordingly      boost::container::small_vector<SharedPtr<Object>, 8> move_objects; diff --git a/src/core/hle/kernel/kernel.h b/src/core/hle/kernel/kernel.h index 4d9549e45..c77e58f3c 100644 --- a/src/core/hle/kernel/kernel.h +++ b/src/core/hle/kernel/kernel.h @@ -31,7 +31,6 @@ enum class HandleType : u32 {      ServerPort,      ClientSession,      ServerSession, -    Domain,  };  enum { @@ -84,27 +83,12 @@ public:          case HandleType::CodeSet:          case HandleType::ClientPort:          case HandleType::ClientSession: -        case HandleType::Domain:              return false;          }          UNREACHABLE();      } -    /** -     * Check if svcSendSyncRequest can be called on the object -     * @return True svcSendSyncRequest can be called on the object, otherwise false -     */ -    bool IsSyncable() const { -        switch (GetHandleType()) { -        case HandleType::ClientSession: -        case HandleType::Domain: -            return true; -        } - -        UNREACHABLE(); -    } -  public:      static unsigned int next_object_id; diff --git a/src/core/hle/kernel/server_session.cpp b/src/core/hle/kernel/server_session.cpp index 09d02a691..54481f7f1 100644 --- a/src/core/hle/kernel/server_session.cpp +++ b/src/core/hle/kernel/server_session.cpp @@ -4,6 +4,7 @@  #include <tuple> +#include "core/hle/ipc_helpers.h"  #include "core/hle/kernel/client_port.h"  #include "core/hle/kernel/client_session.h"  #include "core/hle/kernel/handle_table.h" @@ -61,6 +62,38 @@ ResultCode ServerSession::HandleSyncRequest(SharedPtr<Thread> thread) {      // from its ClientSession, so wake up any threads that may be waiting on a svcReplyAndReceive or      // similar. +    Kernel::HLERequestContext context(this); +    u32* cmd_buf = (u32*)Memory::GetPointer(thread->GetTLSAddress()); +    context.PopulateFromIncomingCommandBuffer(cmd_buf, *Kernel::g_current_process, +                                              Kernel::g_handle_table); + +    // If the session has been converted to a domain, handle the doomain request +    if (IsDomain()) { +        auto& domain_message_header = context.GetDomainMessageHeader(); +        if (domain_message_header) { +            // If there is a DomainMessageHeader, then this is CommandType "Request" +            const u32 object_id{context.GetDomainMessageHeader()->object_id}; +            switch (domain_message_header->command) { +            case IPC::DomainMessageHeader::CommandType::SendMessage: +                return domain_request_handlers[object_id - 1]->HandleSyncRequest(context); + +            case IPC::DomainMessageHeader::CommandType::CloseVirtualHandle: { +                LOG_DEBUG(IPC, "CloseVirtualHandle, object_id=0x%08X", object_id); + +                domain_request_handlers[object_id - 1] = nullptr; + +                IPC::ResponseBuilder rb{context, 2}; +                rb.Push(RESULT_SUCCESS); +                return RESULT_SUCCESS; +            } +            } + +            LOG_CRITICAL(IPC, "Unknown domain command=%d", domain_message_header->command.Value()); +            ASSERT(false); +        } +        // If there is no domain header, the regular session handler is used +    } +      // If this ServerSession has an associated HLE handler, forward the request to it.      ResultCode result{RESULT_SUCCESS};      if (hle_handler != nullptr) { @@ -69,11 +102,6 @@ ResultCode ServerSession::HandleSyncRequest(SharedPtr<Thread> thread) {          if (translate_result.IsError())              return translate_result; -        Kernel::HLERequestContext context(this); -        u32* cmd_buf = (u32*)Memory::GetPointer(Kernel::GetCurrentThread()->GetTLSAddress()); -        context.PopulateFromIncomingCommandBuffer(cmd_buf, *Kernel::g_current_process, -                                                  Kernel::g_handle_table); -          result = hle_handler->HandleSyncRequest(context);      } else {          // Add the thread to the list of threads that have issued a sync request with this @@ -84,6 +112,15 @@ ResultCode ServerSession::HandleSyncRequest(SharedPtr<Thread> thread) {      // If this ServerSession does not have an HLE implementation, just wake up the threads waiting      // on it.      WakeupAllWaitingThreads(); + +    // Handle scenario when ConvertToDomain command was issued, as we must do the conversion at the +    // end of the command such that only commands following this one are handled as domains +    if (convert_to_domain) { +        ASSERT_MSG(domain_request_handlers.empty(), "already a domain"); +        domain_request_handlers = {hle_handler}; +        convert_to_domain = false; +    } +      return result;  } diff --git a/src/core/hle/kernel/server_session.h b/src/core/hle/kernel/server_session.h index 6ff4ef8c1..144692106 100644 --- a/src/core/hle/kernel/server_session.h +++ b/src/core/hle/kernel/server_session.h @@ -79,7 +79,10 @@ public:      std::string name;                ///< The name of this session (optional)      std::shared_ptr<Session> parent; ///< The parent session, which links to the client endpoint.      std::shared_ptr<SessionRequestHandler> -        hle_handler; ///< This session's HLE request handler (optional) +        hle_handler; ///< This session's HLE request handler (applicable when not a domain) + +    /// This is the list of domain request handlers (after conversion to a domain) +    std::vector<std::shared_ptr<SessionRequestHandler>> domain_request_handlers;      /// List of threads that are pending a response after a sync request. This list is processed in      /// a LIFO manner, thus, the last request will be dispatched first. @@ -91,6 +94,16 @@ public:      /// TODO(Subv): Find a better name for this.      SharedPtr<Thread> currently_handling; +    /// Returns true if the session has been converted to a domain, otherwise False +    bool IsDomain() const { +        return !domain_request_handlers.empty(); +    } + +    /// Converts the session to a domain at the end of the current command +    void ConvertToDomain() { +        convert_to_domain = true; +    } +  private:      ServerSession();      ~ServerSession() override; @@ -102,6 +115,9 @@ private:       * @return The created server session       */      static ResultVal<SharedPtr<ServerSession>> Create(std::string name = "Unknown"); + +    /// When set to True, converts the session to a domain at the end of the command +    bool convert_to_domain{};  };  /** diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp index 516309036..4c0276cf0 100644 --- a/src/core/hle/kernel/svc.cpp +++ b/src/core/hle/kernel/svc.cpp @@ -20,7 +20,6 @@  #include "core/hle/kernel/shared_memory.h"  #include "core/hle/kernel/svc.h"  #include "core/hle/kernel/svc_wrap.h" -#include "core/hle/kernel/sync_object.h"  #include "core/hle/kernel/thread.h"  #include "core/hle/lock.h"  #include "core/hle/result.h" @@ -87,7 +86,7 @@ static ResultCode ConnectToNamedPort(Handle* out_handle, VAddr port_name_address  /// Makes a blocking IPC call to an OS service.  static ResultCode SendSyncRequest(Handle handle) { -    SharedPtr<SyncObject> session = g_handle_table.Get<SyncObject>(handle); +    SharedPtr<ClientSession> session = g_handle_table.Get<ClientSession>(handle);      if (!session) {          LOG_ERROR(Kernel_SVC, "called with invalid handle=0x%08X", handle);          return ERR_INVALID_HANDLE; diff --git a/src/core/hle/kernel/sync_object.h b/src/core/hle/kernel/sync_object.h deleted file mode 100644 index f2befa2ea..000000000 --- a/src/core/hle/kernel/sync_object.h +++ /dev/null @@ -1,35 +0,0 @@ -// Copyright 2018 yuzu emulator team -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#pragma once - -#include <boost/smart_ptr/intrusive_ptr.hpp> -#include "core/hle/kernel/kernel.h" -#include "core/hle/result.h" - -namespace Kernel { - -class Thread; - -/// Class that represents a Kernel object that svcSendSyncRequest can be called on -class SyncObject : public Object { -public: -    /** -     * Handle a sync request from the emulated application. -     * @param thread Thread that initiated the request. -     * @returns ResultCode from the operation. -     */ -    virtual ResultCode SendSyncRequest(SharedPtr<Thread> thread) = 0; -}; - -// Specialization of DynamicObjectCast for SyncObjects -template <> -inline SharedPtr<SyncObject> DynamicObjectCast<SyncObject>(SharedPtr<Object> object) { -    if (object != nullptr && object->IsSyncable()) { -        return boost::static_pointer_cast<SyncObject>(std::move(object)); -    } -    return nullptr; -} - -} // namespace Kernel | 
