From 6ce038acad67409274340db5a3fc654a5dd1c288 Mon Sep 17 00:00:00 2001 From: Michael Scire Date: Thu, 16 Apr 2020 02:33:36 -0700 Subject: [PATCH] pgl: begin skeletoning shell service, implement two commands. --- .../include/stratosphere/os.hpp | 1 + .../include/stratosphere/os/os_sdk_mutex.hpp | 60 +++++++++ .../include/stratosphere/pm/pm_shell_api.hpp | 1 + .../include/stratosphere/pm/pm_types.hpp | 22 +++- .../source/os/os_sdk_mutex.cpp | 43 +++++++ .../source/pgl/srv/pgl_srv_shell.cpp | 114 ++++++++++++++++++ .../source/pgl/srv/pgl_srv_shell.hpp | 26 ++++ .../pgl/srv/pgl_srv_shell_interface.cpp | 70 +++++++++++ .../pgl/srv/pgl_srv_shell_interface.hpp | 50 ++++++++ .../source/pm/pm_shell_api.cpp | 4 + .../pm/source/impl/pm_process_manager.cpp | 20 --- 11 files changed, 390 insertions(+), 21 deletions(-) create mode 100644 libraries/libstratosphere/include/stratosphere/os/os_sdk_mutex.hpp create mode 100644 libraries/libstratosphere/source/os/os_sdk_mutex.cpp create mode 100644 libraries/libstratosphere/source/pgl/srv/pgl_srv_shell.cpp create mode 100644 libraries/libstratosphere/source/pgl/srv/pgl_srv_shell.hpp create mode 100644 libraries/libstratosphere/source/pgl/srv/pgl_srv_shell_interface.cpp create mode 100644 libraries/libstratosphere/source/pgl/srv/pgl_srv_shell_interface.hpp diff --git a/libraries/libstratosphere/include/stratosphere/os.hpp b/libraries/libstratosphere/include/stratosphere/os.hpp index 57578afda..e67cd32a6 100644 --- a/libraries/libstratosphere/include/stratosphere/os.hpp +++ b/libraries/libstratosphere/include/stratosphere/os.hpp @@ -27,6 +27,7 @@ #include #include #include +#include #include #include #include diff --git a/libraries/libstratosphere/include/stratosphere/os/os_sdk_mutex.hpp b/libraries/libstratosphere/include/stratosphere/os/os_sdk_mutex.hpp new file mode 100644 index 000000000..675c12ac2 --- /dev/null +++ b/libraries/libstratosphere/include/stratosphere/os/os_sdk_mutex.hpp @@ -0,0 +1,60 @@ +/* + * 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 . + */ + +#pragma once +#include +#include + +namespace ams::os { + + class SdkConditionVariable; + + struct SdkMutexType { + union { + s32 _arr[sizeof(impl::InternalCriticalSectionStorage) / sizeof(s32)]; + impl::InternalCriticalSectionStorage _storage; + }; + }; + static_assert(std::is_trivial::value); + + void InitializeSdkMutex(SdkMutexType *mutex); + + void LockSdkMutex(SdkMutexType *mutex); + bool TryLockSdkMutex(SdkMutexType *mutex); + void UnlockSdkMutex(SdkMutexType *mutex); + + bool IsSdkMutexLockedByCurrentThread(const SdkMutexType *mutex); + + class SdkMutex { + private: + friend class SdkConditionVariable; + private: + SdkMutexType mutex; + public: + constexpr SdkMutex() : mutex{{0}} { /* ... */ } + + ALWAYS_INLINE void Lock() { return os::LockSdkMutex(std::addressof(this->mutex)); } + ALWAYS_INLINE bool TryLock() { return os::TryLockSdkMutex(std::addressof(this->mutex)); } + ALWAYS_INLINE void Unlock() { return os::UnlockSdkMutex(std::addressof(this->mutex)); } + + ALWAYS_INLINE bool IsLockedByCurrentThread() const { return os::IsSdkMutexLockedByCurrentThread(std::addressof(this->mutex)); } + + ALWAYS_INLINE void lock() { return this->Lock(); } + ALWAYS_INLINE bool try_lock() { return this->TryLock(); } + ALWAYS_INLINE void unlock() { return this->Unlock(); } + }; + +} diff --git a/libraries/libstratosphere/include/stratosphere/pm/pm_shell_api.hpp b/libraries/libstratosphere/include/stratosphere/pm/pm_shell_api.hpp index 9464b01b5..a7a51247c 100644 --- a/libraries/libstratosphere/include/stratosphere/pm/pm_shell_api.hpp +++ b/libraries/libstratosphere/include/stratosphere/pm/pm_shell_api.hpp @@ -24,5 +24,6 @@ namespace ams::pm::shell { /* Shell API. */ Result LaunchProgram(os::ProcessId *out_process_id, const ncm::ProgramLocation &loc, u32 launch_flags); + Result TerminateProcess(os::ProcessId process_id); } diff --git a/libraries/libstratosphere/include/stratosphere/pm/pm_types.hpp b/libraries/libstratosphere/include/stratosphere/pm/pm_types.hpp index 70bf622b3..fbd4931fe 100644 --- a/libraries/libstratosphere/include/stratosphere/pm/pm_types.hpp +++ b/libraries/libstratosphere/include/stratosphere/pm/pm_types.hpp @@ -32,7 +32,27 @@ namespace ams::pm { ResourceLimitGroup_Count, }; - using LimitableResource = ::LimitableResource; + enum LaunchFlags : u32 { + LaunchFlags_None = 0, + LaunchFlags_SignalOnExit = (1 << 0), + LaunchFlags_SignalOnStart = (1 << 1), + LaunchFlags_SignalOnException = (1 << 2), + LaunchFlags_SignalOnDebugEvent = (1 << 3), + LaunchFlags_StartSuspended = (1 << 4), + LaunchFlags_DisableAslr = (1 << 5), + }; + + enum LaunchFlagsDeprecated : u32 { + LaunchFlagsDeprecated_None = 0, + LaunchFlagsDeprecated_SignalOnExit = (1 << 0), + LaunchFlagsDeprecated_StartSuspended = (1 << 1), + LaunchFlagsDeprecated_SignalOnException = (1 << 2), + LaunchFlagsDeprecated_DisableAslr = (1 << 3), + LaunchFlagsDeprecated_SignalOnDebugEvent = (1 << 4), + LaunchFlagsDeprecated_SignalOnStart = (1 << 5), + }; + + constexpr inline u32 LaunchFlagsMask = (1 << 6) - 1; enum class ProcessEvent { None = 0, diff --git a/libraries/libstratosphere/source/os/os_sdk_mutex.cpp b/libraries/libstratosphere/source/os/os_sdk_mutex.cpp new file mode 100644 index 000000000..e7dbeb56a --- /dev/null +++ b/libraries/libstratosphere/source/os/os_sdk_mutex.cpp @@ -0,0 +1,43 @@ +/* + * 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 + +namespace ams::os { + + void InitializeSdkMutex(SdkMutexType *mutex) { + GetReference(mutex->_storage).Initialize(); + } + + bool IsSdkMutexLockedByCurrentThread(const SdkMutexType *mutex) { + return GetReference(mutex->_storage).IsLockedByCurrentThread(); + } + + void LockSdkMutex(SdkMutexType *mutex) { + AMS_ABORT_UNLESS(!IsSdkMutexLockedByCurrentThread(mutex)); + return GetReference(mutex->_storage).Enter(); + } + + bool TryLockSdkMutex(SdkMutexType *mutex) { + AMS_ABORT_UNLESS(!IsSdkMutexLockedByCurrentThread(mutex)); + return GetReference(mutex->_storage).TryEnter(); + } + + void UnlockSdkMutex(SdkMutexType *mutex) { + AMS_ABORT_UNLESS(IsSdkMutexLockedByCurrentThread(mutex)); + return GetReference(mutex->_storage).Leave(); + } + +} diff --git a/libraries/libstratosphere/source/pgl/srv/pgl_srv_shell.cpp b/libraries/libstratosphere/source/pgl/srv/pgl_srv_shell.cpp new file mode 100644 index 000000000..eae40013a --- /dev/null +++ b/libraries/libstratosphere/source/pgl/srv/pgl_srv_shell.cpp @@ -0,0 +1,114 @@ +/* + * 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 "pgl_srv_shell.hpp" + +namespace ams::pgl::srv { + + namespace { + + constexpr inline size_t ProcessDataCount = 0x20; + + struct ProcessData { + os::ProcessId process_id; + u32 flags; + }; + static_assert(std::is_pod::value); + + enum ProcessDataFlag : u32 { + ProcessDataFlag_None = 0, + ProcessDataFlag_DetailedCrashReportAllowed = (1 << 0), + ProcessDataFlag_DetailedCrashReportEnabled = (1 << 1), + ProcessDataFlag_HasLogOption = (1 << 2), + ProcessDataFlag_OutputAllLog = (1 << 3), + ProcessDataFlag_EnableCrashReportScreenShot = (1 << 4), + }; + + bool g_is_production = true; + bool g_enable_crash_report_screenshot = true; + bool g_enable_jit_debug = false; + + os::SdkMutex g_process_data_mutex; + ProcessData g_process_data[ProcessDataCount]; + + ProcessData *FindProcessData(os::ProcessId process_id) { + for (auto &data : g_process_data) { + if (data.process_id == process_id) { + return std::addressof(data); + } + } + return nullptr; + } + + u32 ConvertToProcessDataFlags(u8 pgl_flags) { + if ((pgl_flags & pgl::LaunchFlags_EnableDetailedCrashReport) == 0) { + /* If we shouldn't generate detailed crash reports, set no flags. */ + return ProcessDataFlag_None; + } else { + /* We can and should generate detailed crash reports. */ + u32 data_flags = ProcessDataFlag_DetailedCrashReportAllowed | ProcessDataFlag_DetailedCrashReportEnabled; + + /* If we should enable crash report screenshots, check the correct flag. */ + if (g_enable_crash_report_screenshot) { + const u32 test_flag = g_is_production ? pgl::LaunchFlags_EnableCrashReportScreenShotForProduction : pgl::LaunchFlags_EnableCrashReportScreenShotForDevelop; + if ((pgl_flags & test_flag) != 0) { + data_flags |= ProcessDataFlag_EnableCrashReportScreenShot; + } + } + + return data_flags; + } + } + + } + + void InitializeProcessControlTask() { + /* TODO */ + } + + Result LaunchProgram(os::ProcessId *out, const ncm::ProgramLocation &loc, u32 pm_flags, u8 pgl_flags) { + /* Convert the input flags to the internal format. */ + const u32 data_flags = ConvertToProcessDataFlags(pgl_flags); + + /* If jit debug is enabled, we want to be signaled on crash. */ + if (g_enable_jit_debug) { + pm_flags |= pm::LaunchFlags_SignalOnException; + } + + /* Launch the process. */ + os::ProcessId process_id; + R_TRY(pm::shell::LaunchProgram(std::addressof(process_id), loc, pm_flags & pm::LaunchFlagsMask)); + + /* Create a ProcessData for the process. */ + { + std::scoped_lock lk(g_process_data_mutex); + ProcessData *new_data = FindProcessData(os::InvalidProcessId); + AMS_ABORT_UNLESS(new_data != nullptr); + + new_data->process_id = process_id; + new_data->flags = data_flags; + } + + /* We succeeded. */ + *out = process_id; + return ResultSuccess(); + } + + Result TerminateProcess(os::ProcessId process_id) { + return pm::shell::TerminateProcess(process_id); + } + +} \ No newline at end of file diff --git a/libraries/libstratosphere/source/pgl/srv/pgl_srv_shell.hpp b/libraries/libstratosphere/source/pgl/srv/pgl_srv_shell.hpp new file mode 100644 index 000000000..4819e1425 --- /dev/null +++ b/libraries/libstratosphere/source/pgl/srv/pgl_srv_shell.hpp @@ -0,0 +1,26 @@ +/* + * 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 . + */ +#pragma once +#include + +namespace ams::pgl::srv { + + void InitializeProcessControlTask(); + + Result LaunchProgram(os::ProcessId *out, const ncm::ProgramLocation &loc, u32 pm_flags, u8 pgl_flags); + Result TerminateProcess(os::ProcessId 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 new file mode 100644 index 000000000..e25dbb23b --- /dev/null +++ b/libraries/libstratosphere/source/pgl/srv/pgl_srv_shell_interface.cpp @@ -0,0 +1,70 @@ +/* + * 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 "pgl_srv_shell_interface.hpp" +#include "pgl_srv_shell.hpp" + +namespace ams::pgl::srv { + + Result ShellInterface::LaunchProgram(ams::sf::Out out, const ncm::ProgramLocation &loc, u32 pm_flags, u8 pgl_flags) { + return pgl::srv::LaunchProgram(out.GetPointer(), loc, pm_flags, pgl_flags); + } + + Result ShellInterface::TerminateProcess(os::ProcessId process_id) { + return pgl::srv::TerminateProcess(process_id); + } + + Result ShellInterface::LaunchProgramFromHost(ams::sf::Out out, const ams::sf::InBuffer &content_path, u32 pm_flags) { + /* TODO */ + } + + Result ShellInterface::GetHostContentMetaInfo(ams::sf::Out out, const ams::sf::InBuffer &content_path) { + /* TODO */ + } + + Result ShellInterface::GetApplicationProcessId(ams::sf::Out out) { + /* TODO */ + } + + Result ShellInterface::BoostSystemMemoryResourceLimit(u64 size) { + /* TODO */ + } + + Result ShellInterface::IsProcessTracked(ams::sf::Out out, os::ProcessId process_id) { + /* TODO */ + } + + Result ShellInterface::EnableApplicationCrashReport(bool enabled) { + /* TODO */ + } + + Result ShellInterface::IsApplicationCrashReportEnabled(ams::sf::Out out) { + /* TODO */ + } + + Result ShellInterface::EnableApplicationAllThreadDumpOnCrash(bool enabled) { + /* TODO */ + } + + Result ShellInterface::TriggerSnapShotDumper(const ams::sf::InBuffer &arg, SnapShotDumpType dump_type) { + /* TODO */ + } + + Result ShellInterface::GetShellEventObserver(ams::sf::Out> out) { + /* TODO */ + } + +} \ No newline at end of file diff --git a/libraries/libstratosphere/source/pgl/srv/pgl_srv_shell_interface.hpp b/libraries/libstratosphere/source/pgl/srv/pgl_srv_shell_interface.hpp new file mode 100644 index 000000000..7d3fe13f0 --- /dev/null +++ b/libraries/libstratosphere/source/pgl/srv/pgl_srv_shell_interface.hpp @@ -0,0 +1,50 @@ +/* + * 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 . + */ +#pragma once +#include + +namespace ams::pgl::srv { + + class ShellInterface final : public pgl::sf::IShellInterface { + NON_COPYABLE(ShellInterface); + NON_MOVEABLE(ShellInterface); + private: + MemoryResource *memory_resource; + public: + constexpr ShellInterface() : memory_resource(nullptr) { /* ... */ } + + void Initialize(MemoryResource *mr) { + AMS_ASSERT(this->memory_resource == nullptr); + this->memory_resource = mr; + } + public: + /* Interface commands. */ + virtual Result LaunchProgram(ams::sf::Out out, const ncm::ProgramLocation &loc, u32 pm_flags, u8 pgl_flags) override final; + virtual Result TerminateProcess(os::ProcessId process_id) override final; + virtual Result LaunchProgramFromHost(ams::sf::Out out, const ams::sf::InBuffer &content_path, u32 pm_flags) override final; + virtual Result GetHostContentMetaInfo(ams::sf::Out out, const ams::sf::InBuffer &content_path) override final; + virtual Result GetApplicationProcessId(ams::sf::Out out) override final; + virtual Result BoostSystemMemoryResourceLimit(u64 size) override final; + virtual Result IsProcessTracked(ams::sf::Out out, os::ProcessId process_id) override final; + virtual Result EnableApplicationCrashReport(bool enabled) override final; + virtual Result IsApplicationCrashReportEnabled(ams::sf::Out out) override final; + virtual Result EnableApplicationAllThreadDumpOnCrash(bool enabled) override final; + virtual Result TriggerSnapShotDumper(const ams::sf::InBuffer &arg, SnapShotDumpType dump_type) override final; + + virtual Result GetShellEventObserver(ams::sf::Out> out) override final; + }; + +} diff --git a/libraries/libstratosphere/source/pm/pm_shell_api.cpp b/libraries/libstratosphere/source/pm/pm_shell_api.cpp index c6a0b2f5e..40a32a163 100644 --- a/libraries/libstratosphere/source/pm/pm_shell_api.cpp +++ b/libraries/libstratosphere/source/pm/pm_shell_api.cpp @@ -24,4 +24,8 @@ namespace ams::pm::shell { return pmshellLaunchProgram(launch_flags, reinterpret_cast(&loc), reinterpret_cast(out_process_id)); } + Result TerminateProcess(os::ProcessId process_id) { + return ::pmshellTerminateProcess(static_cast(process_id)); + } + } diff --git a/stratosphere/pm/source/impl/pm_process_manager.cpp b/stratosphere/pm/source/impl/pm_process_manager.cpp index 21a80595f..bc8892e49 100644 --- a/stratosphere/pm/source/impl/pm_process_manager.cpp +++ b/stratosphere/pm/source/impl/pm_process_manager.cpp @@ -34,26 +34,6 @@ namespace ams::pm::impl { u32 flags; }; - enum LaunchFlags { - LaunchFlags_None = 0, - LaunchFlags_SignalOnExit = (1 << 0), - LaunchFlags_SignalOnStart = (1 << 1), - LaunchFlags_SignalOnException = (1 << 2), - LaunchFlags_SignalOnDebugEvent = (1 << 3), - LaunchFlags_StartSuspended = (1 << 4), - LaunchFlags_DisableAslr = (1 << 5), - }; - - enum LaunchFlagsDeprecated { - LaunchFlagsDeprecated_None = 0, - LaunchFlagsDeprecated_SignalOnExit = (1 << 0), - LaunchFlagsDeprecated_StartSuspended = (1 << 1), - LaunchFlagsDeprecated_SignalOnException = (1 << 2), - LaunchFlagsDeprecated_DisableAslr = (1 << 3), - LaunchFlagsDeprecated_SignalOnDebugEvent = (1 << 4), - LaunchFlagsDeprecated_SignalOnStart = (1 << 5), - }; - #define GET_FLAG_MASK(flag) (hos_version >= hos::Version_5_0_0 ? static_cast(LaunchFlags_##flag) : static_cast(LaunchFlagsDeprecated_##flag)) inline bool ShouldSignalOnExit(u32 launch_flags) {