From b96dd51d3349961189d4ab1bc2a5c45deff21c09 Mon Sep 17 00:00:00 2001 From: Steven Smith Date: Sat, 21 Nov 2015 10:37:22 -0800 Subject: [PATCH] Dynamically determine heap sizes. --- libctru/include/3ds/os.h | 42 ++++++++++++++++++++++++++- libctru/source/os.c | 6 ++++ libctru/source/system/allocateHeaps.c | 14 +++++++-- 3 files changed, 58 insertions(+), 4 deletions(-) diff --git a/libctru/include/3ds/os.h b/libctru/include/3ds/os.h index 34b4754..e9b26c5 100644 --- a/libctru/include/3ds/os.h +++ b/libctru/include/3ds/os.h @@ -17,7 +17,16 @@ /// Retrieves the revision version from a packed system version. #define GET_VERSION_REVISION(version) (((version)>> 8)&0xFF) -/*! OS_VersionBin. Format of the system version: "..-" */ +/// Memory regions. +typedef enum +{ + MEMREGION_ALL = 0, ///< All regions. + MEMREGION_APPLICATION = 1, ///< APPLICATION memory. + MEMREGION_SYSTEM = 2, ///< SYSTEM memory. + MEMREGION_BASE = 3, ///< BASE memory. +} MemRegion; + +/// OS_VersionBin. Format of the system version: "..-" typedef struct { u8 build; @@ -78,6 +87,37 @@ static inline u32 osGetKernelVersion(void) return (*(vu32*)0x1FF80000) & ~0xFF; } +/** + * @brief Gets the size of the specified memory region. + * @param region Memory region to check. + * @return The size of the memory region, in bytes. + */ +static inline u32 osGetMemRegionSize(MemRegion region) +{ + if(region == MEMREGION_ALL) { + return osGetMemRegionSize(MEMREGION_APPLICATION) + osGetMemRegionSize(MEMREGION_SYSTEM) + osGetMemRegionSize(MEMREGION_BASE); + } else { + return *(vu32*) (0x1FF80040 + (region - 1) * 0x4); + } +} + +/** + * @brief Gets the number of used bytes within the specified memory region. + * @param region Memory region to check. + * @return The number of used bytes of memory. + */ +s64 osGetMemRegionUsed(MemRegion region); + +/** + * @brief Gets the number of free bytes within the specified memory region. + * @param region Memory region to check. + * @return The number of free bytes of memory. + */ +static inline s64 osGetMemRegionFree(MemRegion region) +{ + return (s64) osGetMemRegionSize(region) - osGetMemRegionUsed(region); +} + /** * @brief Gets the current time. * @return The number of milliseconds since 1st Jan 1900 00:00. diff --git a/libctru/source/os.c b/libctru/source/os.c index 8bbc0cc..abd93e4 100644 --- a/libctru/source/os.c +++ b/libctru/source/os.c @@ -51,6 +51,12 @@ void* osConvertOldLINEARMemToNew(const void* addr) { return 0; } +s64 osGetMemRegionUsed(MemRegion region) { + s64 mem_used; + svcGetSystemInfo(&mem_used, 0, region); + return mem_used; +} + //--------------------------------------------------------------------------------- static datetime_t getSysTime(void) { //--------------------------------------------------------------------------------- diff --git a/libctru/source/system/allocateHeaps.c b/libctru/source/system/allocateHeaps.c index 6bfcb62..0d7859c 100644 --- a/libctru/source/system/allocateHeaps.c +++ b/libctru/source/system/allocateHeaps.c @@ -1,6 +1,7 @@ #include <3ds/types.h> #include <3ds/svc.h> #include <3ds/env.h> +#include <3ds/os.h> extern char* fake_heap_start; extern char* fake_heap_end; @@ -13,9 +14,16 @@ u32 __ctru_linear_heap_size; void __attribute__((weak)) __system_allocateHeaps() { u32 tmp=0; - // Retrieve heap sizes. - __ctru_heap_size = envGetHeapSize(); - __ctru_linear_heap_size = envGetLinearHeapSize(); + if(envIsHomebrew()) { + // Use launcher-provided heap information. + __ctru_heap_size = envGetHeapSize(); + __ctru_linear_heap_size = envGetLinearHeapSize(); + } else { + // Distribute available memory into halves, aligning to page size. + u32 size = (osGetMemRegionFree(MEMREGION_APPLICATION) / 2) & 0xFFFFF000; + __ctru_heap_size = size; + __ctru_linear_heap_size = size; + } // Allocate the application heap __ctru_heap = 0x08000000;