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来表示我们的内核开始运行了。


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寄存器运行,最高优先级任务开始运行。

系统任务切换则是靠OSTimeDly,下节介绍


你可能感兴趣的:(ucos,之系统启动,OSStart(),PendSV_Handler)