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

📄 tskdos.asm

📁 一个嵌入式实时操作系统源码
💻 ASM
📖 第 1 页 / 共 3 页
字号:
uf_nobsychk:
	les	bx,in_error
	cmp	es:byte ptr [bx],0
	jnz	no_relc_uf		; don't release if in error
;
	les	bx,tsk_glob_rec.current_task
	cli
	mov	es:t_indos[bx],0
	mov	word ptr es:sched_ent_func[bx],0
	mov	word ptr es:sched_ent_func+2[bx],0
	sti
;
	callp	release_resource,<<ds,#upper_dos>>
;
;	All done, restore registers and return.
;
no_relc_uf:
	cli
	mov	ax,entry_flags[bp]
	mov	caller_flags[bp],ax
	iret
;
;--------------------------------------------------------------------------
;
;	Terminate, TSR and Spawn calls go directly to DOS.
;	TSR has to reset the exit address if it's the PSP of the 
;	current group, so the group is not deleted.
;
term_resident:
	les	bx,tsk_glob_rec.dos_vars
	mov	ax,es:[bx+psp_offset]		; current PSP
	les	bx,tsk_glob_rec.current_task
	les	bx,es:tgroup[bx]
	cmp	es:gcreate_psp[bx],ax
	jne	terminate
	push	ds
	mov	ds,ax
	mov	ax,word ptr es:grp_exit_addr[bx]
	mov	word ptr ds:psp_exit_addr,ax
	mov	ax,word ptr es:grp_exit_addr+2[bx]
	mov	word ptr ds:psp_exit_addr+2,ax
	pop	ds
;
terminate:
	add	sp,2
	push	caller_flags[bp]
	popf
	call	tsk_old_stack
	cli
	jmp	cs:savdos
;
@dosentry	endp
;
;--------------------------------------------------------------------------
;
;	'dosbusy' checks the DOS busy flags.
;
;	Entry:	-
;	Exit:	DL is nonzero if DOS is busy.
;
@dosbusy	proc	near
;
	push	bx
	push	es
	les	bx,in_error
	mov	dl,es:byte ptr [bx]
	les	bx,tsk_glob_rec.dos_in_use
	or	dl,es:byte ptr [bx]
	pop	es
	pop	bx
	ret
;
@dosbusy	endp
;
;--------------------------------------------------------------------------
;
;	Wait_dos_free uses busy waiting (calling _yield) in case
;	some other background program has entered DOS without going
;	through our INT 21 interface.
;
@wait_dos_free	proc	near
	push	es
	push	bx
;
in_use_loop:
	les	bx,in_error
	cmp	byte ptr es:[bx],0
	jne	is_in_use		; wait if in_error set
;
	cmp	idle_active,0		; idle interrupt active?
	je	ck_inuse		; check for flag if no
	pop	bx
	pop	es
	ret				; else return immediately
;
ck_inuse:
	les	bx,tsk_glob_rec.dos_in_use
	cmp	byte ptr es:[bx],0
	jne	is_in_use
	pop	bx
	pop	es
	ret
;
is_in_use:
	call	yield
	jmp	in_use_loop
;
@wait_dos_free	endp
;
;----------------------------------------------------------------------------
;
;	'relres' releases the DOS-resources of a task.
;
;	Entry:
;		ES:BX = TCB pointer
;
@relres	proc	near
;
	test	es:t_indos[bx],OWN_UPPER
	jz	rel_lower
	xor	es:t_indos[bx],OWN_UPPER
	push	bx
	push	es
	callp	release_resource,<<ds,#upper_dos>>
	pop	es
	pop	bx
;
rel_lower:
	test	es:t_indos[bx],OWN_LOWER
	jz	rel_exit
	xor	es:t_indos[bx],OWN_LOWER
	push	bx
	push	es
	callp	release_resource,<<ds,#lower_dos>>
	pop	es
	pop	bx
;
rel_exit:
	ret
