From f28a410ba043ef74c9f1c7d16d65962024ac49fe Mon Sep 17 00:00:00 2001 From: Michael Scire Date: Fri, 12 Feb 2021 06:08:16 -0800 Subject: [PATCH] htc: fixes, can now enter ReadyState with wip starlink code --- .../source/htc/server/htc_htcmisc_impl.cpp | 2 - .../source/htcfs/htcfs_client_impl.cpp | 166 ++++++++++++++++++ .../source/htcfs/htcfs_client_impl.hpp | 11 +- .../source/htcfs/htcfs_header_factory.hpp | 3 +- .../source/htcfs/htcfs_hipc_server.cpp | 2 +- .../ctrl/htclow_service_channel_parser.cpp | 4 +- stratosphere/htc/source/htc_main.cpp | 1 - 7 files changed, 182 insertions(+), 7 deletions(-) create mode 100644 libraries/libstratosphere/source/htcfs/htcfs_client_impl.cpp diff --git a/libraries/libstratosphere/source/htc/server/htc_htcmisc_impl.cpp b/libraries/libstratosphere/source/htc/server/htc_htcmisc_impl.cpp index 632c0e446..3ed5d71e7 100644 --- a/libraries/libstratosphere/source/htc/server/htc_htcmisc_impl.cpp +++ b/libraries/libstratosphere/source/htc/server/htc_htcmisc_impl.cpp @@ -111,7 +111,6 @@ namespace ams::htc::server { if (m_rpc_client.WaitAny(htclow::ChannelState_Disconnected, m_cancel_event.GetBase()) != 0) { break; } - } } @@ -150,7 +149,6 @@ namespace ams::htc::server { if (m_rpc_server.WaitAny(htclow::ChannelState_Disconnected, m_cancel_event.GetBase()) != 0) { break; } - } } diff --git a/libraries/libstratosphere/source/htcfs/htcfs_client_impl.cpp b/libraries/libstratosphere/source/htcfs/htcfs_client_impl.cpp new file mode 100644 index 000000000..b7ff385be --- /dev/null +++ b/libraries/libstratosphere/source/htcfs/htcfs_client_impl.cpp @@ -0,0 +1,166 @@ +/* + * Copyright (c) 2018-2020 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#include +#include "htcfs_client_impl.hpp" +#include "../htclow/htclow_default_channel_config.hpp" + +namespace ams::htcfs { + + namespace { + + /* TODO: Move to a header? */ + constexpr u16 RpcChannelId = 0; + + alignas(os::ThreadStackAlignment) constinit u8 g_monitor_thread_stack[os::MemoryPageSize]; + + constinit u8 g_cache[32_KB]; + + } + + ClientImpl::ClientImpl(htclow::HtclowManager *manager) + : m_htclow_manager(manager), + m_cache_manager(g_cache, sizeof(g_cache)), + m_header_factory(), + m_mutex(), + m_module(htclow::ModuleId::Htcfs), + m_rpc_channel(manager), + m_data_channel(manager), + m_connected(false), + m_event(os::EventClearMode_ManualClear) + { + /* Start our thread. */ + this->Start(); + } + + void ClientImpl::Start() { + /* Create our thread. */ + os::CreateThread(std::addressof(m_monitor_thread), ThreadEntry, this, g_monitor_thread_stack, sizeof(g_monitor_thread_stack), AMS_GET_SYSTEM_THREAD_PRIORITY(htc, HtcfsMonitor)); + + /* Set thread name pointer. */ + os::SetThreadNamePointer(std::addressof(m_monitor_thread), AMS_GET_SYSTEM_THREAD_NAME(htc, HtcfsMonitor)); + + /* Start our thread. */ + os::StartThread(std::addressof(m_monitor_thread)); + } + + void ClientImpl::Cancel() { + /* Signal our event. */ + m_event.Signal(); + } + + void ClientImpl::Wait() { + /* Wait for and destroy our thread. */ + os::WaitThread(std::addressof(m_monitor_thread)); + os::DestroyThread(std::addressof(m_monitor_thread)); + } + + void ClientImpl::ThreadBody() { + /* Loop forever, until we're cancelled. */ + while (!m_event.TryWait()) { + /* Lock ourselves. */ + std::scoped_lock lk(m_mutex); + + /* Open our channel. */ + R_ABORT_UNLESS(m_rpc_channel.Open(std::addressof(m_module), RpcChannelId)); + + /* Ensure that we clean up our channel when we're done. */ + ON_SCOPE_EXIT { + m_rpc_channel.Close(); + m_cache_manager.Invalidate(); + }; + + /* Set our channel config and buffers. */ + m_rpc_channel.SetConfig(htclow::DefaultChannelConfig); + m_rpc_channel.SetReceiveBuffer(m_receive_buffer, sizeof(m_receive_buffer)); + m_rpc_channel.SetSendBuffer(m_send_buffer, sizeof(m_send_buffer)); + + /* Wait for our channel state to be connectable. */ + if (this->WaitAny(htclow::ChannelState_Connectable, m_event.GetBase()) != 0) { + return; + } + + /* Ensure that when we're done, we reset our connected status. */ + ON_SCOPE_EXIT { m_connected = false; }; + + /* Try to connect. */ + const Result conn_result = m_rpc_channel.Connect(); + if (R_FAILED(conn_result)) { + /* DEBUG */ + R_ABORT_UNLESS(conn_result); + continue; + } + + /* Ensure that we manage our connection correctly. */ + auto conn_guard = SCOPE_GUARD { m_rpc_channel.Shutdown(); }; + + /* Try to set up the protocol. */ + const Result setup_result = this->SetUpProtocol(); + if (R_FAILED(setup_result)) { + R_ABORT_UNLESS(setup_result); + continue; + } + + /* We're properly connected now. */ + m_connected = true; + conn_guard.Cancel(); + + /* Tear down the protocol when we're done processing. */ + ON_SCOPE_EXIT { this->TearDownProtocol(); }; + + /* Wait to become disconnected. */ + if (this->WaitAny(htclow::ChannelState_Disconnected, m_event.GetBase()) != 0) { + break; + } + } + } + + int ClientImpl::WaitAny(htclow::ChannelState state, os::EventType *event) { + /* Wait. */ + int idx = 0; + while (m_rpc_channel.GetChannelState() != state) { + /* Get the channel state event. */ + os::EventType *channel_state_event = m_rpc_channel.GetChannelStateEvent(); + + /* Perform wait with lock temporarily not held. */ + { + m_mutex.Unlock(); + idx = os::WaitAny(channel_state_event, event); + m_mutex.Lock(); + } + + /* If we're cancel-signalled, we're done. */ + if (idx != 0) { + break; + } + + /* Clear the channel state event. */ + os::ClearEvent(channel_state_event);; + } + return idx; + } + + Result ClientImpl::SetUpProtocol() { + /* TODO: Actual client <-> host RPC here. */ + m_header_factory.SetVersion(1); + return ResultSuccess(); + } + + void ClientImpl::TearDownProtocol() { + /* Set the header factory version to zero. */ + m_header_factory.SetVersion(0); + } + +} diff --git a/libraries/libstratosphere/source/htcfs/htcfs_client_impl.hpp b/libraries/libstratosphere/source/htcfs/htcfs_client_impl.hpp index fd5508c62..8403186d1 100644 --- a/libraries/libstratosphere/source/htcfs/htcfs_client_impl.hpp +++ b/libraries/libstratosphere/source/htcfs/htcfs_client_impl.hpp @@ -32,11 +32,15 @@ namespace ams::htcfs { HeaderFactory m_header_factory; os::SdkMutex m_mutex; htclow::Module m_module; - htclow::Channel m_channel; + htclow::Channel m_rpc_channel; htclow::Channel m_data_channel; bool m_connected; os::ThreadType m_monitor_thread; os::Event m_event; + private: + static void ThreadEntry(void *arg) { static_cast(arg)->ThreadBody(); } + + void ThreadBody(); public: ClientImpl(htclow::HtclowManager *manager); @@ -48,6 +52,11 @@ namespace ams::htcfs { void Start(); void Cancel(); void Wait(); + private: + int WaitAny(htclow::ChannelState state, os::EventType *event); + + Result SetUpProtocol(); + void TearDownProtocol(); }; } diff --git a/libraries/libstratosphere/source/htcfs/htcfs_header_factory.hpp b/libraries/libstratosphere/source/htcfs/htcfs_header_factory.hpp index 643c98653..8fe691f5b 100644 --- a/libraries/libstratosphere/source/htcfs/htcfs_header_factory.hpp +++ b/libraries/libstratosphere/source/htcfs/htcfs_header_factory.hpp @@ -24,7 +24,8 @@ namespace ams::htcfs { public: HeaderFactory() : m_version() { /* ... */ } public: - /* ... */ + s16 GetVersion() const { return m_version; } + void SetVersion(s16 version) { m_version = version; } }; } diff --git a/libraries/libstratosphere/source/htcfs/htcfs_hipc_server.cpp b/libraries/libstratosphere/source/htcfs/htcfs_hipc_server.cpp index f550aa9b4..c23db56f2 100644 --- a/libraries/libstratosphere/source/htcfs/htcfs_hipc_server.cpp +++ b/libraries/libstratosphere/source/htcfs/htcfs_hipc_server.cpp @@ -23,7 +23,7 @@ namespace ams::htcfs { static constexpr inline size_t NumServers = 1; static constexpr inline size_t MaxSessions = 30; - static constexpr inline sm::ServiceName ServiceName = sm::ServiceName::Encode("htcfs"); + static constexpr inline sm::ServiceName ServiceName = sm::ServiceName::Encode("file_io"); struct ServerOptions { static constexpr size_t PointerBufferSize = 0x1000; diff --git a/libraries/libstratosphere/source/htclow/ctrl/htclow_service_channel_parser.cpp b/libraries/libstratosphere/source/htclow/ctrl/htclow_service_channel_parser.cpp index 2a64382ce..48d27b132 100644 --- a/libraries/libstratosphere/source/htclow/ctrl/htclow_service_channel_parser.cpp +++ b/libraries/libstratosphere/source/htclow/ctrl/htclow_service_channel_parser.cpp @@ -21,6 +21,8 @@ namespace ams::htclow::ctrl { namespace { + constexpr auto JsonParseFlags = rapidjson::kParseTrailingCommasFlag | rapidjson::kParseInsituFlag; + void ParseBody(s16 *out_version, const char **out_channels, int *out_num_channels, int max_channels, void *str, size_t str_size) { /* Create JSON handler. */ JsonHandler json_handler(out_version, out_channels, out_num_channels, max_channels); @@ -32,7 +34,7 @@ namespace ams::htclow::ctrl { rapidjson::InsituStringStream json_stream(static_cast(str)); /* Parse the json. */ - json_reader.Parse(json_stream, json_handler); + json_reader.Parse(json_stream, json_handler); } constexpr bool IsNumericCharacter(char c) { diff --git a/stratosphere/htc/source/htc_main.cpp b/stratosphere/htc/source/htc_main.cpp index a3e651a12..5f2bc88fd 100644 --- a/stratosphere/htc/source/htc_main.cpp +++ b/stratosphere/htc/source/htc_main.cpp @@ -303,4 +303,3 @@ int main(int argc, char **argv) return 0; } -