📄 tskdos.asm
字号:
xor ax,ax
mov es,ax
;
assume es:intseg
;
; Restore interrupt entries
;
cli
test tsk_instflags,IFL_VIDEO
jz rem_novid2
mov ax,savvidoff
mov vidoff,ax
mov ax,savvidseg
mov vidseg,ax
;
rem_novid2:
test tsk_instflags,IFL_DISK
jz rem_nodsk2
mov ax,savdiskoff
mov diskoff,ax
mov ax,savdiskseg
mov diskseg,ax
mov ax,savfdiskoff
mov fdiskoff,ax
mov ax,savfdiskseg
mov fdiskseg,ax
;
rem_nodsk2:
mov ax,savtermoff
mov termoff,ax
mov ax,savtermseg
mov termseg,ax
;
mov ax,savdosoff
mov idosoff,ax
mov ax,savdosseg
mov idosseg,ax
;
mov ax,savidleoff
mov idleoff,ax
mov ax,savidleseg
mov idleseg,ax
;
mov ax,savcsectoff
mov csectoff,ax
mov ax,savcsectseg
mov csectseg,ax
;
mov ax,savabsreadoff
mov absreadoff,ax
mov ax,savabsreadseg
mov absreadseg,ax
;
mov ax,savabswriteoff
mov abswriteoff,ax
mov ax,savabswriteseg
mov abswriteseg,ax
;
mov ax,savkeepoff
mov keepoff,ax
mov ax,savkeepseg
mov keepseg,ax
;
IF (DEBUG AND DEB_DOSTRBUF)
mov ax,savmuxoff
mov muxoff,ax
mov ax,savmuxseg
mov muxseg,ax
ENDIF
;
IF DEBUG AND DEB_DOSTRBUF
mov ax,savdpmioff
mov dpmioff,ax
mov ax,savdpmiseg
mov dpmiseg,ax
ENDIF
;
sti
;
pop es
IFDEF LOAD_DS
pop ds
ENDIF
ret
;
assume es:nothing
;
tsk_remove_dos endp
;
;
;---------------------------------------------------------------------------
;---------------------------------------------------------------------------
;
;
; INT 10: Video BIOS interrupt
;
@videntry proc far
;
call tsk_switch_stack
callp request_cresource,<<ds,#video>,0,0>
mov ax,caller_flags[bp]
mov vid_flags,ax
call tsk_old_stack
pushf
cli
call savvid
call tsk_switch_stack
mov ax,vid_flags
mov caller_flags[bp],ax
callp release_resource,<<ds,#video>>
iret
;
@videntry endp
;
;---------------------------------------------------------------------------
;
;
; INT 13 and INT 40: Disk I/O BIOS interrupt
;
@diskentry proc far
;
call tsk_switch_stack
test dl,80h ; fixed disk ?
jz disk_floppy ; jump if not
callp request_cresource,<<ds,#hdisk_io>,0,0>
call tsk_old_stack
pushf
cli
call savdisk
call tsk_switch_stack
callp release_resource,<<ds,#hdisk_io>>
mov ax,entry_flags[bp]
mov caller_flags[bp],ax
iret
;
disk_floppy:
callp request_cresource,<<ds,#fdisk_io>,0,0>
call tsk_old_stack
pushf
cli
call savdisk
call tsk_switch_stack
callp release_resource,<<ds,#fdisk_io>>
mov ax,entry_flags[bp]
mov caller_flags[bp],ax
iret
;
@diskentry endp
;
@fdiskentry proc far
;
call tsk_switch_stack
callp request_cresource,<<ds,#fdisk_io>,0,0>
call tsk_old_stack
pushf
cli
call savfdisk
call tsk_switch_stack
callp release_resource,<<ds,#fdisk_io>>
mov ax,entry_flags[bp]
mov caller_flags[bp],ax
iret
;
@fdiskentry endp
;
;---------------------------------------------------------------------------
;
; Stack-Offsets relative to BP
;
d_func = -2
;
;---------------------------------------------------------------------------
;
; INT 25: Absolute Disk Read
;
; This interrupt is channeled through the normal DOS-function
; processing, with function = 0x25 and special flag set.
; It is re-translated later after the necessary resources
; have been requested. INT 25 is handled like a function > 0C.
; Interrupts 25 und 26 leave the flag-word on the stack.
; Since flags are removed in normal processing, the flag-word
; has to be duplicated on the stack here.
;
absread_int:
sti
push bp ; reserve space
push bp ; save BP
mov bp,sp
push ax
mov ax,4[bp] ; Move return offset, segment down
mov 2[bp],ax
mov ax,6[bp]
mov 4[bp],ax
mov ax,8[bp] ; duplicate flags
mov 6[bp],ax
pop ax
pop bp
call tsk_switch_stack
mov ax,2501h
mov cx,ax
jmp dosentry_2
;
;
;---------------------------------------------------------------------------
;
; INT 26: Absolute Disk Write
;
; This interrupt is channeled through the normal DOS-function
; processing, with function = 0x26 and special flag set.
; It is re-translated later after the necessary resources
; have been requested. INT 26 is handled like a function > 0C.
; Interrupts 25 und 26 leave the flag-word on the stack.
; Since flags are removed in normal processing, the flag-word
; has to be duplicated on the stack here.
;
abswrite_int:
sti
push bp ; reserve space
push bp ; save BP
mov bp,sp
push ax
mov ax,4[bp] ; Move return offset, segment down
mov 2[bp],ax
mov ax,6[bp]
mov 4[bp],ax
mov ax,8[bp] ; duplicate flags
mov 6[bp],ax
pop ax
pop bp
call tsk_switch_stack
mov ax,2601h
mov cx,ax
jmp short dosentry_2
;
;---------------------------------------------------------------------------
;
; INT 27: Terminate But Stay Resident Interrupt
;
; This interrupt is translated to INT 21, function 31.
;
keep_int:
call tsk_switch_stack
;
add dx,0fh ; last addr + 0f to round
sub dx,caller_cs[bp] ; minus CS (= PSP)
mov cl,4
shr dx,cl ; div 16 = paragraphs
mov ax,3100h ; Keep process
mov save_ax[bp],ax
mov cx,ax
jmp short dosentry_2
;
;---------------------------------------------------------------------------
;
; INT 20: Terminate Program interrupt
;
; This interrupt is translated to INT 21, function 4c.
;
terminate_int:
call tsk_switch_stack
mov ax,4c00h
mov save_ax[bp],ax
mov cx,ax
jmp short dosentry_2
;
;---------------------------------------------------------------------------
;
; INT 21: DOS-Interrupt
;
@dosentry proc far
;
; First, check for those special DOS functions that may be called
; even if DOS is busy. We don't want to block anyone from making
; those calls, lest we might kill the system.
;
cmp ah,33h ; set/get break flag
je non_block
cmp ah,50h ; set PSP
je non_block
cmp ah,51h ; get PSP
je non_block
cmp ah,62h
je non_block
cmp ah,64h
jne blocking
non_block:
jmp savdos
;
blocking:
call tsk_switch_stack
xor cl,cl
mov ch,ah
;
dosentry_2:
IF DEBUG AND (DEB_DOSTRACE OR DEB_DOSTRBUF)
push ax
push bx
push es
push si
cli
mov bx,tr_ptr
mov tr_buffer.tr_ax[bx],ax
mov ax,save_bx[bp]
mov tr_buffer.tr_bx[bx],ax
mov ax,save_ds[bp]
mov tr_buffer.tr_ds[bx],ax
les si,tsk_glob_rec.current_task
mov tr_buffer.tr_tcb_o[bx],si
mov tr_buffer.tr_tcb_s[bx],es
mov al,es:t_indos[si]
mov tr_buffer.tr_tindos[bx],al
les si,tsk_glob_rec.dos_vars
mov ax,es:[si+psp_offset] ; current PSP
mov tr_buffer.tr_psp[bx],ax
les si,in_error
mov al,byte ptr es:[si]
mov tr_buffer.tr_inerr[bx],al
les si,tsk_glob_rec.dos_in_use
mov al,byte ptr es:[si]
mov tr_buffer.tr_indos[bx],al
mov al,idle_active
mov tr_buffer.tr_idle[bx],al
xor al,al
mov tr_buffer.tr_flags[bx],al
cmp lower_dos.rcount,0
je trw_nolo
or tr_buffer.tr_flags[bx],1
mov ax,word ptr lower_dos.rowner
cmp tr_buffer.tr_tcb_o[bx],ax
jne trw_nolo
mov ax,word ptr lower_dos.rowner + 2
cmp tr_buffer.tr_tcb_s[bx],ax
jne trw_nolo
or tr_buffer.tr_flags[bx],2
trw_nolo:
cmp upper_dos.rcount,0
je trw_noup
or tr_buffer.tr_flags[bx],4
mov ax,word ptr upper_dos.rowner
cmp tr_buffer.tr_tcb_o[bx],ax
jne trw_noup
mov ax,word ptr upper_dos.rowner + 2
cmp tr_buffer.tr_tcb_s[bx],ax
jne trw_noup
or tr_buffer.tr_flags[bx],8
trw_noup:
IF DEBUG AND DEB_DOSTRBUF
add bx,TYPE trrec
cmp bx,TR_ENTRIES * TYPE trrec
jb trw_nowrap
xor bx,bx
trw_nowrap:
mov tr_ptr,bx
inc tr_count
ENDIF
pop si
IF DEBUG AND DEB_DOSTRACE
push cx
push dx
callp tsk_vcprintf,<<ds,#tr_string>,<ds,/tr_buffer[bx]>>
pop dx
pop cx
ENDIF
sti
pop es
pop bx
pop ax
ENDIF
;
push cx ; BP-2: func in CH, special flag in CL
or cl,cl
jnz dosent_x ; no function check if special
;
; Check if this is a special 'get dos version' call to determine
; if CTask is resident.
;
; A special call has
;
; AX = 3000h
;
; BX = 1234h - Get global variable block address
; then
; DS:DX = pointer to version string
; or
; BX = 1235h - CTask internal function
; then
; CX = function code
;
; Function codes for internal functions:
;
; 2300h Schedule
; 2301h Yield
;
cmp ax,3000h
jne no_spdos
cmp bx,1234h
jb no_spdos
je get_globvars
cmp bx,1235h
ja no_spdos
cmp save_cx[bp],MIN_SPFUNC
jb no_spdos
cmp save_cx[bp],MAX_SPFUNC
ja no_spdos
call @special_function
jmp short spec_ret
;
get_globvars:
cmp dx,0fff0h
jae no_spdos
push ds
mov si,dx
mov ds,save_ds[bp]
mov di,offset tsk_glob_rec
mov cx,8
repe cmpsb
pop ds
jz is_spdos
jmp short no_spdos
;
; Special version call returns global variable block address
; in BX (offset) and CX (segment).
;
is_spdos:
mov save_bx[bp],offset tsk_glob_rec
mov save_cx[bp],@CTASK_DATA
;
spec_ret:
add sp,2
call tsk_old_stack
mov ax,cs:dos_version
clc
iret
;
;---------------------------------------------------------------------------
;
;
no_spdos:
mov ax,d_func[bp]
or ah,ah ; terminate?
jne dosent_x
mov save_ax[bp],4c00h ; translate to fn 4c, retcode 0
mov d_func[bp],4c00h
;
; Now the real fun begins.
;
dosent_x:
sti ; Interrupts allowed now
;
; DL is used as an "emergency" marker. If nonzero, no resources
; are to be requested, and the in-dos flag is not to be checked.
; There is an "emergency" if the task is marked as owning
; DOS resources, but re-enters INT 21.
;
xor dl,dl
les bx,tsk_glob_rec.current_task
test es:t_indos[bx],OWN_UPPER OR OWN_LOWER
jz no_reenter ; no trouble if task doesn't own DOS
;
call @dosbusy ; this sets DL nonzero if busy
jnz no_reenter ; Don't release resources if busy
;
; If the task owns DOS resources, but DOS is not busy, something
; strange is going on (this case should have been handled by the
; 'schedent' routine). Anyway, we assume that DOS is right about
; not being busy, and release the resources. Although the resources
; will be requested again a few instructions later, this is sensible
; to give other tasks that might be waiting on the resource a chance
; to execute.
;
call @relres
xor dl,dl
;
; The preliminaries are done with, we now have to distinguish
; between functions 00-0C and 0D-FF.
;
no_reenter:
mov ax,d_func[bp]
cmp ah,0ch
jbe lower_funcs
jmp upper_funcs
;
;
; Functions 00-0C
;
lower_funcs:
;
; first, request the "lower_dos" resource unless this is an emergency.
;
or dl,dl
jnz lower_emergency
callp request_resource,<<ds,#lower_dos>,0,0>
;
; we have it, now let's get the upper_dos resource, too
;
callp request_resource,<<ds,#upper_dos>,0,0>
;
les bx,tsk_glob_rec.current_task
mov es:t_indos[bx],OWN_UPPER or OWN_LOWER
;
; both resources gained, now we may execute the function if dos is free
;
call @wait_dos_free
;
; Set the scheduler entry function
;
cli
mov word ptr es:sched_ent_func[bx],offset @schedent
mov word ptr es:sched_ent_func+2[bx],cs
sti
;
lower_emergency:
add sp,2
push caller_flags[bp]
popf
call tsk_old_stack
;
calldos ; execute function
;
; Now we have to release the resources, unless DOS still indicates
; that it is busy. This would indicate that a critical error has
; occurred, and DOS processing is not really complete.
;
call tsk_switch_stack
;
call @dosbusy
jnz no_relc ; return if DOS still busy
;
; Clear the flags in the TCB, and the scheduler entry function.
;
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>>
callp release_resource,<<ds,#lower_dos>>
;
; All done, restore registers and return.
;
no_relc:
cli
mov ax,entry_flags[bp]
mov caller_flags[bp],ax
iret
;
;--------------------------------------------------------------------------
;
; Functions 0D and above
;
upper_funcs:
;
; first, request the "upper_dos" resource unless this is an emergency.
;
or dl,dl
jnz upper_emergency
;
callp request_resource,<<ds,#upper_dos>,0,0>
;
les bx,tsk_glob_rec.current_task
mov es:t_indos[bx],OWN_UPPER
;
; resource gained, now we may execute the function if dos is free
;
call @wait_dos_free
;
; Set the scheduler entry function
;
cli
mov word ptr es:sched_ent_func[bx],offset @schedent
mov word ptr es:sched_ent_func+2[bx],cs
sti
;
upper_emergency:
cmp byte ptr d_func[bp],0
jne no_term
mov ax,save_ax[bp]
cmp ah,31h ; terminate resident?
jne ckfunc1
jmp term_resident
ckfunc1:
cmp ax,4b00h ; spawn new process?
jne ckfunc2
jmp terminate
ckfunc2:
cmp ah,4ch ; terminate program?
jne no_term
jmp terminate
;
no_term:
;
; Filter special-functions 25/26 (Absolute Read/Write)
;
pop ax
cmp ax,2501h
jne uf_exec1
push caller_flags[bp]
popf
call tsk_old_stack
pushf
cli
call cs:savabsread
pop cs:temp_1 ; remove flags
jmp short uf_complete
;
uf_exec1:
cmp ax,2601h
jne uf_exec2
push caller_flags[bp]
popf
call tsk_old_stack
pushf
cli
call cs:savabswrite
pop cs:temp_1 ; remove flags
jmp short uf_complete
;
uf_exec2:
push caller_flags[bp]
popf
call tsk_old_stack
;
calldos ; execute function
;
; Now we have to release the resources, unless DOS still indicates
; that it is busy. This would indicate that a critical error has
; occurred, and DOS processing is not really complete.
; However, if we were called from INT 28, DOS must still be busy,
; so we only check the in_error flag.
;
uf_complete:
call tsk_switch_stack
;
cmp idle_active,0
jnz uf_nobsychk ; don't check busy if INT 28 call
les bx,tsk_glob_rec.dos_in_use
cmp es:byte ptr [bx],0
jne no_relc_uf ; don't release if busy
;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -