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], ðer[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.