[comp.os.vms] Help with a Kernal mode macro program

dstevens@sitvxb (David L Stevens) (07/08/87)

 Greetings,
        I am trying to modify FINGER to go out and get the Server and Port
 name from the UCB blocks for the LAT device, we are using LAT-Plus.  I
 have below the code that I use, the problem I am having is that the MOVC3
 statement in the Kernal Mode code, crashes the system every time I run it.
 If I take out the MOVC3 statements, and run the program the Length of the
 port string, the length of the Server string are retrieved no problem.  Also
 I checked, and R8 does point at the beginning of the LAT information area in
 the UCB block.  If anyone can tell me what I am doing wrong here please let
 me know, I'm stumpted.  Remember this is KERNAL Mode code that is broken, and
 as such will crash the system, and requires CMKRNL priv, so be carefull when
 you test it/(hopfully) fix it.

------------------------------------------------------------------------------
                        LAT_PLUS_INFO.MAR

        .title lat_plus_info
;;; lat_info - get information about LAT terminals (privileged)
;++
;    Module :   LAT_INFO.MAR
;    Author :   David L. Stevens
;               Stevens Institute of Technology
;
; This module was based on the TTUCB.MAR file of the Finger system.  I
;    gratefully thank the author of that program for the help that it
;    gave me while hacking out this program.  This program requires
;    CMKRNL privileges to run.  It will retrieve the Server name, the
;    Server Port Number and the Server's Ethernet address.  Hopefully
;    DEC will not modify the format of a LAT Plus UCB and destroy the offsets.
;
; revision history:
;
;  7-July-1987          Create this Module.             [DLS]
;
;--

        .library  /sys$library:lib.mlb/
        $ucbdef
        $ddbdef
        $ipldef
        $ttyucbdef
;
;       Useful constants
;
num_args        =       4                       ;; Number of arguments
ap_numb         =       4                       ;; Offset to unit number
ap_name         =       8                       ;; Offset to return buff addr
ap_port         =       12                      ;; Offset to return port buffer
ap_eth          =       16                      ;; Offset to return eth buffer

ucb$b_srv_info  =       ^x134                   ;; offset in UCB to server info

srv_info_port   =       1
srv_info_name   =       2









;;
;; LAT_INFO
;;
;; this routine is called to get information about a specified lat line
;;
;;      r2  - LTA device number to get info on
;;      r3  - Pointer to return buffer for the Server name
;;      r4  - Pointer to return buffer for the Server port
;;      r5  - Pointer to return buffer for the Server ethernet address
;;      r6  - Scratch
;;

        .entry  lat_info,^M<r2,r3,r4,r5,r6>

        cmpl    #num_args,(ap)                  ; need this many arguments
        beql    10$                             ; branch if correct
        movl    #ss$_badparam,r0                ; setup error status
        ret                                     ; go give him the bad news

10$:    clrl    eth_addr                        ; Clear out the --
        clrw    eth_addr+4                      ;   -- ethernet addr buffer
        clrb    srv_name_len                    ; Clear out the server name len
        clrb    port_len                        ; Clear out the port # buff

        $lkwset_s inadr=lock1                   ; lock routine into working set
        cmpl    #ss$_wasclr,r0                  ; did we lock the pages?
        beql    20$                             ; branch if so
        cmpl    #ss$_wasset,r0                  ; were they already locked?
        bneq    err                             ; if not, then error

20$:    movw    ap_numb(ap),unit_numb           ; Get the needed unit number
        $cmkrnl_s routin=latinfkrn              ; do the privileged stuff
        movl    r0,r6                           ; save status for later

        $ulwset_s inadr=lock1                   ; unlock kernel routine
        cmpl    #ss$_wasclr,r0                  ; did we unlock the pages?
        beql    info                            ; branch if so
        cmpl    #ss$_wasset,r0                  ; were they already unlocked?
        beql    info                            ; branch if so
err:    ret                                     ; ERROR; that's all folks!

info:   tstb    srv_name_len
        beql    40$
        movl    ap_name(ap),r3                  ; Get the return name buf addr
        movc3   srv_name_len,srv_name_str,(r3)

