⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 tskstck.asm

📁 一个多任务操作系统CTask的源代码 用C语言编写
💻 ASM
字号:
;
;	--- Version 2.2 91-05-21 19:25 ---
;
;	CTask - Local Stack Switch handler module.
;
;	Public Domain Software written by
;		Thomas Wagner
;		Ferrari electronic Gmbh
;		Beusselstrasse 27
;		D-1000 Berlin 21
;		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 callers flags at offset 4.
;
;	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.
;
;	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.
;
;	Version 2.1 slightly changes the handling of flag restoration
;	on auto-backswitch. The old algorithm restored the caller flags
;	on entry to the backswitch routine, which caused problems with
;	debuggers if the interrupted code was being single-stepped.
;	Now the original flags always will be restored on exit of the
;	back-switch, regardless of the return used (IRET or RET 2).
;	To modify the flags returned, you have to explicitly modify
;	the caller_flags field in the saved register area.
;
	name	tskstck
;
	include	tsk.mac
	include	tskdeb.h
;
	.tsk_model
;
	Pubfunc	tsk_switch_stack
	Pubfunc	tsk_old_stack
;
	IF	DEBUG AND DEB_FLASHERS
	Locext	tsk_inccdis
	extrn	tsk_debflash: word
	extrn	tsk_dtposn: dword
	ENDIF
;
;
STACKSIZE	=	512	; local stack size (bytes)
NUM_STACKS	=	8	; Number of local stacks
;
	IF	FAR_STACKS
ctask_stacks	segment word public 'CTASK_STACKS'
	ELSE
	.tsk_data
	ENDIF
;
lstacks	label	word
	db	NUM_STACKS * STACKSIZE dup (?)
;
	IF	FAR_STACKS
ctask_stacks	ends
	.tsk_data
	ENDIF
;
	IF	NOT ROM_CODE
;
	.tsk_edata
	.tsk_code
;
sseg	equ	<cs>
	ENDIF
;
stack_full	dw	0	; count 'all stacks in use' events
	IF	DEBUG AND DEB_FLASHERS
usecnt	db	0
	ENDIF
	EVEN
;
;
	IF	ROM_CODE
r_ds		dw	?
	ENDIF
r_ss		dw	?
r_sp		dw	?
r_bx		dw	?
r_cx		dw	?
r_bp		dw	?
call_ip		dw	?
call_cs		dw	?
retaoff		dw	?
	IF	LOCALS_FAR
retaseg		dw	?
	ENDIF
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 segment.
;
stacks	label	word
xst	=	offset lstacks + STACKSIZE
	rept	NUM_STACKS
	dw	xst
xst	=	xst + STACKSIZE
	endm
;
	IF	ROM_CODE
;
	.tsk_edata
	.tsk_code
;
sseg	equ	<ds>
	ENDIF
;
tsk_dgroup	dw	@CTASK_DATA
;
	IF	FAR_STACKS
stackseg	dw	SEG ctask_stacks
	ELSE
stackseg	equ	<tsk_dgroup>
	ENDIF
;
;
Localfunc tsk_switch_stack
;
	IF	ROM_CODE
	push	ds
	mov	ds,cs:tsk_dgroup
	pop	r_ds
	ENDIF
	pushf
	cli
	pop	sseg:sflags
	pop	sseg:retaoff		; return address
	IF	LOCALS_FAR
	pop	sseg:retaseg
	ENDIF
	mov	sseg:r_bx,bx		; save bx & cx in CS
	mov	sseg:r_cx,cx
	mov	sseg:r_bp,bp		; save BP
	mov	bp,sp
	mov	bx,[bp]			; get caller's IP
	mov	sseg:call_ip,bx
	mov	bx,2[bp]		; get caller's CS
	mov	sseg: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 sseg:[bx],0	; in use ?
	jne	st_found		; jump if free
	inc	bx
	inc	bx
	loop	stlp
;
;	No unused stack, continue on caller's stack
;
	IF	DEBUG AND DEB_FLASHERS
	push	ds
	mov	ds,cs:tsk_dgroup
	cmp	tsk_debflash,0
	je	debdd0
	push	ax
	mov	ax,DEBP_CNTSTOFL
	call	tsk_inccdis
	pop	ax
debdd0:
	pop	ds
	ENDIF
	inc	sseg:stack_full
	xor	bx,bx
	jmp	short st_old
;
;	Stack found, perform switch
;
st_found:
	mov	sseg:r_ss,ss		; save SS/SP
	mov	sseg:r_sp,sp
	mov	ss,cs:stackseg		; load new SS/SP
	mov	sp,sseg:[bx]
	mov	cx,sp			; save new SP value
	mov	word ptr sseg:[bx],0	; mark stack in use
	push	sseg:r_ss			; push old SS/SP
	push	sseg:r_sp