;
@relres	endp
;
;----------------------------------------------------------------------------
;
;	The 'schedent' function is called by the scheduler if the
;	scheduler is entered and the current task owns one of the
;	DOS resources.
;	This routine checks whether the DOS busy flags are clear now,
;	which would mean that the task left DOS without passing through
;	the return address. If that's the case, we release the resources.
;
;	The only catch is that there is a race condition if we just check
;	the busy flags. There is a time slot where the function is set in
;	the TCB, but the busy flag is clear because DOS has not yet been
;	entered. Since we have no control over what will happen, and how 
;	long it will take to reach the point where the in_use flag is 
;	incremented, we can't simply disable preemption. So what we have
;	to do is to wait for some other indication that DOS has begun
;	executing the request, and mark this in the TCB. In all versions
;	starting at 3.1, DOS will call the 'critical section' INT 2A
;	with AX=8200 on functions > 0C after incrementing the in_use flag.
;	We also have some indication that DOS is active if the 'idle'
;	INT 28 is called, or if the in_use flag is set when we get here.
;
;	Entry:
;		DS	CTask data segment
;		BX	Global data block offset
;		ES:DI	Task control block
;
@schedent	proc	far
;
	call	@dosbusy		; DOS still busy ?
	jz	schedent_relres		; release resources if not busy
	or	es:t_indos[di],DOS_ENTERED
	ret
;
schedent_relres:	
	test	es:t_indos[di],DOS_ENTERED
	jz	schedent_ret		; don't release if DOS not yet entered
;
	mov	bx,di
	call	@relres
;
schedent_ret:
	ret
;
@schedent	endp
;
;----------------------------------------------------------------------------
;
;	INT 28: DOS Idle Interrupt
;
@idleentry	proc	far
;
	call	tsk_switch_stack
;
;	check the in_use flag. If it's set, set the DOS_ENTERED flag
;	in the current TCB.
;
	les	bx,tsk_glob_rec.dos_in_use
	cmp	byte ptr es:[bx],0
	je	no_entermark
;
	les	bx,tsk_glob_rec.current_task
	or	es:t_indos[bx],DOS_ENTERED
;
;	Check if someone is waiting for upper_dos. If not, we can return
;	immediately.
;
no_entermark:
	les	bx,upper_dos.rwaiting.q_first
	test	es:q_kind[bx],Q_HEAD
	jnz	idle_exit
;
;	Also make sure this is not a second invocation of INT 28, and
;	that the in_error flag is not set.
;	Normally, this should never happen, but better safe than sorry.
;
	cmp	idle_active,0
	jne	idle_exit
	les	bx,in_error
	cmp	byte ptr es:[bx],0
	jne	idle_exit
;
	inc	idle_active
;
;	someone is waiting, let's please him by releasing the resource.
;	temporarily increase priority
;
	les	bx,tsk_glob_rec.current_task
	push	es:cqueue.q_el.q_prior[bx]
	push	es:cqueue.q_el.q_ini_prior[bx]
	mov	es:cqueue.q_el.q_prior[bx],0ffffh
	mov	es:cqueue.q_el.q_ini_prior[bx],0ffffh
	push	bx
	push	es
;
;	release resource & request it again
;
	callp	release_resource,<<ds,#upper_dos>>
	callp	request_resource,<<ds,#upper_dos>,0,0>
;
;	ready, restore priority
;
	cli
	pop	es
	pop	bx
	pop	es:cqueue.q_el.q_ini_prior[bx]
	pop	es:cqueue.q_el.q_prior[bx]
;
	mov	idle_active,0
;
idle_exit:
	push	caller_flags[bp]
	popf
	call	tsk_old_stack
	cli
;
	jmp	cs:savidle		; chain to original interrupt
;
@idleentry	endp
;
;----------------------------------------------------------------------------
;
;	INT 2A: DOS Critical Section Interrupt
;
;	Not documented.
;	Is used by DOS PRINT to mark Critical Regions.
;	Usage by PRINT:
;		AX = 8700 - Begin Critical Region
;				Returns:
;				Carry set if already active.
;		AX = 8701 - End Critical Region
;
;	Other usage in DOS, function unknown:
;		AH = 82 (AL undefined)
;			seems to be called on DOS-Functions > 0C
;		AH = 84 (AL undefined)
;			seems to be called when DOS is idle
;
;	We only handle function number 82 in this version,
;	it is used to mark that DOS has been entered. All functions
;	are passed on to the next in chain.
;
@critsectint	proc	far
;
	cmp	ah,82h
	jne	cs_exit
	push	ds
	push	es
	push	bx
	mov	ds,cs:tsk_dgroup
