From 33a570b1c335cc38e50b7fef6bf4ed840bbd4ab2 Mon Sep 17 00:00:00 2001 From: fincs Date: Fri, 3 Jul 2020 18:07:20 +0200 Subject: [PATCH] Refactor default heap allocation code, see details: - Use reslimit svcs to retrieve free mem (suggested by @TuxSH) - this removes the hardcoded assumption that the process is in APPLICATION. - The algorithm for calculating default app/linear heap sizes has been tweaked to ensure 32MB of linear heap are available for normal apps running on Old3DS consoles under appmemtype 0 (i.e. the default). - Misc cleanup and error checking. --- libctru/source/system/allocateHeaps.c | 47 ++++++++++++++++++++++----- 1 file changed, 39 insertions(+), 8 deletions(-) diff --git a/libctru/source/system/allocateHeaps.c b/libctru/source/system/allocateHeaps.c index 0c8478d..dbf6ce3 100644 --- a/libctru/source/system/allocateHeaps.c +++ b/libctru/source/system/allocateHeaps.c @@ -2,8 +2,10 @@ #include <3ds/allocator/mappable.h> #include <3ds/env.h> #include <3ds/os.h> +#include <3ds/result.h> -#define DEFAULT_LINEAR_HEAP_SIZE (32 << 20) // 32MB +#define HEAP_SPLIT_SIZE_CAP (24 << 20) // 24MB +#define LINEAR_HEAP_SIZE_CAP (32 << 20) // 32MB extern char* fake_heap_start; extern char* fake_heap_end; @@ -15,17 +17,43 @@ __attribute__((weak)) u32 __ctru_heap_size = 0; __attribute__((weak)) u32 __ctru_linear_heap_size = 0; void __attribute__((weak)) __system_allocateHeaps(void) { - u32 tmp = 0; - u32 remaining = osGetMemRegionFree(MEMREGION_APPLICATION) &~ 0xFFF; + Result rc; + + // Retrieve handle to the resource limit object for our process + Handle reslimit = 0; + rc = svcGetResourceLimit(&reslimit, CUR_PROCESS_HANDLE); + if (R_FAILED(rc)) + svcBreak(USERBREAK_PANIC); + + // Retrieve information about total/used memory + s64 maxCommit = 0, currentCommit = 0; + ResourceLimitType reslimitType = RESLIMIT_COMMIT; + svcGetResourceLimitLimitValues(&maxCommit, reslimit, &reslimitType, 1); // for APPLICATION this is equal to APPMEMALLOC at all times + svcGetResourceLimitCurrentValues(¤tCommit, reslimit, &reslimitType, 1); + svcCloseHandle(reslimit); + + // Calculate how much remaining free memory is available + u32 remaining = (u32)(maxCommit - currentCommit) &~ 0xFFF; if (__ctru_heap_size + __ctru_linear_heap_size > remaining) svcBreak(USERBREAK_PANIC); if (__ctru_heap_size == 0 && __ctru_linear_heap_size == 0) { - // By default, automatically allocate all remaining free memory, aligning to page size. + // Split available memory equally between linear and application heaps (with rounding in favor of the latter) __ctru_linear_heap_size = (remaining / 2) & ~0xFFF; - __ctru_linear_heap_size = __ctru_linear_heap_size <= DEFAULT_LINEAR_HEAP_SIZE ? __ctru_linear_heap_size : DEFAULT_LINEAR_HEAP_SIZE; __ctru_heap_size = remaining - __ctru_linear_heap_size; + + // If the application heap size is bigger than the cap, prefer to grow linear heap instead + if (__ctru_heap_size > HEAP_SPLIT_SIZE_CAP) { + __ctru_heap_size = HEAP_SPLIT_SIZE_CAP; + __ctru_linear_heap_size = remaining - __ctru_heap_size; + + // However if the linear heap size is bigger than the cap, prefer to grow application heap + if (__ctru_linear_heap_size > LINEAR_HEAP_SIZE_CAP) { + __ctru_linear_heap_size = LINEAR_HEAP_SIZE_CAP; + __ctru_heap_size = remaining - __ctru_linear_heap_size; + } + } } else if (__ctru_heap_size == 0) { __ctru_heap_size = remaining - __ctru_linear_heap_size; } else if (__ctru_linear_heap_size == 0) { @@ -33,11 +61,14 @@ void __attribute__((weak)) __system_allocateHeaps(void) { } // Allocate the application heap - __ctru_heap = OS_HEAP_AREA_BEGIN; - svcControlMemory(&tmp, __ctru_heap, 0x0, __ctru_heap_size, MEMOP_ALLOC, MEMPERM_READ | MEMPERM_WRITE); + rc = svcControlMemory(&__ctru_heap, OS_HEAP_AREA_BEGIN, 0x0, __ctru_heap_size, MEMOP_ALLOC, MEMPERM_READ | MEMPERM_WRITE); + if (R_FAILED(rc)) + svcBreak(USERBREAK_PANIC); // Allocate the linear heap - svcControlMemory(&__ctru_linear_heap, 0x0, 0x0, __ctru_linear_heap_size, MEMOP_ALLOC_LINEAR, MEMPERM_READ | MEMPERM_WRITE); + rc = svcControlMemory(&__ctru_linear_heap, 0x0, 0x0, __ctru_linear_heap_size, MEMOP_ALLOC_LINEAR, MEMPERM_READ | MEMPERM_WRITE); + if (R_FAILED(rc)) + svcBreak(USERBREAK_PANIC); // Mappable allocator init mappableInit(OS_MAP_AREA_BEGIN, OS_MAP_AREA_END);