mirror of https://github.com/PCSX2/pcsx2.git
530 lines
14 KiB
C
530 lines
14 KiB
C
//[module] SYSMEM
|
|
//[processor] IOP
|
|
//[type] ELF-IRX
|
|
//[name] System_Memory_Manager
|
|
//[version] 0x101
|
|
//[memory map] 0x00001500(0x000015C3) in RAM
|
|
//[handlers] see fileio/80000003
|
|
//[entry point] sysmem_start, sysmem_stub(it is handeled specialy by loadcore)
|
|
//[made by] [RO]man (roman_ps2dev@hotmail.com) september 2002
|
|
|
|
#define min(a, b) ((a)<(b)?(a):(b))
|
|
#define max(a, b) ((a)>(b)?(a):(b))
|
|
|
|
#include <tamtypes.h>
|
|
|
|
#include "ksysmem.h"
|
|
#include "kloadcore.h"
|
|
#include "iopdebug.h"
|
|
|
|
#define EIGHTMEGSm256 (8*1024*1024-256) //0x007FFF00
|
|
#define ALIGN256 0xFFFFFF00
|
|
|
|
#define mALLOCATED(info) (info & 1)
|
|
#define mADDRESS(info) ((info >> 1) & 0x7FFF)
|
|
#define mSIZE(info) (info >> 17)
|
|
//[000000000000000 0 000000000000000 1]
|
|
//[ size of block |?|address of block|a]located
|
|
//upper 15bits are the size of block in 256bytes units [8MB addressability]
|
|
//unknown 1 bit
|
|
//15bits for address of block in 256bytes units [8MB addressability; 15+8 bits]
|
|
//the lower bit means that block is allocated or not (1/0)
|
|
|
|
struct allocELEM{ //sizeof()=8
|
|
struct allocELEM *next;
|
|
/* unsigned int size :15,
|
|
unknown :1, // info could be declared this way
|
|
addr :15,
|
|
allocated:1; */
|
|
unsigned int info; // here is stored data about
|
|
// an allocable memory chunk
|
|
};
|
|
|
|
#define smFIRST 0
|
|
#define smFIRSTF 2 //first one that can be freed
|
|
#define smCHECK 27
|
|
#define smLAST 30
|
|
#define smMAX (smLAST+1) //max number of elements = 31
|
|
|
|
struct allocTABLE{ //sizeof()=256=0x100
|
|
struct allocTABLE *next; //+00
|
|
struct allocELEM list[31]; //+04 8 * 31 = 248 = 0xF8;
|
|
int dummy;
|
|
};
|
|
|
|
char* (*_Kprintf)(unsigned int, ...);
|
|
unsigned int unk;
|
|
|
|
///////////////////////////////////////////////////////////////////////
|
|
unsigned int memsize;
|
|
|
|
void *_start(u32 iopmemsize);
|
|
void *sysmem_init_memory();
|
|
void sysmem_retonly();
|
|
unsigned int *sysmem_return_addr_of_memsize();
|
|
|
|
//////////////////////////////entrypoint///////////////////////////////
|
|
struct export sysmem_stub __attribute__((section(".text"))) = {
|
|
0x41C00000,
|
|
0,
|
|
VER(1, 1), // 1.1 => 0x101
|
|
0,
|
|
"sysmem",
|
|
(func)_start, // entrypoint
|
|
(func)sysmem_init_memory,
|
|
(func)sysmem_retonly,
|
|
(func)sysmem_return_addr_of_memsize,
|
|
(func)AllocSysMemory,
|
|
(func)FreeSysMemory,
|
|
(func)QueryMemSize,
|
|
(func)QueryMaxFreeMemSize,
|
|
(func)QueryTotalFreeMemSize,
|
|
(func)QueryBlockTopAddress,
|
|
(func)QueryBlockSize,
|
|
(func)sysmem_retonly,
|
|
(func)sysmem_retonly,
|
|
(func)sysmem_retonly,
|
|
(func)Kprintf,
|
|
(func)sysmem_call15_set_Kprintf,
|
|
0
|
|
};
|
|
|
|
struct allocTABLE *alloclist;
|
|
char _alloclist[0x200]; // temp buffer
|
|
//struct allocTABLE _alloclist; // has to be last!, also temp!
|
|
|
|
void Kputc(u8 c) {
|
|
*((u8*)0x1f80380c) = c;
|
|
}
|
|
|
|
void Kputs(u8 *s) {
|
|
while (*s != 0) {
|
|
Kputc(*s++);
|
|
}
|
|
}
|
|
|
|
void Kprintnum(unsigned int n)
|
|
{
|
|
char chars[16] = "0123456789abcdef";
|
|
int i = 0;
|
|
while(i < 8) {
|
|
Kputc(chars[n>>28]);
|
|
n <<= 4;
|
|
++i;
|
|
}
|
|
}
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////[OK]
|
|
void sysmem_retonly(){}
|
|
|
|
//////////////////////////////entrypoint///////////////////////////////[OK]
|
|
void *_start(u32 iopmemsize)
|
|
{
|
|
iopmemsize=min(EIGHTMEGSm256, iopmemsize);
|
|
|
|
alloclist = (struct allocTABLE*)(((u32)&_alloclist + 255) & 0xFFFFFF00); // round up
|
|
memsize = iopmemsize & 0xFFFFFF00;
|
|
|
|
//__printf("sysmem_start: %x, %x\n", memsize, ((u32)alloclist+sizeof(struct allocTABLE)));
|
|
//Kprintnum((int)alloclist); Kputs(" alloclist\n");
|
|
//Kprintnum((int)&alloclist); Kputs(" &alloclist\n");
|
|
|
|
if (memsize >= ((u32)alloclist+sizeof(struct allocTABLE))) //alloctable must fit memory
|
|
return sysmem_init_memory();
|
|
alloclist = NULL;
|
|
return NULL;
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////
|
|
extern void* _end;
|
|
void *sysmem_init_memory(){ //mark all mem as not allocated, available
|
|
unsigned int i;
|
|
struct allocELEM *p;
|
|
|
|
//__printf("system_init_memory\n");
|
|
|
|
if (alloclist == NULL) return NULL;
|
|
|
|
alloclist->next=NULL;
|
|
for (i=smFIRST; i<smMAX; i++){
|
|
alloclist->list[i].next=&alloclist->list[i+1];
|
|
alloclist->list[i].info=0;
|
|
}
|
|
alloclist->list[smLAST].next=NULL;
|
|
|
|
alloclist->list[smFIRST].info &= 0x0001FFFF;
|
|
alloclist->list[smFIRST].info |= (((memsize<0 ?
|
|
memsize+255:memsize) >> 8) << 17);
|
|
|
|
// _end ~= alloclist + sizeof(struct alocTABLE);
|
|
|
|
//this is not NULL! but the starting address of the first 0x1500 bytes allocated
|
|
if ( AllocSysMemory(ALLOC_FIRST, (int)alloclist, NULL)==0) {
|
|
if (alloclist==AllocSysMemory(ALLOC_FIRST, sizeof(struct allocTABLE)-4, NULL)){ //alloc allocated allocation table;-)
|
|
for (p=alloclist->list; p; p=p->next) {
|
|
if (!mALLOCATED(p->info)) {
|
|
return (void*)((mADDRESS(p->info))<<8);//next free block address
|
|
}
|
|
}
|
|
return NULL;
|
|
}
|
|
}
|
|
alloclist=NULL;
|
|
return NULL;
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////[OK]
|
|
unsigned int QueryMemSize(){
|
|
if (alloclist)
|
|
return memsize;//2*1024*1024-256=0x001FFF00
|
|
return 0;
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////[OK]
|
|
unsigned int QueryMaxFreeMemSize(){
|
|
unsigned int maxfree=0;
|
|
struct allocELEM *p;
|
|
|
|
if (alloclist)
|
|
for (p=alloclist->list; p; p=p->next)
|
|
if (!mALLOCATED(p->info))
|
|
maxfree = max(maxfree, mSIZE(p->info));
|
|
return maxfree<<8; // => 256bytes allocation units
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////[OK]
|
|
unsigned int QueryTotalFreeMemSize(){
|
|
unsigned int freesize=0;
|
|
struct allocELEM *p;
|
|
|
|
if (alloclist)
|
|
for (p=alloclist->list; p; p=p->next)
|
|
if (!mALLOCATED(p->info))
|
|
freesize+=mSIZE(p->info);
|
|
return freesize<<8; // => 256bytes allocation units
|
|
}
|
|
|
|
void *alloc(int flags, int size, void *mem);
|
|
void maintain();
|
|
///////////////////////////////////////////////////////////////////////[OK]
|
|
void *AllocSysMemory(int flags, int size, void *mem){
|
|
if (alloclist && (flags<3)){
|
|
void *r=alloc(flags, size, mem);
|
|
maintain();
|
|
//Kprintnum((int)r); Kputs("\n");
|
|
return (void*)r;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
int free(void *mem);
|
|
///////////////////////////////////////////////////////////////////////[OK]
|
|
int FreeSysMemory(void *mem){
|
|
struct allocTABLE *table;
|
|
int r;
|
|
|
|
for (table=alloclist; table; table=table->next) //must not be among
|
|
if (mem==table) //the allocation tables
|
|
return -1;
|
|
if (r=free(mem))
|
|
return r;
|
|
maintain();
|
|
return r; //r==0 ;-)
|
|
}
|
|
|
|
struct allocELEM *findblock(void *a);
|
|
///////////////////////////////////////////////////////////////////////[OK]
|
|
void *QueryBlockTopAddress(void *address){
|
|
struct allocELEM *p;
|
|
|
|
if (p=findblock(address))
|
|
return (void*)((mADDRESS(p->info) << 8) +
|
|
(mALLOCATED(p->info) ? USED : FREE));
|
|
return (void*)-1;
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////[OK]
|
|
int QueryBlockSize(void *address){
|
|
struct allocELEM *p;
|
|
|
|
if (p=findblock(address))
|
|
return (mSIZE(p->info) << 8) |
|
|
(mALLOCATED(p->info) ? USED : FREE);
|
|
return -1;
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////[OK]
|
|
unsigned int *sysmem_return_addr_of_memsize(){
|
|
return &memsize;
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////
|
|
void *alloc(int flags, int size, void *mem){
|
|
struct allocELEM *a, *last, *k;
|
|
unsigned int bsize, //block size in 256bytes units
|
|
baddress, //block address in 256bytes units
|
|
i, tmp;
|
|
void *address;
|
|
|
|
bsize = (size+255) >> 8; // round to upper
|
|
if (bsize==0) return NULL;
|
|
|
|
switch (flags){
|
|
case ALLOC_FIRST:
|
|
for (a = alloclist->list; a; a=a->next)
|
|
if ((!mALLOCATED(a->info)))
|
|
if (mSIZE(a->info) >= bsize)
|
|
break;
|
|
if (a==NULL) return NULL;
|
|
|
|
if (mSIZE(a->info) == bsize){
|
|
a->info|=1; //alloc it
|
|
return (void*)(mADDRESS(a->info) << 8); //all done, how quick!
|
|
}
|
|
|
|
address = (void*)(mADDRESS(a->info) << 8);
|
|
i = a->info;
|
|
|
|
a->info=((a->info | 1) & 0x1FFFF) | //alloc block
|
|
(bsize << 17); //of wanted size
|
|
|
|
i = (i & 0xFFFF0001) | (((mADDRESS(i) + bsize) & 0x7FFF) << 1);
|
|
i = (i & 0x1FFFF) | ((mSIZE(i) - bsize) << 17);
|
|
|
|
a=a->next;
|
|
while (mSIZE(i)>0){
|
|
tmp=a->info;
|
|
a->info=i;
|
|
i=tmp;
|
|
a = a->next;
|
|
}
|
|
return address;
|
|
|
|
case ALLOC_LAST:
|
|
last=NULL;
|
|
for (a = alloclist->list; a; a=a->next)
|
|
if ((!mALLOCATED(a->info)))
|
|
if (mSIZE(a->info) >= bsize)
|
|
last=a; //use last one suitable
|
|
a = last;
|
|
if (a==0) return NULL;
|
|
|
|
if (mSIZE(a->info) == bsize){
|
|
a->info|=1; //alloc it
|
|
return (void*)(mADDRESS(a->info) << 8);
|
|
}
|
|
|
|
a->info = (a->info & 0x0001FFFF) |
|
|
((mSIZE(a->info) - bsize) << 17); //put rest of block
|
|
|
|
i = (((i & 0xFFFF0001)//this line has no use; this is stupid
|
|
| ((mADDRESS(a->info) + mSIZE(a->info)) & 0x7FFF) << 1) //calculate address of block to use
|
|
& 0x0001FFFF) //keep only address (and alloc' state)
|
|
| (bsize << 17) //put size
|
|
| 1; //mark as allocated
|
|
a=a->next;
|
|
|
|
address = (void*)(mADDRESS(i) << 8); //address in bytes
|
|
while (mSIZE(i)>0){
|
|
tmp=a->info;
|
|
a->info=i;
|
|
i=tmp;
|
|
a = a->next;
|
|
}
|
|
return address;
|
|
|
|
case ALLOC_LATER:
|
|
if ((unsigned int)mem & 0xFF) return NULL;
|
|
baddress = (unsigned int)mem >> 8; //addr in 256bytes units
|
|
for (a = alloclist->list; a ; a=a->next){
|
|
if (baddress < mADDRESS(a->info)) return NULL;//cannot realloc
|
|
if ((!mALLOCATED(a->info)) &&
|
|
(mSIZE(a->info) + mADDRESS(a->info) >= baddress + bsize))
|
|
break;
|
|
}
|
|
if (a==0) return NULL;
|
|
|
|
if (mADDRESS(a->info) < baddress){
|
|
tmp = mADDRESS(a->info) + mSIZE(a->info) - baddress;
|
|
a->info= (a->info & 0x1FFFF) |
|
|
((mSIZE(a->info) - tmp) << 17);
|
|
|
|
i =(((i & 0xFFFF0001) | //stupid compiler
|
|
((mADDRESS(a->info) + mSIZE(a->info)) & 0x7FFF) << 1)
|
|
& 0x1FFFE)
|
|
| (tmp << 17);
|
|
|
|
k = a = a->next;
|
|
while (mSIZE(i)>0){
|
|
tmp=a->info;
|
|
a->info=i;
|
|
i=tmp;
|
|
a=a->next;
|
|
}
|
|
a = k;
|
|
}
|
|
|
|
if (mSIZE(a->info)==bsize){
|
|
a->info|=1; //alloc it
|
|
return (void*)(mADDRESS(a->info) << 8);
|
|
}
|
|
|
|
address = (void*)(mADDRESS(a->info) << 8);
|
|
i = a->info;
|
|
|
|
a->info=((a->info | 1) & 0x1FFFF) | //alloc block
|
|
(bsize << 17);
|
|
|
|
i = (i & 0xFFFF0001) | (((mADDRESS(i) + bsize) & 0x7FFF) << 1);
|
|
i = (i & 0x1FFFF) | ((mSIZE(i) - bsize) << 17);
|
|
|
|
a=a->next;
|
|
while (mSIZE(i)>0){
|
|
tmp=a->info;
|
|
a->info=i;
|
|
i=tmp;
|
|
a = a->next;
|
|
}
|
|
return address;
|
|
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
/***original while (mSIZE(i)>0){
|
|
x=a->next; //stupid, n'est ce pas?
|
|
tmp=a->info;
|
|
a->next=z; //stupid, n'est ce pas?
|
|
a->info=i;
|
|
a->next=x; //stupid, n'est ce pas?
|
|
z=x; //stupid, n'est ce pas?
|
|
i=tmp;
|
|
a = a->next;
|
|
} ***/
|
|
|
|
///////////////////////////////////////////////////////////////////////[OK]
|
|
int free(void *mem){
|
|
int skip; // counter (0,1,2) of elements to remove
|
|
struct allocELEM *a, // an element
|
|
*p, // prev
|
|
*n; // next
|
|
|
|
if ((unsigned int)mem & 0xFF) return -1; // only 256byte multiple
|
|
|
|
for (a=&alloclist->list[smFIRSTF], p=NULL; a; a=a->next){
|
|
if ((mSIZE(a->info) && (mADDRESS(a->info)==
|
|
((unsigned int)mem >> 8)))) // convert to 256byte units
|
|
break;
|
|
p=a;
|
|
}
|
|
|
|
if (a==NULL) return -1; //block not found
|
|
|
|
if (!mALLOCATED(a->info))return -1; //cannot free a freed block
|
|
|
|
n=NULL;
|
|
skip=0;
|
|
|
|
a->info&=0xFFFFFFFE; //free block
|
|
|
|
if ((a->next) && (!mALLOCATED(a->next->info))){//bind with next free block
|
|
n = a->next;
|
|
skip = 1;
|
|
a->info = (a->info & 0x1FFFE) |
|
|
((mSIZE(a->info) + mSIZE(a->next->info)) << 17);
|
|
}
|
|
|
|
if (p && (!mALLOCATED(p->info))){ //bind with previous free block
|
|
n=a;
|
|
skip++; // or skip=2;
|
|
p->info=(p->info & 0x1FFFF) |
|
|
((mSIZE(p->info) + mSIZE(a->info)) << 17);
|
|
}
|
|
|
|
if (skip){
|
|
a=n;
|
|
while (--skip!=-1)
|
|
a=a->next;
|
|
while (a){
|
|
n->info=a->info;
|
|
a=a->next;
|
|
n=n->next;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
/***original while (a){
|
|
t1=n->next;
|
|
t2=a->next;
|
|
t3=a->info;
|
|
n->next=t2; //stupid compiler, see above
|
|
n->info=t3;
|
|
n->next=t1;
|
|
a=a->next;
|
|
n=t1;
|
|
}***/
|
|
|
|
///////////////////////////////////////////////////////////////////////[OK]
|
|
void maintain(){
|
|
struct allocTABLE *table, *new;
|
|
int i;
|
|
|
|
for (table=alloclist; table->next; table = table->next) //+0x00
|
|
; //move to last non-NULL
|
|
if (mSIZE(table->list[smCHECK].info)>0) //+0xE0 //27 (i.e.28th)
|
|
// a new table is needed; alloc it
|
|
if (new=(struct allocTABLE*)alloc(0, sizeof(struct allocTABLE), 0)){
|
|
table->next=new; // link it
|
|
table->list[smLAST].next=&new->list[smFIRST];// link it's table elements
|
|
table=table->next; // move to it
|
|
table->next=NULL; // mark as end of tables
|
|
for (i=0; i<smMAX; i++){ // init table elements
|
|
table->list[i].next=&table->list[i+1];
|
|
table->list[i].info=0;
|
|
}
|
|
table->list[smLAST].next=NULL;
|
|
}
|
|
|
|
table=alloclist;
|
|
if (table->next){
|
|
while (table->next->next)
|
|
table=table->next;
|
|
if (table->next) //redundant check
|
|
if (mSIZE(table->list[smCHECK].info)==0){
|
|
struct allocTABLE *t=table->next;
|
|
table->list[smLAST].next=NULL;
|
|
table->next =NULL;
|
|
free(t);
|
|
}
|
|
}
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////[OK]
|
|
struct allocELEM *findblock(void *a){ // it finds the block for a given address
|
|
struct allocELEM *p;
|
|
for (p = alloclist->list; p; p=p->next)
|
|
if (((unsigned int)a >= (mADDRESS(p->info) << 8)) &&
|
|
((unsigned int)a < (mADDRESS(p->info) << 8) + mSIZE(p->info)))
|
|
break;
|
|
return p;
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////[OK]
|
|
char *Kprintf(const char *format,...){
|
|
if (_Kprintf)
|
|
return _Kprintf(unk, format, (void*)(format+4));//it is not accurate since mips
|
|
// have the 2nd, 3rd & 4th parameters
|
|
// in regs and not in stack,
|
|
// but you got the idea
|
|
return NULL;
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////[OK]
|
|
void sysmem_call15_set_Kprintf(char* (*newKprintf)(unsigned int, const char*, ...), unsigned int newunk){
|
|
if (_Kprintf && newKprintf)
|
|
newKprintf(newunk, _Kprintf(0));
|
|
unk = newunk;
|
|
_Kprintf = newKprintf;
|
|
}
|