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