1298 lines
35 KiB
NASM
1298 lines
35 KiB
NASM
|
;*****************************************************************
|
|||
|
;
|
|||
|
; 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.
|
|||
|
;
|
|||
|
; LOGITECH SA. CH-1143 Apples, Switzerland
|
|||
|
;
|
|||
|
; Modula-2/86 Run Time Support package
|
|||
|
;
|
|||
|
; Module: TRANSFER.ASM
|
|||
|
; Handles Interrupts and Processes
|
|||
|
; Version: 8086, RAM-based, MS-DOS 1.1 and MS-DOS 2.0
|
|||
|
; Release: 1.1 - Dec 84
|
|||
|
;
|
|||
|
;*****************************************************************
|
|||
|
|
|||
|
|
|||
|
CGROUP group code
|
|||
|
DGROUP group data
|
|||
|
|
|||
|
assume CS: CGROUP
|
|||
|
assume DS: DGROUP
|
|||
|
assume ES: NOTHING
|
|||
|
assume SS: NOTHING
|
|||
|
|
|||
|
include RTS.INC
|
|||
|
|
|||
|
|
|||
|
;*****************************************************************************
|
|||
|
|
|||
|
; EXPORT QUALIFIED
|
|||
|
public GET_INTERRUPT_MASK
|
|||
|
public SET_INTERRUPT_MASK
|
|||
|
public SEND_EOI
|
|||
|
public TRANSFER
|
|||
|
public IOTRANSFER
|
|||
|
public NEWPROCESS
|
|||
|
public MON_ENTRY, MON_EXIT
|
|||
|
public LISTEN
|
|||
|
public get_device_status
|
|||
|
public set_device_status
|
|||
|
public REST_I_V
|
|||
|
public FREE_INT_VECT
|
|||
|
public STOPPED_1B
|
|||
|
public STOPPED_23
|
|||
|
;
|
|||
|
;*****************************************************************************
|
|||
|
data segment public 'data'
|
|||
|
|
|||
|
; FROM RTS IMPORT
|
|||
|
extrn cur_proc_addr:dword
|
|||
|
extrn device_mask:word
|
|||
|
extrn cur_process:word
|
|||
|
extrn m2_start_mark:word
|
|||
|
extrn m2_end_mark:word
|
|||
|
|
|||
|
data ends
|
|||
|
;*****************************************************************************
|
|||
|
|
|||
|
|
|||
|
;*****************************************************************************
|
|||
|
code segment public 'code'
|
|||
|
|
|||
|
; FROM RTS IMPORT
|
|||
|
extrn RTS_DS:word ; part of code segment
|
|||
|
extrn DUMMY_ISR:near
|
|||
|
extrn NORM_ADDR:near
|
|||
|
extrn COMP_STACK:near
|
|||
|
extrn TERMINATE:near
|
|||
|
|
|||
|
; FROM SERVICES IMPORT
|
|||
|
extrn SAVE_CPU_INFO:near
|
|||
|
extrn STACK_OVF:near
|
|||
|
|
|||
|
code ends
|
|||
|
;*****************************************************************************
|
|||
|
|
|||
|
|
|||
|
;*****************************************************************************
|
|||
|
data segment public 'data'
|
|||
|
|
|||
|
; Here are the definitions related to Interrupts. These original
|
|||
|
; values are valid for IBM-PC / IBM-XT. If you run the Modula-2/86
|
|||
|
; System on another hardware, it is possible, that the values in the
|
|||
|
; declarations below, three routines 'GET_INTERRUPT_MASK, 'SEND_EOI',
|
|||
|
; 'SET_INTERRUPT_MASK and as well as some code inside 'TRANSFER' and
|
|||
|
; 'COM_ISR' are to be modified.
|
|||
|
|
|||
|
; The following points should be checked out:
|
|||
|
; a) Is there an interrupt controller in your machine (chip number is
|
|||
|
; typically 8259)? The declarations and the three routines below
|
|||
|
; handle this interrupt controller. If no such chip is present, the
|
|||
|
; values of the declarations have no importance and the corresponding
|
|||
|
; part in the three routines has to be selected.
|
|||
|
; b) Is Input/Output to the interrupt controller done through I/O-ports
|
|||
|
; or is it memory-mapped (i.e. the registers of the interrupt controller
|
|||
|
; have fixed memory addresses)? Select the corresponding part in the
|
|||
|
; three routines.
|
|||
|
; c) Which ports are used for the interrupt controller, or which memory
|
|||
|
; addresses are used (if memory-mapped)? Change the declarations
|
|||
|
; accordingly.
|
|||
|
; d) How are the priorities distributed? In the array 'PRIORITY_MASKS'
|
|||
|
; below there is the interrupt mask for every priority level.
|
|||
|
; A priority is the number that can be given to a Modula-2 module (in
|
|||
|
; the module header, e.g: MODULE CriticalRegion [7]; to give priority 7).
|
|||
|
; The given priority is used as an index in the array 'PRIORITY_MASKS'
|
|||
|
; to select the corresponding interrupt mask.
|
|||
|
|
|||
|
; NOTE WELL: The Modula-2 Run-Time-Support does read the interrupt mask,
|
|||
|
; even if you do not intend to use IOTRANSFER or priority modules.
|
|||
|
; If this distributed version does not correspond to the character-
|
|||
|
; istics of your machine, the required adaptation must be done.
|
|||
|
; Alternatively you can select the part in the three routines that
|
|||
|
; has to be used if no interrupt controller is present.
|
|||
|
|
|||
|
|
|||
|
|
|||
|
MASK_8259 EQU 21H
|
|||
|
; Port address of control word 1 in Interrupt Controller.
|
|||
|
; This port is used to read and write the interrupt mask.
|
|||
|
; See routines 'GET_INTERRUPT_MASK' and 'SET_INTERRUPT_MASK'
|
|||
|
; below.
|
|||
|
|
|||
|
CTRL_W2_8259 EQU 20H
|
|||
|
; Port address of control word 2 in Interrupt Controller.
|
|||
|
; This port is used to send the End-Of-Interrupt code.
|
|||
|
; See routine SEND_EOI below.
|
|||
|
|
|||
|
IO_SEGMENT EQU 0H
|
|||
|
; Segment-Register value to access memory-mapped I/O ports.
|
|||
|
; For machines without memory mapping, this value has no
|
|||
|
; meaning.
|
|||
|
|
|||
|
EOI_8259 EQU 20H
|
|||
|
; End-Of-Interrupt code for the Interrupt Controller.
|
|||
|
; Used in routine SEND_EOI below.
|
|||
|
|
|||
|
MAX_PRIO_LEVEL EQU 07H
|
|||
|
; Maximum priority handled by the Run-Time-Support.
|
|||
|
; Priority levels are: 0..MAX_PRIO_LEVEL.
|
|||
|
; If this value is changed, the corresponding parameter
|
|||
|
; in the compiler parameter module has to be adapted too
|
|||
|
; (compiler module 'COMPPARA').
|
|||
|
|
|||
|
PRIORITY_MASKS DB 80H,0C0H,0E0H,0F0H,0F8H,0FCH,0FEH,0FFH
|
|||
|
; This ARRAY holds for every priority level the
|
|||
|
; priority mask, which has to become effective
|
|||
|
; during execution of a priority module.
|
|||
|
; The values in this mask may be modified, to
|
|||
|
; implement any desired priority schema.
|
|||
|
; Priority 0 corresponds to the first element in
|
|||
|
; this array, priority 7 to the last.
|
|||
|
; no priority corresponds to a mask with all bits zero
|
|||
|
|
|||
|
data ends
|
|||
|
|
|||
|
;*****************************************************************************
|
|||
|
|
|||
|
|
|||
|
|
|||
|
;*****************************************************************************
|
|||
|
|
|||
|
code segment public 'code'
|
|||
|
|
|||
|
|
|||
|
; Insert statetments of procedure bodies at marked positions
|
|||
|
; in TRANSFER and COM_ISR. This positions are marked:
|
|||
|
|
|||
|
;**** Here the code of GET_INTERRUPT_MASK has been inserted :
|
|||
|
;**** Here the code of SET_INTERRUPT_MASK has been inserted :
|
|||
|
;**** Here the code of SEND_IO has been inserted :
|
|||
|
|
|||
|
;**** End of insertion
|
|||
|
|
|||
|
; This solution has been chosen to avoid procedure call overhead
|
|||
|
; in such time critical routines as TRANSFER ,IOTRANSFER, ISR.
|
|||
|
|
|||
|
|
|||
|
;------------------------------------------------------------
|
|||
|
; public GET_INTERRUPT_MASK
|
|||
|
|
|||
|
; This routine returns in AX the currently valid interrupt mask.
|
|||
|
; The following registers may be used here: AX, DX, DI, ES.
|
|||
|
; If other registers are used, they must be saved and restored.
|
|||
|
|
|||
|
;; The following code sequence has to be used on a hardware
|
|||
|
;; with I/O through port, where the port address is below 100H:
|
|||
|
GET_INTERRUPT_MASK proc near
|
|||
|
IN AL, MASK_8259
|
|||
|
XOR AH, AH
|
|||
|
RET
|
|||
|
GET_INTERRUPT_MASK endp
|
|||
|
|
|||
|
; The following code sequence has to be used on a hardware
|
|||
|
; with I/O through port, where the port address is above 100H:
|
|||
|
;GET_INTERRUPT_MASK proc near
|
|||
|
; MOV DX, MASK_8259
|
|||
|
; IN AL, DX
|
|||
|
; XOR AH, AH
|
|||
|
; RET
|
|||
|
;GET_INTERRUPT_MASK endp
|
|||
|
|
|||
|
; The following code sequence has to be used on a hardware
|
|||
|
; with memory-mapped Input/Output:
|
|||
|
;GET_INTERRUPT_MASK proc near
|
|||
|
; MOV AX, IO_SEGMENT
|
|||
|
; MOV ES, AX
|
|||
|
; MOV DI, MASK_8259
|
|||
|
; MOV AL, ES: [DI]
|
|||
|
; XOR AH, AH
|
|||
|
; RET
|
|||
|
;GET_INTERRUPT_MASK endp
|
|||
|
|
|||
|
; If your application program does not use interrupts nor
|
|||
|
; priority modules, or if there is no interrupt controller
|
|||
|
; present, this routine may return a dummy constant value.
|
|||
|
; In that case, the code here could be:
|
|||
|
; GET_INTERRUPT_MASK proc near
|
|||
|
; MOV AX, 0
|
|||
|
; RET
|
|||
|
; GET_INTERRUPT_MASK endp
|
|||
|
|
|||
|
|
|||
|
;------------------------------------------------------------
|
|||
|
; public SET_INTERRUPT_MASK
|
|||
|
|
|||
|
; This routine sends the interrupt mask to the interrupt
|
|||
|
; controller.
|
|||
|
; the mask sent to the interrupt controller is the logical OR
|
|||
|
; of the device_mask and the given priority mask in AL.
|
|||
|
; The following registers may be used here: AX, DX, DI, ES.
|
|||
|
; If other registers are used, they must be saved and restored.
|
|||
|
|
|||
|
;; The following code sequence has to be used on a hardware
|
|||
|
;; with I/O through port, where the port address is below 100H:
|
|||
|
SET_INTERRUPT_MASK proc near
|
|||
|
mov es, rts_ds
|
|||
|
or ax, es: device_mask
|
|||
|
OUT MASK_8259, AL
|
|||
|
RET
|
|||
|
SET_INTERRUPT_MASK endp
|
|||
|
|
|||
|
; The following code sequence has to be used on a hardware
|
|||
|
; with I/O through port, where the port address is above 100H:
|
|||
|
;SET_INTERRUPT_MASK proc near
|
|||
|
; mov es, rts_ds
|
|||
|
; or ax, es: device_mask
|
|||
|
; MOV DX, MASK_8259
|
|||
|
; OUT DX, AL
|
|||
|
; RET
|
|||
|
;SET_INTERRUPT_MASK endp
|
|||
|
|
|||
|
; The following code sequence has to be used on a hardware
|
|||
|
; with memory-mapped Input/Output:
|
|||
|
;SET_INTERRUPT_MASK proc near
|
|||
|
; mov es, rts_ds
|
|||
|
; or ax, es: device_mask
|
|||
|
; MOV DI, IO_SEGMENT
|
|||
|
; MOV ES, DI
|
|||
|
; MOV DI, MASK_8259
|
|||
|
; MOV ES: [DI], AL
|
|||
|
; RET
|
|||
|
;SET_INTERRUPT_MASK endp
|
|||
|
|
|||
|
; If your application program does not use interrupts nor
|
|||
|
; priority modules, or if there is no interrupt controller
|
|||
|
; present, this routine may be dummy.
|
|||
|
; In that case, the code here could be:
|
|||
|
; SET_INTERRUPT_MASK proc near
|
|||
|
; RET
|
|||
|
; SET_INTERRUPT_MASK endp
|
|||
|
|
|||
|
|
|||
|
;------------------------------------------------------------
|
|||
|
; public SEND_EOI
|
|||
|
|
|||
|
; This routine sends an END-OF-INTERRUPT code (EOI) to the
|
|||
|
; interrupt controller.
|
|||
|
; The following registers may be used here: AX, DX, DI, ES.
|
|||
|
; If other registers are used, they must be saved and restored.
|
|||
|
|
|||
|
;; The following code sequence has to be used on a hardware
|
|||
|
;; with I/O through port, where the port address is below 100H:
|
|||
|
SEND_EOI proc near
|
|||
|
MOV AL, EOI_8259
|
|||
|
OUT CTRL_W2_8259, AL
|
|||
|
RET
|
|||
|
SEND_EOI endp
|
|||
|
|
|||
|
; The following code sequence has to be used on a hardware
|
|||
|
; with I/O through port, where the port address is above 100H:
|
|||
|
;SEND_EOI proc near
|
|||
|
; MOV AL, EOI_8259
|
|||
|
; MOV DX, CTRL_W2_8259
|
|||
|
; OUT DX, AL
|
|||
|
; RET
|
|||
|
;SEND_EOI endp
|
|||
|
|
|||
|
; The following code sequence has to be used on a hardware
|
|||
|
; with memory-mapped Input/Output:
|
|||
|
;SEND_EOI proc near
|
|||
|
; MOV DI, IO_SEGMENT
|
|||
|
; MOV ES, DI
|
|||
|
; MOV DI, CTRL_W2_8259
|
|||
|
; MOV ES: BYTE PTR [DI], EOI_8259
|
|||
|
; RET
|
|||
|
;SEND_EOI endp
|
|||
|
|
|||
|
; If your application program does not use interrupts nor
|
|||
|
; priority modules, or if there is no interrupt controller
|
|||
|
; present, this routine may be dummy.
|
|||
|
; In that case, the code here could be:
|
|||
|
; SEND_EOI proc near
|
|||
|
; RET
|
|||
|
; SEND_EOI endp
|
|||
|
|
|||
|
|
|||
|
;------------------------------------------------------------
|
|||
|
;*********** end of user modifyable part ********************
|
|||
|
;------------------------------------------------------------
|
|||
|
|
|||
|
|
|||
|
;*****************************************************************************
|
|||
|
|
|||
|
data segment public 'data'
|
|||
|
|
|||
|
WAITING_PROC dd 0FFFFfffFh
|
|||
|
rept NBR_ISR-1
|
|||
|
dd 0FFFFfffFh
|
|||
|
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
|
|||
|
|
|||
|
new dd ? ; A(proc. desc. new process)
|
|||
|
old dd ? ; A(A(proc. desc. old process))
|
|||
|
TEMP_P_D ProcessDescriptor <?> ; used by NEWPROCESS
|
|||
|
|
|||
|
data ends
|
|||
|
|
|||
|
;*****************************************************************************
|
|||
|
|
|||
|
|
|||
|
|
|||
|
; public TRANSFER
|
|||
|
|
|||
|
TRANSFER:
|
|||
|
;========
|
|||
|
; save state of current process
|
|||
|
mov bx,es ; save rts_ds
|
|||
|
mov ax,ES:word ptr cur_proc_addr + 2
|
|||
|
mov es,ax
|
|||
|
mov ES:cur_process.pd_ds,ds
|
|||
|
mov ES:cur_process.pd_bp,bp
|
|||
|
mov ES:cur_process.pd_ss,ss
|
|||
|
mov bp,sp ; take bp to address stack
|
|||
|
|
|||
|
mov cx,es ; save base of current process
|
|||
|
les di, dword ptr [bp]+6 ; A(A(new process))
|
|||
|
mov ax,ES: word ptr [di] + 2 ; A(new process)
|
|||
|
mov ds,bx ; rts_ds
|
|||
|
mov word ptr new,0
|
|||
|
mov word ptr new+2,ax
|
|||
|
les di, dword ptr [bp]+10 ; A(A(old process))
|
|||
|
mov word ptr old,di
|
|||
|
mov word ptr old+2,es
|
|||
|
mov ds,cx ; restore base of current process
|
|||
|
mov ax,8 ; number of bytes occupied by params
|
|||
|
mov es,bx ; restore ES with rts_ds
|
|||
|
; jmp transfer_body0
|
|||
|
|
|||
|
TRANSFER_BODY0: ; common part of TRANSFER and IOTRANSFER
|
|||
|
; DS:[SI] points to current process
|
|||
|
|
|||
|
; get IRET params from stack, save them into P.D.
|
|||
|
pop bx
|
|||
|
pop cx
|
|||
|
pop dx
|
|||
|
mov cur_process.pd_flags,dx
|
|||
|
mov cur_process.pd_cs,cx
|
|||
|
mov cur_process.pd_ip,bx
|
|||
|
|
|||
|
; manipulate stack: 'remove parameters'
|
|||
|
add sp,ax
|
|||
|
|
|||
|
; restore IRET parameters onto stack and save SP into P.D.
|
|||
|
push dx
|
|||
|
push cx
|
|||
|
push bx
|
|||
|
mov cur_process.pd_sp,sp
|
|||
|
|
|||
|
TRANSFER_BODY:
|
|||
|
; This is the part of TRANSFER, that is used for all transfer
|
|||
|
; functions: TRANSFER, IOTRANSFER, Interrupt Service Routines.
|
|||
|
; Params: new: ADR of process descriptor of process to be activated,
|
|||
|
; old: ADR of proc. var. (double indirection!)
|
|||
|
; where to save the current one
|
|||
|
; DS:0 points to current process
|
|||
|
; ES contains RTS_DS
|
|||
|
|
|||
|
; set address of new process into cur_proc_addr
|
|||
|
mov bx,ds ; save base of old (current) process
|
|||
|
|
|||
|
mov DS, ES:word ptr new + 2
|
|||
|
mov ES: word ptr cur_proc_addr +2,DS
|
|||
|
mov ES: word ptr cur_proc_addr,0
|
|||
|
|
|||
|
mov ax,cur_process.pd_prio_mask
|
|||
|
|
|||
|
;**** Here the code of SET_INTERRUPT_MASK has been inserted:
|
|||
|
or ax, es: device_mask
|
|||
|
out mask_8259,al
|
|||
|
;**** End of insertion
|
|||
|
|
|||
|
; DS:0 points to new process
|
|||
|
; ES contains rts_ds
|
|||
|
; BX:0 points to old process
|
|||
|
|
|||
|
; get A(A(old process)) and store A(old process)
|
|||
|
les di,ES: old
|
|||
|
mov ES: word ptr [di] +2,bx
|
|||
|
mov ES: word ptr [di],0
|
|||
|
|
|||
|
; ; Now, we restore the machine state:
|
|||
|
mov si,ds ; ds still holds base of new process
|
|||
|
mov ss,si ; change stack pointers to restore regs
|
|||
|
mov sp,0
|
|||
|
mov es,si ; needed later to restore from ES:0
|
|||
|
pop ax
|
|||
|
pop bx
|
|||
|
pop cx
|
|||
|
pop dx
|
|||
|
pop bp ; sp must not be changed
|
|||
|
pop bp
|
|||
|
pop si
|
|||
|
pop di
|
|||
|
pop ds
|
|||
|
pop ss
|
|||
|
MOV SP,ES: word ptr cur_process.PD_SP
|
|||
|
MOV ES,ES: word ptr cur_process.PD_ES
|
|||
|
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 Interrupt Controller (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 si
|
|||
|
push ds
|
|||
|
mov ds,rts_ds
|
|||
|
mov si,word ptr cur_proc_addr + 2
|
|||
|
mov ds,si
|
|||
|
pop cur_process.pd_ds
|
|||
|
pop cur_process.pd_si
|
|||
|
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_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
|
|||
|
mov bp,sp
|
|||
|
mov ax,[bp]
|
|||
|
mov cur_process.pd_ip,ax
|
|||
|
mov ax,[bp]+2
|
|||
|
mov cur_process.pd_cs,ax
|
|||
|
mov ax,[bp]+4
|
|||
|
mov cur_process.pd_flags,ax
|
|||
|
|
|||
|
|
|||
|
; "Push" the parameters for the TRANSFER
|
|||
|
mov ds,rts_ds
|
|||
|
les si,waiting_proc[bx] ; address of old proc var
|
|||
|
mov si,ES:word ptr [si] + 2 ; address of new proc descr
|
|||
|
mov es,si
|
|||
|
mov word ptr new+2,es
|
|||
|
mov ax,ES: word ptr cur_process.pd_int_proc
|
|||
|
mov word ptr old,ax
|
|||
|
mov ax,ES: word ptr cur_process.pd_int_proc+2
|
|||
|
mov word ptr old+2,ax
|
|||
|
|
|||
|
; An IOTRANSFER is valid only for 1 single interruption, so we have to
|
|||
|
; free the corresponding Interrupt Vector:
|
|||
|
mov cx,ds ; save RTS_DS
|
|||
|
mov ax,nil_card
|
|||
|
mov word ptr waiting_proc[bx],ax
|
|||
|
shr bx,1
|
|||
|
mov int_vect_owner[bx],ax
|
|||
|
mov dx,es ; A(new process descriptor)
|
|||
|
mov ds,dx
|
|||
|
mov si,pd_old_isr ; loads offset in structure !!!!
|
|||
|
mov di,cur_process.pd_int_vect
|
|||
|
SHL di, 1
|
|||
|
SHL di, 1
|
|||
|
mov ax,0
|
|||
|
mov es,ax
|
|||
|
movsw
|
|||
|
movsw
|
|||
|
mov es,cx ; restore RTS_DS
|
|||
|
mov ds,ES: word ptr cur_proc_addr + 2 ; restore A(cur_process)
|
|||
|
|
|||
|
; Send a EOI to the 8259:
|
|||
|
|
|||
|
;**** Here the code of SEND_EOI has been inserted:
|
|||
|
mov al,EOI_8259
|
|||
|
out ctrl_w2_8259,al
|
|||
|
;**** End of insertion
|
|||
|
|
|||
|
; 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
|
|||
|
;------------------------------------------------------------
|
|||
|
|
|||
|
; public IOTRANSFER
|
|||
|
|
|||
|
IOTRANSFER:
|
|||
|
;==========
|
|||
|
; on entry ES = rts_ds
|
|||
|
|
|||
|
; 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 ds,cur_process.pd_ds ; restore old ds for save_cpu_info
|
|||
|
call save_cpu_info
|
|||
|
MOV CUR_PROCESS.PD_STATUS, INT_ERR_CODE
|
|||
|
JMP TERMINATE
|
|||
|
|
|||
|
; DI is the index in INT_VECT_OWNER of
|
|||
|
; the first free entry
|
|||
|
|
|||
|
free_int_v:
|
|||
|
mov dx,es ; save rts_ds
|
|||
|
|
|||
|
mov ax,ES:word ptr cur_proc_addr + 2
|
|||
|
mov es,ax
|
|||
|
mov ES:cur_process.pd_ds,ds ; save old DS
|
|||
|
mov ds,ax
|
|||
|
|
|||
|
mov cur_process.pd_bp,bp
|
|||
|
mov cur_process.pd_ss,ss
|
|||
|
|
|||
|
; 'pop' interrupt vector id and keep it for later
|
|||
|
mov bp,sp ; take bp to address stack
|
|||
|
mov bx,[bp]+6
|
|||
|
MOV CUR_PROCESS.PD_INT_VECT,BX
|
|||
|
SHL BX, 1
|
|||
|
SHL BX, 1
|
|||
|
; BX is the offset of the Interrupt Vector
|
|||
|
|
|||
|
|
|||
|
; 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:
|
|||
|
|
|||
|
les si,dword ptr [bp]+8 ; A(A(new process))
|
|||
|
mov word ptr cur_process.pd_int_proc,si
|
|||
|
mov word ptr cur_process.pd_int_proc+2,es
|
|||
|
mov ax,ES:word ptr [si] + 2 ; A(new process)
|
|||
|
mov es,ax
|
|||
|
mov ax,ds ; save base of current (old) process
|
|||
|
mov ds,dx ; set DS to rts_ds
|
|||
|
mov word ptr new+2,es
|
|||
|
mov ds,ax ; restore base of current (old) process
|
|||
|
mov es,dx ; set ES to rts_ds
|
|||
|
|
|||
|
; Put the program identifier in the array
|
|||
|
; INT_VECT_OWNER (used to restore it upon
|
|||
|
; termination):
|
|||
|
MOV AX, CUR_PROCESS.PD_PROG_ID
|
|||
|
MOV ES:INT_VECT_OWNER [di], AX
|
|||
|
|
|||
|
; Put the current process in the array
|
|||
|
; WAITING_PROC (the addr of process var):
|
|||
|
SHL di, 1 ; a pointer-index
|
|||
|
mov ax,[bp] + 12
|
|||
|
mov ES: WORD PTR WAITING_PROC [DI],ax
|
|||
|
mov ES: word ptr old,ax
|
|||
|
mov ax,[bp] + 14
|
|||
|
mov ES: WORD PTR WAITING_PROC + 2 [DI],ax
|
|||
|
mov ES: word ptr old+2,ax
|
|||
|
|
|||
|
; Save the requested Interrupt Vector and
|
|||
|
; put the new one:
|
|||
|
MOV AX, 0
|
|||
|
MOV ES, AX
|
|||
|
MOV AX, ES: [BX]
|
|||
|
MOV word ptr CUR_PROCESS.PD_OLD_ISR, AX
|
|||
|
MOV AX, ES: [BX] + 2
|
|||
|
MOV word ptr 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
|
|||
|
|
|||
|
; Execute a normal TRANSFER:
|
|||
|
mov ax,10 ; number of bytes occupied by params
|
|||
|
mov es,dx ; restore ES with rts_ds
|
|||
|
jmp transfer_body0 ; No return to here
|
|||
|
|
|||
|
|
|||
|
; END IOTRANSFER
|
|||
|
;------------------------------------------------------------
|
|||
|
|
|||
|
; public NEWPROCESS
|
|||
|
|
|||
|
NEWPROCESS proc near
|
|||
|
|
|||
|
call save_cpu_info
|
|||
|
mov ds,rts_ds
|
|||
|
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
|
|||
|
pop bp ; aw oct 9 correct stack if error
|
|||
|
JMP STACK_OVF
|
|||
|
; Not even enough room for the workspace
|
|||
|
SIZE_OK:
|
|||
|
ADD AX, 15 ; set P.D. to paragraph boundary
|
|||
|
call norm_addr
|
|||
|
; Upon return:
|
|||
|
; BX = normalised Segment of
|
|||
|
; workspace
|
|||
|
; AX = Offset, < 16
|
|||
|
; aw oct 2
|
|||
|
mov dx,15 ; the number of lost bytes is the complement
|
|||
|
sub dx,ax ; of AX to 15, DX holds number of lost bytes
|
|||
|
|
|||
|
xor ax,ax ; paragraph boundary
|
|||
|
mov [bp] + 16,bx ; set for later use
|
|||
|
mov [bp] + 14,ax
|
|||
|
add ax,(size ProcessDescriptor)
|
|||
|
; Free space starts at the
|
|||
|
; first paragraph after PD.
|
|||
|
; 15 is to round up (worst case).
|
|||
|
|
|||
|
; Set the initial values for the heap managment:
|
|||
|
MOV word ptr TEMP_P_D.PD_HEAP_BASE + 2,BX
|
|||
|
MOV word ptr TEMP_P_D.PD_HEAP_TOP + 2,BX
|
|||
|
MOV word ptr TEMP_P_D.PD_HEAP_BASE,ax
|
|||
|
add ax,10 ; size of a 'FreeListElement'
|
|||
|
MOV word ptr TEMP_P_D.PD_HEAP_TOP,ax
|
|||
|
MOV ES, BX ; segment of heap
|
|||
|
mov si,size ProcessDescriptor
|
|||
|
; put NILs in the header of Free List:
|
|||
|
MOV ES: WORD PTR [si] + 0, NIL_OFF
|
|||
|
MOV ES: WORD PTR [si] + 2, NIL_SEG
|
|||
|
MOV ES: WORD PTR [si] + 4, NIL_OFF
|
|||
|
MOV ES: WORD PTR [si] + 6, NIL_SEG
|
|||
|
MOV ES: WORD PTR [si] + 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 cx,[bp] + 12
|
|||
|
sub cx,dx ; subtract lost bytes
|
|||
|
add ax,sp_ini_size
|
|||
|
sub cx,ax
|
|||
|
ja enough
|
|||
|
pop bp ; aw oct 9 correct stack if error
|
|||
|
jmp stack_ovf
|
|||
|
enough:
|
|||
|
add cx,ax
|
|||
|
mov ax,cx
|
|||
|
and ax,0fffeH ; even Address for StackBase
|
|||
|
|
|||
|
; 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
|
|||
|
|
|||
|
; 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_dbug_status,0 ;for debugger
|
|||
|
|
|||
|
push si ; save ES:[SI]
|
|||
|
push es
|
|||
|
les si,cur_proc_addr
|
|||
|
|
|||
|
; Copy the Program End Stack:
|
|||
|
MOV CX,ES:word ptr CUR_PROCESS.PD_PROG_END
|
|||
|
MOV word ptr TEMP_P_D.PD_PROG_END, CX
|
|||
|
MOV CX,ES:word ptr CUR_PROCESS.PD_PROG_END+2
|
|||
|
MOV word ptr TEMP_P_D.PD_PROG_END+2, CX
|
|||
|
|
|||
|
; Copy the program IDs from the current process:
|
|||
|
MOV AX,ES:CUR_PROCESS.PD_PROG_ID
|
|||
|
MOV TEMP_P_D.PD_PROG_ID, AX
|
|||
|
MOV AX,ES:CUR_PROCESS.PD_SHARED_ID
|
|||
|
MOV TEMP_P_D.PD_SHARED_ID, AX
|
|||
|
|
|||
|
; Copy the Module Table Header:
|
|||
|
MOV AX,ES:word ptr CUR_PROCESS.PD_MOD_TABLE
|
|||
|
MOV word ptr TEMP_P_D.PD_MOD_TABLE, AX
|
|||
|
MOV AX,ES:word ptr CUR_PROCESS.PD_MOD_TABLE+2
|
|||
|
MOV word ptr TEMP_P_D.PD_MOD_TABLE+2, AX
|
|||
|
|
|||
|
; Copy the father process:
|
|||
|
MOV AX,ES:word ptr CUR_PROCESS.PD_FATHER_PROC
|
|||
|
MOV word ptr TEMP_P_D.PD_FATHER_PROC, AX
|
|||
|
MOV AX,ES:word ptr CUR_PROCESS.PD_FATHER_PROC+2
|
|||
|
MOV word ptr 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,NIL_SEG
|
|||
|
JNE NOT_FATHER
|
|||
|
MOV AX,word ptr cur_proc_addr
|
|||
|
MOV word ptr TEMP_P_D.PD_FATHER_PROC, AX
|
|||
|
MOV AX,word ptr cur_proc_addr + 2
|
|||
|
MOV word ptr TEMP_P_D.PD_FATHER_PROC + 2, AX
|
|||
|
NOT_FATHER:
|
|||
|
|
|||
|
MOV CX,ES:CUR_PROCESS.PD_FLAGS
|
|||
|
MOV TEMP_P_D.PD_FLAGS, CX
|
|||
|
|
|||
|
pop es
|
|||
|
pop si
|
|||
|
|
|||
|
; Set the initial priority mask of the system:
|
|||
|
MOV TEMP_P_D.PD_PRIO_MASK, 0 ; no priority
|
|||
|
|
|||
|
; 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
|
|||
|
inc ax ; for PROCESS_END and RTD
|
|||
|
MOV ES: [SI] + 10, AX ; for PROCESS_END and RTD
|
|||
|
MOV ES: [SI] + 12, BX
|
|||
|
|
|||
|
; Copy the Flags:
|
|||
|
MOV ES: [SI] + 4, CX ; And on stack, for the IRET
|
|||
|
MOV ES: [SI] + 14, CX ; for PROCESS_END and RTD
|
|||
|
|
|||
|
MOV AX, 0
|
|||
|
mov es: [si] + 16,ax ; for PROCESS_END and RTD
|
|||
|
|
|||
|
; Set Status to Normal:
|
|||
|
MOV TEMP_P_D.PD_STATUS, AX ; ax still zero
|
|||
|
; 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 ax,word ptr cur_proc_addr + 2
|
|||
|
mov ds,ax
|
|||
|
MOV DS, CUR_PROCESS.PD_DS
|
|||
|
POP BP
|
|||
|
IRET
|
|||
|
NEWPROCESS endp
|
|||
|
;------------------------------------------------------------
|
|||
|
|
|||
|
|
|||
|
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 es,CS:rts_ds
|
|||
|
call save_cpu_info
|
|||
|
mov bp,sp
|
|||
|
add bp,6 ; set bp for debugger
|
|||
|
MOV CUR_PROCESS.PD_STATUS, PROCESS_END_CODE
|
|||
|
JMP TERMINATE
|
|||
|
|
|||
|
;------------------------------------------------------------
|
|||
|
|
|||
|
|
|||
|
; 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:
|
|||
|
call save_cpu_info
|
|||
|
mov es,rts_ds
|
|||
|
CMP BX, MAX_PRIO_LEVEL
|
|||
|
JBE LEVEL_OK
|
|||
|
MOV BX, MAX_PRIO_LEVEL
|
|||
|
LEVEL_OK:
|
|||
|
POP SI ; remove return block
|
|||
|
POP DX
|
|||
|
POP CX
|
|||
|
PUSH cur_process.pd_prio_mask ; save old mask
|
|||
|
MOV al, es: priority_masks [bx]
|
|||
|
; xor ah, ah
|
|||
|
MOV CUR_PROCESS.PD_PRIO_MASK, AX
|
|||
|
|
|||
|
;**** Here the code of SET_INTERRUPT_MASK has been inserted:
|
|||
|
or ax, es: device_mask
|
|||
|
out mask_8259,al
|
|||
|
;**** End of insertion
|
|||
|
|
|||
|
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.
|
|||
|
call save_cpu_info
|
|||
|
POP SI ; remove return block
|
|||
|
POP DX
|
|||
|
POP CX
|
|||
|
POP AX ; old mask
|
|||
|
MOV CUR_PROCESS.PD_PRIO_MASK, AX
|
|||
|
;**** Here the code of SET_INTERRUPT_MASK has been inserted:
|
|||
|
mov es,rts_ds
|
|||
|
or ax, es: device_mask
|
|||
|
out mask_8259,al
|
|||
|
;**** End of insertion
|
|||
|
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
|
|||
|
; temporarily. 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.
|
|||
|
call save_cpu_info
|
|||
|
PUSH cur_process.pd_prio_mask ; save it
|
|||
|
XOR AX, AX
|
|||
|
MOV CUR_PROCESS.PD_PRIO_MASK, AX
|
|||
|
CALL SET_INTERRUPT_MASK ; 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
|
|||
|
CALL SET_INTERRUPT_MASK ; restore old mask
|
|||
|
MOV DS, CUR_PROCESS.PD_DS
|
|||
|
IRET
|
|||
|
|
|||
|
;------------------------------------------------------------
|
|||
|
|
|||
|
|
|||
|
get_device_status:
|
|||
|
;=================
|
|||
|
; this function returns the status (enabled or disabled) of a device
|
|||
|
; upon entry: CX holds the device number [0..maxdevice]
|
|||
|
; this is the bit number of the device in the
|
|||
|
; interrupt controller mask
|
|||
|
; upon exit: BX holds the inverse bit value in the device_mask
|
|||
|
; BX = 1 (TRUE ) -> enabled
|
|||
|
; BX = 0 (FALSE) -> disabled
|
|||
|
|
|||
|
; IF device IN device_mask THEN
|
|||
|
; enabled := FALSE;
|
|||
|
; ELSE
|
|||
|
; enabled := TRUE;
|
|||
|
; END;
|
|||
|
|
|||
|
call save_cpu_info
|
|||
|
mov ds, rts_ds
|
|||
|
mov ax, 1
|
|||
|
shl ax, cl
|
|||
|
test device_mask, ax
|
|||
|
jz enabled
|
|||
|
xor bx, bx
|
|||
|
jmp end_get
|
|||
|
enabled:
|
|||
|
mov bx, 1
|
|||
|
end_get:
|
|||
|
iret
|
|||
|
|
|||
|
|
|||
|
|
|||
|
set_device_status:
|
|||
|
;=================
|
|||
|
; this function sets the status (enable or disable) of a device
|
|||
|
; upon entry: CX holds the device number [0..maxdevice]
|
|||
|
; this is the bit number of the device in the
|
|||
|
; interrupt controller mask
|
|||
|
; BX holds the inverse bit value to write into the device_mask
|
|||
|
; BX = 1 (TRUE ) -> enable
|
|||
|
; BX = 0 (FALSE) -> disable
|
|||
|
|
|||
|
; IF enable THEN
|
|||
|
; EXCL(device_mask, device)
|
|||
|
; ELSE
|
|||
|
; INCL(device_mask, device)
|
|||
|
; END;
|
|||
|
; SetInterruptMask(cur_process.prio_mask)
|
|||
|
|
|||
|
call save_cpu_info
|
|||
|
mov es, rts_ds
|
|||
|
mov ax, 1
|
|||
|
shl ax, cl
|
|||
|
disable: ; set the bit
|
|||
|
or es:device_mask, ax
|
|||
|
or bx, bx ; CMP BX, 0
|
|||
|
jz end_set
|
|||
|
enable: ; clear the bit
|
|||
|
not ax
|
|||
|
and es:device_mask, ax
|
|||
|
end_set:
|
|||
|
mov ax, cur_process.pd_prio_mask
|
|||
|
call set_interrupt_mask
|
|||
|
iret
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
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
|
|||
|
PUSH DS ; save it
|
|||
|
MOV AX, 0FFFFH ; used as NIL
|
|||
|
MOV word ptr 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 segment of waiting process
|
|||
|
; and SI is its offset
|
|||
|
MOV DI, PD_INT_VECT [SI] ; offset of I.V.
|
|||
|
SHL di, 1
|
|||
|
SHL di, 1
|
|||
|
ADD SI, PD_OLD_ISR
|
|||
|
MOVSW
|
|||
|
MOVSW
|
|||
|
POP DS ; restore it
|
|||
|
RET
|
|||
|
FREE_1_VECT endp
|
|||
|
|
|||
|
|
|||
|
; public REST_I_V
|
|||
|
|
|||
|
REST_I_V proc near
|
|||
|
;=================
|
|||
|
mov si,word ptr cur_proc_addr + 2
|
|||
|
mov es,si
|
|||
|
MOV CX,ES: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 CX, BX
|
|||
|
JE FREE_THIS_ONE
|
|||
|
CMP CX, 0 ; 0 is used as a joker:
|
|||
|
JNE I_V_DONE ; it's not 0
|
|||
|
CMP BX, NIL_CARD ; it's 0: free all vectors,
|
|||
|
JE I_V_DONE ; if owner not 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 save_cpu_info
|
|||
|
CALL REST_I_V
|
|||
|
IRET
|
|||
|
|
|||
|
;************** handling of control break key ********************************
|
|||
|
|
|||
|
|
|||
|
iret_instr equ 0CFH
|
|||
|
|
|||
|
address struc
|
|||
|
off dw ?
|
|||
|
base dw ?
|
|||
|
address ends
|
|||
|
|
|||
|
flagtype record fooHigh: 7, trace_flag: 1, fooLow: 8
|
|||
|
|
|||
|
return_block struc
|
|||
|
save_bp dw ?
|
|||
|
return_addr dd ? ; address
|
|||
|
flags dw ? ; flagtype
|
|||
|
old_ret_addr dd ? ; address
|
|||
|
old_flags dw ? ; flagtype
|
|||
|
return_block ends
|
|||
|
|
|||
|
|
|||
|
|
|||
|
;*****************************************************************************
|
|||
|
vectors segment at 0
|
|||
|
|
|||
|
org 1 * 4
|
|||
|
|
|||
|
single_step_vector address <>
|
|||
|
|
|||
|
org 1BH * 4
|
|||
|
|
|||
|
ctrl_break_vector address <>
|
|||
|
|
|||
|
vectors ends
|
|||
|
;*****************************************************************************
|
|||
|
|
|||
|
|
|||
|
|
|||
|
;*****************************************************************************
|
|||
|
data segment public 'data'
|
|||
|
|
|||
|
save_single_step_vector address <>
|
|||
|
|
|||
|
data ends
|
|||
|
;*****************************************************************************
|
|||
|
|
|||
|
|
|||
|
|
|||
|
stopped_23:
|
|||
|
;==========
|
|||
|
int 1BH
|
|||
|
nop
|
|||
|
iret
|
|||
|
|
|||
|
|
|||
|
|
|||
|
STOPPED_1B: ; entry for interrupt 1bH
|
|||
|
;==========
|
|||
|
push bp
|
|||
|
mov bp, sp
|
|||
|
push ds
|
|||
|
push es
|
|||
|
push si
|
|||
|
push ax
|
|||
|
|
|||
|
mov ds, rts_ds
|
|||
|
|
|||
|
xor ax, ax ; es:0 points to interrupt
|
|||
|
mov es, ax ; vector table
|
|||
|
|
|||
|
; set interrupt vector for control break to a dummy ISR
|
|||
|
mov si, offset ctrl_break_vector
|
|||
|
mov es: [si].off, offset CGROUP: DUMMY_ISR
|
|||
|
; we know that ctrl_break_vector.base is already set to CS
|
|||
|
|
|||
|
; save interrupt vector for single step
|
|||
|
mov si, offset single_step_vector
|
|||
|
mov ax, es: [si].off
|
|||
|
mov save_single_step_vector.off, ax
|
|||
|
mov ax, es: [si].base
|
|||
|
mov save_single_step_vector.base, ax
|
|||
|
|
|||
|
; set interrupt vector for single step
|
|||
|
mov es: [si].base, cs
|
|||
|
mov es: [si].off, offset CGROUP: single_step
|
|||
|
|
|||
|
or [bp].flags, mask trace_flag ; set trace bit
|
|||
|
|
|||
|
pop ax
|
|||
|
pop si
|
|||
|
pop es
|
|||
|
pop ds
|
|||
|
pop bp
|
|||
|
iret ; we single step through the following instructions
|
|||
|
; until we are back in modula-2 code
|
|||
|
|
|||
|
|
|||
|
single_step:
|
|||
|
; save used registers
|
|||
|
push bp
|
|||
|
mov bp, sp
|
|||
|
push es
|
|||
|
push si
|
|||
|
push dx
|
|||
|
push ds
|
|||
|
push ax
|
|||
|
|
|||
|
les si, [bp].return_addr
|
|||
|
mov dx, es ; es holds codesegment of interrupted
|
|||
|
; instruction
|
|||
|
mov ds, rts_ds ; check if we are in modula-2 code
|
|||
|
mov ax, m2_start_mark
|
|||
|
cmp dx, ax ; lower limit
|
|||
|
jb no
|
|||
|
mov ax, m2_end_mark
|
|||
|
cmp dx, ax ; upper limit
|
|||
|
jbe possible_stop
|
|||
|
|
|||
|
no: cmp byte ptr es: [si], iret_instr
|
|||
|
jne goon
|
|||
|
; make sure that we stay in single step mode after an IRET
|
|||
|
or [bp].old_flags, mask trace_flag ; set trace bit
|
|||
|
|
|||
|
goon: ; make sure that we stay in single step mode
|
|||
|
; it's possible that somebody has modified our
|
|||
|
; return block on the stack
|
|||
|
or [bp].flags, mask trace_flag ; set trace bit
|
|||
|
pop ax
|
|||
|
pop ds
|
|||
|
pop dx
|
|||
|
pop si
|
|||
|
pop es
|
|||
|
pop bp
|
|||
|
iret
|
|||
|
|
|||
|
possible_stop:
|
|||
|
|
|||
|
xor ax, ax ; es:0 points to interrupt
|
|||
|
mov es, ax ; vector table
|
|||
|
|
|||
|
; restore interrupt vector for single step
|
|||
|
mov si, offset single_step_vector
|
|||
|
mov ax, save_single_step_vector.off
|
|||
|
mov es: [si].off, ax
|
|||
|
mov ax, save_single_step_vector.base
|
|||
|
mov es: [si].base, ax
|
|||
|
|
|||
|
; reset interrupt vector for control break
|
|||
|
mov si, offset ctrl_break_vector
|
|||
|
mov es: [si].off, offset CGROUP: stopped_1B
|
|||
|
; we know that ctrl_break_vector.base is already set to CS
|
|||
|
|
|||
|
|
|||
|
mov es,rts_ds
|
|||
|
|
|||
|
lea sp, [bp] ; reset stack,
|
|||
|
pop bp ; don't restore saved registers
|
|||
|
|
|||
|
call save_cpu_info
|
|||
|
|
|||
|
mov cur_process.pd_status,warned_code
|
|||
|
JMP terminate
|
|||
|
|
|||
|
|
|||
|
;************** handling of control break key ********************************
|
|||
|
|
|||
|
code ends
|
|||
|
|
|||
|
;*****************************************************************************
|
|||
|
|
|||
|
|
|||
|
end
|
|||
|
|