[comp.os.vms] code to DISCONNECT a terminal

KVC@ENGVAX.SCG.HAC.COM (Kevin Carosso) (07/28/87)

        .TITLE  UNLINK_VT a set of routines to unlike a VT
        .IDENT  /V1.0-000/
        .LIBRARY /SYS$LIBRARY:LIB.MLB/

;++
;
;               These routines are a system hack to allow a privileged user
;       to disconnect a VT with outstanding I/O from it's physical device.
;       The correct way to perform this would be to modify the code in TTDRIVER
;       that does the disconnect.  For testing purpose this is a more expediant
;       way to accomplist this goal.
;
;       NOTE:
;               The required privs to use this are:
;
;                       1) CMKRNL
;                       2) SHARE
;
; CALLING SEQUENCE:
;
;       ret_stat = UNLINK_VT (device_name)
;
;       device_name     -       address of a string descriptor, the string must
;                               contain name of VT to be disconnected (ex VTA0:)
;
; AUTHOR:
;
;       Forrest A. Kenney       28-August-1986
;
; REVISION HISTORY:
;
;       Kevin Carosso           14-JUL-1987     Hughes Aircraft, SCG/CTC
;               Modified a bit for local use, don't bother with
;               the privilege checks, must have CMKRNL and SHARE only.
;               Raise to device IPL while mucking in the UCB as
;               Forrest Kenney suggested.
;
;               Clear R2 before calling IOC$SEARCH.  Since we now run
;               above IPL 2, we have to lock our kernel code into memory.
;
;--









        .SBTTL  External and local symbol definitions

;
; External symbols
;

        $CCBDEF                         ; Define CCB
        $DVIDEF                         ; Device information
        $IPLDEF                         ; Define various CPU IPL levels
        $JPIDEF                         ; Process information
        $SSDEF                          ; System status codes
        $UCBDEF                         ; Unit control block
        $TTYDEFS                        ; TTY specific definitions
        $TTYMACS                        ; Define terminal macros
        $TTYUCBDEF                      ; TTY UCB definitions


;+
; A simple macro to help build item list items
;-
        .MACRO  ITEM    LENGTH,CODE,BUFF_ADDR,RET_LEN=0

        .WORD           LENGTH
        .WORD           CODE
        .ADDRESS        BUFF_ADDR
        .ADDRESS        RET_LEN

        .ENDM   ITEM









        .SBTTL  Allocate local storage


        .PSECT  $DATA   LONG,NOEXE,RD,WRT

DEVNAM: .BLKB   64                      ; Block hold PHYDEV name
        DEVNAM_LEN = .-DEVNAM
DEVNAM_SIZ:                             ; Storage for length of PHYDEV name
        .LONG   0

DISC_FLAG:                              ; Is device disconnectable
        .LONG   0

CHANNEL:
        .WORD   0                       ; Channel number for assign
IOSB:   .BLKW   4                       ; IOSB for $GETDVI

DVILST: ITEM    DEVNAM_LEN,DVI$_TT_PHYDEVNAM,DEVNAM,DEVNAM_SIZ
        ITEM    4,DVI$_TT_DISCONNECT,DISC_FLAG
        .LONG   0

lock_range:                             ; For $LKWSET call
        .address        begin_lock
        .address        end_lock










        .PSECT  $CODE   LONG,PIC,NOWRT,RD,EXE,CON,REL,LCL,SHR
        .SBTTL  Validate device & request
;+
;
;               This routine will validate the device to be disconnected is a
;       virtual terminal and the the user has the correct privs to do it.  The
;       sequence is listed below:
;
;               1) Assign a channel to the device
;               2) Determine if device can be disconnected
;               3) Calls KERNEL mode routine (to get UCB address and disconnect
it)
;
;       INPUTS:
;               4(AP)   - Address of a descriptor containing device name
;
;       OUTPUT:
;               R0      - Status of operation
;
;                               SS$_IVDEVNAM
;                               SS$_NOPRIV
;                               any possible returns from $ASSIGN or $GETDVI
;
;-

        .ENTRY  UNLINK_VT,^M<>

;+
; Lock down our kernel mode, high IPL code.
;-
        $LKWSET_S       INADR = lock_range
        blbs    r0, 5$
        ret
