diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index e9b04098b..7d267fdcf 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -29,6 +29,7 @@ set(SRCS hle/applets/mii_selector.cpp hle/applets/swkbd.cpp hle/kernel/address_arbiter.cpp + hle/kernel/client_port.cpp hle/kernel/event.cpp hle/kernel/kernel.cpp hle/kernel/memory.cpp @@ -36,6 +37,7 @@ set(SRCS hle/kernel/process.cpp hle/kernel/resource_limit.cpp hle/kernel/semaphore.cpp + hle/kernel/server_port.cpp hle/kernel/session.cpp hle/kernel/shared_memory.cpp hle/kernel/thread.cpp @@ -167,6 +169,7 @@ set(HEADERS hle/applets/mii_selector.h hle/applets/swkbd.h hle/kernel/address_arbiter.h + hle/kernel/client_port.h hle/kernel/event.h hle/kernel/kernel.h hle/kernel/memory.h @@ -174,6 +177,7 @@ set(HEADERS hle/kernel/process.h hle/kernel/resource_limit.h hle/kernel/semaphore.h + hle/kernel/server_port.h hle/kernel/session.h hle/kernel/shared_memory.h hle/kernel/thread.h diff --git a/src/core/hle/function_wrappers.h b/src/core/hle/function_wrappers.h index bf7f875b6..8839ce482 100644 --- a/src/core/hle/function_wrappers.h +++ b/src/core/hle/function_wrappers.h @@ -194,6 +194,16 @@ template void Wrap() { FuncReturn(func(PARAM(0), PARAM(1)).raw); } +template void Wrap() { + Handle param_1 = 0; + Handle param_2 = 0; + u32 retval = func(¶m_1, ¶m_2, reinterpret_cast(Memory::GetPointer(PARAM(2))), PARAM(3)).raw; + // The first out parameter is moved into R2 and the second is moved into R1. + Core::g_app_core->SetReg(1, param_2); + Core::g_app_core->SetReg(2, param_1); + FuncReturn(retval); +} + //////////////////////////////////////////////////////////////////////////////////////////////////// // Function wrappers that return type u32 diff --git a/src/core/hle/kernel/client_port.cpp b/src/core/hle/kernel/client_port.cpp new file mode 100644 index 000000000..444ce8d45 --- /dev/null +++ b/src/core/hle/kernel/client_port.cpp @@ -0,0 +1,16 @@ +// Copyright 2016 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include "common/assert.h" + +#include "core/hle/kernel/client_port.h" +#include "core/hle/kernel/kernel.h" +#include "core/hle/kernel/server_port.h" + +namespace Kernel { + +ClientPort::ClientPort() {} +ClientPort::~ClientPort() {} + +} // namespace diff --git a/src/core/hle/kernel/client_port.h b/src/core/hle/kernel/client_port.h new file mode 100644 index 000000000..480b6ddae --- /dev/null +++ b/src/core/hle/kernel/client_port.h @@ -0,0 +1,36 @@ +// Copyright 2016 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include + +#include "common/common_types.h" + +#include "core/hle/kernel/kernel.h" + +namespace Kernel { + +class ServerPort; + +class ClientPort : public Object { +public: + friend class ServerPort; + std::string GetTypeName() const override { return "ClientPort"; } + std::string GetName() const override { return name; } + + static const HandleType HANDLE_TYPE = HandleType::ClientPort; + HandleType GetHandleType() const override { return HANDLE_TYPE; } + + SharedPtr server_port; ///< ServerPort associated with this client port. + u32 max_sessions; ///< Maximum number of simultaneous sessions the port can have + u32 active_sessions; ///< Number of currently open sessions to this port + std::string name; ///< Name of client port (optional) + +protected: + ClientPort(); + ~ClientPort() override; +}; + +} // namespace diff --git a/src/core/hle/kernel/kernel.h b/src/core/hle/kernel/kernel.h index 4d4276f7a..27ba3f912 100644 --- a/src/core/hle/kernel/kernel.h +++ b/src/core/hle/kernel/kernel.h @@ -35,7 +35,7 @@ enum KernelHandle : Handle { enum class HandleType : u32 { Unknown = 0, - Port = 1, + Session = 2, Event = 3, Mutex = 4, @@ -48,6 +48,8 @@ enum class HandleType : u32 { Timer = 11, ResourceLimit = 12, CodeSet = 13, + ClientPort = 14, + ServerPort = 15, }; enum { @@ -72,6 +74,7 @@ public: bool IsWaitable() const { switch (GetHandleType()) { case HandleType::Session: + case HandleType::ServerPort: case HandleType::Event: case HandleType::Mutex: case HandleType::Thread: @@ -80,13 +83,13 @@ public: return true; case HandleType::Unknown: - case HandleType::Port: case HandleType::SharedMemory: case HandleType::Redirection: case HandleType::Process: case HandleType::AddressArbiter: case HandleType::ResourceLimit: case HandleType::CodeSet: + case HandleType::ClientPort: return false; } } diff --git a/src/core/hle/kernel/server_port.cpp b/src/core/hle/kernel/server_port.cpp new file mode 100644 index 000000000..fcc684a20 --- /dev/null +++ b/src/core/hle/kernel/server_port.cpp @@ -0,0 +1,41 @@ +// Copyright 2016 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include + +#include "common/assert.h" + +#include "core/hle/kernel/client_port.h" +#include "core/hle/kernel/kernel.h" +#include "core/hle/kernel/server_port.h" +#include "core/hle/kernel/thread.h" + +namespace Kernel { + +ServerPort::ServerPort() {} +ServerPort::~ServerPort() {} + +bool ServerPort::ShouldWait() { + // If there are no pending sessions, we wait until a new one is added. + return pending_sessions.size() == 0; +} + +void ServerPort::Acquire() { + ASSERT_MSG(!ShouldWait(), "object unavailable!"); +} + +std::tuple, SharedPtr> ServerPort::CreatePortPair(u32 max_sessions, std::string name) { + SharedPtr server_port(new ServerPort); + SharedPtr client_port(new ClientPort); + + server_port->name = name + "_Server"; + client_port->name = name + "_Client"; + client_port->server_port = server_port; + client_port->max_sessions = max_sessions; + client_port->active_sessions = 0; + + return std::make_tuple(std::move(server_port), std::move(client_port)); +} + +} // namespace diff --git a/src/core/hle/kernel/server_port.h b/src/core/hle/kernel/server_port.h new file mode 100644 index 000000000..e9c972ce6 --- /dev/null +++ b/src/core/hle/kernel/server_port.h @@ -0,0 +1,46 @@ +// Copyright 2016 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include +#include + +#include "common/common_types.h" + +#include "core/hle/kernel/kernel.h" + +namespace Kernel { + +class ClientPort; + +class ServerPort final : public WaitObject { +public: + /** + * Creates a pair of ServerPort and an associated ClientPort. + * @param max_sessions Maximum number of sessions to the port + * @param name Optional name of the ports + * @return The created port tuple + */ + static std::tuple, SharedPtr> CreatePortPair(u32 max_sessions, std::string name = "UnknownPort"); + + std::string GetTypeName() const override { return "ServerPort"; } + std::string GetName() const override { return name; } + + static const HandleType HANDLE_TYPE = HandleType::ServerPort; + HandleType GetHandleType() const override { return HANDLE_TYPE; } + + std::string name; ///< Name of port (optional) + + std::vector> pending_sessions; ///< ServerSessions waiting to be accepted by the port + + bool ShouldWait() override; + void Acquire() override; + +private: + ServerPort(); + ~ServerPort() override; +}; + +} // namespace diff --git a/src/core/hle/svc.cpp b/src/core/hle/svc.cpp index 0ce72de87..5d71d5619 100644 --- a/src/core/hle/svc.cpp +++ b/src/core/hle/svc.cpp @@ -14,12 +14,14 @@ #include "core/arm/arm_interface.h" #include "core/hle/kernel/address_arbiter.h" +#include "core/hle/kernel/client_port.h" #include "core/hle/kernel/event.h" #include "core/hle/kernel/memory.h" #include "core/hle/kernel/mutex.h" #include "core/hle/kernel/process.h" #include "core/hle/kernel/resource_limit.h" #include "core/hle/kernel/semaphore.h" +#include "core/hle/kernel/server_port.h" #include "core/hle/kernel/shared_memory.h" #include "core/hle/kernel/thread.h" #include "core/hle/kernel/timer.h" @@ -834,6 +836,23 @@ static ResultCode CreateMemoryBlock(Handle* out_handle, u32 addr, u32 size, u32 return RESULT_SUCCESS; } +static ResultCode CreatePort(Handle* server_port, Handle* client_port, const char* name, u32 max_sessions) { + // TODO(Subv): Implement named ports. + ASSERT_MSG(name == nullptr, "Named ports are currently unimplemented"); + + using Kernel::ServerPort; + using Kernel::ClientPort; + using Kernel::SharedPtr; + + auto ports = ServerPort::CreatePortPair(max_sessions); + CASCADE_RESULT(*client_port, Kernel::g_handle_table.Create(std::move(std::get>(ports)))); + // Note: The 3DS kernel also leaks the client port handle if the server port handle fails to be created. + CASCADE_RESULT(*server_port, Kernel::g_handle_table.Create(std::move(std::get>(ports)))); + + LOG_TRACE(Kernel_SVC, "called max_sessions=%u", max_sessions); + return RESULT_SUCCESS; +} + static ResultCode GetSystemInfo(s64* out, u32 type, s32 param) { using Kernel::MemoryRegion; @@ -1011,7 +1030,7 @@ static const FunctionDef SVC_Table[] = { {0x44, nullptr, "Unknown"}, {0x45, nullptr, "Unknown"}, {0x46, nullptr, "Unknown"}, - {0x47, nullptr, "CreatePort"}, + {0x47, HLE::Wrap, "CreatePort"}, {0x48, nullptr, "CreateSessionToPort"}, {0x49, nullptr, "CreateSession"}, {0x4A, nullptr, "AcceptSession"},