//[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 #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; ilist[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; ilist[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; }