home *** CD-ROM | disk | FTP | other *** search
/ The C Users' Group Library 1994 August / wc-cdrom-cusersgrouplibrary-1994-08.iso / vol_300 / 330_03 / tskstck.asm < prev    next >
Assembly Source File  |  1990-10-12  |  9KB  |  424 lines

  1. ;
  2. ;    --- Version 2.2 90-10-12 15:33 ---
  3. ;
  4. ;    CTask - Local Stack Switch handler module.
  5. ;
  6. ;    Public Domain Software written by
  7. ;        Thomas Wagner
  8. ;        Ferrari electronic Gmbh
  9. ;        Beusselstrasse 27
  10. ;        D-1000 Berlin 21
  11. ;        Germany
  12. ;
  13. ;    This file is new with version 1.2.
  14. ;
  15. ;    In this version, all Hard- and Software INT handlers switch
  16. ;    to a local stack (INT 16 for AH=0 only). Stack overruns have
  17. ;    been observed, especially in conjunction with VDISK and the
  18. ;    Microsoft Editor. Some Microsoft products (and some other TSR's)
  19. ;    link into interrupts without switching to local stacks. This
  20. ;    can lead to situations where just a few words are available
  21. ;    for use by the CTask handlers. In the abovementioned combination,
  22. ;    a keyboard interrupt occurring while VDISK is active leaves
  23. ;    four (!) words of stack space for INT 16 execution.
  24. ;    Since most of the interrupts should be reentrant, a number
  25. ;    of stacks are maintained (constant NUM_STACKS), and the call 
  26. ;    is passed without a stack switch if all local stacks are in use. 
  27. ;
  28. ;    To avoid duplication of the stack switch and register save code 
  29. ;    in all handlers, a global stack switcher is implemented here. 
  30. ;    It pushes the address of a back-switch routine on the new stack, 
  31. ;    so the calling routine doesn't have to care about explicitly
  32. ;    calling the restore routine.
  33. ;
  34. ;    No registers may be pushed prior to the call to switch_stack if
  35. ;    the auto-switchback is to be used, since switch_stack assumes
  36. ;    the old stack to contain the callers flags at offset 4.
  37. ;
  38. ;    When old_stack is called to explicitly switch back, stack 
  39. ;    contents prior to the call to switch_stack are insignificant.
  40. ;
  41. ;    Switch_stack will set up registers as follows:
  42. ;        BP = base of register save area on stack
  43. ;        DS,ES = DGROUP
  44. ;        Direction flag clear
  45. ;        Interrupts enabled
  46. ;    All other registers are unchanged.
  47. ;
  48. ;    To allow preservation of the flag state on entry to switch_stack,
  49. ;    the flags are pushed on the save area, but not automatically
  50. ;    restored. Copy the entry_flags into caller_flags to restore
  51. ;    the entry flags on return.
  52. ;
  53. ;    old_stack will not restore flags from the stack, it will preserve
  54. ;    the flag state.
  55. ;
  56. ;    Version 2.1 slightly changes the handling of flag restoration
  57. ;    on auto-backswitch. The old algorithm restored the caller flags
  58. ;    on entry to the backswitch routine, which caused problems with
  59. ;    debuggers if the interrupted code was being single-stepped.
  60. ;    Now the original flags always will be restored on exit of the
  61. ;    back-switch, regardless of the return used (IRET or RET 2).
  62. ;    To modify the flags returned, you have to explicitly modify
  63. ;    the caller_flags field in the saved register area.
  64. ;
  65.     name    tskstck
  66. ;
  67.     include    tsk.mac
  68.     include    tskdeb.h
  69. ;
  70.     .tsk_model
  71. ;
  72.     Pubfunc    tsk_switch_stack
  73.     Pubfunc    tsk_old_stack
  74. ;
  75.     IF    DEBUG AND DEB_FLASHERS
  76.     Locext    tsk_inccdis
  77.     extrn    tsk_debflash: word
  78.     extrn    tsk_dtposn: dword
  79.     ENDIF
  80. ;
  81. ;
  82. STACKSIZE    =    256    ; local stack size (bytes)
  83. NUM_STACKS    =    8    ; Number of local stacks
  84. ;
  85.     IF    FAR_STACKS
  86. ctask_stacks    segment word public 'CTASK_STACKS'
  87.     ELSE
  88.     .tsk_data
  89.     ENDIF
  90. ;
  91. lstacks    label    word
  92.     db    NUM_STACKS * STACKSIZE dup (?)
  93. ;
  94.     IF    FAR_STACKS
  95. ctask_stacks    ends
  96.     .tsk_data
  97.     ENDIF
  98. ;
  99.     IF    NOT ROM_CODE
  100. ;
  101.     .tsk_edata
  102.     .tsk_code
  103. ;
  104. sseg    equ    <cs>
  105.     ENDIF
  106. ;
  107. stack_full    dw    0    ; count 'all stacks in use' events
  108.     IF    DEBUG AND DEB_FLASHERS
  109. usecnt    db    0
  110.     ENDIF
  111.     EVEN
  112. ;
  113. ;
  114.     IF    ROM_CODE
  115. r_ds        dw    ?
  116.     ENDIF
  117. r_ss        dw    ?
  118. r_sp        dw    ?
  119. r_bx        dw    ?
  120. r_cx        dw    ?
  121. r_bp        dw    ?
  122. call_ip        dw    ?
  123. call_cs        dw    ?
  124. retaoff        dw    ?
  125.     IF    LOCALS_FAR
  126. retaseg        dw    ?
  127.     ENDIF
  128. sflags        dw    ?
  129. ;
  130. ;    Caution: Since a zero slot offset is used to detect
  131. ;    that no stack was allocated, the "stacks" array may not
  132. ;    be located at offset 0 in the segment.
  133. ;
  134. stacks    label    word
  135. xst    =    offset lstacks + STACKSIZE
  136.     rept    NUM_STACKS
  137.     dw    xst
  138. xst    =    xst + STACKSIZE
  139.     endm
  140. ;
  141.     IF    ROM_CODE
  142. ;
  143.     .tsk_edata
  144.     .tsk_code
  145. ;
  146. sseg    equ    <ds>
  147.     ENDIF
  148. ;
  149. tsk_dgroup    dw    @CTASK_DATA
  150. ;
  151.     IF    FAR_STACKS
  152. stackseg    dw    SEG ctask_stacks
  153.     ELSE
  154. stackseg    equ    <tsk_dgroup>
  155.     ENDIF
  156. ;
  157. ;
  158. Localfunc tsk_switch_stack
  159. ;
  160.     IF    ROM_CODE
  161.     push    ds
  162.     mov    ds,cs:tsk_dgroup
  163.     pop    r_ds
  164.     ENDIF
  165.     pushf
  166.     cli
  167.     pop    sseg:sflags
  168.     pop    sseg:retaoff        ; return address
  169.     IF    LOCALS_FAR
  170.     pop    sseg:retaseg
  171.     ENDIF
  172.     mov    sseg:r_bx,bx        ; save bx & cx in CS
  173.     mov    sseg:r_cx,cx
  174.     mov    sseg:r_bp,bp        ; save BP
  175.     mov    bp,sp
  176.     mov    bx,[bp]            ; get caller's IP
  177.     mov    sseg:call_ip,bx
  178.     mov    bx,2[bp]        ; get caller's CS
  179.     mov    sseg:call_cs,bx
  180.     mov    bp,4[bp]        ; get caller's flags into BP
  181. ;
  182.     mov    cx,NUM_STACKS        ; total number of stacks
  183.     mov    bx,offset stacks    ; stack table
  184. stlp:
  185.     cmp    word ptr sseg:[bx],0    ; in use ?
  186.     jne    st_found        ; jump if free
  187.     inc    bx
  188.     inc    bx
  189.     loop    stlp
  190. ;
  191. ;    No unused stack, continue on caller's stack
  192. ;
  193.     IF    DEBUG AND DEB_FLASHERS
  194.     push    ds
  195.     mov    ds,cs:tsk_dgroup
  196.     cmp    tsk_debflash,0
  197.     je    debdd0
  198.     push    ax
  199.     mov    ax,DEBP_CNTSTOFL
  200.     call    tsk_inccdis
  201.     pop    ax
  202. debdd0:
  203.     pop    ds
  204.     ENDIF
  205.     inc    sseg:stack_full
  206.     xor    bx,bx
  207.     jmp    short st_old
  208. ;
  209. ;    Stack found, perform switch
  210. ;
  211. st_found:
  212.     mov    sseg:r_ss,ss        ; save SS/SP
  213.     mov    sseg:r_sp,sp
  214.     mov    ss,cs:stackseg        ; load new SS/SP
  215.     mov    sp,sseg:[bx]
  216.     mov    cx,sp            ; save new SP value
  217.     mov    word ptr sseg:[bx],0    ; mark stack in use
  218.     push    sseg:r_ss            ; push old SS/SP
  219.     push    sseg:r_sp
  220. st_old:
  221.     push    sseg:r_bx
  222.     push    sseg:r_cx
  223.     push    bx            ; push stack slot index
  224.     push    cx            ; push new SP
  225. ;
  226.     push    ax            ; push remaining regs
  227.     push    dx
  228.     push    si
  229.     push    di
  230.     push    sseg:r_bp
  231.     IF    ROM_CODE
  232.     push    r_ds
  233.     ELSE
  234.     push    ds
  235.     ENDIF
  236.     push    es
  237. ;
  238.     push    bp            ; push caller's flags
  239.     push    sseg:call_cs        ; push caller's CS
  240.     push    sseg:call_ip        ; push caller's IP
  241. ;
  242.     push    sseg:sflags        ; push entry flags
  243.     push    cs            ; and special return
  244.     mov    cx,offset @stsw_retn
  245.     push    cx
  246.     mov    bx,sseg:r_bx        ; restore regs bx,cx
  247.     mov    cx,sseg:r_cx
  248.     mov    bp,sp            ; set BP to stack bottom
  249.     IF    LOCALS_FAR
  250.     push    sseg:retaseg
  251.     ENDIF
  252.     push    sseg:retaoff        ; push retaddr on new stack
  253.     cld
  254.     sti
  255.     mov    ds,cs:tsk_dgroup
  256.     mov    es,cs:tsk_dgroup
  257.     IF    DEBUG AND DEB_FLASHERS
  258.     cmp    slot_idx[bp],0
  259.     je    debdd1
  260.     cmp    tsk_debflash,0
  261.     je    debdd1
  262.     inc    sseg:usecnt
  263.     push    ax
  264.     push    ds
  265.     push    si
  266.     mov    al,sseg:usecnt
  267.     add    al,'0'
  268.     lds    si,tsk_dtposn
  269.     mov    DEBP_STACKNUM[si],al
  270.     pop    si
  271.     pop    ds
  272.     pop    ax
  273. debdd1:
  274.     ENDIF
  275.     ret                ; restore flags & return
  276. ;
  277. tsk_switch_stack    endp
  278. ;
  279. ;
  280. Localfunc tsk_old_stack
  281. ;
  282.     pushf                ; save flags
  283.     cli
  284.     IF    ROM_CODE
  285.     mov    ds,cs:tsk_dgroup
  286.     ENDIF
  287.     pop    sseg:sflags
  288.     pop    sseg:retaoff        ; return address
  289.     IF    LOCALS_FAR
  290.     pop    sseg:retaseg
  291.     ENDIF
  292.     add    sp,12            ; discard dummy return & flags
  293. ;
  294.     IF    DEBUG AND DEB_FLASHERS
  295.     mov    ds,cs:tsk_dgroup
  296.     cmp    slot_idx[bp],0
  297.     je    debdd2
  298.     cmp    tsk_debflash,0
  299.     je    debdd2
  300.     dec    sseg:usecnt
  301.     mov    al,sseg:usecnt
  302.     add    al,'0'
  303.     lds    si,tsk_dtposn
  304.     mov    DEBP_STACKNUM[si],al
  305.     IF    ROM_CODE
  306.     mov    ds,cs:tsk_dgroup
  307.     ENDIF
  308. debdd2:
  309.     ENDIF
  310. ;
  311.     pop    es            ; restore regs
  312.     IF    ROM_CODE
  313.     pop    r_ds
  314.     ELSE
  315.     pop    ds
  316.     ENDIF
  317.     pop    bp
  318.     pop    di
  319.     pop    si
  320.     pop    dx
  321.     pop    ax
  322. ;
  323.     pop    cx            ; new SP
  324.     pop    bx            ; stack slot index
  325.     or    bx,bx            ; no new stack?
  326.     jnz    old_sw
  327.     pop    cx
  328.     pop    bx
  329.     jmp    short old_ret
  330. old_sw:
  331.     mov    sseg:[bx],cx        ; reset stack slot
  332.     pop    cx
  333.     pop    bx
  334.     pop    sseg:r_sp
  335.     pop    ss               ; old SS
  336.     mov    sp,sseg:r_sp
  337. old_ret:
  338.     IF    LOCALS_FAR
  339.     push    sseg:retaseg
  340.     ENDIF
  341.     push    sseg:retaoff        ; push retaddr on old stack
  342.     push    sseg:sflags
  343.     IF    ROM_CODE
  344.     mov    ds,r_ds
  345.     ENDIF
  346.     popf                ; restore flags
  347.     ret                ; and return
  348. ;
  349. tsk_old_stack    endp
  350. ;
  351. ; stsw_retn is where the call returns to when there is no explicit
  352. ; call to old_stack.
  353. ;
  354. @stsw_retn    proc    far
  355. ;
  356.     cli
  357.     add    sp,4            ; discard caller CS/IP
  358.     IF    ROM_CODE
  359.     mov    ds,cs:tsk_dgroup
  360.     ENDIF
  361.     pop    sseg:sflags        ; store caller's flags in CS
  362. ;
  363.     IF    DEBUG AND DEB_FLASHERS
  364.     mov    ds,cs:tsk_dgroup
  365.     cmp    slot_idx[bp],0
  366.     je    debdd3
  367.     cmp    tsk_debflash,0
  368.     je    debdd3
  369.     dec    sseg:usecnt
  370.     mov    al,sseg:usecnt
  371.     add    al,'0'
  372.     lds    si,tsk_dtposn
  373.     mov    DEBP_STACKNUM[si],al
  374.     IF    ROM_CODE
  375.     mov    ds,cs:tsk_dgroup
  376.     ENDIF
  377. debdd3:
  378.     ENDIF
  379. ;
  380.     pop    es            ; restore regs
  381.     IF    ROM_CODE
  382.     pop    r_ds
  383.     ELSE
  384.     pop    ds
  385.     ENDIF
  386.     pop    bp
  387.     pop    di
  388.     pop    si
  389.     pop    dx
  390.     pop    ax
  391. ;
  392.     pop    cx            ; new SP
  393.     pop    bx            ; stack slot index
  394.     or    bx,bx            ; no new stack?
  395.     jnz    retn_sw
  396.     pop    cx
  397.     pop    bx
  398.     jmp    short retn_ret
  399. retn_sw:
  400.     mov    sseg:[bx],cx        ; reset stack slot
  401.     pop    cx
  402.     pop    bx
  403.     pop    sseg:r_sp
  404.     pop    ss               ; old SS
  405.     mov    sp,sseg:r_sp
  406. retn_ret:
  407.     push    bp
  408.     mov    bp,sp
  409.     push    ax
  410.     mov    ax,sseg:sflags        ; push flags on old stack
  411.     mov    6[bp],ax
  412.     pop    ax
  413.     pop    bp
  414.     IF    ROM_CODE
  415.     mov    ds,r_ds
  416.     ENDIF
  417.     iret
  418. ;
  419. @stsw_retn    endp
  420. ;
  421.     .tsk_ecode
  422.     end
  423.  
  424.