您的位置:首页 > 其它

【原创】uC/OS II 任务切换原理

2015-02-14 13:56 387 查看
今天学习了uC/OS II的任务切换,知道要实现任务的切换,要将原先任务的寄存器压入任务堆栈,再将新任务中任务堆栈的寄存器内容弹出到CPU的寄存器,其中的CS、IP寄存器没有出栈和入栈指令,所以只能引发一次中断,自动将CS、IP寄存器压入堆栈,再利用中断返回,将新任务的任务断点指针弹出到CPU的CS、IP寄存器中,实现任务切换。虽然明白个大概,但是其中的细节却有点模糊,为什么调用IRET中断返回指令后,弹入CPU的CS、IP寄存器的断点指针是新任务的断点指针,而不是当前任务的,UCOS II是如何实现这个过程的?网上的文章没有提及任务切换的细节,然而这些细节却是理解的重点,所以才有了今天这一篇文章!

在uC/OS II中,任务的调度由任务调度器完成,其主要的工作有两项:
1.在任务就绪表中查找最高优先级的就绪任务,该任务将是未来切换执行的任务;
2.实现任务的切换。

任务级的任务调度器,由OS_Sched()实现。

_OSCtxSw PROC FAR
;
;保存当前任务寄存器内容,将它们压入当前任务堆栈,AX、CX、DX、BX、SP(原始值)、BP、SI 及 DI
PUSHA ;
PUSH ES ;
PUSH DS ;
;
;将当前任务的任务控制块的指针段地址赋值给DS寄存器
MOV AX, SEG _OSTCBCur;Reload DS in case it was altered
MOV DS, AX ;
;
; LES指令作用,取得OSTCBCur变量内容(因为任务控制块的第一个成员为任务堆栈指针,所以ES:[BX+0]表示的地址不仅是任务控制块的首地址,也是任务堆栈指针的地址),低字存放于BX,高字存放于ES,有关LES详细查看另一篇文章!
;同时由于任务控制块的第一成员为任务堆栈指针变量,所以任务堆栈指针成员变量的地址和任务控制块的地址一样
LES BX, DWORD PTR DS:_OSTCBCur; OSTCBCur->OSTCBStkPtr = SS:SP!!!
MOV ES:[BX+2], SS ;将当前SS(栈的基地址)寄存器值存放至当前任务控制块的2,3内存单元
MOV ES:[BX+0], SP ;将当前SP(栈顶的偏移量)存放至当前任务控制块的0,1内存单元
;
CALL FAR PTR _OSTaskSwHook;Call user defined task switch hook
;
;存储器寻址,DS:_OSTCBHighRdy+2存放的是新任务的栈基址SS,DS:_OSTCBHighRdy存放的是栈顶偏移量SP
MOV AX, WORD PTR DS:_OSTCBHighRdy+2;将OSTCBHighRdy赋值给OSTCBCur,使OSTCBCur指向新的任务控制块
MOV DX, WORD PTR DS:_OSTCBHighRdy;OSTCBCur=OSTCBHighRdy
MOV WORD PTR DS:_OSTCBCur+2, AX ;
MOV WORD PTR DS:_OSTCBCur, DX ;
;
MOV AL, BYTE PTR DS:_OSPrioHighRdy;OSPrioCur=OSPrioHighRdy
MOV BYTE PTR DS:_OSPrioCur, AL ;
;
;将最高级优先级任务的任务控制块包含的SS和SP寄存器值,CPU的SS和SP指向了新的任务堆栈
LES BX, DWORD PTR DS:_OSTCBHighRdy; SS:SP =OSTCBHighRdy->OSTCBStkPtr
MOV SS, ES:[BX+2];
MOV SP, ES:[BX];
;
;注意:这里弹出的是新任务的堆栈,而不是旧的,因为CPU的SS和SP已经指向了新的任务堆栈
POP DS ;Loadnew task's context
POP ES ;
POPA ;
;
;当新任务的堆栈都弹出的时候,只剩下新任务的CS、IP指针,刚好运行IRET弹到CPU的CS、IP寄存器,开始新任务的运行
IRET ;Return to new task
;
_OSCtxSw ENDP


View Code

请仔细将上面代码对照着注释看一遍,注释已经说得很清楚了,_OSCtxSw的堆栈操作,可以看下面两幅图
(0)在调用_OSCtxSw中断服务程序前,CPU将PSW和任务断点指针CS、IP压入当前任务堆栈
(1)将CPU寄存器AX、CX、DX、BX、SP(原始值)、BP、SI 及 DI压入当前任务堆栈
(2)将当前CPU的堆栈指针SS和SP存入当前任务控制块的任务堆栈指针变量(FAR指针变量占4字节)
说明:至此,当前任务的断点数据已经全部保存,所以在每一个新任务运行之前,uC/OS都会将旧任务的断点数据全部按照顺序压入私有堆栈中,同时每一个新任务的任务堆栈都已保存初始化好的或以前任务中止时,CPU保存的断点数据。
(3)OSTCBCur = OSTCBHighRdy、OSPrioCur = OSPrioHighRdy
(4)使CPU的SS和SP堆栈指针指向新的任务堆栈
(5)将新的任务堆栈的内容弹出到CPU寄存器,顺序为DS、ES、DI、SI、BP、SP、BX、DX、CX、AX。
说明:注意是新任务堆栈在进行弹栈操作,而新任务堆栈在弹栈前,和旧任务的断点数据全部压栈后的结构一模一样,都是顺序为DS、ES、DI、SI、BP、SP、BX、DX、CX、AX、IP、CS、PSW。经过POP DS POP ES POPA,这3条指令之后,新任务堆栈便只剩下IP、CS、PSW,IP和CS这断点指针指向新任务的任务代码,只要将它们弹出到CPU的CS、IP寄存器,就可以实现任务切换。
(6)运行IRET,将新任务断点指针弹出到CPU的CS、IP指针寄存器,PSW弹出到CPU的PSW寄存器
(7)至此,uC/OS开始运行新任务





参考链接:
μC-OS-Ⅱ中通过中断返回指令实现任务切换 http://www.docin.com/p-223857136.html
我对OSCtxSW()任务级任务切换函数的理解(以图例的方式) http://blog.163.com/muren20062094%40yeah/blog/static/1618444162011727102557489/
uCOSii中断处理过程详解 http://www.doc88.com/p-1498746979512.html
uC/OS II任务调度 http://blog.sina.com.cn/s/blog_6f36f4fb0100n3or.html
uC/OS-II任务栈处理的一种改进方法 http://www.3edu.net/lw/qrs/lw_46692.html

本文链接:/article/7044950.html
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: