RetroArch/ctr/ctr_memory.c
Justin Weiss 5756ff0b16 [3DS] Free memory in 1MB blocks
When freeing large blocks of memory, the 3DS may kernel panic. Freeing
in smaller blocks seems to avoid the crashes.
2020-09-28 19:12:15 -07:00

155 lines
3.6 KiB
C

#include <3ds.h>
#include <stdlib.h>
#include <errno.h>
#include <sys/types.h>
#include "ctr_debug.h"
extern u32 __heapBase;
extern u32 __heap_size;
extern u32 __stack_bottom;
extern u32 __stack_size_extra;
extern u32 __stacksize__;
u32 ctr_get_linear_free(void);
u32 ctr_get_linear_unused(void);
u32 ctr_get_stack_free(void)
{
extern u32 __stack_bottom;
uint32_t* stack_bottom_current = (u32*)__stack_bottom;
while(*stack_bottom_current++ == 0xFCFCFCFC);
stack_bottom_current--;
return ((u32)stack_bottom_current - __stack_bottom);
}
u32 ctr_get_stack_usage(void)
{
extern u32 __stacksize__;
u32 stack_free = ctr_get_stack_free();
return __stacksize__ > stack_free? __stacksize__ - stack_free: 0;
}
void ctr_linear_free_pages(u32 pages);
void ctr_free_pages(u32 pages)
{
u32 linear_free_pages;
u32 stack_free, stack_usage, stack_free_pages;
if(!pages)
return;
linear_free_pages = ctr_get_linear_free() >> 12;
if ((ctr_get_linear_unused() >> 12) > pages + 0x100)
return ctr_linear_free_pages(pages);
#if 0
if (linear_free_pages > pages + 0x400)
return ctr_linear_free_pages(pages);
#endif
stack_free = ctr_get_stack_free();
stack_usage = __stacksize__ > stack_free
? __stacksize__ - stack_free
: 0;
stack_free = stack_free > __stack_size_extra
? __stack_size_extra
: stack_free;
stack_free_pages = stack_free >> 12;
if(linear_free_pages + (stack_free_pages - (stack_usage >> 12)) > pages)
{
stack_free_pages -= (stack_usage >> 12);
stack_free_pages = stack_free_pages > pages ? pages : stack_free_pages;
linear_free_pages = pages - stack_free_pages;
}
else if(linear_free_pages + stack_free_pages > pages)
stack_free_pages = pages - linear_free_pages;
else
return;
if(linear_free_pages)
ctr_linear_free_pages(linear_free_pages);
if(stack_free_pages)
{
u32 tmp;
svcControlMemory(&tmp, __stack_bottom,
0x0,
stack_free_pages << 12,
MEMOP_FREE, MEMPERM_READ | MEMPERM_WRITE);
__stack_bottom += stack_free_pages << 12;
__stack_size_extra -= stack_free_pages << 12;
__stacksize__ -= stack_free_pages << 12;
#if 0
printf("s:0x%08X-->0x%08X(-0x%08X) \n", stack_free,
stack_free - (stack_free_pages << 12),
stack_free_pages << 12);
DEBUG_HOLD();
#endif
}
}
u32 ctr_get_free_space(void)
{
s64 mem_used;
u32 app_memory = *((u32*)0x1FF80040);
svcGetSystemInfo(&mem_used, 0, 1);
return app_memory - (u32)mem_used;
}
void ctr_request_free_pages(u32 pages)
{
u32 free_pages = ctr_get_free_space() >> 12;
if (pages > free_pages)
{
ctr_free_pages(pages - free_pages);
free_pages = ctr_get_free_space() >> 12;
}
}
void* _sbrk_r(struct _reent *ptr, ptrdiff_t incr)
{
static u32 sbrk_top = 0;
u32 tmp;
int diff;
if (!sbrk_top)
sbrk_top = __heapBase;
diff = ((sbrk_top + incr + 0xFFF) & ~0xFFF)
- (__heapBase + __heap_size);
if (diff > 0)
{
ctr_request_free_pages(diff >> 12);
if (svcControlMemory(&tmp, __heapBase + __heap_size,
0x0, diff, MEMOP_ALLOC, MEMPERM_READ | MEMPERM_WRITE) < 0)
{
ptr->_errno = ENOMEM;
return (caddr_t) -1;
}
}
__heap_size += diff;
while (diff < 0) {
int size = -diff < 0x100000 ? -diff : 0x100000;
diff += size;
svcControlMemory(&tmp, __heapBase + __heap_size - diff,
0x0, size, MEMOP_FREE, 0);
}
sbrk_top += incr;
return (caddr_t)(sbrk_top - incr);
}