//[module] THREADMAN //[processor] IOP //[type] ELF-IRX //[name] Multi_Thread_Manager //[version] 0x101 //[memory map] 0xBF802070 //[handlers] - //[entry point] start, thbase_stub, thevent_stub, thsemap_stub, // thmsgbx_stub, thfpool_stub, thvpool_stub, thrdman_stub //[made by] [RO]man (roman_ps2dev@hotmail.com) november 2002 - january 2003 #include "err.h" #include "ksysmem.h" #include "kloadcore.h" #include "kintrman.h" #include "kstdio.h" #include "ksysclib.h" #include "ktimrman.h" #include "kheaplib.h" #include "iopdebug.h" #include "kthbase.h" int debug=1; #define _dprintf(fmt, args...) \ if (debug > 0) __printf("threadman:" fmt, ## args) int _start(); void _retonly() {} struct export thbase_stub={ 0x41C00000, 0, VER(1, 1), // 1.1 => 0x101 0, "thbase", (func)_start, // entrypoint (func)_retonly, (func)_retonly, (func)_retonly, (func)_retonly, (func)_retonly, (func)_retonly, (func)_retonly, (func)_retonly, // 0x08 (func)_retonly, (func)_retonly, (func)_retonly, (func)_retonly, (func)_retonly, (func)_retonly, (func)_retonly, (func)_retonly, // 0x10 (func)_retonly, (func)_retonly, (func)_retonly, (func)_retonly, (func)_retonly, (func)_retonly, (func)_retonly, (func)_retonly, // 0x18 (func)_retonly, (func)_retonly, (func)_retonly, (func)_retonly, (func)_retonly, (func)_retonly, (func)_retonly, (func)_retonly, // 0x20 (func)_retonly, (func)_retonly, (func)_retonly, (func)_retonly, (func)_retonly, (func)_retonly, (func)_retonly, (func)_retonly, // 0x28 (func)_retonly, 0 }; struct export thevent_stub={ 0x41C00000, 0, VER(1, 1), // 1.1 => 0x101 0, "thevent", (func)_start, // entrypoint (func)_retonly, (func)_retonly, (func)_retonly, (func)_retonly, (func)_retonly, (func)_retonly, (func)_retonly, (func)_retonly, // 0x08 (func)_retonly, (func)_retonly, (func)_retonly, (func)_retonly, (func)_retonly, (func)_retonly, 0 }; struct export thsemap_stub={ 0x41C00000, 0, VER(1, 1), // 1.1 => 0x101 0, "thsemap", (func)_start, // entrypoint (func)_retonly, (func)_retonly, (func)_retonly, (func)_retonly, (func)_retonly, (func)_retonly, (func)_retonly, (func)_retonly, // 0x08 (func)_retonly, (func)_retonly, (func)_retonly, (func)_retonly, 0 }; int _start() { int x; _dprintf("_start\n"); // if (RegisterNonAutoLinkEntries(&thrdman_stub)) return 1; if (RegisterLibraryEntries(&thbase_stub)) return 1; CpuSuspendIntr(&x); RegisterLibraryEntries(&thevent_stub); RegisterLibraryEntries(&thsemap_stub); // RegisterLibraryEntries(&thmsgbx_stub); // RegisterLibraryEntries(&thfpool_stub); // RegisterLibraryEntries(&thvpool_stub); CpuEnableIntr(); } #if 0 unsigned int ready; unsigned int _263; unsigned int _14; /////////////////////////////////////////////////////////////////////// unsigned int *threadman_callx(){ return &ready; } /////////////////////////////////////////////////////////////////////// int thbase_start(int argc, char* argv[]){ int x; if (RegisterNonAutoLinkEntries(&thrdman_stub)) return 1; if (RegisterLibraryEntries(&thbase_stub)) return 1; CpuSuspendIntr(&x); RegisterLibraryEntries(&thevent_stub); RegisterLibraryEntries(&thsemap_stub); RegisterLibraryEntries(&thmsgbx_stub); RegisterLibraryEntries(&thfpool_stub); RegisterLibraryEntries(&thvpool_stub); memset(&ready, 0, 1220); //305 x 4 => zero all bss _unk3=8; _2=NULL; LL_reset(&a); LL_reset(&b); LL_reset(&c); LL_reset(&d); LL_reset(&e); LL_reset(&f); LL_reset(&g); LL_reset(&h); LL_reset(&i); LL_reset(&threads_list); for (j=0; j<128; j++) LL_reset(&prio_lists[j]); hp=CreateHeap(0x800, 1); //s3=&hp th=allocheap(0x7F01, sizeof(struct TCB)); th->id=++ids;//short th->thp_stackSize=512; th->stack=AllocSysMemory(ALLOC_LAST, 512, 0); th->prio=th->thp_priority=127;//LOWEST_PRIORITY+1 th->thp_attr=TH_C; th->status=THS_READY; th->gp=gp; th->thp_entry=infinite_call; th->area=th->stack + ((th->thp_stackSize >> 2) << 2) - 0xB8; memset(th->area, 0, 0xB8); th->area->field_00=0xFFFFFFFE; th->area->H78=th->area->H74==&th->area->regs; th->area->ExitThread=ExitThread; th->area->gp=th->gp; th->area->attr=(th->attr & TH_COP) | 0x404; th->area->attr|=th->attr & TH_UMODE; th->area->entry=th->thp_entry; th->area->ei=1; _2.next=th; _2.prev=th; enqueue(th); th=allocheap(0x7F01, sizeof(struct TCB)); th->id=++ids;//short th->thp_stackSize=QueryBlockSize(&j); th->stack=QueryBlockTopAddress(&j); th->thp_priority=8; //MODULE_INIT_PRIORITY th->prio=1; //HIGHEST_PRIORITY th->thp_attr=0x2000000; th->status=THS_RUN; th->gp=gp; th->next_2=_2.next; _2.next=th; ready.prev=ready.next=th; th->next=NULL; th->prev=NULL; SetCtxSwitchHandler(handler1_switchcontexts); SetCtxSwitchReqHandler(handler2_morethan1ready); sub_50A0(); efp.attr=2; efp.initPattern=0; efp.option=0; systemStatusFlag=CreateEventFlag(&efp); if (v0=QueryBootMode(4)) SetEventFlag(systemStatusFlag, 1<<(v0->H0 & 3));//H0 short loadcore_call20_registerFunc(&lc20_2, 2, 0); loadcore_call20_registerFunc(&lc20_3, 3, 0); CpuEnableIntr(); return 0; } /////////////////////////////////////////////////////////////////////// int lc20_2(){ CpuEnableIntr(); return 0; } /////////////////////////////////////////////////////////////////////// int lc20_3(int a){ _dprintf("%s\n", __FUNCTION__); CpuEnableIntr(); ChangeThreadPriority(0, 126);//LOWEST_PRIORIT if (a->H0 == 0) { for (;;) { DelayThread(1000000); //never exit } } return 0; } /////////////////////////////////////////////////////////////////////// void infinite_call(){ infinite_call(); } /////////////////////////////////////////////////////////////////////// void syscall_32(){ li $v0, 0x20 syscall #0 } /////////////////////////////////////////////////////////////////////// void enqueue(struct TCB *th){ flags[th->prio>>5] |= 1 << (th->prio & 0x1F); LL_add_before(&prio_lists[th->prio], th); } ///////////////////////////////////////////////////////////////////////clone? void enqueue2(struct TCB *th){ flags[th->prio>>5] |= 1 << (th->prio & 0x1F); LL_add_before(&prio_lists[th->prio], th); } /////////////////////////////////////////////////////////////////////// void unqueue(ll, prio){ if (LL_0_1_elements(ll) flags[prio>>5] &= ~(1 << (prio & 0x1F)) LL_remove(ll); } /////////////////////////////////////////////////////////////////////// int run(struct TCB *th, int x){ if (th->prio >= ready.next->prio){ th->status=THS_READY; enqueue(th); CpuResumeIntr(x); return KE_OK; }else{ ready.next->status=THS_READY; enqueue2(ready.next); th->status=THS_RUN; ready->prev=th; return syscall_32(0, 0, x, 0); } } /////////////////////////////////////////////////////////////////////// int getHighestUsed(){ int i; for (i=0; i<4; i++) if (flags[i]) return (i<<5)+getHighestUsed_32(flags[i]); return 128; //LOWEST_PRIORITY+2 } /////////////////////////////////////////////////////////////////////// void switch(){ int hp; ready.prev=ready.next; if (ready.next->status != THS_RUN){ if (unk3 & 4) Kprintf(" not THS_RUN "); hp=getHighestUsed(); if (hp<128){ if (unk3 & 4) Kprintf(" readyq = %x, newrun = %x:%d, prio = %d", &prio_lists[hp], prio_lists[hp].next, prio_lists[hp].next->id, hp); unqueue(prio_lists[hp].next, hp); prio_lists[hp].next->status=THS_RUN; ready.prev=prio_lists[hp].next; }else Kprintf("Panic: not found executable Thread\n"); }else if ((hp=getHighestUsed())<128){ if (unk3 & 4) Kprintf(" THS_RUN cp=%d : hp=%d ", ready.next->prio, hp); if (hpprio){ if (unk3 & 4) Kprintf(" readyq = %x, newrun = %x:%d, prio = %d", &prio_list[hp], prio_list[hp].next, prio_list[hp].next->id, hp); unqueue(prio_list[hp].next, hp); prio_list[hp].next->status=ready.next->status; ready.prev=prio_lists[hp].next; ready.next->status=THS_READY; enqueue2(ready.next); } }else Kprintf("Panic: not found ready Thread\n"); if (unk3 & 4) Kprintf("\n"); } /////////////////////////////////////////////////////////////////////// void stack_overflow(struct TCB *th){ register ImageInfo ii; register char *name; Kprintf("\nThread (thid=%x, #%d) stack overflow\n Stack = %x, Stack size = %x, SP=%x\n", (th<<5) | ((th->id & 0x3F) << 1) | 1, th->id & 0xFFFF, th->stack, th->thp_stackSize, th->area); if ((ii=loadcore_call24_findImageInfo(th->thp_entry)) && (name=ii->H04)) Kprintf(" Module Name = %s\n", name); __asm break #0x400 ); /////////////////////////////////////////////////////////////////////// struct TCB *handler1_switchcontexts(struct AREA *area){ s0=&unk4; unk4++; if (unk3 & 3){ if (1==unk3 & 3) Kprintf("[%3d->", ready.next->id); if (2==unk3 & 3) Kprintf("switch_context(%x:%x,pc=%x,ei=%x =>%x:%d)\n", area, area->field_00, area->entry, area->ei, ready.next, ready.next->id); } ready.next->area=area; if (area < ready.next->stack) stack_overflow(ready.next); if (ready.prev->next==NULL) switch(); if (ready.prev != ready.next){ s0=GetTimerCounter(timid); ready.next->field_30=moveregs(0, s0-www.prev, ready.next->field_30); www.prev=s0; } if (unk3 & 3){ if (unk3 & 3 == 1) Kprintf("%3d]", ready.prev->id); if (unk3 & 3 == 2) Kprintf(" switch_context --> %x:%x,pc=%x,ei=%x =>%x:%d\n" ready.prev->area, ready.prev->area->field_00, ready.prev->area->entry, ready.prev->area->ei, ready.prev, ready.prev->id); } if (unk3 & 0x20){ 0xBF802070=~(1 << ((ready.prev->id-1) & 7)); } return ready.prev; } /////////////////////////////////////////////////////////////////////// int handler2_morethan1ready(){ return (0 < (ready.prev^ready.next)); //return (ready.prev!=ready.next); } /////////////////////////////////////////////////////////////////////// void queue_on_prio(struct TCB *th, void *fld, int prio){ register struct TCB *p; LL_remove(th); for (p=fld->H14; p !=&fld->H14 && prio>=p->prio; p=p->next); LL_add_before(p, th); } ///////////////////////////////////////////////////////////////////////[04] int CreateThread(struct ThreadParam *param){ int x; register struct TCB *th; if (QueryIntrContext()) return KE_ILLEGAL_CONTEXT; if (param->attr & 0x1CFFFFF7) return KE_ILLEGAL_ATTR; if (param->initPriority-1>=126) return KE_ILLEGAL_PRIORITY; if (param->entry & 3) return KE_ILLEGAL_ENTRY; if (param->stackSize<0x130) return KE_ILLEGAL_STACK_SIZE; CpuSuspendIntr(&x); if (th=allocheap(0x7F01, sizeof(struct TCB))){ //0x50 param->stackSize = (param->stackSize+0xFF) & 0xFFFFFF00; stack=AllocSysMemory(ALLOC_LAST, param->stackSize, NULL); if (!stack) freeheap(th); } if (!th || !stack){ CpuResumeIntr(x); return KE_NO_MEMORY; } th->id=++ids; th->thp_entry=param->entry; th->stack=stack; th->thp_stackSize; th->thp_priority=param->initPriority; th->thp_attr=attr; th->status=THS_DORMANT; th->thp_option=param->option; th->gp=$gp; th->next_2=&_2; _2.next=th; LL_add_before(threads_list, th); if (!(th->thp_attr & TH_NO_FILLSTACK)) memset(th->stack, 0xFF, th->thp_stackSize-48); CpuResumeIntr(x); return ((int)th<<5) | ((th->id & 0x3F) << 1) | 1; } ///////////////////////////////////////////////////////////////////////[05] int DeleteThread(int thid){ int x; register struct TCB *th, *p; if (QueryIntrContext()) return KE_ILLEGAL_CONTEXT; if (thid==0) return KE_ILLEGAL_THID; CpuSuspendIntr(&x); th=(struct TCB *)(thid>>7<<2); if ((th->_7F01 != 0x7F01) || (((thid>>1) & 0x3F) != (th->id & 0x3F)) || (_2.prev == th)){ CpuResumeIntr(x); return KE_UNKNOWN_THID; } if (th->status != THS_DORMANT){ CpuResumeIntr(x); return KE_NOT_DORMANT; } FreeSysMemory(th->stack); LL_remove(th); if (_2.next==th) _2.next=th->next_2; else for (p=_2.next; p->next_2; p=p->next_2) if (p->next_2==th){ p->next_2=th->next_2; break; } freeheap(th); CpuResumeIntr(x); return KE_OK; } /////////////////////////////////////////////////////////////////////// int startThread(struct TCB *th,int x){ th->field_1C=0; th->field_20=0; th->field_1E=0; th->prio=thp_priority; th->area->field_00=0xFFFFFFFE; th->area->field_78=th->area->field_74=&th->area->regs; th->area->ExitThread=ExitThread; th->area->gp=th->gp; th->area->attr=(th->attr & TH_COP) | 0x404; th->area->attr|=th->attr & TH_UMODE; th->area->entry->th->thp_entry; th->ei=1; LL_remove(th); return run(th, x); } ///////////////////////////////////////////////////////////////////////[06] int StartThread(int thid,u_long arg){ int x; register struct TCB *th, *p; if (QueryIntrContext()) return KE_ILLEGAL_CONTEXT; if (thid==0) return KE_ILLEGAL_THID; CpuSuspendIntr(&x); th=(struct TCB *)(thid>>7<<2); if ((th->_7F01 != 0x7F01) || (((thid>>1) & 0x3F) != (th->id & 0x3F))){ CpuResumeIntr(x); return KE_UNKNOWN_THID; } if (th->status != THS_DORMANT){ CpuResumeIntr(x); return KE_NOT_DORMANT; } th->area = th->stack + ((th->thp_stackSize >> 2) << 2) - 0xB8; memset(th->area, 0, 0xB8); th->area->arg=arg; return startThread(th, x); } ///////////////////////////////////////////////////////////////////////[07] int StartThreadArgs(int thid,int args,void *argp){ int x; register struct TCB *th, *p; register void *_argp; if (QueryIntrContext()) return KE_ILLEGAL_CONTEXT; if (thid==0) return KE_ILLEGAL_THID; CpuSuspendIntr(&x); th=(struct TCB *)(thid>>7<<2); if ((th->_7F01 != 0x7F01) || (((thid>>1) & 0x3F) != (th->id & 0x3F))){ CpuResumeIntr(x); return KE_UNKNOWN_THID; } if (th->status != THS_DORMANT){ CpuResumeIntr(x); return KE_NOT_DORMANT; } _argp=th->stack + ((th->thp_stackSize >> 2) - ((args+3) >> 2)) << 2 if (args>0 && argp) memcpy(_argp, argp, args); memset(th->area, 0, 0xB8); //BUG: these instructions should be switched! th->area = th->stack + ((th->thp_stackSize >> 2) << 2) - 0xB8; th->area->arg =args; th->area->argp=_argp; return startThread(th, x); } ///////////////////////////////////////////////////////////////////////[08] int ExitThread(){ th=ready->next; if (QueryIntrContext()) return KE_ILLEGAL_CONTEXT CpuSuspendIntr(&x); th->status=THS_DORMANT; LL_add_before(&threads_list, th); a0=0; do{ ready.prev=0; syscall_32(0, 0, x, 0); Kprintf("panic ! Thread DORMANT !\n"); __asm break #0x400 while(1); } ///////////////////////////////////////////////////////////////////////[09] int ExitDeleteThread(){ return KE_ERROR; } ///////////////////////////////////////////////////////////////////////[10] int TerminateThread(int thid){ int x; register struct TCB *th, *p; if (QueryIntrContext()) return KE_ILLEGAL_CONTEXT; if (thid==0) return KE_ILLEGAL_THID; CpuSuspendIntr(&x); th=(struct TCB *)(thid>>7<<2); if (ready.next==th){ CpuResumeIntr(x); return KE_ILLEGAL_THID; } if ((th->_7F01 != 0x7F01) || (((thid>>1) & 0x3F) != (th->id & 0x3F))){ CpuResumeIntr(x); return KE_UNKNOWN_THID; } if (th->status == THS_DORMANT){ CpuResumeIntr(x); return KE_DORMANT; } LL_remove(th); if (th->status==THS_WAIT) if (th->field_1C==2) CancelAlarm(alarmhandler, th); else if (th->field_1C>=2) && (th->field_1C<8) th->field_20->H10--; th->status=THS_DORMANT; LL_add_before(&threads_list, th); CpuResumeIntr(x); return KE_OK; } /////////////////////////////////////////////////////////////////////// void LL_add_before(struct ll *list, struct ll *new){ new->next=list; new->prev=list->prev; list->prev=new; new->prev->next=new; } ///////////////////////////////////////////////////////////////////////:) int getHighestUsed_32(int flags_32){ v=-4; do{ i=flags_32<<28; flags_32>>=4; v+=4; }while(i==0); return v + ((0x1020103 >> ((i>>26) & 0x1C)) & 0xF); } #endif