40$:    tstb    port_len
        beql    50$
        movl    ap_port(ap),r4                  ; Get the return port buf addr
        movc3   port_len,port_numb,(r4)

50$:    tstl    eth_addr
        beql    60$
        movl    ap_eth(ap),r5                   ; Get the return eth-adr buf adr
        movl    eth_addr,(r5)
        movw    eth_addr+4,4(r5)

60$:    movl    r6,r0
        ret                                     ; that's all folks!










;
;       Descriptor used to lock kernel routine into our working set
;
lock1:  .address        latinfkrn
        .address        latinfkrnend

;;
;; LATINFKRN
;;
;; Entry point for the privileged search and slurp. The following
;; registers are used:
;;
;;      r0  - return status
;;      r6  - Port Buffer
;;      r7  - Server name buffer
;;      r8  - Start address of LAT Plus Info
;;      r9  - address of current LAT UCB
;;      r10 - address of current DDB
;;

        .entry  latinfkrn,^M<r6,r7,r8,r9,r10>

        jsb     sch$iolockr                     ;; lock io data base for read
        dsbint  #ipl$_synch                     ;; raise ipl while mucking...
;;
;; First we need to search the DDB's for the one for the desired device
;;
        movl    ioc$gl_devlist,r10              ;; ddb list in r10
        movl    #port_numb, r6                  ;; Port buffer address
        movl    #srv_name_str, r7               ;; Server name buffer address
        brb     jump1                           ;; jump into middle loop

loop1:  movl    ddb$l_link(r10),r10             ;; look at next ddb
jump1:  beql    finish                          ;; already did last controller

        cmpc3   #3,dev_name,ddb$t_name+1(r10)   ;; Is it an LTA DDB ???
        bneq    loop1                           ;; No try for the next one.
;;
;; Now we traverse down the string of UCB's for the correct unit
;;
        movl    ddb$l_ucb(r10),r9               ;; fetch first ucb for this ddb
        brb     jump2                           ;; jump into innermost loop

loop2:  movl    ucb$l_link(r9),r9               ;; look at next ucb
jump2:  beql    finish                          ;; no more units left

        cmpw    unit_numb,ucb$w_unit(r9)        ;; is this the right unit number
        bneq    loop2                           ;; next ucb if not
;;
;; Establish a pointer to the beginning of the LAT Plus Data
;;
        addl3   #ucb$b_srv_info, r9, r8
;;
;; Now we get the information we need about the LAT line
;;
        movzbw  (r8), port_len                  ;; Get the length of port string
        beql    srvinf                          ;; If Zero length then branch
;;
;; Move the data into the storage area
;;
        movc3   port_len, srv_info_port(r8), (r6)
;;
;; Get the Server name information
;;
srvinf:
        addl2   port_len, r8                    ;; Offset to srv name length
;;
;; Get the length of the string
;;
        movzbw  srv_info_port(r8), srv_name_len
        beql    finish                          ;; If Zero length then branch
;;
;; Get the data
;;
  ;;    movc3   srv_name_len, srv_info_name(r8), (r7)
;;
;; Now set up for a return
;;
finish: jsb     sch$iounlock                    ;; unlock io data base
        enbint                                  ;; restore ipl

        movl    #ss$_normal,r0                  ;; set up normal return
        ret                                     ;; back to user mode

;;
;; Storage locations
;;

dev_name:       .asciz  "LTA"                   ;; Generic device name
unit_numb:      .blkw   1                       ;; Current unit number
port_len:       .blkw   1                       ;; Length of port string
port_numb:      .blkb   16                      ;; Remote port string
srv_name_len:   .blkw   1                       ;; Length of server name string
srv_name_str:   .blkb   16                      ;; Server name string
eth_addr:       .blkw   3                       ;; Servers Ethernet Address

latinfkrnend:                                   ;; end of locked memory

        .end


-------------------------------------------------------------------------------
                                TEST.C

