pureikyubu/Docs/RE/OSAlloc.c
ogamespec c21147ccff Cumulative changes all around project, regarding Stage 1
Docs: New TODO moved to EMU, old renamed to old_todo
Docs: Old coding style is deprecated (old_style.txt)
Docs: Removed mention about CubeDocumented and fixed old emails
RE: boot.s, proved first asm line (lis instruction parameter)
RE: Added PAL and NTSC Boot and IPL IDA files
RE: Some work on NTSC IPL (identified many lib calls, including OS, GX)
RE: Added EXI Bootrom descrambler by segher
RE: GXInit
RE: Internal GX lib structures (GXPrivate.h)
RE: More details on lomem (OS versions)
RE: OSInit and OS.c
RE: OSAlloc (heap allocator)
RE: Very first code of Metrowerk runtime (__start.c)
Docs: Added copy of http://gcdev.narod.ru
Source\Utils: Command processor (Cmd.c)
Source\Utils: File wrapper
Source\Utils: Gekko disasm cleaned up and ported to plain C
Source\Utils: Double-linked lists
Source\Utils: Ported old Profiler code
Source\Utils: String utils
2015-09-04 19:45:10 +03:00

381 lines
8 KiB
C

// Dolphin OSAlloc
typedef struct _Cell
{
struct _Cell * prev;
struct _Cell * next;
int size;
HeapDesc * hd;
u32 requested; // Size of original unaligned data
} Cell;
typedef struct HeapDesc
{
u32 size;
Cell * free;
Cell * allocated;
u32 paddingBytes;
u32 headerBytes;
u32 payloadBytes;
} HeapDesc;
HeapDesc * HeapArray;
int NumHeaps;
void * ArenaStart;
void * ArenaEnd;
volatile OSHeapHandle __OSCurrHeap;
//
// Double-linked Lists
//
Cell * DLAddFront ( Cell * list, Cell * cell )
/*++
Add new cell to the head. Return new list address.
--*/
{
cell->next = list;
cell->prev = NULL;
if ( list ) list->prev = cell;
return cell;
}
Cell * DLLookup ( Cell * list, Cell * cell)
/*++
Check whenever cell is owned by the list.
--*/
{
while ( list )
{
if ( list == cell ) return list;
list = list->next;
}
return NULL;
}
Cell * DLExtract ( Cell * list, Cell * cell )
/*++
Delete cell, return new list address.
--*/
{
if ( cell->next )
cell->next->prev = cell->prev;
if ( cell->prev )
{
cell->prev->next = cell->next;
return list;
}
else return cell->next;
}
Cell * DLInsert (Cell * list, Cell * cell )
{
Cell * prev, next;
next = list;
prev = NULL;
while ( next && (next < cell) )
{
prev = next;
next = next->next;
}
cell->next = next;
cell->prev = prev;
if ( next )
{
next->prev = cell;
if ( (cell + cell->size) == next )
{
cell->size += next->size;
cell->next = next->next;
if ( cell->next ) cell->next->prev = cell;
}
}
if ( prev )
{
prev->next = cell;
if ( (prev + prev->size) == cell )
{
prev->size += cell->size;
prev->next = next;
if ( next ) next->prev = prev;
}
return list;
}
return cell;
}
BOOL DLOverlap ( Cell * list, void * start, void * end )
/*++
Check if list lies within specified range, or at least touch it by any cell.
--*/
{
Cell * cell;
cell = list;
while ( cell )
{
if ( start <= cell && cell < end ) return TRUE;
if ( start < (cell + cell->size) && (cell + cell->size) <= end ) return TRUE;
cell = cell->next;
}
return FALSE;
}
int DLSize (Cell * list)
/*++
Get list size (sum of all cell sizes)
--*/
{
int size = 0;
cell = list;
while ( cell )
{
size += cell->size;
cell = cell->next;
}
return size;
}
void * OSInitAlloc ( void * arenaStart,
void * arenaEnd,
int maxHeaps )
{
HeapDesc * Heap;
int n;
ASSERTMSG ( maxHeaps > 0, "OSInitAlloc(): invalid number of heaps." );
ASSERTMSG ( arenaStart < arenaEnd, "OSInitAlloc(): invalid range." );
ASSERTMSG ( ((arenaEnd - arenaStart) / sizeof(HeapDesc) ) >= maxHeaps, "OSInitAlloc(): too small range." );
HeapArray = arenaStart;
NumHeaps = maxHeaps;
//
// Initialize heap descriptors
//
for (n=0; n<NumHeaps; n++)
{
Heap = &HeapDesc[n];
Heap->size = -1;
Heap->allocated = NULL;
Heap->free = NULL;
Heap->payloadBytes = 0;
Heap->headerBytes = 0;
Heap->paddingBytes = 0;
}
__OSCurrHeap = -1;
ArenaStart = OSRoundUp32B ( &HeapArray[maxHeaps] );
ArenaEnd = OSRoundDown32B ( arenaEnd );
ASSERTMSG ( (ArenaEnd - ArenaStart) >= 0x40, "OSInitAlloc(): too small range." );
return ArenaStart;
}
void * OSAllocFromHeap ( OSHeapHandle heap, u32 size)
{
HeapDesc * hd;
Cell * cell;
Cell * newCell;
u32 leftoverSize;
u32 requested;
const int CellSizePadded = OSRoundUp32B( sizeof(Cell) );
ASSERTMSG ( HeapArray, "OSAllocFromHeap(): heap is not initialized." );
ASSERTMSG ( size > 0, "OSAllocFromHeap(): invalid size." );
ASSERTMSG ( heap >= 0 && heap < NumHeaps, "OSAllocFromHeap(): invalid heap handle." );
ASSERTMSG ( HeapArray[heap].size >= 0, "OSAllocFromHeap(): invalid heap handle." );
//
// Find free space in free list.
//
hd = &HeapArray[heap];
requested = OSRoundUp32B (size);
cell = hd->free;
while ( cell )
{
if ( cell->size >= requested ) break;
cell = cell->next;
}
if ( cell == NULL )
{
OSReport ( "OSAllocFromHeap: Warning- failed to allocate %d bytes\n", requested );
return NULL;
}
ASSERTMSG ( (cell & (CellSizePadded-1)) == 0, "OSAllocFromHeap(): heap is broken." );
ASSERTMSG ( cell->hd == NULL, "OSAllocFromHeap(): heap is broken." );
leftoverSize = cell->size - requested;
//
// Allocate new cell.
//
if ( leftoverSize >= 2 * CellSizePadded )
{
cell->size = requested;
newCell = cell + requested;
newCell->size = leftoverSize;
newCell->hd = NULL;
newCell->prev = cell->prev;
newCell->next = cell->next;
if ( newCell->next ) newCell->next->prev = newCell;
if ( newCell->prev == NULL )
{
if ( hd->free != cell )
OSHalt ( "OSAllocFromHeap(): heap is broken." );
hd->free = newCell;
}
else newCell->prev->next = newCell;
}
else hd->free = DLExtract ( hd->free, cell );
//
// Add allocated cell in allocated list.
//
hd->allocated = DLAddFront ( hd->allocated, cell );
cell->hd = hd;
cell->requested = size;
hd->headerBytes += CellSizePadded;
hd->paddingBytes += cell->size - (size + CellSizePadded );
hd->payloadBytes += size;
return cell + CellSizePadded;
}
void OSFreeToHeap ( OSHeapHandle heap, void * ptr )
{
HeapDesc * hd;
Cell * cell;
const int CellSizePadded = OSRoundUp32B( sizeof(Cell) );
ASSERTMSG ( HeapArray, "OSFreeToHeap(): heap is not initialized." );
ASSERTMSG ( ptr >= (ArenaStart + CellSizePadded) && ptr < ArenaEnd , "OSFreeToHeap(): invalid pointer." );
ASSERTMSG ( (ptr & (CellSizePadded-1)) == 0, "OSFreeToHeap(): invalid pointer." );
hd = &HeapArray[heap];
ASSERTMSG ( hd->size >= 0, "OSFreeToHeap(): invalid heap handle." );
cell = ptr - CellSizePadded;
ASSERTMSG ( cell->hd == hd, "OSFreeToHeap(): invalid pointer." );
ASSERTMSG ( DLLookup(hd->allocated, cell), "OSFreeToHeap(): invalid pointer." );
cell->hd = NULL;
hd->headerBytes -= CellSizePadded;
hd->paddingBytes -= (cell->size - (cell->requested + CellSizePadded));
hd->payloadBytes -= cell->requested;
hd->allocated = DLExtract ( hd->allocated, cell );
hd->free = DLInsert ( hd->free, cell );
}
void OSAddToHeap (OSHeapHandle heap, void *start, void *end )
{
HeapDesc *hd;
Cell *cell;
int i;
ASSERTMSG ( HeapArray, "OSAddToHeap(): heap is not initialized." );
ASSERTMSG ( heap >= 0 && heap < NumHeaps, "OSAddToHeap(): invalid heap handle." );
ASSERTMSG ( HeapArray[heap].size >= 0, "OSAllocFromHeap(): invalid heap handle." );
hd = &HeapArray[heap];
ASSERTMSG ( start < end, "OSAddToHeap(): invalid range." );
start = OSRoundUp32B (start);
end = OSRoundDown32B (end);
ASSERTMSG ( (end - start) >= 0x40, "OSAddToHeap(): too small range." );
ASSERTMSG ( start >= ArenaStart && end <= ArenaEnd, "OSAddToHeap(): invalid range." );
//
// Check if area crossing already existing heap.
//
for (i=0; i<NumHeaps; i++)
{
if ( HeapArray[i].size >= 0 )
{
if ( DLOverlap ( HeapArray[i].free, start, end) )
{
OSHalt ( "OSAddToHeap(): invalid range." );
}
if ( DLOverlap ( HeapArray[i].allocated, start, end) )
{
OSHalt ( "OSAddToHeap(): invalid range." );
}
}
}
//
// Add large single cell.
//
cell = (Cell *)start;
cell->size = end - start;
cell->hd = NULL;
hd->size += cell->size;
hd->free = DLInsert ( hd->free, cell );
}