void testCheckStackLayout(const char *title, int argSize, u32 attr) { char argLengthTemp[0x1000]; memset(argLengthTemp, 0xAB, sizeof(argLengthTemp)); // First create the thread to wipe the stack area, that way we can see what it'd look like clean. SceUID stackCheckThread = sceKernelCreateThread("stackCheck", &stackCheckFunc, 0x10, 0x1000, attr, NULL); stackCheckInfo.size = sizeof(stackCheckInfo); sceKernelReferThreadStatus(stackCheckThread, &stackCheckInfo); sceKernelTerminateDeleteThread(stackCheckThread); memset(stackCheckInfo.stack, 0xCC, stackCheckInfo.stackSize); stackCheckName = title; stackCheckThread = sceKernelCreateThread("stackCheck", &stackCheckFunc, 0x10, 0x1000, attr, NULL); sceKernelStartThread(stackCheckThread, argSize, argLengthTemp); sceKernelWaitThreadEnd(stackCheckThread, NULL); u32 *stack = (u32 *) stackCheckInfo.stack; stack[1] = 0xFF1337FF; sceKernelTerminateDeleteThread(stackCheckThread); if (stack[1] != 0xFF1337FF) { schedf(" %s: WARNING: stack cleared to something after delete: %08x.\n", stackCheckName, stack[1]); } checkpoint("%s", title); }
int clear_thread(SceSize args, void *argp) { int result; u32 outBits; SceKernelThreadInfo info; info.size = sizeof(SceKernelThreadInfo); sceKernelReferThreadStatus (0, &info); printf("thread '%-12s' sp %p pattern %08x START\n", info.name, info.stack, CLEAR_PATTERN); while(!done) { // 0x00FF00FF initPattern // 0x000000FF should work - ok // 0x00000FF0 should fail - ok // 0x0000FF00 should fail - ok outBits = 0xbaadc0de; result = sceKernelWaitEventFlag(evid, CLEAR_PATTERN, PSP_EVENT_WAITCLEAR, &outBits, 0); printf("thread '%-12s' result %08x outBits %08x\n", info.name, result, (int)outBits); sceKernelSleepThreadCB(); } return 0; }
int or_thread(SceSize args, void *argp) { int result; u32 outBits; SceKernelThreadInfo info; info.size = sizeof(SceKernelThreadInfo); sceKernelReferThreadStatus (0, &info); printf("thread '%-12s' sp %p pattern %08x START\n", info.name, info.stack, OR_PATTERN); while(!done) { // 0x00FF00FF initPattern // 0x000000FF should work - ok // 0x00000FF0 should work - ok // 0x0000FF00 should fail - ok outBits = 0xbaadc0de; volatile SceUInt timeout = 1000*1000*5; //result = sceKernelWaitEventFlag(evid, OR_PATTERN, PSP_EVENT_WAITOR, &outBits, &timeout); result = sceKernelWaitEventFlag(evid, OR_PATTERN, PSP_EVENT_WAITOR, &outBits, 0); printf("thread '%-12s' result %08x outBits %08x\n", info.name, result, (int)outBits); //if (timeout) timeout = *(int*)timeout; printf("timeout %d/%08x\n", (int)timeout, (int)timeout); sceKernelSleepThreadCB(); } return 0; }
int control_module_threads(SceUID module_id, int pause) { // get an array of all threads int thread_count; if (sceKernelGetThreadmanIdList(SCE_KERNEL_TMID_Thread, NULL, 0, &thread_count) < 0) return 0; if (thread_count < 1) return 0; SceUID thread_id[thread_count]; if (sceKernelGetThreadmanIdList(SCE_KERNEL_TMID_Thread, thread_id, thread_count, NULL) < 0) return 0; int i; SceModule* module; SceKernelThreadInfo thread_info; thread_info.size = sizeof(SceKernelThreadInfo); for (i = 0; i < thread_count; i++) { // determine if a thread is from the game if (sceKernelReferThreadStatus(thread_id[i], &thread_info)) continue; module = sceKernelFindModuleByAddress((unsigned int) thread_info.entry); if (module && module->modid == module_id) { // pause or resume the thread if (pause) sceKernelSuspendThread(thread_id[i]); else sceKernelResumeThread(thread_id[i]); } } return 1; }
int threadCtrlSuspend() { if (threadCtrlState() == THREAD_CTRL_STATE_SUSPEND) { return 1; } int i, n; SceUID this_thid; SceKernelThreadInfo thinfo; this_thid = sceKernelGetThreadId(); sceKernelGetThreadmanIdList(SCE_KERNEL_TMID_Thread, current_thid, MAX_THREAD, ¤t_count); for (i = 0;i < current_count;i++) { memset(&thinfo, 0, sizeof(SceKernelThreadInfo)); thinfo.size = sizeof(SceKernelThreadInfo); sceKernelReferThreadStatus(current_thid[i], &thinfo); if (thinfo.status & PSP_THREAD_SUSPEND || current_thid[i] == this_thid) { current_thid[i] = -1; continue; } for (n = 0;n < first_count;n++) { if (current_thid[i] == first_thid[n]) { current_thid[i] = -1; break; } } } /* - - - - - - - - - - - - - - - - - - - - - - - - - - - */ /* I got a hint from taba's JPCheat, thanks! */ /* - - - - - - - - - - - - - - - - - - - - - - - - - - - */ if (use_safely_suspend) { int count; for (count = 0;count < 1000;count++) { if ((IO_MEM_STICK_STATUS & 0x2000) == 0) { count = 0; } sceKernelDelayThread(1); } } /* - - - - - - - - - - - - - - - - - - - - - - - - - - - */ for (i = 0;i < current_count;i++) { if (current_thid[i] >= 0) { sceKernelSuspendThread(current_thid[i]); } } return 0; }
static void PSPAUDIO_ThreadInit(_THIS) { /* Increase the priority of this audio thread by 1 to put it ahead of other SDL threads. */ SceUID thid; SceKernelThreadInfo status; thid = sceKernelGetThreadId(); status.size = sizeof(SceKernelThreadInfo); if (sceKernelReferThreadStatus(thid, &status) == 0) { sceKernelChangeThreadPriority(thid, status.currentPriority - 1); } }
// returns the result of sceKernelReferThreadStatus int referThread(int thid) { int result; SceKernelThreadInfo info; memset(&info, 0, sizeof(info)); info.size = sizeof(SceKernelThreadInfo); result = sceKernelReferThreadStatus(thid, &info); printf("[%s] pri:%02x status:%02x waitType:%02x\n", info.name, info.currentPriority, info.status, info.waitType); if (info.status & PSP_THREAD_RUNNING) printf(" RUNNING\n"); if (info.status & PSP_THREAD_READY) printf(" READY\n"); if (info.status & PSP_THREAD_WAITING) printf(" WAITING\n"); if (info.status & PSP_THREAD_SUSPEND) printf(" SUSPEND\n"); if (info.status & PSP_THREAD_STOPPED) printf(" STOPPED\n"); if (info.status & PSP_THREAD_KILLED) printf(" KILLED\n"); return result; }
int SDL_SYS_CreateThread(SDL_Thread *thread, void *args) { SceKernelThreadInfo status; int priority = 32; /* Set priority of new thread to the same as the current thread */ status.size = sizeof(SceKernelThreadInfo); if (sceKernelReferThreadStatus(sceKernelGetThreadId(), &status) == 0) { priority = status.currentPriority; } thread->handle = sceKernelCreateThread(thread->name, ThreadEntry, priority, thread->stacksize ? ((int) thread->stacksize) : 0x8000, PSP_THREAD_ATTR_VFPU, NULL); if (thread->handle < 0) { return SDL_SetError("sceKernelCreateThread() failed"); } sceKernelStartThread(thread->handle, 4, &args); return 0; }
/* Dump the current thread's status */ void dump_threadstatus(void) { int thid; SceKernelThreadInfo status; int ret; thid = sceKernelGetThreadId(); memset(&status, 0, sizeof(SceKernelThreadInfo)); printf("Thread ID: %08X\n", thid); status.size = sizeof(SceKernelThreadInfo); ret = sceKernelReferThreadStatus(thid, &status); printf("Get Thread Status: %08X\n", ret); if(ret == 0) { printf("Name: %s\n", status.name); printf("Thread Addr: %p\n", status.entry); printf("Stack Addr: %p\n", status.stack); printf("Stack Size: %08X\n", status.stackSize); printf("gp: %p\n", status.gpReg); printf("Initial Pri: %x\n", status.initPriority); printf("Current Pri: %x\n", status.currentPriority); } }
void syscallLog(const SyscallInfo *syscallInfo, const u32 *parameters, u64 result, u32 ra, const char *prefix) { char buffer[300]; char *s = buffer; int i, j, k; int length; int lineStart; // Don't log out own sceIoWrites. if (syscallInfo->nid == 0x42EC03AC && parameters[0] == commonInfo->logFd) { return; } if (logTimestamp) { pspTime time; if (sceRtcGetCurrentClockLocalTime(&time) == 0) { s = appendInt(s, time.hour, 2); *s++ = ':'; s = appendInt(s, time.minutes, 2); *s++ = ':'; s = appendInt(s, time.seconds, 2); *s++ = '.'; s = appendInt(s, time.microseconds, 6); *s++ = ' '; } } if (logThreadName) { SceKernelThreadInfo currentThreadInfo; currentThreadInfo.size = sizeof(currentThreadInfo); currentThreadInfo.name[0] = '\0'; sceKernelReferThreadStatus(0, ¤tThreadInfo); s = append(s, currentThreadInfo.name); *s++ = ' '; *s++ = '-'; *s++ = ' '; } if (logRa) { s = appendHex(s, ra, 0); *s++ = ' '; } s = append(s, prefix); s = append(s, syscallInfo->name); int types = syscallInfo->paramTypes; for (i = 0; i < syscallInfo->numParams; i++, types >>= 4) { if (i > 0) { *s++ = ','; } *s++ = ' '; int parameter = parameters[i]; switch (types & 0xF) { case TYPE_HEX32: s = appendHex(s, parameter, 0); break; case TYPE_INT32: s = appendInt(s, parameter, 0); break; case TYPE_STRING: s = appendHex(s, parameter, 8); if (parameter != 0) { *s++ = '('; *s++ = '\''; s = append(s, (char *) parameter); *s++ = '\''; *s++ = ')'; } break; case TYPE_POINTER32: s = appendHex(s, parameter, 8); if (parameter != 0) { *s++ = '('; s = appendHex(s, _lw(parameter), 0); *s++ = ')'; } break; case TYPE_POINTER64: s = appendHex(s, parameter, 8); if (parameter != 0) { *s++ = '('; s = appendHex(s, _lw(parameter), 8); *s++ = ' '; s = appendHex(s, _lw(parameter + 4), 8); *s++ = ')'; } break; case TYPE_VARSTRUCT: s = appendHex(s, parameter, 8); if (parameter != 0) { *s++ = ':'; *s++ = '\n'; writeLog(buffer, s - buffer); s = buffer; length = _lw(parameter); lineStart = 0; for (j = 0; j < length; j += 4) { if (j > 0) { if ((j % 16) == 0) { s = append(s, " >"); for (k = lineStart; k < j; k++) { char c = _lb(parameter + k); if (c < ' ' || c > '~') { c = '.'; } *s++ = c; } s = append(s, "<\n"); writeLog(buffer, s - buffer); s = buffer; lineStart = j; } else { *s++ = ','; *s++ = ' '; } } s = appendHex(s, _lw(parameter + j), 8); } } break; case TYPE_FIXSTRUCT: s = appendHex(s, parameter, 8); if (parameter != 0) { *s++ = ':'; *s++ = '\n'; writeLog(buffer, s - buffer); s = buffer; length = FIXSTRUCT_SIZE; lineStart = 0; for (j = 0; j < length; j += 4) { if (j > 0) { if ((j % 16) == 0) { s = append(s, " >"); for (k = lineStart; k < j; k++) { char c = _lb(parameter + k); if (c < ' ' || c > '~') { c = '.'; } *s++ = c; } s = append(s, "<\n"); writeLog(buffer, s - buffer); s = buffer; lineStart = j; } else { *s++ = ','; *s++ = ' '; } } s = appendHex(s, _lw(parameter + j), 8); } } break; } } *s++ = ' '; *s++ = '='; *s++ = ' '; s = appendHex(s, (int) result, 0); #if DEBUG_MUTEX s = mutexLog(s, syscallInfo, parameters, result); #endif *s++ = '\n'; writeLog(buffer, s - buffer); #if DEBUG_UTILITY_SAVEDATA utilitySavedataLog(buffer, syscallInfo, parameters[0]); #endif }
void runReferTests() { SceKernelThreadInfo2 info; int i; SceUID delayThread = sceKernelCreateThread("delay", &delayFunc, sceKernelGetThreadCurrentPriority(), 0x1000, PSP_THREAD_ATTR_VFPU, NULL); SceUID deletedThread = sceKernelCreateThread("deleted", &delayFunc, sceKernelGetThreadCurrentPriority(), 0x1000, 0, NULL); sceKernelDeleteThread(deletedThread); info.size = sizeof(info); checkpointNext("Thread IDs:"); checkpoint(" NULL: %08x", sceKernelReferThreadStatus(0, &info)); checkpoint(" Current: %08x", sceKernelReferThreadStatus(sceKernelGetThreadId(), &info)); checkpoint(" Deleted: %08x", sceKernelReferThreadStatus(deletedThread, &info)); checkpoint(" Invalid: %08x", sceKernelReferThreadStatus(0xDEADBEEF, &info)); // Crashes. //checkpointNext("sceKernelReferThreadStatus info ptr:"); //checkpoint(" NULL info: %08x", sceKernelReferThreadStatus(0, NULL)); checkpointNext("Sizes:"); int sizes[] = {-1, 0, 1, 2, 3, 4, 5, 8, 16, 32, 64, 80, 82, 108, 128, 1024}; for (i = 0; i < ARRAY_SIZE(sizes); ++i) { memset(&info, 0xff, sizeof(info)); info.size = sizes[i]; int result = sceKernelReferThreadStatus(0, &info); checkpoint(" %d: %08x => %d (exit: %x)", sizes[i], result, info.size, info.exitStatus); } info.size = sizeof(info); sceKernelStartThread(delayThread, 0, NULL); sceKernelReferThreadStatus(delayThread, &info); checkpointNext("Values:"); schedfThreadInfo(&info, &delayFunc); SceUID slumberThread = sceKernelCreateThread("slumber", &slumberFunc, sceKernelGetThreadCurrentPriority() - 1, 0x1000, 0, NULL); checkpoint(" slumber before start:"); sceKernelReferThreadStatus(slumberThread, &info); schedfThreadInfo(&info, &slumberFunc); sceKernelStartThread(slumberThread, 0, NULL); checkpoint(" started slumber"); checkpoint(" slumber after start:"); sceKernelReferThreadStatus(slumberThread, &info); schedfThreadInfo(&info, &slumberFunc); sceKernelTerminateThread(slumberThread); checkpoint(" terminated slumber"); checkpoint(" slumber after terminate:"); sceKernelReferThreadStatus(slumberThread, &info); schedfThreadInfo(&info, &slumberFunc); sceKernelStartThread(slumberThread, 0, NULL); checkpoint(" started slumber"); checkpoint(" slumber after start:"); sceKernelReferThreadStatus(slumberThread, &info); schedfThreadInfo(&info, &slumberFunc); checkpoint(" woke slumber: %08x", sceKernelWakeupThread(slumberThread)); checkpoint(" slumber after wake:"); sceKernelReferThreadStatus(slumberThread, &info); schedfThreadInfo(&info, &slumberFunc); sceKernelTerminateDeleteThread(slumberThread); checkpoint(" terminated and deleted slumber"); // TODO: Test more cases. flushschedf(); }
int main(int argc, char *argv[]) { int i, result; SceKernelThreadInfo info; SceUID testThread = sceKernelCreateThread("test", &testFunc, sceKernelGetThreadCurrentPriority(), 0x1000, 0, NULL); SceUID deletedThread = sceKernelCreateThread("deleted", &testFunc, sceKernelGetThreadCurrentPriority(), 0x1000, 0, NULL); sceKernelDeleteThread(deletedThread); checkpointNext("Thread IDs:"); checkpoint(" Normal: %08x", sceKernelStartThread(testThread, 0, NULL)); checkpoint(" Twice: %08x", sceKernelStartThread(testThread, 0, NULL)); checkpoint(" NULL: %08x", sceKernelStartThread(0, 0, NULL)); checkpoint(" Current: %08x", sceKernelStartThread(sceKernelGetThreadId(), 0, NULL)); checkpoint(" Deleted: %08x", sceKernelStartThread(deletedThread, 0, NULL)); checkpoint(" Invalid: %08x", sceKernelStartThread(0xDEADBEEF, 0, NULL)); checkpointNext("Argument length:"); SceUID argLengthThread = sceKernelCreateThread("argLength", &argLengthFunc, sceKernelGetThreadCurrentPriority() - 1, 0x800, 0, NULL); char argLengthTemp[0x1000]; void *argLengthStack; info.size = sizeof(info); sceKernelReferThreadStatus(argLengthThread, &info); argLengthStack = info.stack; result = sceKernelStartThread(argLengthThread, 8, NULL); sceKernelWaitThreadEnd(argLengthThread, NULL); char temp[256]; if (argLengthArgv == 0) sprintf(temp, "NULL"); else if (argLengthArgv == argLengthTemp) sprintf(temp, "original"); else sprintf(temp, "stack+0x%x", (char *)argLengthArgv - (char *)argLengthStack); checkpoint(" With NULL ptr: %08x (%d, %s)", result, argLengthArgc, temp); // Note: larger than stack seems to crash the PSP... static int lengths[] = {-1, 0x80000000, 0, 1, 2, 3, 4, 5, 6, 7, 8, 80, 90, 0x600}; for (i = 0; i < ARRAY_SIZE(lengths); ++i) { argLengthArgc = -1; argLengthArgv = NULL; result = sceKernelStartThread(argLengthThread, lengths[i], argLengthTemp); sceKernelWaitThreadEnd(argLengthThread, NULL); if (argLengthArgv == 0) sprintf(temp, "NULL"); else if (argLengthArgv == argLengthTemp) sprintf(temp, "original"); else sprintf(temp, "stack+0x%x", (char *)argLengthArgv - (char *)argLengthStack); checkpoint(" %d arg length: %08x (%d, %s)", lengths[i], result, argLengthArgc, temp); } // NULL crashes it, though... checkpointNext("Argument pointers:"); void *argptrs[] = {argLengthTemp, (void *)0xDEADBEEF, (void *)0x80000000}; for (i = 0; i < ARRAY_SIZE(argptrs); ++i) { argLengthArgc = -1; argLengthArgv = NULL; result = sceKernelStartThread(argLengthThread, 4, argptrs[i]); sceKernelWaitThreadEnd(argLengthThread, NULL); if (argLengthArgv == 0) sprintf(temp, "NULL"); else if (argLengthArgv == argLengthTemp) sprintf(temp, "original"); else sprintf(temp, "stack+0x%x", (char *)argLengthArgv - (char *)argLengthStack); checkpoint(" arg ptr #%d: %08x (%d, %s)", i, result, argLengthArgc, temp); } checkpointNext("Priorities:"); static int priorities[] = {0x8, 0x1F, 0x20, 0x21, 0x40}; for (i = 0; i < ARRAY_SIZE(priorities); ++i) { argLengthArgc = -1; sceKernelDeleteThread(argLengthThread); argLengthThread = sceKernelCreateThread("argLength", &argLengthFunc, priorities[i], 0x800, 0, NULL); result = sceKernelStartThread(argLengthThread, priorities[i], argLengthTemp); int afterStart = argLengthArgc; sceKernelWaitThreadEnd(argLengthThread, NULL); int priorityDiff = priorities[i] - sceKernelGetThreadCurrentPriority(); checkpoint(" priority 0x%02x: %08x (current%s0x%02x, %s)", priorities[i], result, priorityDiff < 0 ? "-" : "+", priorityDiff < 0 ? -priorityDiff : priorityDiff, afterStart == priorities[i] ? "resched" : (argLengthArgc == priorities[i] ? "deferred" : "never")); } checkpointNext("Stack:"); testCheckStackLayout(" No arg", 0, 0); testCheckStackLayout(" Odd arg", 1, 0); testCheckStackLayout(" Large arg", 0x600, 0); testCheckStackLayout(" Low stack", 0, 0x00400000); testCheckStackLayout(" Without fill", 0, 0x00100000); testCheckStackLayout(" Clear stack", 0, 0x00200000); return 0; }