dos_compilers/Logitech Modula-2 v1/TRANSFER.ASM
2024-06-30 15:16:10 -07:00

817 lines
22 KiB
NASM
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

;**********************************************************************
;
; Copyrigth (C) 1984 Logitech. All Rights Reserved.
;
; Permission is hereby granted to registered users to use or
; abstract the following program in the implementation of
; customized versions. This permission does not include the
; right to redistribute the source code of this program.
;
;
; Modula-2/86 Run Time Support package
;
; TRANSFER.ASM - Process/Interrupt Module
;
; Release 1.0 - Jan 24 84
;
;*******************************************************
include RTS.INC
data segment public
extrn CUR_PROCESS:byte ;:ProcessDescriptor
extrn CUR_P_PTR:dword
extrn FCT_CODE:byte
WAITING_PROC dd 0FFFF000Fh
rept NBR_ISR-1
dd 0FFFF000Fh
endm
; Room for 8 process descriptors, waiting on an interrupt
INT_VECT_OWNER dw NBR_ISR dup ( NIL_CARD )
; This array holds for every used Interrupt Vector the program id of the owner
TEMP_W dd ?
TEMP_B dd ?
TEMP_P_D ProcessDescriptor <?> ; scratch process descrip.
MASK_8259 EQU 21H ; port address of control word 1
CTRL_W2_8259 EQU 20H ; port address of control word 2
EOI_8259 EQU 20H ; end-of-interrupt code
BASE_8259 EQU 08H ; first interrupt handled by 8259
MAX_PRIO_LEVEL EQU 07H ; priority levels 0..MAX_PRIO_LEVEL
;;; removed jan 24 84:
;OLD_MASK DB NBR_ISR DUP (?)
; ; holds for every ISR the old value of the mask-bit
;NEW_MASK DB NBR_ISR DUP (?)
; ; holds for every used ISR a 1 in the bit, which corresponds
; ; to the mask-bit in the 8259 or a value 0FFH if not handled
; ; by the 8259
PRIORITY_MASKS DB 1,3,7,0FH,1FH,3FH,7FH,0FFH
; his mask may be changed to implement any
; desired priority schema.
data ends
code segment public
extrn RTS_DS:word ; part of code segment
extrn NORM_ADDR:near
extrn COMP_STACK:near
extrn STACK_OVF:near
extrn TERMINATE:near
extrn SAVE_CPU_INFO:near
assume CS:code, DS:data
;------------------------------------------------------------
public TRANSFER
TRANSFER:
;========
; The registers needed for the TRANSFER are already saved.
; Swap the Return Address and the parameters: (interrupts better be off!)
MOV BP, SP
POP WORD PTR TEMP_W ; RetAdd
POP WORD PTR TEMP_W+2 ; RetCodeSeg
POP CUR_PROCESS.PD_FLAGS
; Move the parameters:
POP [BP]
POP 2[BP]
POP 4[BP]
POP 6[BP]
PUSH CUR_PROCESS.PD_FLAGS ; reconstruct interrupt frame
PUSH WORD PTR TEMP_W+2 ; underneath parameters!
PUSH WORD PTR TEMP_W ; flags, segment, offset
MOV CUR_PROCESS.PD_SP, SP ; save SP above parameters..
SUB SP, 8 ; Set SP so parameters can be popped
TRANSFER_BODY:
; This is the part of TRANSFER, that is used for all transfer
; functions: TRANSFER, IOTRANSFER, Interrupt Service Routines.
; Params: 0[SP] ADR of process variable of process to be activated,
; 4[SP] ADR of p. var., where to save the current one
; Get the addr of the NEW process descriptor and copy it into
; the TEMP_P_D area. This is required by the semantic of this function!
PUSH DS
POP ES ; Destination Segment
; In the parameter-list is the addr of the pointer (VARPAR):
POP DI
POP DS
LDS SI, dword ptr [DI]
; save the parameter for the assignement to CUR_P_PTR (see below):
MOV ES: WORD PTR TEMP_B, SI
MOV ES: WORD PTR TEMP_B + 2, DS
MOV DI, OFFSET TEMP_P_D
MOV CX, (size ProcessDescriptor)/2
REP MOVSW ; Copy it into the TEMP_P_D area
; Copy the current-one in the OLD process descriptor:
PUSH ES
POP DS
LES DI, CUR_P_PTR
MOV SI, OFFSET CUR_PROCESS
MOV CX, (size ProcessDescriptor)/2
REP MOVSW
; ... and update the varpar:
POP DI
POP ES ; This is the addr of the varpar
MOV SI,OFFSET CUR_P_PTR ; It holds the original of the P.D.
movsw
movsw
; Update interrupt mask in current process descriptor:
IN AL, MASK_8259
XOR AH, AH
MOV CUR_PROCESS.PD_PRIO_MASK, AX
; check if both processes have the same priority:
CMP AX, TEMP_P_D.PD_PRIO_MASK ; TEMP_P_D is the new one
JE PRIORITY_SET
; we have to change the processor's priority:
MOV AX, TEMP_P_D.PD_PRIO_MASK ; the new one
OUT MASK_8259, AL
PRIORITY_SET:
; Now, we copy the TEMP_P_D area into the CURRENT descriptor:
PUSH DS
POP ES
MOV SI, OFFSET TEMP_P_D
MOV DI, OFFSET CUR_PROCESS
MOV CX, (size ProcessDescriptor)/2
REP MOVSW
; ... and set the pointer to the new process:
MOV SI, OFFSET TEMP_B
MOV DI, OFFSET CUR_P_PTR
movsw
movsw
; Now, we restore the machine state:
MOV SS, CUR_PROCESS.PD_SS
MOV SP, CUR_PROCESS.PD_SP
MOV DS, CUR_PROCESS.PD_DS
PUSH DS ; We'll restore it at the very end
MOV AX, ES
MOV DS, AX
MOV ES, CUR_PROCESS.PD_ES
MOV DI, CUR_PROCESS.PD_DI
MOV SI, CUR_PROCESS.PD_SI
MOV BP, CUR_PROCESS.PD_BP
MOV DX, CUR_PROCESS.PD_DX
MOV CX, CUR_PROCESS.PD_CX
MOV BX, CUR_PROCESS.PD_BX
MOV AX, CUR_PROCESS.PD_AX
POP DS ; The new-one
IRET ; resume the new process!
; END TRANSFER
;------------------------------------------------------------
; Interrupt service routines:
; ==========================
; There is a fix number of interrupts, that can be treated simultanously.
; Here we allow up to 8 or 16 interrupts at a time, depending on the
; value of 'NBR_ISR'.
; The routines ISRn are the entry points to the common Interrupt
; Service Routine (COM_ISR).
; Every routine is 4 bytes long. This fact is used implicitly in COM_ISR
; and in IOTRANSFER. The Call to COM_ISR allows the identification of the
; Interrupt Vector (return addr of the Call).
ISR0: NOP
CALL COM_ISR
ISR1: NOP
CALL COM_ISR
ISR2: NOP
CALL COM_ISR
ISR3: NOP
CALL COM_ISR
ISR4: NOP
CALL COM_ISR
ISR5: NOP
CALL COM_ISR
ISR6: NOP
CALL COM_ISR
ISR7: NOP
CALL COM_ISR
IF NBR_ISR / 8
; This block of 8 Interrupt Service Routines has to be repeated for
; every additional 8259:
ISR8: NOP
CALL COM_ISR
ISR9: NOP
CALL COM_ISR
ISR10: NOP
CALL COM_ISR
ISR11: NOP
CALL COM_ISR
ISR12: NOP
CALL COM_ISR
ISR13: NOP
CALL COM_ISR
ISR14: NOP
CALL COM_ISR
ISR15: NOP
CALL COM_ISR
ENDIF
COM_ISR:
; Common part of the Interrupt Service Routines
; Save all the registers, except SP (has yet to be adjusted)
; and CS, IP, Flags. They are on the stack and will be
; used directly there (in the IRET of the next TRANSFER):
PUSH DS
MOV DS, RTS_DS
POP CUR_PROCESS.PD_DS
MOV CUR_PROCESS.PD_AX, AX
MOV CUR_PROCESS.PD_BX, BX
MOV CUR_PROCESS.PD_CX, CX
MOV CUR_PROCESS.PD_DX, DX
MOV CUR_PROCESS.PD_BP, BP
MOV CUR_PROCESS.PD_SI, SI
MOV CUR_PROCESS.PD_DI, DI
MOV CUR_PROCESS.PD_SS, SS
MOV CUR_PROCESS.PD_ES, ES
; Find the interrupt vector:
POP BX ; Return addr of ISRn
SUB BX, OFFSET ISR1 ; BX is index in table WAITING_PROC
; Complete the update of process descriptor:
MOV CUR_PROCESS.PD_SP, SP
POP CX ; just to get access to the Flags
POP DX
POP AX
MOV CUR_PROCESS.PD_FLAGS, AX
PUSH AX
PUSH DX
PUSH CX
; Push the parameters for the TRANSFER
LES SI, WAITING_PROC [BX] ; get address of PROCESS var
LES SI, ES:DWORD PTR [SI] ; get address of process descriptor
; the interrupted process:
PUSH ES: WORD PTR [SI].PD_INT_PROC+2
PUSH ES: WORD PTR [SI].PD_INT_PROC
; the waiting process:
PUSH WORD PTR WAITING_PROC+2 [BX]
PUSH WORD PTR WAITING_PROC [BX]
; A IOTRANSFER is valid only for 1 single interruption, so we have to
; free the corresponding Interrupt Vector:
CALL FREE_1_VECT
MOV DS, CS: RTS_DS
; Send a EOI to the 8259:
MOV AL, EOI_8259
OUT CTRL_W2_8259, AL
;;; removed jan 24 84:
; ; Before enabling interrupts, we mask the bit in the 8259
; ; that corresponds to the current interrupt:
; ; (BX holds number of used ISR * 2)
; SHR BX, 1 ; byte index
; MOV CL, NEW_MASK [BX]
; CMP CL, 0FFH ; NIL? i.e. not handled by 8259?
; JE INT_CTRL_MASKED
; MOV DL, OLD_MASK [BX]
; IN AL, MASK_8259 ; get current mask
; CMP DL, 0 ; was old bit set?
; JE RESET_BIT
; OR AL, CL ; set it
; JMP BIT_IS_OK
;RESET_BIT:
; NOT CL
; AND AL, CL ; reset it
;BIT_IS_OK:
; OUT MASK_8259, AL
;INT_CTRL_MASKED:
; at the end of the following TRANSFER we are performing
; an IRET, which enables the interrupts.
; Now, we're ready for a TRANSFER:
JMP TRANSFER_BODY
; END Interrupt Service Routines
;------------------------------------------------------------
page
public IOTRANSFER
IOTRANSFER:
;==========
; The registers needed for the TRANSFER are
; already saved.
; Swap the Return Address and the parameters:
MOV BP, SP
POP WORD PTR TEMP_W ; RetAdd
POP WORD PTR TEMP_W+2 ; RetCodeSeg
POP CUR_PROCESS.PD_FLAGS
; Move the paramaters:
POP AX
MOV [BP], AX
POP AX
MOV [BP]+2, AX
POP AX
MOV [BP]+4, AX
POP AX
MOV [BP]+6, AX
POP AX
MOV [BP]+8, AX
; Restore the Return Block:
PUSH CUR_PROCESS.PD_FLAGS
PUSH WORD PTR TEMP_W+2 ; RetCodeSeg
PUSH WORD PTR TEMP_W ; RetAdd
MOV CUR_PROCESS.PD_SP, SP
; Set SP so, that the parameters can be popped:
SUB SP, 10
POP BX ; Interrupt Vector
MOV CUR_PROCESS.PD_INT_VECT, BX
SHL BX, 1
SHL BX, 1
; BX is the offset of the Interrupt Vector
; Find a unused Interrupt Service Routine (ISRn), represented by
; a free entry in the array INT_VECT_OWNER:
MOV DI, OFFSET INT_VECT_OWNER
MOV AX, NIL_CARD
MOV CX, NBR_ISR
INC CX ; Increment it, so we can test for 0
REPNE SCASW ; Scan the array for a NIL
SUB DI, 2 ; It has already been incremented
MOV AX, OFFSET INT_VECT_OWNER
SUB DI, AX ; Get word index
CMP CL, 0
JNE FREE_INT_V
; There is no more free Interrupt Service Routine:
MOV CUR_PROCESS.PD_STATUS, INT_ERR_CODE
JMP TERMINATE
FREE_INT_V:
; BX is the offset of the Interrupt Vector
; DI is the index in INT_VECT_OWNER of
; the first free entry
; Put the program identifier in the array
; INT_VECT_OWNER (used to restore it upon
; termination):
MOV AX, CUR_PROCESS.PD_PROG_ID
MOV INT_VECT_OWNER [DI], AX
; Set in the P.D., where to save the running
; process, when Interrupt will occur. It is
; the 2nd parameter of IOTRANSFER = addr of
; proc. variable:
POP WORD PTR CUR_PROCESS.PD_INT_PROC
POP WORD PTR CUR_PROCESS.PD_INT_PROC + 2
; Put the current process in the array
; WAITING_PROC (the addr of process var):
MOV DX, DI ; save it
SHL DI, 1 ; a pointer-index
POP WORD PTR WAITING_PROC [DI]
POP WORD PTR WAITING_PROC + 2 [DI]
; Restore the parameters for the subsequent
; TRANSFER:
SUB SP, 8
; Save the requested Interrupt Vector and
; put the new one:
MOV AX, 0
MOV ES, AX
MOV AX, ES: [BX]
MOV CUR_PROCESS.PD_OLD_ISR, AX
MOV AX, ES: [BX] + 2
MOV CUR_PROCESS.PD_OLD_ISR + 2, AX
ADD DI, OFFSET ISR0
; Implicit use of the fact, that the ISRn have a size of 4 Bytes!
; DI is the address of the corresponding Interrupt Service Routine
MOV ES: [BX], DI
MOV ES: [BX] + 2, CS
;;; removed jan 24 84:
; ; Before making the TRANSFER, we are going to unmask the corres-
; ; ponding bit in the 8259 Interrupt Controller, to allow this
; ; interrupt to occur:
; ; (DX is the number of used ISR * 2)
; SHR DX, 1 ; byte index
; MOV DI, DX
; MOV NEW_MASK [DI], 0FFH ; NIL, used by ISR
; MOV AX, CUR_PROCESS.PD_INT_VECT
; SUB AX, BASE_8259 ; check, if this interrupt is
; JB INT_CTRL_READY ; handled by 8259
; CMP AX, NBR_ISR
; JAE INT_CTRL_READY
; ; it is handled by the 8259
; MOV CX, AX ; = level inside 8259
; MOV BX, 1 ; = mask for level 0
; SHL BX, CL ; = mask for actual level
; MOV NEW_MASK [DI], BL ;;;; temporarily: only 8 levels
; IN AL, MASK_8259 ; fetch old mask
; MOV CL, AL
; AND CL, BL ; get old value of this bit
; MOV OLD_MASK [DI], CL ; and save it
; ; now unmask the bit:
; NOT BL
; AND AL, BL
; OUT MASK_8259, AL
;INT_CTRL_READY:
; Execute a normal TRANSFER:
JMP TRANSFER_BODY ; No return here
; END IOTRANSFER
;------------------------------------------------------------
page
public NEWPROCESS
NEWPROCESS proc near
PUSH BP
MOV BP, SP
MOV AX, [BP] + 14 ; Offset of process workspace
MOV BX, [BP] + 16 ; Segment of it
MOV CX, AX
ADD CX, (size ProcessDescriptor) + 10 + 15
; Check, if there is room for process
; descr and 'free list header' for
; heap. 15 is needed to round up.
JNC SIZE_OK
JMP STACK_OVF
; Not even enough room for the workspace
SIZE_OK:
ADD AX, (size ProcessDescriptor) + 15
; Free space starts at the
; first paragraph after PD.
; 15 is to round up (worst case).
CALL NORM_ADDR
; Upon return:
; BX = normalised Segment of
; free mem (after P.D.)
; AX = Offset, < 16
; Set the initial values for the heap managment:
MOV TEMP_P_D.PD_HEAP_BASE + 2, BX
MOV TEMP_P_D.PD_HEAP_TOP + 2, BX
MOV TEMP_P_D.PD_HEAP_BASE, 0
MOV TEMP_P_D.PD_HEAP_TOP, 10
; size of a 'FreeElementPtr'
MOV ES, BX ; segment of heap
; put NILs in the header of Free List:
MOV ES: WORD PTR 0, NIL_OFF
MOV ES: WORD PTR 2, NIL_SEG
MOV ES: WORD PTR 4, NIL_OFF
MOV ES: WORD PTR 6, NIL_SEG
MOV ES: WORD PTR 8, 0
; size of free element (redundant)
; See comment under 'Fill in the Default
; Process Descriptor'. For a new process
; however, we must fully install an empty heap,
; since we can not call 'InstallHeap' as
; done in the initialization of the module
; Storage for the MAIN process.
; Compute the initial stack values:
MOV DX, (size ProcessDescriptor) + 15
MOV CL, 4
SHR DX, CL ; compute PD size in paragrafs
MOV AX, [BP] + 14 ; Get offset of Workspace
AND AX, 0FH
JZ SET_STACK ; We loose one paragraph for rounding
INC DX ; (stack and heap start at a parag. address).
SET_STACK:
MOV AX, [BP] + 12 ; Size of process' WSP, in paragrafs
SUB AX, DX ; Size minus proc-descriptor
CALL COMP_STACK ; Sets stack to end of WSP
; BX = SS, AX = SP
; SP has to be set after the return block
; that we're going to put:
SUB AX, SP_INI_SIZE
MOV TEMP_P_D.PD_SP, AX ; Set SP and SS in new descriptor
MOV TEMP_P_D.PD_SS, BX
MOV SI, AX
MOV ES, BX
SUB AX, SP_RESERVE
MOV TEMP_P_D.PD_SP_LIM, AX ; Set Stack Limit
; Stack Limit is actual value
; of SP minus some reserve
; Prepare the error return on the new stack:
; (ES,SI) are the initial stack of this new process.
MOV ES:WORD PTR 8[SI], CS
MOV ES:WORD PTR 6[SI], OFFSET PROCESS_END
; A process should never terminate!
MOV AX, SI
ADD AX, 6
MOV TEMP_P_D.PD_RET_SP, AX
; Return Stack Value (not used)
; Copy the Program End Stack:
MOV CX, CUR_PROCESS.PD_PROG_END
MOV TEMP_P_D.PD_PROG_END, CX
MOV CX, CUR_PROCESS.PD_PROG_END+2
MOV TEMP_P_D.PD_PROG_END+2, CX
; Copy the program IDs from the current process:
MOV AX, CUR_PROCESS.PD_PROG_ID
MOV TEMP_P_D.PD_PROG_ID, AX
MOV AX, CUR_PROCESS.PD_SHARED_ID
MOV TEMP_P_D.PD_SHARED_ID, AX
; Copy the Module Table Header:
MOV AX, CUR_PROCESS.PD_MOD_TABLE
MOV TEMP_P_D.PD_MOD_TABLE, AX
MOV AX, CUR_PROCESS.PD_MOD_TABLE+2
MOV TEMP_P_D.PD_MOD_TABLE+2, AX
; Copy the father process:
MOV AX, CUR_PROCESS.PD_FATHER_PROC
MOV TEMP_P_D.PD_FATHER_PROC, AX
MOV AX, CUR_PROCESS.PD_FATHER_PROC+2
MOV TEMP_P_D.PD_FATHER_PROC+2, AX
; Check if the father process is NIL, in which
; case we have to put the addr of the current PD:
CMP AX, 0FFFFH
JNE NOT_FATHER
MOV AX, CUR_P_PTR
MOV TEMP_P_D.PD_FATHER_PROC, AX
MOV AX, CUR_P_PTR + 2
MOV TEMP_P_D.PD_FATHER_PROC + 2, AX
NOT_FATHER:
; Copy the priority mask from the current process:
MOV AX, CUR_PROCESS.PD_PRIO_MASK
MOV TEMP_P_D.PD_PRIO_MASK, AX
; Set the Continuation Address:
; (We put it on the stack, for a IRET)
MOV AX, [BP] + 18
MOV BX, [BP] + 20
MOV ES: [SI] + 0, AX
MOV ES: [SI] + 2, BX
; Copy the Flags:
MOV CX, CUR_PROCESS.PD_FLAGS
MOV TEMP_P_D.PD_FLAGS, CX
MOV ES: [SI] + 4, CX
; And on stack, for the IRET
; Set Status to Normal:
MOV AX, 0
MOV TEMP_P_D.PD_STATUS, AX
; don't modify AX here!
; Set dynamic link to 0, used by the
; debugger to detect end of calling sequence:
MOV TEMP_P_D.PD_BP, AX
; Set the address of the descriptor in the VAR-PAR:
MOV ES, [BP] + 10 ; addr of varpar
MOV BX, [BP] + 8
MOV DI, [BP] + 14 ; addr of workspace
MOV CX, [BP] + 16
MOV ES: [BX], DI
MOV ES: [BX] + 2, CX
; Copy the new descriptor from the TEMP_P_D
; area into the real workspace:
MOV ES, CX ; (ES,DI) = workspace
MOV SI, OFFSET TEMP_P_D ; (DS,SI) = TEMP_P_D
MOV CX, (size ProcessDescriptor)/2
REP MOVSW
MOV DS, CUR_PROCESS.PD_DS
POP BP
IRET
;------------------------------------------------------------
PROCESS_END:
;===========
; We arrive here, when the code of a process is executed and a
; return from its code is performed. Since a process is not called
; like a procedure, but started through a TRANSFER, this situation
; is illegal:
MOV CUR_PROCESS.PD_STATUS, PROCESS_END_CODE
JMP TERMINATE
NEWPROCESS endp
;------------------------------------------------------------
page
public MON_ENTRY, MON_EXIT
MON_ENTRY:
;=========
; Upon entry: BX holds requested priority level.
; The interrupt controller is set to disable all
; interrupts of the requested or lower levels.
; check the parameter:
CMP BX, MAX_PRIO_LEVEL
JBE LEVEL_OK
MOV BX, MAX_PRIO_LEVEL
LEVEL_OK:
POP SI ; remove return block
POP DX
POP CX
IN AL, MASK_8259
XOR AH, AH
PUSH AX ; save old mask
OR AL, PRIORITY_MASKS [BX]
OUT MASK_8259, AL
MOV CUR_PROCESS.PD_PRIO_MASK, AX
PUSH CX ; restore return block
PUSH DX
PUSH SI
MOV DS, CUR_PROCESS.PD_DS
IRET
MON_EXIT:
;========
; Restore the mask that has been saved on the stack
; at the entry to that procedure. Note that changes
; in the interrupt mask that occured during execution
; of this 'priority procedure' are not conserved!
; If interrupts are treated with IOTRANSFER, such
; changes should never occur.
POP SI ; remove return block
POP DX
POP CX
POP AX ; old mask
MOV CUR_PROCESS.PD_PRIO_MASK, AX
OUT MASK_8259, AL
PUSH CX ; restore return block
PUSH DX
PUSH SI
MOV DS, CUR_PROCESS.PD_DS
IRET
public LISTEN
LISTEN:
;======
; This function lowers the priority and enables interrupts
; tempoarily. Note that changes in the interrupt mask that
; occur during the execution of pending interrupts are not
; conserved, the old mask is restored at the end! If
; interrupts are treated with IOTRANSFER, such changes
; should never occur.
IN AL, MASK_8259
XOR AH, AH ; update current mask
PUSH AX ; and save it
XOR AX, AX
MOV CUR_PROCESS.PD_PRIO_MASK, AX
OUT MASK_8259, AL ; unmask all bits
STI ; Allow all interrupts
NOP ; (there is a one-instruction lag)
MOV CX, 20H
LISTEN_AGAIN:
DEC CX ; we have to wait longer, to give
; all pending interrupts a chance
JNZ LISTEN_AGAIN
CLI
POP AX
MOV CUR_PROCESS.PD_PRIO_MASK, AX
OUT MASK_8259, AL ; restore old mask
MOV DS, CUR_PROCESS.PD_DS
IRET
;------------------------------------------------------------
public GET_INTERRUPT_MASK
GET_INTERRUPT_MASK proc near
IN AL, MASK_8259
XOR AH, AH
RET
GET_INTERRUPT_MASK endp
;------------------------------------------------------------
public REST_INTERRUPT_MASK
REST_INTERRUPT_MASK proc near
OUT MASK_8259, AL
RET
REST_INTERRUPT_MASK endp
;------------------------------------------------------------
FREE_1_VECT proc near
; Upon entry: (ES,SI) hold addr of P.D. that owns the vector.
; BX holds number of used ISR (0..NBR_ISR-1) times 4
; Upon exit: BX holds number of used ISR times 2
; We have to do both:
; a) free its entry in WAITING_PROC and in INT_VECT_OWNER
MOV AX, 0FFFFH ; used as NIL
MOV WAITING_PROC [BX], AX
SHR BX, 1
MOV INT_VECT_OWNER [BX], AX
; b) and to restore the interrupt vector
PUSH ES
MOV AX, 0
MOV ES, AX
POP DS ; DS is segm of waiting process
; and SI is its offset
MOV DI, PD_INT_VECT [SI]
SHL DI, 1
SHL DI, 1 ; multiply by 4, to get addr.
ADD SI, PD_OLD_ISR
MOVSW
MOVSW
RET
FREE_1_VECT endp
public REST_I_V
REST_I_V proc near
MOV AX, CUR_PROCESS.PD_PROG_ID
; AX holds the current ID
MOV DI, NBR_ISR
SHL DI, 1 ; WORD index
NEXT_I_V:
DEC DI
DEC DI
MOV BX, INT_VECT_OWNER [DI]
; BX holds the owner
CMP AX, BX
JE FREE_THIS_ONE
CMP AX, 0 ; 0 is a joker !
JNE I_V_DONE ; It's not 0
CMP BX, NIL_CARD
JE I_V_DONE ; It's NIL
FREE_THIS_ONE:
; This entry is owned by the current program:
MOV BX, DI
SHL BX, 1
LES SI, WAITING_PROC [BX] ; get addr of PROCESS variable
LES SI, ES:DWORD PTR [SI] ; get addr of process descriptor
PUSH DI ; save it
CALL FREE_1_VECT
POP DI
I_V_DONE:
CMP DI, 0
JNE NEXT_I_V
RET
REST_I_V endp
public FREE_INT_VECT
FREE_INT_VECT:
;=============
; Restores the old Interrupt Vectors of all entries, used by the
; current program.
CALL REST_I_V
MOV DS, CUR_PROCESS.PD_DS
IRET
;------------------------------------------------------------
public STOPPED
STOPPED:
;======
; We arrive here when ctrl-break is entered from the
; keyboard.
MOV ES, RTS_DS
; We are coming from a DOS function (which we don't want to
; debug), so we have first to remove the return block that
; points to the DOS:
POP AX
POP AX
POP AX
CALL SAVE_CPU_INFO
; Give the interrupt controller an End-Of-Interrupt.
; There is for sure one that we have to send (for the KBD
; routine that has made the software interrupt to arrive
; here). We might be in a nested ISR (timer has a lower
; priority than KBD), so let's send 2 EOI (it doesn't harm):
MOV AL, EOI_8259
OUT CTRL_W2_8259, AL
OUT CTRL_W2_8259, AL
; Set status to some reasonable value:
MOV FCT_CODE, TERMINATE_FCT
MOV CUR_PROCESS.PD_STATUS, STOP_CODE
JMP TERMINATE
;------------------------------------------------------------
code ends
end