home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Frostbyte's 1980s DOS Shareware Collection
/
floppyshareware.zip
/
floppyshareware
/
DOOG
/
CTASK.ZIP
/
TSKSTCK.ASM
< prev
next >
Wrap
Assembly Source File
|
1989-12-20
|
6KB
|
262 lines
;
; --- Version 2.0 89-12-13 17:15 ---
;
; CTask - Local Stack Switch handler module.
;
; Public Domain Software written by
; Thomas Wagner
; Patschkauer Weg 31
; D-1000 Berlin 33
; West Germany
;
; This file is new with version 1.2.
;
; In this version, all Hard- and Software INT handlers switch
; to a local stack (INT 16 for AH=0 only). Stack overruns have
; been observed, especially in conjunction with VDISK and the
; Microsoft Editor. Some Microsoft products (and some other TSR's)
; link into interrupts without switching to local stacks. This
; can lead to situations where just a few words are available
; for use by the CTask handlers. In the abovementioned combination,
; a keyboard interrupt occurring while VDISK is active leaves
; four (!) words of stack space for INT 16 execution.
; Since most of the interrupts should be reentrant, a number
; of stacks are maintained (constant NUM_STACKS), and the call
; is passed without a stack switch if all local stacks are in use.
;
; To avoid duplication of the stack switch and register save code
; in all handlers, a global stack switcher is implemented here.
; It pushes the address of a back-switch routine on the new stack,
; so the calling routine doesn't have to care about explicitly
; calling the restore routine.
;
; No registers may be pushed prior to the call to switch_stack if
; the auto-switchback is to be used, since switch_stack assumes
; the old stack to contain the caller's flags at offset 8.
;
; When old_stack is called to explicitly switch back, stack
; contents prior to the call to switch_stack are insignificant.
;
; Switch_stack will set up registers as follows:
; BP = base of register save area on stack
; DS,ES = DGROUP
; Direction flag clear
; Interrupts enabled
; All other registers are unchanged.
;
; Since the switch_stack routine pushes the caller's flags on
; the stack, the original flags will be restored if an IRET is used
; to enter the auto-backswitch. For RET 2, the flags on entry
; to the backswitch-routine will be preserved.
; To allow preservation of the flag state on entry to switch_stack,
; the flags are pushed on the save area, but not automatically
; restored. Copy the entry_flags into caller_flags to restore
; the entry flags on return.
;
; old_stack will not restore flags from the stack, it will preserve
; the flag state.
;
.model large,c
;
include tsk.mac
;
public tsk_switch_stack
public tsk_old_stack
;
extrn tsk_dgroup: word
;
STACKSIZE = 256 ; local stack size (bytes)
NUM_STACKS = 8 ; Number of local stacks
;
.tsk_data
;
lstacks label word ; Stacks for INT 16
db NUM_STACKS * STACKSIZE dup (?)
;
.tsk_edata
.tsk_code
;
;
stack_full dw 0 ; count all stacks in use events
;
r_ss dw ?
r_sp dw ?
r_bx dw ?
r_cx dw ?
r_bp dw ?
call_ip dw ?
call_cs dw ?
retaoff dw ?
retaseg dw ?
sflags dw ?
;
; Caution: Since a zero slot offset is used to detect
; that no stack was allocated, the "stacks" array may not
; be located at offset 0 in the code segment.
;
stacks label word
xst = offset lstacks + STACKSIZE
rept NUM_STACKS
dw xst
xst = xst + STACKSIZE
endm
;
;
tsk_switch_stack proc near
;
pushf
cli
pop cs:sflags
pop cs:retaoff ; return address
mov cs:r_bx,bx ; save bx & cx in CS
mov cs:r_cx,cx
mov cs:r_bp,bp ; save BP
mov bp,sp
mov bx,[bp] ; get caller's IP
mov cs:call_ip,bx
mov bx,2[bp] ; get caller's CS
mov cs:call_cs,bx
mov bp,4[bp] ; get caller's flags into BP
;
mov cx,NUM_STACKS ; total number of stacks
mov bx,offset stacks ; stack table
stlp:
cmp word ptr cs:[bx],0 ; in use ?
jne st_found ; jump if free
inc bx
inc bx
loop stlp
;
; No unused stack, continue on caller's stack
;
inc cs:stack_full
xor bx,bx
jmp short st_old
;
; Stack found, perform switch
;
st_found:
mov cs:r_ss,ss ; save SS/SP
mov cs:r_sp,sp
mov ss,cs:tsk_dgroup ; load new SS/SP
mov sp,cs:[bx]
mov cx,sp ; save new SP value
mov word ptr cs:[bx],0 ; mark stack in use
push cs:r_ss ; push old SS/SP
push cs:r_sp
st_old:
push cs:r_bx
push cs:r_cx
push bx ; push stack slot index
push cx ; push new SP
;
push ax ; push remaining regs
push dx
push si
push di
push cs:r_bp
push ds
push es
;
push cs:sflags ; push entry flags
push cs:call_cs ; push caller's CS
push cs:call_ip ; push caller's IP
;
push bp ; push caller's flags
push cs ; and special return
mov cx,offset stsw_retn
push cx
mov bx,cs:r_bx ; restore regs bx,cx
mov cx,cs:r_cx
mov bp,sp ; set BP to stack bottom
push cs:retaoff ; push retaddr on new stack
cld
sti
mov ds,cs:tsk_dgroup
mov es,cs:tsk_dgroup
ret ; restore flags & return
;
tsk_switch_stack endp
;
;
tsk_old_stack proc near
;
pushf ; save flags
cli
pop cs:sflags
pop cs:retaoff ; return address
add sp,12 ; discard dummy return & flags
;
pop es ; restore regs
pop ds
pop bp
pop di
pop si
pop dx
pop ax
;
pop cx ; new SP
pop bx ; stack slot index
or bx,bx ; no new stack?
jnz old_sw
pop cx
pop bx
jmp short old_ret
old_sw:
mov cs:[bx],cx ; reset stack slot
pop cx
pop bx
pop cs:r_sp
pop ss ; old SS
mov sp,cs:r_sp
old_ret:
push cs:retaoff ; push retaddr on old stack
push cs:sflags
popf ; restore flags
ret ; and return
;
tsk_old_stack endp
;
; stsw_retn is where the call returns to when there is no explicit
; call to old_stack.
;
stsw_retn proc far
;
pushf ; save flags
cli
pop cs:sflags ; in CS
;
add sp,6 ; discard caller CS/IP & entry flags
;
pop es ; restore regs
pop ds
pop bp
pop di
pop si
pop dx
pop ax
;
pop cx ; new SP
pop bx ; stack slot index
or bx,bx ; no new stack?
jnz retn_sw
pop cx
pop bx
jmp short retn_ret
retn_sw:
mov cs:[bx],cx ; reset stack slot
pop cx
pop bx
pop cs:r_sp
pop ss ; old SS
mov sp,cs:r_sp
retn_ret:
push cs:sflags ; push flags on old stack
popf ; restore flags
ret 2 ; and return
;
stsw_retn endp
;
end