From 6dc8ab6f176de2e1dee29e50bc4b50f69ab1597a Mon Sep 17 00:00:00 2001 From: Michael Scire Date: Mon, 7 May 2018 03:50:33 -0600 Subject: [PATCH] ProcessManager: Refactor resource limits, complete pm:shell. --- stratosphere/pm/source/pm_registration.cpp | 96 +-------- stratosphere/pm/source/pm_registration.hpp | 1 - stratosphere/pm/source/pm_resource_limits.cpp | 192 ++++++++++++++++++ stratosphere/pm/source/pm_resource_limits.hpp | 16 ++ stratosphere/pm/source/pm_shell.cpp | 5 +- stratosphere/pm/source/pm_shell.hpp | 2 +- 6 files changed, 219 insertions(+), 93 deletions(-) create mode 100644 stratosphere/pm/source/pm_resource_limits.cpp create mode 100644 stratosphere/pm/source/pm_resource_limits.hpp diff --git a/stratosphere/pm/source/pm_registration.cpp b/stratosphere/pm/source/pm_registration.cpp index 15c0b4ebc..c499e8696 100644 --- a/stratosphere/pm/source/pm_registration.cpp +++ b/stratosphere/pm/source/pm_registration.cpp @@ -3,6 +3,7 @@ #include #include "pm_registration.hpp" +#include "pm_resource_limits.hpp" #include "pm_process_wait.hpp" static ProcessList g_process_list; @@ -21,24 +22,6 @@ static SystemEvent *g_process_event = NULL; static SystemEvent *g_debug_title_event = NULL; static SystemEvent *g_debug_application_event = NULL; -static const u64 g_memory_resource_limits[5][3] = { - {0x010D00000ULL, 0x0CD500000ULL, 0x021700000ULL}, - {0x01E100000ULL, 0x080000000ULL, 0x061800000ULL}, - {0x014800000ULL, 0x0CD500000ULL, 0x01DC00000ULL}, - {0x028D00000ULL, 0x133400000ULL, 0x023800000ULL}, - {0x028D00000ULL, 0x0CD500000ULL, 0x089700000ULL} -}; - -/* These are the limits for LimitableResources. */ -/* Memory, Threads, Events, TransferMemories, Sessions. */ -static u64 g_resource_limits[3][5] = { - {0x0, 0x1FC, 0x258, 0x80, 0x31A}, - {0x0, 0x60, 0x0, 0x20, 0x1}, - {0x0, 0x60, 0x0, 0x20, 0x5}, -}; - -static Handle g_resource_limit_handles[3] = {0}; - Registration::AutoProcessListLock::AutoProcessListLock() { g_process_list.Lock(); this->has_lock = true; @@ -63,53 +46,7 @@ void Registration::InitializeSystemResources() { g_debug_application_event = new SystemEvent(&IEvent::PanicCallback); g_process_launch_start_event = new SystemEvent(&Registration::ProcessLaunchStartCallback); - /* Get memory limits. */ - u64 memory_arrangement; - if (R_FAILED(splGetConfig(SplConfigItem_MemoryArrange, &memory_arrangement))) { - /* TODO: panic. */ - } - memory_arrangement &= 0x3F; - int memory_limit_type; - switch (memory_arrangement) { - case 2: - memory_limit_type = 1; - break; - case 3: - memory_limit_type = 2; - break; - case 17: - memory_limit_type = 3; - break; - case 18: - memory_limit_type = 4; - break; - default: - memory_limit_type = 0; - break; - } - for (unsigned int i = 0; i < 3; i++) { - g_resource_limits[i][0] = g_memory_resource_limits[memory_limit_type][i]; - } - - /* Create resource limits. */ - for (unsigned int i = 0; i < 3; i++) { - if (i > 0) { - if (R_FAILED(svcCreateResourceLimit(&g_resource_limit_handles[i]))) { - /* TODO: Panic. */ - } - } else { - u64 out = 0; - if (R_FAILED(svcGetInfo(&out, 9, 0, 0))) { - /* TODO: Panic. */ - } - g_resource_limit_handles[i] = (Handle)out; - } - for (unsigned int r = 0; r < 5; r++) { - if (R_FAILED(svcSetResourceLimitLimitValue(g_resource_limit_handles[i], (LimitableResource)r, g_resource_limits[i][r]))) { - /* TODO: Panic. */ - } - } - } + ResourceLimitUtils::InitializeLimits(); } Result Registration::ProcessLaunchStartCallback(Handle *handles, size_t num_handles, u64 timeout) { @@ -131,7 +68,6 @@ void Registration::HandleProcessLaunch() { Result rc; u64 launch_flags = g_process_launch_state.launch_flags; u64 *out_pid = g_process_launch_state.out_pid; - u32 reslimit_idx; Process new_process = {0}; new_process.tid_sid = g_process_launch_state.tid_sid; u8 *ac_buf = new u8[4 * sizeof(LoaderProgramInfo)]; @@ -144,14 +80,9 @@ void Registration::HandleProcessLaunch() { } /* Get the resource limit handle, ensure that we can launch the program. */ - if ((program_info.application_type & 3) == 1) { - if (HasApplicationProcess(NULL)) { - rc = 0xA0F; - goto HANDLE_PROCESS_LAUNCH_END; - } - reslimit_idx = 1; - } else { - reslimit_idx = 2 * ((program_info.application_type & 3) == 2); + if ((program_info.application_type & 3) == 1 && HasApplicationProcess(NULL)) { + rc = 0xA0F; + goto HANDLE_PROCESS_LAUNCH_END; } /* Try to register the title for launch in loader... */ @@ -161,11 +92,11 @@ void Registration::HandleProcessLaunch() { /* Make sure the previous application is cleaned up. */ if ((program_info.application_type & 3) == 1) { - EnsureApplicationResourcesAvailable(); + ResourceLimitUtils::EnsureApplicationResourcesAvailable(); } /* Try to create the process... */ - if (R_FAILED((rc = ldrPmCreateProcess(LAUNCHFLAGS_ARGLOW(launch_flags) | LAUNCHFLAGS_ARGHIGH(launch_flags), new_process.ldr_queue_index, g_resource_limit_handles[reslimit_idx], &new_process.handle)))) { + if (R_FAILED((rc = ldrPmCreateProcess(LAUNCHFLAGS_ARGLOW(launch_flags) | LAUNCHFLAGS_ARGHIGH(launch_flags), new_process.ldr_queue_index, ResourceLimitUtils::GetResourceLimitHandle(program_info.application_type), &new_process.handle)))) { goto PROCESS_CREATION_FAILED; } @@ -508,17 +439,4 @@ Handle Registration::GetDebugTitleEventHandle() { Handle Registration::GetDebugApplicationEventHandle() { return g_debug_application_event->get_handle(); -} - -void Registration::EnsureApplicationResourcesAvailable() { - Handle application_reslimit_h = g_resource_limit_handles[1]; - for (unsigned int i = 0; i < 5; i++) { - u64 result; - do { - if (R_FAILED(svcGetResourceLimitCurrentValue(&result, application_reslimit_h, (LimitableResource)i))) { - return; - } - svcSleepThread(1000000ULL); - } while (result); - } } \ No newline at end of file diff --git a/stratosphere/pm/source/pm_registration.hpp b/stratosphere/pm/source/pm_registration.hpp index e7e6697dd..d2df05308 100644 --- a/stratosphere/pm/source/pm_registration.hpp +++ b/stratosphere/pm/source/pm_registration.hpp @@ -65,6 +65,5 @@ class Registration { static Result LaunchProcessByTidSid(TidSid tid_sid, u64 launch_flags, u64 *out_pid); static bool HasApplicationProcess(Process **out); - static void EnsureApplicationResourcesAvailable(); }; diff --git a/stratosphere/pm/source/pm_resource_limits.cpp b/stratosphere/pm/source/pm_resource_limits.cpp new file mode 100644 index 000000000..d59a4919b --- /dev/null +++ b/stratosphere/pm/source/pm_resource_limits.cpp @@ -0,0 +1,192 @@ +#include +#include + +#include "pm_resource_limits.hpp" + +/* Memory that system, application, applet are allowed to allocate. */ +static const u64 g_memory_resource_limits_deprecated[5][3] = { + {0x010D00000ULL, 0x0CD500000ULL, 0x021700000ULL}, + {0x01E100000ULL, 0x080000000ULL, 0x061800000ULL}, + {0x014800000ULL, 0x0CD500000ULL, 0x01DC00000ULL}, + {0x028D00000ULL, 0x133400000ULL, 0x023800000ULL}, + {0x028D00000ULL, 0x0CD500000ULL, 0x089700000ULL} +}; + +/* These limits were altered in 4.x, which introduced ResourceLimitUtils::BoostSystemMemoryResourceLimit(). */ +static const u64 g_memory_resource_limits_4x[5][3] = { + {0x011700000ULL, 0x0CD500000ULL, 0x020D00000ULL}, /* 10 MB was taken from applet and given to system. */ + {0x01E100000ULL, 0x080000000ULL, 0x061800000ULL}, /* No changes. */ + {0x015200000ULL, 0x0CD500000ULL, 0x01D200000ULL}, /* 10 MB was taken from applet and given to system. */ + {0x028D00000ULL, 0x133400000ULL, 0x023800000ULL}, /* No changes. */ + {0x028D00000ULL, 0x0CD500000ULL, 0x089700000ULL} /* No changes. */ +}; + +/* These are the limits for LimitableResources. */ +/* Memory, Threads, Events, TransferMemories, Sessions. */ +static u64 g_resource_limits_deprecated[3][5] = { + {0x0, 0x1FC, 0x258, 0x80, 0x31A}, + {0x0, 0x60, 0x0, 0x20, 0x1}, + {0x0, 0x60, 0x0, 0x20, 0x5}, +}; + +/* 4.x boosted the number of threads that system modules are allowed to make. */ +static u64 g_resource_limits_4x[3][5] = { + {0x0, 0x260, 0x258, 0x80, 0x31A}, + {0x0, 0x60, 0x0, 0x20, 0x1}, + {0x0, 0x60, 0x0, 0x20, 0x5}, +}; + +static Handle g_resource_limit_handles[3] = {0}; + + +static u64 g_memory_resource_limits[5][3] = {0}; +static u64 g_resource_limits[3][5] = {0}; +static int g_memory_limit_type; +static u64 g_system_boost_size = 0; + +/* Tries to set Resource limits for a category. */ +static Result SetResourceLimits(ResourceLimitUtils::ResourceLimitCategory category, u64 new_memory_size) { + Result rc = 0; + u64 old_memory_size = g_resource_limits[category][LimitableResource_Memory]; + g_resource_limits[category][LimitableResource_Memory] = new_memory_size; + for (unsigned int r = 0; r < 5; r++) { + if (R_FAILED((rc = svcSetResourceLimitLimitValue(g_resource_limit_handles[category], (LimitableResource)r, g_resource_limits[category][r])))) { + g_resource_limits[category][LimitableResource_Memory] = old_memory_size; + return rc; + } + } + return rc; +} + + +static Result SetNewMemoryResourceLimit(ResourceLimitUtils::ResourceLimitCategory category, u64 new_memory_size) { + Result rc = 0; + u64 old_memory_size = g_resource_limits[category][LimitableResource_Memory]; + g_resource_limits[category][LimitableResource_Memory] = new_memory_size; + if (R_FAILED((rc = svcSetResourceLimitLimitValue(g_resource_limit_handles[category], LimitableResource_Memory, g_resource_limits[category][LimitableResource_Memory])))) { + g_resource_limits[category][LimitableResource_Memory] = old_memory_size; + } + return rc; +} + +void ResourceLimitUtils::InitializeLimits() { + /* Set global aliases. */ + if (kernelAbove400()) { + memcpy(&g_memory_resource_limits, &g_memory_resource_limits_4x, sizeof(g_memory_resource_limits)); + memcpy(&g_resource_limits, &g_resource_limits_4x, sizeof(g_resource_limits)); + } else { + memcpy(&g_memory_resource_limits, &g_memory_resource_limits_deprecated, sizeof(g_memory_resource_limits)); + memcpy(&g_resource_limits, &g_resource_limits_deprecated, sizeof(g_resource_limits)); + } + /* Get memory limits. */ + u64 memory_arrangement; + if (R_FAILED(splGetConfig(SplConfigItem_MemoryArrange, &memory_arrangement))) { + /* TODO: panic. */ + } + memory_arrangement &= 0x3F; + switch (memory_arrangement) { + case 2: + g_memory_limit_type = 1; + break; + case 3: + g_memory_limit_type = 2; + break; + case 17: + g_memory_limit_type = 3; + break; + case 18: + g_memory_limit_type = 4; + break; + default: + g_memory_limit_type = 0; + break; + } + + /* Create resource limits. */ + for (unsigned int i = 0; i < 3; i++) { + if (i > 0) { + if (R_FAILED(svcCreateResourceLimit(&g_resource_limit_handles[i]))) { + /* TODO: Panic. */ + } + } else { + u64 out = 0; + if (R_FAILED(svcGetInfo(&out, 9, 0, 0))) { + /* TODO: Panic. */ + } + g_resource_limit_handles[i] = (Handle)out; + } + + if (R_FAILED(SetResourceLimits((ResourceLimitCategory)i, g_memory_resource_limits[g_memory_limit_type][i]))) { + /* TODO: Panic. */ + } + } +} + +void ResourceLimitUtils::EnsureApplicationResourcesAvailable() { + Handle application_reslimit_h = g_resource_limit_handles[1]; + for (unsigned int i = 0; i < 5; i++) { + u64 result; + do { + if (R_FAILED(svcGetResourceLimitCurrentValue(&result, application_reslimit_h, (LimitableResource)i))) { + return; + } + svcSleepThread(1000000ULL); + } while (result); + } +} + +Handle ResourceLimitUtils::GetResourceLimitHandle(u16 application_type) { + if ((application_type & 3) == 1) { + return g_resource_limit_handles[1]; + } else { + return g_resource_limit_handles[2 * ((application_type & 3) == 2)]; + } +} + +Result ResourceLimitUtils::BoostSystemMemoryResourceLimit(u64 boost_size) { + Result rc = 0; + if (boost_size > g_memory_resource_limits[g_memory_limit_type][ResourceLimitCategory_Application]) { + return 0xC0F; + } + u64 app_size = g_memory_resource_limits[g_memory_limit_type][ResourceLimitCategory_Application] - boost_size; + if (kernelAbove500()) { + if (boost_size < g_system_boost_size) { + if (R_FAILED((rc = svcSetUnsafeLimit(boost_size)))) { + return rc; + } + if (R_FAILED((rc = SetNewMemoryResourceLimit(ResourceLimitCategory_Application, app_size)))) { + return rc; + } + } else { + if (R_FAILED((rc = SetNewMemoryResourceLimit(ResourceLimitCategory_Application, app_size)))) { + return rc; + } + if (R_FAILED((rc = svcSetUnsafeLimit(boost_size)))) { + return rc; + } + } + } else if (kernelAbove400()) { + u64 sys_size = g_memory_resource_limits[g_memory_limit_type][ResourceLimitCategory_System] + boost_size; + if (boost_size < g_system_boost_size) { + if (R_FAILED((rc = SetResourceLimits(ResourceLimitCategory_System, sys_size)))) { + return rc; + } + if (R_FAILED((rc = SetResourceLimits(ResourceLimitCategory_Application, app_size)))) { + return rc; + } + } else { + if (R_FAILED((rc = SetResourceLimits(ResourceLimitCategory_Application, app_size)))) { + return rc; + } + if (R_FAILED((rc = SetResourceLimits(ResourceLimitCategory_System, sys_size)))) { + return rc; + } + } + } else { + rc = 0xF601; + } + if (R_SUCCEEDED(rc)) { + g_system_boost_size = boost_size; + } + return rc; +} \ No newline at end of file diff --git a/stratosphere/pm/source/pm_resource_limits.hpp b/stratosphere/pm/source/pm_resource_limits.hpp new file mode 100644 index 000000000..bf31b561b --- /dev/null +++ b/stratosphere/pm/source/pm_resource_limits.hpp @@ -0,0 +1,16 @@ +#pragma once +#include +#include + +class ResourceLimitUtils { + public: + enum ResourceLimitCategory { + ResourceLimitCategory_System = 0, + ResourceLimitCategory_Application = 1, + ResourceLimitCategory_Applet = 2 + }; + static void InitializeLimits(); + static void EnsureApplicationResourcesAvailable(); + static Handle GetResourceLimitHandle(u16 application_type); + static Result BoostSystemMemoryResourceLimit(u64 boost_size); +}; \ No newline at end of file diff --git a/stratosphere/pm/source/pm_shell.cpp b/stratosphere/pm/source/pm_shell.cpp index 4a749c2cf..349438b66 100644 --- a/stratosphere/pm/source/pm_shell.cpp +++ b/stratosphere/pm/source/pm_shell.cpp @@ -1,5 +1,6 @@ #include #include "pm_registration.hpp" +#include "pm_resource_limits.hpp" #include "pm_shell.hpp" #include "pm_debug.hpp" @@ -170,11 +171,11 @@ std::tuple ShellService::get_application_process_id() { return {0x20F, 0}; } -std::tuple ShellService::boost_system_memory_resource_limit() { +std::tuple ShellService::boost_system_memory_resource_limit(u64 sysmem_size) { if (!kernelAbove400()) { return {0xF601}; } /* TODO */ - return {0xF601}; + return {ResourceLimitUtils::BoostSystemMemoryResourceLimit(sysmem_size)}; } diff --git a/stratosphere/pm/source/pm_shell.hpp b/stratosphere/pm/source/pm_shell.hpp index e4a85898b..b9ec9a199 100644 --- a/stratosphere/pm/source/pm_shell.hpp +++ b/stratosphere/pm/source/pm_shell.hpp @@ -46,5 +46,5 @@ class ShellService : IServiceObject { std::tuple clear_process_notification_flag(u64 pid); std::tuple notify_boot_finished(); std::tuple get_application_process_id(); - std::tuple boost_system_memory_resource_limit(); + std::tuple boost_system_memory_resource_limit(u64 sysmem_size); }; \ No newline at end of file