mirror of
https://github.com/Atmosphere-NX/Atmosphere.git
synced 2024-12-18 08:22:04 +00:00
romfs: zelda is a blight upon this earth
This commit is contained in:
parent
a9fc5fdab0
commit
576f1c43a4
4 changed files with 147 additions and 67 deletions
|
@ -24,7 +24,7 @@ namespace ams {
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
/* TODO: we really shouldn't be using malloc just to avoid dealing with real allocator separation. */
|
/* TODO: we really shouldn't be using malloc just to avoid dealing with real allocator separation. */
|
||||||
constexpr size_t MallocBufferSize = 16_MB;
|
constexpr size_t MallocBufferSize = 32_MB;
|
||||||
alignas(os::MemoryPageSize) constinit u8 g_malloc_buffer[MallocBufferSize];
|
alignas(os::MemoryPageSize) constinit u8 g_malloc_buffer[MallocBufferSize];
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,80 +28,161 @@ namespace ams::mitm::fs {
|
||||||
|
|
||||||
struct ApplicationWithDynamicHeapInfo {
|
struct ApplicationWithDynamicHeapInfo {
|
||||||
ncm::ProgramId program_id;
|
ncm::ProgramId program_id;
|
||||||
size_t dynamic_heap_size;
|
size_t dynamic_app_heap_size;
|
||||||
|
size_t dynamic_system_heap_size;
|
||||||
};
|
};
|
||||||
|
|
||||||
constexpr const ApplicationWithDynamicHeapInfo ApplicationsWithDynamicHeap[] = {
|
constexpr const ApplicationWithDynamicHeapInfo ApplicationsWithDynamicHeap[] = {
|
||||||
{ 0x01006F8002326000, 32_MB }, /* Animal Crossing: New Horizons. */
|
/* Animal Crossing: New Horizons. */
|
||||||
{ 0x0100A6301214E000, 40_MB }, /* Fire Emblem: Engage. */
|
/* Requirement ~24 MB. */
|
||||||
|
/* No particular heap sensitivity. */
|
||||||
|
{ 0x01006F8002326000, 16_MB, 0_MB },
|
||||||
|
|
||||||
|
/* Fire Emblem: Engage. */
|
||||||
|
/* Requirement ~32+ MB. */
|
||||||
|
/* No particular heap sensitivity. */
|
||||||
|
{ 0x0100A6301214E000, 16_MB, 0_MB },
|
||||||
|
|
||||||
|
/* The Legend of Zelda: Tears of the Kingdom. */
|
||||||
|
/* Requirement ~48 MB. */
|
||||||
|
/* Game is highly sensitive to memory stolen from application heap. */
|
||||||
|
/* 1.0.0 tolerates no more than 16 MB stolen. 1.1.0 no more than 12 MB. */
|
||||||
|
{ 0x0100F2C0115B6000, 10_MB, 8_MB },
|
||||||
};
|
};
|
||||||
|
|
||||||
constexpr size_t GetDynamicHeapSize(ncm::ProgramId program_id) {
|
constexpr size_t GetDynamicAppHeapSize(ncm::ProgramId program_id) {
|
||||||
for (const auto &info : ApplicationsWithDynamicHeap) {
|
for (const auto &info : ApplicationsWithDynamicHeap) {
|
||||||
if (info.program_id == program_id) {
|
if (info.program_id == program_id) {
|
||||||
return info.dynamic_heap_size;
|
return info.dynamic_app_heap_size;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
constexpr size_t GetDynamicSysHeapSize(ncm::ProgramId program_id) {
|
||||||
|
for (const auto &info : ApplicationsWithDynamicHeap) {
|
||||||
|
if (info.program_id == program_id) {
|
||||||
|
return info.dynamic_system_heap_size;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<auto MapImpl, auto UnmapImpl>
|
||||||
|
struct DynamicHeap {
|
||||||
|
uintptr_t heap_address{};
|
||||||
|
size_t heap_size{};
|
||||||
|
size_t outstanding_allocations{};
|
||||||
|
util::TypedStorage<mem::StandardAllocator> heap{};
|
||||||
|
os::SdkMutex release_heap_lock{};
|
||||||
|
|
||||||
|
constexpr DynamicHeap() = default;
|
||||||
|
|
||||||
|
void Map() {
|
||||||
|
if (this->heap_address == 0) {
|
||||||
|
/* NOTE: Lock not necessary, because this is the only location which do 0 -> non-zero. */
|
||||||
|
|
||||||
|
R_ABORT_UNLESS(MapImpl(std::addressof(this->heap_address), this->heap_size));
|
||||||
|
AMS_ABORT_UNLESS(this->heap_address != 0);
|
||||||
|
|
||||||
|
/* Create heap. */
|
||||||
|
util::ConstructAt(this->heap, reinterpret_cast<void *>(this->heap_address), this->heap_size);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void TryRelease() {
|
||||||
|
if (this->outstanding_allocations == 0) {
|
||||||
|
std::scoped_lock lk(this->release_heap_lock);
|
||||||
|
|
||||||
|
if (this->heap_address != 0) {
|
||||||
|
util::DestroyAt(this->heap);
|
||||||
|
this->heap = {};
|
||||||
|
|
||||||
|
R_ABORT_UNLESS(UnmapImpl(this->heap_address, this->heap_size));
|
||||||
|
|
||||||
|
this->heap_address = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void *Allocate(size_t size) {
|
||||||
|
void * const ret = util::GetReference(this->heap).Allocate(size);
|
||||||
|
if (AMS_LIKELY(ret != nullptr)) {
|
||||||
|
++this->outstanding_allocations;
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool TryFree(void *p) {
|
||||||
|
if (this->IsAllocated(p)) {
|
||||||
|
--this->outstanding_allocations;
|
||||||
|
|
||||||
|
util::GetReference(this->heap).Free(p);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IsAllocated(void *p) const {
|
||||||
|
const uintptr_t address = reinterpret_cast<uintptr_t>(p);
|
||||||
|
|
||||||
|
return this->heap_address != 0 && (this->heap_address <= address && address < this->heap_address + this->heap_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Reset() {
|
||||||
|
/* This should require no remaining allocations. */
|
||||||
|
AMS_ABORT_UNLESS(this->outstanding_allocations == 0);
|
||||||
|
|
||||||
|
/* Free the heap. */
|
||||||
|
this->TryRelease();
|
||||||
|
AMS_ABORT_UNLESS(this->heap_address == 0);
|
||||||
|
|
||||||
|
/* Clear the heap size. */
|
||||||
|
this->heap_size = 0;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Result MapByHeap(uintptr_t *out, size_t size) {
|
||||||
|
R_TRY(os::SetMemoryHeapSize(size));
|
||||||
|
R_RETURN(os::AllocateMemoryBlock(out, size));
|
||||||
|
}
|
||||||
|
|
||||||
|
Result UnmapByHeap(uintptr_t address, size_t size) {
|
||||||
|
os::FreeMemoryBlock(address, size);
|
||||||
|
R_RETURN(os::SetMemoryHeapSize(0));
|
||||||
|
}
|
||||||
|
|
||||||
/* Dynamic allocation globals. */
|
/* Dynamic allocation globals. */
|
||||||
constinit os::SdkMutex g_romfs_build_lock;
|
constinit os::SdkMutex g_romfs_build_lock;
|
||||||
constinit ncm::ProgramId g_dynamic_heap_program_id{};
|
constinit ncm::ProgramId g_dynamic_heap_program_id{};
|
||||||
constinit size_t g_dynamic_heap_size = 0;
|
|
||||||
|
|
||||||
constinit os::SdkMutex g_release_dynamic_heap_lock;
|
|
||||||
constinit bool g_building_from_dynamic_heap = false;
|
constinit bool g_building_from_dynamic_heap = false;
|
||||||
constinit uintptr_t g_dynamic_heap_address = 0;
|
|
||||||
constinit size_t g_dynamic_heap_outstanding_allocations = 0;
|
|
||||||
|
|
||||||
constinit util::TypedStorage<mem::StandardAllocator> g_dynamic_heap{};
|
constinit DynamicHeap<os::AllocateUnsafeMemory, os::FreeUnsafeMemory> g_dynamic_app_heap;
|
||||||
|
constinit DynamicHeap<MapByHeap, UnmapByHeap> g_dynamic_sys_heap;
|
||||||
bool IsAllocatedFromDynamicHeap(void *p) {
|
|
||||||
const uintptr_t address = reinterpret_cast<uintptr_t>(p);
|
|
||||||
|
|
||||||
return g_dynamic_heap_address != 0 && (g_dynamic_heap_address <= address && address < g_dynamic_heap_address + g_dynamic_heap_size);
|
|
||||||
}
|
|
||||||
|
|
||||||
void InitializeDynamicHeapForBuildRomfs(ncm::ProgramId program_id) {
|
void InitializeDynamicHeapForBuildRomfs(ncm::ProgramId program_id) {
|
||||||
if (program_id == g_dynamic_heap_program_id && g_dynamic_heap_size > 0) {
|
if (program_id == g_dynamic_heap_program_id && g_dynamic_app_heap.heap_size > 0) {
|
||||||
/* This romfs will build out of dynamic heap. */
|
/* This romfs will build out of dynamic heap. */
|
||||||
g_building_from_dynamic_heap = true;
|
g_building_from_dynamic_heap = true;
|
||||||
|
|
||||||
if (g_dynamic_heap_address == 0) {
|
g_dynamic_app_heap.Map();
|
||||||
/* NOTE: Lock not necessary, because this is the only location which do 0 -> non-zero. */
|
|
||||||
|
|
||||||
/* Map application memory as heap. */
|
if (g_dynamic_sys_heap.heap_size > 0) {
|
||||||
R_ABORT_UNLESS(os::AllocateUnsafeMemory(std::addressof(g_dynamic_heap_address), g_dynamic_heap_size));
|
g_dynamic_sys_heap.Map();
|
||||||
AMS_ABORT_UNLESS(g_dynamic_heap_address != 0);
|
|
||||||
|
|
||||||
/* Create exp heap. */
|
|
||||||
util::ConstructAt(g_dynamic_heap, reinterpret_cast<void *>(g_dynamic_heap_address), g_dynamic_heap_size);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ReleaseDynamicHeap() {
|
|
||||||
std::scoped_lock lk(g_release_dynamic_heap_lock);
|
|
||||||
|
|
||||||
if (g_dynamic_heap_address != 0) {
|
|
||||||
util::DestroyAt(g_dynamic_heap);
|
|
||||||
g_dynamic_heap = {};
|
|
||||||
|
|
||||||
R_ABORT_UNLESS(os::FreeUnsafeMemory(g_dynamic_heap_address, g_dynamic_heap_size));
|
|
||||||
|
|
||||||
g_dynamic_heap_address = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void FinalizeDynamicHeapForBuildRomfs() {
|
void FinalizeDynamicHeapForBuildRomfs() {
|
||||||
/* We are definitely no longer building out of dynamic heap. */
|
/* We are definitely no longer building out of dynamic heap. */
|
||||||
g_building_from_dynamic_heap = false;
|
g_building_from_dynamic_heap = false;
|
||||||
|
|
||||||
if (g_dynamic_heap_outstanding_allocations == 0) {
|
g_dynamic_app_heap.TryRelease();
|
||||||
ReleaseDynamicHeap();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -110,10 +191,15 @@ namespace ams::mitm::fs {
|
||||||
AMS_UNUSED(type);
|
AMS_UNUSED(type);
|
||||||
|
|
||||||
if (g_building_from_dynamic_heap) {
|
if (g_building_from_dynamic_heap) {
|
||||||
void * const ret = util::GetReference(g_dynamic_heap).Allocate(size);
|
void *ret = g_dynamic_app_heap.Allocate(size);
|
||||||
AMS_ABORT_UNLESS(ret != nullptr);
|
|
||||||
|
|
||||||
++g_dynamic_heap_outstanding_allocations;
|
if (ret == nullptr && g_dynamic_sys_heap.heap_address != 0) {
|
||||||
|
ret = g_dynamic_sys_heap.Allocate(size);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ret == nullptr) {
|
||||||
|
ret = std::malloc(size);
|
||||||
|
}
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
} else {
|
} else {
|
||||||
|
@ -125,12 +211,13 @@ namespace ams::mitm::fs {
|
||||||
AMS_UNUSED(type);
|
AMS_UNUSED(type);
|
||||||
AMS_UNUSED(size);
|
AMS_UNUSED(size);
|
||||||
|
|
||||||
if (IsAllocatedFromDynamicHeap(p)) {
|
if (g_dynamic_app_heap.TryFree(p)) {
|
||||||
--g_dynamic_heap_outstanding_allocations;
|
if (!g_building_from_dynamic_heap) {
|
||||||
util::GetReference(g_dynamic_heap).Free(p);
|
g_dynamic_app_heap.TryRelease();
|
||||||
|
}
|
||||||
if (!g_building_from_dynamic_heap && g_dynamic_heap_outstanding_allocations == 0) {
|
} else if (g_dynamic_sys_heap.TryFree(p)) {
|
||||||
ReleaseDynamicHeap();
|
if (!g_building_from_dynamic_heap) {
|
||||||
|
g_dynamic_sys_heap.TryRelease();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
std::free(p);
|
std::free(p);
|
||||||
|
@ -916,20 +1003,12 @@ namespace ams::mitm::fs {
|
||||||
R_SUCCEED_IF(!is_application);
|
R_SUCCEED_IF(!is_application);
|
||||||
|
|
||||||
/* First, we need to ensure that, if the game used dynamic heap, we clear it. */
|
/* First, we need to ensure that, if the game used dynamic heap, we clear it. */
|
||||||
if (g_dynamic_heap_size > 0) {
|
if (g_dynamic_app_heap.heap_size > 0) {
|
||||||
mitm::fs::FinalizeLayeredRomfsStorage(g_dynamic_heap_program_id);
|
mitm::fs::FinalizeLayeredRomfsStorage(g_dynamic_heap_program_id);
|
||||||
|
|
||||||
/* This should have freed any remaining allocations. */
|
|
||||||
AMS_ABORT_UNLESS(g_dynamic_heap_outstanding_allocations == 0);
|
|
||||||
|
|
||||||
/* Free the heap. */
|
/* Free the heap. */
|
||||||
if (g_dynamic_heap_address != 0) {
|
g_dynamic_app_heap.Reset();
|
||||||
ReleaseDynamicHeap();
|
g_dynamic_sys_heap.Reset();
|
||||||
}
|
|
||||||
|
|
||||||
/* Clear the heap globals. */
|
|
||||||
g_dynamic_heap_address = 0;
|
|
||||||
g_dynamic_heap_size = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Next, if we aren't going to end up building a romfs, we can ignore dynamic heap. */
|
/* Next, if we aren't going to end up building a romfs, we can ignore dynamic heap. */
|
||||||
|
@ -939,11 +1018,12 @@ namespace ams::mitm::fs {
|
||||||
R_SUCCEED_IF(!mitm::fs::HasSdRomfsContent(program_id));
|
R_SUCCEED_IF(!mitm::fs::HasSdRomfsContent(program_id));
|
||||||
|
|
||||||
/* Next, set the new program id for dynamic heap. */
|
/* Next, set the new program id for dynamic heap. */
|
||||||
g_dynamic_heap_program_id = program_id;
|
g_dynamic_heap_program_id = program_id;
|
||||||
g_dynamic_heap_size = GetDynamicHeapSize(g_dynamic_heap_program_id);
|
g_dynamic_app_heap.heap_size = GetDynamicAppHeapSize(g_dynamic_heap_program_id);
|
||||||
|
g_dynamic_sys_heap.heap_size = GetDynamicSysHeapSize(g_dynamic_heap_program_id);
|
||||||
|
|
||||||
/* Set output. */
|
/* Set output. */
|
||||||
*out_size = g_dynamic_heap_size;
|
*out_size = g_dynamic_app_heap.heap_size;
|
||||||
|
|
||||||
R_SUCCEED();
|
R_SUCCEED();
|
||||||
}
|
}
|
||||||
|
|
|
@ -259,8 +259,8 @@ namespace ams::pm::impl {
|
||||||
|
|
||||||
if (mitm_boost_size > 0 || is_application) {
|
if (mitm_boost_size > 0 || is_application) {
|
||||||
R_ABORT_UNLESS(BoostSystemMemoryResourceLimitForMitm(mitm_boost_size));
|
R_ABORT_UNLESS(BoostSystemMemoryResourceLimitForMitm(mitm_boost_size));
|
||||||
ON_RESULT_FAILURE_2 { R_ABORT_UNLESS(BoostSystemMemoryResourceLimitForMitm(0)); };
|
|
||||||
}
|
}
|
||||||
|
ON_RESULT_FAILURE_2 { if (mitm_boost_size > 0 || is_application) { R_ABORT_UNLESS(BoostSystemMemoryResourceLimitForMitm(0)); } };
|
||||||
|
|
||||||
/* Ensure resources are available. */
|
/* Ensure resources are available. */
|
||||||
resource::WaitResourceAvailable(std::addressof(program_info));
|
resource::WaitResourceAvailable(std::addressof(program_info));
|
||||||
|
|
|
@ -33,7 +33,7 @@ namespace ams::pm::resource {
|
||||||
constexpr size_t ReservedMemorySize600 = 5_MB;
|
constexpr size_t ReservedMemorySize600 = 5_MB;
|
||||||
|
|
||||||
/* Atmosphere always allocates extra memory for system usage. */
|
/* Atmosphere always allocates extra memory for system usage. */
|
||||||
constexpr size_t ExtraSystemMemorySizeAtmosphere = 24_MB;
|
constexpr size_t ExtraSystemMemorySizeAtmosphere = 32_MB;
|
||||||
|
|
||||||
/* Desired extra threads. */
|
/* Desired extra threads. */
|
||||||
constexpr u64 BaseApplicationThreads = 96;
|
constexpr u64 BaseApplicationThreads = 96;
|
||||||
|
|
Loading…
Reference in a new issue