st_old:
	push	sseg:r_bx
	push	sseg: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	sseg:r_bp
	IF	ROM_CODE
	push	r_ds
	ELSE
	push	ds
	ENDIF
	push	es
;
	push	bp			; push caller's flags
	push	sseg:call_cs		; push caller's CS
	push	sseg:call_ip		; push caller's IP
;
	push	sseg:sflags		; push entry flags
	push	cs			; and special return
	mov	cx,offset @stsw_retn
	push	cx
	mov	bx,sseg:r_bx		; restore regs bx,cx
	mov	cx,sseg:r_cx
	mov	bp,sp			; set BP to stack bottom
	IF	LOCALS_FAR
	push	sseg:retaseg
	ENDIF
	push	sseg:retaoff		; push retaddr on new stack
	cld
	sti
	mov	ds,cs:tsk_dgroup
	mov	es,cs:tsk_dgroup
	IF	DEBUG AND DEB_FLASHERS
	cmp	slot_idx[bp],0
	je	debdd1
	cmp	tsk_debflash,0
	je	debdd1
	inc	sseg:usecnt
	push	ax
	push	ds
	push	si
	mov	al,sseg:usecnt
	add	al,'0'
	lds	si,tsk_dtposn
	mov	DEBP_STACKNUM[si],al
	pop	si
	pop	ds
	pop	ax
debdd1:
	ENDIF
	ret				; restore flags & return
;
tsk_switch_stack	endp
;
;
Localfunc tsk_old_stack
;
	pushf				; save flags
	cli
	IF	ROM_CODE
	mov	ds,cs:tsk_dgroup
	ENDIF
	pop	sseg:sflags
	pop	sseg:retaoff		; return address
	IF	LOCALS_FAR
	pop	sseg:retaseg
	ENDIF
	add	sp,12			; discard dummy return & flags
;
	IF	DEBUG AND DEB_FLASHERS
	mov	ds,cs:tsk_dgroup
	cmp	slot_idx[bp],0
	je	debdd2
	cmp	tsk_debflash,0
	je	debdd2
	dec	sseg:usecnt
	mov	al,sseg:usecnt
	add	al,'0'
	lds	si,tsk_dtposn
	mov	DEBP_STACKNUM[si],al
	IF	ROM_CODE
	mov	ds,cs:tsk_dgroup
	ENDIF
debdd2:
	ENDIF
;
	pop	es			; restore regs
	IF	ROM_CODE
	pop	r_ds
	ELSE
	pop	ds
	ENDIF
	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	sseg:[bx],cx		; reset stack slot
	pop	cx
	pop	bx
	pop	sseg:r_sp
	pop	ss   			; old SS
	mov	sp,sseg:r_sp
old_ret:
	IF	LOCALS_FAR
	push	sseg:retaseg
	ENDIF
	push	sseg:retaoff		; push retaddr on old stack
	push	sseg:sflags
	IF	ROM_CODE
	mov	ds,r_ds
	ENDIF
	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
;
	cli
	add	sp,4			; discard caller CS/IP
	IF	ROM_CODE
	mov	ds,cs:tsk_dgroup
	ENDIF
	pop	sseg:sflags		; store caller's flags in CS
;
	IF	DEBUG AND DEB_FLASHERS
	mov	ds,cs:tsk_dgroup
	cmp	slot_idx[bp],0
	je	debdd3
	cmp	tsk_debflash,0
	je	debdd3
	dec	sseg:usecnt
	mov	al,sseg:usecnt
	add	al,'0'
	lds	si,tsk_dtposn
	mov	DEBP_STACKNUM[si],al
	IF	ROM_CODE
	mov	ds,cs:tsk_dgroup
	ENDIF
debdd3:
	ENDIF
;
	pop	es			; restore regs
	IF	ROM_CODE
	pop	r_ds
	ELSE
	pop	ds
	ENDIF
	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	sseg:[bx],cx		; reset stack slot
	pop	cx
	pop	bx
	pop	sseg:r_sp
	pop	ss   			; old SS
	mov	sp,sseg:r_sp
retn_ret:
	push	bp
	mov	bp,sp
	push	ax
	mov	ax,sseg:sflags		; push flags on old stack
	mov	6[bp],ax
	pop	ax
	pop	bp
	IF	ROM_CODE
	mov	ds,r_ds
	ENDIF
	iret
;
@stsw_retn	endp
;
	.tsk_ecode
	end

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -