diff --git a/libraries/libstratosphere/include/stratosphere/cfg/cfg_api.hpp b/libraries/libstratosphere/include/stratosphere/cfg/cfg_api.hpp index daab6d04c..c2e03a517 100644 --- a/libraries/libstratosphere/include/stratosphere/cfg/cfg_api.hpp +++ b/libraries/libstratosphere/include/stratosphere/cfg/cfg_api.hpp @@ -20,10 +20,6 @@ namespace ams::cfg { - /* Privileged Process configuration. */ - bool IsInitialProcess(); - void GetInitialProcessRange(os::ProcessId *out_min, os::ProcessId *out_max); - /* SD card configuration. */ bool IsSdCardRequiredServicesReady(); void WaitSdCardRequiredServicesReady(); diff --git a/libraries/libstratosphere/include/stratosphere/pgl/pgl_event_observer.hpp b/libraries/libstratosphere/include/stratosphere/pgl/pgl_event_observer.hpp index 5e6250aba..a0ad49e91 100644 --- a/libraries/libstratosphere/include/stratosphere/pgl/pgl_event_observer.hpp +++ b/libraries/libstratosphere/include/stratosphere/pgl/pgl_event_observer.hpp @@ -71,9 +71,9 @@ namespace ams::pgl { explicit EventObserverByTipc(Args &&... args) : m_tipc_interface(std::forward(args)...) { /* ... */ } public: virtual Result GetSystemEvent(os::SystemEventType *out) override { - ams::tipc::CopyHandle handle; + os::NativeHandle handle; R_TRY(m_tipc_interface.GetProcessEventHandle(std::addressof(handle))); - os::AttachReadableHandleToSystemEvent(out, handle.GetValue(), true, os::EventClearMode_AutoClear); + os::AttachReadableHandleToSystemEvent(out, handle, true, os::EventClearMode_AutoClear); return ResultSuccess(); } diff --git a/libraries/libstratosphere/include/stratosphere/tipc/impl/tipc_autogen_interface_macros.hpp b/libraries/libstratosphere/include/stratosphere/tipc/impl/tipc_autogen_interface_macros.hpp index 4323a8bd7..845d68381 100644 --- a/libraries/libstratosphere/include/stratosphere/tipc/impl/tipc_autogen_interface_macros.hpp +++ b/libraries/libstratosphere/include/stratosphere/tipc/impl/tipc_autogen_interface_macros.hpp @@ -86,6 +86,16 @@ namespace ams::tipc::impl { } \ } + #define AMS_TIPC_IMPL_IS_FIRMWARE_VERSION_ALWAYS_VALID(CLASSNAME, CMD_ID, RETURN, NAME, ARGS, ARGNAMES, VERSION_MIN, VERSION_MAX) \ + { \ + constexpr bool MinValid = VERSION_MIN == hos::Version_Min; \ + constexpr bool MaxValid = VERSION_MAX == hos::Version_Max; \ + if (!MinValid || !MaxValid) { \ + return false; \ + } \ + } + + #define AMS_TIPC_DEFINE_INTERFACE_WITH_DEFAULT_BASE(NAMESPACE, INTERFACE, BASE, CMD_MACRO) \ namespace NAMESPACE { \ \ @@ -117,6 +127,11 @@ namespace ams::tipc::impl { CMD_MACRO(ImplType, AMS_TIPC_IMPL_PROCESS_METHOD_REQUEST_BY_ID) \ \ return this->ProcessDefaultMethod(impl, message_buffer); \ + } \ + \ + static consteval bool IsFirmwareVersionAlwaysValid() { \ + CMD_MACRO(ImplType, AMS_TIPC_IMPL_IS_FIRMWARE_VERSION_ALWAYS_VALID); \ + return true; \ } \ public: \ virtual Result ProcessRequest() override { \ @@ -132,7 +147,7 @@ namespace ams::tipc::impl { \ /* Get decision variables. */ \ const auto tag = svc::ipc::MessageBuffer::MessageHeader(message_buffer).GetTag(); \ - const auto fw_ver = hos::GetVersion(); \ + const auto fw_ver = IsFirmwareVersionAlwaysValid() ? hos::Version_Current : hos::GetVersion(); \ \ /* Process against the command ids. */ \ if (false) { } \ diff --git a/libraries/libstratosphere/include/stratosphere/tipc/impl/tipc_impl_command_serialization.hpp b/libraries/libstratosphere/include/stratosphere/tipc/impl/tipc_impl_command_serialization.hpp index a190cadd8..6667dc390 100644 --- a/libraries/libstratosphere/include/stratosphere/tipc/impl/tipc_impl_command_serialization.hpp +++ b/libraries/libstratosphere/include/stratosphere/tipc/impl/tipc_impl_command_serialization.hpp @@ -76,9 +76,9 @@ namespace ams::tipc::impl { constexpr inline ArgumentType GetArgumentType = [] { if constexpr (tipc::IsBuffer) { return ArgumentType::Buffer; - } else if constexpr (std::is_base_of::value) { + } else if constexpr (std::same_as || std::same_as) { return ArgumentType::InHandle; - } else if constexpr (std::is_base_of::value) { + } else if constexpr (std::same_as || std::same_as) { return ArgumentType::OutHandle; } else if constexpr (std::is_base_of::value) { return ArgumentType::OutData; @@ -126,10 +126,10 @@ namespace ams::tipc::impl { using InCopyHandleFilter = TypeEqualityFilter; template - using OutMoveHandleFilter = TypeEqualityFilter>; + using OutMoveHandleFilter = TypeEqualityFilter; template - using OutCopyHandleFilter = TypeEqualityFilter>; + using OutCopyHandleFilter = TypeEqualityFilter; template struct BufferAttributeArrayGetter; @@ -267,6 +267,8 @@ namespace ams::tipc::impl { static_assert(NumInHandles <= 8, "Methods must take in <= 8 Handles"); static_assert(NumOutHandles <= 8, "Methods must output <= 8 Handles"); + static_assert(NumInHandles == 0, "In Handles not yet implemented!"); + /* Buffer marshalling. */ static constexpr std::array BufferAttributes = BufferAttributeArrayGetter::value; static constexpr size_t NumInBuffers = BufferAttributeCounter::GetCount(BufferAttributes); @@ -340,18 +342,18 @@ namespace ams::tipc::impl { current_info.out_raw_data_index++; } else if constexpr (arg_type == ArgumentType::InHandle) { /* New InHandle, increment the appropriate index. */ - if constexpr (std::is_same::value) { + if constexpr (std::same_as) { current_info.in_move_handle_index++; - } else if constexpr (std::is_same::value) { + } else if constexpr (std::same_as) { current_info.in_copy_handle_index++; } else { static_assert(!std::is_same::value, "Invalid InHandle kind"); } } else if constexpr (arg_type == ArgumentType::OutHandle) { /* New OutHandle, increment the appropriate index. */ - if constexpr (std::is_same>::value) { + if constexpr (std::same_as) { current_info.out_move_handle_index++; - } else if constexpr (std::is_same>::value) { + } else if constexpr (std::same_as) { current_info.out_copy_handle_index++; } else { static_assert(!std::is_same::value, "Invalid OutHandle kind"); @@ -418,25 +420,25 @@ namespace ams::tipc::impl { static constexpr size_t NumMove = _NumMove; static constexpr size_t NumCopy = _NumCopy; private: - MoveHandle move_handles[NumMove]; - CopyHandle copy_handles[NumCopy]; + os::NativeHandle move_handles[NumMove]; + os::NativeHandle copy_handles[NumCopy]; public: - constexpr ALWAYS_INLINE OutHandleHolder() : move_handles(), copy_handles() { /* ... */ } + ALWAYS_INLINE OutHandleHolder() { /* ... */ } template - constexpr ALWAYS_INLINE MoveHandle *GetMoveHandlePointer() { + constexpr ALWAYS_INLINE os::NativeHandle *GetMoveHandlePointer() { static_assert(Index < NumMove, "Index < NumMove"); return move_handles + Index; } template - constexpr ALWAYS_INLINE CopyHandle *GetCopyHandlePointer() { + constexpr ALWAYS_INLINE os::NativeHandle *GetCopyHandlePointer() { static_assert(Index < NumCopy, "Index < NumCopy"); return copy_handles + Index; } ALWAYS_INLINE void CopyTo(const svc::ipc::MessageBuffer &buffer) const { - #define _TIPC_OUT_HANDLE_HOLDER_WRITE_COPY_HANDLE(n) do { if constexpr (NumCopy > n) { buffer.SetHandle(OutIndex + n, copy_handles[n].GetValue()); } } while (0) + #define _TIPC_OUT_HANDLE_HOLDER_WRITE_COPY_HANDLE(n) do { if constexpr (NumCopy > n) { buffer.SetHandle(OutIndex + n, copy_handles[n]); } } while (0) _TIPC_OUT_HANDLE_HOLDER_WRITE_COPY_HANDLE(0); _TIPC_OUT_HANDLE_HOLDER_WRITE_COPY_HANDLE(1); _TIPC_OUT_HANDLE_HOLDER_WRITE_COPY_HANDLE(2); @@ -446,7 +448,7 @@ namespace ams::tipc::impl { _TIPC_OUT_HANDLE_HOLDER_WRITE_COPY_HANDLE(6); _TIPC_OUT_HANDLE_HOLDER_WRITE_COPY_HANDLE(7); #undef _TIPC_OUT_HANDLE_HOLDER_WRITE_COPY_HANDLE - #define _TIPC_OUT_HANDLE_HOLDER_WRITE_MOVE_HANDLE(n) do { if constexpr (NumMove > n) { buffer.SetHandle(OutIndex + NumCopy + n, move_handles[n].GetValue()); } } while (0) + #define _TIPC_OUT_HANDLE_HOLDER_WRITE_MOVE_HANDLE(n) do { if constexpr (NumMove > n) { buffer.SetHandle(OutIndex + NumCopy + n, move_handles[n]); } } while (0) _TIPC_OUT_HANDLE_HOLDER_WRITE_MOVE_HANDLE(0); _TIPC_OUT_HANDLE_HOLDER_WRITE_MOVE_HANDLE(1); _TIPC_OUT_HANDLE_HOLDER_WRITE_MOVE_HANDLE(2); @@ -507,10 +509,10 @@ namespace ams::tipc::impl { return T(out_raw_holder.template GetAddress()); } else if constexpr (Info.arg_type == ArgumentType::InHandle) { /* New InHandle. */ - if constexpr (std::is_same::value) { + if constexpr (std::same_as) { constexpr auto HandleIndex = CommandMeta::InMessageHandleIndex + CommandMeta::NumInCopyHandles + Info.in_move_handle_index; return T(message_buffer.GetHandle(HandleIndex)); - } else if constexpr (std::is_same::value) { + } else if constexpr (std::same_as) { constexpr auto HandleIndex = CommandMeta::InMessageHandleIndex + Info.in_copy_handle_index; return T(message_buffer.GetHandle(HandleIndex)); } else { @@ -518,10 +520,14 @@ namespace ams::tipc::impl { } } else if constexpr (Info.arg_type == ArgumentType::OutHandle) { /* New OutHandle. */ - if constexpr (std::is_same>::value) { - return T(out_handles_holder.template GetMoveHandlePointer()); - } else if constexpr (std::is_same>::value) { - return T(out_handles_holder.template GetCopyHandlePointer()); + if constexpr (std::same_as) { + os::NativeHandle * const ptr = out_handles_holder.template GetMoveHandlePointer(); + *ptr = os::InvalidNativeHandle; + return T(ptr); + } else if constexpr (std::same_as) { + os::NativeHandle * const ptr = out_handles_holder.template GetCopyHandlePointer(); + *ptr = os::InvalidNativeHandle; + return T(ptr); } else { static_assert(!std::is_same::value, "Invalid OutHandle kind"); } diff --git a/libraries/libstratosphere/include/stratosphere/tipc/tipc_handles.hpp b/libraries/libstratosphere/include/stratosphere/tipc/tipc_handles.hpp index 1c72ff40d..bba680ec5 100644 --- a/libraries/libstratosphere/include/stratosphere/tipc/tipc_handles.hpp +++ b/libraries/libstratosphere/include/stratosphere/tipc/tipc_handles.hpp @@ -20,147 +20,72 @@ namespace ams::tipc { - namespace impl { - - struct InHandleTag{}; - struct OutHandleTag{}; - - template - struct InHandle : public InHandleTag { - os::NativeHandle handle; - - constexpr InHandle() : handle(os::InvalidNativeHandle) { /* ... */ } - constexpr InHandle(os::NativeHandle h) : handle(h) { /* ... */ } - constexpr InHandle(const InHandle &o) : handle(o.handle) { /* ... */ } - - constexpr void operator=(const os::NativeHandle &h) { this->handle = h; } - constexpr void operator=(const InHandle &o) { this->handle = o.handle; } - - constexpr /* TODO: explicit? */ operator os::NativeHandle() const { return this->handle; } - constexpr os::NativeHandle GetValue() const { return this->handle; } - }; - - template - class OutHandleImpl : public OutHandleTag { - static_assert(std::is_base_of::value, "OutHandleImpl requires InHandle base"); - private: - T *m_ptr; - public: - constexpr OutHandleImpl(T *p) : m_ptr(p) { /* ... */ } - - constexpr void SetValue(const os::NativeHandle &value) { - *m_ptr = value; - } - - constexpr void SetValue(const T &value) { - *m_ptr = value; - } - - constexpr const T &GetValue() const { - return *m_ptr; - } - - constexpr T *GetPointer() const { - return m_ptr; - } - - constexpr os::NativeHandle *GetHandlePointer() const { - return &m_ptr->handle; - } - - constexpr T &operator *() const { - return *m_ptr; - } - - constexpr T *operator ->() const { - return m_ptr; - } - }; - - } - - using MoveHandle = typename impl::InHandle; - using CopyHandle = typename impl::InHandle; - - static_assert(sizeof(MoveHandle) == sizeof(os::NativeHandle), "sizeof(MoveHandle)"); - static_assert(sizeof(CopyHandle) == sizeof(os::NativeHandle), "sizeof(CopyHandle)"); - - template<> - class IsOutForceEnabled : public std::true_type{}; - template<> - class IsOutForceEnabled : public std::true_type{}; - - template<> - class Out : public impl::OutHandleImpl { + /* TODO: How do InHandles work in tipc? No examples to work off of. */ + class CopyHandle { private: - using T = MoveHandle; - using Base = impl::OutHandleImpl; + CopyHandle(); + }; + + class MoveHandle { + private: + MoveHandle(); + }; + + template<> + class Out { + private: + os::NativeHandle * const m_ptr; public: - constexpr Out(T *p) : Base(p) { /* ... */ } + ALWAYS_INLINE Out(os::NativeHandle *p) : m_ptr(p) { /* ... */ } - constexpr void SetValue(const os::NativeHandle &value) { - Base::SetValue(value); + ALWAYS_INLINE void SetValue(os::NativeHandle v) const { + *m_ptr = v; } - constexpr void SetValue(const T &value) { - Base::SetValue(value); + ALWAYS_INLINE const os::NativeHandle &GetValue() const { + return *m_ptr; } - constexpr const T &GetValue() const { - return Base::GetValue(); + ALWAYS_INLINE os::NativeHandle *GetPointer() const { + return m_ptr; } - constexpr T *GetPointer() const { - return Base::GetPointer(); + /* Convenience operators. */ + ALWAYS_INLINE os::NativeHandle &operator*() const { + return *m_ptr; } - constexpr os::NativeHandle *GetHandlePointer() const { - return Base::GetHandlePointer(); - } - - constexpr T &operator *() const { - return Base::operator*(); - } - - constexpr T *operator ->() const { - return Base::operator->(); + ALWAYS_INLINE os::NativeHandle *operator->() const { + return m_ptr; } }; template<> - class Out : public impl::OutHandleImpl { + class Out { private: - using T = CopyHandle; - using Base = impl::OutHandleImpl; + os::NativeHandle * const m_ptr; public: - constexpr Out(T *p) : Base(p) { /* ... */ } + ALWAYS_INLINE Out(os::NativeHandle *p) : m_ptr(p) { /* ... */ } - constexpr void SetValue(const os::NativeHandle &value) { - Base::SetValue(value); + ALWAYS_INLINE void SetValue(os::NativeHandle v) const { + *m_ptr = v; } - constexpr void SetValue(const T &value) { - Base::SetValue(value); + ALWAYS_INLINE const os::NativeHandle &GetValue() const { + return *m_ptr; } - constexpr const T &GetValue() const { - return Base::GetValue(); + ALWAYS_INLINE os::NativeHandle *GetPointer() const { + return m_ptr; } - constexpr T *GetPointer() const { - return Base::GetPointer(); + /* Convenience operators. */ + ALWAYS_INLINE os::NativeHandle &operator*() const { + return *m_ptr; } - constexpr os::NativeHandle *GetHandlePointer() const { - return Base::GetHandlePointer(); - } - - constexpr T &operator *() const { - return Base::operator*(); - } - - constexpr T *operator ->() const { - return Base::operator->(); + ALWAYS_INLINE os::NativeHandle *operator->() const { + return m_ptr; } }; diff --git a/libraries/libstratosphere/source/cfg/cfg_privileged_process.cpp b/libraries/libstratosphere/source/cfg/cfg_privileged_process.cpp deleted file mode 100644 index 46fbc5177..000000000 --- a/libraries/libstratosphere/source/cfg/cfg_privileged_process.cpp +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Copyright (c) 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 - -namespace ams::cfg { - - namespace { - - constinit os::SdkMutex g_lock; - constinit bool g_got_privileged_process_status = false; - constinit os::ProcessId g_min_initial_process_id = os::InvalidProcessId, g_max_initial_process_id = os::InvalidProcessId; - constinit os::ProcessId g_cur_process_id = os::InvalidProcessId; - - ALWAYS_INLINE void EnsurePrivilegedProcessStatusCached() { - if (AMS_LIKELY(g_got_privileged_process_status)) { - return; - } - - std::scoped_lock lk(g_lock); - - if (AMS_LIKELY(!g_got_privileged_process_status)) { - R_ABORT_UNLESS(svc::GetSystemInfo(std::addressof(g_min_initial_process_id.value), svc::SystemInfoType_InitialProcessIdRange, svc::InvalidHandle, svc::InitialProcessIdRangeInfo_Minimum)); - R_ABORT_UNLESS(svc::GetSystemInfo(std::addressof(g_max_initial_process_id.value), svc::SystemInfoType_InitialProcessIdRange, svc::InvalidHandle, svc::InitialProcessIdRangeInfo_Maximum)); - g_cur_process_id = os::GetCurrentProcessId(); - - g_got_privileged_process_status = true; - } - } - - } - - bool IsInitialProcess() { - /* Cache initial process range and extents. */ - EnsurePrivilegedProcessStatusCached(); - - /* Determine if we're Initial. */ - return g_min_initial_process_id <= g_cur_process_id && g_cur_process_id <= g_max_initial_process_id; - } - - void GetInitialProcessRange(os::ProcessId *out_min, os::ProcessId *out_max) { - /* Cache initial process range and extents. */ - EnsurePrivilegedProcessStatusCached(); - - /* Set output. */ - *out_min = g_min_initial_process_id; - *out_max = g_max_initial_process_id; - } - -} diff --git a/libraries/libstratosphere/source/pgl/srv/pgl_srv_shell_interface.cpp b/libraries/libstratosphere/source/pgl/srv/pgl_srv_shell_interface.cpp index 4aebf7825..3d6215123 100644 --- a/libraries/libstratosphere/source/pgl/srv/pgl_srv_shell_interface.cpp +++ b/libraries/libstratosphere/source/pgl/srv/pgl_srv_shell_interface.cpp @@ -171,7 +171,7 @@ namespace ams::pgl::srv { } Result ShellInterfaceTipc::GetShellEventObserver(ams::tipc::OutMoveHandle out) { - return pgl::srv::AllocateShellEventObserverForTipc(out.GetHandlePointer()); + return pgl::srv::AllocateShellEventObserverForTipc(out.GetPointer()); } } diff --git a/stratosphere/pm/source/pm_main.cpp b/stratosphere/pm/source/pm_main.cpp index 6d8a0d052..aa8138ec6 100644 --- a/stratosphere/pm/source/pm_main.cpp +++ b/stratosphere/pm/source/pm_main.cpp @@ -60,8 +60,9 @@ namespace ams { void RegisterPrivilegedProcesses() { /* Get privileged process range. */ - os::ProcessId min_priv_process_id = os::InvalidProcessId, max_priv_process_id = os::InvalidProcessId; - cfg::GetInitialProcessRange(std::addressof(min_priv_process_id), std::addressof(max_priv_process_id)); + os::ProcessId min_priv_process_id, max_priv_process_id; + R_ABORT_UNLESS(svc::GetSystemInfo(std::addressof(min_priv_process_id.value), svc::SystemInfoType_InitialProcessIdRange, svc::InvalidHandle, svc::InitialProcessIdRangeInfo_Minimum)); + R_ABORT_UNLESS(svc::GetSystemInfo(std::addressof(max_priv_process_id.value), svc::SystemInfoType_InitialProcessIdRange, svc::InvalidHandle, svc::InitialProcessIdRangeInfo_Maximum)); /* Get current process id/program id. */ const auto cur_process_id = os::GetCurrentProcessId(); diff --git a/stratosphere/sm/source/impl/sm_service_manager.cpp b/stratosphere/sm/source/impl/sm_service_manager.cpp index d42a18416..099c23cc5 100644 --- a/stratosphere/sm/source/impl/sm_service_manager.cpp +++ b/stratosphere/sm/source/impl/sm_service_manager.cpp @@ -141,7 +141,8 @@ namespace ams::sm::impl { public: InitialProcessIdLimits() { /* Retrieve process limits. */ - cfg::GetInitialProcessRange(std::addressof(m_min), std::addressof(m_max)); + R_ABORT_UNLESS(svc::GetSystemInfo(std::addressof(m_min.value), svc::SystemInfoType_InitialProcessIdRange, svc::InvalidHandle, svc::InitialProcessIdRangeInfo_Minimum)); + R_ABORT_UNLESS(svc::GetSystemInfo(std::addressof(m_max.value), svc::SystemInfoType_InitialProcessIdRange, svc::InvalidHandle, svc::InitialProcessIdRangeInfo_Maximum)); /* Ensure range is sane. */ AMS_ABORT_UNLESS(m_min <= m_max); @@ -405,6 +406,27 @@ namespace ams::sm::impl { program_id == ncm::SystemProgramId::Creport; } + Result CreatePortImpl(os::NativeHandle *out_server, os::NativeHandle *out_client, size_t max_sessions, bool is_light, sm::ServiceName &name) { + /* Create the port. */ + svc::Handle server_port, client_port; + R_TRY(svc::CreatePort(std::addressof(server_port), std::addressof(client_port), max_sessions, is_light, reinterpret_cast(name.name))); + + /* Set the output handles. */ + *out_server = server_port; + *out_client = client_port; + return ResultSuccess(); + } + + Result ConnectToPortImpl(os::NativeHandle *out, os::NativeHandle port) { + /* Connect to the port. */ + svc::Handle session; + R_TRY(svc::ConnectToPort(std::addressof(session), port)); + + /* Set the output handle. */ + *out = session; + return ResultSuccess(); + } + Result GetMitmServiceHandleImpl(os::NativeHandle *out, ServiceInfo *service_info, const MitmProcessInfo &client_info) { /* Get the mitm info. */ MitmInfo *mitm_info = GetMitmInfo(service_info); @@ -419,28 +441,16 @@ namespace ams::sm::impl { } /* If we shouldn't mitm, give normal session. */ - R_UNLESS(should_mitm, svc::ConnectToPort(out, service_info->port_h)); + R_UNLESS(should_mitm, ConnectToPortImpl(out, service_info->port_h)); /* Create both handles. */ { /* Get the forward handle. */ - os::NativeHandle fwd_hnd; - R_TRY(svc::ConnectToPort(std::addressof(fwd_hnd), service_info->port_h)); - - /* Ensure that the forward handle is closed, if we fail to get the mitm handle. */ - auto fwd_guard = SCOPE_GUARD { os::CloseNativeHandle(fwd_hnd); }; + R_TRY(ConnectToPortImpl(std::addressof(mitm_info->fwd_sess_h), service_info->port_h)); /* Get the mitm handle. */ /* This should be guaranteed to succeed, since we got a forward handle. */ - os::NativeHandle hnd; - R_ABORT_UNLESS(svc::ConnectToPort(std::addressof(hnd), mitm_info->port_h)); - - /* We got both handles, so we no longer need to clean up the forward handle. */ - fwd_guard.Cancel(); - - /* Save the handles to their respective storages. */ - mitm_info->fwd_sess_h = fwd_hnd; - *out = hnd; + R_ABORT_UNLESS(ConnectToPortImpl(out, mitm_info->port_h)); } mitm_info->waiting_ack_process_id = client_info.process_id; @@ -450,9 +460,6 @@ namespace ams::sm::impl { } Result GetServiceHandleImpl(os::NativeHandle *out, ServiceInfo *service_info, os::ProcessId process_id) { - /* Clear handle output. */ - *out = os::InvalidNativeHandle; - /* Get the mitm info. */ MitmInfo *mitm_info = GetMitmInfo(service_info); @@ -468,7 +475,7 @@ namespace ams::sm::impl { } /* We're not returning a mitm handle, so just return a normal port handle. */ - return svc::ConnectToPort(out, service_info->port_h); + return ConnectToPortImpl(out, service_info->port_h); } Result RegisterServiceImpl(os::NativeHandle *out, os::ProcessId process_id, ServiceName service, size_t max_sessions, bool is_light) { @@ -483,16 +490,13 @@ namespace ams::sm::impl { R_UNLESS(free_service != nullptr, sm::ResultOutOfServices()); /* Create the new service. */ - *out = os::InvalidNativeHandle; - os::NativeHandle server_hnd = os::InvalidNativeHandle; - R_TRY(svc::CreatePort(out, std::addressof(server_hnd), max_sessions, is_light, reinterpret_cast(free_service->name.name))); + R_TRY(CreatePortImpl(out, std::addressof(free_service->port_h), max_sessions, is_light, free_service->name)); /* Save info. */ free_service->name = service; free_service->owner_process_id = process_id; free_service->max_sessions = max_sessions; free_service->is_light = is_light; - free_service->port_h = server_hnd; /* This might undefer some requests. */ TriggerResume(service); @@ -745,10 +749,6 @@ namespace ams::sm::impl { MitmInfo *mitm_info = GetFreeMitmInfo(); R_UNLESS(mitm_info != nullptr, sm::ResultOutOfServices()); - /* Always clear output. */ - *out = os::InvalidNativeHandle; - *out_query = os::InvalidNativeHandle; - /* If we don't have a future mitm declaration, add one. */ /* Client will clear this when ready to process. */ const bool has_existing_future_declaration = HasFutureMitmDeclaration(service); @@ -762,7 +762,7 @@ namespace ams::sm::impl { { /* Get the port handles. */ os::NativeHandle hnd, port_hnd; - R_TRY(svc::CreatePort(std::addressof(hnd), std::addressof(port_hnd), service_info->max_sessions, service_info->is_light, reinterpret_cast(service_info->name.name))); + R_TRY(CreatePortImpl(std::addressof(hnd), std::addressof(port_hnd), service_info->max_sessions, service_info->is_light, service_info->name)); /* Ensure that we clean up the port handles, if something goes wrong creating the query sessions. */ auto port_guard = SCOPE_GUARD { os::CloseNativeHandle(hnd); os::CloseNativeHandle(port_hnd); }; diff --git a/stratosphere/sm/source/sm_manager_service.cpp b/stratosphere/sm/source/sm_manager_service.cpp deleted file mode 100644 index d3131a73e..000000000 --- a/stratosphere/sm/source/sm_manager_service.cpp +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright (c) 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 "sm_manager_service.hpp" -#include "impl/sm_service_manager.hpp" - -namespace ams::sm { - - Result ManagerService::RegisterProcess(os::ProcessId process_id, const tipc::InBuffer acid_sac, const tipc::InBuffer aci_sac) { - return impl::RegisterProcess(process_id, ncm::InvalidProgramId, cfg::OverrideStatus{}, acid_sac.GetPointer(), acid_sac.GetSize(), aci_sac.GetPointer(), aci_sac.GetSize()); - } - - Result ManagerService::UnregisterProcess(os::ProcessId process_id) { - return impl::UnregisterProcess(process_id); - } - - void ManagerService::AtmosphereEndInitDefers() { - R_ABORT_UNLESS(impl::EndInitialDefers()); - } - - void ManagerService::AtmosphereHasMitm(tipc::Out out, ServiceName service) { - R_ABORT_UNLESS(impl::HasMitm(out.GetPointer(), service)); - } - - Result ManagerService::AtmosphereRegisterProcess(os::ProcessId process_id, ncm::ProgramId program_id, cfg::OverrideStatus override_status, const tipc::InBuffer acid_sac, const tipc::InBuffer aci_sac) { - /* This takes in a program id and override status, unlike RegisterProcess. */ - return impl::RegisterProcess(process_id, program_id, override_status, acid_sac.GetPointer(), acid_sac.GetSize(), aci_sac.GetPointer(), aci_sac.GetSize()); - } - -} diff --git a/stratosphere/sm/source/sm_manager_service.hpp b/stratosphere/sm/source/sm_manager_service.hpp index 850ee8c6c..f9e2f30d7 100644 --- a/stratosphere/sm/source/sm_manager_service.hpp +++ b/stratosphere/sm/source/sm_manager_service.hpp @@ -15,17 +15,33 @@ */ #pragma once #include +#include "impl/sm_service_manager.hpp" namespace ams::sm { /* Service definition. */ class ManagerService { public: - Result RegisterProcess(os::ProcessId process_id, const tipc::InBuffer acid_sac, const tipc::InBuffer aci_sac); - Result UnregisterProcess(os::ProcessId process_id); - void AtmosphereEndInitDefers(); - void AtmosphereHasMitm(tipc::Out out, ServiceName service); - Result AtmosphereRegisterProcess(os::ProcessId process_id, ncm::ProgramId program_id, cfg::OverrideStatus override_status, const tipc::InBuffer acid_sac, const tipc::InBuffer aci_sac); + Result RegisterProcess(os::ProcessId process_id, const tipc::InBuffer acid_sac, const tipc::InBuffer aci_sac) { + return impl::RegisterProcess(process_id, ncm::InvalidProgramId, cfg::OverrideStatus{}, acid_sac.GetPointer(), acid_sac.GetSize(), aci_sac.GetPointer(), aci_sac.GetSize()); + } + + Result UnregisterProcess(os::ProcessId process_id) { + return impl::UnregisterProcess(process_id); + } + + void AtmosphereEndInitDefers() { + R_ABORT_UNLESS(impl::EndInitialDefers()); + } + + void AtmosphereHasMitm(tipc::Out out, ServiceName service) { + R_ABORT_UNLESS(impl::HasMitm(out.GetPointer(), service)); + } + + Result AtmosphereRegisterProcess(os::ProcessId process_id, ncm::ProgramId program_id, cfg::OverrideStatus override_status, const tipc::InBuffer acid_sac, const tipc::InBuffer aci_sac) { + /* This takes in a program id and override status, unlike RegisterProcess. */ + return impl::RegisterProcess(process_id, program_id, override_status, acid_sac.GetPointer(), acid_sac.GetSize(), aci_sac.GetPointer(), aci_sac.GetSize()); + } }; static_assert(sm::impl::IsIManagerInterface); diff --git a/stratosphere/sm/source/sm_tipc_server.cpp b/stratosphere/sm/source/sm_tipc_server.cpp index ab22cba67..892fa91a3 100644 --- a/stratosphere/sm/source/sm_tipc_server.cpp +++ b/stratosphere/sm/source/sm_tipc_server.cpp @@ -150,8 +150,6 @@ namespace ams::sm { /* Create the manager port handle. */ R_ABORT_UNLESS(impl::RegisterServiceForSelf(std::addressof(manager_port_handle), sm::ServiceName::Encode("sm:m"), MaxSessionsManager)); - - /* TODO: Debug Monitor port? */ } /* Register the ports. */ diff --git a/stratosphere/sm/source/sm_user_service.cpp b/stratosphere/sm/source/sm_user_service.cpp index 786e0b335..23d178097 100644 --- a/stratosphere/sm/source/sm_user_service.cpp +++ b/stratosphere/sm/source/sm_user_service.cpp @@ -19,91 +19,188 @@ namespace ams::sm { - UserService::~UserService() { - if (m_initialized) { - impl::OnClientDisconnected(m_process_id); + namespace { + + constexpr const u8 CmifResponseToQueryPointerBufferSize[] = { + 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x53, 0x46, 0x43, 0x4F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + }; + + static_assert(CmifCommandType_Request == 4); + + constexpr const u8 CmifExpectedRequestHeaderForRegisterClientAndDetachClient[] = { + 0x04, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x00, + }; + + constexpr const u8 CmifResponseToRegisterClientAndDetachClient[] = { + 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x53, 0x46, 0x43, 0x4F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }; + + constexpr const u8 CmifExpectedRequestHeaderForGetServiceHandleAndUnregisterService[] = { + 0x04, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00 + }; + + constexpr const u8 CmifResponseToGetServiceHandleAndRegisterService[] = { + 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x80, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x53, 0x46, 0x43, 0x4F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }; + + constexpr const u8 CmifResponseToUnregisterService[] = { + 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x53, 0x46, 0x43, 0x4F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }; + + constexpr const u8 CmifExpectedRequestHeaderForRegisterService[] = { + 0x04, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00 + }; + + static_assert(tipc::ResultRequestDeferred().GetValue() == 0xC823); + constexpr const u8 CmifResponseToForceProcessorDeferral[] = { + 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x23, 0xC8, 0x00, 0x00, + }; + + } + + Result UserService::ProcessDefaultServiceCommand(const svc::ipc::MessageBuffer &message_buffer) { + /* Parse the hipc headers. */ + const svc::ipc::MessageBuffer::MessageHeader message_header(message_buffer); + const svc::ipc::MessageBuffer::SpecialHeader special_header(message_buffer, message_header); + + /* Get the request tag. */ + const auto tag = message_header.GetTag(); + + /* Handle the case where we received a control request. */ + if (tag == CmifCommandType_Control || tag == CmifCommandType_ControlWithContext) { + /* The only control/control with context command which we support is QueryPointerBufferSize. */ + /* We do not have a pointer buffer, and so our pointer buffer size is zero. */ + /* Return the relevant hardcoded response. */ + std::memcpy(message_buffer.GetBufferForDebug(), CmifResponseToQueryPointerBufferSize, sizeof(CmifResponseToQueryPointerBufferSize)); + return ResultSuccess(); + } + + /* We only support request (with context), from this point forwards. */ + R_UNLESS((tag == CmifCommandType_Request || tag == CmifCommandType_RequestWithContext), tipc::ResultInvalidMethod()); + + /* For ease of parsing, we will alter the tag to be Request when it is RequestWithContext. */ + if (tag == CmifCommandType_RequestWithContext) { + message_buffer.Set(svc::ipc::MessageBuffer::MessageHeader(CmifCommandType_Request, + message_header.GetHasSpecialHeader(), + message_header.GetPointerCount(), + message_header.GetSendCount(), + message_header.GetReceiveCount(), + message_header.GetExchangeCount(), + message_header.GetRawCount(), + message_header.GetReceiveListCount())); + } + + /* NOTE: Nintendo only supports RegisterClient and GetServiceHandle. However, it would break */ + /* a substantial amount of homebrew system modules, if we were to not provide shims for some */ + /* other commands (RegisterService, and UnregisterService, in particular). As such, we will */ + /* do the nice thing, and accommodate this by providing backwards compatibility shims for */ + /* those commands. */ + + /* Please note, though, that the atmosphere extensions are not shimmed, as performing all the required */ + /* parsing for that seems unreasonable. Also, if you are using atmosphere extensions, you are probably */ + /* used to my breaking shit regularly anyway, and I don't expect much of a fuss to be raised by you. */ + /* I invite you to demonstrate to me that this expectation does not reflect reality. */ + const u8 * const raw_message_buffer = static_cast(message_buffer.GetBufferForDebug()); + u8 * const out_message_buffer = static_cast(message_buffer.GetBufferForDebug()); + + if (std::memcmp(raw_message_buffer, CmifExpectedRequestHeaderForRegisterClientAndDetachClient, sizeof(CmifExpectedRequestHeaderForRegisterClientAndDetachClient)) == 0) { + /* Get the command id. */ + const u32 command_id = *reinterpret_cast(raw_message_buffer + 0x28); + + /* Get the client process id. */ + u64 client_process_id; + std::memcpy(std::addressof(client_process_id), raw_message_buffer + 0xC, sizeof(client_process_id)); + + if (command_id == 0) { + /* Invoke the handler for RegisterClient. */ + R_ABORT_UNLESS(this->RegisterClient(tipc::ClientProcessId{ client_process_id })); + } else if (command_id == 4) { + /* Invoke the handler for DetachClient. */ + R_ABORT_UNLESS(this->DetachClient(tipc::ClientProcessId{ client_process_id })); + } else { + return tipc::ResultInvalidMethod(); + } + + /* Serialize output. */ + std::memcpy(out_message_buffer, CmifResponseToRegisterClientAndDetachClient, sizeof(CmifResponseToRegisterClientAndDetachClient)); + } else if (std::memcmp(raw_message_buffer, CmifExpectedRequestHeaderForGetServiceHandleAndUnregisterService, sizeof(CmifExpectedRequestHeaderForGetServiceHandleAndUnregisterService)) == 0) { + /* Get the command id. */ + const u32 command_id = *reinterpret_cast(raw_message_buffer + 0x18); + + /* Get the service_name. */ + sm::ServiceName service_name; + std::memcpy(std::addressof(service_name), raw_message_buffer + 0x20, sizeof(service_name)); + + if (command_id == 1) { + /* Invoke the handler for GetServiceHandle. */ + svc::Handle out_handle = svc::InvalidHandle; + const Result result = this->GetServiceHandle(std::addressof(out_handle), service_name); + + /* Serialize output. */ + if (R_SUCCEEDED(result) || !tipc::ResultRequestDeferred::Includes(result)) { + std::memcpy(out_message_buffer + 0x00, CmifResponseToGetServiceHandleAndRegisterService, sizeof(CmifResponseToGetServiceHandleAndRegisterService)); + std::memcpy(out_message_buffer + 0x0C, std::addressof(out_handle), sizeof(out_handle)); + std::memcpy(out_message_buffer + 0x18, std::addressof(result), sizeof(result)); + } else { + std::memcpy(out_message_buffer, CmifResponseToForceProcessorDeferral, sizeof(CmifResponseToForceProcessorDeferral)); + } + } else if (command_id == 3) { + /* Invoke the handler for UnregisterService. */ + const Result result = this->UnregisterService(service_name); + + /* Serialize output. */ + if (R_SUCCEEDED(result) || !tipc::ResultRequestDeferred::Includes(result)) { + std::memcpy(out_message_buffer + 0x00, CmifResponseToUnregisterService, sizeof(CmifResponseToUnregisterService)); + std::memcpy(out_message_buffer + 0x18, std::addressof(result), sizeof(result)); + } else { + std::memcpy(out_message_buffer, CmifResponseToForceProcessorDeferral, sizeof(CmifResponseToForceProcessorDeferral)); + } + } else { + return tipc::ResultInvalidMethod(); + } + } else if (std::memcmp(raw_message_buffer, CmifExpectedRequestHeaderForRegisterService, sizeof(CmifExpectedRequestHeaderForRegisterService)) == 0) { + /* Get the command id. */ + const u32 command_id = *reinterpret_cast(raw_message_buffer + 0x18); + + /* Get the service_name. */ + sm::ServiceName service_name; + std::memcpy(std::addressof(service_name), raw_message_buffer + 0x20, sizeof(service_name)); + + /* Get "is light". */ + bool is_light; + is_light = (raw_message_buffer[0x28] & 0x01) != 0; + + /* Get the max sessions. */ + u32 max_sessions; + std::memcpy(std::addressof(max_sessions), raw_message_buffer + 0x2C, sizeof(max_sessions)); + + if (command_id == 2) { + /* Invoke the handler for RegisterService. */ + svc::Handle out_handle = svc::InvalidHandle; + const Result result = this->RegisterService(std::addressof(out_handle), service_name, max_sessions, is_light); + + /* Serialize output. */ + if (R_SUCCEEDED(result) || !tipc::ResultRequestDeferred::Includes(result)) { + std::memcpy(out_message_buffer + 0x00, CmifResponseToGetServiceHandleAndRegisterService, sizeof(CmifResponseToGetServiceHandleAndRegisterService)); + std::memcpy(out_message_buffer + 0x0C, std::addressof(out_handle), sizeof(out_handle)); + std::memcpy(out_message_buffer + 0x18, std::addressof(result), sizeof(result)); + } else { + std::memcpy(out_message_buffer, CmifResponseToForceProcessorDeferral, sizeof(CmifResponseToForceProcessorDeferral)); + } + } else { + return tipc::ResultInvalidMethod(); + } + } else { + return tipc::ResultInvalidMethod(); } - } - Result UserService::RegisterClient(const tipc::ClientProcessId client_process_id) { - m_process_id = client_process_id.value; - m_initialized = true; return ResultSuccess(); } - Result UserService::EnsureInitialized() { - R_UNLESS(m_initialized, sm::ResultInvalidClient()); - return ResultSuccess(); - } - - Result UserService::GetServiceHandle(tipc::OutMoveHandle out_h, ServiceName service) { - R_TRY(this->EnsureInitialized()); - return impl::GetServiceHandle(out_h.GetHandlePointer(), m_process_id, service); - } - - Result UserService::RegisterService(tipc::OutMoveHandle out_h, ServiceName service, u32 max_sessions, bool is_light) { - R_TRY(this->EnsureInitialized()); - return impl::RegisterService(out_h.GetHandlePointer(), m_process_id, service, max_sessions, is_light); - } - - Result UserService::UnregisterService(ServiceName service) { - R_TRY(this->EnsureInitialized()); - return impl::UnregisterService(m_process_id, service); - } - - Result UserService::DetachClient(const tipc::ClientProcessId client_process_id) { - AMS_UNUSED(client_process_id); - - m_initialized = false; - return ResultSuccess(); - } - - Result UserService::AtmosphereInstallMitm(tipc::OutMoveHandle srv_h, tipc::OutMoveHandle qry_h, ServiceName service) { - R_TRY(this->EnsureInitialized()); - return impl::InstallMitm(srv_h.GetHandlePointer(), qry_h.GetHandlePointer(), m_process_id, service); - } - - Result UserService::AtmosphereUninstallMitm(ServiceName service) { - R_TRY(this->EnsureInitialized()); - return impl::UninstallMitm(m_process_id, service); - } - - Result UserService::AtmosphereAcknowledgeMitmSession(tipc::Out client_info, tipc::OutMoveHandle fwd_h, ServiceName service) { - R_TRY(this->EnsureInitialized()); - return impl::AcknowledgeMitmSession(client_info.GetPointer(), fwd_h.GetHandlePointer(), m_process_id, service); - } - - Result UserService::AtmosphereHasMitm(tipc::Out out, ServiceName service) { - R_TRY(this->EnsureInitialized()); - return impl::HasMitm(out.GetPointer(), service); - } - - Result UserService::AtmosphereWaitMitm(ServiceName service) { - R_TRY(this->EnsureInitialized()); - return impl::WaitMitm(service); - } - - Result UserService::AtmosphereDeclareFutureMitm(ServiceName service) { - R_TRY(this->EnsureInitialized()); - return impl::DeclareFutureMitm(m_process_id, service); - } - - Result UserService::AtmosphereClearFutureMitm(ServiceName service) { - R_TRY(this->EnsureInitialized()); - return impl::ClearFutureMitm(m_process_id, service); - } - - Result UserService::AtmosphereHasService(tipc::Out out, ServiceName service) { - R_TRY(this->EnsureInitialized()); - return impl::HasService(out.GetPointer(), service); - } - - Result UserService::AtmosphereWaitService(ServiceName service) { - R_TRY(this->EnsureInitialized()); - return impl::WaitService(service); - } - } - -/* Include the backwards compatibility shim for CMIF. */ -#include "sm_user_service_cmif_shim.inc" diff --git a/stratosphere/sm/source/sm_user_service.hpp b/stratosphere/sm/source/sm_user_service.hpp index 736813545..f43a7e31f 100644 --- a/stratosphere/sm/source/sm_user_service.hpp +++ b/stratosphere/sm/source/sm_user_service.hpp @@ -15,6 +15,7 @@ */ #pragma once #include +#include "impl/sm_service_manager.hpp" namespace ams::sm { @@ -25,28 +26,86 @@ namespace ams::sm { bool m_initialized; public: constexpr UserService() : m_process_id{os::InvalidProcessId}, m_initialized{false} { /* ... */ } - virtual ~UserService(); - private: - Result EnsureInitialized(); + virtual ~UserService() { + if (m_initialized) { + impl::OnClientDisconnected(m_process_id); + } + } public: /* Official commands. */ - Result RegisterClient(const tipc::ClientProcessId client_process_id); - Result GetServiceHandle(tipc::OutMoveHandle out_h, ServiceName service); - Result RegisterService(tipc::OutMoveHandle out_h, ServiceName service, u32 max_sessions, bool is_light); - Result UnregisterService(ServiceName service); - Result DetachClient(const tipc::ClientProcessId client_process_id); + Result RegisterClient(const tipc::ClientProcessId client_process_id) { + m_process_id = client_process_id.value; + m_initialized = true; + return ResultSuccess(); + } + + Result GetServiceHandle(tipc::OutMoveHandle out_h, ServiceName service) { + R_UNLESS(m_initialized, sm::ResultInvalidClient()); + return impl::GetServiceHandle(out_h.GetPointer(), m_process_id, service); + } + + Result RegisterService(tipc::OutMoveHandle out_h, ServiceName service, u32 max_sessions, bool is_light) { + R_UNLESS(m_initialized, sm::ResultInvalidClient()); + return impl::RegisterService(out_h.GetPointer(), m_process_id, service, max_sessions, is_light); + } + + Result UnregisterService(ServiceName service) { + R_UNLESS(m_initialized, sm::ResultInvalidClient()); + return impl::UnregisterService(m_process_id, service); + } + + Result DetachClient(const tipc::ClientProcessId client_process_id) { + AMS_UNUSED(client_process_id); + + m_initialized = false; + return ResultSuccess(); + } /* Atmosphere commands. */ - Result AtmosphereInstallMitm(tipc::OutMoveHandle srv_h, tipc::OutMoveHandle qry_h, ServiceName service); - Result AtmosphereUninstallMitm(ServiceName service); - Result AtmosphereAcknowledgeMitmSession(tipc::Out client_info, tipc::OutMoveHandle fwd_h, ServiceName service); - Result AtmosphereHasMitm(tipc::Out out, ServiceName service); - Result AtmosphereWaitMitm(ServiceName service); - Result AtmosphereDeclareFutureMitm(ServiceName service); - Result AtmosphereClearFutureMitm(ServiceName service); + Result AtmosphereInstallMitm(tipc::OutMoveHandle srv_h, tipc::OutMoveHandle qry_h, ServiceName service) { + R_UNLESS(m_initialized, sm::ResultInvalidClient()); + return impl::InstallMitm(srv_h.GetPointer(), qry_h.GetPointer(), m_process_id, service); + } - Result AtmosphereHasService(tipc::Out out, ServiceName service); - Result AtmosphereWaitService(ServiceName service); + Result AtmosphereUninstallMitm(ServiceName service) { + R_UNLESS(m_initialized, sm::ResultInvalidClient()); + return impl::UninstallMitm(m_process_id, service); + } + + Result AtmosphereAcknowledgeMitmSession(tipc::Out client_info, tipc::OutMoveHandle fwd_h, ServiceName service) { + R_UNLESS(m_initialized, sm::ResultInvalidClient()); + return impl::AcknowledgeMitmSession(client_info.GetPointer(), fwd_h.GetPointer(), m_process_id, service); + } + + Result AtmosphereHasMitm(tipc::Out out, ServiceName service) { + R_UNLESS(m_initialized, sm::ResultInvalidClient()); + return impl::HasMitm(out.GetPointer(), service); + } + + Result AtmosphereWaitMitm(ServiceName service) { + R_UNLESS(m_initialized, sm::ResultInvalidClient()); + return impl::WaitMitm(service); + } + + Result AtmosphereDeclareFutureMitm(ServiceName service) { + R_UNLESS(m_initialized, sm::ResultInvalidClient()); + return impl::DeclareFutureMitm(m_process_id, service); + } + + Result AtmosphereClearFutureMitm(ServiceName service) { + R_UNLESS(m_initialized, sm::ResultInvalidClient()); + return impl::ClearFutureMitm(m_process_id, service); + } + + Result AtmosphereHasService(tipc::Out out, ServiceName service) { + R_UNLESS(m_initialized, sm::ResultInvalidClient()); + return impl::HasService(out.GetPointer(), service); + } + + Result AtmosphereWaitService(ServiceName service) { + R_UNLESS(m_initialized, sm::ResultInvalidClient()); + return impl::WaitService(service); + } public: /* Backwards compatibility layer for cmif. */ Result ProcessDefaultServiceCommand(const svc::ipc::MessageBuffer &message_buffer); diff --git a/stratosphere/sm/source/sm_user_service_cmif_shim.inc b/stratosphere/sm/source/sm_user_service_cmif_shim.inc deleted file mode 100644 index a9f4a3c02..000000000 --- a/stratosphere/sm/source/sm_user_service_cmif_shim.inc +++ /dev/null @@ -1,213 +0,0 @@ -/* - * Copyright (c) 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 . - */ - -namespace ams::sm { - - namespace { - - constexpr const u8 CmifResponseToQueryPointerBufferSize[] = { - 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x53, 0x46, 0x43, 0x4F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - }; - - static_assert(CmifCommandType_Request == 4); - - constexpr const u8 CmifExpectedRequestHeaderForRegisterClientAndDetachClient[] = { - 0x04, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x00, - }; - - constexpr const u8 CmifResponseToRegisterClientAndDetachClient[] = { - 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x53, 0x46, 0x43, 0x4F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - }; - - constexpr const u8 CmifExpectedRequestHeaderForGetServiceHandleAndUnregisterService[] = { - 0x04, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00 - }; - - constexpr const u8 CmifResponseToGetServiceHandleAndRegisterService[] = { - 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x80, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x53, 0x46, 0x43, 0x4F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - }; - - constexpr const u8 CmifResponseToUnregisterService[] = { - 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x53, 0x46, 0x43, 0x4F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - }; - - constexpr const u8 CmifExpectedRequestHeaderForRegisterService[] = { - 0x04, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00 - }; - - static_assert(tipc::ResultRequestDeferred().GetValue() == 0xC823); - constexpr const u8 CmifResponseToForceProcessorDeferral[] = { - 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x23, 0xC8, 0x00, 0x00, - }; - - } - - Result UserService::ProcessDefaultServiceCommand(const svc::ipc::MessageBuffer &message_buffer) { - /* Parse the hipc headers. */ - const svc::ipc::MessageBuffer::MessageHeader message_header(message_buffer); - const svc::ipc::MessageBuffer::SpecialHeader special_header(message_buffer, message_header); - - /* Get the request tag. */ - const auto tag = message_header.GetTag(); - - /* Handle the case where we received a control request. */ - if (tag == CmifCommandType_Control || tag == CmifCommandType_ControlWithContext) { - /* The only control/control with context command which we support is QueryPointerBufferSize. */ - /* We do not have a pointer buffer, and so our pointer buffer size is zero. */ - /* Return the relevant hardcoded response. */ - std::memcpy(message_buffer.GetBufferForDebug(), CmifResponseToQueryPointerBufferSize, sizeof(CmifResponseToQueryPointerBufferSize)); - return ResultSuccess(); - } - - /* We only support request (with context), from this point forwards. */ - R_UNLESS((tag == CmifCommandType_Request || tag == CmifCommandType_RequestWithContext), tipc::ResultInvalidMethod()); - - /* For ease of parsing, we will alter the tag to be Request when it is RequestWithContext. */ - if (tag == CmifCommandType_RequestWithContext) { - message_buffer.Set(svc::ipc::MessageBuffer::MessageHeader(CmifCommandType_Request, - message_header.GetHasSpecialHeader(), - message_header.GetPointerCount(), - message_header.GetSendCount(), - message_header.GetReceiveCount(), - message_header.GetExchangeCount(), - message_header.GetRawCount(), - message_header.GetReceiveListCount())); - } - - /* NOTE: Nintendo only supports RegisterClient and GetServiceHandle. However, it would break */ - /* a substantial amount of homebrew system modules, if we were to not provide shims for some */ - /* other commands (RegisterService, and UnregisterService, in particular). As such, we will */ - /* do the nice thing, and accommodate this by providing backwards compatibility shims for */ - /* those commands. */ - - /* Please note, though, that the atmosphere extensions are not shimmed, as performing all the required */ - /* parsing for that seems unreasonable. Also, if you are using atmosphere extensions, you are probably */ - /* used to my breaking shit regularly anyway, and I don't expect much of a fuss to be raised by you. */ - /* I invite you to demonstrate to me that this expectation does not reflect reality. */ - const u8 * const raw_message_buffer = static_cast(message_buffer.GetBufferForDebug()); - u8 * const out_message_buffer = static_cast(message_buffer.GetBufferForDebug()); - - if (std::memcmp(raw_message_buffer, CmifExpectedRequestHeaderForRegisterClientAndDetachClient, sizeof(CmifExpectedRequestHeaderForRegisterClientAndDetachClient)) == 0) { - /* Get the command id. */ - const u32 command_id = *reinterpret_cast(raw_message_buffer + 0x28); - - /* Get the client process id. */ - u64 client_process_id; - std::memcpy(std::addressof(client_process_id), raw_message_buffer + 0xC, sizeof(client_process_id)); - - if (command_id == 0) { - /* Invoke the handler for RegisterClient. */ - R_ABORT_UNLESS(this->RegisterClient(tipc::ClientProcessId{ client_process_id })); - } else if (command_id == 4) { - /* Invoke the handler for DetachClient. */ - R_ABORT_UNLESS(this->DetachClient(tipc::ClientProcessId{ client_process_id })); - } else { - return tipc::ResultInvalidMethod(); - } - - /* Serialize output. */ - std::memcpy(out_message_buffer, CmifResponseToRegisterClientAndDetachClient, sizeof(CmifResponseToRegisterClientAndDetachClient)); - } else if (std::memcmp(raw_message_buffer, CmifExpectedRequestHeaderForGetServiceHandleAndUnregisterService, sizeof(CmifExpectedRequestHeaderForGetServiceHandleAndUnregisterService)) == 0) { - /* Get the command id. */ - const u32 command_id = *reinterpret_cast(raw_message_buffer + 0x18); - - /* Get the service_name. */ - sm::ServiceName service_name; - std::memcpy(std::addressof(service_name), raw_message_buffer + 0x20, sizeof(service_name)); - - if (command_id == 1) { - /* Invoke the handler for GetServiceHandle. */ - tipc::MoveHandle out_handle; - const Result result = this->GetServiceHandle(std::addressof(out_handle), service_name); - - /* Ensure that the output handle is invalid-handle, if we failed. */ - if (R_FAILED(result)) { - out_handle = svc::InvalidHandle; - } - - /* Serialize output. */ - if (R_SUCCEEDED(result) || !tipc::ResultRequestDeferred::Includes(result)) { - std::memcpy(out_message_buffer + 0x00, CmifResponseToGetServiceHandleAndRegisterService, sizeof(CmifResponseToGetServiceHandleAndRegisterService)); - std::memcpy(out_message_buffer + 0x0C, std::addressof(out_handle), sizeof(out_handle)); - std::memcpy(out_message_buffer + 0x18, std::addressof(result), sizeof(result)); - } else { - std::memcpy(out_message_buffer, CmifResponseToForceProcessorDeferral, sizeof(CmifResponseToForceProcessorDeferral)); - } - } else if (command_id == 3) { - /* Invoke the handler for UnregisterService. */ - const Result result = this->UnregisterService(service_name); - - /* Serialize output. */ - if (R_SUCCEEDED(result) || !tipc::ResultRequestDeferred::Includes(result)) { - std::memcpy(out_message_buffer + 0x00, CmifResponseToUnregisterService, sizeof(CmifResponseToUnregisterService)); - std::memcpy(out_message_buffer + 0x18, std::addressof(result), sizeof(result)); - } else { - std::memcpy(out_message_buffer, CmifResponseToForceProcessorDeferral, sizeof(CmifResponseToForceProcessorDeferral)); - } - } else { - return tipc::ResultInvalidMethod(); - } - } else if (std::memcmp(raw_message_buffer, CmifExpectedRequestHeaderForRegisterService, sizeof(CmifExpectedRequestHeaderForRegisterService)) == 0) { - /* Get the command id. */ - const u32 command_id = *reinterpret_cast(raw_message_buffer + 0x18); - - /* Get the service_name. */ - sm::ServiceName service_name; - std::memcpy(std::addressof(service_name), raw_message_buffer + 0x20, sizeof(service_name)); - - /* Get "is light". */ - bool is_light; - is_light = (raw_message_buffer[0x28] & 0x01) != 0; - - /* Get the max sessions. */ - u32 max_sessions; - std::memcpy(std::addressof(max_sessions), raw_message_buffer + 0x2C, sizeof(max_sessions)); - - if (command_id == 2) { - /* Invoke the handler for RegisterService. */ - tipc::MoveHandle out_handle; - const Result result = this->RegisterService(std::addressof(out_handle), service_name, max_sessions, is_light); - - /* Ensure that the output handle is invalid-handle, if we failed. */ - if (R_FAILED(result)) { - out_handle = svc::InvalidHandle; - } - - /* Serialize output. */ - if (R_SUCCEEDED(result) || !tipc::ResultRequestDeferred::Includes(result)) { - std::memcpy(out_message_buffer + 0x00, CmifResponseToGetServiceHandleAndRegisterService, sizeof(CmifResponseToGetServiceHandleAndRegisterService)); - std::memcpy(out_message_buffer + 0x0C, std::addressof(out_handle), sizeof(out_handle)); - std::memcpy(out_message_buffer + 0x18, std::addressof(result), sizeof(result)); - } else { - std::memcpy(out_message_buffer, CmifResponseToForceProcessorDeferral, sizeof(CmifResponseToForceProcessorDeferral)); - } - } else { - return tipc::ResultInvalidMethod(); - } - } else { - return tipc::ResultInvalidMethod(); - } - - return ResultSuccess(); - } - -}