;
;	check the in_use flag. If it's set, set the DOS_ENTERED flag
;	in the current TCB.
;
	les	bx,tsk_glob_rec.dos_in_use
	cmp	byte ptr es:[bx],0
	je	cs_no_enter
;
	les	bx,tsk_glob_rec.current_task
	or	es:t_indos[bx],DOS_ENTERED
;
cs_no_enter:
	pop	bx
	pop	es
	pop	ds
;
cs_exit:
	jmp	cs:savcsect
;
@critsectint	endp
;
;---------------------------------------------------------------------------
;---------------------------------------------------------------------------
;
term_err_msg	db	0dh,0ah,"Program terminated - CTask uninstalled"
		db	0dh,0ah,'$'
;
group_term_msg	db	0dh,0ah,"Program terminated - Task Group removed"
		db	0dh,0ah,'$'
;
gcb_mixup_err	db	0dh,0ah,"Group chain damaged - System halted"
		db	07h,'$'
;
;---------------------------------------------------------------------------
;
;	tsk_emergency_exit is entered by DOS when a task group exits
;	without releasing the current group.
;	Registers are set up, remove_group is called, and the program
;	is terminated by jumping to the terminate_address.
;
tsk_emergency_exit	proc	far
;
	pushf
	sub	sp,4		; make room for return addr
	push	bp
	mov	bp,sp
	push	ax
	push	bx
	push	cx
	push	dx
	push	si
	push	di
	push	ds
	push	es
	mov	ax,@CTASK_DATA
	mov	ds,ax
;
	les	bx,tsk_glob_rec.current_task[bx]
	les	bx,es:tgroup[bx]
	mov	ax,word ptr es:grp_exit_addr[bx]
	mov	2[bp],ax
	mov	ax,word ptr es:grp_exit_addr+2[bx]
	mov	4[bp],ax
;
	callp	tsk_remove_group,<<es,bx>,0>
;
	mov	dx,offset group_term_msg
        cmp	ax,0
	je	emergency_end
	jb	pg_fatal
;
	les	bx,tsk_glob_rec.current_task[bx]
	les	bx,es:tgroup[bx]
	callp	tsk_kill_group,<<es,bx>>
	call	tsk_remove_tasker
;
	mov	dx,offset term_err_msg
;
emergency_end:
;
	mov	ax,cs
	mov	ds,ax
	mov	ah,9
	int	21h
;
	pop	es
	pop	ds
	pop	di
	pop	si
	pop	dx
	pop	cx
	pop	bx
	pop	ax
	pop	bp
	iret
;
pg_fatal:
	mov	si,offset gcb_mixup_err
	jmp	short fatal_error
;
tsk_emergency_exit	endp
;
;--------------------------------------------------------------------------
;
;	fatal_error can be called if the system can't continue for
;	some reason. It issues an error message and halts the system.
;	SI must point to the '$'-terminated error message.
;
;	tsk_fatal does the same, but assumes C calling sequence and
;	a zero-terminated string.
;
Globalfunc tsk_fatal,<strp: far ptr>
;
	cld
	lds	si,strp
	jmp	short dis_err
;
tsk_fatal	endp
;
fatal_error:
	mov	ax,cs
	mov	ds,ax
;
dis_err:
	IF	IBM
	xor	ax,ax
	int	10h		; re-init display
fatal_loop:
	lodsb
	cmp	al,'$'
	je	fatal_end
	or	al,al
	jz	fatal_end
        mov     bx,7
        mov     ah,14
	int	10h
	jmp	fatal_loop
	ELSE
	mov	dx,si
	mov	ah,9
	int	21h
	ENDIF
fatal_end:
	sti
	jmp	fatal_end
;
;--------------------------------------------------------------------------
;
;	void CGlobalfunc tsk_fatal_pmd (byteptr string, ...)
;
;	tsk_fatal_pmd is only present in "checking" mode.
;	It does a minimal "post mortem dump", and displays the
;	error message passed as parameter.
;	The messages are output to both the primary and secondary 
;	monitor via the "regen" printf routines in tskprf.
;	The system is then halted, this routine never returns.
;
	IF	CHECKING
;
;
CGlobalfunc	tsk_fatal_pmd,<txt: far ptr,argp:far ptr>
;
;	int	3	; uncomment to break to debugger
	push	sp
	push	ss
	push	es
	push	ds
	push	di
	push	si
	push	dx
	push	cx
	push	bx
	push	ax
