ba_wang_mao 发表于 2008-5-12 10:36:02

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
 

ba_wang_mao 发表于 2008-5-16 11:02:07

没有告诉吗?

TTLife 发表于 2008-5-16 11:31:52

(1)
SP初始化为一函数(或任务)的地址值

也即在初始化时SP可以视为一个指向函数(或任务)的指针!

Forever 发表于 2008-5-16 13:12:37

我看到在M8上移植的,里面用到了CALL指令,但是现在M8不支持这个指令,不知道,他们怎么编译运行成功的!

ba_wang_mao 发表于 2008-5-17 16:19:51

帮忙分析一下,执行_OSCtxSw()后,每一条指令时的SP=?

ba_wang_mao 发表于 2008-5-19 11:35:12

帮忙分析一下,执行_OSCtxSw()后,每一条指令时的SP=?

ba_wang_mao 发表于 2008-5-22 17:37:29

帮忙分析一下,执行_OSCtxSw()后,每一条指令执行时的SP=?

ba_wang_mao 发表于 2008-9-5 10:37:53

帮忙分析一下,执行_OSCtxSw()后,每一条指令执行时的SP=?

rainyss 发表于 2008-9-5 10:52:49

不要重复发问.

楼主钻了牛角尖了.要理解运作规律,诀窍在于抓住根本而不是钻牛角尖.

OS堆栈切换很简单,跟你用call-return的道理一样,不同的时,call之后它将SP指针改到别的地方了.
由于每次切换任务的压栈和出栈过程是一样的,所以你完全可以忽略掉压栈和出栈进程,把它当然一次时间比较长的call空函数就行了.

gloryzkl 发表于 2011-9-15 00:05:21

mark

chinabn 发表于 2011-9-15 08:57:04

回复【8楼】rainyss
-----------------------------------------------------------------------

同意!
底层汇编,要自己理解!

yrktcst 发表于 2011-9-17 19:30:29

你的签名太长了

aprogramer 发表于 2011-9-17 20:30:16

请问:
 (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]
查看完整版本: uCOS/II 任务堆栈初始化子程序OSTaskStkInit 任务切换时SP指针的变化过程,我的理解