;-- ; Copyright © 1994 by Brian Schenkenberger. All rights reserved. ; ------------------------- ; This software is provided "as is" and is supplied for informational purpose ; only. No warranty is expressed or implied and no liability can be accepted ; for any actions or circumstances incurred from the use of this software or ; from the information contained herein. The author makes no claim as to the ; suitablility or fitness of the software or information contained herein for ; a particular purpose. ; ------------------------- ; This software may be copied and distributed only with the inclusion of this ; copyright notice. ;-- .TITLE CTRLV ; demo of how to load code into P1 space on both ; OpenVMS VAX and OpenVMS AlphaAXP (common code) .IDENT /V2.4%253/ ;++ ; This program demonstrates how to load code into process P1 space on both ; OpenVMS VAX and OpenVMS AlphaAXP systems. This program makes use of the ; OpenVMS image activation system services, $IMGACT and $IMGFIX. This is ; especially important on an Alpha system because code on Alpha can not be ; arbitrarily placed into address space. To overcome this limitation, the ; code to be loaded into P1 virtual address space is placed in a shareable ; image which is then, activated into P1 address space. Implementing this ; mechanism permits the $IMGFIX system service to "fix-up" image addresses ; relative to the location where the image has be loaded. ; ; In order for this mechanism to work, this program (aka. the loader) must ; be built as a P0 only image. This is because the shareable image will be ; activated in P1 space directly below the process permanent portion of P1 ; space and will then, become a part of the permanent portion of P1 space. ; This program *must* be a P0 only image to keep the virtual address space ; just below the process permanent portion of P1 space free. ; ; The program works in two steps. First, the shareable image is activated ; into P0 space to determine the size of the activated image. The $IMGACT ; system service can not expand the region of P1 space to place the image ; since P1 space grows downward; therefore, it can not determine the base ; address to start mapping the image. By first activating the image in P0 ; space, the size of the activated iage can be determined. ; ; When the size has been determined, the second step occurs. The image is ; activated a second time with the $IMGACT system service's INADR argument ; pointing to the calculated address range in P1 space. $IMGFIX is called ; to fixup the relocated image. ; ; The P1 cell, CTL$GL_CTLBASVA is updated to contain the lowest P1 virtual ; address, thus, making the newly activated image a part of the P1 process ; permanent region. ; ; The OOB AST is then established, obtaining the AST routine address from ; its stored loction at the base address of the image in P1 space. (Note: ; This routine assume that the shareable image has be built such that, the ; base of the image contains the address of the procedure's entry point.) ;-- ; Author: ; Brian Schenkenberger, VAXman- VAXman@AdvSysCon.COM ;-- ; Modified: 06-AUG-1994 (author's b'day) ; Added code to support CTRL-Verify as a prilieged installed utility. ; If installed, program must be granted CMEXEC and LOG_IO privilege. ; Added code to change the control key designation at run-time. ; ; This code was originally intended to be a "how-to-do" demonstration ; package. However, since it is being used as a privileged installed ; utility, the code has been modified to plug a security "hole". The ; logical "VAST_SHARE" must now be specified as /SYSTEM/EXEC. This is ; to avoid having an outer mode logical defined to point to some other ; shareable image which would then be executed in EXECUTVE mode. ; ; Modified: 12-AUG-1994 ; Added code to support the use of CTRL-Verify in a subprocess. The ; OOB AST "toggle-verify" function is now unique to each process. ; ; Modified: 10-SEP-1994 ; Added code to get the terminal specific display attributes from the ; SMG terminal table. ;-- ; VAX Build: ; $ MACRO LOAD_CTRLV.MAR ; $ SET COMMAND/OBJECT CTRLVCMD.CLD ; $ LINK/NOTRACEBACK/P0IMAGE LOAD_CTRLV.OBJ,CTRLVCMD.OBJ ;-- ; AXP Build: ; $ MACRO LOAD_CTRLV.MAR ; $ SET COMMAND/OBJECT CTRLVCMD.CLD ; $ LINK/NOTRACEBACK/P0IMAGE/NATIVE LOAD_CTRLV.OBJ,CTRLVCMD.OBJ ;-- .LIBRARY "SYS$LIBRARY:LIB" .LINK "SYS$SYSTEM:SYS.STB"/SE ; (/SYSEXE on Alpha) ;++ ; Determine the target architecture ;-- .ntype ...on_alpha...,R31 .iif eq,<...on_alpha...@-4&^xF>-5, alpha=0 .iif df,alpha, .disable flagging ;++ ; Local macro definitions ;-- .MACRO CHKSTS STS,RTN=RET,?L1 ; simple CHecK STatuS macro BLBS STS,L1 RTN L1: .ENDM CHKSTS ;++ ; Local symbol definitions ;-- MAXLEN = 40 ; maximum size of work string buffer ;++ ; Include file definitions ;-- $CCBDEF ; channel control block definitions $DCDEF ; device class code definitions $DSCDEF ; descriptor type and class codes $IACDEF ; image activation control flags $IODEF ; queue I/O service definitions $JIBDEF ; job information block definitions $PCBDEF ; prc. control block definitions $PHDDEF ; prc. header block definitions $PRVDEF ; prc. privilege mask definitions $PSLDEF ; prc. status longword definitions $SSDEF ; system status code definitions $STSDEF ; system status field definitions $TASTDEF ; terminal AST control block def's $TTYUCBDEF ; terminal ucb extension definitions ;++ ; Program data section ;-- .PSECT DATA,WRT,NOEXE,5 IMGHDR: .BLKB 512 ; storage for activated image header REQADR: .QUAD 0 ; requested virtual address range RETADR: .QUAD 0 ; returned virtual address range DEV: .QUAD 0 ; device name descriptor stored here CHAN: .LONG 0 ; assigned channel number stored here CTRLV: .LONG 0 ; storage for control character MASK: .LONG 0 ;\ .LONG 0 ;- mask for out-of-band control key AST IOSB: .QUAD 0 ; storage for the I/O status block CHAR: .QUAD 0 ; storage for terminal characteristics ASSUME PRV$V_LOG_IO LT 32 ASSUME PRV$V_CMEXEC LT 32 PRIVS: .LONG PRV$M_LOG_IO!PRV$M_CMEXEC ; mask to set .LONG ; required priv CMDLIN: .LONG !,0 KEYCOD: .LONG !,0 VON: .LONG !,0 VOFF: .LONG !,0 WRKSTR: LENGTH: .LONG 0 .ADDRESS BUFFER BUFFER: .BLKB MAXLEN TRMTBL: .LONG 0 ; storage for the terminal table ;_________11111111112222222222333333333344444444445555555 ;12345678901234567890123456789012345678901234567890123456 OFFSTR: .ASCID / Verify-Off / ONSTR: .ASCID / Verify-On / OFFUNK: .ASCID /*VERIFY-OFF*/ ONUNK: .ASCID /*VERIFY-ON*/ .ALIGN LONG IMAGE: .ASCID /VAST_SHARE/ ; the logical name defined .ALIGN LONG FORMAT: .ASCID /CTRL-Verify loaded at: !XL for key CTRL-!AS / OUTPUT: .ASCID / / VERB: .ASCID /CTRLV / QUAL: .ASCID /KEY/ ;++ ; Program code section ;-- .PSECT CODE,NOWRT,EXE,5 .ENTRY INSTALL$KEY_AST,0 PUSHAB CMDLIN CALLS #1,G^LIB$GET_FOREIGN ; get the command line CHKSTS R0 ; check status PUSHAB VERB ; prepend the foreign command line PUSHAB CMDLIN ; with the verb before parsing CALLS #2,G^STR$PREFIX CHKSTS R0 ; check status PUSHAB G^LIB$GET_INPUT PUSHAB CTRLV_CLITABLE ; CTRL-VERIFY symbol table PUSHAB CMDLIN ; the command to be parsed CALLS #3,G^CLI$DCL_PARSE ; parse it. BISL2 #STS$M_INHIB_MSG,R0 ; don't let DCL report error CHKSTS R0 ; check status PUSHAB KEYCOD PUSHAB KEYCOD ; dynamic string to hold key PUSHAB QUAL ; get value of /KEY entity CALLS #3,G^CLI$GET_VALUE CHKSTS R0 ; check status CMPW KEYCOD,#1 ; single character keyword? BEQL 10$ ; branch if true. PUSHAB KEYCOD PUSHAB KEYCOD ; reuse the dynamic string PUSHAB KEYCOD ; get value of KEYWORD entity CALLS #3,G^CLI$GET_VALUE CHKSTS R0 ; check status 10$: SUBB3 #^a/@/,@KEYCOD+4,R0 ; compute value of control character BICL3 #^c^x1F,R0,CTRLV ; mask it and save it BBSS CTRLV,MASK+4,20$ ; define the OOB mask 20$: $SETPRV_S ENBFLG=#1,PRVADR=PRIVS ; enable LOG_IO privy CHKSTS R0 $CMEXEC_S ROUTIN=EXEC$ROUTINE BLBS R0,30$ PUSHL R0 PUSHL #1 MOVAB (SP),R0 $PUTMSG_S MSGVEC=(R0) RET 30$: MOVAB KEYCOD,R0 $FAO_S CTRSTR=FORMAT,OUTBUF=OUTPUT,OUTLEN=OUTPUT,- P1=@#CTL$GL_CTLBASVA,P2=R0 PUSHAL OUTPUT CALLS #1,G^LIB$PUT_OUTPUT RET ;++ ; The following code is called at executive mode to perform the "magic". ;-- .ENTRY EXEC$ROUTINE,^M MOVL @#CTL$GL_PCB,R4 ; get P1 mapping of PCB BBS #PCB$V_INTER,PCB$L_STS(R4),10$ ; is process interactive? MOVL #SS$_IVMODE,R0 ; no! say SS$_IVMODE RET 10$: MOVL PCB$L_JIB(R4),R0 ; get the process's JIB address MOVL JIB$L_MPID(R0),R0 ; get the process's master IPID .if ndf alpha JSB G^EXE$IPID_TO_PCB ; get PCB of the master process .if_false JSB G^EXE$CVT_IPID_TO_PCB ; get PCB of the master process TSTL R0 ; needed on Alpha for the BLSS .endc BLSS 20$ MOVL #SS$_NONEXPR,R0 ; got here??? say SS$_NONEXPR RET 20$: MOVZBL PCB$T_TERMINAL(R0),DEV ; get terminal length MOVAL PCB$T_TERMINAL+1(R0),DEV+4 ; and name address $ASSIGN_S DEVNAM=DEV,- ; assign channel to term CHAN=CHAN CHKSTS R0 ; check status .if ndf alpha SUBL3 CHAN,@#CTL$GL_CCBBASE,R1 ; get address of the CCB .if_false CLRL -(SP) ; clear stack for CCB PUSHL SP ; push its adr on stack PUSHL CHAN ; along with the channel CALLS #2,G^IOC$CHAN_TO_CCB ; get address of the CCB MOVL @(SP)+,R1 ; CCB to R1, fixup stack .endc MOVL CCB$L_UCB(R1),R5 ; get address of the UCB MOVAL UCB$L_TL_BANDQUE(R5),R3 ; get adr of TAST list 30$: MOVL (R3),R3 ; get TAST block off list BEQL 40$ ; no more TAST blocks CMPL (R3),- ; is this TAST associated PCB$L_PID(R4) ; with this process? BNEQ 30$ ; no. try another one... BBC CTRLV,- ; quit if CTRLV already set (R3),30$ $DASSGN_S CHAN=CHAN ; deassign unused channel MOVZWL #SS$_VECINUSE,R0 ; signify AST already loaded RET 40$: SMG$K_BEGIN_REVERSE = 447 ;\ values not defined in SMG$K_END_REVERSE = 470 ; \ SYS$SHARE:STARLET.MLB SMG$K_SAVE_CURSOR = 560 ; / values extracted from SMG$K_RESTORE_CURSOR = 558 ;/ SYS$SHARE:STARLET.REQ $QIOW_S EFN=#0,- ; get the characteristics of the CHAN=CHAN,- ; terminal FUNC=#IO$_SENSEMODE,- IOSB=IOSB,- P1=CHAR,P2=#8 CHKSTS R0 ; should we continue CHKSTS IOSB ; should we continue CMPB CHAR,#DC$_TERM ; is it _really_ a terminal? BEQL 50$ ; should we continue RET 50$: PUSHL #0 PUSHAL TRMTBL ; initialize a term table PUSHAB CHAR+1 ; for this terminal type CALLS #3,G^SMG$INIT_TERM_TABLE_BY_TYPE TSTL TRMTBL ; was a terminal table found? BNEQ 60$ ; yes! then look up sequence MOVQ OFFUNK,VOFF ; VOFF -> unknown term format MOVQ ONUNK,VON ; VON -> unknown term format BRB 70$ 60$: MOVAL #SMG$K_SAVE_CURSOR,R0 ; save cursor position sequence JSB BUILD_STRINGS ; append seq. to message strings MOVAL #SMG$K_BEGIN_REVERSE,R0 ; begin reverse video sequence JSB BUILD_STRINGS ; append seq. to message strings PUSHAB OFFSTR ; copy "Verify-Off" string PUSHAB VOFF ; into message string CALLS #2,G^STR$APPEND CHKSTS R0 ; should we continue PUSHAB ONSTR ; copy "Verify-On" string PUSHAB VON ; into message string CALLS #2,G^STR$APPEND CHKSTS R0 ; should we continue MOVAL #SMG$K_END_REVERSE,R0 ; end reverse video sequence JSB BUILD_STRINGS ; append seq. to message strings MOVAL #SMG$K_RESTORE_CURSOR,R0; restore cursor position seq. JSB BUILD_STRINGS ; append seq. to message strings 70$: $IMGACT_S - ; activate image in P0VA space NAME=IMAGE,- ; shareable image file name HDRBUF=IMGHDR,- ; buffer for image header IMGCTL=#,- RETADR=RETADR,- ; returned P0VA mapped range ACMODE=#PSL$C_USER ; user mode access CHKSTS R0 ; should we continue ;++ ; At this point, the image has been activated into P0 space so that the ; size of the activated image can be calculated. We no longer need nor ; want the image activated in P0 space. The image control block of the ; image (ICB/IMCB) is removed from the done list (IAC$GL_IMAGE_LIST) to ; allow the $IMGACT service to properly complete the P1 space activation. ; The P0 VA space occupied by the activation is deleted. This is not a ; real necessity in this program since, P0 address space is deleted as ; a consequence of image rundown. ;-- REMQUE @IAC$GL_IMAGE_LIST+4,R0 ; I(M)CB should be a end of queue BVS 80$ ; was queue empty? (shouldn't be) INSQUE (R0),@IAC$GL_ICBFL+4 ; put I(M)CB on the lookaside list 80$: $DELTVA_S INADR=RETADR ; delete P0VA range from $imgact CHKSTS R0 ; should we continue ;++ ; Calculate the address range in P1 space into which the image will be re- ; activated. ;-- MOVQ RETADR,R0 ; R0=lo P0VA, R1=hi P0VA SUBL2 R0,R1 ; calc. # of bytes mapped MOVL @#CTL$GL_PHD,R0 ; get P1 mapping of PHD ADDL3 MMG$GL_BWP_MASK,- ;\ calc. lowest P1VA PHD$L_FREP1VA(R0),R3 ;/ SUBL3 R1,R3,R2 ;\ calc. starting P1VA BICL2 MMG$GL_BWP_MASK,R2 ;/ MOVQ R2,REQADR ; move P1VA range to reqadr $IMGACT_S - ; activate image in P1VA space NAME=IMAGE,- ; shareable image file name HDRBUF=IMGHDR,- ; buffer for image header IMGCTL=#,- ; activation flags INADR=REQADR,- ; requested P1VA range RETADR=RETADR,- ; returned P1VA range ACMODE=#PSL$C_EXEC ; executive mode access CHKSTS R0 ; should we continue $IMGFIX_S ; do image address fixup CHKSTS R0 ; should we continue ;++ ; P1 space is allocated for the verify message strings and addresses ; of the strings in P1 space are modified in the image. ;-- $OFFSET 0,POSITIVE,<- ; offsets in the loaded image ,- ; offset to the OOB AST routine ,- ; offset to initialization rtn. ,- ; offset to image's V$OFF desc. > ; offset to image's V$ON desc. ADDW3 VON,VOFF,R1 ; calc how much space we need MOVZWL R1,R1 ; convert it to a longword JSB G^EXE$ALOP1PROC ; ask for the p1 space CHKSTS R0 ; should we continue MOVL RETADR,R0 ; get base address of loaded image MOVZWL VOFF,R1 ; get the length of V-off message MOVQ R1,V$OFF(R0) ; copy descriptor to loaded image MOVC3 R1,@VOFF+4,(R2) ; copy V-off string into P1 space MOVL RETADR,R0 ; get base address of loaded image MOVZWL VON,R2 ; get the length of V-on message MOVQ R2,V$ON(R0) ; copy descriptor to loaded image MOVC3 R2,@VON+4,(R3) ; copy V-on string into P1 space ;++ ; The following calls the initialization routine in the loaded image to ; build the DCL$ATTACH_ logical name for this process. ;-- MOVL RETADR,R0 ; get base address of loaded image CALLS #0,@INIRTN(R0) ; call the initialization routine CHKSTS R0 ; should we continue ;++ ; At this point, the image has been activated into P1 space and the image ; fixups have been applied. The address in CTL$GL_CTLBASVA is updated to ; reflect the new base of the P1 process permanent region. ;-- $CMKRNL_S ROUTIN=SETP1END CHKSTS R0 ; should we continue ;++ ; All said and done, the control-V key AST can now be queued. ;-- MOVL @RETADR,R0 $QIOW_S - ; queue the control-KEY AST FUNC=#IO$_SETCHAR!IO$M_OUTBAND!IO$M_TT_PROCESS,- CHAN=CHAN,- P1=(R0),- P2=#MASK,- P3=#PSL$C_EXEC RET ; done! ;++ ; This routine modifies the address stored in CTL$GL_CTLBASVA to reflect ; the new base of P1 process permanent address space. Called at kernel ; mode because CTL$GL_CTLBASVA is protected URKW. ;-- .ENTRY SETP1END,0 MOVL RETADR,@#CTL$GL_CTLBASVA ; new base in P1 space MOVL #SS$_NORMAL,R0 RET ;++ ; This routine appends portions of the verify status message together. ;-- BUILD_STRINGS: .iif df,alpha, .JSB_ENTRY INPUT=,OUTPUT= PUSHL #0 PUSHAB BUFFER ; buffer for escape sequence PUSHAL LENGTH ; length of escape sequence PUSHAL #MAXLEN ; maximum for escape sequence PUSHAL (R0) ; attribute code to obtain PUSHAL TRMTBL ; the terminal table address CALLS #6,G^SMG$GET_TERM_DATA ; get the data. CHKSTS R0 ; should we continue PUSHAB WRKSTR ; desc of data from SMG$GET_TERM_DATA PUSHAB VOFF ; dyn. desc. to hold verify off message CALLS #2,G^STR$APPEND ; append new codes to end of message CHKSTS R0 ; should we continue PUSHAB WRKSTR ; desc of data from SMG$GET_TERM_DATA PUSHAB VON ; dyn. desc. to hold verify on message CALLS #2,G^STR$APPEND ; append new codes to end of message CHKSTS R0 ; should we continue RSB .END INSTALL$KEY_AST