;
	mov	ds,tsk_dgroup
	callp	preempt_off
	callp	tsk_set_currdis
;
	callp	tsk_rputc,<0ch>
	les	di,txt
	lea	bx,argp
	call	@fatal_dump
;
	callp	tsk_set_dualdis
	or	ax,ax
	jz	no_second
;
	callp	tsk_rputc,<0ch>
	les	di,txt
	lea	bx,argp
	call	@fatal_dump
;
no_second:
	jmp	fatal_end
;
tsk_fatal_pmd	endp
;
;
pmd1	db	0ah
	db	'AX = %04X  BX = %04X  CX = %04X  DX = %04X',0ah
	db	'SI = %04X  DI = %04X  DS = %04X  ES = %04X',0ah
	db	'SS = %04X  SP = %04X  BP = %04X',0ah
	db	'IP = %04X  CS = %04X',0ah,0
pmd2	db	'Current Task = %FP'
	IF	TSK_NAMED
	db	' (%s)'
	ENDIF
	db	0ah,0
pmde	db	'System Halted',0
;
;
@fatal_dump	proc	near
;
	callp	tsk_vrprintf,<<es,di>,<ss,bx>>
	mov	bx,sp
	add	bx,2
	callp	tsk_vrprintf,<<cs,#pmd1>,<ss,bx>>
;
	IF	SINGLE_DATA
	mov	bx,offset tsk_glob_rec
	push	ds
	pop	es
	ELSE
	les	bx,tsk_global
	ENDIF
	les	bx,es:current_task[bx]
	IF	TSK_NAMED
	lea	dx,tname.nname[bx]
	callp	tsk_rprintf,<<cs,#pmd2>,<es,bx>,<es,dx>>
	ELSE
	callp	tsk_rprintf,<<cs,#pmd2>,<es,bx>>
	ENDIF
	callp	tsk_rprintf,<<cs,#pmde>>
	ret
;
@fatal_dump	endp
;
	ENDIF
;
;---------------------------------------------------------------
;
@sp_schedule	proc	near
	call	schedule
	ret
@sp_schedule	endp
;
@sp_yield	proc	near
	call	yield
	ret
@sp_yield	endp
;
;
spfunctab	label	word
	dw	@sp_schedule
	dw	@sp_yield
;
@special_function	proc	near
;
	mov	bx,save_cx[bp]
	xor	bh,bh
	add	bx,bx
	jmp	spfunctab[bx]
;
@special_function	endp
;
;---------------------------------------------------------------
;
	IF	DEBUG AND DEB_DOSTRBUF
;
dpmi_int	proc	far
;
	inc	cs:i31count
	pushf
	call	savdpmi
	pushf
	dec	cs:i31count
	popf
	ret	2
;
dpmi_int	endp
;
	ENDIF
	IF	DEBUG AND DEB_DOSTRBUF
;
multiplex_int	proc	far
;
	inc	cs:i2fcount
	pushf
	call	savmux
	pushf
	dec	cs:i2fcount
	popf
	ret	2
;
multiplex_int	endp
;
dump_dostrace	proc	far
;
	mov	bx,tr_ptr
	mov	cx,TR_ENTRIES
	lea	ax,tr_head
	cmp	tr_count,cx
	jae	dtr_cok
	xor	bx,bx
	mov	cx,tr_count
	or	cx,cx
	jnz	dtr_cok
	lea	ax,tr_none
;
dtr_cok:
	push	bx
	push	cx
	callp	tsk_cprintf,<<ds,#tr_string>>
	pop	cx
	pop	bx
	jcxz	dtr_end
;
dtr_loop:
	push	bx
	push	cx
;
	callp	tsk_vcprintf,<<ds,#tr_string>,<ds,/tr_buffer[bx]>>
;
	pop	cx
	pop	bx
	add	bx,TYPE trrec
	cmp	bx,TR_ENTRIES * TYPE trrec
	jb	dtr_nowrap
	xor	bx,bx
dtr_nowrap:
	loop	dtr_loop
	xor	bx,bx
	mov	tr_ptr,cx
	mov	tr_count,cx
dtr_end:
	ret
;
dump_dostrace	endp
;
	ENDIF
;
	.tsk_ecode
;
	ENDIF
;
        end

⌨️ 快捷键说明

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