;***************************************************** ;* ;* Dispatch Routines ;* ;***************************************************** ;===== fdisp: ;===== ; This entry point used by interrupt routines in XIOS cli push ds ! mov ds,sysdat cmp indisp,true ! jne do_dispatch pop ds ! iret do_dispatch: mov es_sav,es mov bx_sav,bx mov bx,rlr mov es,p_uda[bx] mov u_in_int,true pop u_ds_sav push bx mov bl,p_stat[bx] mov u_stat_sav,bl pop bx mov p_stat[bx],ps_run mov bx,es_sav mov u_es_sav,bx mov bx,bx_sav jmp dsptch ;dispatcher will jump to here if ; u_in_int = true. int_disp_exit: mov u_in_int,false mov bx_sav,bx mov es_sav,ax mov bx,rlr mov al,u_stat_sav mov p_stat[bx],al mov ax,es_sav mov bx,bx_sav mov indisp,false mov ds,u_ds_sav mov es,u_es_sav iret ;======== farpdisp: ;======== ; Intermodule pdisp (non-interrupt) call pdisp ! ret ;===== 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 ! cld ! cli cmp indisp,true ! jne dispin popf ! ret dispin: mov indisp,true pop u_flag_sav ; store and switch stack mov u_ss,ss ! mov u_sp,sp mov ss,sysdat ! mov sp,offset dsptchtos sti ; save registers ; NOTE: We will use DS instead of ES ; No segment overrides... push es ! pop ds mov ds:u_ax,ax mov ds:u_bx,bx mov ds:u_cx,cx mov ds:u_dx,dx mov ds:u_di,di mov ds:u_si,si mov ds:u_bp,bp ; save interrupt vectors ; block move first 5 mov bx,0 ! mov ds,bx mov si,bx ! mov di,offset u_ivectors mov cx,10 ! rep movs ax,ax ; block move mpmint,debugint mov si,offset i_mpm_ip ! mov di,offset u_mpm_ip mov cx,4 ! rep movs ax,ax ; take current process off RLR. mov ds,sysdat cli mov si,rlr 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 mov bh,0 ! mov bl,p_stat[si] ! shl bx,1 jmp cs:dsp_table[bx] dsp_table dw disp_act ;00 - run dw poll_act ;01 - poll device dw delay_act ;02 - delay dw swap_act ;03 - 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 ;09 - (nop)-ciowait sleep_act: ;--------- ; insert running process into list specified by ; u_dparam and set p_stat from p_scratch mov bx,u_dparam 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 poll_act: ;-------- ; set p_wait field of process = device number. ; put running process on poll list and wait ; for the device specified by u_dparam ; input: SI=pd address mov dx,u_dparam mov p_wait[si],dx mov ax,plr ! mov p_link[si],ax mov plr,si ! 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 push si ! mov al,io_strtclk call xiosif ! pop si 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 swap_act: ;-------- ; put running process on swap list ; input: SI=pd address mov bx,(offset slr)-p_link call insert_process ! 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 ; BX=address of Flag entry mov bx,u_dparam 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 jmps disp_act term_act: ;-------- ; terminate the running process ; free memory,free pd ; input: SI=pd address mov ax,rlr mov p_link[si],ax mov rlr,si mov ch,0 ! mov cl,ncondev nxtcon: jcxz delst dec cx ! mov p_cns[si],cl push cx ! push si mov cx,f_condetach ! call mpmif pop si ! pop cx ! jmps nxtcon delst: mov cl,nlstdev nxtlst: jcxz free_nxt dec cx ! mov dx,cx add dl,ncondev mov p_lst[si],dl push cx ! push si mov cx,f_lstdetach ! call mpmif pop si ! pop cx ! jmps nxtlst free_nxt: push si mov si,p_mem[si] test si,si ! jz end_free push ds ! sub cx,cx ! push cx push ms_start[si] mov ax,ss ! mov ds,ax ! mov dx,sp mov cx,f_memfree ! call mpmif pop bx ! pop cx ! pop ds ! pop si jmps free_nxt end_free: mov mxmemowner,0 mov dx,offset mxmemqpb ! mov cx,f_qwrite call mpmif pop si mov ax,p_link[si] mov rlr,ax mov p_link[si],0 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 ; ; input: BX = list root ; SI = pd number mov cx,pflag[si] ! and cx,pf_resource ins_npd: mov di,p_link[bx] cmp di,0 ! jz ins_out mov al,p_prior[di] cmp al,p_prior[si] ja ins_out jb ins_nxt cmp cx,0 ! jz ins_nxt jmps ins_out ins_nxt: mov bx,di ! jmp ins_npd ins_out: cmp cx,0 ! jz ins_exit mov cx,pf_resource not cx ! and p_flag[si],cx 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 cmp si,0 ! jz drltorlr ;SI is valid PD, poll it. push di ! mov cx,p_wait[si] 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 push di ! mov bx,(offset rlr)-p_link mov p_stat[si],ps_run call insert_process ! pop si ;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. cli ! mov si,drl cmp si,0 ! jz switch mov ax,p_link[si] ! mov drl,ax mov p_stat[si],ps_run mov bx,(offset rlr)-p_link call insert_process sti ! jmps drltorlr switch: ;------ ; switch to the first process on the Ready List mov bx,rlr mov dx,p_uda[bx] ! mov ds,dx push dx ;UDA on stack ; restore interrupt vectors mov ax,0 ! mov es,ax mov si,offset u_ivectors ! mov di,ax mov cx,10 ! rep movs ax,ax mov si,offset u_mpm_ip mov di,offset i_mpm_ip mov cx,4 ! rep movs ax,ax ; restore registers mov ax,ds:u_ax mov bx,ds:u_bx mov cx,ds:u_cx mov dx,ds:u_dx mov si,ds:u_si mov di,ds:u_di mov bp,ds:u_bp ; restore DS and ES and stack pop es mov ss,u_ss mov sp,u_sp mov ds,sysdat cmp u_in_int,true ! jne dret jmp int_disp_exit dret: push u_flag_sav ! popf mov indisp,false ret