From baec67ebefaf6dd7728ec62664b1724c9df5c3c4 Mon Sep 17 00:00:00 2001 From: Toad King Date: Mon, 27 Aug 2012 20:36:05 -0400 Subject: [PATCH] (GX) add MEM2 manager --- Makefile.wii | 2 +- console/griffin/griffin.c | 1 + gx/frontend/main.c | 3 + gx/gx_video.c | 7 +- gx/mem2_manager.c | 299 ++++++++++++++++++++++++++++++++++++++ gx/mem2_manager.h | 17 +++ 6 files changed, 326 insertions(+), 3 deletions(-) create mode 100644 gx/mem2_manager.c create mode 100644 gx/mem2_manager.h diff --git a/Makefile.wii b/Makefile.wii index 5a5ae93035..5b8648fbbc 100644 --- a/Makefile.wii +++ b/Makefile.wii @@ -34,7 +34,7 @@ LIBDIRS := -L$(DEVKITPRO)/libogc/lib/wii -L. MACHDEP := -DGEKKO -DHW_RVL -mrvl -mcpu=750 -meabi -mhard-float CFLAGS += -Wall -std=gnu99 $(MACHDEP) $(INCLUDE) -LDFLAGS := $(MACHDEP) -Wl,-Map,$(notdir $(ELF_TARGET)).map -T gx/ld/rvl.ld +LDFLAGS := $(MACHDEP) -Wl,-Map,$(notdir $(ELF_TARGET)).map,-wrap,malloc,-wrap,free,-wrap,memalign,-wrap,calloc,-wrap,realloc,-wrap,strdup,-wrap,strndup,-wrap,malloc_usable_size -T gx/ld/rvl.ld LIBS := -lfat -lretro_wii -lwiiuse -logc -lbte OBJ = console/griffin/griffin.o console/font.binobj console/rzlib/rzlib.o diff --git a/console/griffin/griffin.c b/console/griffin/griffin.c index 0ea5c50a5c..e51e6b9631 100644 --- a/console/griffin/griffin.c +++ b/console/griffin/griffin.c @@ -133,6 +133,7 @@ VIDEO DRIVER #elif defined(GEKKO) #ifdef HW_RVL #include "../../gx/vi_encoder.c" +#include "../../gx/mem2_manager.c" #endif #include "../../gx/gx_video.c" #endif diff --git a/gx/frontend/main.c b/gx/frontend/main.c index f61c3de9a5..dc57a3bf79 100644 --- a/gx/frontend/main.c +++ b/gx/frontend/main.c @@ -28,6 +28,8 @@ #include "../../console/rarch_console_input.h" #include "../../console/rarch_console_main_wrap.h" +#include "../mem2_manager.h" + #include #include #include @@ -395,6 +397,7 @@ int main(void) #ifdef HW_RVL IOS_ReloadIOS(IOS_GetVersion()); L2Enhance(); + gx_init_mem2(); #endif fatInitDefault(); diff --git a/gx/gx_video.c b/gx/gx_video.c index cf0728d49b..55ba8fd0b2 100644 --- a/gx/gx_video.c +++ b/gx/gx_video.c @@ -20,6 +20,7 @@ #include "../console/rarch_console_video.h" #include "../console/font.h" #include "../gfx/gfx_common.h" +#include "mem2_manager.h" #include "gx_video.h" #include #include @@ -27,6 +28,8 @@ #include #include +#define SYSMEM1_SIZE 0x01800000 + void *g_framebuf[2]; unsigned g_current_framebuf; @@ -652,12 +655,12 @@ static bool gx_frame(void *data, const void *frame, gfx_window_title(fps_txt, sizeof(fps_txt)); gx_blit_line(x, y, fps_txt); y += FONT_HEIGHT * 2; - snprintf(mem1_txt, sizeof(mem1_txt), "MEM1: %8d / 25165824", SYS_GetArena1Size()); /* 25165824 = 0x01800000 */ + snprintf(mem1_txt, sizeof(mem1_txt), "MEM1: %8d / %8d", SYSMEM1_SIZE - SYS_GetArena1Size(), SYSMEM1_SIZE); gx_blit_line(x, y, mem1_txt); #ifdef HW_RVL y += FONT_HEIGHT * 2; char mem2_txt[128]; - snprintf(mem2_txt, sizeof(mem2_txt), "MEM2: %8d / 67108864", SYS_GetArena2Size()); /* 67108864 = 0x04000000 */ + snprintf(mem2_txt, sizeof(mem2_txt), "MEM2: %8d / %8d", gx_mem2_used(), gx_mem2_total()); gx_blit_line(x, y, mem2_txt); #endif } diff --git a/gx/mem2_manager.c b/gx/mem2_manager.c new file mode 100644 index 0000000000..0ed61abe7d --- /dev/null +++ b/gx/mem2_manager.c @@ -0,0 +1,299 @@ +/** + * Adopted from WiiMC (Tantric 2009-2012) and WiiFlow (http://code.google.com/p/wiiflow/) + */ + +#include +#include +#include +#include +#include +#include +#include +#include "mem2_manager.h" + +// Forbid the use of MEM2 through malloc +u32 MALLOC_MEM2 = 0; + +/*** from libogc (lwp_heap.inl) ****/ + +static __inline__ heap_block *__lwp_heap_blockat(heap_block *block, u32 offset) +{ + return (heap_block*) ((char*) block + offset); +} + +static __inline__ heap_block *__lwp_heap_usrblockat(void *ptr) +{ + u32 offset = *(((u32*) ptr) - 1); + return __lwp_heap_blockat(ptr, -offset + -HEAP_BLOCK_USED_OVERHEAD); +} +static __inline__ bool __lwp_heap_blockin(heap_cntrl *heap, heap_block *block) +{ + return ((u32) block >= (u32) heap->start && (u32) block <= (u32)heap->final); +} +static __inline__ bool __lwp_heap_blockfree(heap_block *block) +{ + return !(block->front_flag & HEAP_BLOCK_USED); +} +static __inline__ u32 __lwp_heap_blocksize(heap_block *block) +{ + 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; + + _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; +} + +#define ROUNDUP32(v) (((u32)(v) + 0x1f) & ~0x1f) + +static heap_cntrl gx_mem2_heap; + +bool gx_init_mem2() +{ + u32 level; + u32 size = SYS_GetArena2Size(); + + _CPU_ISR_Disable(level); + + void *heap_ptr = (void *) ROUNDUP32(((u32) SYS_GetArena2Hi() - size)); + + SYS_SetArena2Hi(heap_ptr); + __lwp_heap_init(&gx_mem2_heap, heap_ptr, size, 32); + _CPU_ISR_Restore(level); + return true; +} + +void *_mem2_memalign(u8 align, u32 size) +{ + void *ptr; + + if(size == 0) + return NULL; + + ptr = __lwp_heap_allocate(&gx_mem2_heap, size); + + if (ptr == NULL) + return NULL; + + return ptr; +} + +void *_mem2_malloc(u32 size) +{ + return _mem2_memalign(32, size); +} + +void _mem2_free(void *ptr) +{ + if(!ptr) + return; + + __lwp_heap_free(&gx_mem2_heap, ptr); + } + +void *_mem2_realloc(void *ptr, u32 newsize) +{ + void *newptr = NULL; + + if (ptr == NULL) + return _mem2_malloc(newsize); + + if (newsize == 0) + { + _mem2_free(ptr); + return NULL; + } + + u32 size = __lwp_heap_block_size(&gx_mem2_heap, ptr); + + if (size > newsize) + size = newsize; + + newptr = _mem2_malloc(newsize); + + if (newptr == NULL) + return NULL; + + memcpy(newptr, ptr, size); + _mem2_free(ptr); + return newptr; +} + +void *_mem2_calloc(u32 num, u32 size) +{ + void *ptr = _mem2_malloc(num * size); + + if (ptr == NULL) + return NULL; + + memset(ptr, 0, num * size); + return ptr; +} + +char *_mem2_strdup(const char *s) +{ + char *ptr = NULL; + if (s) + { + int len = strlen(s) + 1; + ptr = _mem2_calloc(1, len); + if (ptr) + memcpy(ptr, s, len); + } + return ptr; +} + +char *_mem2_strndup(const char *s, size_t n) +{ + char *ptr = NULL; + if (s) + { + int len = n + 1; + ptr = _mem2_calloc(1, len); + if (ptr) + memcpy(ptr, s, len); + } + return ptr; +} + +u32 gx_mem2_used() +{ + heap_iblock info; + __lwp_heap_getinfo(&gx_mem2_heap, &info); + return info.used_size; +} + +u32 gx_mem2_total() +{ + heap_iblock info; + __lwp_heap_getinfo(&gx_mem2_heap, &info); + return info.used_size + info.free_size; +} + +#ifdef __cplusplus +extern "C" +{ +#endif + +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); + +void *__wrap_malloc(size_t size) +{ + void *p = __real_malloc(size); + if (p != 0) + return p; + return _mem2_malloc(size); +} + +void *__wrap_calloc(size_t n, size_t size) +{ + void *p = __real_calloc(n, size); + if (p != 0) + return p; + return _mem2_calloc(n, size); +} + +void *__wrap_memalign(size_t a, size_t size) +{ + void *p = __real_memalign(a, size); + if (p != 0) + return p; + return _mem2_memalign(a, size); +} + +void __wrap_free(void *p) +{ + if (!p) + return; + + if (((u32) p & 0x10000000) != 0) + _mem2_free(p); + else + __real_free(p); +} + +void *__wrap_realloc(void *p, size_t size) +{ + void *n; + // ptr from mem2 + 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; +} + +void *__wrap_strdup(const char *s) +{ + void *p = __real_strdup(s); + if (p != 0) + return p; + return _mem2_strdup(s); +} + +void *__wrap_strndup(const char *s, size_t n) +{ + void *p = __real_strndup(s, n); + if (p != 0) + return p; + return _mem2_strndup(s, n); +} + +size_t __wrap_malloc_usable_size(void *p) +{ + if (((u32) p & 0x10000000) != 0) + return __lwp_heap_block_size(&gx_mem2_heap, p); + return __real_malloc_usable_size(p); +} + +#ifdef __cplusplus +} +#endif diff --git a/gx/mem2_manager.h b/gx/mem2_manager.h new file mode 100644 index 0000000000..0a81fd17ff --- /dev/null +++ b/gx/mem2_manager.h @@ -0,0 +1,17 @@ +/**************************************************************************** + * WiiMC + * Tantric 2009-2012 + * + * mem2_manager.h + * + * MEM2 allocator + ****************************************************************************/ + +#ifndef _MEM2_MANAGER_H +#define _MEM2_MANAGER_H + +bool gx_init_mem2(); +u32 gx_mem2_used(); +u32 gx_mem2_total(); + +#endif