#include        <stdio.h>
main()
{
    char        name[20];
    char        port[20];
    int         ether[2];
    int         i = 0;

    ether[0] = 0; ether[1] = 0;
    for (;i<20;i++)
    {
        name[i] = NULL;
        port[i] = NULL;
    }

    lat_info(1,&name[0], &port[0], &ether[0]);
    printf(" LTA1, Server name %s, port %s, ether %x%x. \n",
                name, port, ether[0],ether[1]);
 }

-------------------------------------------------------------------------------

 The command to link the programs together is:
        $ LINK TEST,LAT_PLUS_INFO,SYS$SYSTEM:SYS.STB/SELECT

 Any and all help will be gratefully appreciated.

 - Thanx
 - Dave Stevens
 - Systems Programmer
 - Stevens Institute of Technology
 - Address:
        BITnet:         DSTEVENS@SITVXA
        ARPAnet:        DSTEVENS%SITVXA.BITNET@WISCVM.ARPA
        CCnet:          SITVXA::DSTEVENS

gkn@SDS.SDSC.EDU (07/09/87)

	From:	 dstevens (David L Stevens) @ sitvxb
	Subject: Help with a Kernal mode macro program
	Date:	 Wed, 8 Jul 87 12:29:44 EDT
 
        I am trying to modify FINGER to go out and get the Server and Port
	name from the UCB blocks for the LAT device, we are using LAT-Plus.
	I have below the code that I use, the problem I am having is that the
	MOVC3 statement in the Kernal Mode code, crashes the system every time
	I run it.

Well, here are a few problems with this:

 
You don't really need to lock any pages in your working set;  you don't
need to run above IPL 2.

        $lkwset_s inadr=lock1                   ; lock routine into working set

Owning the I/O database mutex is a sufficient lock on the I/O database; you
don't need to raise IPL all the way to SYNCH.  This just makes things more
difficult.  Also, you need to have your PCB address in R4 when you attempt
to gain ownership of a mutex.  I suspect that you were just lucky and R4
already contained your PCB address...

        jsb     sch$iolockr                     ;; lock io data base for read
        dsbint  #ipl$_synch                     ;; raise ipl while mucking...

