mirror of
https://github.com/libretro/RetroArch.git
synced 2024-11-26 17:50:56 +00:00
5756ff0b16
When freeing large blocks of memory, the 3DS may kernel panic. Freeing in smaller blocks seems to avoid the crashes.
155 lines
3.6 KiB
C
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);
|
|
}
|