diff --git a/stratosphere/pm/source/pm_registration.cpp b/stratosphere/pm/source/pm_registration.cpp index 05fbb66b1..b5296c500 100644 --- a/stratosphere/pm/source/pm_registration.cpp +++ b/stratosphere/pm/source/pm_registration.cpp @@ -39,6 +39,24 @@ static u64 g_resource_limits[3][5] = { static Handle g_resource_limit_handles[3] = {0}; +Registration::AutoProcessListLock::AutoProcessListLock() { + g_process_list.Lock(); + this->has_lock = true; +} + +Registration::AutoProcessListLock::~AutoProcessListLock() { + if (this->has_lock) { + this->Unlock(); + } +} + +void Registration::AutoProcessListLock::Unlock() { + if (this->has_lock) { + g_process_list.Unlock(); + } + this->has_lock = false; +} + void Registration::InitializeSystemResources() { g_process_event = new SystemEvent(&IEvent::PanicCallback); g_debug_title_event = new SystemEvent(&IEvent::PanicCallback); @@ -124,7 +142,7 @@ void Registration::HandleProcessLaunch() { /* Get the resource limit handle, ensure that we can launch the program. */ if ((program_info.application_type & 3) == 1) { - if (HasApplicationProcess()) { + if (HasApplicationProcess(NULL)) { rc = 0xA0F; goto HANDLE_PROCESS_LAUNCH_END; } @@ -310,8 +328,8 @@ void Registration::HandleSignaledProcess(Process *process) { } void Registration::FinalizeExitedProcess(Process *process) { + AutoProcessListLock auto_lock; bool signal_debug_process_5x = kernelAbove500() && process->flags & 1; - g_process_list.Lock(); /* Unregister with FS. */ if (R_FAILED(fsprUnregisterProgram(process->pid))) { /* TODO: Panic. */ @@ -338,20 +356,20 @@ void Registration::FinalizeExitedProcess(Process *process) { /* Remove NOTE: This probably frees process. */ RemoveProcessFromList(process->pid); - g_process_list.Unlock(); + auto_lock.Unlock(); if (signal_debug_process_5x) { g_process_event->signal_event(); } } void Registration::AddProcessToList(Process *process) { - g_process_list.Lock(); + AutoProcessListLock auto_lock; g_process_list.process_waiters.push_back(new ProcessWaiter(process)); - g_process_list.Unlock(); } void Registration::RemoveProcessFromList(u64 pid) { - g_process_list.Lock(); + AutoProcessListLock auto_lock; + /* Remove process from list. */ for (unsigned int i = 0; i < g_process_list.process_waiters.size(); i++) { ProcessWaiter *pw = g_process_list.process_waiters[i]; @@ -363,36 +381,120 @@ void Registration::RemoveProcessFromList(u64 pid) { break; } } - g_process_list.Unlock(); } void Registration::SetProcessState(u64 pid, ProcessState new_state) { - g_process_list.Lock(); + AutoProcessListLock auto_lock; + /* Set process state. */ - for (unsigned int i = 0; i < g_process_list.process_waiters.size(); i++) { - ProcessWaiter *pw = g_process_list.process_waiters[i]; + for (auto &pw : g_process_list.process_waiters) { Registration::Process *process = pw->get_process(); if (process->pid == pid) { process->state = new_state; break; } } - g_process_list.Unlock(); } -bool Registration::HasApplicationProcess() { - bool has_app = false; - g_process_list.Lock(); +bool Registration::HasApplicationProcess(Process **out) { + AutoProcessListLock auto_lock; for (auto &pw : g_process_list.process_waiters) { - if (pw->get_process()->flags & 0x40) { - has_app = true; - break; + Registration::Process *process = pw->get_process(); + if (process->flags & 0x40) { + if (out != NULL) { + *out = process; + } + return true; } } - g_process_list.Unlock(); - return has_app; + return false; +} + +Registration::Process *Registration::GetProcess(u64 pid) { + AutoProcessListLock auto_lock; + + for (auto &pw : g_process_list.process_waiters) { + Process *p = pw->get_process(); + if (p->pid == pid) { + return p; + } + } + + return NULL; +} + +Registration::Process *Registration::GetProcessByTitleId(u64 tid) { + AutoProcessListLock auto_lock; + + for (auto &pw : g_process_list.process_waiters) { + Process *p = pw->get_process(); + if (p->tid_sid.title_id == tid) { + return p; + } + } + + return NULL; +} + +Handle Registration::GetProcessEventHandle() { + return g_process_event->get_handle(); +} + +void Registration::GetProcessEventType(u64 *out_pid, u64 *out_type) { + AutoProcessListLock auto_lock; + + for (auto &pw : g_process_list.process_waiters) { + Process *p = pw->get_process(); + if (kernelAbove200() && p->state >= ProcessState_DebugDetached && p->flags & 0x100) { + p->flags &= ~0x100; + *out_pid = p->pid; + *out_type = kernelAbove500() ? 2 : 5; + return; + } + if (p->flags & 0x10) { + p->flags &= ~0x10; + *out_pid = p->pid; + *out_type = kernelAbove500() ? (((p->flags >> 5) & 1) | 4) : (((p->flags >> 5) & 1) + 3); + return; + } + if (p->flags & 2) { + *out_pid = p->pid; + *out_type = kernelAbove500() ? 3 : 1; + return; + } + if (!kernelAbove500() && p->flags & 1 && p->state == ProcessState_Exited) { + *out_pid = p->pid; + *out_type = 2; + return; + } + } + if (kernelAbove500()) { + auto_lock.Unlock(); + g_dead_process_list.Lock(); + if (g_dead_process_list.process_waiters.size()) { + ProcessWaiter *pw = g_dead_process_list.process_waiters[0]; + Registration::Process *process = pw->get_process(); + g_dead_process_list.process_waiters.erase(g_dead_process_list.process_waiters.begin()); + *out_pid = process->pid; + *out_type = 1; + delete pw; + g_dead_process_list.Unlock(); + return; + } + g_dead_process_list.Unlock(); + } + *out_pid = 0; + *out_type = 0; +} + +Handle Registration::GetDebugTitleEventHandle() { + return g_debug_title_event->get_handle(); +} + +Handle Registration::GetDebugApplicationEventHandle() { + return g_debug_application_event->get_handle(); } void Registration::EnsureApplicationResourcesAvailable() { diff --git a/stratosphere/pm/source/pm_registration.hpp b/stratosphere/pm/source/pm_registration.hpp index 832382e72..bb32988c4 100644 --- a/stratosphere/pm/source/pm_registration.hpp +++ b/stratosphere/pm/source/pm_registration.hpp @@ -31,7 +31,15 @@ class Registration { u64* out_pid; Result result; }; - + class AutoProcessListLock { + private: + bool has_lock; + public: + AutoProcessListLock(); + ~AutoProcessListLock(); + void Unlock(); + }; + static void InitializeSystemResources(); static IWaitable *GetProcessLaunchStartEvent(); static Result ProcessLaunchStartCallback(Handle *handles, size_t num_handles, u64 timeout); @@ -44,12 +52,19 @@ class Registration { static void RemoveProcessFromList(u64 pid); static void SetProcessState(u64 pid, ProcessState new_state); + static Process *GetProcess(u64 pid); + static Process *GetProcessByTitleId(u64 tid); + static Handle GetProcessEventHandle(); + static void GetProcessEventType(u64 *out_pid, u64 *out_type); + static Handle GetDebugTitleEventHandle(); + static Handle GetDebugApplicationEventHandle(); + static void HandleProcessLaunch(); static void SignalFinishLaunchProcess(); static Result LaunchProcess(u64 title_id, FsStorageId storage_id, u64 launch_flags, u64 *out_pid); static Result LaunchProcessByTidSid(TidSid tid_sid, u64 launch_flags, u64 *out_pid); - static bool HasApplicationProcess(); + static bool HasApplicationProcess(Process **out); static void EnsureApplicationResourcesAvailable(); }; diff --git a/stratosphere/pm/source/pm_shell.cpp b/stratosphere/pm/source/pm_shell.cpp index 3c6cce716..84ede2dfa 100644 --- a/stratosphere/pm/source/pm_shell.cpp +++ b/stratosphere/pm/source/pm_shell.cpp @@ -50,7 +50,7 @@ Result ShellService::dispatch(IpcParsedCommand &r, IpcCommand &out_c, u64 cmd_id case Shell_Cmd_GetProcessEventType: rc = WrapIpcCommandImpl<&ShellService::get_process_event_type>(this, r, out_c, pointer_buffer, pointer_buffer_size); break; - case Shell_Cmd_FinalizeDeadProcess: + case Shell_Cmd_FinalizeExitedProcess: rc = WrapIpcCommandImpl<&ShellService::finalize_dead_process>(this, r, out_c, pointer_buffer, pointer_buffer_size); break; case Shell_Cmd_ClearProcessNotificationFlag: @@ -78,55 +78,93 @@ Result ShellService::handle_deferred() { } std::tuple launch_process(u64 launch_flags, Registration::TidSid tid_sid) { - /* TODO */ - return {0xF601, 0}; + u64 pid = 0; + Result rc = Registration::LaunchProcessByTidSid(tid_sid, launch_flags, &pid); + return {rc, pid}; } std::tuple terminate_process_id(u64 pid) { - /* TODO */ - return {0xF601}; + Registration::AutoProcessListLock auto_lock; + + Registration::Process *proc = Registration::GetProcess(pid); + if (proc != NULL) { + return {svcCloseHandle(proc->handle)}; + } else { + return {0x20F}; + } } std::tuple terminate_title_id(u64 tid) { - /* TODO */ - return {0xF601}; + Registration::AutoProcessListLock auto_lock; + + Registration::Process *proc = Registration::GetProcessByTitleId(tid); + if (proc != NULL) { + return {svcCloseHandle(proc->handle)}; + } else { + return {0x20F}; + } } std::tuple get_process_wait_event() { - /* TODO */ - return {0xF601, 0}; + return {0x0, Registration::GetProcessEventHandle()}; } std::tuple get_process_event_type() { - /* TODO */ - return {0xF601, 0, 0}; + u64 type, pid; + Registration::GetProcessEventType(&pid, &type); + return {0x0, type, pid}; } -std::tuple finalize_dead_process(u64 pid) { - /* TODO */ - return {0xF601}; +std::tuple finalize_exited_process(u64 pid) { + Registration::AutoProcessListLock auto_lock; + + Registration::Process *proc = Registration::GetProcess(pid); + if (proc == NULL) { + return {0x20F}; + } else if (proc->state != ProcessState_Exited) { + return {0x60F}; + } else { + Registration::FinalizeExitedProcess(proc); + return {0x0}; + } } std::tuple clear_process_notification_flag(u64 pid) { - /* TODO */ - return {0xF601}; + Registration::AutoProcessListLock auto_lock; + + Registration::Process *proc = Registration::GetProcess(pid); + if (proc != NULL) { + proc->flags &= ~2; + return {0x0}; + } else { + return {0x20F}; + } } std::tuple notify_boot_finished() { - u64 boot_pid; + u64 boot2_pid; if (!g_has_boot_finished) { - Registration::LaunchProcess(BOOT2_TITLE_ID, FsStorageId_NandSystem, 0, &boot_pid); g_has_boot_finished = true; + return {Registration::LaunchProcess(BOOT2_TITLE_ID, FsStorageId_NandSystem, 0, &boot2_pid)}; } return {0}; } std::tuple get_application_process_id() { - /* TODO */ - return {0xF601, 0}; + Registration::AutoProcessListLock auto_lock; + + Registration::Process *app_proc; + if (Registration::HasApplicationProcess(&app_proc)) { + return {0, app_proc->pid}; + } + return {0x20F, 0}; } std::tuple boost_system_memory_resource_limit() { + if (!kernelAbove400()) { + return {0xF601}; + } + /* TODO */ return {0xF601}; } diff --git a/stratosphere/pm/source/pm_shell.hpp b/stratosphere/pm/source/pm_shell.hpp index a8270f6a1..b7627e08b 100644 --- a/stratosphere/pm/source/pm_shell.hpp +++ b/stratosphere/pm/source/pm_shell.hpp @@ -12,7 +12,7 @@ enum ShellCmd { Shell_Cmd_TerminateTitleId = 2, Shell_Cmd_GetProcessWaitEvent = 3, Shell_Cmd_GetProcessEventType = 4, - Shell_Cmd_FinalizeDeadProcess = 5, + Shell_Cmd_FinalizeExitedProcess = 5, Shell_Cmd_ClearProcessNotificationFlag = 6, Shell_Cmd_NotifyBootFinished = 7, Shell_Cmd_GetApplicationProcessId = 8,