11bc15386SPeter Tyser /* 2*1a459660SWolfgang Denk * SPDX-License-Identifier: GPL-2.0+ 31bc15386SPeter Tyser */ 41bc15386SPeter Tyser 51bc15386SPeter Tyser #include <common.h> 61bc15386SPeter Tyser #include <exports.h> 71bc15386SPeter Tyser 81bc15386SPeter Tyser /* 91bc15386SPeter Tyser * Author: Arun Dharankar <ADharankar@ATTBI.Com> 101bc15386SPeter Tyser * 111bc15386SPeter Tyser * A very simple thread/schedular model: 121bc15386SPeter Tyser * - only one master thread, and no parent child relation maintained 131bc15386SPeter Tyser * - parent thread cannot be stopped or deleted 141bc15386SPeter Tyser * - no permissions or credentials 151bc15386SPeter Tyser * - no elaborate safety checks 161bc15386SPeter Tyser * - cooperative multi threading 171bc15386SPeter Tyser * - Simple round-robin scheduleing with no priorities 181bc15386SPeter Tyser * - no metering/statistics collection 191bc15386SPeter Tyser * 201bc15386SPeter Tyser * Basic idea of implementing this is to allow more than one tests to 211bc15386SPeter Tyser * execute "simultaneously". 221bc15386SPeter Tyser * 231bc15386SPeter Tyser * This may be modified such thread_yield may be called in syscalls, and 241bc15386SPeter Tyser * timer interrupts. 251bc15386SPeter Tyser */ 261bc15386SPeter Tyser 271bc15386SPeter Tyser 281bc15386SPeter Tyser #define MAX_THREADS 8 291bc15386SPeter Tyser 301bc15386SPeter Tyser #define CTX_SIZE 512 311bc15386SPeter Tyser #define STK_SIZE 8*1024 321bc15386SPeter Tyser 331bc15386SPeter Tyser #define STATE_EMPTY 0 341bc15386SPeter Tyser #define STATE_RUNNABLE 1 351bc15386SPeter Tyser #define STATE_STOPPED 2 361bc15386SPeter Tyser #define STATE_TERMINATED 2 371bc15386SPeter Tyser 381bc15386SPeter Tyser #define MASTER_THREAD 0 391bc15386SPeter Tyser 401bc15386SPeter Tyser #define RC_FAILURE (-1) 411bc15386SPeter Tyser #define RC_SUCCESS (0) 421bc15386SPeter Tyser 431bc15386SPeter Tyser typedef vu_char *jmp_ctx; 441bc15386SPeter Tyser unsigned long setctxsp (vu_char *sp); 451bc15386SPeter Tyser int ppc_setjmp(jmp_ctx env); 461bc15386SPeter Tyser void ppc_longjmp(jmp_ctx env, int val); 471bc15386SPeter Tyser #define setjmp ppc_setjmp 481bc15386SPeter Tyser #define longjmp ppc_longjmp 491bc15386SPeter Tyser 501bc15386SPeter Tyser struct lthread { 511bc15386SPeter Tyser int state; 521bc15386SPeter Tyser int retval; 531bc15386SPeter Tyser char stack[STK_SIZE]; 541bc15386SPeter Tyser uchar context[CTX_SIZE]; 551bc15386SPeter Tyser int (*func) (void *); 561bc15386SPeter Tyser void *arg; 571bc15386SPeter Tyser }; 581bc15386SPeter Tyser static volatile struct lthread lthreads[MAX_THREADS]; 591bc15386SPeter Tyser static volatile int current_tid = MASTER_THREAD; 601bc15386SPeter Tyser 611bc15386SPeter Tyser 621bc15386SPeter Tyser static uchar dbg = 0; 631bc15386SPeter Tyser 641bc15386SPeter Tyser #define PDEBUG(fmt, args...) { \ 651bc15386SPeter Tyser if(dbg != 0) { \ 661bc15386SPeter Tyser printf("[%s %d %s]: ",__FILE__,__LINE__,__FUNCTION__);\ 671bc15386SPeter Tyser printf(fmt, ##args); \ 681bc15386SPeter Tyser printf("\n"); \ 691bc15386SPeter Tyser } \ 701bc15386SPeter Tyser } 711bc15386SPeter Tyser 721bc15386SPeter Tyser static int testthread (void *); 731bc15386SPeter Tyser static void sched_init (void); 741bc15386SPeter Tyser static int thread_create (int (*func) (void *), void *arg); 751bc15386SPeter Tyser static int thread_start (int id); 761bc15386SPeter Tyser static void thread_yield (void); 771bc15386SPeter Tyser static int thread_delete (int id); 781bc15386SPeter Tyser static int thread_join (int *ret); 791bc15386SPeter Tyser 801bc15386SPeter Tyser #if 0 /* not used yet */ 811bc15386SPeter Tyser static int thread_stop (int id); 821bc15386SPeter Tyser #endif /* not used yet */ 831bc15386SPeter Tyser 841bc15386SPeter Tyser /* An example of schedular test */ 851bc15386SPeter Tyser 861bc15386SPeter Tyser #define NUMTHREADS 7 871bc15386SPeter Tyser int sched (int ac, char *av[]) 881bc15386SPeter Tyser { 891bc15386SPeter Tyser int i, j; 901bc15386SPeter Tyser int tid[NUMTHREADS]; 911bc15386SPeter Tyser int names[NUMTHREADS]; 921bc15386SPeter Tyser 931bc15386SPeter Tyser app_startup(av); 941bc15386SPeter Tyser 951bc15386SPeter Tyser sched_init (); 961bc15386SPeter Tyser 971bc15386SPeter Tyser for (i = 0; i < NUMTHREADS; i++) { 981bc15386SPeter Tyser names[i] = i; 991bc15386SPeter Tyser j = thread_create (testthread, (void *) &names[i]); 1001bc15386SPeter Tyser if (j == RC_FAILURE) 1011bc15386SPeter Tyser printf ("schedtest: Failed to create thread %d\n", i); 1021bc15386SPeter Tyser if (j > 0) { 1031bc15386SPeter Tyser printf ("schedtest: Created thread with id %d, name %d\n", 1041bc15386SPeter Tyser j, i); 1051bc15386SPeter Tyser tid[i] = j; 1061bc15386SPeter Tyser } 1071bc15386SPeter Tyser } 1081bc15386SPeter Tyser printf ("schedtest: Threads created\n"); 1091bc15386SPeter Tyser 1101bc15386SPeter Tyser printf ("sched_test: function=0x%08x\n", (unsigned)testthread); 1111bc15386SPeter Tyser for (i = 0; i < NUMTHREADS; i++) { 1121bc15386SPeter Tyser printf ("schedtest: Setting thread %d runnable\n", tid[i]); 1131bc15386SPeter Tyser thread_start (tid[i]); 1141bc15386SPeter Tyser thread_yield (); 1151bc15386SPeter Tyser } 1161bc15386SPeter Tyser printf ("schedtest: Started %d threads\n", NUMTHREADS); 1171bc15386SPeter Tyser 1181bc15386SPeter Tyser while (1) { 1191bc15386SPeter Tyser printf ("schedtest: Waiting for threads to complete\n"); 1201bc15386SPeter Tyser if (tstc () && getc () == 0x3) { 1211bc15386SPeter Tyser printf ("schedtest: Aborting threads...\n"); 1221bc15386SPeter Tyser for (i = 0; i < NUMTHREADS; i++) { 1231bc15386SPeter Tyser printf ("schedtest: Deleting thread %d\n", tid[i]); 1241bc15386SPeter Tyser thread_delete (tid[i]); 1251bc15386SPeter Tyser } 1261bc15386SPeter Tyser return RC_SUCCESS; 1271bc15386SPeter Tyser } 1281bc15386SPeter Tyser j = -1; 1291bc15386SPeter Tyser i = thread_join (&j); 1301bc15386SPeter Tyser if (i == RC_FAILURE) { 1311bc15386SPeter Tyser printf ("schedtest: No threads pending, " 1321bc15386SPeter Tyser "exiting schedular test\n"); 1331bc15386SPeter Tyser return RC_SUCCESS; 1341bc15386SPeter Tyser } 1351bc15386SPeter Tyser printf ("schedtest: thread is %d returned %d\n", i, j); 1361bc15386SPeter Tyser thread_yield (); 1371bc15386SPeter Tyser } 1381bc15386SPeter Tyser 1391bc15386SPeter Tyser return RC_SUCCESS; 1401bc15386SPeter Tyser } 1411bc15386SPeter Tyser 1421bc15386SPeter Tyser static int testthread (void *name) 1431bc15386SPeter Tyser { 1441bc15386SPeter Tyser int i; 1451bc15386SPeter Tyser 1461bc15386SPeter Tyser printf ("testthread: Begin executing thread, myname %d, &i=0x%08x\n", 1471bc15386SPeter Tyser *(int *) name, (unsigned)&i); 1481bc15386SPeter Tyser 1491bc15386SPeter Tyser printf ("Thread %02d, i=%d\n", *(int *) name, i); 1501bc15386SPeter Tyser 1511bc15386SPeter Tyser for (i = 0; i < 0xffff * (*(int *) name + 1); i++) { 1521bc15386SPeter Tyser if (tstc () && getc () == 0x3) { 1531bc15386SPeter Tyser printf ("testthread: myname %d terminating.\n", 1541bc15386SPeter Tyser *(int *) name); 1551bc15386SPeter Tyser return *(int *) name + 1; 1561bc15386SPeter Tyser } 1571bc15386SPeter Tyser 1581bc15386SPeter Tyser if (i % 100 == 0) 1591bc15386SPeter Tyser thread_yield (); 1601bc15386SPeter Tyser } 1611bc15386SPeter Tyser 1621bc15386SPeter Tyser printf ("testthread: returning %d, i=0x%x\n", 1631bc15386SPeter Tyser *(int *) name + 1, i); 1641bc15386SPeter Tyser 1651bc15386SPeter Tyser return *(int *) name + 1; 1661bc15386SPeter Tyser } 1671bc15386SPeter Tyser 1681bc15386SPeter Tyser 1691bc15386SPeter Tyser static void sched_init (void) 1701bc15386SPeter Tyser { 1711bc15386SPeter Tyser int i; 1721bc15386SPeter Tyser 1731bc15386SPeter Tyser for (i = MASTER_THREAD + 1; i < MAX_THREADS; i++) 1741bc15386SPeter Tyser lthreads[i].state = STATE_EMPTY; 1751bc15386SPeter Tyser 1761bc15386SPeter Tyser current_tid = MASTER_THREAD; 1771bc15386SPeter Tyser lthreads[current_tid].state = STATE_RUNNABLE; 1781bc15386SPeter Tyser PDEBUG ("sched_init: master context = 0x%08x", 1791bc15386SPeter Tyser (unsigned)lthreads[current_tid].context); 1801bc15386SPeter Tyser return; 1811bc15386SPeter Tyser } 1821bc15386SPeter Tyser 1831bc15386SPeter Tyser static void thread_yield (void) 1841bc15386SPeter Tyser { 1851bc15386SPeter Tyser static int i; 1861bc15386SPeter Tyser 1871bc15386SPeter Tyser PDEBUG ("thread_yield: current tid=%d", current_tid); 1881bc15386SPeter Tyser 1891bc15386SPeter Tyser #define SWITCH(new) \ 1901bc15386SPeter Tyser if(lthreads[new].state == STATE_RUNNABLE) { \ 1911bc15386SPeter Tyser PDEBUG("thread_yield: %d match, ctx=0x%08x", \ 1921bc15386SPeter Tyser new, \ 1931bc15386SPeter Tyser (unsigned)lthreads[current_tid].context); \ 1941bc15386SPeter Tyser if(setjmp(lthreads[current_tid].context) == 0) { \ 1951bc15386SPeter Tyser current_tid = new; \ 1961bc15386SPeter Tyser PDEBUG("thread_yield: tid %d returns 0", \ 1971bc15386SPeter Tyser new); \ 1981bc15386SPeter Tyser longjmp(lthreads[new].context, 1); \ 1991bc15386SPeter Tyser } else { \ 2001bc15386SPeter Tyser PDEBUG("thread_yield: tid %d returns 1", \ 2011bc15386SPeter Tyser new); \ 2021bc15386SPeter Tyser return; \ 2031bc15386SPeter Tyser } \ 2041bc15386SPeter Tyser } 2051bc15386SPeter Tyser 2061bc15386SPeter Tyser for (i = current_tid + 1; i < MAX_THREADS; i++) { 2071bc15386SPeter Tyser SWITCH (i); 2081bc15386SPeter Tyser } 2091bc15386SPeter Tyser 2101bc15386SPeter Tyser if (current_tid != 0) { 2111bc15386SPeter Tyser for (i = 0; i <= current_tid; i++) { 2121bc15386SPeter Tyser SWITCH (i); 2131bc15386SPeter Tyser } 2141bc15386SPeter Tyser } 2151bc15386SPeter Tyser 2161bc15386SPeter Tyser PDEBUG ("thread_yield: returning from thread_yield"); 2171bc15386SPeter Tyser return; 2181bc15386SPeter Tyser } 2191bc15386SPeter Tyser 2201bc15386SPeter Tyser static int thread_create (int (*func) (void *), void *arg) 2211bc15386SPeter Tyser { 2221bc15386SPeter Tyser int i; 2231bc15386SPeter Tyser 2241bc15386SPeter Tyser for (i = MASTER_THREAD + 1; i < MAX_THREADS; i++) { 2251bc15386SPeter Tyser if (lthreads[i].state == STATE_EMPTY) { 2261bc15386SPeter Tyser lthreads[i].state = STATE_STOPPED; 2271bc15386SPeter Tyser lthreads[i].func = func; 2281bc15386SPeter Tyser lthreads[i].arg = arg; 2291bc15386SPeter Tyser PDEBUG ("thread_create: returns new tid %d", i); 2301bc15386SPeter Tyser return i; 2311bc15386SPeter Tyser } 2321bc15386SPeter Tyser } 2331bc15386SPeter Tyser 2341bc15386SPeter Tyser PDEBUG ("thread_create: returns failure"); 2351bc15386SPeter Tyser return RC_FAILURE; 2361bc15386SPeter Tyser } 2371bc15386SPeter Tyser 2381bc15386SPeter Tyser static int thread_delete (int id) 2391bc15386SPeter Tyser { 2401bc15386SPeter Tyser if (id <= MASTER_THREAD || id > MAX_THREADS) 2411bc15386SPeter Tyser return RC_FAILURE; 2421bc15386SPeter Tyser 2431bc15386SPeter Tyser if (current_tid == id) 2441bc15386SPeter Tyser return RC_FAILURE; 2451bc15386SPeter Tyser 2461bc15386SPeter Tyser lthreads[id].state = STATE_EMPTY; 2471bc15386SPeter Tyser return RC_SUCCESS; 2481bc15386SPeter Tyser } 2491bc15386SPeter Tyser 2501bc15386SPeter Tyser static void thread_launcher (void) 2511bc15386SPeter Tyser { 2521bc15386SPeter Tyser PDEBUG ("thread_launcher: invoking func=0x%08x", 2531bc15386SPeter Tyser (unsigned)lthreads[current_tid].func); 2541bc15386SPeter Tyser 2551bc15386SPeter Tyser lthreads[current_tid].retval = 2561bc15386SPeter Tyser lthreads[current_tid].func (lthreads[current_tid].arg); 2571bc15386SPeter Tyser 2581bc15386SPeter Tyser PDEBUG ("thread_launcher: tid %d terminated", current_tid); 2591bc15386SPeter Tyser 2601bc15386SPeter Tyser lthreads[current_tid].state = STATE_TERMINATED; 2611bc15386SPeter Tyser thread_yield (); 2621bc15386SPeter Tyser printf ("thread_launcher: should NEVER get here!\n"); 2631bc15386SPeter Tyser 2641bc15386SPeter Tyser return; 2651bc15386SPeter Tyser } 2661bc15386SPeter Tyser 2671bc15386SPeter Tyser static int thread_start (int id) 2681bc15386SPeter Tyser { 2691bc15386SPeter Tyser PDEBUG ("thread_start: id=%d", id); 2701bc15386SPeter Tyser if (id <= MASTER_THREAD || id > MAX_THREADS) { 2711bc15386SPeter Tyser return RC_FAILURE; 2721bc15386SPeter Tyser } 2731bc15386SPeter Tyser 2741bc15386SPeter Tyser if (lthreads[id].state != STATE_STOPPED) 2751bc15386SPeter Tyser return RC_FAILURE; 2761bc15386SPeter Tyser 2771bc15386SPeter Tyser if (setjmp (lthreads[current_tid].context) == 0) { 2781bc15386SPeter Tyser lthreads[id].state = STATE_RUNNABLE; 2791bc15386SPeter Tyser current_tid = id; 2801bc15386SPeter Tyser PDEBUG ("thread_start: to be stack=0%08x", 2811bc15386SPeter Tyser (unsigned)lthreads[id].stack); 2821bc15386SPeter Tyser setctxsp ((vu_char *)<hreads[id].stack[STK_SIZE]); 2831bc15386SPeter Tyser thread_launcher (); 2841bc15386SPeter Tyser } 2851bc15386SPeter Tyser 2861bc15386SPeter Tyser PDEBUG ("thread_start: Thread id=%d started, parent returns", id); 2871bc15386SPeter Tyser 2881bc15386SPeter Tyser return RC_SUCCESS; 2891bc15386SPeter Tyser } 2901bc15386SPeter Tyser 2911bc15386SPeter Tyser #if 0 /* not used so far */ 2921bc15386SPeter Tyser static int thread_stop (int id) 2931bc15386SPeter Tyser { 2941bc15386SPeter Tyser if (id <= MASTER_THREAD || id >= MAX_THREADS) 2951bc15386SPeter Tyser return RC_FAILURE; 2961bc15386SPeter Tyser 2971bc15386SPeter Tyser if (current_tid == id) 2981bc15386SPeter Tyser return RC_FAILURE; 2991bc15386SPeter Tyser 3001bc15386SPeter Tyser lthreads[id].state = STATE_STOPPED; 3011bc15386SPeter Tyser return RC_SUCCESS; 3021bc15386SPeter Tyser } 3031bc15386SPeter Tyser #endif /* not used so far */ 3041bc15386SPeter Tyser 3051bc15386SPeter Tyser static int thread_join (int *ret) 3061bc15386SPeter Tyser { 3071bc15386SPeter Tyser int i, j = 0; 3081bc15386SPeter Tyser 3091bc15386SPeter Tyser PDEBUG ("thread_join: *ret = %d", *ret); 3101bc15386SPeter Tyser 3111bc15386SPeter Tyser if (!(*ret == -1 || *ret > MASTER_THREAD || *ret < MAX_THREADS)) { 3121bc15386SPeter Tyser PDEBUG ("thread_join: invalid tid %d", *ret); 3131bc15386SPeter Tyser return RC_FAILURE; 3141bc15386SPeter Tyser } 3151bc15386SPeter Tyser 3161bc15386SPeter Tyser if (*ret == -1) { 3171bc15386SPeter Tyser PDEBUG ("Checking for tid = -1"); 3181bc15386SPeter Tyser while (1) { 3191bc15386SPeter Tyser /* PDEBUG("thread_join: start while-loopn"); */ 3201bc15386SPeter Tyser j = 0; 3211bc15386SPeter Tyser for (i = MASTER_THREAD + 1; i < MAX_THREADS; i++) { 3221bc15386SPeter Tyser if (lthreads[i].state == STATE_TERMINATED) { 3231bc15386SPeter Tyser *ret = lthreads[i].retval; 3241bc15386SPeter Tyser lthreads[i].state = STATE_EMPTY; 3251bc15386SPeter Tyser /* PDEBUG("thread_join: returning retval %d of tid %d", 3261bc15386SPeter Tyser ret, i); */ 3271bc15386SPeter Tyser return RC_SUCCESS; 3281bc15386SPeter Tyser } 3291bc15386SPeter Tyser 3301bc15386SPeter Tyser if (lthreads[i].state != STATE_EMPTY) { 3311bc15386SPeter Tyser PDEBUG ("thread_join: %d used slots tid %d state=%d", 3321bc15386SPeter Tyser j, i, lthreads[i].state); 3331bc15386SPeter Tyser j++; 3341bc15386SPeter Tyser } 3351bc15386SPeter Tyser } 3361bc15386SPeter Tyser if (j == 0) { 3371bc15386SPeter Tyser PDEBUG ("thread_join: all slots empty!"); 3381bc15386SPeter Tyser return RC_FAILURE; 3391bc15386SPeter Tyser } 3401bc15386SPeter Tyser /* PDEBUG("thread_join: yielding"); */ 3411bc15386SPeter Tyser thread_yield (); 3421bc15386SPeter Tyser /* PDEBUG("thread_join: back from yield"); */ 3431bc15386SPeter Tyser } 3441bc15386SPeter Tyser } 3451bc15386SPeter Tyser 3461bc15386SPeter Tyser if (lthreads[*ret].state == STATE_TERMINATED) { 3471bc15386SPeter Tyser i = *ret; 3481bc15386SPeter Tyser *ret = lthreads[*ret].retval; 3491bc15386SPeter Tyser lthreads[*ret].state = STATE_EMPTY; 3501bc15386SPeter Tyser PDEBUG ("thread_join: returing %d for tid %d", *ret, i); 3511bc15386SPeter Tyser return RC_SUCCESS; 3521bc15386SPeter Tyser } 3531bc15386SPeter Tyser 3541bc15386SPeter Tyser PDEBUG ("thread_join: thread %d is not terminated!", *ret); 3551bc15386SPeter Tyser return RC_FAILURE; 3561bc15386SPeter Tyser } 357