diff --git a/stratosphere/libstratosphere b/stratosphere/libstratosphere index d7d7cba3d..45700a12e 160000 --- a/stratosphere/libstratosphere +++ b/stratosphere/libstratosphere @@ -1 +1 @@ -Subproject commit d7d7cba3d35e5aa029ace71891e317e0d5412131 +Subproject commit 45700a12e80404e3c49e2bc4893412489fc72040 diff --git a/stratosphere/pm/source/boot2/boot2_api.cpp b/stratosphere/pm/source/boot2/boot2_api.cpp index ca9e43b46..8a0862095 100644 --- a/stratosphere/pm/source/boot2/boot2_api.cpp +++ b/stratosphere/pm/source/boot2/boot2_api.cpp @@ -137,11 +137,6 @@ namespace sts::boot2 { void LaunchTitle(u64 *out_process_id, const ncm::TitleLocation &loc, u32 launch_flags) { u64 process_id = 0; - /* Don't launch a title twice during boot2. */ - if (pm::info::HasLaunchedTitle(loc.title_id)) { - return; - } - switch (pm::shell::LaunchTitle(&process_id, loc, launch_flags)) { case ResultKernelResourceExhausted: /* Out of resource! */ @@ -186,11 +181,9 @@ namespace sts::boot2 { bool IsMaintenanceMode() { /* Contact set:sys, retrieve boot!force_maintenance. */ - DoWithSmSession([&]() { - R_ASSERT(setsysInitialize()); - }); { - ON_SCOPE_EXIT { setsysExit(); }; + auto set_sys_holder = sm::ScopedServiceHolder(); + R_ASSERT(set_sys_holder.GetResult()); u8 force_maintenance = 1; setsysGetSettingsItemValue("boot", "force_maintenance", &force_maintenance, sizeof(force_maintenance)); @@ -200,50 +193,36 @@ namespace sts::boot2 { } /* Contact GPIO, read plus/minus buttons. */ - DoWithSmSession([&]() { - R_ASSERT(gpioInitialize()); - }); { - ON_SCOPE_EXIT { gpioExit(); }; + auto gpio_holder = sm::ScopedServiceHolder(); + R_ASSERT(gpio_holder.GetResult()); return GetGpioPadLow(GpioPadName_ButtonVolUp) && GetGpioPadLow(GpioPadName_ButtonVolDown); } } - void WaitForMitm(const char *service) { - const auto name = sts::sm::ServiceName::Encode(service); - - while (true) { - bool mitm_installed = false; - R_ASSERT(sts::sm::mitm::HasMitm(&mitm_installed, name)); - if (mitm_installed) { - break; - } - svcSleepThread(1'000'000ull); - } - } - void LaunchFlaggedProgramsFromSdCard() { /* Allow for user-customizable programs. */ DIR *titles_dir = opendir("sdmc:/atmosphere/titles"); struct dirent *ent; - if (titles_dir != NULL) { - while ((ent = readdir(titles_dir)) != NULL) { + if (titles_dir != nullptr) { + ON_SCOPE_EXIT { closedir(titles_dir); }; + + while ((ent = readdir(titles_dir)) != nullptr) { if (strlen(ent->d_name) == 2 * sizeof(u64) && IsHexadecimal(ent->d_name)) { - ncm::TitleId title_id{strtoul(ent->d_name, NULL, 16)}; + ncm::TitleId title_id{strtoul(ent->d_name, nullptr, 16)}; if (pm::info::HasLaunchedTitle(title_id)) { return; } char title_path[FS_MAX_PATH]; std::snprintf(title_path, sizeof(title_path), "sdmc:/atmosphere/titles/%s/flags/boot2.flag", ent->d_name); FILE *f_flag = fopen(title_path, "rb"); - if (f_flag != NULL) { + if (f_flag != nullptr) { fclose(f_flag); LaunchTitle(nullptr, ncm::TitleLocation::Make(title_id, ncm::StorageId::None), 0); } } } - closedir(titles_dir); } } @@ -252,7 +231,7 @@ namespace sts::boot2 { /* Boot2 API. */ void LaunchBootPrograms() { /* Wait until fs.mitm has installed itself. We want this to happen as early as possible. */ - WaitForMitm("fsp-srv"); + R_ASSERT(sm::mitm::WaitMitm(sm::ServiceName::Encode("fsp-srv"))); /* Launch programs required to mount the SD card. */ LaunchList(PreSdCardLaunchPrograms, NumPreSdCardLaunchPrograms); @@ -268,10 +247,11 @@ namespace sts::boot2 { } /* Wait for other atmosphere mitm modules to initialize. */ + R_ASSERT(sm::mitm::WaitMitm(sm::ServiceName::Encode("set:sys"))); if (GetRuntimeFirmwareVersion() >= FirmwareVersion_200) { - WaitForMitm("bpc"); + R_ASSERT(sm::mitm::WaitMitm(sm::ServiceName::Encode("bpc"))); } else { - WaitForMitm("bpc:c"); + R_ASSERT(sm::mitm::WaitMitm(sm::ServiceName::Encode("bpc:c"))); } /* Launch Atmosphere dmnt, using FsStorageId_None to force SD card boot. */ diff --git a/stratosphere/pm/source/impl/pm_process_info.hpp b/stratosphere/pm/source/impl/pm_process_info.hpp index 7a0e98198..5be9f3bc4 100644 --- a/stratosphere/pm/source/impl/pm_process_info.hpp +++ b/stratosphere/pm/source/impl/pm_process_info.hpp @@ -86,63 +86,6 @@ namespace sts::pm::impl { this->state = state; } - void SetSignalOnExit() { - this->SetFlag(Flag_SignalOnExit); - } - - void SetExceptionOccurred() { - this->SetFlag(Flag_ExceptionOccurred); - this->SetFlag(Flag_ExceptionWaitingAttach); - } - - void ClearExceptionOccurred() { - this->ClearFlag(Flag_ExceptionOccurred); - } - - void ClearExceptionWaitingAttach() { - this->ClearFlag(Flag_ExceptionWaitingAttach); - } - - void SetSignalOnDebugEvent() { - this->SetFlag(Flag_SignalOnDebugEvent); - } - - void SetSuspendedStateChanged() { - this->SetFlag(Flag_SuspendedStateChanged); - } - - void ClearSuspendedStateChanged() { - this->ClearFlag(Flag_SuspendedStateChanged); - } - - void SetSuspended() { - this->SetFlag(Flag_Suspended); - } - - void ClearSuspended() { - this->ClearFlag(Flag_Suspended); - } - - void SetApplication() { - this->SetFlag(Flag_Application); - } - - void SetSignalOnStart() { - this->SetFlag(Flag_SignalOnStart); - } - - void ClearSignalOnStart() { - this->ClearFlag(Flag_SignalOnStart); - } - - void SetStartedStateChanged() { - this->SetFlag(Flag_StartedStateChanged); - } - - void ClearStartedStateChanged() { - this->ClearFlag(Flag_StartedStateChanged); - } - bool HasStarted() const { return this->state != ProcessState_Created && this->state != ProcessState_CreatedAttached; } @@ -151,41 +94,60 @@ namespace sts::pm::impl { return this->state == ProcessState_Exited; } - bool ShouldSignalOnExit() const { - return this->HasFlag(Flag_SignalOnExit); +#define DEFINE_FLAG_SET(flag) \ + void Set##flag() { \ + this->SetFlag(Flag_##flag); \ } - bool HasExceptionOccurred() const { - return this->HasFlag(Flag_ExceptionOccurred); +#define DEFINE_FLAG_GET(get, flag) \ + bool get##flag() const { \ + return this->HasFlag(Flag_##flag); \ } - bool HasExceptionWaitingAttach() const { - return this->HasFlag(Flag_ExceptionWaitingAttach); +#define DEFINE_FLAG_CLEAR(flag) \ + void Clear##flag() { \ + this->ClearFlag(Flag_##flag); \ } - bool ShouldSignalOnDebugEvent() const { - return this->HasFlag(Flag_SignalOnDebugEvent); + DEFINE_FLAG_SET(SignalOnExit) + DEFINE_FLAG_GET(Should, SignalOnExit) + + /* This needs a manual setter, because it sets two flags. */ + void SetExceptionOccurred() { + this->SetFlag(Flag_ExceptionOccurred); + this->SetFlag(Flag_ExceptionWaitingAttach); } - bool ShouldSignalOnStart() const { - return this->HasFlag(Flag_SignalOnStart); - } + DEFINE_FLAG_GET(Has, ExceptionOccurred) + DEFINE_FLAG_GET(Has, ExceptionWaitingAttach) + DEFINE_FLAG_CLEAR(ExceptionOccurred) + DEFINE_FLAG_CLEAR(ExceptionWaitingAttach) - bool HasSuspendedStateChanged() const { - return this->HasFlag(Flag_SuspendedStateChanged); - } + DEFINE_FLAG_SET(SignalOnDebugEvent) + DEFINE_FLAG_GET(Should, SignalOnDebugEvent) - bool IsSuspended() const { - return this->HasFlag(Flag_Suspended); - } + DEFINE_FLAG_SET(SuspendedStateChanged) + DEFINE_FLAG_GET(Has, SuspendedStateChanged) + DEFINE_FLAG_CLEAR(SuspendedStateChanged) - bool IsApplication() const { - return this->HasFlag(Flag_Application); - } + DEFINE_FLAG_SET(Suspended) + DEFINE_FLAG_GET(Is, Suspended) + DEFINE_FLAG_CLEAR(Suspended) - bool HasStartedStateChanged() const { - return this->HasFlag(Flag_StartedStateChanged); - } + DEFINE_FLAG_SET(Application) + DEFINE_FLAG_GET(Is, Application) + + DEFINE_FLAG_SET(SignalOnStart) + DEFINE_FLAG_GET(Should, SignalOnStart) + DEFINE_FLAG_CLEAR(SignalOnStart) + + DEFINE_FLAG_SET(StartedStateChanged) + DEFINE_FLAG_GET(Has, StartedStateChanged) + DEFINE_FLAG_CLEAR(StartedStateChanged) + +#undef DEFINE_FLAG_SET +#undef DEFINE_FLAG_GET +#undef DEFINE_FLAG_CLEAR }; @@ -195,7 +157,7 @@ namespace sts::pm::impl { private: std::shared_ptr process_info; public: - ProcessInfoWaiter(std::shared_ptr p) : process_info(p) { /* ... */ } + ProcessInfoWaiter(std::shared_ptr p) : process_info(std::move(p)) { /* ... */ } /* IWaitable */ Handle GetHandle() override { @@ -235,27 +197,27 @@ namespace sts::pm::impl { } void Remove(u64 process_id) { - for (size_t i = 0; i < this->processes.size(); i++) { - if (this->processes[i]->GetProcessId() == process_id) { - this->processes.erase(this->processes.begin() + i); + for (auto it = this->processes.begin(); it != this->processes.end(); it++) { + if ((*it)->GetProcessId() == process_id) { + this->processes.erase(it); break; } } } std::shared_ptr Find(u64 process_id) { - for (size_t i = 0; i < this->processes.size(); i++) { - if (this->processes[i]->GetProcessId() == process_id) { - return this->processes[i]; + for (auto it = this->processes.begin(); it != this->processes.end(); it++) { + if ((*it)->GetProcessId() == process_id) { + return *it; } } return nullptr; } std::shared_ptr Find(ncm::TitleId title_id) { - for (size_t i = 0; i < this->processes.size(); i++) { - if (this->processes[i]->GetTitleLocation().title_id == title_id) { - return this->processes[i]; + for (auto it = this->processes.begin(); it != this->processes.end(); it++) { + if ((*it)->GetTitleLocation().title_id == title_id) { + return *it; } } return nullptr; diff --git a/stratosphere/pm/source/impl/pm_process_manager.cpp b/stratosphere/pm/source/impl/pm_process_manager.cpp index 1b75e7f60..148dab43c 100644 --- a/stratosphere/pm/source/impl/pm_process_manager.cpp +++ b/stratosphere/pm/source/impl/pm_process_manager.cpp @@ -141,20 +141,20 @@ namespace sts::pm::impl { /* Process Tracking globals. */ HosThread g_process_track_thread; - SessionManagerBase *g_process_waitable_manager = nullptr; + auto g_process_waitable_manager = WaitableManager(1); /* Process lists. */ ProcessList g_process_list; ProcessList g_dead_process_list; /* Global events. */ - IEvent *g_process_event = nullptr; - IEvent *g_hook_to_create_process_event = nullptr; - IEvent *g_hook_to_create_application_process_event = nullptr; - IEvent *g_boot_finished_event = nullptr; + IEvent *g_process_event = CreateWriteOnlySystemEvent(); + IEvent *g_hook_to_create_process_event = CreateWriteOnlySystemEvent(); + IEvent *g_hook_to_create_application_process_event = CreateWriteOnlySystemEvent(); + IEvent *g_boot_finished_event = CreateWriteOnlySystemEvent(); /* Process Launch synchronization globals. */ - IEvent *g_process_launch_start_event = nullptr; + IEvent *g_process_launch_start_event = CreateWriteOnlySystemEvent(); HosSignal g_process_launch_finish_signal; Result g_process_launch_result = ResultSuccess; LaunchProcessArgs g_process_launch_args = {}; @@ -167,13 +167,9 @@ namespace sts::pm::impl { void ProcessTrackingMain(void *arg) { /* This is the main loop of the process tracking thread. */ - /* Create waitable manager. */ - static auto s_process_waiter = WaitableManager(1); - g_process_waitable_manager = &s_process_waiter; - /* Service processes. */ - g_process_waitable_manager->AddWaitable(g_process_launch_start_event); - g_process_waitable_manager->Process(); + g_process_waitable_manager.AddWaitable(g_process_launch_start_event); + g_process_waitable_manager.Process(); } inline u32 GetLoaderCreateProcessFlags(u32 launch_flags) { @@ -189,6 +185,18 @@ namespace sts::pm::impl { return ldr_flags; } + bool HasApplicationProcess() { + ProcessListAccessor list(g_process_list); + + for (size_t i = 0; i < list->GetSize(); i++) { + if (list[i]->IsApplication()) { + return true; + } + } + + return false; + } + Result StartProcess(std::shared_ptr process_info, const ldr::ProgramInfo *program_info) { R_TRY(svcStartProcess(process_info->GetHandle(), program_info->main_thread_priority, program_info->default_cpu_id, program_info->main_thread_stack_size)); process_info->SetState(ProcessState_Running); @@ -203,7 +211,7 @@ namespace sts::pm::impl { const bool allow_debug = (program_info.flags & ldr::ProgramInfoFlag_AllowDebug) || GetRuntimeFirmwareVersion() < FirmwareVersion_200; /* Ensure we only try to run one application. */ - if (is_application) { + if (is_application && HasApplicationProcess()) { return ResultPmApplicationRunning; } @@ -268,7 +276,7 @@ namespace sts::pm::impl { { ProcessListAccessor list(g_process_list); list->Add(process_info); - g_process_waitable_manager->AddWaitable(new ProcessInfoWaiter(process_info)); + g_process_waitable_manager.AddWaitable(new ProcessInfoWaiter(process_info)); } *args->out_process_id = process_id; @@ -395,7 +403,7 @@ namespace sts::pm::impl { Result LaunchTitle(u64 *out_process_id, const ncm::TitleLocation &loc, u32 flags) { /* Ensure we only try to launch one title at a time. */ static HosMutex s_lock; - std::scoped_lock lk(s_lock); + std::scoped_lock lk(s_lock); /* Set global arguments, signal, wait. */ g_process_launch_args = { diff --git a/stratosphere/pm/source/pm_debug_monitor_service.hpp b/stratosphere/pm/source/pm_debug_monitor_service.hpp index 88f7b2e75..edd125b40 100644 --- a/stratosphere/pm/source/pm_debug_monitor_service.hpp +++ b/stratosphere/pm/source/pm_debug_monitor_service.hpp @@ -47,7 +47,7 @@ namespace sts::pm::dmnt { class DebugMonitorService final : public DebugMonitorServiceBase { private: enum class CommandId { - GetExceptionProcessIdList = 0, + GetExceptionProcessIdList = 0, StartProcess = 1, GetProcessId = 2, HookToCreateProcess = 3, @@ -83,7 +83,7 @@ namespace sts::pm::dmnt { private: enum class CommandId { GetModuleIdList = 0, - GetExceptionProcessIdList = 1, + GetExceptionProcessIdList = 1, StartProcess = 2, GetProcessId = 3, HookToCreateProcess = 4, diff --git a/stratosphere/pm/source/pm_main.cpp b/stratosphere/pm/source/pm_main.cpp index b4e52cb66..b93bf6111 100644 --- a/stratosphere/pm/source/pm_main.cpp +++ b/stratosphere/pm/source/pm_main.cpp @@ -72,9 +72,9 @@ void __libnx_initheap(void) { namespace { - static constexpr u32 PrivilegedFileAccessHeader[0x1C / sizeof(u32)] = {0x00000001, 0x00000000, 0x80000000, 0x0000001C, 0x00000000, 0x0000001C, 0x00000000}; - static constexpr u32 PrivilegedFileAccessControl[0x2C / sizeof(u32)] = {0x00000001, 0x00000000, 0x80000000, 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF}; - static constexpr size_t ProcessCountMax = 0x40; + constexpr u32 PrivilegedFileAccessHeader[0x1C / sizeof(u32)] = {0x00000001, 0x00000000, 0x80000000, 0x0000001C, 0x00000000, 0x0000001C, 0x00000000}; + constexpr u32 PrivilegedFileAccessControl[0x2C / sizeof(u32)] = {0x00000001, 0x00000000, 0x80000000, 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF}; + constexpr size_t ProcessCountMax = 0x40; /* This works around a bug fixed by FS in 4.0.0. */ /* Not doing so will cause KIPs with higher process IDs than 7 to be unable to use filesystem services. */ diff --git a/stratosphere/sm/source/impl/sm_service_manager.cpp b/stratosphere/sm/source/impl/sm_service_manager.cpp index a09b097cc..ab9ba143c 100644 --- a/stratosphere/sm/source/impl/sm_service_manager.cpp +++ b/stratosphere/sm/source/impl/sm_service_manager.cpp @@ -459,6 +459,17 @@ namespace sts::sm::impl { return ResultSuccess; } + Result WaitService(ServiceName service) { + bool has_service = false; + R_TRY(impl::HasService(&has_service, service)); + + /* Wait until we have the service. */ + if (!has_service) { + return ResultServiceFrameworkRequestDeferredByUser; + } + return ResultSuccess; + } + Result GetServiceHandle(Handle *out, u64 pid, ServiceName service) { /* Validate service name. */ R_TRY(ValidateServiceName(service)); @@ -564,6 +575,17 @@ namespace sts::sm::impl { return ResultSuccess; } + Result WaitMitm(ServiceName service) { + bool has_mitm = false; + R_TRY(impl::HasMitm(&has_mitm, service)); + + /* Wait until we have the mitm. */ + if (!has_mitm) { + return ResultServiceFrameworkRequestDeferredByUser; + } + return ResultSuccess; + } + Result InstallMitm(Handle *out, Handle *out_query, u64 pid, ServiceName service) { /* Validate service name. */ R_TRY(ValidateServiceName(service)); diff --git a/stratosphere/sm/source/impl/sm_service_manager.hpp b/stratosphere/sm/source/impl/sm_service_manager.hpp index f836e8957..3c8b55da6 100644 --- a/stratosphere/sm/source/impl/sm_service_manager.hpp +++ b/stratosphere/sm/source/impl/sm_service_manager.hpp @@ -26,6 +26,7 @@ namespace sts::sm::impl { /* Service management. */ Result HasService(bool *out, ServiceName service); + Result WaitService(ServiceName service); Result GetServiceHandle(Handle *out, u64 pid, ServiceName service); Result RegisterService(Handle *out, u64 pid, ServiceName service, size_t max_sessions, bool is_light); Result RegisterServiceForSelf(Handle *out, ServiceName service, size_t max_sessions); @@ -33,6 +34,7 @@ namespace sts::sm::impl { /* Mitm extensions. */ Result HasMitm(bool *out, ServiceName service); + Result WaitMitm(ServiceName service); Result InstallMitm(Handle *out, Handle *out_query, u64 pid, ServiceName service); Result UninstallMitm(u64 pid, ServiceName service); Result AcknowledgeMitmSession(u64 *out_pid, Handle *out_hnd, u64 pid, ServiceName service); diff --git a/stratosphere/sm/source/sm_user_service.cpp b/stratosphere/sm/source/sm_user_service.cpp index bb2fd7c18..b6ec513fa 100644 --- a/stratosphere/sm/source/sm_user_service.cpp +++ b/stratosphere/sm/source/sm_user_service.cpp @@ -75,9 +75,19 @@ namespace sts::sm { return impl::HasMitm(out.GetPointer(), service); } + Result UserService::AtmosphereWaitMitm(ServiceName service) { + R_TRY(this->EnsureInitialized()); + return impl::WaitMitm(service); + } + Result UserService::AtmosphereHasService(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); + } + } diff --git a/stratosphere/sm/source/sm_user_service.hpp b/stratosphere/sm/source/sm_user_service.hpp index 5572dd2c2..3347f9236 100644 --- a/stratosphere/sm/source/sm_user_service.hpp +++ b/stratosphere/sm/source/sm_user_service.hpp @@ -36,8 +36,10 @@ namespace sts::sm { AtmosphereAssociatePidTidForMitm = 65002, AtmosphereAcknowledgeMitmSession = 65003, AtmosphereHasMitm = 65004, + AtmosphereWaitMitm = 65005, AtmosphereHasService = 65100, + AtmosphereWaitService = 65101, }; private: u64 pid = InvalidProcessId; @@ -57,8 +59,10 @@ namespace sts::sm { virtual Result AtmosphereAssociatePidTidForMitm(u64 pid, u64 tid); virtual Result AtmosphereAcknowledgeMitmSession(Out client_pid, Out fwd_h, ServiceName service); virtual Result AtmosphereHasMitm(Out out, ServiceName service); + virtual Result AtmosphereWaitMitm(ServiceName service); virtual Result AtmosphereHasService(Out out, ServiceName service); + virtual Result AtmosphereWaitService(ServiceName service); public: DEFINE_SERVICE_DISPATCH_TABLE { MAKE_SERVICE_COMMAND_META(UserService, Initialize), @@ -71,8 +75,10 @@ namespace sts::sm { MAKE_SERVICE_COMMAND_META(UserService, AtmosphereAssociatePidTidForMitm), MAKE_SERVICE_COMMAND_META(UserService, AtmosphereAcknowledgeMitmSession), MAKE_SERVICE_COMMAND_META(UserService, AtmosphereHasMitm), + MAKE_SERVICE_COMMAND_META(UserService, AtmosphereWaitMitm), MAKE_SERVICE_COMMAND_META(UserService, AtmosphereHasService), + MAKE_SERVICE_COMMAND_META(UserService, AtmosphereWaitService), }; };