Nut/OS  4.10.3
API Reference
context.c
Go to the documentation of this file.
00001 
00036 /*
00037  * $Log: context.c,v $
00038  *
00039  */
00040 
00041 #include <cfg/os.h>
00042 
00043 #include <string.h>
00044 
00045 #include <sys/atom.h>
00046 #include <sys/heap.h>
00047 #include <sys/thread.h>
00048 
00049 #include <avr32/io.h>
00050 
00055 
00056 
00064 typedef struct {
00065     uint32_t csf_cpsr;
00066     uint32_t csf_lr;
00067     uint32_t csf_r7;
00068     uint32_t csf_r6;
00069     uint32_t csf_r5;
00070     uint32_t csf_r4;
00071     uint32_t csf_r3;
00072     uint32_t csf_r2;
00073     uint32_t csf_r1;
00074     uint32_t csf_r0;
00075 } SWITCHFRAME;
00076 
00082 typedef struct {
00083     uint32_t cef_pc;
00084     uint32_t cef_r12;
00085 } ENTERFRAME;
00086 
00090 static void NutThreadEntry(void) __attribute__ ((naked));
00091 void NutThreadEntry(void)
00092 {
00093     /* Load argument in r12 and jump to thread entry. */
00094     __asm__ volatile ("popm   r12, lr\n\t"      /* put the value of cef_r12 in R12 and the value of cef_pc in lr */
00095                       "mov    pc,lr\n\t"        /* then pc recieve lr */
00096                       :::"r12", "lr", "pc");
00097 }
00098 
00099 
00111 void NutThreadSwitch(void) __attribute__ ((naked));
00112 void NutThreadSwitch(void)
00113 {
00114     /* Save CPU context. */
00115     __asm__ volatile ("pushm    r0-r7, lr \n\t"    /* Save registers in the stack */
00116                       "mfsr       r10, %1 \n\t"    /* Save status in R10 */
00117                       "pushm      r10     \n\t"    /* Save r10 in the stack */
00118                       "st.w        %0, sp \n\t"    /* the address contained in R10 contain the address of the stack pointer. */
00119                       :"=m" (runningThread->td_sp)
00120                       :"i"(AVR32_SR)
00121                       :"r10");
00122 
00123     /* Select thread on top of the run queue. */
00124     runningThread = runQueue;
00125     runningThread->td_state = TDS_RUNNING;
00126 
00127     /* Restore context. */
00128     /* When changing this, remember to keep NutThreadCreate copy in sync */
00129     __asm__ volatile ("ld.w    sp, %0\n\t"         /* Restore stack pointer. */
00130                       "popm    r10   \n\t"         /* Get saved status... */
00131                       "mtsr    %1, r10\n\t" "popm r0-r7, lr\n\t"        /* Restore registers. */
00132                       "mov     pc, lr\n\t"         /* Restore status and return. */
00133                       ::"m" (runningThread->td_sp), "i"(AVR32_SR)
00134                       :"r10");
00135 
00136 #if defined(NUT_CRITICAL_NESTING) && !defined(NUT_CRITICAL_NESTING_STACK)
00137     critical_nesting_level = 0;
00138 #endif
00139 }
00140 
00161 HANDLE NutThreadCreate(char *name, void (*fn) (void *), void *arg, size_t stackSize)
00162 {
00163     uint8_t *threadMem;
00164     SWITCHFRAME *sf;
00165     ENTERFRAME *ef;
00166     NUTTHREADINFO *td;
00167 
00168     /*
00169      * Allocate stack and thread info structure in one block.
00170      * We sill setup the following layout:
00171      *
00172      * Upper memory addresses.
00173      *
00174      *              +--------------------+
00175      *              I                    I
00176      *              I   NUTTHREADINFO    I
00177      *              I                    I
00178      * td ->        +-----+--------------+ <- Stack top
00179      *              I     I              I
00180      *              I  T  I   ENTERFRAME I
00181      *              I  H  I              I
00182      * ef ->        I  R  +--------------+
00183      *              I  E  I              I    ^
00184      *              I  A  I  SWITCHFRAME I    I
00185      *              I  D  I              I    I  pop moves up
00186      * sf ->        I     +--------------+ <- Initial stack pointer
00187      *              I  S  I              I    I  push moves down
00188      *              I  T  I Application  I    I
00189      *              I  A  I Stack        I    V
00190      *              I  C  I              I
00191      *              I  K  I              I
00192      * threadMem -> +-----+--------------+ <- Stack bottom
00193      *
00194      * Lower memory addresses.
00195      */
00196     if ((threadMem = NutHeapAlloc(stackSize + sizeof(NUTTHREADINFO))) == 0) {
00197         return 0;
00198     }
00199     td = (NUTTHREADINFO *) (threadMem + stackSize);
00200     ef = (ENTERFRAME *) ((uptr_t) td - sizeof(ENTERFRAME));
00201     sf = (SWITCHFRAME *) ((uptr_t) ef - sizeof(SWITCHFRAME));
00202 
00203     /* 
00204      * Set predefined values at the stack bottom. May be used to detect
00205      * stack overflows.
00206      */
00207 #if defined(NUTDEBUG_CHECK_STACKMIN) || defined(NUTDEBUG_CHECK_STACK)
00208     {
00209         uint32_t *fip = (uint32_t *) threadMem;
00210         while (fip < (uint32_t *) sf) {
00211             *fip++ = DEADBEEF;
00212         }
00213     }
00214 #else
00215     *((uint32_t *) threadMem) = DEADBEEF;
00216     *((uint32_t *) (threadMem + 4)) = DEADBEEF;
00217     *((uint32_t *) (threadMem + 8)) = DEADBEEF;
00218     *((uint32_t *) (threadMem + 12)) = DEADBEEF;
00219 #endif
00220 
00221     /*
00222      * Setup the entry frame to simulate C function entry.
00223      */
00224     ef->cef_pc = (uptr_t) fn;
00225     ef->cef_r12 = (uptr_t) arg;
00226 
00227     /*
00228      * Setup the switch frame.
00229      */
00230     sf->csf_lr = (uptr_t) NutThreadEntry;
00231     sf->csf_cpsr = (AVR32_SR_M_SUP << AVR32_SR_M_OFFSET);       /* [M2:M0]=001 - Supervisor Mode I1M=0 I0M=0, GM=0 */
00232 
00233     /*
00234      * Initialize the thread info structure and insert it into the 
00235      * thread list and the run queue.
00236      */
00237     memcpy(td->td_name, name, sizeof(td->td_name) - 1);
00238     td->td_name[sizeof(td->td_name) - 1] = 0;
00239     td->td_state = TDS_READY;
00240     td->td_sp = (uptr_t) sf;
00241     td->td_priority = 64;
00242     td->td_memory = threadMem;
00243     td->td_timer = 0;
00244     td->td_queue = 0;
00245 
00246     NutEnterCritical();
00247     td->td_next = nutThreadList;
00248     nutThreadList = td;
00249     NutThreadAddPriQueue(td, (NUTTHREADINFO **) & runQueue);
00250 
00251     /*
00252      * If no thread is running, then this is the first thread ever 
00253      * created. In Nut/OS, the idle thread is created first.
00254      */
00255     if (runningThread == 0) {
00256         /* This will never return. */
00257         runningThread = runQueue;
00258         runningThread->td_state = TDS_RUNNING;
00259         /* Restore context. */
00260         __asm__ volatile (      /* */
00261                              "ld.w    sp, %0\n\t"       /* Restore stack pointer. */
00262                              "popm    r10   \n\t"       /* Get saved status... */
00263                              "mtsr    %1, r10\n\t" "popm r0-r7, lr\n\t" /* Restore registers. */
00264                              "mov     pc, lr\n\t"       /* Restore status and return. */
00265                              ::"m" (runningThread->td_sp), "i"(AVR32_SR)
00266                              :"r10");
00267     }
00268 
00269     /*
00270      * If current context is not in front of the run queue (highest 
00271      * priority), then switch to the thread in front.
00272      */
00273     if (runningThread != runQueue) {
00274         runningThread->td_state = TDS_READY;
00275         NutThreadSwitch();
00276     }
00277     NutExitCritical();
00278 
00279     return td;
00280 }
00281