pokediamond/include/nitro/os_alloc.c
2020-04-24 02:58:35 +01:00

715 lines
15 KiB
C

//
// Created by mart on 4/23/20.
//
#include "os_alloc.h"
#include "consts.h"
#include "os_system.h"
extern BOOL OSi_MainExArenaEnabled;
extern BOOL OSi_Initialized; // TODO: located at 0x021d36f0
extern u32 OS_GetConsoleType();
extern u32 OS_CONSOLE_SIZE_MASK;
extern u32 OS_CONSOLE_SIZE_4MB;
extern Cell* DLInsert(Cell* list, Cell* cell);
extern Cell* DLAddFront(Cell* list, Cell* cell);
extern void OS_SetProtectionRegion1(u32 param);
extern void OS_SetProtectionRegion2(u32 param);
void* OSiHeapInfo[OS_ARENA_MAX] = {
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL
};
#ifdef MATCH_ASM
asm static Cell* DLExtract(Cell* list, Cell* cell)
{
ldr r3, [r1, #0x4]
cmp r3, #0x0
ldrne r2, [r1, #0x0]
strne r2, [r3, #0x0]
ldr r2, [r1, #0x0]
cmp r2, #0x0
ldreq r0, [r1, #0x4]
ldrne r1, [r1, #0x4]
strne r1, [r2, #0x4]
bx lr
}
#else
static Cell* DLExtract(Cell* list, Cell* cell)
{
if (cell->next) {
cell->prev = cell->next->prev;
}
if (cell->prev) {
cell->prev->next = cell->next;
return list;
}
else {
return cell->next;
}
}
#endif
#ifdef MATCH_ASM
asm void* OS_AllocFromArenaHi(OSArenaId id, u32 size, u32 align) {
stmdb sp!,{ r4-r6, lr }
mov r4,r0
mov r6,r1
mov r5,r2
bl OS_GetArenaHi
cmp r0,#0x0
moveq r0,#0x0
ldmeqia sp!,{ r4-r6, lr }
bxeq lr
sub r1,r5,#0x1
mvn r2,r1
and r0,r0,r2
sub r1,r0,r6
mov r0,r4
and r5,r1,r2
bl OS_GetArenaLo
cmp r5,r0
movcc r0,#0x0
ldmccia sp!,{ r4-r6, lr }
bxcc lr
mov r0,r4
mov r1,r5
bl OS_SetArenaHi
mov r0,r5
ldmia sp!,{ r4-r6, lr }
bx lr
}
#else
void* OS_AllocFromArenaHi(OSArenaId id, u32 size, u32 align) {
void* ptr;
u8* arenaHi;
arenaHi = OS_GetArenaHi(id);
if (!arenaHi) {
return NULL;
}
arenaHi = (u8 *)OSi_TRUNC(arenaHi, align);
arenaHi -= size;
arenaHi = ptr = (void *)OSi_TRUNC(arenaHi, align);
if (arenaHi < (u8*)OS_GetArenaLo(id)) {
return NULL;
}
OS_SetArenaHi(id, arenaHi);
return ptr;
}
#endif
#ifdef MATCH_ASM
asm void* OS_AllocFromArenaLo(OSArenaId id, u32 size, u32 align) {
stmdb sp!,{ r4-r7, lr }
sub sp,sp,#0x4
mov r7,r0
mov r6,r1
mov r5,r2
bl OS_GetArenaLo
cmp r0,#0x0
addeq sp,sp,#0x4
moveq r0,#0x0
ldmeqia sp!,{ r4-r7, lr }
bxeq lr
add r0,r0,r5
sub r1,r5,#0x1
mvn r2,r1
sub r0,r0,#0x1
and r4,r2,r0
add r0,r4,r6
add r0,r0,r5
sub r1,r0,#0x1
mov r0,r7
and r5,r2,r1
bl OS_GetArenaHi
cmp r5,r0
addhi sp,sp,#0x4
movhi r0,#0x0
ldmhiia sp!,{ r4-r7, lr }
bxhi lr
mov r0,r7
mov r1,r5
bl OS_SetArenaLo
mov r0,r4
add sp,sp,#0x4
ldmia sp!,{ r4-r7, lr }
bx lr
}
#else
void* OS_AllocFromArenaLo(OSArenaId id, u32 size, u32 align) {
void* ptr;
u8* arenaLo;
ptr = OS_GetArenaLo(id);
if (!ptr) {
return NULL;
}
arenaLo = ptr = (void *)OSi_ROUND(ptr, align);
arenaLo += size;
arenaLo = (u8 *)OSi_ROUND(arenaLo, align);
if (arenaLo > (u8*)OS_GetArenaHi(id)) {
return NULL;
}
OS_SetArenaLo(id, arenaLo);
return ptr;
}
#endif
#ifdef MATCH_ASM
asm void OS_SetArenaLo(OSArenaId id, void* newLo) {
mov r0,r0, lsl #0x2
add r0,r0,#0x2700000
add r0,r0,#0xff000
str r1,[r0,#0xda0]
bx lr
}
#else
void OS_SetArenaLo(OSArenaId id, void* newLo) {
OSi_GetArenaInfo().lo[id] = newLo;
}
#endif
#ifdef MATCH_ASM
asm void OS_SetArenaHi(OSArenaId id, void* newHi) {
mov r0,r0, lsl #0x2
add r0,r0,#0x2700000
add r0,r0,#0xff000
str r1,[r0,#0xdc4]
bx lr
}
#else
void OS_SetArenaHi(OSArenaId id, void* newHi) {
OSi_GetArenaInfo().lo[id] = newHi;
}
#endif
#ifdef MATCH_ASM
asm void* OS_GetInitArenaLo(OSArenaId id) {
// TODO: idk how to do switch case stuff properly in asm
}
#else
void* OS_GetInitArenaLo(OSArenaId id) {
switch (id) {
case OS_ARENA_MAIN:
return (void *)0x0225ffa0;
case OS_ARENA_MAINEX:
if (!OSi_MainExArenaEnabled || (OS_GetConsoleType() & OS_CONSOLE_SIZE_MASK) == OS_CONSOLE_SIZE_4MB) {
return NULL;
} else {
return (void *)0x023e0000;
}
case OS_ARENA_ITCM:
return (void *)0x01ff8720;
case OS_ARENA_DTCM:
return (void *)0x027e0080;
case OS_ARENA_SHARED:
return (void *)0x027ff000;
case OS_ARENA_WRAM_MAIN:
return (void *)0x037f8000;
default:
return NULL;
}
}
#endif
#ifdef MATCH_ASM
asm void* OS_GetInitArenaHi(OSArenaId id) {
stmdb sp!, {lr}
sub sp, sp, #0x4
cmp r0, #0x6
addls pc, pc, r0, lsl #0x2
b _020CC508
_020CC41C:
b _020CC438
b _020CC508
b _020CC448
b _020CC488
b _020CC498
b _020CC4E8
b _020CC4F8
_020CC438:
add sp, sp, #0x4
ldr r0, =OSi_MAIN_ARENA_HI_DEFAULT
ldmfd sp!, {lr}
bx lr
_020CC448:
ldr r0, =OSi_MainExArenaEnabled
ldr r0, [r0]
cmp r0, #0x0
beq _020CC468
bl OS_GetConsoleType
and r0, r0, #0x3
cmp r0, #0x1
bne _020CC478
_020CC468:
add sp, sp, #0x4
mov r0, #0x0
ldmfd sp!, {lr}
bx lr
_020CC478:
add sp, sp, #0x4
mov r0, #OSi_MAINEX_ARENA_HI_DEFAULT
ldmfd sp!, {lr}
bx lr
_020CC488:
add sp, sp, #0x4
mov r0, #HW_ITCM_ARENA_HI_DEFAULT
ldmfd sp!, {lr}
bx lr
_020CC498:
ldr r0, =0x027E0000
ldr r1, =0x00000000
ldr r2, =0x00000400
add r3, r0, #0x3f80
cmp r1, #0x0
sub r2, r3, r2
bne _020CC4CC
ldr r1, =0x027E0080
add sp, sp, #0x4
cmp r0, r1
movcc r0, r1
ldmfd sp!, {lr}
bx lr
_020CC4CC:
cmp r1, #0x0
ldrlt r0, =0x027E0080
add sp, sp, #0x4
sublt r0, r0, r1
subge r0, r2, r1
ldmfd sp!, {lr}
bx lr
_020CC4E8:
add sp, sp, #0x4
ldr r0, =HW_SHARED_ARENA_HI_DEFAULT
ldmfd sp!, {lr}
bx lr
_020CC4F8:
add sp, sp, #0x4
ldr r0, =OSi_WRAM_MAIN_ARENA_HI_DEFAULT;
ldmfd sp!, {lr}
bx lr
_020CC508:
mov r0, #0x0
add sp, sp, #0x4
ldmia sp!, {lr}
bx lr
}
#else
void* OS_GetInitArenaHi(OSArenaId id) {
switch (id) {
case OS_ARENA_MAIN:
return (void *)OSi_MAIN_ARENA_HI_DEFAULT;
case OS_ARENA_MAINEX:
if (!OSi_MainExArenaEnabled || (OS_GetConsoleType() & OS_CONSOLE_SIZE_MASK) == OS_CONSOLE_SIZE_4MB) {
return (void *)0;
} else {
return (void *)OSi_MAINEX_ARENA_HI_DEFAULT;
}
case OS_ARENA_ITCM:
return (void *)HW_ITCM_ARENA_HI_DEFAULT;
case OS_ARENA_DTCM:
return (void *)0x027e0080; //todo pretty sure this is incorrect, no constant and doesn't match
case OS_ARENA_SHARED:
return (void *)HW_SHARED_ARENA_HI_DEFAULT;
case OS_ARENA_WRAM_MAIN:
return (void *)OSi_WRAM_MAIN_ARENA_HI_DEFAULT;
default:
return NULL;
}
}
#endif
#ifdef MATCH_ASM
asm void* OS_GetArenaLo(OSArenaId id) {
mov r0,r0, lsl #0x2
add r0,r0,#0x2700000
add r0,r0,#0xff000
ldr r0,[r0,#0xda0]
bx lr
}
#else
void* OS_GetArenaLo(OSArenaId id) {
return OSi_GetArenaInfo().lo[id];
}
#endif
#ifdef MATCH_ASM
asm void* OS_GetArenaHi(OSArenaId id) {
mov r0,r0, lsl #0x2
add r0,r0,#0x2700000
add r0,r0,#0xff000
ldr r0,[r0,#0xdc4]
bx lr
}
#else
void* OS_GetArenaHi(OSArenaId id) {
return OSi_GetArenaInfo().hi[id];
}
#endif
#ifdef MATCH_ASM
asm void OS_InitArenaEx() {
stmdb sp!,{ lr }
sub sp,sp,#0x4
mov r0,#0x2
bl OS_GetInitArenaHi
mov r1,r0
mov r0,#0x2
bl OS_SetArenaHi
mov r0,#0x2
bl OS_GetInitArenaLo
mov r1,r0
mov r0,#0x2
bl OS_SetArenaLo
ldr r0, =OSi_MainExArenaEnabled
ldr r0,[r0,#0x0]
cmp r0,#0x0
beq _020CC5B8
bl OS_GetConsoleType
and r0,r0,#0x3
cmp r0,#0x1
addne sp,sp,#0x4
ldmneia sp!,{ lr }
bxne lr
_020CC5B8:
ldr r0, =0x0200002b
bl OS_SetProtectionRegion1
ldr r0, =0x023e0021
bl OS_SetProtectionRegion2
add sp,sp,#0x4
ldmia sp!,{ lr }
bx lr
}
#else
void OS_InitArenaEx() {
void* uVar1;
uVar1 = OS_GetInitArenaHi(OS_ARENA_MAINEX);
OS_SetArenaHi(2,uVar1);
uVar1 = OS_GetInitArenaLo(OS_ARENA_MAINEX);
OS_SetArenaLo(2,uVar1);
if (!OSi_MainExArenaEnabled || (OS_GetConsoleType() & OS_CONSOLE_SIZE_MASK) == OS_CONSOLE_SIZE_4MB) {
return;
}
// TODO:
// OS_SetProtectionRegion1(&UNK_0200002b);
// OS_SetProtectionRegion2(0x023e0021);
}
#endif
#ifdef MATCH_ASM
asm void OS_InitArena() {
stmdb sp!,{ lr }
sub sp,sp,#0x4
ldr r1, =OSi_Initialized
ldr r0,[r1,#0x0]
cmp r0,#0x0
addne sp,sp,#0x4
ldmneia sp!,{ lr }
bxne lr
mov r2,#0x1
mov r0,#0x0
str r2,[r1,#0x0]
bl OS_GetInitArenaHi
mov r1,r0
mov r0,#0x0
bl OS_SetArenaHi
mov r0,#0x0
bl OS_GetInitArenaLo
mov r1,r0
mov r0,#0x0
bl OS_SetArenaLo
mov r0,#0x2
mov r1,#0x0
bl OS_SetArenaLo
mov r0,#0x2
mov r1,#0x0
bl OS_SetArenaHi
mov r0,#0x3
bl OS_GetInitArenaHi
mov r1,r0
mov r0,#0x3
bl OS_SetArenaHi
mov r0,#0x3
bl OS_GetInitArenaLo
mov r1,r0
mov r0,#0x3
bl OS_SetArenaLo
mov r0,#0x4
bl OS_GetInitArenaHi
mov r1,r0
mov r0,#0x4
bl OS_SetArenaHi
mov r0,#0x4
bl OS_GetInitArenaLo
mov r1,r0
mov r0,#0x4
bl OS_SetArenaLo
mov r0,#0x5
bl OS_GetInitArenaHi
mov r1,r0
mov r0,#0x5
bl OS_SetArenaHi
mov r0,#0x5
bl OS_GetInitArenaLo
mov r1,r0
mov r0,#0x5
bl OS_SetArenaLo
mov r0,#0x6
bl OS_GetInitArenaHi
mov r1,r0
mov r0,#0x6
bl OS_SetArenaHi
mov r0,#0x6
bl OS_GetInitArenaLo
mov r1,r0
mov r0,#0x6
bl OS_SetArenaLo
add sp,sp,#0x4
ldmia sp!,{ lr }
bx lr
}
#else
void OS_InitArena() {
if (OSi_Initialized) {
return;
}
OSi_Initialized = TRUE;
OS_SetArenaHi(OS_ARENA_MAIN, OS_GetInitArenaHi(OS_ARENA_MAIN));
OS_SetArenaLo(OS_ARENA_MAIN, OS_GetInitArenaLo(OS_ARENA_MAIN));
OS_SetArenaLo(OS_ARENA_MAINEX, (void *)0);
OS_SetArenaHi(OS_ARENA_MAINEX, (void *)0);
OS_SetArenaHi(OS_ARENA_ITCM, OS_GetInitArenaHi(OS_ARENA_ITCM));
OS_SetArenaLo(OS_ARENA_ITCM, OS_GetInitArenaLo(OS_ARENA_ITCM));
OS_SetArenaHi(OS_ARENA_DTCM, OS_GetInitArenaHi(OS_ARENA_DTCM));
OS_SetArenaLo(OS_ARENA_DTCM, OS_GetInitArenaLo(OS_ARENA_DTCM));
OS_SetArenaHi(OS_ARENA_SHARED, OS_GetInitArenaHi(OS_ARENA_SHARED));
OS_SetArenaLo(OS_ARENA_SHARED, OS_GetInitArenaLo(OS_ARENA_SHARED));
OS_SetArenaHi(OS_ARENA_WRAM_MAIN, OS_GetInitArenaHi(OS_ARENA_WRAM_MAIN));
OS_SetArenaLo(OS_ARENA_WRAM_MAIN, OS_GetInitArenaLo(OS_ARENA_WRAM_MAIN));
}
#endif
#define HEADERSIZE OSi_ROUND(sizeof(Cell), 32)
#define MINOBJSIZE (HEADERSIZE+32)
#ifdef MATCH_ASM
asm void OS_FreeToHeap(OSArenaId id, OSHeapHandle heap, void* ptr) {
stmdb sp!, {r4-r7, lr}
sub sp,sp,#0x4
mov r7,r0
mov r5,r1
mov r4,r2
bl OS_DisableInterrupts
ldr r1,=OSiHeapInfo
mov r6,r0
ldr r0,[r1,r7,lsl #0x2]
cmp r5,#0x0
ldrlt r5,[r0,#0x0]
ldr r1,[r0,#0x10]
mov r0,#0xc
mla r7,r5,r0,r1
sub r4,r4,#0x20
ldr r0,[r7,#0x8]
mov r1,r4
bl DLExtract
str r0,[r7,#0x8]
ldr r0,[r7,#0x4]
mov r1,r4
bl DLInsert
str r0,[r7,#0x4]
mov r0,r6
bl OS_RestoreInterrupts
add sp,sp,#0x4
ldmia sp!,{ r4-r7, lr }
bx lr
}
#else
void OS_FreeToHeap(OSArenaId id, OSHeapHandle heap, void* ptr) {
OSHeapInfo *heapInfo;
HeapDesc *hd;
Cell *cell;
OSIntrMode enabled = OS_DisableInterrupts();
heapInfo = OSiHeapInfo[id];
if (heap < 0) {
heap = heapInfo->currentHeap;
}
cell = (Cell *) ((char *)ptr - HEADERSIZE);
hd = &heapInfo->heapArray[heap];
hd->allocated = DLExtract(hd->allocated, cell);
hd->free = DLInsert(hd->free, cell);
OS_RestoreInterrupts(enabled);
}
#endif
#ifdef MATCH_ASM
asm void* OS_AllocFromHeap(OSArenaId id, OSHeapHandle heap, u32 size) {
stmdb sp!, {r4-r7,lr}
sub sp, sp, #0x4
mov r6, r0
mov r5, r1
mov r7, r2
bl OS_DisableInterrupts
ldr r1, =OSiHeapInfo
mov r4, r0
ldr r1, [r1, r6, lsl #0x2]
cmp r1, #0x0
bne _020CC7AC
bl OS_RestoreInterrupts
add sp, sp, #0x4
mov r0, #0x0
ldmia sp!, {r4-r7,lr}
bx lr
_020CC7AC:
cmp r5, #0x0
ldrlt r5, [r1, #0x0]
ldr r1, [r1, #0x10]
mov r0, #0xc
mla r6, r5, r0, r1
ldr r0, [r6, #0x4]
add r1, r7, #0x20
add r1, r1, #0x1f
mov r5, r0
cmp r0, #0x0
bic r7, r1, #0x1f
beq _020CC7F4
_020CC7DC:
ldr r1, [r5, #0x8]
cmp r7, r1
ble _020CC7F4
ldr r5, [r5, #0x4]
cmp r5, #0x0
bne _020CC7DC
_020CC7F4:
cmp r5, #0x0
bne _020CC814
mov r0, r4
bl OS_RestoreInterrupts
add sp, sp, #0x4
mov r0, #0x0
ldmia sp!, {r4-r7,lr}
bx lr
_020CC814:
ldr r1, [r5, #0x8]
sub r1, r1, r7
cmp r1, #0x40
bhs _020CC834
mov r1, r5
bl DLExtract
str r0, [r6, #0x4]
b _020CC86C
_020CC834:
str r7, [r5, #0x8]
add r2, r5, r7
str r1, [r2, #0x8]
ldr r0, [r5, #0x0]
str r0, [r5, r7]
ldr r0, [r5, #0x4]
str r0, [r2, #0x4]
ldr r0, [r2, #0x4]
cmp r0, #0x0
strne r2, [r0, #0x0]
ldr r0, [r2, #0x0]
cmp r0, #0x0
strne r2, [r0, #0x4]
streq r2, [r6, #0x4]
_020CC86C:
ldr r0, [r6, #0x8]
mov r1, r5
bl DLAddFront
str r0, [r6, #0x8]
mov r0, r4
bl OS_RestoreInterrupts
add r0, r5, #0x20
add sp, sp, #0x4
ldmia sp!, {r4-r7,lr}
bx lr
}
#else
void* OS_AllocFromHeap(OSArenaId id, OSHeapHandle heap, u32 size) {
OSHeapInfo* heapInfo;
HeapDesc* hd;
Cell* cell;
Cell* newCell;
long leftoverSize;
OSIntrMode enabled = OS_DisableInterrupts();
heapInfo = OSiHeapInfo[id];
if (!heapInfo) {
OS_RestoreInterrupts(enabled);
return NULL;
}
if (heap < 0) {
heap = heapInfo->currentHeap;
}
hd = &heapInfo->heapArray[heap];
size += HEADERSIZE;
size = OSi_ROUND(size, 32);
for (cell = hd->free; cell != NULL; cell = cell->next) {
if ((long)size <= cell->size) {
break;
}
}
if (cell == NULL) {
OS_RestoreInterrupts(enabled);
return NULL;
}
leftoverSize = cell->size - (long)size;
if (leftoverSize < MINOBJSIZE) {
hd->free = DLExtract(hd->free, cell);
} else {
cell->size = (long)size;
newCell = (Cell *) ((char *)cell + size);
newCell->size = leftoverSize;
newCell->prev = cell->prev;
newCell->next = cell->next;
if (newCell->next != NULL) {
newCell->next->prev = newCell;
}
if (newCell->prev != NULL) {
newCell->prev->next = newCell;
} else {
hd->free = newCell;
}
}
hd->allocated = DLAddFront(hd->allocated, cell);
OS_RestoreInterrupts(enabled);
return (void *)((char *)cell + HEADERSIZE);
}
#endif