diff --git a/stratosphere/pm/pm.json b/stratosphere/pm/pm.json index f999cdcc7..005504b72 100644 --- a/stratosphere/pm/pm.json +++ b/stratosphere/pm/pm.json @@ -1,7 +1,7 @@ { "name": "ProcessManager", "title_id": "0x0100000000000003", - "main_thread_stack_size": "0x00002000", + "main_thread_stack_size": "0x00003000", "main_thread_priority": 49, "default_cpu_id": 3, "process_category": 1, diff --git a/stratosphere/pm/source/impl/pm_process_info.cpp b/stratosphere/pm/source/impl/pm_process_info.cpp index a867cac5b..90373b55a 100644 --- a/stratosphere/pm/source/impl/pm_process_info.cpp +++ b/stratosphere/pm/source/impl/pm_process_info.cpp @@ -18,6 +18,64 @@ namespace ams::pm::impl { + namespace { + + template + class ProcessInfoAllocator { + NON_COPYABLE(ProcessInfoAllocator); + NON_MOVEABLE(ProcessInfoAllocator); + static_assert(MaxProcessInfos >= 0x40, "MaxProcessInfos is too small."); + private: + util::TypedStorage m_process_info_storages[MaxProcessInfos]{}; + bool m_process_info_allocated[MaxProcessInfos]{}; + os::SdkMutex m_lock{}; + private: + constexpr inline size_t GetProcessInfoIndex(ProcessInfo *process_info) const { + return process_info - GetPointer(m_process_info_storages[0]); + } + public: + constexpr ProcessInfoAllocator() = default; + + template + ProcessInfo *AllocateProcessInfo(Args &&... args) { + std::scoped_lock lk(m_lock); + + for (size_t i = 0; i < MaxProcessInfos; i++) { + if (!m_process_info_allocated[i]) { + m_process_info_allocated[i] = true; + + std::memset(m_process_info_storages + i, 0, sizeof(m_process_info_storages[i])); + + return util::ConstructAt(m_process_info_storages[i], std::forward(args)...); + } + } + + return nullptr; + } + + void FreeProcessInfo(ProcessInfo *process_info) { + std::scoped_lock lk(m_lock); + + const size_t index = this->GetProcessInfoIndex(process_info); + AMS_ABORT_UNLESS(index < MaxProcessInfos); + AMS_ABORT_UNLESS(m_process_info_allocated[index]); + + util::DestroyAt(m_process_info_storages[index]); + m_process_info_allocated[index] = false; + } + }; + + /* Process lists. */ + constinit ProcessList g_process_list; + constinit ProcessList g_exit_list; + + /* Process Info Allocation. */ + /* Note: The kernel slabheap is size 0x50 -- we allow slightly larger to account for the dead process list. */ + constexpr size_t MaxProcessCount = 0x60; + constinit ProcessInfoAllocator g_process_info_allocator; + + } + ProcessInfo::ProcessInfo(os::NativeHandle h, os::ProcessId pid, ldr::PinId pin, const ncm::ProgramLocation &l, const cfg::OverrideStatus &s) : m_process_id(pid), m_pin_id(pin), m_loc(l), m_status(s), m_handle(h), m_state(svc::ProcessState_Created), m_flags(0) { os::InitializeMultiWaitHolder(std::addressof(m_multi_wait_holder), m_handle); os::SetMultiWaitHolderUserData(std::addressof(m_multi_wait_holder), reinterpret_cast(this)); @@ -37,10 +95,27 @@ namespace ams::pm::impl { /* Close the process's handle. */ os::CloseNativeHandle(m_handle); m_handle = os::InvalidNativeHandle; - - /* Unlink the process from its multi wait. */ - os::UnlinkMultiWaitHolder(std::addressof(m_multi_wait_holder)); } } + ProcessListAccessor GetProcessList() { + return ProcessListAccessor(g_process_list); + } + + ProcessListAccessor GetExitList() { + return ProcessListAccessor(g_exit_list); + } + + ProcessInfo *AllocateProcessInfo(svc::Handle process_handle, os::ProcessId process_id, ldr::PinId pin_id, const ncm::ProgramLocation &location, const cfg::OverrideStatus &override_status) { + return g_process_info_allocator.AllocateProcessInfo(process_handle, process_id, pin_id, location, override_status); + } + + void CleanupProcessInfo(ProcessListAccessor &list, ProcessInfo *process_info) { + /* Remove the process from the list. */ + list->Remove(process_info); + + /* Delete the process. */ + g_process_info_allocator.FreeProcessInfo(process_info); + } + } diff --git a/stratosphere/pm/source/impl/pm_process_info.hpp b/stratosphere/pm/source/impl/pm_process_info.hpp index f89403767..f2dae02ae 100644 --- a/stratosphere/pm/source/impl/pm_process_info.hpp +++ b/stratosphere/pm/source/impl/pm_process_info.hpp @@ -64,8 +64,8 @@ namespace ams::pm::impl { ~ProcessInfo(); void Cleanup(); - void LinkToMultiWait(os::MultiWaitType &multi_wait) { - os::LinkMultiWaitHolder(std::addressof(multi_wait), std::addressof(m_multi_wait_holder)); + os::MultiWaitHolderType *GetMultiWaitHolder() { + return std::addressof(m_multi_wait_holder); } os::NativeHandle GetHandle() const { @@ -232,4 +232,10 @@ namespace ams::pm::impl { } }; + ProcessListAccessor GetProcessList(); + ProcessListAccessor GetExitList(); + + ProcessInfo *AllocateProcessInfo(svc::Handle process_handle, os::ProcessId process_id, ldr::PinId pin_id, const ncm::ProgramLocation &location, const cfg::OverrideStatus &override_status); + void CleanupProcessInfo(ProcessListAccessor &list, ProcessInfo *process_info); + } diff --git a/stratosphere/pm/source/impl/pm_process_manager.cpp b/stratosphere/pm/source/impl/pm_process_manager.cpp index 036814f66..32ef0feac 100644 --- a/stratosphere/pm/source/impl/pm_process_manager.cpp +++ b/stratosphere/pm/source/impl/pm_process_manager.cpp @@ -15,9 +15,9 @@ */ #include #include "pm_process_manager.hpp" -#include "pm_resource_manager.hpp" - +#include "pm_process_tracker.hpp" #include "pm_process_info.hpp" +#include "pm_spec.hpp" namespace ams::pm::impl { @@ -29,13 +29,7 @@ namespace ams::pm::impl { HookType_Application = (1 << 1), }; - struct LaunchProcessArgs { - os::ProcessId *out_process_id; - ncm::ProgramLocation location; - u32 flags; - }; - -#define GET_FLAG_MASK(flag) (hos_version >= hos::Version_5_0_0 ? static_cast(LaunchFlags_##flag) : static_cast(LaunchFlagsDeprecated_##flag)) + #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) { const auto hos_version = hos::GetVersion(); @@ -70,115 +64,26 @@ namespace ams::pm::impl { return launch_flags & GET_FLAG_MASK(DisableAslr); } -#undef GET_FLAG_MASK - - template - class ProcessInfoAllocator { - NON_COPYABLE(ProcessInfoAllocator); - NON_MOVEABLE(ProcessInfoAllocator); - static_assert(MaxProcessInfos >= 0x40, "MaxProcessInfos is too small."); - private: - util::TypedStorage m_process_info_storages[MaxProcessInfos]{}; - bool m_process_info_allocated[MaxProcessInfos]{}; - os::SdkMutex m_lock{}; - private: - constexpr inline size_t GetProcessInfoIndex(ProcessInfo *process_info) const { - return process_info - GetPointer(m_process_info_storages[0]); - } - public: - constexpr ProcessInfoAllocator() = default; - - template - ProcessInfo *AllocateProcessInfo(Args &&... args) { - std::scoped_lock lk(m_lock); - - for (size_t i = 0; i < MaxProcessInfos; i++) { - if (!m_process_info_allocated[i]) { - m_process_info_allocated[i] = true; - - std::memset(m_process_info_storages + i, 0, sizeof(m_process_info_storages[i])); - - return util::ConstructAt(m_process_info_storages[i], std::forward(args)...); - } - } - - return nullptr; - } - - void FreeProcessInfo(ProcessInfo *process_info) { - std::scoped_lock lk(m_lock); - - const size_t index = this->GetProcessInfoIndex(process_info); - AMS_ABORT_UNLESS(index < MaxProcessInfos); - AMS_ABORT_UNLESS(m_process_info_allocated[index]); - - util::DestroyAt(m_process_info_storages[index]); - m_process_info_allocated[index] = false; - } - }; + #undef GET_FLAG_MASK /* Process Tracking globals. */ - void ProcessTrackingMain(void *); - - constinit os::ThreadType g_process_track_thread; - alignas(os::ThreadStackAlignment) constinit u8 g_process_track_thread_stack[16_KB]; - - /* Process lists. */ - constinit ProcessList g_process_list; - constinit ProcessList g_dead_process_list; - - /* Process Info Allocation. */ - /* Note: The kernel slabheap is size 0x50 -- we allow slightly larger to account for the dead process list. */ - constexpr size_t MaxProcessCount = 0x60; - constinit ProcessInfoAllocator g_process_info_allocator; + constinit ProcessTracker g_process_tracker; + alignas(os::ThreadStackAlignment) constinit u8 g_process_track_thread_stack[8_KB]; /* Global events. */ - constinit os::SystemEventType g_process_event; constinit os::SystemEventType g_hook_to_create_process_event; constinit os::SystemEventType g_hook_to_create_application_process_event; constinit os::SystemEventType g_boot_finished_event; - /* Process Launch synchronization globals. */ - constinit os::SdkMutex g_launch_program_lock; - os::Event g_process_launch_start_event(os::EventClearMode_AutoClear); - os::Event g_process_launch_finish_event(os::EventClearMode_AutoClear); - constinit Result g_process_launch_result = ResultSuccess(); - constinit LaunchProcessArgs g_process_launch_args = {}; - /* Hook globals. */ constinit std::atomic g_program_id_hook; constinit std::atomic g_application_hook; - /* Forward declarations. */ - Result LaunchProcess(os::MultiWaitType &multi_wait, const LaunchProcessArgs &args); - void OnProcessSignaled(ProcessListAccessor &list, ProcessInfo *process_info); - /* Helpers. */ - void ProcessTrackingMain(void *) { - /* This is the main loop of the process tracking thread. */ - - /* Setup multi wait/holders. */ - os::MultiWaitType process_multi_wait; - os::MultiWaitHolderType start_event_holder; - os::InitializeMultiWait(std::addressof(process_multi_wait)); - os::InitializeMultiWaitHolder(std::addressof(start_event_holder), g_process_launch_start_event.GetBase()); - os::LinkMultiWaitHolder(std::addressof(process_multi_wait), std::addressof(start_event_holder)); - - while (true) { - auto signaled_holder = os::WaitAny(std::addressof(process_multi_wait)); - if (signaled_holder == std::addressof(start_event_holder)) { - /* Launch start event signaled. */ - /* TryWait will clear signaled, preventing duplicate notifications. */ - if (g_process_launch_start_event.TryWait()) { - g_process_launch_result = LaunchProcess(process_multi_wait, g_process_launch_args); - g_process_launch_finish_event.Signal(); - } - } else { - /* Some process was signaled. */ - ProcessListAccessor list(g_process_list); - OnProcessSignaled(list, reinterpret_cast(os::GetMultiWaitHolderUserData(signaled_holder))); - } - } + void CreateDebuggerEvent() { + /* Create debugger hook events. */ + R_ABORT_UNLESS(os::CreateSystemEvent(std::addressof(g_hook_to_create_process_event), os::EventClearMode_AutoClear, true)); + R_ABORT_UNLESS(os::CreateSystemEvent(std::addressof(g_hook_to_create_application_process_event), os::EventClearMode_AutoClear, true)); } inline u32 GetLoaderCreateProcessFlags(u32 launch_flags) { @@ -195,7 +100,7 @@ namespace ams::pm::impl { } bool HasApplicationProcess() { - ProcessListAccessor list(g_process_list); + auto list = GetProcessList(); for (auto &process : *list) { if (process.IsApplication()) { @@ -212,19 +117,14 @@ namespace ams::pm::impl { R_SUCCEED(); } - void CleanupProcessInfo(ProcessListAccessor &list, ProcessInfo *process_info) { - /* Remove the process from the list. */ - list->Remove(process_info); + Result LaunchProgramImpl(ProcessInfo **out_process_info, os::ProcessId *out_process_id, const ncm::ProgramLocation &loc, u32 flags) { + /* Set the output to nullptr, if we fail. */ + *out_process_info = nullptr; - /* Delete the process. */ - g_process_info_allocator.FreeProcessInfo(process_info); - } - - Result LaunchProcess(os::MultiWaitType &multi_wait, const LaunchProcessArgs &args) { /* Get Program Info. */ ldr::ProgramInfo program_info; cfg::OverrideStatus override_status; - R_TRY(ldr::pm::AtmosphereGetProgramInfo(std::addressof(program_info), std::addressof(override_status), args.location)); + R_TRY(ldr::pm::AtmosphereGetProgramInfo(std::addressof(program_info), std::addressof(override_status), loc)); const bool is_application = (program_info.flags & ldr::ProgramInfoFlag_ApplicationTypeMask) == ldr::ProgramInfoFlag_Application; const bool allow_debug = (program_info.flags & ldr::ProgramInfoFlag_AllowDebug) || hos::GetVersion() < hos::Version_2_0_0; @@ -232,14 +132,14 @@ namespace ams::pm::impl { R_UNLESS(!is_application || !HasApplicationProcess(), pm::ResultApplicationRunning()); /* Fix the program location to use the right program id. */ - const ncm::ProgramLocation location = ncm::ProgramLocation::Make(program_info.program_id, static_cast(args.location.storage_id)); + const ncm::ProgramLocation fixed_location = ncm::ProgramLocation::Make(program_info.program_id, static_cast(loc.storage_id)); /* Pin and create the process. */ os::NativeHandle process_handle; ldr::PinId pin_id; { /* Pin the program with loader. */ - R_TRY(ldr::pm::AtmospherePinProgram(std::addressof(pin_id), location, override_status)); + R_TRY(ldr::pm::AtmospherePinProgram(std::addressof(pin_id), fixed_location, override_status)); /* If we fail after now, unpin. */ ON_RESULT_FAILURE { ldr::pm::UnpinProgram(pin_id); }; @@ -263,29 +163,28 @@ namespace ams::pm::impl { ON_RESULT_FAILURE_2 { if (mitm_boost_size > 0 || is_application) { R_ABORT_UNLESS(BoostSystemMemoryResourceLimitForMitm(0)); } }; /* Ensure resources are available. */ - resource::WaitResourceAvailable(std::addressof(program_info)); + WaitResourceAvailable(std::addressof(program_info)); /* Actually create the process. */ - R_TRY(ldr::pm::CreateProcess(std::addressof(process_handle), pin_id, GetLoaderCreateProcessFlags(args.flags), resource::GetResourceLimitHandle(std::addressof(program_info)))); + R_TRY(ldr::pm::CreateProcess(std::addressof(process_handle), pin_id, GetLoaderCreateProcessFlags(flags), GetResourceLimitHandle(std::addressof(program_info)))); } /* Get the process id. */ os::ProcessId process_id = os::GetProcessId(process_handle); /* Make new process info. */ - ProcessInfo *process_info = g_process_info_allocator.AllocateProcessInfo(process_handle, process_id, pin_id, location, override_status); + ProcessInfo *process_info = AllocateProcessInfo(process_handle, process_id, pin_id, fixed_location, override_status); AMS_ABORT_UNLESS(process_info != nullptr); - /* Link new process info. */ + /* Add the new process info to the process list. */ { - ProcessListAccessor list(g_process_list); + auto list = GetProcessList(); list->push_back(*process_info); - process_info->LinkToMultiWait(multi_wait); } /* Prevent resource leakage if register fails. */ ON_RESULT_FAILURE { - ProcessListAccessor list(g_process_list); + auto list = GetProcessList(); process_info->Cleanup(); CleanupProcessInfo(list, process_info); }; @@ -296,166 +195,73 @@ namespace ams::pm::impl { const u8 *aci_fah = acid_fac + program_info.acid_fac_size; /* Register with FS and SM. */ - R_TRY(fsprRegisterProgram(static_cast(process_id), static_cast(location.program_id), static_cast(location.storage_id), aci_fah, program_info.aci_fah_size, acid_fac, program_info.acid_fac_size)); - R_TRY(sm::manager::RegisterProcess(process_id, location.program_id, override_status, acid_sac, program_info.acid_sac_size, aci_sac, program_info.aci_sac_size)); + R_TRY(fsprRegisterProgram(static_cast(process_id), static_cast(fixed_location.program_id), static_cast(fixed_location.storage_id), aci_fah, program_info.aci_fah_size, acid_fac, program_info.acid_fac_size)); + R_TRY(sm::manager::RegisterProcess(process_id, fixed_location.program_id, override_status, acid_sac, program_info.acid_sac_size, aci_sac, program_info.aci_sac_size)); /* Set flags. */ if (is_application) { process_info->SetApplication(); } - if (ShouldSignalOnStart(args.flags) && allow_debug) { + if (ShouldSignalOnStart(flags) && allow_debug) { process_info->SetSignalOnStart(); } - if (ShouldSignalOnExit(args.flags)) { + if (ShouldSignalOnExit(flags)) { process_info->SetSignalOnExit(); } - if (ShouldSignalOnDebugEvent(args.flags) && allow_debug) { + if (ShouldSignalOnDebugEvent(flags) && allow_debug) { process_info->SetSignalOnDebugEvent(); } /* Process hooks/signaling. */ - if (location.program_id == g_program_id_hook) { + if (fixed_location.program_id == g_program_id_hook) { os::SignalSystemEvent(std::addressof(g_hook_to_create_process_event)); g_program_id_hook = ncm::InvalidProgramId; } else if (is_application && g_application_hook) { os::SignalSystemEvent(std::addressof(g_hook_to_create_application_process_event)); g_application_hook = false; - } else if (!ShouldStartSuspended(args.flags)) { + } else if (!ShouldStartSuspended(flags)) { R_TRY(StartProcess(process_info, std::addressof(program_info))); } - *args.out_process_id = process_id; + *out_process_id = process_id; + *out_process_info = process_info; R_SUCCEED(); } - void OnProcessSignaled(ProcessListAccessor &list, ProcessInfo *process_info) { - /* Reset the process's signal. */ - svc::ResetSignal(process_info->GetHandle()); - - /* Update the process's state. */ - const svc::ProcessState old_state = process_info->GetState(); - { - s64 tmp = 0; - R_ABORT_UNLESS(svc::GetProcessInfo(std::addressof(tmp), process_info->GetHandle(), svc::ProcessInfoType_ProcessState)); - process_info->SetState(static_cast(tmp)); - } - const svc::ProcessState new_state = process_info->GetState(); - - /* If we're transitioning away from crashed, clear waiting attached. */ - if (old_state == svc::ProcessState_Crashed && new_state != svc::ProcessState_Crashed) { - process_info->ClearExceptionWaitingAttach(); - } - - switch (new_state) { - case svc::ProcessState_Created: - case svc::ProcessState_CreatedAttached: - case svc::ProcessState_Terminating: - break; - case svc::ProcessState_Running: - if (process_info->ShouldSignalOnDebugEvent()) { - process_info->ClearSuspended(); - process_info->SetSuspendedStateChanged(); - os::SignalSystemEvent(std::addressof(g_process_event)); - } else if (hos::GetVersion() >= hos::Version_2_0_0 && process_info->ShouldSignalOnStart()) { - process_info->SetStartedStateChanged(); - process_info->ClearSignalOnStart(); - os::SignalSystemEvent(std::addressof(g_process_event)); - } - process_info->ClearUnhandledException(); - break; - case svc::ProcessState_Crashed: - if (!process_info->HasUnhandledException()) { - process_info->SetExceptionOccurred(); - os::SignalSystemEvent(std::addressof(g_process_event)); - } - process_info->SetExceptionWaitingAttach(); - break; - case svc::ProcessState_RunningAttached: - if (process_info->ShouldSignalOnDebugEvent()) { - process_info->ClearSuspended(); - process_info->SetSuspendedStateChanged(); - os::SignalSystemEvent(std::addressof(g_process_event)); - } - process_info->ClearUnhandledException(); - break; - case svc::ProcessState_Terminated: - /* Free process resources, unlink from multi wait. */ - process_info->Cleanup(); - - if (hos::GetVersion() < hos::Version_5_0_0 && process_info->ShouldSignalOnExit()) { - os::SignalSystemEvent(std::addressof(g_process_event)); - } else { - /* Handle the case where we need to keep the process alive some time longer. */ - if (hos::GetVersion() >= hos::Version_5_0_0 && process_info->ShouldSignalOnExit()) { - /* Remove from the living list. */ - list->Remove(process_info); - - /* Add the process to the list of dead processes. */ - { - ProcessListAccessor dead_list(g_dead_process_list); - dead_list->push_back(*process_info); - } - - /* Signal. */ - os::SignalSystemEvent(std::addressof(g_process_event)); - } else { - /* Actually delete process. */ - CleanupProcessInfo(list, process_info); - } - } - break; - case svc::ProcessState_DebugBreak: - if (process_info->ShouldSignalOnDebugEvent()) { - process_info->SetSuspended(); - process_info->SetSuspendedStateChanged(); - os::SignalSystemEvent(std::addressof(g_process_event)); - } - break; - } - } - } /* Initialization. */ Result InitializeProcessManager() { /* Create events. */ - R_ABORT_UNLESS(os::CreateSystemEvent(std::addressof(g_process_event), os::EventClearMode_AutoClear, true)); - R_ABORT_UNLESS(os::CreateSystemEvent(std::addressof(g_hook_to_create_process_event), os::EventClearMode_AutoClear, true)); - R_ABORT_UNLESS(os::CreateSystemEvent(std::addressof(g_hook_to_create_application_process_event), os::EventClearMode_AutoClear, true)); - R_ABORT_UNLESS(os::CreateSystemEvent(std::addressof(g_boot_finished_event), os::EventClearMode_AutoClear, true)); + CreateProcessEvent(); + CreateDebuggerEvent(); + R_ABORT_UNLESS(os::CreateSystemEvent(std::addressof(g_boot_finished_event), os::EventClearMode_AutoClear, true)); /* Initialize resource limits. */ - R_TRY(resource::InitializeResourceManager()); + R_TRY(InitializeSpec()); - /* Create thread. */ - R_ABORT_UNLESS(os::CreateThread(std::addressof(g_process_track_thread), ProcessTrackingMain, nullptr, g_process_track_thread_stack, sizeof(g_process_track_thread_stack), AMS_GET_SYSTEM_THREAD_PRIORITY(pm, ProcessTrack))); - os::SetThreadNamePointer(std::addressof(g_process_track_thread), AMS_GET_SYSTEM_THREAD_NAME(pm, ProcessTrack)); + /* Initialize the process tracker. */ + g_process_tracker.Initialize(g_process_track_thread_stack, sizeof(g_process_track_thread_stack)); - /* Start thread. */ - os::StartThread(std::addressof(g_process_track_thread)); + /* Start the process tracker thread. */ + g_process_tracker.StartThread(); R_SUCCEED(); } /* Process Management. */ Result LaunchProgram(os::ProcessId *out_process_id, const ncm::ProgramLocation &loc, u32 flags) { - /* Ensure we only try to launch one program at a time. */ - std::scoped_lock lk(g_launch_program_lock); + /* Launch the program. */ + ProcessInfo *process_info = nullptr; + R_TRY(LaunchProgramImpl(std::addressof(process_info), out_process_id, loc, flags)); - /* Set global arguments, signal, wait. */ - g_process_launch_args = { - .out_process_id = out_process_id, - .location = loc, - .flags = flags, - }; - g_process_launch_start_event.Signal(); - g_process_launch_finish_event.Wait(); - - R_RETURN(g_process_launch_result); + /* Register the process info with the tracker. */ + g_process_tracker.QueueEntry(process_info); + R_SUCCEED(); } Result StartProcess(os::ProcessId process_id) { - ProcessListAccessor list(g_process_list); + auto list = GetProcessList(); auto process_info = list->Find(process_id); R_UNLESS(process_info != nullptr, pm::ResultProcessNotFound()); @@ -467,7 +273,7 @@ namespace ams::pm::impl { } Result TerminateProcess(os::ProcessId process_id) { - ProcessListAccessor list(g_process_list); + auto list = GetProcessList(); auto process_info = list->Find(process_id); R_UNLESS(process_info != nullptr, pm::ResultProcessNotFound()); @@ -476,7 +282,7 @@ namespace ams::pm::impl { } Result TerminateProgram(ncm::ProgramId program_id) { - ProcessListAccessor list(g_process_list); + auto list = GetProcessList(); auto process_info = list->Find(program_id); R_UNLESS(process_info != nullptr, pm::ResultProcessNotFound()); @@ -484,15 +290,10 @@ namespace ams::pm::impl { R_RETURN(svc::TerminateProcess(process_info->GetHandle())); } - Result GetProcessEventHandle(os::NativeHandle *out) { - *out = os::GetReadableHandleOfSystemEvent(std::addressof(g_process_event)); - R_SUCCEED(); - } - Result GetProcessEventInfo(ProcessEventInfo *out) { /* Check for event from current process. */ { - ProcessListAccessor list(g_process_list); + auto list = GetProcessList(); for (auto &process : *list) { @@ -528,14 +329,14 @@ namespace ams::pm::impl { /* Check for event from exited process. */ if (hos::GetVersion() >= hos::Version_5_0_0) { - ProcessListAccessor dead_list(g_dead_process_list); + auto exit_list = GetExitList(); - if (!dead_list->empty()) { - auto &process_info = dead_list->front(); - out->event = GetProcessEventValue(ProcessEvent::Exited); + if (!exit_list->empty()) { + auto &process_info = exit_list->front(); + out->event = GetProcessEventValue(ProcessEvent::Exited); out->process_id = process_info.GetProcessId(); - CleanupProcessInfo(dead_list, std::addressof(process_info)); + CleanupProcessInfo(exit_list, std::addressof(process_info)); R_SUCCEED(); } } @@ -546,7 +347,7 @@ namespace ams::pm::impl { } Result CleanupProcess(os::ProcessId process_id) { - ProcessListAccessor list(g_process_list); + auto list = GetProcessList(); auto process_info = list->Find(process_id); R_UNLESS(process_info != nullptr, pm::ResultProcessNotFound()); @@ -557,7 +358,7 @@ namespace ams::pm::impl { } Result ClearExceptionOccurred(os::ProcessId process_id) { - ProcessListAccessor list(g_process_list); + auto list = GetProcessList(); auto process_info = list->Find(process_id); R_UNLESS(process_info != nullptr, pm::ResultProcessNotFound()); @@ -575,7 +376,7 @@ namespace ams::pm::impl { } Result GetExceptionProcessIdList(u32 *out_count, os::ProcessId *out_process_ids, size_t max_out_count) { - ProcessListAccessor list(g_process_list); + auto list = GetProcessList(); size_t count = 0; @@ -596,7 +397,7 @@ namespace ams::pm::impl { } Result GetProcessId(os::ProcessId *out, ncm::ProgramId program_id) { - ProcessListAccessor list(g_process_list); + auto list = GetProcessList(); auto process_info = list->Find(program_id); R_UNLESS(process_info != nullptr, pm::ResultProcessNotFound()); @@ -606,7 +407,7 @@ namespace ams::pm::impl { } Result GetProgramId(ncm::ProgramId *out, os::ProcessId process_id) { - ProcessListAccessor list(g_process_list); + auto list = GetProcessList(); auto process_info = list->Find(process_id); R_UNLESS(process_info != nullptr, pm::ResultProcessNotFound()); @@ -616,7 +417,7 @@ namespace ams::pm::impl { } Result GetApplicationProcessId(os::ProcessId *out_process_id) { - ProcessListAccessor list(g_process_list); + auto list = GetProcessList(); for (auto &process : *list) { if (process.IsApplication()) { @@ -629,7 +430,7 @@ namespace ams::pm::impl { } Result AtmosphereGetProcessInfo(os::NativeHandle *out_process_handle, ncm::ProgramLocation *out_loc, cfg::OverrideStatus *out_status, os::ProcessId process_id) { - ProcessListAccessor list(g_process_list); + auto list = GetProcessList(); auto process_info = list->Find(process_id); R_UNLESS(process_info != nullptr, pm::ResultProcessNotFound()); @@ -706,33 +507,4 @@ namespace ams::pm::impl { R_SUCCEED(); } - /* Resource Limit API. */ - Result BoostSystemMemoryResourceLimit(u64 boost_size) { - R_RETURN(resource::BoostSystemMemoryResourceLimit(boost_size)); - } - - Result BoostApplicationThreadResourceLimit() { - R_RETURN(resource::BoostApplicationThreadResourceLimit()); - } - - Result BoostSystemThreadResourceLimit() { - R_RETURN(resource::BoostSystemThreadResourceLimit()); - } - - Result GetAppletResourceLimitCurrentValue(pm::ResourceLimitValue *out) { - R_RETURN(resource::GetResourceLimitCurrentValue(ResourceLimitGroup_Applet, out)); - } - - Result GetAppletResourceLimitPeakValue(pm::ResourceLimitValue *out) { - R_RETURN(resource::GetResourceLimitPeakValue(ResourceLimitGroup_Applet, out)); - } - - Result AtmosphereGetCurrentLimitInfo(s64 *out_cur_val, s64 *out_lim_val, u32 group, u32 resource) { - R_RETURN(resource::GetResourceLimitValues(out_cur_val, out_lim_val, static_cast(group), static_cast(resource))); - } - - Result BoostSystemMemoryResourceLimitForMitm(u64 boost_size) { - R_RETURN(resource::BoostSystemMemoryResourceLimitForMitm(boost_size)); - } - } diff --git a/stratosphere/pm/source/impl/pm_process_manager.hpp b/stratosphere/pm/source/impl/pm_process_manager.hpp index b12e91651..61acbe1b0 100644 --- a/stratosphere/pm/source/impl/pm_process_manager.hpp +++ b/stratosphere/pm/source/impl/pm_process_manager.hpp @@ -48,13 +48,4 @@ namespace ams::pm::impl { Result NotifyBootFinished(); Result GetBootFinishedEventHandle(os::NativeHandle *out); - /* Resource Limit API. */ - Result BoostSystemMemoryResourceLimit(u64 boost_size); - Result BoostApplicationThreadResourceLimit(); - Result BoostSystemThreadResourceLimit(); - Result GetAppletResourceLimitCurrentValue(pm::ResourceLimitValue *out); - Result GetAppletResourceLimitPeakValue(pm::ResourceLimitValue *out); - Result AtmosphereGetCurrentLimitInfo(s64 *out_cur_val, s64 *out_lim_val, u32 group, u32 resource); - Result BoostSystemMemoryResourceLimitForMitm(u64 boost_size); - } diff --git a/stratosphere/pm/source/impl/pm_process_tracker.cpp b/stratosphere/pm/source/impl/pm_process_tracker.cpp new file mode 100644 index 000000000..5d1c3b418 --- /dev/null +++ b/stratosphere/pm/source/impl/pm_process_tracker.cpp @@ -0,0 +1,193 @@ +/* + * 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 "pm_process_tracker.hpp" +#include "pm_process_info.hpp" +#include "pm_spec.hpp" + +namespace ams::pm::impl { + + namespace { + + /* Global process event. */ + constinit os::SystemEventType g_process_event; + + } + + void ProcessTracker::Initialize(void *stack, size_t stack_size) { + /* Initialize our events. */ + os::InitializeEvent(std::addressof(m_request_event), false, os::EventClearMode_AutoClear); + os::InitializeEvent(std::addressof(m_reply_event), false, os::EventClearMode_AutoClear); + + /* Our process count should initially be zero. */ + m_process_count = 0; + + /* Create the process tracking thread. */ + R_ABORT_UNLESS(os::CreateThread(std::addressof(m_thread), ProcessTracker::ThreadFunction, this, stack, stack_size, AMS_GET_SYSTEM_THREAD_PRIORITY(pm, ProcessTrack))); + os::SetThreadNamePointer(std::addressof(m_thread), AMS_GET_SYSTEM_THREAD_NAME(pm, ProcessTrack)); + } + + void ProcessTracker::StartThread() { + /* Start thread. */ + os::StartThread(std::addressof(m_thread)); + } + + void ProcessTracker::ThreadBody() { + /* This is the main loop of the process tracking thread. */ + + /* Setup multi wait/holders. */ + os::MultiWaitType process_multi_wait; + os::MultiWaitHolderType enqueue_event_holder; + os::InitializeMultiWait(std::addressof(process_multi_wait)); + os::InitializeMultiWaitHolder(std::addressof(enqueue_event_holder), std::addressof(m_request_event)); + os::LinkMultiWaitHolder(std::addressof(process_multi_wait), std::addressof(enqueue_event_holder)); + + while (true) { + auto signaled_holder = os::WaitAny(std::addressof(process_multi_wait)); + if (signaled_holder == std::addressof(enqueue_event_holder)) { + /* TryWait will clear signaled, preventing duplicate notifications. */ + if (os::TryWaitEvent(std::addressof(m_request_event))) { + /* Link the process to our multi-wait. */ + os::LinkMultiWaitHolder(std::addressof(process_multi_wait), m_queued_process_info->GetMultiWaitHolder()); + m_queued_process_info = nullptr; + + /* Increment our process count. */ + ++m_process_count; + + /* Reply. */ + os::SignalEvent(std::addressof(m_reply_event)); + } + } else { + /* Some process was signaled. */ + this->OnProcessSignaled(reinterpret_cast(os::GetMultiWaitHolderUserData(signaled_holder))); + } + } + } + + void ProcessTracker::QueueEntry(ProcessInfo *process_info) { + /* Lock ourselves. */ + std::scoped_lock lk(m_mutex); + + /* Request to enqueue the process info. */ + m_queued_process_info = process_info; + os::SignalEvent(std::addressof(m_request_event)); + + /* Wait for acknowledgement. */ + os::WaitEvent(std::addressof(m_reply_event)); + } + + void ProcessTracker::OnProcessSignaled(ProcessInfo *process_info) { + /* Get the process list. */ + auto list = GetProcessList(); + + /* Reset the process's signal. */ + svc::ResetSignal(process_info->GetHandle()); + + /* Update the process's state. */ + const svc::ProcessState old_state = process_info->GetState(); + { + s64 tmp = 0; + R_ABORT_UNLESS(svc::GetProcessInfo(std::addressof(tmp), process_info->GetHandle(), svc::ProcessInfoType_ProcessState)); + process_info->SetState(static_cast(tmp)); + } + const svc::ProcessState new_state = process_info->GetState(); + + /* If we're transitioning away from crashed, clear waiting attached. */ + if (old_state == svc::ProcessState_Crashed && new_state != svc::ProcessState_Crashed) { + process_info->ClearExceptionWaitingAttach(); + } + + switch (new_state) { + case svc::ProcessState_Created: + case svc::ProcessState_CreatedAttached: + case svc::ProcessState_Terminating: + break; + case svc::ProcessState_Running: + if (process_info->ShouldSignalOnDebugEvent()) { + process_info->ClearSuspended(); + process_info->SetSuspendedStateChanged(); + os::SignalSystemEvent(std::addressof(g_process_event)); + } else if (hos::GetVersion() >= hos::Version_2_0_0 && process_info->ShouldSignalOnStart()) { + process_info->SetStartedStateChanged(); + process_info->ClearSignalOnStart(); + os::SignalSystemEvent(std::addressof(g_process_event)); + } + process_info->ClearUnhandledException(); + break; + case svc::ProcessState_Crashed: + if (!process_info->HasUnhandledException()) { + process_info->SetExceptionOccurred(); + os::SignalSystemEvent(std::addressof(g_process_event)); + } + process_info->SetExceptionWaitingAttach(); + break; + case svc::ProcessState_RunningAttached: + if (process_info->ShouldSignalOnDebugEvent()) { + process_info->ClearSuspended(); + process_info->SetSuspendedStateChanged(); + os::SignalSystemEvent(std::addressof(g_process_event)); + } + process_info->ClearUnhandledException(); + break; + case svc::ProcessState_Terminated: + /* Unlink from multi wait. */ + os::UnlinkMultiWaitHolder(process_info->GetMultiWaitHolder()); + + /* Free process resources. */ + process_info->Cleanup(); + + if (hos::GetVersion() < hos::Version_5_0_0 && process_info->ShouldSignalOnExit()) { + os::SignalSystemEvent(std::addressof(g_process_event)); + } else { + /* Handle the case where we need to keep the process alive some time longer. */ + if (hos::GetVersion() >= hos::Version_5_0_0 && process_info->ShouldSignalOnExit()) { + /* Remove from the living list. */ + list->Remove(process_info); + + /* Add the process to the list of dead processes. */ + { + GetExitList()->push_back(*process_info); + } + + /* Signal. */ + os::SignalSystemEvent(std::addressof(g_process_event)); + } else { + /* Actually delete process. */ + CleanupProcessInfo(list, process_info); + } + } + break; + case svc::ProcessState_DebugBreak: + if (process_info->ShouldSignalOnDebugEvent()) { + process_info->SetSuspended(); + process_info->SetSuspendedStateChanged(); + os::SignalSystemEvent(std::addressof(g_process_event)); + } + break; + } + } + + void CreateProcessEvent() { + /* Create process event. */ + R_ABORT_UNLESS(os::CreateSystemEvent(std::addressof(g_process_event), os::EventClearMode_AutoClear, true)); + } + + Result GetProcessEventHandle(os::NativeHandle *out) { + *out = os::GetReadableHandleOfSystemEvent(std::addressof(g_process_event)); + R_SUCCEED(); + } + +} diff --git a/stratosphere/pm/source/impl/pm_process_tracker.hpp b/stratosphere/pm/source/impl/pm_process_tracker.hpp new file mode 100644 index 000000000..c1de7c2aa --- /dev/null +++ b/stratosphere/pm/source/impl/pm_process_tracker.hpp @@ -0,0 +1,57 @@ +/* + * 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 . + */ +#pragma once +#include +#include "pm_process_info.hpp" + +namespace ams::pm::impl { + + class ProcessTracker { + NON_COPYABLE(ProcessTracker); + NON_MOVEABLE(ProcessTracker); + private: + os::ThreadType m_thread; + os::EventType m_request_event; + os::EventType m_reply_event; + os::SdkMutex m_mutex; + ProcessInfo *m_queued_process_info; + util::Atomic m_process_count; + public: + constexpr ProcessTracker() : m_thread(), m_request_event(), m_reply_event(), m_mutex(), m_queued_process_info(nullptr), m_process_count(0) { + /* ... */ + } + + void Initialize(void *stack, size_t stack_size); + void StartThread(); + + void QueueEntry(ProcessInfo *process_info); + + u32 GetProcessCount() const { + return m_process_count; + } + private: + void OnProcessSignaled(ProcessInfo *process_info); + private: + static void ThreadFunction(void *_this) { + static_cast(_this)->ThreadBody(); + } + + void ThreadBody(); + }; + + void CreateProcessEvent(); + +} diff --git a/stratosphere/pm/source/impl/pm_resource_manager.cpp b/stratosphere/pm/source/impl/pm_spec.cpp similarity index 93% rename from stratosphere/pm/source/impl/pm_resource_manager.cpp rename to stratosphere/pm/source/impl/pm_spec.cpp index f11a72dca..a395b0255 100644 --- a/stratosphere/pm/source/impl/pm_resource_manager.cpp +++ b/stratosphere/pm/source/impl/pm_spec.cpp @@ -14,9 +14,9 @@ * along with this program. If not, see . */ #include -#include "pm_resource_manager.hpp" +#include "pm_spec.hpp" -namespace ams::pm::resource { +namespace ams::pm::impl { namespace { @@ -209,8 +209,8 @@ namespace ams::pm::resource { R_SUCCEED(); } - template - ALWAYS_INLINE Result GetResourceLimitValuesImpl(ResourceLimitGroup group, pm::ResourceLimitValue *out) { + template + ALWAYS_INLINE Result GetResourceLimitValueImpl(pm::ResourceLimitValue *out, ResourceLimitGroup group) { /* Sanity check group. */ AMS_ABORT_UNLESS(group < ResourceLimitGroup_Count); @@ -219,11 +219,11 @@ namespace ams::pm::resource { /* Get values. */ int64_t values[svc::LimitableResource_Count]; - R_ABORT_UNLESS(GetResourceLimitValueImpl(std::addressof(values[svc::LimitableResource_PhysicalMemoryMax]), handle, svc::LimitableResource_PhysicalMemoryMax)); - R_ABORT_UNLESS(GetResourceLimitValueImpl(std::addressof(values[svc::LimitableResource_ThreadCountMax]), handle, svc::LimitableResource_ThreadCountMax)); - R_ABORT_UNLESS(GetResourceLimitValueImpl(std::addressof(values[svc::LimitableResource_EventCountMax]), handle, svc::LimitableResource_EventCountMax)); - R_ABORT_UNLESS(GetResourceLimitValueImpl(std::addressof(values[svc::LimitableResource_TransferMemoryCountMax]), handle, svc::LimitableResource_TransferMemoryCountMax)); - R_ABORT_UNLESS(GetResourceLimitValueImpl(std::addressof(values[svc::LimitableResource_SessionCountMax]), handle, svc::LimitableResource_SessionCountMax)); + R_ABORT_UNLESS(ImplFunction(std::addressof(values[svc::LimitableResource_PhysicalMemoryMax]), handle, svc::LimitableResource_PhysicalMemoryMax)); + R_ABORT_UNLESS(ImplFunction(std::addressof(values[svc::LimitableResource_ThreadCountMax]), handle, svc::LimitableResource_ThreadCountMax)); + R_ABORT_UNLESS(ImplFunction(std::addressof(values[svc::LimitableResource_EventCountMax]), handle, svc::LimitableResource_EventCountMax)); + R_ABORT_UNLESS(ImplFunction(std::addressof(values[svc::LimitableResource_TransferMemoryCountMax]), handle, svc::LimitableResource_TransferMemoryCountMax)); + R_ABORT_UNLESS(ImplFunction(std::addressof(values[svc::LimitableResource_SessionCountMax]), handle, svc::LimitableResource_SessionCountMax)); /* Set to output. */ out->physical_memory = values[svc::LimitableResource_PhysicalMemoryMax]; @@ -278,8 +278,7 @@ namespace ams::pm::resource { } - /* Resource API. */ - Result InitializeResourceManager() { + Result InitializeSpec() { /* Create resource limit handles. */ for (size_t i = 0; i < ResourceLimitGroup_Count; i++) { if (i == ResourceLimitGroup_System) { @@ -459,16 +458,16 @@ namespace ams::pm::resource { } } - Result GetResourceLimitCurrentValue(ResourceLimitGroup group, pm::ResourceLimitValue *out) { - R_RETURN(GetResourceLimitValuesImpl<::ams::svc::GetResourceLimitCurrentValue>(group, out)); + Result GetResourceLimitCurrentValue(pm::ResourceLimitValue *out, ResourceLimitGroup group) { + R_RETURN(GetResourceLimitValueImpl<::ams::svc::GetResourceLimitCurrentValue>(out, group)); } - Result GetResourceLimitPeakValue(ResourceLimitGroup group, pm::ResourceLimitValue *out) { - R_RETURN(GetResourceLimitValuesImpl<::ams::svc::GetResourceLimitPeakValue>(group, out)); + Result GetResourceLimitPeakValue(pm::ResourceLimitValue *out, ResourceLimitGroup group) { + R_RETURN(GetResourceLimitValueImpl<::ams::svc::GetResourceLimitPeakValue>(out, group)); } - Result GetResourceLimitLimitValue(ResourceLimitGroup group, pm::ResourceLimitValue *out) { - R_RETURN(GetResourceLimitValuesImpl<::ams::svc::GetResourceLimitLimitValue>(group, out)); + Result GetResourceLimitLimitValue(pm::ResourceLimitValue *out, ResourceLimitGroup group) { + R_RETURN(GetResourceLimitValueImpl<::ams::svc::GetResourceLimitLimitValue>(out, group)); } Result GetResourceLimitValues(s64 *out_cur, s64 *out_lim, ResourceLimitGroup group, svc::LimitableResource resource) { diff --git a/stratosphere/pm/source/impl/pm_resource_manager.hpp b/stratosphere/pm/source/impl/pm_spec.hpp similarity index 76% rename from stratosphere/pm/source/impl/pm_resource_manager.hpp rename to stratosphere/pm/source/impl/pm_spec.hpp index b6f5605af..1f49282f4 100644 --- a/stratosphere/pm/source/impl/pm_resource_manager.hpp +++ b/stratosphere/pm/source/impl/pm_spec.hpp @@ -16,10 +16,10 @@ #pragma once #include -namespace ams::pm::resource { +namespace ams::pm::impl { + + Result InitializeSpec(); - /* Resource API. */ - Result InitializeResourceManager(); Result BoostSystemMemoryResourceLimit(u64 boost_size); Result BoostApplicationThreadResourceLimit(); Result BoostSystemThreadResourceLimit(); @@ -31,9 +31,9 @@ namespace ams::pm::resource { void WaitResourceAvailable(const ldr::ProgramInfo *info); - Result GetResourceLimitCurrentValue(ResourceLimitGroup group, pm::ResourceLimitValue *out); - Result GetResourceLimitPeakValue(ResourceLimitGroup group, pm::ResourceLimitValue *out); - Result GetResourceLimitLimitValue(ResourceLimitGroup group, pm::ResourceLimitValue *out); + Result GetResourceLimitCurrentValue(pm::ResourceLimitValue *out, ResourceLimitGroup group); + Result GetResourceLimitPeakValue(pm::ResourceLimitValue *outm, ResourceLimitGroup group); + Result GetResourceLimitLimitValue(pm::ResourceLimitValue *out, ResourceLimitGroup group); Result GetResourceLimitValues(s64 *out_cur, s64 *out_lim, ResourceLimitGroup group, svc::LimitableResource resource); diff --git a/stratosphere/pm/source/pm_boot_mode_service.cpp b/stratosphere/pm/source/pm_boot_mode_service.cpp index 719fff51f..ff389fe75 100644 --- a/stratosphere/pm/source/pm_boot_mode_service.cpp +++ b/stratosphere/pm/source/pm_boot_mode_service.cpp @@ -21,7 +21,7 @@ namespace ams::pm { namespace { /* Global bootmode. */ - BootMode g_boot_mode = BootMode::Normal; + constinit BootMode g_boot_mode = BootMode::Normal; } diff --git a/stratosphere/pm/source/pm_debug_monitor_service.cpp b/stratosphere/pm/source/pm_debug_monitor_service.cpp index dd5433c78..d9c3b1621 100644 --- a/stratosphere/pm/source/pm_debug_monitor_service.cpp +++ b/stratosphere/pm/source/pm_debug_monitor_service.cpp @@ -16,6 +16,7 @@ #include #include "pm_debug_monitor_service.hpp" #include "impl/pm_process_manager.hpp" +#include "impl/pm_spec.hpp" namespace ams::pm { @@ -76,7 +77,7 @@ namespace ams::pm { } Result DebugMonitorService::AtmosphereGetCurrentLimitInfo(sf::Out out_cur_val, sf::Out out_lim_val, u32 group, u32 resource) { - R_RETURN(impl::AtmosphereGetCurrentLimitInfo(out_cur_val.GetPointer(), out_lim_val.GetPointer(), group, resource)); + R_RETURN(impl::GetResourceLimitValues(out_cur_val.GetPointer(), out_lim_val.GetPointer(), static_cast(group), static_cast(resource))); } } diff --git a/stratosphere/pm/source/pm_info_service.cpp b/stratosphere/pm/source/pm_info_service.cpp index 55b308fce..29ae868cb 100644 --- a/stratosphere/pm/source/pm_info_service.cpp +++ b/stratosphere/pm/source/pm_info_service.cpp @@ -16,6 +16,7 @@ #include #include "pm_info_service.hpp" #include "impl/pm_process_manager.hpp" +#include "impl/pm_spec.hpp" namespace ams::pm { @@ -34,11 +35,11 @@ namespace ams::pm { } Result InformationService::GetAppletResourceLimitCurrentValue(sf::Out out) { - R_RETURN(impl::GetAppletResourceLimitCurrentValue(out.GetPointer())); + R_RETURN(impl::GetResourceLimitCurrentValue(out.GetPointer(), ResourceLimitGroup_Applet)); } Result InformationService::GetAppletResourceLimitPeakValue(sf::Out out) { - R_RETURN(impl::GetAppletResourceLimitPeakValue(out.GetPointer())); + R_RETURN(impl::GetResourceLimitPeakValue(out.GetPointer(), ResourceLimitGroup_Applet)); } /* Atmosphere extension commands. */ diff --git a/stratosphere/pm/source/pm_shell_service.cpp b/stratosphere/pm/source/pm_shell_service.cpp index 7248bc0e2..db69c6f12 100644 --- a/stratosphere/pm/source/pm_shell_service.cpp +++ b/stratosphere/pm/source/pm_shell_service.cpp @@ -16,6 +16,7 @@ #include #include "pm_shell_service.hpp" #include "impl/pm_process_manager.hpp" +#include "impl/pm_spec.hpp" namespace ams::pm {