romfs/ams.mitm/pm: refactor to dynamically steal heap for certain games. (#2122)

* fs.mitm: skeleton the use of special allocation in romfs build

* pm: add api for ams.mitm to steal application memory

* pm/mitm: okay, that api won't work, try a different one

* romfs: revert memory usage increases; we'll handle torture games case-by-case.

* pm/romfs: first (broken?) pass at dynamic heap.

I cannot wait to figure out all the ways this is wrong.

* Release the dynamic heap a little more eagerly

* romfs: animal crossing is also not a nice game

* romfs: fix issues in close-during-build

* romfs: zelda is a blight upon this earth
This commit is contained in:
SciresM 2023-05-14 03:06:52 -07:00 committed by GitHub
parent 85c23b5781
commit f2ee44da74
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
31 changed files with 871 additions and 111 deletions

View file

@ -244,6 +244,24 @@ namespace ams::pm::impl {
/* If we fail after now, unpin. */
ON_RESULT_FAILURE { ldr::pm::UnpinProgram(pin_id); };
/* Ensure we can talk to mitm services. */
{
AMS_FUNCTION_LOCAL_STATIC_CONSTINIT(bool, s_initialized_mitm, false);
if (!s_initialized_mitm) {
mitm::pm::Initialize();
s_initialized_mitm = true;
}
}
/* Determine boost size for mitm. */
u64 mitm_boost_size = 0;
R_TRY(mitm::pm::PrepareLaunchProgram(std::addressof(mitm_boost_size), program_info.program_id, override_status, is_application));
if (mitm_boost_size > 0 || is_application) {
R_ABORT_UNLESS(BoostSystemMemoryResourceLimitForMitm(mitm_boost_size));
}
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));
@ -713,4 +731,8 @@ namespace ams::pm::impl {
R_RETURN(resource::GetResourceLimitValues(out_cur_val, out_lim_val, static_cast<ResourceLimitGroup>(group), static_cast<svc::LimitableResource>(resource)));
}
Result BoostSystemMemoryResourceLimitForMitm(u64 boost_size) {
R_RETURN(resource::BoostSystemMemoryResourceLimitForMitm(boost_size));
}
}

View file

@ -55,5 +55,6 @@ namespace ams::pm::impl {
Result GetAppletCurrentResourceLimitValues(pm::ResourceLimitValues *out);
Result GetAppletPeakResourceLimitValues(pm::ResourceLimitValues *out);
Result AtmosphereGetCurrentLimitInfo(s64 *out_cur_val, s64 *out_lim_val, u32 group, u32 resource);
Result BoostSystemMemoryResourceLimitForMitm(u64 boost_size);
}

View file

