.title ATG_FT_USS - User system service dispatcher .ident 'X01.05' ;++ ; Module: ATG_FT_USS ; Package: MMTS ; Author: Nick de Smith (NICK@NCDLAB.ULCC.AC.UK,PSI%234213300154::NICK) ; Creation date: 24-Oct-91 ; ; © 1992, Copyright Applied Telematics Group Ltd. and Nick de Smith ; All rights reserved. ; ; This software is supplied for information only. No guarantee ; is supplied for this software, and no liability will be ; accepted for any action resulting from the use of this ; software or the information contained herein. ; ; Under no circumstances may this software be used for ; commercial gain, including its sale, lease or loan. ; ; This software may be copied only with the inclusion of this ; copyright notice. ; The author is prepared to enter into correspondence with ; interested parties, but will not necessarily maintain this ; software. ; ; Revision history: ; ; Edit Edit date By Why ; X01.05 03-Jan-92 NMdS Add in code review from DEC: ; Remove use of DEVICELOCK to prevent page faults at high IPL. ; Use write lock on I/O database instead and keep IPL at ASTDEL. ; X01.04 28-Nov-91 NMdS Remember to restore R5 after a MOVC3! ; X01.03 11-Nov-91 NMdS Add in device name ; X01.02 28-Oct-91 NMdS Add in device lock to protect UCB ; X01.01 24-Oct-91 NMdS First Attempt ; ; Abstract: ; This module contains a dispatcher for user written system services ; along with a service and a user rundown routine. ; The routine supplied is: ; ; sts.wl = ATG_FT_SET_ACCPORNAM( chan.rw.v, [devnam.rx.d], text.rx.d ) ; ; sts longword, write, by value ; Returned system status ; ; chan word, read, by value ; Channel number of FT device (from PTD$CREATE) ; If this word is 0, the "devnam" argument is used to locate the ; device ; ; devnam string, read, by descriptor, optional ; Device name of FT device to modify. Used only if "chan" is 0. ; You must have LOGICAL access to the device to specify it by name ; ; text string, read, by descriptor ; Access port name string to set. Must be <= 63 characters. ; ; Overview: ; User written system services are contained in privileged shareable ; images that are linked into user program images in exactly the ; same fashion as any shareable image. The creation and installation ; of a privileged, shareable image is slightly different from that ; of an ordinary shareable image. These differences are: ; ; 1. A vector defining the entry points and providing other ; control information to the image activator. This vector ; is a the lowest address in an image section with the VEC ; attribute. ; ; 2. The shareable image is linked with the /PROTECT option ; that marks all of the image sections so that they will ; protected and given EXEC mode ownership by the image ; activator. ; ; 3. The shareable image MUST be installed /SHARE /PROTECT ; with the INSTALL utility in order for the image activator ; to connect the privileged shareable image to the change mode ; dispatchers. ; ; A privileged shareable image implementing user written system services ; is comprised of the following major components: ; ; 1. A transfer vector containing all of the entry points and ; collecting them at the lowest virtual address in the shareable ; image. This formalism enables revision of the shareable ; image without necessitating the relinking of images that ; use it. ; ; 2. A Privileged Library Vector in a PSECT with the VEC attribute ; that describes the entry points for dispatching EXEC and ; KERNEL mode services along with validation information. ; ; 3. A dispatcher for kernel mode services. This code will ; be called by the VMS change mode dispatcher when it ; fails to recognize a kernel mode service request. ; ; 4. A dispatcher for executive mode services. This code will ; be called by the VMS change mode dispatcher when it fails ; to recognize an executive mode service request. ; ; 5. Service routines to perform the various services. ; ; The first four components are contained in this template and are ; most easily implemented in MACRO, while the service routines can ; be implemented in BLISS or MACRO. Other languages may be usable ; but are not recommended -- particularly if they require runtime ; support routines or are extravagant in their use of stack or are ; unable to generate PIC code. ; ; This code is position-independent (PIC) and it is good practice ; to implement shareable images this way whenever possible. ;-- .sbttl Declarations and Equates ; ; Include Files ; .library "SYS$LIBRARY:LIB.MLB" ; Macro library for system structure definitions $dyndef ; Data structure type codes $ipldef ; IPL definition $irpdef ; I/O request packed definitions $sfdef ; Saved frame offset definitions ; ; Macro Definitions ; .macro blbcw reg=r0, dest, ?lab blbs reg, lab brw dest lab: .endm .macro wo inst, src, dest, ?lab, ?lab1 inst src, lab brb lab1 lab: brw dest lab1: .endm ; ; DEFINE_SERVICE - A macro to make the appropriate entries in several ; different PSECTs required to define an EXEC or KERNEL ; mode service. These include the transfer vector, ; the case table for dispatching, and a table containing ; the number of required arguments. ; ; DEFINE_SERVICE name,number_of_arguments,mode ; .macro DEFINE_SERVICE, NAME, NARG=0, MODE=KERNEL .psect $$$TRANSFER_VECTOR, page, nowrt, exe, pic .align QUAD ; Align entry points for speed and style .transfer NAME ; Define name as universal symbol for entry .mask NAME ; Use entry mask defined in main routine .if idn mode, KERNEL chmk # ; Change to kernel mode and execute ret ; Return KERNEL_COUNTER = KERNEL_COUNTER + 1 ; Advance counter .psect KERNEL_NARG, byte, nowrt, exe, pic .byte NARG ; Define number of required arguments .psect USER_KERNEL_DISP1, byte, nowrt, exe, pic .word <2 + NAME - KCASE_BASE> ; Make entry in kernel mode CASE table .iff chme # ; Change to executive mode and execute ret ; Return EXEC_COUNTER = EXEC_COUNTER + 1 ; Advance counter .psect EXEC_NARG, byte, nowrt, exe, pic .byte NARG ; Define number of required arguments .psect USER_EXEC_DISP1, byte, nowrt, exe, pic .word <2+NAME-ECASE_BASE> ; Make entry in exec mode CASE table .endc ; .endm DEFINE_SERVICE ; ; Equated Symbols ; $ccbdef ; Define CCB offsets $ddbdef ; DDB definitions $dptdef ; Driver Prologue Table definitions $ftucbdef ; FTDRIVER UCB extensions $ftvecdef ; FTDRIVER port vector offsets $pcbdef ; Software PCB fields $phddef ; Define process header offsets $plvdef ; Define PLV offsets and values $psldef ; Define process status fields $ssdef ; Define system statii $ttyucbdef ; TTY UCB extensions $ttyvecdef ; TTY port vector offsets $ucbdef ; UCB definitions ; ; Initialize counters for change mode dispatching codes ; KERNEL_COUNTER = 0 ; Kernel code counter EXEC_COUNTER = 0 ; Exec code counter ; ; Own Storage ; .psect KERNEL_NARG, byte, nowrt, exe, pic KERNEL_NARG: ; Base of byte table containing the number of required arguments. .psect EXEC_NARG, byte, nowrt, exe, pic EXEC_NARG: ; Base of byte table containing the number of required arguments. .sbttl Transfer Vector and Service Definitions ;++ ; The use of transfer vectors to effect entry to the user written system services ; enables some updating of the shareable image containing them without necessitating ; a re-link of all programs that call them. The PSECT containing the transfer ; vector will be positioned at the lowest virtual address in the shareable image ; and so long as the transfer vector is not re-ordered, programs linked with ; one version of the shareable image will continue to work with the next. ; ; Thus as additional services are added to a privileged shareable image, their ; definitions should be added to the end of the following list to ensure that ; programs using previous versions of it will not need to be re-linked. ; To completely avoid relinking existing programs the size of the privileged ; shareable image must not change so some padding will be required to provide ; the opportunity for future growth. ;-- DEFINE_SERVICE ATG_FT_SET_ACCPORNAM, 3, KERNEL ; Set access port name ; ; The base values used to generate the dispatching codes should be negative for ; user services and must be chosen to avoid overlap with any other privileged ; shareable images that will be used concurrently. Their definition is ; deferred to this point in the assembly to cause their use in the preceding ; macro calls to be forward references that guarantee the size of the change ; mode instructions to be four bytes. This satisfies an assumption that is ; made by for services that have to wait and be retried. The PC for retrying ; the change mode instruction that invokes the service is assumed to be 4 bytes ; less than that saved in the change mode exception frame. Of course, the ; particular service routine determines whether this is possible. ; KCODE_BASE = -1024 ; Base CHMK code value for these services ECODE_BASE = -1024 ; Base CHME code value for these services .sbttl Change Mode Dispatcher Vector Block ;++ ; This vector is used by the image activator to connect the privileged shareable ; image to the VMS change mode dispatcher. The offsets in the vector are self- ; relative to enable the construction of position independent images. The system ; version number will be used by the image activator to verify that this ; shareable image was linked with the symbol table for the current system. ; ; Change Mode Vector Format ; ; +------------------------------------------+ ; ! Vector Type Code ! PLV$L_TYPE ; ! (PLV$C_TYP_CMOD) ! ; +------------------------------------------+ ; ! System Version Number ! PLV$L_VERSION ; ! (SYS$K_VERSION) ! ; +------------------------------------------+ ; ! Kernel Mode Dispatcher Offset ! PLV$L_KERNEL ; ! ! ; +------------------------------------------+ ; ! Exec Mode Entry Offset ! PLV$L_EXEC ; ! ! ; +------------------------------------------+ ; ! User Rundown Service Offset ! PLV$L_USRUNDWN ; ! ! ; +------------------------------------------+ ; ! Reserved ! ; ! ! ; +------------------------------------------+ ; ! RMS Dispatcher Offset ! PLV$L_RMS ; ! ! ; +------------------------------------------+ ; ! Address Check ! PLV$L_CHECK ; ! ! ; +------------------------------------------+ ; ; The reference to SYS$K_VERSION will only be resolved if the image is ; linked against SYS.STB. In other cases the version check is ; unnecessary and will not be done. ; .weak SYS$K_VERSION ; .psect USER_SERVICES, page, vec, pic, nowrt, exe .long PLV$C_TYP_CMOD ; Set type of vector to change mode dispatcher .long SYS$K_VERSION ; Identify system version .long KERNEL_DISPATCH-. ; Offset to kernel mode dispatcher .long EXEC_DISPATCH-. ; Offset to executive mode dispatcher .long USER_RUNDOWN-. ; Offset to user rundown service .long 0 ; Reserved. .long 0 ; No RMS dispatcher .long 0 ; Address check - PIC image .sbttl Kernel Mode Dispatcher ;++ ; Input Parameters: ; ; (SP) - Return address if bad change mode value ; ; R0 - Change mode argument value. ; ; R4 - Current PCB Address. (Therefore R4 must be specified in all ; register save masks for kernel routines.) ; ; AP - Argument pointer existing when the change ; mode instruction was executed. ; ; FP - Address of minimal call frame to exit ; the change mode dispatcher and return to ; the original mode. ;-- .psect USER_KERNEL_DISP0, byte, nowrt, exe, pic KACCVIO: ; KERNEL access violation movzwl #SS$_ACCVIO, r0 ; Set access violation status code... ret ; ...and return KINSFARG: ; KERNEL insufficient arguments. movzwl #SS$_INSFARG, r0 ; Set status code... ret ; ...and return kNOTME: rsb ; RSB to forward request KERNEL_DISPATCH:: ; Entry to dispatcher movab w^-KCODE_BASE(r0), r1 ; R1 = Normalised dispatch code value blss KNOTME ; Branch if code value too low cmpw r1, #KERNEL_COUNTER ; Check high limit bgequ KNOTME ; Branch if out of range ; ; The dispatch code has now been verified as being handled by this dispatcher, ; now the argument list will be probed and the required number of arguments ; verified. ; movzbl w^KERNEL_NARG[r1], r1 ; R1 = required argument count moval @#4[r1], r1 ; R1 = byte count including arg count ifnord r1, (ap), KACCVIO ; Branch if arglist not readable cmpb (ap), w^[r0] ; Check for required number blssu KINSFARG ; of arguments movl fp, sp ; Reset stack for service routine casew r0 ,- ; Case on change mode argument value #KCODE_BASE ,- ; Base value # ; Limit value (number of entries) KCASE_BASE: ; Case table base address for DEFINE_SERVICE ; ; Case table entries are made in the PSECT USER_KERNEL_DISP1 by ; invocations of the DEFINE_SERVICE macro. The three PSECTS, ; USER_KERNEL_DISP0,1,2 will be abutted in lexical order at link-time. ; .psect USER_KERNEL_DISP2, byte, nowrt, exe, pic BUG_CHECK IVSSRVRQST,FATAL ; Since the change mode code is validated ; above, we should never get here .sbttl Executive Mode Dispatcher ;++ ; Input Parameters: ; ; (SP) - Return address if bad change mode value ; ; R0 - Change mode argument value. ; ; AP - Argument pointer existing when the change ; mode instruction was executed. ; ; FP - Address of minimal call frame to exit ; the change mode dispatcher and return to ; the original mode. ;-- .psect USER_EXEC_DISP0, byte, nowrt, exe, pic EACCVIO: ; EXEC access violation movzwl #SS$_ACCVIO, r0 ; Set access violation status code... ret ; ...and return EINSFARG: ; EXEC insufficient arguments. movzwl #SS$_INSFARG, r0 ; Set status code... ret ; ...and return ENOTME: rsb ; RSB to forward request EXEC_DISPATCH:: ; Entry to dispatcher movab w^-ECODE_BASE(r0), r1 ; R1 = Normalised dispatch code value blss ENOTME ; Branch if code value too low cmpw r1, #EXEC_COUNTER ; Check high limit bgequ ENOTME ; Branch if out of range ; ; The dispatch code has now been verified as being handled by this dispatcher, ; now the argument list will be probed and the required number of arguments ; verified. ; movzbl w^EXEC_NARG[r1], r1 ; R1 = required argument count moval @#4[r1], r1 ; R1 = byte count including arg count ifnord r1, (ap), EACCVIO ; Branch if arglist not readable cmpb (ap), w^[r0] ; Check for required number blssu EINSFARG ; of arguments movl fp, sp ; Reset stack for service routine casew r0 ,- ; Case on change mode argument value #ECODE_BASE ,- ; Base value # ; Limit value (number of entries) ECASE_BASE: ; Case table base address for DEFINE_SERVICE ; ; Case table entries are made in the PSECT USER_EXEC_DISP1 by ; invocations of the DEFINE_SERVICE macro. The three PSECTS, ; USER_EXEC_DISP0,1,2 will be abutted in lexical order at link-time. ; .psect USER_EXEC_DISP2, byte, nowrt, exe, pic BUG_CHECK IVSSRVRQST,FATAL ; Since the change mode code is validated ; above, we should never get here .sbttl Local data ;+ ; The data in this section is local to each process. It may only ; be written from EXEC or KERNEL mode. ;- .psect $data rd, wrt, noexe, pic $gblini ; Define field macros .sbttl User Rundown Service ;++ ; Functional description ; ---------------------- ; This service is invoked from within the kernel mode system service ; that performs image rundown. It is invoked before any system ; rundown functions (i.e. deassign channels, release memory) are ; performed. User code should not invoked any RMS services or RTL ; routines, must not signal any exceptions. User code can invoke ; most system services execpt those that use RMS (e.g. $PUTMSG). ; ; Calling sequence: ; ; JSB USER_RUNDOWN ; Entered at IPL=0 and must leave at IPL=0. ; ; Input: ; R4 Current PCB Address. (Therefore R4 must be specified in all ; register save masks for kernel routines.) ; R7 Access mode parameter to $RUNDWN maximised with previous mode ; AP Argument pointer existing when the $RUNDWN system ; service was invoked. ; 4(AP) Access mode parameter to $RUNDWN ;-- .psect USER_CODE, byte, nowrt, exe, pic USER_RUNDOWN:: ; Entry point for service rsb .sbttl ATG_FT_SET_ACCPORNAM - Set Access Port Name of FTAn device ;++ ; ATG_FT_SET_ACCPORNAM - Set Access Port Name of FTAn device ; ; Functional Description ; ---------------------- ; This routine set s tha access port name for the FTAn: device on the passed ; channel. The channel handle is verified as one from PTD$CREATE, and the string ; is checked for readability and size. If the device supports access port names, ; the name is set. ; ; This routine should continue to work even after DEC have implemented their own ; version of access port name support for FTAn: devices. ; ; Inputs: ; ; CHANNEL(AP) = Handle for channel to use ; NAME(ap) => Access port name descriptor ; DEVNAM(ap) => Name of device to modify (if 4(ap) = 0) ; ; R4 => current PCB ; ; Outputs: ; ; R0 = Completion Status Code ; SS$_UNSUPPORTED Access port name support is not available ; SS$_ACCVIO Passed parameters are unreadable ; SS$_BADPARAM Passed string is > 63 characters long ; SS$_DEVOFFLINE Device is offline and request cannot proceed ; SS$_IVCHAN Illegal channel (not from PTD$CREATE) ; SS$_NOPRIV Insufficient privilege to perform request ;-- FT_C_ACCPORNAM_LENGTH = 64 ; Size of access port name buffer FT_C_HEADER = 12 ; Size of NPP buffer header CHANNEL = 4 ; AP offset to FTAn: device channel DEVNAM = 8 ; '' '' '' device name NAME = 12 ; '' '' '' access port name .enable local_block UNLOCK: ; Unlock the I/O mutex pushl r0 ; Save completion status jsb g^SCH$IOUNLOCK ; Unlock the I/O database SETIPL #0 ; Ensure IPL = 0 movl (sp)+, r0 ; Restore completion status rsb .entry ATG_FT_SET_ACCPORNAM,^m movab g^EXE$SIGTORET, SF$A_HANDLER(fp) ; Trap errors jsb g^SCH$IOLOCKW ; Lock the I/O database for write access movzwl CHANNEL(ap), r0 ; R0 = Channel number for FT device beqlu 60$ ; Do a device name lookup jsb g^VALIDATE_CHAN ; Check that the channel number is valid blbcw r0, 90$ ; Exit if channel not valid brb 70$ IVDEVNAM_U: movzwl #SS$_IVDEVNAM, r0 ; Say invalid device name jsb g^UNLOCK ; Unlock the I/O database ret BADPARAM_U: movzwl #SS$_BADPARAM, r0 ; Say bad parameter jsb g^UNLOCK ; Unlock the I/O database ret ACCVIO_U: movzwl #SS$_ACCVIO, r0 ; Say access violation 10$: jsb g^UNLOCK ; Unlock the I/O database ret ; ; No channel number, check for a device name ; 60$: movl DEVNAM(ap), r1 ; R1 => Device name descriptor beqlu BADPARAM_U ; Must be a device name if no channel ifnord #8, (r1), ACCVIO_U ; Check readability of descriptor jsb g^IOC$SEARCHDEV ; Look for the device (IPL=ASTDEL) blbc r0, 10$ ; Exit if device not located movl r1, r5 ; R5 => UCB jsb g^EXE$CHKLOGACCES ; Check for Logical access to device blbc r0, 10$ ; Exit if no access allowed cmpl #^a/FTDR/, DDB$T_DRVNAM_STR(r2) ; Check device driver name bneq IVDEVNAM_U ; NEQ = incorrect driver cmpl #^a/IVER/, DDB$T_DRVNAM_STR+4(r2) bneq IVDEVNAM_U ; NEQ = incorrect driver ; ; R4 => PCB ; R5 => UCB ; Now check the access port name string that has been supplied. ; 70$: movl NAME(ap), r1 ; R1 => Access port name descriptor ifnord #8, (r1), ACCVIO_U ; Check readability of descriptor movq (r1), r1 ; R2 => access port name string movzwl r1, r1 ; R1 = length of string cmpl r1, # ; Check length of string bgtru BADPARAM_U ; Exit if string is too long ASSUME le 512 ; IFNORD fully checks only up to 1 pagelet ifnord r1, (r2), ACCVIO_U ; Check readability of string ; ; R1 = length of access port name string ; R2 => Access port name string ; R4 => PCB ; R5 => FT UCB ; bbc #TTY$V_PC_ACCPORNAM, UCB$W_TT_PRTCTL(r5), UNSUPPORTED_U ; Check for support movl UCB$L_TT_ACCPORNAM(r5), r3 ; R3 => Access port name string beqlu UNSUPPORTED_U ; Paranoid check if buffer is there pushl r4 ; Save the PCB movb r1, (r3)+ ; Set length of string movc3 r1, (r2), (r3) ; Copy access port name string movl (sp)+, r4 ; R4 => PCB movzwl #SS$_NORMAL, r0 ; Say succesful completion 90$: jsb g^UNLOCK ; Unlock the I/O database (IPL=0) 100$: ret ; ...and return UNSUPPORTED_U: movzwl #SS$_UNSUPPORTED, r0 ; Say unsupported function brb 90$ .disable local_block .sbttl VALIDATE_CHAN - Validate channel is legal ;++ ; VALIDATE_CHAN - Validate channel is legal ; ; Functional Description ; ---------------------- ; This routine is called by the system services to verify that the I/O ; channel supplied for the request is valid. It performs the same checks that ; EXE$QIO does when validating a channel. Additionally it adds checks to make ; sure it is talking to the correct device and only using the control connection ; channel. ; ; This code is remarkably similar to PTD$VALIDIATE_CHAN! ; ; Synchronization ; --------------- ; This routine can be entered at IPL 0, and requires no special synchronization. ; Its called here from device IPL to prevent process and FT device deletion ; during the checks. ; ; Inputs: ; ; R0 = Channel number ; R4 => Caller's PCB ; ; Output: ; ; R0 = Completion status ; SS$_NORMAL - Successful completion ; SS$_DEVOFFLINE - Device is offline and request cannot proceed ; SS$_IVCHAN - Illegal channel ; SS$_NOPRIV - Insufficient privilege to perform request ; R1 => DDB ; R3 = PSL ; R5 => PHYUCB ; R6 => CCB ; R11 = Current mode ;-- VALIDATE_CHAN: bicl #<^XFFFF0000!>, r0 ; Fetch channel number and other bits beql IVCHAN ; EQL bad channel cmpw r0, g^CTL$GW_CHINDX ; Legal channel index bgtru IVCHAN ; GTRU bad channel mnegl r0, r0 ; R0 = channel index movl g^CTL$GL_CCBBASE, r6 ; R6 = CCB base address movab (r6)[r0], r6 ; R6 => CCB for passed channel movpsl r3 ; R3 = current PSL movzbl CCB$B_AMOD(r6), r5 ; R5 = channel access mode beql IVCHAN ; EQL Illegal channel extzv #PSL$V_PRVMOD, #PSL$S_PRVMOD, r3, r11 ; R11 = previous mode cmpb r11, r5 ; Caller have priv to use this channel? bgeq PRIVERR ; GEQ no priv error exit movl CCB$L_UCB(r6), r5 ; R5 => UCB for device movl UCB$L_DDB(r5), r1 ; R1 => DDB for device cmpl #^a/FTDR/, DDB$T_DRVNAM_STR(r1) ; Check device driver name bneq IVCHAN ; NEQ incorrect driver cmpl #^a/IVER/, DDB$T_DRVNAM_STR+4(r1) bneq IVCHAN ; NEQ incorrect driver cmpw r0, UCB$W_FT_CHAN(r5) ; Make sure this is the control channel bneq IVCHAN ; NEQ illegal channel exit bbc #UCB$V_ONLINE, UCB$W_STS(r5), OFFLINE ; Check device online movzwl #SS$_NORMAL, r0 ; Ok, its a valid channel rsb IVCHAN: movzwl #SS$_IVCHAN, r0 ; Illegal channel rsb OFFLINE: movzwl #SS$_DEVOFFLINE, r0 ; Device offline rsb PRIVERR: movzwl #SS$_NOPRIV, r0 ; No privilege rsb .end