home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Power-Programmierung
/
CD1.mdf
/
magazine
/
drdobbs
/
1987
/
12
/
holub
/
swap.asm
< prev
next >
Wrap
Assembly Source File
|
1987-12-21
|
33KB
|
341 lines
; SWAP.ASM Routine to do context swaps. Everything in
; this file is VERY compiler dependant and
; VERY nonportable.
;
TITLE swap.c
NAME swap
_TEXT SEGMENT WORD PUBLIC 'CODE'
_TEXT ENDS
_DATA SEGMENT WORD PUBLIC 'DATA'
_DATA ENDS
CONST SEGMENT WORD PUBLIC 'CONST'
CONST ENDS
_BSS SEGMENT WORD PUBLIC 'BSS'
op db 0 ; Used by rst_chkstk and chg_chkstk
segm dw 0 ; (below).
off dw 0
save_bx dw 0 ; used by __t_swap_in
_BSS ENDS
DGROUP GROUP CONST, _BSS, _DATA
ASSUME CS: _TEXT, DS: DGROUP, SS: DGROUP
_DATA SEGMENT
_DATA ENDS
IF 1
PUBLIC stack_err, mychkstk, rst_chkstk, chg_chkstk
PUBLIC op, segm, off
ENDIF
;------------------------------------------------------------
_TEXT SEGMENT
ASSUME CS: _TEXT
PUBLIC __t_swap_in ; Swaps two tasks
PUBLIC __t_install ; Installs a task when none active
PUBLIC __t_shazam ; Starts multitasking
PUBLIC _t_stop ; Stops multitasking.
PUBLIC __t_sus_chkstk ; Temporarily suspend stack checking.
PUBLIC __t_rst_chkstk ; Restore it again.
EXTRN __chkstk:NEAR ; in standard library
EXTRN _free:NEAR ; In standard library
EXTRN __t_slowdown:NEAR; In schedule.asm
EXTRN _t_block:NEAR ; "
EXTRN _t_release:NEAR ; "
EXTRN _t_iserr:NEAR ; In task.c
EXTRN _T_active:WORD ; Declared in kernel.h. Pointer
; to currently active task
;------------------------------------------------------------
save_sp dw 0
save_ss dw 0
chk_on dw 0 ; No stack probes while nonzero
;------------------------------------------------------------
__t_shazam PROC NEAR
; Start the ball rolling. Save the current context.
; then start up the first task. On entry,
; T_active must point at the first task to activate.
; Stack on entry (from top to bottom) is:
;
; return address from _t_shazam call
; old bp saved by t_start
; t_start's return address
; speedup_factor passed to t_start
;
add sp,2 ; Discard return addr to _t_shazam
; Uncovering bp from main that
; was saved by t_start()
push si
push di
push ds ; push this last
mov WORD PTR cs:save_sp, sp
mov WORD PTR cs:save_ss, ss
call chg_chkstk
mov bx, WORD PTR _T_active
jmp shazam
__t_shazam ENDP
;------------------------------------------------------------
_t_stop PROC NEAR
; t_stop( errcode )
;
; This routine deletes the current task, causes
; multitasking to be turned off, and passes control
; back to the routine that called t_start()
; (immediately following the t_start call).
; Errcode is passed back to the calling routine as the
; return value of t_start().
;
; It can be called directly by a running task; it's
; called automatically when the last task is deleted,
; or when the only running task deletes itself.
cli ; Just to make sure
add sp,2 ; Discard return address
pop ax ; return value = errcode
mov ss, WORD PTR cs:save_ss ; Restore initial stack...
mov sp, WORD PTR cs:save_sp ;
pop ds ; ...and data segment.
push ax
call rst_chkstk ; Put back original __chkstk
call __t_slowdown ; Disable weird timer int.
pop ax ; get back return value
push ax
or ax,ax ; if( errcode == NOERR ) )
jnz t_stop1 ; {
push _T_active ; free( T_active );
call _free ;
add sp,2 ; }
t_stop1:
pop ax ; return( errcode )
pop di ; resore si and di saved by
pop si ; by __t_shazem,
pop bp ; and bp saved by t_start.
ret ;
_t_stop ENDP
;------------------------------------------------------------
__t_install PROC NEAR
; _t_install(new)
; TCB *new;
;
; Delete the current task and replace it with the
; new one. This routine saves some space (and execution
; time) by jumping into the middle of swap() to install
; the new task. The scheduler must be blocked when
; this routine is called. This routine does not
; return.
add sp,2 ; discard return address
pop bx ; bx = new
mov ss,WORD PTR [bx+2] ; ss:sp = new task's stack;
mov sp,WORD PTR [bx]
push bx
push _T_active ; free( T_active )
call _free
add sp,2 ; Discard arg to free()
pop bx; ; get back bx.
jmp shazam
__t_install ENDP
;------------------------------------------------------------
__t_swap_in PROC NEAR
; _t_swap_in( new )
; TCB *new;
;
; Do a context swap. Replace T_active with new, This
; routine returns only when the original context is
; restored. Swapping MUST be blocked when this subroutine
; is called. Release() is called once the new context
; is installed and T_active is modified to point at the
; new task.
cli
mov WORD PTR cs:save_bx,bx
pop bx ; bx = return address
pushf ; Save current context
push cs
push bx ; (Push return address as new ip)
push ax
push save_bx
push cx
push dx
push si
push di
push bp
push ds
push es
; Stack now looks like this:
;
; new [sp + 24]
; flags [sp + 22]
; cs [sp + 20]
; ip [sp + 18]
; ax [sp + 16]
; bx [sp + 14]
; cx [sp + 12]
; dx [sp + 10]
; si [sp + 8]
; di [sp + 6]
; bp [sp + 4]
; ds [sp + 2]
; es [sp] (top of stack)
mov bx,WORD PTR _T_active
mov WORD PTR [bx+2],ss
mov WORD PTR [bx],sp
mov bx,sp
mov bx,WORD PTR [bx+24] ; bx = new
shazam: ; __t_shazam and __t_install
; come here to do the swap
mov WORD PTR _T_active,bx ; T_active = new;
mov ss,WORD PTR [bx+2] ; Switch to new task's stack
mov sp,WORD PTR [bx]
pop es
pop ds
pop bp
pop di
pop si
pop dx
pop cx
pop bx
pop ax
call _t_release
sti
iret
__t_swap_in ENDP
;------------------------------------------------------------
; __t_chg_chkstk() Normal stack checking off
; __t_rst_chkstk() back on again
;
; __t_sus_chkstk() Suspend stack checking temporarily
; __t_rst_chkstk() restore it again.
;
; Turn off Microsoft stack checking by overwriting the first
; 5 bytes of __chkstk with an absolute jump to mychkstk.
; This is a kludge but I can't get the Microsoft compiler
; to link my own version of __chkstk, even when I use the
; source file that they supply.
chg_chkstk PROC NEAR
mov bx,OFFSET __chkstk
mov ah,BYTE PTR cs:[bx+0]
mov BYTE PTR op,ah
mov ax,WORD PTR cs:[bx+1]
mov WORD PTR off,ax
mov ax,WORD PTR cs:[bx+3]
mov WORD PTR segm,ax
mov BYTE PTR cs:[bx+0],0EAH ; EA=JMP
mov WORD PTR cs:[bx+1],OFFSET mychkstk ; offset
mov WORD PTR cs:[bx+3],cs ; segment
mov cs:chk_on,1 ; Enable stack checking
ret
chg_chkstk ENDP
rst_chkstk PROC NEAR
mov bx,OFFSET __chkstk
mov ah,BYTE PTR op
mov BYTE PTR cs:[bx+0],ah
mov ax,WORD PTR off
mov WORD PTR cs:[bx+1],ax
mov ax,WORD PTR segm
mov WORD PTR cs:[bx+3],ax
ret
rst_chkstk ENDP
__t_sus_chkstk PROC NEAR
mov cs:chk_on,0
ret
__t_sus_chkstk ENDP
__t_rst_chkstk PROC NEAR
mov cs:chk_on,1
ret
__t_rst_chkstk ENDP
;------------------------------------------------------------
; On entry AX holds the number of bytes required for local
; variables. Chkstk normally checks the stack and, at the
; same time, finishes setting up the stack frame by
; subtracting the contents of ax from the stack pointer.
;
mychkstk PROC NEAR
mov cx,cs:chk_on ; If stack checking disabled at
or cx,cx ; run time, skip past the actual
jz nocheck ; test.
mov cx,_T_active
add cx,44 ; Offset to stack base + 4
cmp sp,cx ; if( sp <= stack_base )
jbe stack_err
nocheck:
pop cx ; cx = return address
sub sp,ax ; finish setting up stack frame
jmp cx ; ret to caller w/o modifying stack.
stack_err: ; Return address still on the stack
mov ax,-9
push ax
call _t_stop ; Shouldn't return
mov cx,0
jmp cx ; Panic abort to DOS
mychkstk ENDP
_TEXT ENDS
END