ucos 之系統啓動 OSStart() 源碼分析 3

OSStart(void)

void  OSStart (void)
{
    if (OSRunning == OS_FALSE) {
        OS_SchedNew();                               /* Find highest priority's task priority number */
        OSPrioCur     = OSPrioHighRdy;     //最高優先級賦給 當前優先級
        OSTCBHighRdy  = OSTCBPrioTbl[OSPrioHighRdy]; /* 從TCB鏈表中取出最高優先級 賦給 最高級TCB   */
        OSTCBCur      = OSTCBHighRdy;  //最高優先級賦給 當前優先級
        OSStartHighRdy();                            /*     */
    }
}


 OS_SchedNew();  詳解見http://my.oschina.net/u/274829/blog/263287

OSStartHighRdy

// 系統執行命令爲彙編代碼
OSStartHighRdy
        ;設置pendSV中斷優先級 0xff
        LDR     R4, =NVIC_SYSPRI2      ;  PendSV 中斷  
        LDR     R5, =NVIC_PENDSV_PRI  ;0xff
        STR     R5, [R4]                  ;將R5寄存器值賦到R4中

        ;設置堆棧指針爲0 
        MOV     R4, #0                 ; set the PSP to 0 for initial context switch call
        MSR     PSP, R4        ;MSR將R4值賦給PSP

         ; OSRunning = TRUE
        LDR     R4, =OSRunning  ;將=OSRunning指令地址放到R4中      
        MOV     R5, #1
        STRB    R5, [R4]  ;將R5寄存器數據寫入R4地址內存中

        ;切換到最高優先級的任務
        LDR     R4, =NVIC_INT_CTRL     ;rigger the PendSV exception (causes context switch)
        LDR     R5, =NVIC_PENDSVSET
        STR     R5, [R4]   ;切換到最高級中斷 使能PendSV SysTick中斷

        CPSIE   I                      ;開中斷的彙編代碼
OSStartHang
        B       OSStartHang            ;should never get here

以上是任務建立的全過程cpuPSP初始化爲0來運行咱們系統中優先級最高的任務並將OSRunning標記爲true來表示咱們的內核開始運行了。spa


PendSV_Handler

PendSV_Handler
    CPSID   I                                                   ; 關因此中斷
    MRS     R0, PSP                                             ; PSP是當前進程堆棧的指針,將PSP賦值給R0
    CBZ     R0, PendSV_Handler_Nosave                     ; 若是R0爲0時跳轉到PendSV_Handler_Nosave
 
    ;已經存在任務  保存正在運行的任務 
    SUBS    R0, R0, #0x20                                       ; 偏移0x20的位置用來保存R4至R11
    STM     R0, {R4-R11} ;將剩下的R4至R11寄存器保存在此進程的堆棧中
 
    LDR     R1, =p_OSTCBCur                      
    ; OSTCBCur->OSTCBStkPtr = SP; 即OSTCBCur->OSTCBStkPtr這個保存當前的棧尾,以便下次彈出
    LDR     R1, [R1]
    STR     R0, [R1]                                            ; R0 is SP of process being switched out
   ;此時,整個上下文的過程已經被保存
   
PendSV_Handler_Nosave
    PUSH    {R14}                                               ; Save LR exc_return value
    LDR     R0, =OSTaskSwHook                                   ; OSTaskSwHook();  這裏用於用戶擴展
    BLX     R0
    POP     {R14}
 
    ;將最高優先級任務賦給當前優先級
    LDR     R0, =OSPrioCur                                      ; OSPrioCur = OSPrioHighRdy;
    LDR     R1, =OSPrioHighRdy ;將當前優先級變量指向最高優先級
    LDRB    R2, [R1]
    STRB    R2, [R0]
 
    LDR     R0, =p_OSTCBCur                                     ; OSTCBCur  = OSTCBHighRdy;
    LDR     R1, =p_OSTCBHighRdy ;TCB表也同樣
    LDR     R2, [R1]
    STR     R2, [R0]
    ;到這裏,[R2]保存的是新的進程的堆棧指針SP
    LDR     R0, [R2]                                            ;  SP = OSTCBHighRdy->OSTCBStkPtr;
    LDM     R0, {R4-R11}                                        ;  彈出其它寄存器,和前面的是一個逆過程
    ADDS    R0, R0, #0x20                                       ;和前面的逆過程對比可知
    MSR     PSP, R0                                             ; 將R0中的SP賦值給PSP寄存器
    ORR     LR, LR, #0x04                                       ; 確保異常返回時使用進程堆棧
    CPSIE   I ;開中斷
    BX      LR                                                  ; 異常返回將恢復那些自動出棧的剩餘寄存器
    ;跳到當前任務 開始運行


這裏是系統默認中斷作的事:主要工做有判斷是否第一次運行、將最高級任務賦給當前任務,而後將放到cpu寄存器運行,最高優先級任務開始運行。.net

系統任務切換則是靠OSTimeDly,下節介紹指針

相關文章
相關標籤/搜索