搜索
bottom↓
回复: 12

uCOS/II 任务堆栈初始化子程序OSTaskStkInit 任务切换时SP指针的变化过程,我的理解

[复制链接]

出0入0汤圆

发表于 2008-5-12 10:36:02 | 显示全部楼层 |阅读模式
请问:
 (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:[BX+2], SS                   ;
            MOV    ES:[BX+0], SP                   ;
        如果执行PUSHA之前,SP=0,那么执行完DS后,SP=20吗?
    此时执行 MOV    ES:[BX+2], SS                   ;
              MOV    ES:[BX+0], 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:[BX+2]                   ;
          MOV    SP, ES:[BX]                     ;
      如果假定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:[BX+2], SS                   ;
            MOV    ES:[BX+0], 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:[BX+2]                   ;
         MOV    SP, ES:[BX]                     ;
;
          POP    DS                              ; Load new task's context
          POP    ES                              ;
          POPA                                   ;
           IRET                                   ; Return to new task
_OSCtxSw    ENDP
 

阿莫论坛20周年了!感谢大家的支持与爱护!!

一只鸟敢站在脆弱的枝条上歇脚,它依仗的不是枝条不会断,而是自己有翅膀,会飞。

出0入0汤圆

 楼主| 发表于 2008-5-16 11:02:07 | 显示全部楼层
没有告诉吗?

出0入0汤圆

发表于 2008-5-16 11:31:52 | 显示全部楼层
(1)
SP初始化为一函数(或任务)的地址值

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

出0入0汤圆

发表于 2008-5-16 13:12:37 | 显示全部楼层
我看到在M8上移植的,里面用到了CALL指令,但是现在M8不支持这个指令,不知道,他们怎么编译运行成功的!

出0入0汤圆

 楼主| 发表于 2008-5-17 16:19:51 | 显示全部楼层
帮忙分析一下,执行_OSCtxSw()后,每一条指令时的SP=?

出0入0汤圆

 楼主| 发表于 2008-5-19 11:35:12 | 显示全部楼层
帮忙分析一下,执行_OSCtxSw()后,每一条指令时的SP=?

出0入0汤圆

 楼主| 发表于 2008-5-22 17:37:29 | 显示全部楼层
帮忙分析一下,执行_OSCtxSw()后,每一条指令执行时的SP=?

出0入0汤圆

 楼主| 发表于 2008-9-5 10:37:53 | 显示全部楼层
帮忙分析一下,执行_OSCtxSw()后,每一条指令执行时的SP=?

出0入0汤圆

发表于 2008-9-5 10:52:49 | 显示全部楼层
不要重复发问.

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

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

出0入0汤圆

发表于 2011-9-15 00:05:21 | 显示全部楼层
mark

出0入0汤圆

发表于 2011-9-15 08:57:04 | 显示全部楼层
回复【8楼】rainyss
-----------------------------------------------------------------------

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

出0入0汤圆

发表于 2011-9-17 19:30:29 | 显示全部楼层
你的签名太长了

出0入0汤圆

发表于 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:[BX+2], SS                   ;
            MOV    ES:[BX+0], SP                   ;
        如果执行PUSHA之前,SP=0,那么执行完DS后,SP=20吗?
    此时执行 MOV    ES:[BX+2], SS                   ;
              MOV    ES:[BX+0], 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, 确实就是你说的
回帖提示: 反政府言论将被立即封锁ID 在按“提交”前,请自问一下:我这样表达会给举报吗,会给自己惹麻烦吗? 另外:尽量不要使用Mark、顶等没有意义的回复。不得大量使用大字体和彩色字。【本论坛不允许直接上传手机拍摄图片,浪费大家下载带宽和论坛服务器空间,请压缩后(图片小于1兆)才上传。压缩方法可以在微信里面发给自己(不要勾选“原图),然后下载,就能得到压缩后的图片】。另外,手机版只能上传图片,要上传附件需要切换到电脑版(不需要使用电脑,手机上切换到电脑版就行,页面底部)。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

手机版|Archiver|amobbs.com 阿莫电子技术论坛 ( 粤ICP备2022115958号, 版权所有:东莞阿莫电子贸易商行 创办于2004年 (公安交互式论坛备案:44190002001997 ) )

GMT+8, 2024-5-16 10:23

© Since 2004 www.amobbs.com, 原www.ourdev.cn, 原www.ouravr.com

快速回复 返回顶部 返回列表