@ -52,9 +52,16 @@ namespace ams::pm::resource {
constinit os::SdkMutex g_resource_limit_lock;
constinit os::NativeHandle g_resource_limit_handles[ResourceLimitGroup_Count];
constinit spl::MemoryArrangement g_memory_arrangement = spl::MemoryArrangement_Standard;
constinit u64 g_system_memory_boost_size = 0;
constinit u64 g_extra_threads_available[ResourceLimitGroup_Count];
constinit os::SdkMutex g_system_memory_boost_lock;
constinit u64 g_system_memory_boost_size = 0;
constinit u64 g_system_memory_boost_size_for_mitm = 0;
ALWAYS_INLINE u64 GetCurrentSystemMemoryBoostSize() {
return g_system_memory_boost_size + g_system_memory_boost_size_for_mitm;
}
constinit u64 g_resource_limits[ResourceLimitGroup_Count][svc::LimitableResource_Count] = {
[ResourceLimitGroup_System] = {
[svc::LimitableResource_PhysicalMemoryMax] = 0, /* Initialized dynamically later. */
@ -220,6 +227,47 @@ namespace ams::pm::resource {
R_SUCCEED();
}
Result BoostSystemMemoryResourceLimitLocked(u64 normal_boost, u64 mitm_boost) {
/* Check pre-conditions. */
AMS_ASSERT(g_system_memory_boost_lock.IsLockedByCurrentThread());
/* Determine total boost. */
const u64 boost_size = normal_boost + mitm_boost;
/* Don't allow all application memory to be taken away. */
R_UNLESS(boost_size <= g_memory_resource_limits[g_memory_arrangement][ResourceLimitGroup_Application], pm::ResultInvalidSize());
const u64 new_app_size = g_memory_resource_limits[g_memory_arrangement][ResourceLimitGroup_Application] - boost_size;
{
std::scoped_lock lk(g_resource_limit_lock);
if (hos::GetVersion() >= hos::Version_5_0_0) {
/* Starting in 5.0.0, PM does not allow for only one of the sets to fail. */
if (boost_size < GetCurrentSystemMemoryBoostSize()) {
R_TRY(svc::SetUnsafeLimit(boost_size));
R_ABORT_UNLESS(SetMemoryResourceLimitLimitValue(ResourceLimitGroup_Application, new_app_size));
} else {
R_TRY(SetMemoryResourceLimitLimitValue(ResourceLimitGroup_Application, new_app_size));
R_ABORT_UNLESS(svc::SetUnsafeLimit(boost_size));
}
} else {
const u64 new_sys_size = g_memory_resource_limits[g_memory_arrangement][ResourceLimitGroup_System] + boost_size;
if (boost_size < GetCurrentSystemMemoryBoostSize()) {
R_TRY(SetMemoryResourceLimitLimitValue(ResourceLimitGroup_System, new_sys_size));
R_TRY(SetMemoryResourceLimitLimitValue(ResourceLimitGroup_Application, new_app_size));
} else {
R_TRY(SetMemoryResourceLimitLimitValue(ResourceLimitGroup_Application, new_app_size));
R_TRY(SetMemoryResourceLimitLimitValue(ResourceLimitGroup_System, new_sys_size));
}
}
g_system_memory_boost_size = normal_boost;
g_system_memory_boost_size_for_mitm = mitm_boost;
}
R_SUCCEED();
}
}
/* Resource API. */
@ -352,37 +400,19 @@ namespace ams::pm::resource {
}
Result BoostSystemMemoryResourceLimit(u64 boost_size) {
/* Don't allow all application memory to be taken away. */
R_UNLESS(boost_size <= g_memory_resource_limits[g_memory_arrangement][ResourceLimitGroup_Application], pm::ResultInvalidSize());
/* Ensure only one boost change happens at a time. */
std::scoped_lock lk(g_system_memory_boost_lock);
const u64 new_app_size = g_memory_resource_limits[g_memory_arrangement][ResourceLimitGroup_Application] - boost_size;
{
std::scoped_lock lk(g_resource_limit_lock);
/* Boost to the appropriate total amount. */
R_RETURN(BoostSystemMemoryResourceLimitLocked(boost_size, g_system_memory_boost_size_for_mitm));
}
if (hos::GetVersion() >= hos::Version_5_0_0) {
/* Starting in 5.0.0, PM does not allow for only one of the sets to fail. */
if (boost_size < g_system_memory_boost_size) {
R_TRY(svc::SetUnsafeLimit(boost_size));
R_ABORT_UNLESS(SetMemoryResourceLimitLimitValue(ResourceLimitGroup_Application, new_app_size));
} else {
R_TRY(SetMemoryResourceLimitLimitValue(ResourceLimitGroup_Application, new_app_size));
R_ABORT_UNLESS(svc::SetUnsafeLimit(boost_size));
}
} else {
const u64 new_sys_size = g_memory_resource_limits[g_memory_arrangement][ResourceLimitGroup_System] + boost_size;
if (boost_size < g_system_memory_boost_size) {
R_TRY(SetMemoryResourceLimitLimitValue(ResourceLimitGroup_System, new_sys_size));
R_TRY(SetMemoryResourceLimitLimitValue(ResourceLimitGroup_Application, new_app_size));
} else {
R_TRY(SetMemoryResourceLimitLimitValue(ResourceLimitGroup_Application, new_app_size));
R_TRY(SetMemoryResourceLimitLimitValue(ResourceLimitGroup_System, new_sys_size));
}
}
Result BoostSystemMemoryResourceLimitForMitm(u64 boost_size) {
/* Ensure only one boost change happens at a time. */
std::scoped_lock lk(g_system_memory_boost_lock);
g_system_memory_boost_size = boost_size;
}
R_SUCCEED();
/* Boost to the appropriate total amount. */
R_RETURN(BoostSystemMemoryResourceLimitLocked(g_system_memory_boost_size, boost_size));
}
Result BoostApplicationThreadResourceLimit() {

View file

@ -24,6 +24,8 @@ namespace ams::pm::resource {
Result BoostApplicationThreadResourceLimit();
Result BoostSystemThreadResourceLimit();
Result BoostSystemMemoryResourceLimitForMitm(u64 boost_size);
os::NativeHandle GetResourceLimitHandle(ResourceLimitGroup group);
os::NativeHandle GetResourceLimitHandle(const ldr::ProgramInfo *info);