Also, all references to locations inside VMS should use the general addressing
mode (to ensure that the code is PIC.  Writing non-PIC code is a hard habit
to break if you're a PDP-11 programmer ...)

	MOVL	G^SCH$GL_CURPCB,R4		;;Grab my PCB address
	JSB	G^SCH$IOLOCKR			;;Lock the I/O database for reading

;;
;; First we need to search the DDB's for the one for the desired device
;;

If you make a descriptor of the device name and unit number, you can save
yourself tons of work by calling IOC$SEARCHDEV, eg:

LTA_DEV:	.Ascid	"LTA1"

	MOVAQ	LTA_DEV,R1			;;Here's the device to search for
	JSB	G^IOC$SEARCHDEV			;;Go find the UCB

You must own the I/O database mutex to call IOC$SEARCHDEV.  It returns status
in R0 (low bit clear means it couldn't find the device).  The device's UCB
address will be returned in R1.  IOC$SEARCHDEV is in module IOSUBPAGD, on
fiche panel 443 B05 (for VMS V4.5).


        movl    ioc$gl_devlist,r10              ;; ddb list in r10

Use G^ addressing, eg:

	MOVL	G^IOC$GL_DEVLIST,R10		;;DDB list in R10


        movl    #port_numb, r6                  ;; Port buffer address
        movl    #srv_name_str, r7               ;; Server name buffer address

Use the MOVAB instruction, eg:

	MOVAB	PORT_NUMB,R6			;;Port buffer address
	MOVAB	SRV_NAME_STR,R7			;;Server name buffer address

;;
;; Establish a pointer to the beginning of the LAT Plus Data
;;
        addl3   #ucb$b_srv_info, r9, r8

You could save a few cycles and use:

	MOVAB	UCB$B_SRV_INFO(R9),R8		;;Address the LAT data area


Your system is crashing because the instruction below is adding more than you
think to R8.  Recall that you only stored 16 bits worth of information in
PORT_LEN, and you're using 32 bits with the ADDL instrction.  The high order
16 bits are comming from the low order 16 bits of PORT_NUMB, which is not
making the processor very happy when it goes to check to make sure you can
see the entire source string described by the first two operands for the MOVC3
instruction ...

        addl2   port_len, r8                    ;; Offset to srv name length

  ;;    movc3   srv_name_len, srv_info_name(r8), (r7)


Also, you're going to run into trouble with disconnectable LAT terminals...


A while back, I wrote a subroutine which will retrieve information about a
LAT port.  Here's another copy:

--------------------------------------------------------------------------------
	.Title	LAT_Info	- Get information about a LAT terminal
	.Ident	/V01.001/
	.Enable	SUP
	.Default Displacement,Word
	.Subtitle	Introduction

;+
;
; ----- LAT_Info:  Get information about a LAT terminal
;
;
; Facility:
;
;	VAX/VMS system programming
;
; Abstract:
;
;	This module provides a routine which can be called from any
;	VAX native  language to obtain information about a specific
;	LAT terminal.
;
; Environment:
;
;	VAX/VMS native mode, VMS V4.2 or later, LATPlus V01.012 or later,
;	CMKRNL privilege.
;
;
;
; Version:	V01.001
; Date:		03-Feb-1987
;
; Gerard K. Newman	19-Dec-1986
; San Diego Supercomputer Center
; GA Technologies
; P.O. Box 85608
; San Diego, CA  92138
; 619.534.5076
;
; Internet:	GKN@SDS.SDSC.EDU
; Bitnet:	GKN@SDSC.BITNET
; Span:		SDSC::GKN (27.1)
;
;
; Modifications:
;
;	 3-Feb-1987	GKN	Don't allow LTA0: to be used.
;
;-

	.Page
	.Subtitle	Local definitions

	.Library "SYS$LIBRARY:LIB"			;Get special macros from here
	.Link	 "SYS$SYSTEM:SYS.STB"/Selective_Search	;Ease the link process a bit

	.NoCross			;Save a tree

	$DCDEF				;Device class & type definitions
	$DDBDEF				;Device data block offsets
	$SSDEF				;System service codes
	$TTYUCBDEF			;Terminal UCB offsets
	$UCBDEF				;UCB offsets

	.Cross				;Turn CREF back on


; Local definitions

; Constants that are likely to change in a future release of VMS that are not
; defined in SYS.STB  or in a macro anywhere.  These values come from looking
; at the running system with SDA.

; Offset in an LT UCB to the length of the port name, which is a counted
; string.  Immediately following the port name is another counted string
; which is the LAT node name.

UCB$B_LT_PORT	=	^X134		;Offset to the port name length
UCB$B_LT_SESS	=	^X195		;Offset to the session number

	.Page
	.Subtitle	LAT_INFO	- Get information about a LAT terminal

;+
;
; ----- LAT_INFO:  Get information about a LAT terminal
;
;
; This routine can be called by any VAX native language to obtain the server
; name, port name  and session number of a  LAT connection given a LT device
; name.  The calling program must have  CMKRNL privilege and  must be linked
; with SYS.STB.
;
; Caveats:
;
;	Will only work with fixed (non-dynamic) string descriptors.
;
; Call sequence:
;
;	status.wlv = LAT_INFO (terminal.rt.dx, session.wlr, server.wt.dx, port.wt.dx)
;
; Inputs:
;
;	4(AP)	- Address of a descriptor of the LT device name.
;	8(AP)	- Address of a longword to return the session number in.
;	12(AP)	- Address of a descriptor to return the server name.
;	16(AP)	- Address of a descriptor to return the server port name.
;
; Outputs:
;
;	R0	- SS$_NOPRIV:	 No CMKRNL privilege.
;		- SS$_ACCVIO:	 One of the arguments is not accessible.
;		- SS$_NOSUCHDEV: The specified LT device can't be found.
;		- SS$_IVDEVNAM:	 The specified device isn't a LAT terminal.
;		- SS$_NORMAL:	 Success.
;
;-

	.Psect	LAT_INFO	EXE,RD,NOWRT,PIC,SHR,PAGE

	.Entry	LAT_INFO,^M<>		;Entry here

	$CMKRNL_S ROUTIN=B^20$,-	;Do this
		ARGLST=(AP)		; in kernel mode

10$:	RET				;Done, status in R0

; Here in kernel mode to do all of the actual work.

20$:	.Word	^M<R2,R3,R4,R5,R6,R7,R8,R9,R10,R11> ;Here in kernel mode to get some info

; First, check to see if we can read the argument list.

	MOVL	#SS$_ACCVIO,R0		;Presume we can't
	IFNORD	#<5*4>,(AP),10$		;Probe the argument list

; Check the number of arguments

	MOVL	#SS$_INSFARG,R0		;Presume we have too few arguments
	CMPB	#4,(AP)			;Do we have enough arguments?
	BNEQ	10$			;If NEQ no, it's wrong somehow

; Check to see if we can write the session number.

	MOVL	#SS$_ACCVIO,R0		;Presume we can't
	IFNOWRT	#4,@8(AP),10$		;Probe the output session number

; See if we can read the device name descriptor.

	MOVL	4(AP),R1		;Address the LT device name descriptor
	JSB	G^EXE$PROBER_DSC	;Probe the descriptor
	BLBC	R0,10$			;Sigh.
	MOVQ	R1,-(SP)		;Save a safe copy of the probed descriptor
	MOVL	SP,R11			;Remember where it is
	CLRW	2(R11)			;Never mind the type and class info

; See if we have write access to the two output descriptors.

	MOVL	12(AP),R1		;Address the server name output descriptor
	JSB	G^EXE$PROBEW_DSC	;Probe the descriptor
	BLBC	R0,10$			;Sigh.
	MOVQ	R1,-(SP)		;Stash a safe copy of the descriptor
	MOVL	SP,R10			;Remember where I put it
	CLRW	2(R10)			;Never mind the type and class info
	MOVL	16(AP),R1		;Address the port name output descriptor
	JSB	G^EXE$PROBEW_DSC	;Probe the descriptor
	BLBC	R0,10$			;Sigh.
	MOVQ	R1,-(SP)		;Stash a safe copy of said descriptor
	MOVL	SP,R9			;Remember where it is
	CLRW	2(R9)			;Never mind the type and class info

; Ok.  Now go hunt down the device the user told us was a LAT terminal
; and see if it really is.

	MOVL	G^SCH$GL_CURPCB,R4	;Get my PCB address
	JSB	G^SCH$IOLOCKR		;Lock the I/O database mutex
	MOVL	R11,R1			;Address the device name descriptor
	JSB	G^IOC$SEARCHDEV		;Go search for the device.
	BLBC	R0,30$			;We lose.

; Now check to see if it's even a terminal, and if it is see if it's a LAT
; terminal.  Remember to chain  to the physical UCB  first in case this is
; a disconnectable terminal.

	MOVL	#SS$_IVDEVNAM,R0	     ;Presume it isn't a terminal
	CMPB	#DC$_TERM,UCB$B_DEVCLASS(R1) ;Is it a terminal?
	BNEQ	30$			     ;If NEQ no.
	MOVL	UCB$L_TL_PHYUCB(R1),R1	     ;Get to the "real" UCB
	BGEQ	30$			     ;If GEQ this is probably LTA0:
	MOVL	UCB$L_DDB(R1),R2	     ;Find the DDB
	CMPW	#^A/LT/,DDB$T_NAME+1(R2)     ;Is this a LAT terminal?
	BNEQ	30$			     ;If NEQ no

; It's a LAT terminal all right.  Obtain the server name, port name and
; session number.

	MOVZBL	UCB$B_LT_SESS(R1),@8(AP) ;Stash the session number
	MOVAB	UCB$B_LT_PORT(R1),R1	 ;Address the port name
	MOVL	R9,R6			 ;Here's the output descriptor address
	BSBB	MOVE_ASCIC		 ;Move the port name
	MOVW	(R6),@16(AP)		 ;Replace the length
	MOVL	R10,R6			 ;R1 now points at the server name
	BSBB	MOVE_ASCIC		 ;So go move it, too
	MOVW	(R6),@12(AP)		 ;Replace the length
	MOVL	#SS$_NORMAL,R0		 ;Success!
	MOVL	G^SCH$GL_CURPCB,R4	 ;Get my PCB address again

30$:	PUSHL	R0			;Save the return status
	JSB	G^SCH$IOUNLOCK		;Unlock the I/O database mutex
	SETIPL	#0			;Drop back down from IPL$_ASTDEL
	POPL	R0			;Restore the return status
	RET				;Back to user mode

; Short subroutine to move a .Ascic string to a place described by a
; descriptor.  Forms a  proper descriptor of the result, and handles
; short buffers, etc.
;
; Inputs:
;
;	R1	- Address of the .Ascic string
;	R6	- Address of the output descriptor
;
; Outputs:
;
;	R1	- Address of one byte past the end of the .Ascic string
;	R0-R5	- Smashed

MOVE_ASCIC:				;Here to move a .Ascic string

	MOVZBL	(R1)+,R0		;Grab the string length
	CMPW	(R6),R0			;Check the string length
	BGEQU	10$			;If GEQU then we can use it
	MOVZWL	(R6),R0			;Else only copy what will fit

10$:	MOVW	R0,(R6)			;Stash the length
	MOVC3	R0,(R1),@4(R6)		;Copy the string
	RSB				;Done


	.End
--------------------------------------------------------------------------------
gkn
--------------------------------------
Arpa:	GKN@SDSC.ARPA
Bitnet:	GKN@SDSC
Span:	SDSC::GKN (27.1)
USPS:	Gerard K. Newman
	San Diego Supercomputer Center
	P.O. Box 85608
	San Diego, CA 92138
AT&T:	619.534.5076

ted@blia.BLI.COM (Ted Marshall) (07/10/87)

This on is easy! :-) (But don't feel too bad. The reason it's easy is that
I've been bitten on this one too!)

Your problem is that the movc instructions destroy registers R0 through R5.
Reading from my trusty VAX Architecture Handbook, 1981, after a movc3, these
registers are left with the following values:

	R0 = 0

	R1 = address of 1 byte beyond the source string

	R2 = 0

	R3 = address of 1 byte beyond the destination string

	R4 = 0

	R5 = 0

One of the reasons this is done is that the instruction is interruptible. If
an interrupt does occur during the movc3, the processor saves the state of the
instruction in these registers and sets the FPD (First Part Done) bit in the
PSL. When the instruction stream resumes, the PC still points at the movc3.
The FPD bit tells the processor to restore the state from the registers and
continue from there.

Anyway, in your program, the routine that does the movc3 does not save R2
through R5. Note also that since this is called with the $CMKRNL system
service, the direct caller is not your program but the EXE$CMKRNL routine
in the executive. I haven't looked at it in the fiche, but I expect that
when your routine returns to it, it tries to use a value it saved in one
of these registers and gets an access violation.

Thus, I expect that the fix is to add R2, R3, R4 and R5 to the entry mask
for that routine. [Note: I don't have a LAT server and have not verified
that this is the complete fix, but it is at least part of it.]

-- 
Ted Marshall       ...!ucbvax!mtxinu!blia!ted <or> mtxinu!blia!ted@Berkeley.EDU
Britton Lee, Inc., 14600 Winchester Blvd, Los Gatos, Ca 95030     (408)378-7000
The opinions expressed above are those of the poster and not his employer.

LEICHTER-JERRY@YALE.ARPA (07/11/87)

    
     Greetings,
            I am trying to modify FINGER to go out and get the Server and Port
     name from the UCB blocks for the LAT device, we are using LAT-Plus.  I
     have below the code that I use, the problem I am having is that the MOVC3
     statement in the Kernal Mode code, crashes the system every time I run
     it....

            .entry  latinfkrn,^M<r6,r7,r8,r9,r10>
	...
            movc3   port_len, srv_info_port(r8), (r6)

movc3 modifies registers r0-r5.  r0-r1 are not a problem unless your code
uses them (I didn't look at it that closely), but you MUST save r2-r5 in
your entry mask (or save/restore them yourself, if that's preferable for
some reason).

BTW, it's not clear to me that locking the pages involved in the working set
is sufficient for your purposes; you have to be sure they are in memory before
they are accessed.  I don't know for certain, but I suspect $LKWSET will
simply start the paging going - I don't think it will necessarily wait for
it to complete.

The usual technique, if all the code fits in no more than two pages, is to
place the IPL you are setting in memory at the end of the code.  The instruc-
tion that sets the IPL is then itself guaranteed to be in memory, and it
is certain to fault in the page containing the IPL.  While at elevated IPL,
neither page will fault out.  (This can, of course, fail horribly if the
SETIPL and the IPL itself get more than 2 pages apart, as there can then be
a "hole" between the two.)  If you do this, the $LKWSET is redundant.

							-- Jerry
-------

jeh@crash.CTS.COM (Jamie Hanrahan) (07/11/87)

In article <8707110215.AA28319@ucbvax.Berkeley.EDU>,
 <LEICHTER-JERRY@YALE.ARPA> writes:
>BTW, it's not clear to me that locking the pages involved in the working set
>is sufficient for your purposes; you have to be sure they are in memory before
>they are accessed.  I don't know for certain, but I suspect $LKWSET will
>simply start the paging going - I don't think it will necessarily wait for
>it to complete.
>
>The usual technique, if all the code fits in no more than two pages, is to
>place the IPL you are setting in memory at the end of the code.  The instruc-
>tion that sets the IPL is then itself guaranteed to be in memory, and it
>is certain to fault in the page containing the IPL.  While at elevated IPL,
>neither page will fault out.  (This can, of course, fail horribly if the
>SETIPL and the IPL itself get more than 2 pages apart, as there can then be
>a "hole" between the two.)  If you do this, the $LKWSET is redundant.
 
 $LKWSET will in fact wait to complete until all of the requested pages
 are faulted in.  The technique of referencing the IPL value, which is
 stored at the end of the code to be locked, at the beginning (via DSBINT
 or SETIPL), is a hack.  It's true that it's a _common_ hack inside VMS,
 but I still feel it should be avoided.  After all, someone who isn't
 familiar with this particular idiom might have to understand the code
 someday.  The use of the $LKWSET service makes the intent absolutely
 clear.

jeh@crash.CTS.COM (Jamie Hanrahan) (07/11/87)

In article <870708122836.001@sitvxb> dstevens@sitvxb (David L Stevens) writes:
>
> ...the MOVC3
> statement in the Kernal Mode code, crashes the system every time I run it.

I replied to this via mail, but since then several not-quite-correct
responses have been posted as news, so here goes...

The folks who point out that MOVC3 clobbers R0-R5 are correct.  (And,
by the bye, LOC3 hits R0-R3.)  BUT, simply mentioning R2 through R5
in the kernel (not "kernal", please!) mode routine's entry point mask
is not sufficient to avoid the crashes.  

The code shown is calling the VMS system routines EXE$IOLOCKR (lock
I/O data base via mutex for read) and EXE$IOUNLOCK (unlock I/O data
base mutex).  These routines require R4 to point to the current 
process's PCB.  The call to IOLOCKR works because the $CMKRNL service
calls the target routine with R4 pointing to the PCB, but after the 
MOVC3, R4 contains 0.  The mutex-handling routines check to ensure
that R4 is pointing to a valid PCB and bugcheck if it doesn't; hence
the crash.  

R4 can be pushed at the beginning of the routine and popped just
before the call to UNLOCK, or pushed and popped around the MOVC3s. 
Personally, I would put the following statement just before the calls
to both EXE$IOUNLOCK and EXE$IOLOCKR:

	MOVL    G^SCH$GL_CURPCB, R4     ; get addr of cur proc PCB

Sure, it's not necessary for IOLOCKR because of the context that 
this code happens to run in... but that might change someday.  
The MOVL makes the code less context-dependent, and also more
understandable.  

One other thing:  All references to system-space labels 
(EXE$IOLOCKR, EXE$UNLOCK) should be preceded with the G^ prefix
to ensure that they're position independent.  

DISCLAIMER:  Names of system-space labels in the above were typed
from memory.  The suffixes are correct but the prefixes (EXE$, 
SCH$, etc.) may be mixed up... it's late/early/not good.