mirror of
https://github.com/SEPPDROID/Digital-Research-Source-Code.git
synced 2025-10-24 17:04:19 +00:00
689 lines
20 KiB
Plaintext
689 lines
20 KiB
Plaintext
;*****************************************************
|
||
;*
|
||
;* Dispatch Routines
|
||
;*
|
||
;*****************************************************
|
||
|
||
;=====
|
||
fdisp:
|
||
;=====
|
||
; This entry point used by interrupt routines in XIOS
|
||
; Note: if the XIOS is performing memory protection interrupt
|
||
; handlers must enable O.S. memory before calling the O.S.
|
||
|
||
cli
|
||
push ds ! mov ds,sysdat
|
||
cmp indisp,true ! je nodisp ;if indisp=true then we are
|
||
mov ax_sav,ax ;in the dispatcher and
|
||
mov al,true ! mov indisp,al ;this code is skipped
|
||
mov ax,es ! mov es_sav,ax
|
||
mov ax,rlr ! xchg ax,bx ! mov bx_sav,ax
|
||
mov es,p_uda[bx]
|
||
mov al,true ! mov u_in_int,al
|
||
pop ax ! mov u_ds_sav,ax
|
||
mov al,p_stat[bx]
|
||
mov u_stat_sav,al
|
||
mov p_stat[bx],ps_run
|
||
mov ax,es_sav
|
||
mov u_es_sav,ax
|
||
|
||
; AX in AX_SAV
|
||
; BX in BX_SAV
|
||
; ES in U_ES_SAV
|
||
; DS in U_DS_SAV
|
||
; p_stat in U_STAT_SAV
|
||
jmp intdisp
|
||
;dispatcher will jump to here if
|
||
; u_in_int = true.
|
||
|
||
int_disp_exit: ;interrupts are off
|
||
|
||
; AX in AX
|
||
; BX in BX
|
||
; ES in U_ES_SAV
|
||
; DS in U_DS_SAV
|
||
; p_stat in U_STAT_SAV
|
||
|
||
mov ax_sav,ax
|
||
mov ax,bx ! mov bx_sav,ax
|
||
;check for
|
||
cmp drl,0 ! jnz intdisp ;interrupt occurence
|
||
;on dispatcher exit
|
||
|
||
mov al,false ! mov u_in_int,al
|
||
mov ax,rlr ! mov bx,ax
|
||
mov al,u_stat_sav
|
||
mov p_stat[bx],al
|
||
mov ax,bx_sav ! mov bx,ax
|
||
mov ax,ax_sav
|
||
mov indisp,false
|
||
mov ds,u_ds_sav
|
||
mov es,u_es_sav
|
||
iret
|
||
|
||
nodisp: pop ds
|
||
iret
|
||
|
||
|
||
;========
|
||
farpdisp:
|
||
;========
|
||
; Intermodule pdisp (non-interrupt)
|
||
|
||
call pdisp ! retf
|
||
|
||
;=====
|
||
pdisp:
|
||
;=====
|
||
; Call dispatcher with no special action
|
||
|
||
push bx ! mov bx,rlr
|
||
mov p_stat[bx],ps_run ! pop bx
|
||
;jmp dsptch
|
||
|
||
;======
|
||
dsptch:
|
||
;======
|
||
; The dispatch function looks like a noop to the
|
||
; caller. All flags and registers are maintained.
|
||
; No levels of user stack is used.
|
||
; (jmp dispatch = ret)
|
||
; Interrupt routines enter through fdisp.
|
||
;
|
||
; Dispatch has two (2) arguments:
|
||
; 1. the p_stat field of the process descriptor
|
||
; determines the type of action to perform
|
||
; for this process.
|
||
; 2. the dparam field of the uda is an argument
|
||
; to the action.
|
||
; The main part of the dispatch routine takes the
|
||
; currently running process off the Ready list
|
||
; and jmps to a routine which will put it on some
|
||
; other list depending on the p_stat argument.
|
||
; The subsequent routine will then jump to the
|
||
; scheduler which will do polling of devices and
|
||
; move processes off the dispatch ready list onto
|
||
; the Ready list. The Ready List is maintained
|
||
; in priority order with round-robin scheduling
|
||
; of processes with equivalent priorities. The
|
||
; first process on the ready list will then be
|
||
; switched in.
|
||
|
||
; set indisp flag
|
||
pushf ! cli
|
||
cmp indisp,true ! jne dispin
|
||
popf ! ret
|
||
dispin: mov indisp,true
|
||
pop u_flag_sav
|
||
|
||
; assumming bx=RLR:
|
||
; if PLR=0 and DRL=0 then
|
||
; if p_stat[bx]=PS_RUN then
|
||
; if p_link[bx]=0 or
|
||
; p_prior[p_link[bx]]<>p_prior[bx] then
|
||
; don't do dispatch
|
||
|
||
mov ax_sav,ax
|
||
mov ax,bx ! mov bx_sav,bx
|
||
intdisp:
|
||
cmp plr,0 ! jne dcont ;if Poll list = 0 and
|
||
cmp drl,0 ! jne dcont ;Dsptch Ready list = 0 and
|
||
mov ax,rlr ! mov bx,ax ;(RLR can never be 0 here)
|
||
cmp p_stat[bx],ps_run ! jne dcont ;our status is run and
|
||
cmp p_link[bx],0 ! je no_disp2 ;other PD to ready to run
|
||
mov al,p_prior[bx] ;with an equal priority
|
||
mov bx,p_link[bx] ;THEN skip the dispatch
|
||
cmp al,p_prior[bx] ! je dcont
|
||
no_disp2:
|
||
mov ax,bx_sav ! mov bx,ax
|
||
mov ax,ax_sav
|
||
jmp dext
|
||
|
||
dcont:
|
||
mov u_ss,ss ! mov u_sp,sp
|
||
mov ss,sysdat ! mov sp,offset dsptchtos
|
||
mov ax,bx_sav ! mov bx,ax
|
||
mov ax,ax_sav
|
||
sti
|
||
cld
|
||
; save registers
|
||
; NOTE: We will use DS instead of ES
|
||
; No segment overrides...
|
||
|
||
push es ! pop ds
|
||
mov ds:u_ax,ax
|
||
mov ax,bx ! mov ds:u_bx,ax
|
||
mov ax,cx ! mov ds:u_cx,ax
|
||
mov ax,dx ! mov ds:u_dx,ax
|
||
mov ax,di ! mov ds:u_di,ax
|
||
mov ax,si ! mov ds:u_si,ax
|
||
mov ax,bp ! mov ds:u_bp,ax
|
||
|
||
; Save interrupt vectors 0,1,3,4 not INT 2 which is NMI
|
||
; MP/M-86, CCP/M-86 1.0 on the IBM PC saved NMI
|
||
; Block move first 2
|
||
|
||
xor bx,bx ! mov ds,bx
|
||
mov si,bx ! mov di,offset u_ivectors
|
||
mov dx,4
|
||
mov cx,dx ! rep movsw
|
||
mov cx,dx ! add si,dx ;get next 2
|
||
add di,dx ;skip INT 2 location documented
|
||
rep movsw ;now as reserved word in UDA
|
||
; block move osint,debugint
|
||
|
||
mov si,offset i_os_ip ! mov di,offset u_os_ip
|
||
mov cx,dx ! rep movsw
|
||
mov ds, sysdat
|
||
|
||
; if 8087 emulator user,swap extra vectors
|
||
mov bx,rlr
|
||
test p_sflag[bx],psf_em87
|
||
jz u_disp ; not an emulator user
|
||
push es ! mov ax,ds ; save segment registers
|
||
push cx! push di
|
||
mov cx, em_seg ; move 14 vectors from
|
||
mov si, em_offs ; low memory to uda extension
|
||
mov di, offset u_8087
|
||
mov es, p_uda[bx]
|
||
mov ds,cx
|
||
mov cx, tot_emvecs/2
|
||
rep movsw
|
||
pop di ! pop cx
|
||
pop es ! mov ds,ax ; restore segment registers
|
||
|
||
; swap out userdisp vectors.
|
||
; acts like a nop to non-userdisp processes
|
||
u_disp:
|
||
mov si,rlr
|
||
mov ax,user_save
|
||
callf p_userdisp[si]
|
||
jmps dcont1
|
||
def_emultr: ; this is the default routine for non-userdisp proc's
|
||
retf
|
||
|
||
dcont1: ; take current process off RLR.
|
||
;disable memory for the process
|
||
;we are taking out of context
|
||
;turn off interrupts ?
|
||
;dsp_disabled:
|
||
nop
|
||
mov ax,rlr ! mov si,ax
|
||
mov ax,p_link[si] ! mov rlr,ax
|
||
mov p_link[si],0
|
||
; We are now in NO-MAN's land
|
||
; From now until the end of the
|
||
; switch routine, There is no
|
||
; process in context.
|
||
; SI -> PD just taken out of context.
|
||
; jump to routine for given status
|
||
xor bh,bh ! mov bl,p_stat[si] ! shl bx,1
|
||
jmp cs:dsp_table[bx]
|
||
|
||
org ((offset $)+1) AND 0fffeh
|
||
|
||
dsp_table dw disp_act ;00 - run
|
||
dw disp_act ;01 - (nop)-poll device
|
||
dw delay_act ;02 - delay
|
||
dw disp_act ;03 - (nop)-swap
|
||
dw term_act ;04 - terminate
|
||
dw sleep_act ;05 - sleep
|
||
dw disp_act ;06 - (nop)-dq
|
||
dw disp_act ;07 - (nop)-nq
|
||
dw flag_act ;08 - flag wait
|
||
dw disp_act ;09 - (nop)-ciowait
|
||
dw disp_act ;10 - (nop)-sync
|
||
|
||
sleep_act:
|
||
;---------
|
||
; insert running process into list specified by
|
||
; u_dparam and set p_stat from p_scratch
|
||
; Note: we cannot sleep on the DLR since interrupts are on
|
||
; here, and flag_set can change the DLR
|
||
|
||
mov ax,u_dparam
|
||
mov bx,ax
|
||
push si ! call insert_process
|
||
pop si ! or p_flag[si],pf_resource
|
||
mov al,p_scratch[si] ! mov p_stat[si],al
|
||
jmp schedule
|
||
|
||
delay_act:
|
||
;---------
|
||
; Put the running process on the Delay List. The
|
||
; delay list is built such that any process's
|
||
; remaining delay time is the additive of the delay
|
||
; times of all processes ahead of it plus the # of
|
||
; ticks in it's own p_wait field. At each clock tick
|
||
; the p_wait field of the top process in the list
|
||
; is decremented. If it reaches zero (0), all
|
||
; processes with a zero in the p_wait field are
|
||
; placed on the dispatch ready list.
|
||
; input: SI=pd address
|
||
|
||
cli ;keep flag set from changing
|
||
;if mpm ;TICK, and changing DLR
|
||
; push si ! mov al,io_strtclk
|
||
; call xiosif ! pop si
|
||
;endif
|
||
|
||
;if ccpm
|
||
mov tick,true
|
||
;endif
|
||
|
||
mov bx,(offset dlr)-p_link
|
||
mov cx,u_dparam ! inc cx
|
||
cmp cx,0 ! jne del_lp
|
||
dec cx
|
||
del_lp: mov di,p_link[bx]
|
||
cmp di,0 ! je del_o
|
||
mov ax,p_wait[di]
|
||
cmp ax,cx ! ja del_o
|
||
sub cx,ax ! mov bx,di ! jmps del_lp
|
||
del_o: mov p_link[si],di ! mov p_link[bx],si
|
||
mov p_wait[si],cx
|
||
cmp di,0 ! je del_e
|
||
sub p_wait[di],cx
|
||
del_e: jmp schedule
|
||
|
||
flag_act:
|
||
;--------
|
||
; place running process in flag table to wait
|
||
; for next flag. Note, flag may have been set...
|
||
; input: SI=pd address
|
||
; U_DPARAM=address of Flag entry
|
||
|
||
mov ax,u_dparam ! mov bx,ax
|
||
cli ;protect from flag set
|
||
cmp flg_pd[bx],flag_on ! je gflagon
|
||
mov flg_pd[bx],si ! mov p_link[si],0
|
||
jmp schedule
|
||
gflagon: ; Flag set since wait check
|
||
mov flg_pd[bx],flag_off
|
||
sti
|
||
jmps disp_act
|
||
|
||
term_act:
|
||
;--------
|
||
; Terminate the running process, free memory, free pd, free sync
|
||
; structures. Can only be called by TERMINATE_ENTRY.
|
||
|
||
; input: SI=pd address
|
||
; MEM_SYNC owned by calling process
|
||
|
||
; place PD on rlr for now.
|
||
mov ax,rlr
|
||
mov p_link[si],ax
|
||
mov rlr,si
|
||
|
||
; clean up consoles
|
||
mov cx,f_cioterm ! call osif
|
||
|
||
; clean up memory
|
||
; (we own the MXmemory queue)
|
||
free_nxt:
|
||
mov ax,rlr ! mov si,ax
|
||
mov si,p_mem[si]
|
||
test si,si ! jz end_free
|
||
push ds ! xor cx,cx ! push cx
|
||
push ms_start[si]
|
||
mov ax,ss ! mov ds,ax ! mov dx,sp
|
||
mov cx,f_memfree ! call osif
|
||
pop bx ! pop cx ! pop ds
|
||
jmps free_nxt
|
||
end_free:
|
||
|
||
;release any sync structures
|
||
;after releasing memory
|
||
mov mem_cnt,0 ;and MEM_CNT=1
|
||
;on entry, also own THRD_SYNC
|
||
;so it is safe to call
|
||
;FREEPD below,
|
||
;ASSIGN_SYNC cannot be called
|
||
;with the THRD_SPB
|
||
;SI=terminating process
|
||
mov bx,offset slr - sy_link ;release any sync structures
|
||
t_nsync: ;owned by terminating PD
|
||
mov bx,sy_link[bx]
|
||
test bx,bx ;end of syncs?
|
||
jz t_sync_done
|
||
push bx ;PD cannot be allowed to
|
||
call unsync_entry ;abort if in SY.NEXT
|
||
pop bx
|
||
jmps t_nsync
|
||
|
||
t_sync_done:
|
||
|
||
; take off RLR
|
||
mov si,rlr
|
||
mov ax,p_link[si]
|
||
mov rlr,ax
|
||
mov p_link[si],0
|
||
|
||
cmp si,owner_8087 ;release 8087 if we owned it
|
||
jne t_end ! mov owner_8087,0
|
||
t_end:
|
||
; free up PD
|
||
call freepd ! jmp schedule
|
||
|
||
disp_act:
|
||
;--------
|
||
; place process on RLR
|
||
; input: SI=pd address
|
||
|
||
mov p_stat[si],ps_run
|
||
mov bx,(offset rlr)-p_link
|
||
call insert_process ! jmp schedule
|
||
|
||
;==============
|
||
insert_process:
|
||
;==============
|
||
;
|
||
; put PD# in list ordered by priority
|
||
;
|
||
; entry: BX = list root
|
||
; SI = pd number
|
||
; exit: SI is preserved
|
||
; interrupt state as on entry
|
||
|
||
mov cx,pflag[si] ! and cx,pf_resource
|
||
;if a process was waiting
|
||
ins_npd: mov di,p_link[bx] ;on a resource, insert
|
||
test di,di ! jz ins_out ;it ahead of equal priority
|
||
mov al,p_prior[di] ;process
|
||
cmp al,p_prior[si]
|
||
ja ins_out ;lowest priority first
|
||
jb ins_nxt ;higher - keep going down list
|
||
jcxz ins_nxt ;equal and not resource
|
||
jmps ins_out ;equal & resource
|
||
ins_nxt: mov bx,di ! jmp ins_npd
|
||
ins_out: jcxz ins_exit
|
||
and p_flag[si],not pf_resource
|
||
ins_exit:
|
||
mov p_link[si],di ! mov p_link[bx],si ! ret
|
||
|
||
;========
|
||
schedule:
|
||
;========
|
||
; poll all required devices and place any ready
|
||
; processes on the Ready List
|
||
|
||
;we can enable interrupts now.
|
||
;there MUST be a process on the RLR
|
||
;at this point, ie. IDLE...
|
||
sti
|
||
;go through the Poll List
|
||
mov di,(offset plr)-p_link
|
||
;get the next PD on list.
|
||
;DI is the last one which
|
||
;has already been checked.
|
||
polld_another:
|
||
mov si,p_link[di]
|
||
;SI is the next PD to check
|
||
test si,si ! jz drltorlr
|
||
;SI is valid PD, poll it.
|
||
|
||
;If top PD on the PLR has a worse
|
||
;priority compared to top PD on the RLR,
|
||
;there is no reason to call the XIOS
|
||
;and poll the device, this time through
|
||
;the dispatcher. We must poll on equal
|
||
;priority to keep a compute bound
|
||
;process and the CLOCK from locking
|
||
;out a polling process.
|
||
;Note, we stop polling after
|
||
;the first process that has polled
|
||
;successfully, or we get to the end of
|
||
;the PLR. The process is placed on
|
||
;the RLR.
|
||
|
||
mov bx,rlr ! test bx,bx ;if RLR=0: poll
|
||
jz poll_it
|
||
mov al,p_prior[si] ;priority of 1st poll PD
|
||
cmp al,p_prior[bx] ! jbe poll_it ;poll if equal or better
|
||
jmps drltorlr ;priority than head of RLR
|
||
poll_it:
|
||
push di
|
||
;if mpm
|
||
; mov cx,p_wait[si]
|
||
;endif
|
||
;if ccpm
|
||
mov dx,p_wait[si]
|
||
;endif
|
||
mov al,io_polldev ! call xiosif
|
||
pop di ! mov si,p_link[di]
|
||
;if AL=0, device not ready.
|
||
cmp al,0 ! je polld_next
|
||
;device ready,
|
||
;move SI from PLR to RLR
|
||
mov ax,p_link[si] ! mov p_link[di],ax
|
||
mov bx,(offset rlr)-p_link
|
||
mov p_stat[si],ps_run
|
||
call insert_process ;got one ready to run:
|
||
jmps drltorlr ;stop polling
|
||
;p_link[SI]=next PD to check
|
||
polld_next: ;SI has been checked
|
||
mov di,si ! jmps polld_another
|
||
|
||
drltorlr:
|
||
;--------
|
||
; Pull all processes on the dispatch ready list and
|
||
; place them on the Ready List.
|
||
|
||
;We must disable interrupts while
|
||
;playing with DRL since interrupts
|
||
;doing a Flag_set may also.
|
||
;We must competely drain the DRL since
|
||
;it is in no particular order.
|
||
|
||
cli ! mov si,drl ;protect DRL from flag set
|
||
test si,si ! jz switch
|
||
mov ax,p_link[si] ! mov drl,ax
|
||
; test ax,ax ;is this the last PD on DRL?
|
||
; jnz drl_noi ;yes - don't turn on interrupts
|
||
sti ;interrupts off guarentees
|
||
;drl_noi: ;the last DRL PD with the
|
||
mov p_stat[si],ps_run ;best priority will run
|
||
mov bx,(offset rlr)-p_link ;next and at least until
|
||
call insert_process ;it turns on interrupts
|
||
jmps drltorlr
|
||
|
||
switch:
|
||
;------
|
||
; switch to the first process on the Ready List
|
||
|
||
sti
|
||
mov bx,rlr
|
||
; if no next process, go back ;
|
||
; to schedule. Gives more immediate ;
|
||
; response to polled and interrupt ;
|
||
; driven devices ;
|
||
switch0:
|
||
test bx,bx ! jnz switch1 ;
|
||
jmp schedule ;
|
||
|
||
; Suspendable processes: in order to be suspended, a process
|
||
; must be flagged as suspendable, it must be in the background,
|
||
; and it must not be in the system (e.g.,owning a system queue).
|
||
; It must also not be coming into context to terminate.
|
||
switch1:
|
||
|
||
cli ;check if process should suspend
|
||
mov ax,p_sflag[bx]
|
||
test ax,psf_suspend
|
||
jz switch2 ;no, not at all
|
||
|
||
mov al,p_cns[bx] ;Check vccb's state word
|
||
xor ah,ah ! xor di,di
|
||
mov di,ccblen ! mul di
|
||
mov di,ccb ! add di,ax
|
||
mov ax,c_state[di]
|
||
|
||
test ax,csm_background ;Has it gone into background ?
|
||
jz switch2 ;no, don't need to suspend
|
||
|
||
push es
|
||
mov es,p_uda[bx]
|
||
mov al,u_insys ;Is it in the system? If so, don't
|
||
test al,al ;suspend.
|
||
pop es
|
||
jne switch2
|
||
|
||
test p_flag[bx],pf_ctlc ;Is it terminating ?
|
||
jnz switch2 ;Yes, don't put it back on list.
|
||
|
||
mov ax,p_link[bx] ;All conditions apply; take it off
|
||
mov rlr,ax ;the RLR.
|
||
mov ax,splr ;Get the suspend list
|
||
mov p_link[bx],ax ;link up and
|
||
mov splr,bx ;place on top of suspend list.
|
||
mov p_stat[bx],ps_ciowait ;change its status
|
||
|
||
mov ax,c_state[di] ;Turn on suspend if process was
|
||
test ax,csm_suspend ;created in the background.
|
||
jnz do_dparam
|
||
or c_state[di],csm_suspend
|
||
do_dparam:
|
||
push es ;Put list root into u_dparam
|
||
mov es,p_uda[bx] ;for terminate's pd search.
|
||
mov u_dparam, offset splr
|
||
pop es
|
||
|
||
mov bx,rlr ;BX = RLR
|
||
sti
|
||
|
||
jmp switch0 ;make sure next process isn't suspendable
|
||
|
||
;enable memory for this process
|
||
;turn on interrupts ?
|
||
;
|
||
; ;Save and restore the 8087 environment if process to run
|
||
; ;uses the 8087 and is not the owner. Interrupts
|
||
; ;must be on. Code from Intel Ap. Note. 113 page 29
|
||
;
|
||
; ;This code shouldn't be added unless interrupt windows in
|
||
; ;switch are allowed or the 8087 restore is separated
|
||
; ;from the 8086/8088 restore. The switch code without this
|
||
; ;commented out 8087 code,
|
||
; ;creates an interrupt window approx. 100 to 200 micro
|
||
; ;secs on 5 to 4 meg CPU.
|
||
|
||
; ;Allowing interrupt windows in switch
|
||
; ;means we must check on leaving the dispatcher
|
||
; ;for an interrupt awakened process (DRL again <> 0)
|
||
; ;and call the
|
||
; ;dispatcher again to prevent a 16 milli second wakeup time
|
||
; ;for a PD doing a flagwait after the interrupt service routine.
|
||
; ;Calling the dispatcher at the end of the dispatch
|
||
; ;(see commented out code at end of dispatcher and at
|
||
; ;INT_DISP_EXIT:)
|
||
; ;creates contention problems between PDs waiting for a resource
|
||
; ;and PDs waking up from interrupts. It cannot be guarenteed
|
||
; ;who will run next. An interrupt awakened process can
|
||
; ;get a just freed resource is should have waited for.
|
||
; ;The RTM ASSIGN_SYNC_ENTRY is an untested solution
|
||
; ;for allowing interrupts in the dispatcher switch code.
|
||
|
||
switch2:
|
||
sti ;BX=PD to run next
|
||
test p_flag[bx],pf_8087 ;does this process use the NDP?
|
||
jz try_em87 ;if not, see if it emulates 8087
|
||
cmp bx,owner_8087 ;do we already own it
|
||
je done8087
|
||
mov dx,ds ;DX = DS = SYSDAT
|
||
fwait ;wait until other process is done
|
||
xchg bx,owner_8087 ;new owner, also set by terminate
|
||
test bx,bx ! jz get8087 ;no one owns it if BX=0
|
||
mov ds,p_uda[bx] ;old owner's UDA
|
||
fstcw ds:u_8087 ;save IEM bit status
|
||
nop ;delay while 8087 busy saves control reg
|
||
fdisi ;disable 8087 busy signal
|
||
mov ax,ds:u_8087 ;get original control word
|
||
fsave ds:u_8087 ;save NPX context
|
||
fwait ;IEM=1.wait for save to finish
|
||
mov ds:u_8087,ax ;save original control word
|
||
mov ds,dx ;DS = SYSDAT
|
||
mov es,p_uda[bx] ;swap out and save this user's
|
||
mov di,offset u_ivec87_of ;ndp interrupt vector
|
||
mov si,iofs_87 ;DS:SI = system's vector address
|
||
mov ds,iseg_87 ;ES:DI = user's UDA save area
|
||
mov cx,2! rep movsw
|
||
mov ds,dx ;restore DS to SYSDAT
|
||
get8087:
|
||
mov bx,rlr
|
||
mov ds,p_uda[bx] ;PD to run next
|
||
|
||
frstor ds:u_8087 ;copy in its 8087 environment frsure
|
||
push ds ;DS=UDA . UDA on stack.
|
||
|
||
restore87_int:
|
||
mov ds,dx
|
||
les di,dword ptr iofs_87 ;restore interrupt vectors
|
||
mov ds, p_uda[bx] ;for 8087 user
|
||
mov si, offset u_ivec87_of
|
||
mov cx, 2 ! rep movsw
|
||
jmps restore
|
||
|
||
try_em87: ;8087 emulator has special vector
|
||
test p_sflag[bx],psf_em87 ;set that must be swapped
|
||
jz done8087
|
||
mov ax,ds ;save DS
|
||
mov cx,em_seg ;move 14 vectors from uda extension
|
||
mov di,em_offs ;to low memory
|
||
mov si,offset u_8087 ;u_8087 -> user save area in uda
|
||
mov ds,p_uda[bx]
|
||
mov es,cx
|
||
mov cx,tot_emvecs/2
|
||
rep movsw
|
||
mov ds,ax ;restore DS
|
||
|
||
done8087: ;no more 8087 or emulator business...
|
||
;BX=PD to run next
|
||
mov dx,p_uda[bx] ! mov ds,dx ;DS=UDA
|
||
push dx ;UDA on stack
|
||
|
||
restore:
|
||
mov es, sysdat ;Restore userdisp vectors.
|
||
mov ax, es:user_restore ;Acts like a nop to non-userdisp
|
||
mov si, es:rlr ;processes.
|
||
callf es:p_userdisp[si] ;Default routine does a retf.
|
||
|
||
xor ax,ax ! mov es,ax ! mov di,ax
|
||
mov si,offset u_ivectors
|
||
mov dx,4
|
||
mov cx,dx ! rep movsw ;restore interrupt vectors 0,1
|
||
mov cx,dx ! add di,dx ;don't touch NMI
|
||
add si,dx ;skip what was NMI
|
||
rep movsw ;restore interupt vectors 3,4
|
||
|
||
mov si,offset u_os_ip ;DS=UDA
|
||
mov di,offset i_os_ip
|
||
mov cx,dx ! rep movsw
|
||
|
||
; restore registers
|
||
mov ax,ds:u_bx ! mov bx,ax
|
||
mov ax,ds:u_cx ! mov cx,ax
|
||
mov ax,ds:u_dx ! mov dx,ax
|
||
mov ax,ds:u_si ! mov si,ax
|
||
mov ax,ds:u_di ! mov di,ax
|
||
mov ax,ds:u_bp ! mov bp,ax
|
||
mov ax,ds:u_ax
|
||
; restore DS and ES and stack
|
||
pop es ;ES=UDA
|
||
cli ;turn interrupts off for rest
|
||
mov ss,u_ss ;of exit
|
||
mov sp,u_sp
|
||
mov ds,sysdat
|
||
dext:
|
||
cmp u_in_int,true ! jne dret
|
||
jmp int_disp_exit
|
||
dret:
|
||
push u_flag_sav
|
||
mov indisp,false
|
||
cmp drl,0 ! je dd_ret
|
||
popf ; someone is on DRL from interrupt during
|
||
jmp pdisp ; switch, dispatch now, no 16ms wait
|
||
dd_ret:
|
||
popf
|
||
ret
|
||
|