RetroArch/wii/mem2_manager.c

310 lines
6.5 KiB
C
Raw Normal View History

2012-08-28 00:36:05 +00:00
/**
* Adopted from WiiMC (Tantric 2009-2012) and WiiFlow (http://code.google.com/p/wiiflow/)
*/
#include <ogc/machine/asm.h>
#include <ogc/lwp_heap.h>
#include <ogc/system.h>
2015-01-12 05:55:31 +00:00
#include "../gfx/drivers/ppc_asm.h"
2012-08-28 00:36:05 +00:00
#include <string.h>
#include <malloc.h>
#include <unistd.h>
#include "mem2_manager.h"
2015-03-15 03:52:46 +00:00
#include <retro_inline.h>
2012-08-28 00:36:05 +00:00
// Forbid the use of MEM2 through malloc
u32 MALLOC_MEM2 = 0;
/*** from libogc (lwp_heap.inl) ****/
2015-03-15 03:52:46 +00:00
static INLINE heap_block *__lwp_heap_blockat(heap_block *block, u32 offset)
2012-08-28 00:36:05 +00:00
{
return (heap_block *) ((char *) block + offset);
2012-08-28 00:36:05 +00:00
}
2015-03-15 03:52:46 +00:00
static INLINE heap_block *__lwp_heap_usrblockat(void *ptr)
2012-08-28 00:36:05 +00:00
{
u32 offset = *(((u32 *) ptr) - 1);
2012-08-28 00:36:05 +00:00
return __lwp_heap_blockat(ptr, -offset + -HEAP_BLOCK_USED_OVERHEAD);
}
2015-03-15 03:52:46 +00:00
static INLINE bool __lwp_heap_blockin(heap_cntrl *heap, heap_block *block)
2012-08-28 00:36:05 +00:00
{
return ((u32) block >= (u32) heap->start && (u32) block <= (u32) heap->final);
2012-08-28 00:36:05 +00:00
}
2015-03-15 03:52:46 +00:00
static INLINE bool __lwp_heap_blockfree(heap_block *block)
2012-08-28 00:36:05 +00:00
{
return !(block->front_flag & HEAP_BLOCK_USED);
}
2015-03-15 03:52:46 +00:00
static INLINE u32 __lwp_heap_blocksize(heap_block *block)
2012-08-28 00:36:05 +00:00
{
return (block->front_flag & ~HEAP_BLOCK_USED);
}
/*** end from libogc (lwp_heap.inl) ****/
static u32 __lwp_heap_block_size(heap_cntrl *theheap, void *ptr)
{
heap_block *block;
u32 dsize, level;
(void)level;
2012-08-28 00:36:05 +00:00
_CPU_ISR_Disable(level);
block = __lwp_heap_usrblockat(ptr);
if(!__lwp_heap_blockin(theheap, block) || __lwp_heap_blockfree(block))
{
_CPU_ISR_Restore(level);
return 0;
}
dsize = __lwp_heap_blocksize(block);
_CPU_ISR_Restore(level);
return dsize;
}
2012-08-28 01:31:40 +00:00
#define ROUNDUP32(v) (((u32)(v) + 0x1f) & ~0x1f)
2012-08-28 00:36:05 +00:00
static heap_cntrl gx_mem2_heap;
2014-06-04 04:22:29 +00:00
bool gx_init_mem2(void)
2012-08-28 00:36:05 +00:00
{
2014-10-22 04:07:27 +00:00
void *heap_ptr;
u32 level, size;
2012-08-28 00:36:05 +00:00
_CPU_ISR_Disable(level);
2014-09-15 04:43:50 +00:00
/* BIG NOTE: MEM2 on the Wii is 64MB, but a portion
* of that is reserved for IOS.
*
* libogc by default defines the "safe" area for MEM2
* to go from 0x90002000 to 0x933E0000.
*
* However, from my testing, I've found I need to
* reserve about 256KB for stuff like network and USB to work correctly.
* However, other sources says these functions need at least 0xE0000 bytes,
* 7/8 of a megabyte, of reserved memory to do this. My initial testing
* shows that we can work with only 128KB, but we use 256KB becuse testing
* has shown some stuff being iffy with only 128KB, mainly Wiimote stuff.
* If some stuff mysteriously stops working, try fiddling with this size.
*/
2014-10-22 04:07:27 +00:00
size = SYS_GetArena2Size() - 1024 * 256;
2012-08-28 01:31:40 +00:00
2014-10-22 04:07:27 +00:00
heap_ptr = (void *) ROUNDUP32(((u32) SYS_GetArena2Hi() - size));
2012-08-28 00:36:05 +00:00
SYS_SetArena2Hi(heap_ptr);
__lwp_heap_init(&gx_mem2_heap, heap_ptr, size, 32);
_CPU_ISR_Restore(level);
2014-10-22 04:07:27 +00:00
2012-08-28 00:36:05 +00:00
return true;
}
void *_mem2_memalign(u8 align, u32 size)
{
2014-10-22 04:07:27 +00:00
if(size == 0)
return NULL;
return __lwp_heap_allocate(&gx_mem2_heap, size);
2012-08-28 00:36:05 +00:00
}
void *_mem2_malloc(u32 size)
{
return _mem2_memalign(32, size);
}
void _mem2_free(void *ptr)
{
2014-10-22 04:07:27 +00:00
if (ptr)
2014-09-15 04:43:50 +00:00
__lwp_heap_free(&gx_mem2_heap, ptr);
2014-10-22 04:07:27 +00:00
}
2012-08-28 00:36:05 +00:00
void *_mem2_realloc(void *ptr, u32 newsize)
{
2014-10-22 04:07:27 +00:00
u32 size;
2012-08-28 00:36:05 +00:00
void *newptr = NULL;
2014-10-22 04:07:27 +00:00
if (!ptr)
2012-08-28 00:36:05 +00:00
return _mem2_malloc(newsize);
if (newsize == 0)
{
_mem2_free(ptr);
return NULL;
}
2014-10-22 04:07:27 +00:00
size = __lwp_heap_block_size(&gx_mem2_heap, ptr);
2012-08-28 00:36:05 +00:00
if (size > newsize)
size = newsize;
newptr = _mem2_malloc(newsize);
2014-10-22 04:07:27 +00:00
if (!newptr)
2012-08-28 00:36:05 +00:00
return NULL;
memcpy(newptr, ptr, size);
_mem2_free(ptr);
2014-10-22 04:07:27 +00:00
2012-08-28 00:36:05 +00:00
return newptr;
}
void *_mem2_calloc(u32 num, u32 size)
{
void *ptr = _mem2_malloc(num * size);
2014-10-22 04:07:27 +00:00
if (!ptr)
2012-08-28 00:36:05 +00:00
return NULL;
memset(ptr, 0, num * size);
return ptr;
}
char *_mem2_strdup(const char *s)
{
char *ptr = NULL;
2014-10-22 04:07:27 +00:00
2012-08-28 00:36:05 +00:00
if (s)
{
int len = strlen(s) + 1;
2014-10-22 04:07:27 +00:00
2012-08-28 00:36:05 +00:00
ptr = _mem2_calloc(1, len);
2014-10-22 04:07:27 +00:00
2012-08-28 00:36:05 +00:00
if (ptr)
memcpy(ptr, s, len);
}
2014-10-22 04:07:27 +00:00
2012-08-28 00:36:05 +00:00
return ptr;
}
char *_mem2_strndup(const char *s, size_t n)
{
char *ptr = NULL;
2014-10-22 04:07:27 +00:00
2012-08-28 00:36:05 +00:00
if (s)
{
int len = n + 1;
ptr = _mem2_calloc(1, len);
2014-10-22 04:07:27 +00:00
2012-08-28 00:36:05 +00:00
if (ptr)
memcpy(ptr, s, len);
}
return ptr;
}
2014-06-04 04:22:29 +00:00
u32 gx_mem2_used(void)
2012-08-28 00:36:05 +00:00
{
heap_iblock info;
__lwp_heap_getinfo(&gx_mem2_heap, &info);
return info.used_size;
}
2014-06-04 04:22:29 +00:00
u32 gx_mem2_total(void)
2012-08-28 00:36:05 +00:00
{
heap_iblock info;
__lwp_heap_getinfo(&gx_mem2_heap, &info);
return info.used_size + info.free_size;
}
void *__real_malloc(size_t size);
void *__real_calloc(size_t n, size_t size);
void *__real_memalign(size_t a, size_t size);
void __real_free(void *p);
void *__real_realloc(void *p, size_t size);
void *__real_strdup(const char *s);
void *__real_strndup(const char *s, size_t n);
size_t __real_malloc_usable_size(void *p);
__attribute__ ((used)) void *__wrap_malloc(size_t size)
2012-08-28 00:36:05 +00:00
{
void *p = __real_malloc(size);
2014-10-22 04:07:27 +00:00
if (p == 0)
return _mem2_malloc(size);
return p;
2012-08-28 00:36:05 +00:00
}
__attribute__ ((used)) void *__wrap_calloc(size_t n, size_t size)
2012-08-28 00:36:05 +00:00
{
void *p = __real_calloc(n, size);
2014-10-22 04:07:27 +00:00
if (p == 0)
return _mem2_calloc(n, size);
return p;
2012-08-28 00:36:05 +00:00
}
__attribute__ ((used)) void *__wrap_memalign(size_t a, size_t size)
2012-08-28 00:36:05 +00:00
{
void *p = __real_memalign(a, size);
2014-10-22 04:07:27 +00:00
if (p == 0)
return _mem2_memalign(a, size);
return p;
2012-08-28 00:36:05 +00:00
}
__attribute__ ((used)) void __wrap_free(void *p)
2012-08-28 00:36:05 +00:00
{
if (!p)
return;
2014-10-22 04:07:27 +00:00
if (((u32)p & 0x10000000) != 0)
2012-08-28 00:36:05 +00:00
_mem2_free(p);
else
__real_free(p);
}
__attribute__ ((used)) void *__wrap_realloc(void *p, size_t size)
2012-08-28 00:36:05 +00:00
{
void *n;
2014-09-15 04:43:50 +00:00
/* ptr from mem2 */
2012-08-28 00:36:05 +00:00
if (((u32) p & 0x10000000) != 0)
{
n = _mem2_realloc(p, size);
if (n != 0)
return n;
n = __real_malloc(size);
if (n == 0)
return 0;
if (p != 0)
{
size_t heap_size = __lwp_heap_block_size(&gx_mem2_heap, p);
memcpy(n, p, heap_size < size ? heap_size : size);
_mem2_free(p);
}
return n;
}
// ptr from malloc
n = __real_realloc(p, size);
if (n != 0)
return n;
n = _mem2_malloc(size);
if (n == 0)
return 0;
if (p != 0)
{
size_t heap_size = __real_malloc_usable_size(p);
memcpy(n, p, heap_size < size ? heap_size : size);
__real_free(p);
}
return n;
}
__attribute__ ((used)) void *__wrap_strdup(const char *s)
2012-08-28 00:36:05 +00:00
{
void *p = __real_strdup(s);
2014-10-22 04:07:27 +00:00
if (p == 0)
return _mem2_strdup(s);
return p;
2012-08-28 00:36:05 +00:00
}
__attribute__ ((used)) void *__wrap_strndup(const char *s, size_t n)
2012-08-28 00:36:05 +00:00
{
void *p = __real_strndup(s, n);
2014-10-22 04:07:27 +00:00
if (p == 0)
return _mem2_strndup(s, n);
return p;
2012-08-28 00:36:05 +00:00
}
__attribute__ ((used)) size_t __wrap_malloc_usable_size(void *p)
2012-08-28 00:36:05 +00:00
{
if (((u32) p & 0x10000000) != 0)
return __lwp_heap_block_size(&gx_mem2_heap, p);
return __real_malloc_usable_size(p);
}