;+
; Get a channel to work with
;-
5$:     CLRQ    -(SP)                   ; Default acmode & no mailbox
        MOVAW   CHANNEL,-(SP)           ; Address of word to hold channel #
        MOVL    4(AP),-(SP)             ; Address of device name string
        CALLS   #4,G^SYS$ASSIGN         ; Assign channel
        BLBS    R0,10$                  ; Success continue
        RET                             ; Failed return with reason
;+
; Now get the device information and make sure it can be disconnected,
; also make sure that don't try to disconnect an already disconnected device
;-
10$:    $GETDVIW_S      CHAN=CHANNEL,-  ; Get device information
                        ITMLST=DVILST,- ;
                        IOSB=IOSB       ;
        BLBS    R0,20$                  ; Setup ok continue
        PUSHL   R0                      ; Save error reason
        BRW     1000$                   ; Branch to exit code
20$:    BLBS    IOSB,30$                ; OK continue
        MOVZWL  IOSB,-(SP)              ; Store failure reason
        BRW     1000$                   ; Branch to exit code
30$:    BLBS    DISC_FLAG,40$           ; Device disconnectable cont
        MOVZWL  #SS$_IVDEVNAM,-(SP)     ; Inproper device for requested operatio
n
        BRW     1000$                   ; Branch to exit code
40$:    TSTL    DEVNAM_SIZ              ; See if got physical device name
        BNEQ    80$                     ; If zero length then already disconnect
ed
        MOVZWL  #SS$_NORMAL,-(SP)       ; Store failure reason
        BRW     1000$                   ; Branch to exit code
;+
; Now build arg list & call Kernel mode routine
;-
80$:    MOVL    AP,-(SP)                ; Store device argument list on stack
        MOVAL   KRNL_CODE,-(SP)         ; Store address of Kernel routine on sta
ck
        CALLS   #2,SYS$CMKRNL           ; Invoke kernel mode routine
        PUSHL   R0                      ; Save status reason

;+
; We have a channel to free before exiting
;-
1000$:  $DASSGN_S       CHAN=CHANNEL    ; Free channel
        BLBS    R0,1010$                ; Ok just exit with correct reason
        MOVL    R0,R1                   ; Save channel DASSGN error
        POPL    R0                      ; Get previous status code
        BLBC    R0,1020$                ; Use first error
        MOVL    R0,R1                   ; Use DASSGN error
        RET                             ; Return
1010$:  POPL    R0                      ; Restore reason
1020$:  RET                             ; Return to caller

;+
; This section of code needs to run at elevated IPL to prevent process
; deletion while owning I/O database MUTEX.  It also will use a backdoor
; hook into the TTDRIVER to UNLINK the VT.
;
;       Note:   R4 contains the current processes PCB address it is suppiled by
;               the change mode dispatcher.  It is needed by SCH$IOLOCKR &
;               SCH$IOUNLOCK
;
;-
begin_lock:

        .ENTRY  KRNL_CODE,^M<R3,R5>
        DSBINT  #IPL$_ASTDEL            ; Raise IPL to prevent process deletion
        JSB     G^SCH$IOLOCKR           ; Lock the I/O database for read access
        MOVL    4(AP),R1                ; Get device descriptor string address
        CLRL    R2                      ; No flags
        CLRL    R3                      ; No lock value block
        JSB     G^IOC$SEARCH            ; Now find the devices UCB
        CMPW    R0,#SS$_DEVALLOC        ; See if device allocated
        BEQL    10$                     ; If allocated proceeded
        BLBC    R0,30$                  ; If no device then exit

10$:    DSBINT  UCB$B_DIPL(R1)          ; Raise to device IPL
        MOVL    UCB$L_TL_PHYUCB(R1),R5  ; Get device's physical UCB address
        BEQL    20$                     ; Device already disconnected just exit
        PUSHL   R4                      ; Save PCB address
        MOVL    UCB$L_TT_CLASS(R5),R4   ; Get class dispatch table address
        JSB     @CLASS_DISCONNECT(R4)   ; Now call disconnect code
        POPL    R4                      ; Restore PCB address
20$:    ENBINT                          ; drop back down
        MOVZWL  #SS$_NORMAL,R0          ; Store success as exit reason

30$:    PUSHL   R0                      ; Save reason
        JSB     G^SCH$IOUNLOCK          ; Unlock I/O database
        POPL    R0                      ; Restore reason
        ENBINT                          ; Lower IPL back to calling level
        RET
;
; Lock down pages between "begin_lock" and here so we don't pagefault
; at high IPL
;
end_lock:
        .END