uCOS/II 任务堆栈初始化子程序OSTaskStkInit 任务切换时SP指针的变化过程,我的理解
请问:(1)、创建任务时,任务堆栈初始化子程序(OSTaskStkInit)中,AX,CX,DX,BX,BP,SI,DI,ES,可以被初始化为
任意值,DS初始化为当前数据段段地址,SP指针也可以被初始化为任意值吗?
(2)、我不明白,当执行后以下几条语句后,SP到底等于多少?
PUSHA ; Save current task's context
PUSH ES ;
PUSH DS ;
;
MOV AX, SEG _OSTCBCur ; Reload DS in case it was altered
MOV DS, AX ;
;
LES BX, DWORD PTR DS:_OSTCBCur ; OSTCBCur->OSTCBStkPtr = SS:SP
MOV ES:, SS ;
MOV ES:, SP ;
如果执行PUSHA之前,SP=0,那么执行完DS后,SP=20吗?
此时执行 MOV ES:, SS ;
MOV ES:, SP ;
后,挂起任务的堆栈中记录的堆栈指针SS:SP=SS:20吗?
我的理解如下:
任务切换子程序OSCtxSw()中
(1)、通过执行PUSHA
将CPU的寄存器AX,CX,DX,BX,SP,BP,SI,DI压入当前任务的堆栈中
(2)、通过执行PUSH ES,PUSH DS
将CPU的寄存器ES,DS压入当前任务的堆栈中
(3)、通过执行如下语句,获取最高优先级任务的堆栈的段地址SS和偏移地址SP
LES BX, DWORD PTR DS:_OSTCBHighRdy; SS:SP = OSTCBHighRdy->OSTCBStkPtr
MOV SS, ES: ;
MOV SP, ES: ;
如果假定SS=4055,
那么此时SP好象应该=20,因为前面执行了PUSHA、PUSH ES、PUSH DS。
(4)、通过执行POP DS、POP ES
将最高优先级任务堆栈中保存的DS、ES恢复到CPU中。此时SP=16
(5)、执行POPA ;
将DI、SI、BP、SP、DX、CX、AX依次从任务堆栈中恢复到CPU中。此时SP=0
附:
1、任务堆栈初始化子程序
OS_STK*OSTaskStkInit (void (*task)(void *pd), void *pdata, OS_STK *ptos, INT16U opt)
{
INT16U *stk;
opt = opt; /* 'opt' is not used, prevent warning */
stk = (INT16U *)ptos; /* Load stack pointer */
*stk-- = (INT16U)FP_SEG(pdata); /* Simulate call to function with argument */
*stk-- = (INT16U)FP_OFF(pdata);
*stk-- = (INT16U)FP_SEG(task);
*stk-- = (INT16U)FP_OFF(task);
*stk-- = (INT16U)0x0202; /* SW = Interrupts enabled */
*stk-- = (INT16U)FP_SEG(task); /* Put pointer to task on top of stack */
*stk-- = (INT16U)FP_OFF(task);
*stk-- = (INT16U)0xAAAA; /* AX = 0xAAAA */
*stk-- = (INT16U)0xCCCC; /* CX = 0xCCCC */
*stk-- = (INT16U)0xDDDD; /* DX = 0xDDDD */
*stk-- = (INT16U)0xBBBB; /* BX = 0xBBBB */
*stk-- = (INT16U)0x0000; /* SP = 0x0000 */
*stk-- = (INT16U)0x1111; /* BP = 0x1111 */
*stk-- = (INT16U)0x2222; /* SI = 0x2222 */
*stk-- = (INT16U)0x3333; /* DI = 0x3333 */
*stk-- = (INT16U)0x4444; /* ES = 0x4444 */
*stk = _DS; /* DS = Current value of DS */
return ((OS_STK *)stk);
}
2、任务切换子程序
_OSCtxSw PROC FAR
PUSHA ; Save current task's context
PUSH ES ;
PUSH DS ;
;
MOV AX, SEG _OSTCBCur ; Reload DS in case it was altered
MOV DS, AX ;
;
LES BX, DWORD PTR DS:_OSTCBCur ; OSTCBCur->OSTCBStkPtr = SS:SP
MOV ES:, SS ;
MOV ES:, SP ;
;
CALL FAR PTR _OSTaskSwHook ; Call user defined task switch hook
;
MOV AX, WORD PTR DS:_OSTCBHighRdy+2 ; OSTCBCur = OSTCBHighRdy
MOV DX, WORD PTR DS:_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 ;
;
LES BX, DWORD PTR DS:_OSTCBHighRdy; SS:SP = OSTCBHighRdy->OSTCBStkPtr
MOV SS, ES: ;
MOV SP, ES: ;
;
POP DS ; Load new task's context
POP ES ;
POPA ;
IRET ; Return to new task
_OSCtxSw ENDP
没有告诉吗? (1)
SP初始化为一函数(或任务)的地址值
也即在初始化时SP可以视为一个指向函数(或任务)的指针! 我看到在M8上移植的,里面用到了CALL指令,但是现在M8不支持这个指令,不知道,他们怎么编译运行成功的! 帮忙分析一下,执行_OSCtxSw()后,每一条指令时的SP=? 帮忙分析一下,执行_OSCtxSw()后,每一条指令时的SP=? 帮忙分析一下,执行_OSCtxSw()后,每一条指令执行时的SP=? 帮忙分析一下,执行_OSCtxSw()后,每一条指令执行时的SP=? 不要重复发问.
楼主钻了牛角尖了.要理解运作规律,诀窍在于抓住根本而不是钻牛角尖.
OS堆栈切换很简单,跟你用call-return的道理一样,不同的时,call之后它将SP指针改到别的地方了.
由于每次切换任务的压栈和出栈过程是一样的,所以你完全可以忽略掉压栈和出栈进程,把它当然一次时间比较长的call空函数就行了. mark 回复【8楼】rainyss
-----------------------------------------------------------------------
同意!
底层汇编,要自己理解! 你的签名太长了 请问:
(1)、创建任务时,任务堆栈初始化子程序(OSTaskStkInit)中,AX,CX,DX,BX,BP,SI,DI,ES,可以被初始化为
任意值,DS初始化为当前数据段段地址,SP指针也可以被初始化为任意值吗?
不可以,SP 也就是stack顶指针,通常,stack都是向下生长的,也就是从高地址往低地址生长。
stack的作用,通常用来保存函数的局部变量,保存函数调用时的,入口参数,返回地址,
由上可见,SP的定义,并不是随心所欲的,定义的太小,离代码段或者数据段太近,有可能因为PUSH 压stack的问题冲掉代码段或者数据段
所以,应该找一处保险的位置,作为SP的使用
(2)、我不明白,当执行后以下几条语句后,SP到底等于多少?
PUSHA ; Save current task's context
PUSH ES ;
PUSH DS ;
;
MOV AX, SEG _OSTCBCur ; Reload DS in case it was altered
MOV DS, AX ;
;
LES BX, DWORD PTR DS:_OSTCBCur ; OSTCBCur->OSTCBStkPtr = SS:SP
MOV ES:, SS ;
MOV ES:, SP ;
如果执行PUSHA之前,SP=0,那么执行完DS后,SP=20吗?
此时执行 MOV ES:, SS ;
MOV ES:, SP ;
后,挂起任务的堆栈中记录的堆栈指针SS:SP=SS:20吗?
如果要问SP到底是多少,确定几件事,
1. 在PUSH 之前,SP是多少,假设是100
2. 在这些指令中,真正影响SP的是哪些指令,
是
PUSHA ; Save current task's context
PUSH ES ;
PUSH DS
我这里假设 stack是向下生长的,
PUSHA 依次保存EAX, ECX, EDX, EBX, ESP,EBP, ESI, and EDI,如果是16的CPU,则对应的寄存器是 AX,CX,DX,BX,SP,BP,SI,DI
之后有 ES 和 DS 被 push
所以,在PUSH DS之后,一共push了 8 + 2 = 10个16-bit的寄存器,SP 向下减少了20个字节的空间, 也就是 100-20 = 80
SP在这些PUSH指令后,变成 80了,
不过按照你的理解,挂起任务中的 SS 和 SP, 确实就是你说的
页:
[1]