TITLE SCMUUO - Session Control UUO handler V104 SUBTTL W. Nichols & V. Brownell/AJR/Tarl 27 JAN 86 SEARCH D36PAR,SCPAR,MACSYM SEARCH F,S SALL ;THIS SOFTWARE IS FURNISHED UNDER A LICENSE AND MAY ONLY BE USED ; OR COPIED IN ACCORDANCE WITH THE TERMS OF SUCH LICENSE. ; .CPYRT<1981,1986> ;COPYRIGHT (C) 1981,1984,1986 ;BY DIGITAL EQUIPMENT CORPORATION, MAYNARD, MASS. ;ALL RIGHTS RESERVED. ; ; XP SCMUUO,104 $RELOC XRESCD SUBTTL Table of Contents ; Table of Contents for SCMUUO ; ; ; Section Page ; 1. Table of Contents. . . . . . . . . . . . . . . . . . . 2 ; 2. Definitions ; 2.1. External References . . . . . . . . . . . . . 3 ; 2.2. Accumulators. . . . . . . . . . . . . . . . . 4 ; 2.3. NSP. ; 2.3.1. Functions and Arguments. . . . . . . 5 ; 2.3.2. Argument Parameters. . . . . . . . . 6 ; 3. SCURST - RESET call from UUOCON. . . . . . . . . . . . 8 ; 4. SCUUUO ; 4.1. The NSP. UUO processor. . . . . . . . . . . . 9 ; 4.2. SCUINI - Initialization . . . . . . . . . . . 11 ; 4.3. SCUAFN - Read the Function Code . . . . . . . 13 ; 4.4. SCURAA - Read the AAn Arguments . . . . . . . 14 ; 5. Argument Readers ; 5.1. SCCCBL - Connect Block. . . . . . . . . . . . 15 ; 5.2. SCCSBL - String Block . . . . . . . . . . . . 16 ; 5.3. SCCARG - Integer Argument . . . . . . . . . . 17 ; 5.4. SCCBCT - Byte Count . . . . . . . . . . . . . 18 ; 5.5. SCCBPT - Byte pointer . . . . . . . . . . . . 19 ; 5.6. SCCBUF - Buffer Checking Subr . . . . . . . . 20 ; 6. Argument Writers ; 6.1. SCSCBL - Store Connect Block into User Space. 23 ; 6.2. SCSSBL - Store String Block into User Space . 24 ; 6.3. SCSARG, SCSBCT, SCSBPT. . . . . . . . . . . . 25 ; 7. Argument Discarders ; 7.1. SCDARG, SCDCBL, SCDSBL. . . . . . . . . . . . 26 ; 8. Subroutines ; 8.1. SCUHBR - Subroutine to do the HIBERs. . . . . 27 ; 8.2. SCUWAK - Subroutine to do the WAKEs.. . . . . 28 ; 8.3. SCTPSI - Get PSI associated variable. . . . . 29 ; 8.4. SCGWRD & SCPWRD . . . . . . . . . . . . . . . 30 ; 8.5. WRDTRP - The Word Troll Processor . . . . . . 31 ; 8.6. GETPRO - Get process block. . . . . . . . . . 32 ; 8.7. GETSTR - Get a string block . . . . . . . . . 34 ; 8.8. PUTPRO - Write Process Block to User's Space. 35 ; 8.9. PUTSTR - Write String Block to User's Space . 36 ; 9. Impure Storage . . . . . . . . . . . . . . . . . . . . 37 ; 10. End of SCMUUO. . . . . . . . . . . . . . . . . . . . . 38 SUBTTL Definitions -- External References ;ENTRY declarations for LINK ENTRY SCUUUO ;USER UUO CALLS FROM UUOCON ENTRY SCURST ;RESET CALL FROM UUOCON ;These are the external references to the D36COM library of routines. EXT DNGMSG ;GET DECNET-36 MESSAGE BLOCK EXT DNFMSG ;FREE MESSAGE BLOCK EXT DNGWDS ;GET SOME WORDS EXT DNGWDZ ;GET SOME ZEROED WORDS EXT DNFWDS ;FREE SOME WORDS EXT DNSWDS ;SMEAR SOME WORDS EXT DNLMSS ;LINK MESSAGE SEGMENT INTO MESSAGE BLOCK ;Here are the references to SCLINK. EXT SCTNSF ;NSP. FUNCTION PROCESSING EXT MAKSJB ;MAKE A SJB EXT SCTRST ;RESET AN SJB EXT SCTWKQ ;ENQUEUE THIS SLB FOR SCTPSQ CALL EXT SCTPSQ ;DEQUEUE NEXT SLB FOR PSI INTERRUPT ;Here are some external references to TOPS-10 things. EXT RTN ;RETURN EXT RSKP ;SKIP RETURN SUBTTL Definitions -- Accumulators ;SCMUUO must use its own AC definitions, since it is the gateway ;between TOPS10's AC usage and DECnet-36's system independent AC usage. OPDEF CALL [PUSHJ P,] OPDEF RET [POPJ P,] .NODDT CALL,RET SJ=U ;(U ) PTR TO SCT JOB BLK (SEE PURGE SJ FURTHER DOWN) MS=P4 ;(P4) POINTER TO CURRENT MSD SA=P3 ;(P3) POINTER TO SCLINK ARGS BLOCK R=:17 ;(R ) BECAUSE MACSYM REDEFINES THIS CX=R ;(R ) SUPER-TEMP FOR MACROS .SAC==CX ;(R ) DIFFERENT NAME, FOR MACROS. ;Notice that W and M correspond to DECnet-36's T5 and T6, so save ;them around calls to D36COM routines. SUBTTL Definitions -- NSP. -- Functions and Arguments ;These are the definitions of all the NSP. functions. The format of the ;NSPFNC macro is function name followed by the three possible arguments ;of the NSP. UUO. ; ; R = Read this arg from user's block ; W = Write this arg into user's block ; P = Privileged Argument DEFINE NSPFNS,< NSPFNC EA,CBL(R),ARG(R),ARG(R,P) ;;ENTER ACTIVE NSPFNC EP,CBL(R) ;;ENTER PASSIVE NSPFNC RI,CBL(W),ARG(W),ARG(W) ;;READ CONNECT DATA NSPFNC AC,SBL(R),ARG(R),ARG(R,P) ;;ACCEPT CONNECT NSPFNC RJ,SBL(R),ARG(R,P) ;;REJECT CONNECT NSPFNC RC,SBL(W),ARG(W),ARG(W) ;;READ CONFIRM INFO NSPFNC SD,SBL(R),ARG(R,P) ;;SYNCHRONOUS DISCONNECT NSPFNC AB,SBL(R),ARG(R,P) ;;ABORT AND RELEASE NSPFNC RD,SBL(W),ARG(W) ;;READ DISCONNECT DATA NSPFNC RL ;;RELEASE CHANNEL NSPFNC RS,ARG(W),ARG(W) ;;READ STATUS NSPFNC IS,SBL(R) ;;SEND INTERRUPT DATA NSPFNC IR,SBL(W) ;;READ INTERRUPT DATA NSPFNC DS,BCT(R,W),BPT(R,W) ;;SEND NORMAL DATA NSPFNC DR,BCT(R,W),BPT(R,W) ;;READ NORMAL DATA NSPFNC SQ,ARG(R),ARG(R),ARG(R) ;;SET QUOTAS AND GOALS NSPFNC RQ,ARG(W),ARG(W),ARG(W) ;;READ QUOTAS AND GOALS NSPFNC JS,ARG(R,P),ARG(R,P) ;;SET JOB QUOTAS & GOALS NSPFNC JR,ARG(W),ARG(W) ;;READ JOB QUOTAS & GOALS NSPFNC PI,ARG(R) ;;SET PSI REASON MASK > SUBTTL Definitions -- NSP. -- Argument Parameters ;Each of these macros is a possible argument to the NSP. UUO. DEFINE ARG(A1,A2,A3),,ARG)> DEFINE SBL(A1,A2,A3),,SBL)> DEFINE CBL(A1,A2,A3),,CBL)> DEFINE BCT(A1,A2,A3),,BCT)> DEFINE BPT(A1,A2,A3),,BPT)> DEFINE COMBLK(FLAGS,TYPE),< %FLG==0 IRP FLAGS,,<%FLG==%FLG!AP'FLAGS>> EXP %FLG!AT.'TYPE> ;These are the optional parameters for any NSP. argument. BEGSTR AP ;ARGUMENT PARAMETER DESCRIPTOR FIELD FLG,6 ;FLAGS ASSOCIATED WITH PARAMETER BIT P ;PRIVILIGED ARG BIT R ;READ ARG FROM USER AT BEG OF UUO BIT W ;WRITE ARG TO USER AT END OF UUO HWORD DSP ;DISPATCH OFFSET BY ARG TYPE ENDSTR ;These are the possible arguments that can be given to the NSP. UUO. DEFINE ARGS,< TYPE ARG ;;GENERALIZED ARGUMENT TYPE CBL ;;CONNECT BLOCK TYPE SBL ;;STRING BLOCK TYPE BCT ;;BUFFER BYTE COUNT TYPE BPT ;;BUFFER BYTE POINTER > ;Now expand them to AT.xxx symbols. DEFINE TYPE(ARG),< %CNT==%CNT+1 AT.'ARG==%CNT-1> %CNT==0 ARGS ;Now make the "check arguments" dispatch table. DEFINE TYPE(ARG),< IFIW SCC'ARG> SCUCDS: ARGS ;Now make the "store arguments" dispatch table. DEFINE TYPE(ARG),< IFIW SCS'ARG> SCUSDS: ARGS ;Now make the "discard arguments" dispatch table. DEFINE TYPE(ARG),< IFIW SCD'ARG> SCUDDS: ARGS ;Now expand the dispatch table. DEFINE NSPFNC(FUNC,ARG1,ARG2,ARG3),< %CNT==%CNT+1 %ARG==0 IFN <%CNT-.NSF'FUNC>,< PRINTX ?NSP. Function .NSF'FUNC in SCMUUO not in PRINTX ? the same order as in SCPAR.UNV PASS2 END> IFNB ,<%ARG==%ARG+1> IFNB ,<%ARG==%ARG+1> IFNB ,<%ARG==%ARG+1> EXP [EXP %ARG ;;COUNT OF ARGUMENTS THAT ARE LEGAL 'ARG1 ;;NOTE THAT THIS LITERAL ONLY INCLUDES 'ARG2 ;; ENTRIES FOR %ARG ARGUMENTS 'ARG3] > %CNT==0 SCUTAB: NSPFNS ;Now get rid of all those useless symbols. PURGE CBL,SBL,ARG,BCT,BPT,NSPFNC,NSPS SUBTTL SCULGO - LOGOUT call from COMCON ;Routine called by COMCON when a job is killed ; ;Call: ; J/ Job number ; PUSHJ P,SCULGO ;Returns: ; CPOPJ ALWAYS SCUPOP:: SCULGO::MCALL (RG,MSEC1,FNDPDS##) ;SET UP PDB SKIPN .PDSJB##(W) ;JOB HAVE ANY SJB? RET ;NO, RETURN SEC1 ;RUN IN SECTION 1 SCULG1: MOVE T1,.PDSJB##(W) ;GET SJB POINTER CALL CHKSJB## ;ANY SLBs ? IFNSK. CALL SCH1BS ;YES, SLEEP FOR A SECOND JRST SCULG1 ;AND TRY AGAIN ENDIF. ; ; Now it's safe to free the SJB ; MOVE T1,.PDSJB##(W) ;GET SJB POINTER SETZM .PDSJB##(W) ;AND CLEAR CALLRET FRESJB## ;FREE THE SJB AND RETURN SUBTTL SCURST - RESET call from UUOCON ;Called from the UUO handler for an NSP. UUO ; ;Call: ; J/ Job number ; ; RET ;ONLY RETURN ; ;Once the RESET gets the required message blocks, it should be quick; ;SCLINK just closes each of the NSP links, it does not abort or ;otherwise wait for a DISCONNECT sequence. SCLINK does have to wait ;for a CLOSE-COMPLETE message from LLINKS before it can relinquish ;control, since it must free up any message blocks outstanding in the ;lower layers of DECnet. SCURST::HRRZ T1,JBTPDB##(J) ;GET POINTER TO USER'S PDB JUMPE T1,CPOPJ## ;JUST GO AWAY IF THERE ISN'T ONE SKIPN T2,.PDSJB##(T1) ;ANY SJB POINTER THERE? RET ;NOTHING, LEAVE NOW SAVEAC ;DN ROUTINES MAY SMASH (M & W) IFN <!>, MOVE SJ,T2 ;SET UP SJ WITH SJB POINTER SEC1 ;DO DECNET IN SECTION 1 IFE FTXMON,< DNCALL SCURSU ;DO DECNET IN DECNET CONTEXT RET > ;Entry point for SCUINI, J and SJ already set up SCURSU: SETONE SJRST,(SJ) ;THIS SJB IS BEING RESET, SEE SCUINI ;Here to try the RESET (again, perhaps) SCURS1: CALL INISAB ;GET AN INITIALIZED SA BLOCK JRST SCURSL ;CAN'T, WAIT A WHILE AND TRY AGAIN MOVX T1,.NSFRE ;THE RESET FUNCTION CODE STOR T1,SAAFN,(SA) ;STORE THE FUNCTION CODE FOR SCLINK MOVE T1,SA ;SCLINK NEEDS A MSG BLK TO QUEUE CALL SCTNSF ;TELL SCLINK TO DO THE RESET NOW TMNE SAERR,(SA) ;DID WE HAVE AN ERROR JRST SCURSL ;YES, TRY AGAIN LATER ;Here when the RESET has completed SETZRO SJRST,(SJ) ;SUCCESS, NO LONGER RESETing CALLRET SCUFSA ;FREE THE SA BLOCK AND RETURN ;Here when the RESET must be restarted later due to allocation failure SCURSL: CALL SCUFSA ;FREE THE SA BLOCK CALL SCH1BS ;SLEEP FOR 1 SECOND JRST SCURS1 ;TRY RESET AGAIN ; ; ROUTINE TO SLEEP FOR 1 SECOND ; SCH1BS: MOVEI T1,1 * ^D1000 ;SLEEP FOR ONE SECOND PUSH P,F ;SAVE WHATEVER AC F IS SETZM F ;HIBER THINKS F POINTS TO A DDB MCALL (RG,MCSEC0,HIBER##) ;WAIT FOR SOME MEMORY POP P,F RET SUBTTL SCUUUO -- The NSP. UUO processor ;Called from the UUO handler for an NSP. UUO ; ;Call: ; T1/ UUOCON sets up T1 with contents of AC ; J/ Job Number ; ; RET ;ON ERROR, ERROR CODE IN USER'S AC ; RETSKP ;ON SUCCESS, WITH FUNCTION COMPLETED INTERNAL SCUUUO XRENT SCUUUO IFE FTXMON, ;SWITCH TO DECNET CONTEXT MOVE P1,T1 ;SAVE CONTENTS OF USER AC CALL SCUINI ;SET UP SJ & SA, SET UP MSG BLK JRST [ MCALL (RG,MCSEC0,STOTAC##) ;CAN'T GET MEMORY, ERROR CODE IN T1 RET] ;STORE CODE IN USER'S AC, ERROR RETURN STOR M,SJMUU,(SJ) ;SAVE MUUO FOR STOTAC, ETC MOVE M,P1 ;POINTER TO USER'S ARG BLOCK MOVX P2,SJPRV ;GET THE PRIVILEGED-JOB FLAG ANDCAM P2,SJ.PRV(SJ) ;ASSUME HE'S LOST ANY PRIVS MCALL (RG,MSEC1,PRVJC##) ;PRIVILEGED JOB? IORM P2,SJ.PRV(SJ) ;YES, REMEMBER THAT CALL SCGWRD ;GET THE FUNCTION WORD SCERR %NEADE,SCUUUE,
CALL SCPWRD ;PUT IT BACK TO CHECK WRITABILITY NOW SCERR %NEADE,SCUUUE,
HRRZ W,T1 ;TELL SCGWRD THE LENGTH OF ARG BLK CALL SCUAFN ;PROCESS THE .NSAFN ARG WORD CALLRET SCUUUE ;PROPOGATE ERROR RETURN CALL SCGWR1 ;GET CHANNEL NUMBER (MAYBE JOB NUMBER) SCERR %NEADE,SCUUUE,
CALL SCPWRD ;PUT IT BACK TO CHECK WRITABILITY NOW SCERR %NEADE,SCUUUE,
STOR T1,SAACH,(SA) ;STORE IT IN THE SA'S ARG BLOCK CALL SCURAA ;READ THE .NSAAn ARGUMENTS FROM USER CALLRET SCUUUE ;PROPOGATE ERROR RETURN ;Call SCLINK to perform the NSP. function. MOVE T1,SA ;T1 POINTS TO SA STRUCTURE'S MSG BLK CALL SCTNSF ;PERFORM THE FUNCTION ;Now store the arguments in the SA block back into the User Space. MOVE M,P1 ;RESTORE VIRGIN M FOR SCPWRD CALL SCUWAxx ;WRITE BACK .NSAxx AS REQUESTED CALLRET SCUUUI ;WE HAD AN ERROR, CHECK IT CALL SCUFSA ;FREE THE SA MESSAGE BLOCK RETSKP ;SUCCESS RETURN ;Here to check the error code returned from SCUWAxx SCUUUI: CAIE T1,%NEADE ;WAS ERROR AN ADDRESS ERROR? CALLRET SCUUUE ;NO, NO PROBLEM FOR US ;Here if we had an address error after the function ;If we get here, then we let an erroneous address get through to ;SCLINK and we were very lucky not get get an IME STOPCD. BUG. CHK,SCMAAE,SCMUUO,SOFT,
,,< Cause: This BUG is not documented yet. > MOVX T1,%NEADE CALLRET SCUUUE ;ERROR RETURN TO USER ;Here to deallocate internal SBlock and CBlocks and the message ;block (SA block) used to pass arguments to SCLINK. ;Give error return. SCUUUE: LOAD M,SJMUU,(SJ) ;TELL STOTAC WHICH AC TO STORE T1 IN MCALL (RG,MCSEC0,STOTAC##);STORE ERROR CODE IN USER'S AC ; CALLRET SCUFSA ;CALL THE NORMAL ROUTINE ;GIVE ERROR RETURN (ORED) ;Free the SA block and any of its appendages SCUFSA: OPSTR ,SJSAB,(SJ) ;GET POINTER TO CURRENT SA BLOCK RET ;LEAVE IF NO SA BLOCK LEFT OPSTR ,SACBP,(SA) ;IS THERE A CONNECT BLOCK? CALL DNFWDS ;YES, FREE UP THOSE WORDS OPSTR ,SASBP,(SA) ;IS THERE A STRING BLOCK? CALL DNFWDS ;YES, FREE UP THOSE WORDS MOVE T1,SA ;WE CHECKED SA ABOVE CALL DNFWDS ;YES, FREE IT OPSTRM ,SJSAB,(SJ) ;WE NO LONGER HAVE AN SA BLOCK RET ;DONE SUBTTL SCUUUO -- SCUINI - Initialization ;Here to set up SCUUUO to process an NSP. function (User Mode) ; ;Call: ; RET ;ON ERROR, ERROR CODE IN T1 ; RETSKP ;ON SUCCESS ; ;Sets up SA/ Message block to pass to SCLINK ; SJ/ Pointer to SC's job block ; J/ Job Number SCUINI: SAVEAC ;DN ROUTINES MAY SMASH M AND W IFN <!>, HRRZ P1,JBTPDB##(J) ;GET POINTER TO JOB'S PDB JUMPE P1,[BUG. CHK,SCMNPD,SCMUUO,SOFT,,,< Cause: This BUG is not documented yet. >,SCUI.A] SKIPE SJ,.PDSJB##(P1) ;GET POINTER TO JOB'S SJB JRST SCUI.1 ;ALREADY HAVE AN SJB, USE IT ;Here to build a SJB for a new job MOVE T1,SCUDFT ;GET DEFAULT GOAL, QUOTAS CALL MAKSJB ;GO MAKE AN SJB SCUI.A: SCERR %NEALF,RTN, MOVE SJ,T1 ;SJB POINTER RETURNED IN T1 STOR J,SJJOB,(SJ) ;SCLINK DOESN'T KNOW ABOUT J MOVEM SJ,.PDSJB##(P1) ;STORE POINTER TO NEW SJB IN PDB SCUI.1: TMNE SJRST,(SJ) ;RESET IN PROGRESS? CALL SCURSU ;MUST COMPLETE THE RESET FIRST CALL INISAB ;SET UP AN SA BLOCK TO SEND TO SCLINK RET ;PROPOGATE ERROR RETURN, CODE IN T1 RETSKP ;Here to set up an SAB block to pass to SCLINK ; ;Call: ; SJ/ Pointer to SC's job block ; ;Return: ; RET ;ON ERROR, ERROR CODE IN T1 ; RETSKP ;ON SUCCESS ; ;Sets up SA/ Message block to pass to SCLINK INISAB: SAVEAC ;DN ROUTINES MAY SMASH M AND W CALL SCUFSA ;FREE ANY LEFTOVER SA BLK & APPENDAGES SETZM SA ;ZERO SA IN CASE OF ALLOCATION FAILURE MOVEI T1,SA.LEN ;LENGTH OF AN SA BLOCK CALL DNGWDS ;GET NON-ZEROED MSG BLK FOR SCLINK ARGS SCERR %NEALF,RTN, MOVE SA,T1 ;SET UP SA STOR SA,SJSAB,(SJ) ;SAVE PTR FOR WHEN WE LEAVE ;Zero some fields we expect to be zero, since block is not zeroed SETZRO SABCT,(SA) ;SCCBxT NEEDS TO KNOW SETZRO SABPT,(SA) ; OR NOT WE HAVE A BPT OR COUNT YET SETZRO SASBP,(SA) ;WE HAVE NO STRING BLOCK SETZRO SACBP,(SA) ;WE HAVE NO CONNECT BLOCK SETZRO SAMFG,(SA) ;WE HAVE NO MONITOR FLAGS ;Fill in some fields that we always need in the SA block STOR SJ,SASJB,(SA) ;STORE THE ADDRESS OF THE SJB XMOVEI T1,SCUHBR ;POINT TO THE HIBER ROUTINE STOR T1,SAHBA,(SA) ;STORE IN THE HIBER ADDRESS ARGUMENT XMOVEI T1,SCUWAK ;GET ADDRESS OF WAKE HANDLER STOR T1,SAWKA,(SA) ; AND TELL SCLINK ABOUT IT RETSKP ;SUCCESS SUBTTL SCUUUO -- SCUAFN - Read the Function Code ;Here to check the .NSAFN word, the function word of the user's args ; ;Call: T1/ The .NSAFN word ; ; RET ;ON SCERR, T1 HOLDS ERROR CODE ; RETSKP ;ON SUCCESS SCUAFN: LOADE T3,NFSIZ,+T1 ;GET SIGNED SIZE (WORDS) OF ARG BLOCK CAIGE T3,2 ;DO WE HAVE THE MINIMUM NUMBER OF ARGS SCERR %NEWNA,RTN, STOR T3,SANAG,(SA) ;SAVE NUMBER OF ARGS IN ARG BLOCK LOAD T3,NFFLG,+T1 ;GET THE FLAGS FROM THE FLAG FIELD STOR T3,SAFLG,(SA) ;STORE THEM IN THE SA FLAG WORD LOAD T3,NFFNC,+T1 ;THE FUNCTION CODE SKIPLE T3 ;CHECK THAT ITS A VALID FUNCTION CAILE T3,.NSFMX ; ON THE FUNCTION TYPE SCERR %NEILF,RTN, STOR T3,SAAFN,(SA) ;STORE THE FUNCTION TYPE IN ARG BLOCK RETSKP SUBTTL SCUUUO -- SCURAA - Read the AAn Arguments ;Store any connect block or string blocks in the internal connect and ;string block format for SCLINK. ; ;Call: SA/ The message block for SA arguments ; ;Call: RET ;ON SCERR, T1 HOLDS ERROR CODE ; RETSKP ;ON SUCCESS ; ;Arguments with APR set are copied from the user's space to monitor ;buffers for SCLINK. Arguments with APW set are checked to assure that ;when we want to copy data to them after the function is complete that ;we will not find a page fault which would restart the UUO. SCURAA: SAVEAC LOAD P2,SAAFN,(SA) ;LOAD UP THE FUNCTION CODE MOVE P2,SCUTAB-1(P2) ;GET THE FUNCTION'S ARGUMENT TABLE MOVE P1,0(P2) ;GET THE COUNT OF EXPECTED ARGUMENTS LOAD T1,SANAG,(SA) ;GET THE NUMBER OF ARGUMENTS USER GAVE CAILE P1,-2(T1) ;CHOSE SMALLER OF THE TWO MOVEI P1,-2(T1) ; (MINUS .NSAFN AND .NSACH) ADD P2,P1 ;POINT TO LAST ARG DESCRIPTOR ADD M,P1 ;POINT TO LAST ARG JUMPLE P1,RSKP ;SUCCESS IF NO ARGS TO COPY SCURA1: TMNN ,(P2) ;SHOULD WE READ OR CHECK FOR WRITE? JRST SCURA3 ;NO, SKIP PROCESSING ;YES CALL SCGWRD ;GET THE ARGUMENT WORD INTO T1 SCERR %NEADE,RTN,
TMNE SJPRV,(SJ) ;YES, PRIVILEGED JOB? JRST SCURA2 ;YES, DON'T CHECK THIS ONE JUMPE T1,SCURA2 ;IF NOTHING SUPPLIED, DON'T PRIV CHECK TMNE APP,(P2) ;NO, IS THIS A PRIVILEGED FUNCTION? SCERR %NEPRV,RTN, SCURA2: LOAD T2,APDSP,(P2) ;GET THE DISPATCH OFFSET CALL @SCUCDS(T2) ;CALL THE CORRECT ARGUMENT PROCESSOR RET ;THERE WAS AN ERROR, PROPAGATE THE ERROR XMOVEI T2,SA.AA1-1(SA) ;POINT TO FIRST AA ARGUMENT ADD T2,P1 ;PASS STORAGE LOC TO ARG PROCESSOR MOVEM T1,(T2) ;STORE VALUE RETURNED BY PROCESSOR TMNE APR,(P2) ;DID WE REALLY WANT TO READ THIS? JRST SCURA3 ;YES, ALL DONE SETZM (T2) ;NO, JUST CHECKING FOR PAGE FAULTS LOAD T1,APDSP,(P2) ;GET DISPATCH OFFSET AGAIN CALL @SCUDDS(T1) ;DISCARD STRING OR CONNECT BLOCK SCURA3: SOJ P2, ;LOOP DOWN THE ARG DESCRIPTORS SOJ M, ;LOOP DOWN USER'S ARG LIST TOO SOJG P1,SCURA1 ;LOOP WHILE STILL MORE ARGS RETSKP ;SUCCESS RETURN SUBTTL Argument Readers -- SCCCBL - Connect Block ;SCCCBL - Read the Connect-Block argument from user address space ; ; Call: T1/ Contents of argument word ; SJ/ Pointer to Session Control Job Block ; ; Return: ; RET ;ON RESOURCE FAILURE ; RETSKP ;ALL IS OK, WITH T1/ WORD FOR SJAAx ; ; Uses: T1-T4 ; ;Note that M is the same as DECnet-36's T6, and is thus not saved ;by calls to DECnet-36 subroutines. SCCCBL: SAVEAC ;PRIVATE M AND SAVE A COUPLE OF PEAS IFN <!>, MOVE P1,T1 ;SAVE USER CBLOCK POINTER OPSTR ,SACBP,(SA) ;DO WE HAVE A CONNECT BLOCK? CALL DNFWDS ;YES, GET A SHINY NEW ONE INSTEAD MOVX T1,CB.LEN ;LENGTH OF A CONNECT BLOCK CALL DNGWDZ ;GET A ZEROED MONITOR CONNECT BLOCK SCERR %NERES,RTN, STOR T1,SACBP,(SA) ;STORE POINTER TO MONITOR CONNECT BLOCK MOVE P2,T1 ;SAVE POINTER TO MONITOR CONNECT BLOCK JUMPE P1,SCCCBX ;LEAVE IF NO USER CONNECT BLOCK MOVE M,P1 ;SET THE NEW BASE TO GET ARGUMENTS FROM ;LENGTH CALL SCGWRD ;GET THE LENGTH OF THE USER CBLOCK SCERR %NEADE,RTN,
HRRZ W,T1 ;TELL SC?WR1 LENGTH OF ARG BLOCK JUMPE W,SCCCBX ;LEAVE IF THE CONNECT BLOCK IS ZERO LONG CAIL W,CBL.MN ;RANGE CHECK THE NUMBER OF ARGS CAILE W,CBL.MX SCERR %NECBL,RTN, ;NAME CALL SCGWR1 ;GET THE POINTER TO THE NAME BLOCK SCERR %NEADE,RTN,
CALL GETSXR ;GET THE STRING BLOCK INTO A SIXBIT WORD SCERR %NEADE,RTN,
SETZRO CBCIR,(P2) ;ZERO CIRCUIT ID SETZRO CBNUM,(P2) ;AND NODE ADDRESS LOAD T2,SAAFN,(SA) ;GET FUNCTION CODE CAIE T2,.NSFEA ;ENTER ACTIVE FUNCTION? JRST SCCCB1 ;NO, SKIP NAME/ADDRESS MAPPING STOR T1,CBNUM,(P2) ;SAVE NODE NAME IN CASE SCTN2A FAILS CALL SCTN2A## ;DO NAME TO NODE ADDRESS TRANSLATION JRST [ LOAD T1,CBNUM,(P2) ;GET BACK NODE NAME CALL SCTN2L## ;TRY FOR LOOPBACK NODE NAME SCERR %NEUKN,RTN, STOR T1,CBCIR,(P2) ;STORE CIRCUIT ID MOVE T1,RTRADR## ;GET OUR NODE ADDRESS MOVE T2,RTRHOM## ;AND OUR AREA NUMBER DPB T2,[POINTR (T1,RN%ARE)] ;BUILD COMPLETE NODE ADDRESS JRST .+1] ;AND CONTINUE STOR T1,CBNUM,(P2) ;SAVE FOR LATER USE SCCCB1: ;SOURCE PROCESS BLOCK CALL SCGWR1 ;GET THE NEXT ARG (SOURCE PROCESS BLOCK PTR) SCERR %NEADE,RTN,
XMOVEI T2,CB.SRC(P2) ;PUT IT HERE CALL GETPRO ;GET THE PROCESS BLOCK RET ;OOPS, GOT AN ERROR ;DESTINATION PROCESS BLOCK CALL SCGWR1 ;GET THE DESTINATION PROCESS BLOCK PTR SCERR %NEADE,RTN,
XMOVEI T2,CB.DST(P2) ;PUT IT HERE CALL GETPRO ;GET THE PROCESS BLOCK RET ;OOPS, GOT AN ERROR ;USER ID CALL SCGWR1 ;GET THE NEXT ARG (USER ID) SCERR %NEADE,RTN,
JUMPE T1,SCCCB2 ;IS THERE A POINTER TO STRING? XMOVEI T2,CB.UID(P2) ;YES, POINT TO ITS AREA IN THE INTERNAL CBLOCK CALL GETSTR ;PUT IT IN SCERR %NEADE,RTN,
STOR T1,CBUCT,(P2) ;ALONG WITH THE COUNT SCCCB2: ;PASSWORD CALL SCGWR1 ;GET THE NEXT ARG (PASSWORD) SCERR %NEADE,RTN,
JUMPE T1,SCCCB3 ;SBLOCK POINTER? XMOVEI T2,CB.PSW(P2) ;YES, PASSWORD PLACE IN CBLOCK CALL GETSTR ;PUT IT IN MONITOR'S CBLOCK SCERR %NEADE,RTN,
STOR T1,CBPCT,(P2) ;SAVE THE COUNT SCCCB3: ;ACCOUNT CALL SCGWR1 ;GET THE NEXT ARG (ACCOUNT STRING) SCERR %NEADE,RTN,
JUMPE T1,SCCCB4 ;SBLOCK POINTER? XMOVEI T2,CB.ACC(P2) ;ACCOUNT'S PLACE IN CBLOCK CALL GETSTR ;PUT IT IN MONITOR'S CBLOCK SCERR %NEADE,RTN,
STOR T1,CBACT,(P2) ;SAVE THE COUNT SCCCB4: ;USER DATA CALL SCGWR1 ;GET THE USER DATA STRING POINTER SCERR %NEADE,RTN,
JUMPE T1,SCCCBX ;JUMP IF NO USER DATA OFFERED XMOVEI T2,CB.UDA(P2) ;PUT IT HERE MOVEI T3,UDA.MX ; WITH THIS MAX LENGTH CALL GETST1 ; IN THE CBLOCK SCERR %NEADE,RTN,
STOR T1,CBCCT,(P2) ; ALONG WITH THE COUNT SCCCBX: LOAD T1,SACBP,(SA) ;RETRIEVE POINTER TO CONNECT BLOCK RETSKP ;RETURN SUCCESSFULLY TO USER SUBTTL Argument Readers -- SCCSBL - String Block ;SCCSBL - Process the String-Block argument ; ; Call: ; T1/ Contents of argument word ; SJ/ Pointer to Session Control Job Block ; ; Return: ; RET ;ON ERROR, CODE IN T1 ; RETSKP ;SUCCESS, WITH T1 WITH VALUE FOR SJAAx ; ; Uses: T1-T4 ; ;We might have blocks hanging off the SA block from last time if ;this is a restarted UUO (after a page fault). We free them and get ;new ones rather than trying to clean them up here to reduce the ;number of paths offered by this code. I assume page fault restarts ;will not happen too often, so the overhead is not significant. SCCSBL: SAVEAC ;GET PRIVATE COPY OF M AND SAVE TWO PS MOVE P1,T1 ;SAVE THAT POINTER OPSTR ,SASBP,(SA) ;DO WE HAVE A STRING BLOCK CALL DNFWDS ;YES, GET A SHINY NEW ONE JUMPE P1,RSKP ;RETURN SUCCESS, EVEN THOUGH NOT THERE MOVX T1,SB.LEN ;GET A STRING CALL DNGWDS ; BLOCK, NO NEED TO ZERO IT SCERR %NEALF,RTN, STOR T1,SASBP,(SA) ;SAVE THE POINTER MOVE P2,T1 ;SAVE THE INTERNAL SBLOCK POINTER XMOVEI T2,SB.DAT(P2) ;PLACE TO STORE THE USER'S STRING MOVE T1,P1 ;GET THE POINTER TO USER'S SBLOCK BACK CALL GETSTR ;STORE THE STRING IN THE SBLOCK SCERR %NEADE,RTN,
STOR T1,SBCNT,(P2) ;SAVE THE COUNT LOAD T1,SASBP,(SA) ;GET STRING BLOCK POINTER AGAIN RETSKP ;RETURN SUCCESS TO THE USER SUBTTL Argument Readers -- SCCARG - Integer Argument ;SCCARG - Process a random argument ; ; Call: ; T1/ Contents of argument word ; T2/ Pointer to appointed storage loc for this argument ; SJ/ Pointer to Session Control Job Block ; ; Return: ; RET ;COULDN'T DO IT ; RETSKP ;WITH T1 CONTAINING WHAT TO STORE IN THE ; ; USER'S ARG BLOCK ; ; Uses: T1-T4 SCCARG: RETSKP SUBTTL Argument Readers -- SCCBCT - Byte Count ;SCCBCT - Process a byte count for a buffer ; ; Call: ; T1/ Contents of argument word ; T2/ Pointer to appointed storage loc for this argument ; SJ/ Pointer to Session Control Job Block ; ; Return: ; RET ;COULDN'T DO IT ; RETSKP ;WITH T1 CONTAINING WHAT TO STORE IN THE ; ; USER'S ARG BLOCK ; ; Uses: T1-T4 SCCBCT: SKIPGE T1 ;CHECK FOR NEGATIVE LENGTH SCERR %NEADE,RTN,
;DON'T ALLOW, SCLINK FALLS OVER STOR T1,SABCT,(SA) ;STORE AS THE BUFFER BYTE POINTER ALSO TMNN SABPT,(SA) ;HAVE ASSOCIATED BYTE POINTER YET? RETSKP ;NO, LET SCCBPT DO IT LATER CALL SCCBUF ;CHECK THE BUFFER RET ;ADDRESS ERROR CODE IN T1 LOAD T1,SABCT,(SA) ;GET VALUE FOR CALLER TO STORE IN SAAAx RETSKP ;SUCCESS SUBTTL Argument Readers -- SCCBPT - Byte pointer ;SCCBPT - Process a byte pointer for a buffer ; ; Call: ; T1/ Contents of argument word ; T2/ Pointer to appointed storage loc for this argument ; SJ/ Pointer to Session Control Job Block ; ; Return: ; RET ;COULDN'T DO IT ; RETSKP ;WITH T1 CONTAINING WHAT TO STORE IN THE ; ; USER'S ARG BLOCK ; ; Uses: T1-T4 ; ;We don't allow indexing or indirection because we store back an incremented ;byte pointer. We would have to store a resolved (no indexing or indirection) ;pointer, because that is what CHKBPT returns and that is what we increment. SCCBPT: STOR T1,SABPT,(SA) ;STORE AS THE BUFFER BYTE POINTER ALSO TMNN SABCT,(SA) ;HAVE ASSOCIATED BYTE COUNT YET? JRST SCCBP1 ;NO, LETS RESOLVE THE BYTE PTR THO CALL SCCBUF ;CHECK THE BUFFER RET ;ADDRESS ERROR CODE IN T1 LOAD T1,SABPT,(SA) ;GET VALUE FOR CALLER TO STORE IN SAAAx RETSKP ;SUCCESS ;Here to resolve the user's byte pointer when we haven't got the ;buffer length yet to check the whole buffer properly. SCCBP1: SAVEAC M ;CHKBPT SMASHES M MOVEI T2,1 ;CHECK A 1 BYTE BUFFER MCALL (RG,MCSEC0,CHKBPT##) ;RESOLVE USER'S INDIRECTION & INDEXING SCERR %NEADE,RTN,
STOR T1,SABPT,(SA) ;STORE THE RESOLVED BYTE POINTER RETSKP ;RETURN BYTE PTR IN T1 FOR SCLINK SUBTTL Argument Readers -- SCCBUF - Buffer Checking Subr ;SCCBUF - Buffer Checking Subroutine for SCCBCT and SCCBPT ; ; Call: ; SJ/ Pointer to Session Control Job Block ; ; Return: ; RET ;ADDRESS ERROR, CODE IN T1 ; RETSKP ;SUCCESS ; Restarts UUO on page fault ; ; Uses: T1-T4 ;Here to address check the user's buffer SCCBUF: SAVEAC M ;CHKBPT SMASHES M LOAD J,SJJOB,(SJ) ;IN CASE WE HAVE A PAGE FAULT LOAD T1,SABPT,(SA) ;GET BYTE POINTER TO USER'S BUFFER LOAD T2,SABCT,(SA) ;GET BYTE LENGTH OF USER'S BUFFER MCALL (RG,MCSEC0,CHKBPT##);GO ASK VMSER IF THIS BPT IS SAFE ;NOTE THAT M HAS BEEN TRASHED. SCERR %NEADE,RTN,
STOR T1,SABPT,(SA) ;STORE THE RESOLVED BYTE POINTER RETSKP ;RETURN TO CALLER ;Copy back the .NSAFN and .NSACH words to the user's arg blk ; ;Call: SA/ The message block for SA arguments ; M/ Pointer to user's arg block for SCGWRD ; ; RET ;ON ERROR, CODE IN T1 ; RETSKP ;ON SUCCESS ; ;We checked before the function that there were at least 2 args ;passed, so we don't have to check again here. SCUWAx:SAVEAC CALL SCGWRD ;GET THE FLAGS AND FUNCTION WORD SCERR %NEADE,RTN,
HRRZ W,T1 ;LOAD UP LENGTH FOR SC?WR1 LOAD T2,SAFLG,(SA) ;GET SA'S FLAGS STOR T2,NFFLG,+T1 ;REPLACE THE OLDER FLAGS CALL SCPWRD ;PUT THE WORD BACK IN THE USER'S SPACE SCERR %NEADE,RTN,
LOAD T1,SAACH,(SA) ;GET THE STATUS WORD,,CHANNEL NUMBER OPSTR ,SAAST,(SA) ;GET THE STATUS IN THE LEFT HALF CALL SCPWR1 ;WRITE IT BACK TO USER SPACE SCERR %NEADE,RTN,
OPSTR ,SAERR,(SA) ;DID WE GET A FAILURE? RET ;ERROR RETURN, CODE IN T1 ;Fall through to next page ; to copy .NSAA1, .NSAA2 and .NSAA3 as requested ;From previous page ;Here to copy .NSAA1, .NSAA2 and .NSAA3 as requested LOAD P2,SAAFN,(SA) ;LOAD UP THE FUNCTION CODE MOVE P2,SCUTAB-1(P2) ;GET THE FUNCTION'S ARGUMENT TABLE MOVE P1,0(P2) ;GET THE COUNT OF EXPECTED ARGUMENTS LOAD T1,SANAG,(SA) ;GET THE NUMBER OF ARGUMENTS USER GAVE CAIL P1,-2(T1) ;CHOSE SMALLER OF THE TWO MOVEI P1,-2(T1) ; (MINUS .NSAFN AND .NSACH) ADD P2,P1 ;POINT TO LAST ARG DESCRIPTOR ADD M,P1 ;POINT TO LAST ARG JUMPLE P1,RSKP ;SUCCESS IF NO ARGS TO COPY SCUWA1: TMNN APW,(P2) ;SHOULD WE WRITE THIS ARG? JRST SCUWA2 ;NO, SKIP WRITE PROCESSOR CALL SCGWRD ;GET THE NEXT USER ARGUMENT SCERR %NEADE,RTN,
MOVE T2,T1 ;PUT THE ARGUMENT IN T2 XMOVEI T1,SA.AA1-1(SA) ;POINT TO ARGUMENTS IN ARG BLOCK ADD T1,P1 ;GET THE ONE WE'RE LOOKING AT MOVE T1,(T1) ;GET THE CONTENTS OF SAAAx LOAD T3,APDSP,(P2) ;GET THE DISPATCH OFFSET CALL @SCUSDS(T3) ;CALL THE CORRECT ARGUMENT PROCESSOR RET ;PROPOGATE ERROR RETURN CALL SCPWRD ;PLACE THE WORD BACK SCERR %NEADE,RTN,
SCUWA2: SOJ P2, ;LOOP DOWN THE ARG DESCRIPTORS SOJ M, ;LOOP DOWN USER'S ARG LIST TOO SOJG P1,SCUWA1 ;LOOP WHILE STILL MORE ARGS RETSKP ;SUCCESS RETURN SUBTTL Argument Writers -- SCSCBL - Store Connect Block into User Space ;SCSCBL - Give user a connect block back ; ; Call: ; T1/ Contents of SAAAx after SCLINK ; T2/ Contents of user argument ; SJ/ Pointer to Session Control Job Block ; ; Return: ; RET ;ON AN ADDRESS FAILURE ; RETSKP ;ON SUCCESS ; ; Uses: T1-T4 SCSCBL: SAVEAC ;GET A COPY OF M AND SAVE SOME PEAS MOVE P2,T2 ;SAVE POINTER TO USER'S CONNECT BLK SKIPN M,T2 ;GET THE POINTER TO CONNECT BLOCK SCERR %NEABE,RTN, CALL SCGWRD ;GET ARG BLOCK LENGTH WORD SCERR %NEADE,RTN,
HRRZ W,T1 ;SAVE FOR SCPWR1 LOAD P1,SACBP,(SA) ;MAKE P1 POINT TO THE CONNECT BLOCK LOAD T1,CBNUM,(P1) ;GET THE NODE NUMBER CALL SCTA2N## ;GET THAT NODE'S NAME SETZ T1, ;DON'T HAVE A NAME, LEAVE IT ZERO LENGTH CALL PUTSX1 ; AND PLACE IT AFTER LENGTH WORD RET ;ERROR, CODE IN T1 XMOVEI T2,CB.SRC(P1) ;POINT TO THE SOURCE PROCESS DESCRIPTOR CALL PUTPR1 ;PLACE IT IN THE USER'S AREA RET ;ERROR, CODE IN T1 XMOVEI T2,CB.DST(P1) ;THE DESTINATION PROCESS DESCRIPTOR CALL PUTPR1 ;PLACE IT IN THE USER'S AREA RET ;ERROR, CODE IN T1 LOAD T1,CBUCT,(P1) ;GET THE USER ID BYTE COUNT XMOVEI T2,CB.UID(P1) ;POINT TO THE STRING CALL PUTST1 ;PLACE THE STRING RET ;ERROR, CODE IN T1 LOAD T1,CBPCT,(P1) ;GET THE PASSWORD'S BYTE COUNT XMOVEI T2,CB.PSW(P1) ;POINT TO THE STRING CALL PUTST1 ;PLACE IN USER SPACE RET ;ERROR, CODE IN T1 LOAD T1,CBACT,(P1) ;GET THE ACCOUNT NAME BYTE COUNT XMOVEI T2,CB.ACC(P1) ;POINT TO THE STRING CALL PUTST1 ; AND PUT IT IN THE USER'S AREA RET ;ERROR, CODE IN T1 LOAD T1,CBCCT,(P1) ;GET THE COUNT OF CONNECT DATA XMOVEI T2,CB.UDA(P1) ;POINT TO THE CONNECT DATA CALL PUTST1 ; PLACE IT IN THE USER'S AREA RET ;ERROR, CODE IN T1 MOVE T1,P2 ;RESTORE CONNECT BLOCK POINTER RETSKP ; AND RETURN SUBTTL Argument Writers -- SCSSBL - Store String Block into User Space ;SCSSBL - Give user a string block back ; ; Call: ; T1/ Contents of SAAAx after SCLINK (ignored here) ; T2/ User pointer to string block ; P1/ Pointer to flag word in SCUTAB for function ; SJ/ Pointer to Session Control Job Block ; M/ Pointer to pointer to string block in user's address space ; ; Return: ; RET ;ON ADDRESS FAILURE ; RETSKP ;ON SUCCESS ; ; Uses: T1-T4 ; ;In this routine, we ignore the contents of SAAAx, since we have a ;pointer to the string block in SASBP. SCSSBL: SAVEAC P1 ;SAVE PTR TO USER STRING BLK HERE MOVE P1,T2 ;WE'LL NEED THIS LATER LOAD T2,SASBP,(SA) ;POINTER TO STRING BLOCK LOAD T1,SBCNT,(T2) ;GET COUNT OF BYTES WE GOT FROM MESSAGE ADDI T2,SB.DAT ;POINT TO START OF STRING'S DATA CALL PUTSTR ;PUT STRING IN USER'S STRING BLOCK RET ;ADDRESS ERROR, CODE IN T1 MOVE T1,P1 ;RESTORE UVA OF STRING BLK FOR SCUWAAx RETSKP ;SUCCESS RETURN SUBTTL Argument Writers -- SCSARG, SCSBCT, SCSBPT ;SCSARG - Store some random argument ; ; Call: ; T1/ Contents of argument word ; SJ/ Pointer to Session Control Job Block ; ; Return: ; RET ;COULDN'T DO IT ; RETSKP ;WITH T1 CONTAINING WHAT TO STORE IN THE ; ; USER'S ARG BLOCK ; ; Uses: T1 SCSBCT: ;NO NEED TO CHECK THIS ON WRITE-BACK SCSBPT: ;DITTO SCSARG: RETSKP ;JUST GIVE HIM WHAT HE GAVE US SUBTTL Argument Discarders -- SCDARG, SCDCBL, SCDSBL ;SCDARG - Discard a block we just built to check for user page faults ; ; Call: ; SA/ Pointer to SA block ; SJ/ Pointer to Session Control Job Block ; ; Return: ; RET ;ONLY RETURN ; ; Uses: T1 SCDBCT: ;NOTHING TO DO FOR BYTE COUNT SCDBPT: ;NOTHING TO DO FOR BYTE POINTER SCDARG: RET ;NOTHING TO DO FOR SINGLE ARG SCDCBL: OPSTR ,SACBP,(SA) ;IS THERE A CONNECT BLK? CALL DNFWDS ;YES, FREE THE CONNECT BLOCK SETZRO SACBP,(SA) ;NO MORE CONNECT BLOCK RET SCDSBL: OPSTR ,SASBP,(SA) ;IS THERE A STRING BLK? CALL DNFWDS ;YES, FREE THE CONNECT BLOCK SETZRO SASBP,(SA) ;NO MORE STRING BLOCK RET SUBTTL Subroutines -- SCUHBR - Subroutine to do the HIBERs. ;SCUHBR - Called by SCLINK to hibernate ; ; Call: ; T1/ Pointer to SJB ; ; Return: ; RET ;ONLY RETURN ; ; Uses: T1 SCUHBR: SAVEAC ;SAVE A FEW ACS MOVE SJ,T1 ;POINTER TO SJB SETZM F ;F DOES NOT HOLD PTR TO A DDB! LOAD J,SJJOB,(SJ) ;MONITOR WANTS TO KNOW WHAT JOB THIS IS MOVX T1,EV.DCN ;DECNET EVENT WAIT MCALL (RG,MCSEC0,ESLEEP##) ;SCUWAK GETS US OUT OF THIS. RET ;AND RETURN SUBTTL Subroutines -- SCUWAK - Subroutine to do the WAKEs. ;SCUWAK - Called when SCLINK thinks we might want to wake the user ; ; Call: T1/ Old Status,,PSI Mask ; T2/ New Status,,Channel Number ; T3/ Pointer to Session Control Job Block ; T4/ Link identifier to pass to SCTWKQ ; T5/ ???,,Status Changes ; ; Return: ; RET ;Tells SCLINK not to queue SLB ; RETSKP ;Tells SCLINK to queue SLB for SCTPSQ ; ; Uses: T1,T2,T3,T4 ; ;SCLINK calls this routine (via SAWKA,(SA)) when either the link ;state has changed or one of the status bits has changed from a ;zero to a one. SCUWAK: ;INISAB PASSES ADDR TO SCLINK SAVEAC ;SAVE A FEW ACS FROM TOPS-10 MOVE P1,T3 ;POINTER TO SJB ;Note that T4 contains the link identifier we pass to SCTWKQ T5==T4+1 ;DEFINE T5 FOR INTERFACE WITH DECNET AND T5,T1 ;AND CHANGES WITH THE PSI MASK TRNN T5,-1 ;ANY INTERESTING CHANGES? JRST SCUWK1 ;NO, SKIP PSI ;Here to signal a PSI interrupt. PSISER will call SCTPSI later ;to discover the reason, so we offer none here. ;If the PSI is accepted, we don't have to do a WAKE as well, because ;PSISER does that for us. MOVE T1,T4 ;PASS LINK IDENTIFIER TO SCTWKQ CALL SCTWKQ ;ASK SCLINK TO QUEUE THIS LINK FOR SCTPSQ JUMPE T1,SCUWK1 ;ALREADY QUEUED; DON'T DO IT AGAIN LOAD J,SJJOB,(P1) ;GET JOB NUMBER WE'RE TO INTERRUPT ; SIGNAL C$NSP ;SIGNAL A PSI INTERRUPT HRROI T1,C$NSP ;THIS HAS TO BE DONE BY HAND SINCE XCALL MUST BE EXECUTED XCT NOPISK## ;PSI ENABLED? MCALL (RG,MSEC1,PSICND##) ;SIGNAL JRST SCUWK1 ;HIBER WAKE ALSO IF PSI DIDN'T WAKE JRST SCUWK2 ;SKIP ASYNCH I/O WAKE IF PSI DID WAKE ;We have to wake the job anyway, for users with asynchronous I/O SCUWK1: LOAD J,SJJOB,(P1) ;GET JOB NUMBER MOVSI T1,IOACE## ;ASYNC IO WAKE BIT (USER CALLS IT HB.RIO) TDNE T1,JBTRTD##(J) ;IS THIS JOB INTERESTED IN SUCH WAKEUPS? MCALL (RG,MCSEC0,WAKEJB##);HIBERING ON ASYNC I/O, WAKE IT UP. SCUWK2: LOAD T1,SJJOB,(P1) ;GET JOB NUMBER FOR EWAKE MCALL (RG,MCSEC0,EWAKE##);(T1)GET JOB OUT OF EW OR MARK FOR WAKE RET ;AND RETURN PURGE T5 ;AND FORGET ABOUT THIS DEFINITION SUBTTL Subroutines -- SCTPSI - Get PSI associated variable ;SCTPSI - Called from PSISER to get associated variable for interrupt ; ; Call: J/ Job Number ; ; Return: ; T2/ Link Status,,Link Number (Channel Number) ; ;T2 is zero if error found ; RET ;Always ; ; Uses: T1,T2,T3,T4 ; ;Since there is no state zero, if we return a zero in T2 (the ;value that will be given to the user as PSI's associated variable) ;we are telling the user that this is a null interrupt. We should ;not give null interrupts, of course, but we need some way of passing ;on errors here... SCTPSI:: SEC1 ;DO OUR STUFF IN EXTENDED SECTIONS SAVEAC ;PSISER IS PICKY. DECNET TRASHES THESE ACS. IFN <!>, ;Load up SJ with the SJB pointer to SCLINK SKIPN T1,JBTPDB##(J) ;GET POINTER TO JOB'S PDB BUG. CHK,SCMNP2,SCMUUO,SOFT,,,< Cause: This BUG is not documented yet. >,SCTPSE HRRZS T1 ;MAKE IT A SECTION ZERO POINTER (NFYPGS) SKIPN T1,.PDSJB##(T1) ;GET POINTER TO JOB'S SJB FOR SCTPSQ JRST SCTPSE ;NO SJB, SHOULD NOT HAPPEN CALL SCTPSQ ;ASK SCLINK TO DEQUEUE NEXT SLB JRST SCTPSE ;NONE THERE, RETURN T2/ ZERO TXNN T1,PSMOR ;ANY MORE SLBs NEED INTERRUPTS? RET ;NO, RETURN T2/ STATUS,,CHN NUMBER PUSH P,T2 ;YES, SAVE T2 FROM PSISER ;J IS ALREADY LOADED BY PSISER ; SIGNAL C$NSP ;SIGNAL ANOTHER INT AFTER THIS ONE HRROI T1,C$NSP ;DO THIS BY HAND XCT NOPISK## ;PSI ENABLED? MCALL (RG,MSEC1,PSICND##) ;SIGNAL THE INTERRUPT JFCL ;IGNORE FAIL RETURN (UNLIKELY) POP P,T2 ;RESTORE ASSOCIATED VARIABLE FOR PSISER RET ;RETURN T2/ STATUS,,CHN NUMBER ;Here on error SCTPSE: MOVEI T2,0 ;ERROR RETURN, GIVE USER NULL INTERRUPT RET SUBTTL Subroutines -- SCGWRD & SCPWRD ; Calls: ; T1/ Word to write for SCPWRD & SCPWR1 ; M/ User Address to GET/PUT ; W/ Remaining length of user arg block ; SJ/ Pointer to Session Control Job Block ; SA/ Pointer to Message Block used for SA args ; ; Return: ; RET ;ADDRESS ERROR, CALLER MUST HANDLE IT ; ; SA BLOCK HAS BEEN DEALLOCATED ; RETSKP ;WITH T1 HOLDING SCGWRD/SCGWR1 WORD ; ; Uses: T1 ; ;When the caller reads the length (first) word of a user arg block, ;s/he is expected to HRRZ W,T1 afterwards for these routines. ; ;Calls to SCGWRD and SCPWRD are assumed to know whether or not there ;is room, eg, they are used to get/put the length word. ;Calls to SC?WR1 are checked for room before they are executed. IFN R-CX, ;These routines do not save R, assuming that it is CX, the super-temp. SCGWR1: ADDI M,1 ;GET THE NEXT WORD SOJLE W,SCGW.1 ;LEAVE IF NO MORE TO READ SCGWRD: LOAD J,SJJOB,(SJ) ;SET UP J IN CASE OF PAGE FAULT MOVE R,.CPADR## ;GETWRD NEEDS R SET UP MCALL (RG,MSEC1,GETWRD##) ;YES, CALL STANDARD TOPS10 GET WORD RET ;BAD RETURN RETSKP ;SKIP RETURN SCGW.1: SETZ T1, ;NO, RETURN ZERO RETSKP ;SUCCESS RETURN SCPWR1: ADDI M,1 ;PUT IN THE NEXT WORD SOJLE W,SCGW.1 ;LEAVE IF NO MORE ROOM TO WRITE SCPWRD: LOAD J,SJJOB,(SJ) ;SET UP J IN CASE OF PAGE FAULT MOVE R,.CPADR## ;PUTWRD NEEDS R SET UP MCALL (RG,MSEC1,PUTWRD##) ;CALL STANDARD TOPS10 PUT WORD RET ;NON-SKIP RETURN RETSKP ;SKIP RETURN SUBTTL Subroutines -- GETPRO - Get process block ;GETPRO - Transfer user's process block to a portion of internal connect block ; ; Call: ; T1/ Pointer to user's process block (destination or source) ; T2/ Pointer to some portion of the internal connect block ; ; Return: ; RET ;ON ERROR WITH T1 CONTAINING ERROR CODE ; RETSKP ;ON SUCCESS ; ; Uses: T1-T4 GETPRO: SAVEAC ;GET OUR OWN M AND SAVE A P MOVE P2,T2 ;SAVE THE POINTER TO INTERNAL CBLOCK SKIPN M,T1 ;SET UP TO GET WORDS FROM USER'S BLOCK RETSKP ;LEAVE EMPTY BLOCK IF NO USER POINTER ;LENGTH CALL SCGWRD ;GET THE LENGTH WORD SCERR %NEADE,RTN,
HRRZ W,T1 ;TELL SC?WR1 LENGTH OF ARG BLOCK JUMPE W,RSKP ;LEAVE EMPTY BLK IF USER'S IS ZERO LONG CAIL W,PBL.MN ;RANGE CHECK THE LENGTH CAILE W,PBL.MX SCERR %NEPBL,RTN, STOR W,PBSIZ,(P2) ;STORE THE LENGTH ;FORMAT TYPE CALL SCGWR1 ;GET THE FORMAT TYPE SCERR %NEADE,RTN,
STOR T1,PBFOR,(P2) ;STORE IT IN THE INTERNAL CONNECT BLOCK CAIL T1,FRM.0 ;RANGE CHECK THE CAILE T1,FRM.MX ; FORMAT TYPE SCERR %NEBFT,RTN, ;OBJECT TYPE CALL SCGWR1 ;GET THE OBJECT TYPE SCERR %NEADE,RTN,
TMNN PBFOR,(P2) ;IS THIS A ZERO FORMAT TYPE? STOR T1,PBOBJ,(P2) ;YES, STORE THE OBJECT TYPE ;Fall through to next page ;From previous page IFN ,> ;PPN CALL SCGWR1 ;GET THE PPN (GRPCODE AND USRCOD) SCERR %NEADE,RTN,
AND T1,[177777,,177777] ;LIMIT TO 16 BITS IN EITHER HALF LOAD T2,PBFOR,(P2) ;GET THE FORMAT TYPE AGAIN CAIN T2,FRM.2 ;IS IT A FORMAT TWO? MOVEM T1,PB.USR(P2) ;YES, PRINTX ABOVE CHECKS THIS MOVEM ;TASK NAME CALL SCGWR1 ;GET THE POINTER TO THE STRING BLOCK SCERR %NEADE,RTN,
XMOVEI T2,PB.NAM(P2) ;SETUP TO STORE STRING IN INT. CBLOCK CALL GETSTR ;STORE IT SCERR %NEADE,RTN,
STOR T1,PBNCT,(P2) ;STORE STRING LENGTH TOO RETSKP ;SUCCESS RETURN SUBTTL Subroutines -- GETSTR - Get a string block ;GETSTR - Transfer user's string block to internal string block ; ; Call: ; T1/ Pointer to the user's string block ; T2/ Pointer to internal block to store string in (not a byte pointer) ; ; Return: ; RET ;ADDRESS FAILURE ; RETSKP ;SUCCESS, T1/ BYTE COUNT ; ; Uses: T1-T4 GETSTR: MOVEI T3,SB.MAX ;DEFAULT MAXIMUM LENGTH OF STRING GETST1: SAVEAC ;GET A COPY OF M AND SAVE TWO PS SKIPN M,T1 ;SET UP TO SCGWRD FROM HERE RETSKP ;DON'T DO ANYTHING IF NO POINTER GIVEN MOVE P2,T2 ;SAVE THE INTERNAL SBLOCK POINTER CALL SCGWRD ;GET THE COUNT RET ;ADDRESS ERROR, CALLER WILL DEAL W/ IT HRRE W,T1 ;TELL SCGWR1 LENGTH OF ARG BLOCK HLRZS T1 ;ISOLATE BYTE COUNT IN RIGHT HALF JUMPE T1,RSKP ;LEAVE NOW IF NOTHING TO DO CAMLE T1,T3 ;WILL THIS FIT IN A STRING BLOCK? RET ;NO, ADDRESS ERROR SAVEAC T1 ;RETURN BYTE COUNT ON EXIT MOVEI P1,3(T1) ;SET TO ROUND UP ON DIVIDE ASH P1,-2 ;CHANGE BYTE COUNT TO WORD COUNT GETS.1: CALL SCGWR1 ;GET NEXT WORD FROM USER'S STR BLK RET ;CALLER WILL HANDLE ADDRESS CHECK MOVEM T1,(P2) ;STORE IN MONITOR BUFFER AOJ P2, ;WALK UP THE MONITOR BUFFER SOJG P1,GETS.1 ;LOOP OVER ALL WORDS SPECIFIED RETSKP ;SUCCESS RETURN, SEE SAVEAC T1 ABOVE SUBTTL Subroutines -- GETSXR - Get string block to sixbit word ;GETSXR - Transfer user's string block to internal sixbit word ; ; Call: ; T1/ Pointer to the user's string block ; ; Return: ; T1/ SIXBIT word (usually node name) ; ; Uses: ; T1-T4 GETSXR: SAVEAC ;WE USE A BUNCH OF ACS SKIPN M,T1 ;PUT POINTER WHERE SCGWRD CAN FIND IT RETSKP ;IF NO POINTER, SIMPLY RETURN. CALL SCGWRD ;GET STRING BLOCK HEADER RET ;FAIL HRRE W,T1 ;LENGTH OF STRING BLOCK IN WORDS. HLRZ P1,T1 ;NUMBER OF BYTES TO FETCH CAILE P1,6 ;WILL NAME FIT IN A SIXBIT WORD RET ;NO. SETZ P2, ;CLEAR DESTINATION WORD MOVE F,[POINT 6,P2] ;BYTE POINTER TO SAVE SIXBIT BYTES GETSX1: JUMPLE P1,GETSX9 ;IF NO MORE BYTES TO DO, EXIT CALL SCGWR1 ;MORE BYTES TO DO, GET A WORD TO PROCESS RET ;FAIL MOVE T4,[POINT 8,T1] ;BYTE POINTER INTO SOURCE STRING MOVEI T3,4 ;MAX NUMBER OF BYTES IN A WORD CAMLE T3,P1 ;ARE THAT MANY BYTES LEFT? MOVE T3,P1 ;NO, TAKE THE NUMBER THAT ARE LEFT SUB P1,T3 ;DECREMENT NUMBER OF BYTES LEFT GETSX2: ILDB T2,T4 ;GET A BYTE CAILE T2,^O140 ;IS IT LOWER CASE? SUBI T2,^O40 ;YES, MAKE IT UPPER CASE SUBI T2,^O40 ;MAKE IT SIXBIT IDPB T2,F ;SAVE IN DESTINATION WORD SOJG T3,GETSX2 ;AND LOOP FOR ANOTHER BYTE JRST GETSX1 ;AND LOOP FOR ANOTHER WORD GETSX9: MOVE T1,P2 ;SIXBIT WORD. RETSKP ;RETURN SUCCESS SUBTTL Subroutines -- PUTPRO - Write Process Block to User's Space ;PUTPRO - Write Process Block to User's Space ; ; Call: ; T2/ Pointer to the Process Block portion of the CBLOCK ; M/ Pointer to the next argument in the CBLOCK ; W/ Remaining Length of block M points at ; ; Return: ; RET ;ON ERROR, CODE IN T1 ; RETSKP ;ALL IS OK ; ; Uses: T1-T4 PUTPR1: ADDI M,1 ;INCR FIRST, LIKE SCGWR1,SCPWR1, ETC SOJLE W,RSKP ;LEAVE IF NO ADDRESS SUPPLIED PUTPRO: SAVEAC MOVE P2,T2 ;SAVE THE POINTER TO PROCESS BLOCK CALL SCGWRD ;GET THE NEXT ARG POINTER FROM CBLOCK SCERR %NEADE,RTN,
MOVE M,T1 ;SET UP THE POINTER TO PBLOCK CALL SCGWRD ;GET THE USER'S LENGTH WORD SCERR %NEADE,RTN,
HRRZ W,T1 ;SAVE LENGTH IN WORDS ;FORMAT TYPE LOAD T1,PBFOR,(P2) ;GET THE FORMAT TYPE CALL SCPWR1 ;PLACE THIS WORD AFTER COUNT WORD SCERR %NEADE,RTN,
LOAD T1,PBOBJ,(P2) ;GET THE OBJECT TYPE ;OBJECT TYPE CALL SCPWR1 ;PLACE THE OBJECT TYPE IN USER SPACE SCERR %NEADE,RTN,
;TASK NAME IFN ,> MOVE T1,PB.USR(P2) ;PBUSR AND PBGRP ARE CHECK TO BE THE SAME CALL SCPWR1 ;STORE PPN (USER AND GROUP) SCERR %NEADE,RTN,
LOAD T1,PBNCT,(P2) ;GET THE BYTE COUNT XMOVEI T2,PB.NAM(P2) ;POINT TO THE STRING CALL PUTST1 ;PLACE IT BACK IN USER'S SPACE RET ;BUG. ALREADY GIVEN FOR ADDRESS ERROR RETSKP ;ALL IS OK SUBTTL Subroutines -- PUTSTR - Write String Block to User's Space ;PUTSTR - Write String Block to User's Space ; ; Call: ; T1/ Byte Count of String ; T2/ Pointer (not a byte pointer) to String ; M/ Pointer to Pointer to User's String Block ; W/ Remaining Length of block M points at ; ; Return: ; RET ;ON ADDRESS ERROR, CALLER TO HANDLE IT ; RETSKP ;ON SUCCESS ; ; Uses: T1-T4 PUTST1: ADDI M,1 ;STR BLK POINTER IS IN NEXT USER WORD SOJLE W,RSKP ;LEAVE IF NO ADDRESS SUPPLIED PUTSTR: SAVEAC DMOVE P1,T1 ;SAVE BYTE COUNT,BYTE POINTER CALL SCGWRD ;GET PTR TO STRING BLOCK SCERR %NEADE,RTN,
SKIPN M,T1 ;GET OUR M SET UP RETSKP ;OOPS, COPIED NOTHING ;There should be a count in the first word of the string block ;indicating the maximum count of bytes to place in the string. CALL SCGWRD ;GET THE COUNT WORD SCERR %NEADE,RTN,
HRRZ W,T1 ;TELL SCPWR1 ABOUT THE LENGTH HRRZ T3,T1 ;GET WORD COUNT AGAIN SOJLE T3,RSKP ;SUBTRACT ONE DUE TO LENGTH WORD ASH T3,2 ;MULT BY FOUR TO GET BYTE COUNT CAMLE P1,T3 ;THERE ENOUGH ROOM IN THE USER'S BLOCK? MOVE P1,T3 ;NO, USE HIS MAX HRL T1,P1 ;GET THE BYTE COUNT IN LEFT HALF ;WORD LENGTH STILL IN THE RIGHT HALF CALL SCPWRD ;PLACE IT IN THE COUNT WORD SCERR %NEADE,RTN,
ADDI P1,3 ;MAKE FOLLOWING DIVIDE ROUND UP ASH P1,-2 ;CONVERT BYTE COUNT TO WORD COUNT ;Note that we come all the way to here even if the byte count is zero ;because we have to put the count in the user's string block. PUTS.1: SOJL P1,RSKP ;SUCCESS WHEN WE'VE COPIED ALL THERE IS MOVE T1,(P2) ;GET NEXT WORD FROM MONITOR BUFFER CALL SCPWR1 ;PUT IT IN NEXT WORD OF USER'S STR BLK SCERR %NEADE,RTN,
AOJA P2,PUTS.1 ;POINT TO NEXT SOURCE WORD AND TRY IT SUBTTL Subroutines -- PUTSTR - Write SIXBIT word to user's String Block ;PUTSXR - Write SIXBIT word into String block in user space ; ; Call: ; T1/ SIXBIT word (usually node name) ; M/ Pointer to Pointer to User's Arg Block ; W/ Remaining Length of block M points at ; ; Return: ; RET ;ON ADDRESS ERROR, CALLER TO HANDLE IT ; ; Uses T1-T4 ; PUTSX1: ADDI M,1 ;POINT TO NEXT LOCATION IN ARG BLOCK SOJLE W,RSKP ;IF NOT IN BLOCK, JUST RETURN PUTSXR: SAVEAC ;SOME ACS WE USE MOVE P1,T1 ;SAVE SIXBIT WORD CALL SCGWRD ;GET THE ENTRY FOR THIS STRING BLOCK SCERR %NEADE,RTN,
SKIPN M,T1 ;MAKE SURE WE GOT SOMETHING RETSKP ;USER DOESN'T WANT THE NODE NAME CALL SCGWRD ;GET THE STRING BLOCK HEADER WORD SCERR %NEADE,RTN,
HRRZ W,T1 ;NUMBER OF WORDS IN STRING BLOCK ;COUNT THE CHARACTERS IN SIXBIT WORD MOVSI T2,770000 ;MASK FOR SIXBIT CHARACTER TDZA P2,P2 ;START OFF COUNT AT ZERO BYTES PUTSX2: LSH T2,-6 ;SHIFT MASK BY ONE CHARACTER TDNE T2,P1 ;DO WE HAVE A CHARACTER IN THIS POSITION? AOJA P2,PUTSX2 ;YES, COUNT IT AND TRY FOR NEXT CHARACTER HRL T1,P2 ;RETURN THE NUMBER OF BYTES WE ARE GIVING CALL SCPWRD ; IN THE HEADER WORD OF THE STRING BLOCK SCERR %NEADE,RTN,
MOVE F,[POINT 6,P1] ;BYTE POINTER TO SIXBIT WORD PUTSX3: JUMPE P2,RSKP ;RETURN MOVE T4,[POINT 8,T1] ;BYTE POINTER TO EIGHTBIT DESTINATION WORD SETZ T1, ;CLEAR DESTINATION WORD MOVEI T3,4 ;NUMBER OF BYTES WHICH WILL FIT IN FIRST WORD CAMLE T3,P2 ;GREATER THAN AVAILABLE BYTES? MOVE T3,P2 ;YES, SET TO LOWER LIMIT SUB P2,T3 ;DECRMENT NUMBER OF BYTES USED PUTSX4: ILDB T2,F ;GET A BYTE FROM SIXBIT WORD ADDI T2,^O40 ;MAKE IT ASCII IDPB T2,T4 ;STORE IT IN DESTINATION WORD SOJG T3,PUTSX4 ;LOOP FOR MORE CHARACTERS CALL SCPWR1 ;COPY THE WORD TO USER'S BLOCK SCERR %NEADE,RTN,
JRST PUTSX3 ;AND LOOP ON ANOTHER WORD U=:SJ ;WE USE U AS AN AC BELOW PURGE SJ ;WE DON'T USE SJ ANY MORE SUBTTL DNET. UUO -- Argument block ;FLAGS WORD AT BEGINNING OF EACH ARGUMENT BLOCK BEGSTR FL FIELD FLA,6 ;FLAGS FIELD - 6 BITS BIT FLS ; STEP BIT FLK ; KNOWN BIT FLR ; ACTIVE (REACHABLE) BIT FLE ; EXECUTOR FILLER 6 ;RESERVED FIELD FNC,6 ;FUNCTION CODE XP .DNLNN,1 ;LIST NODE NAMES XP .DNNDI,2 ;RETURN NODE INFO XP .DNSLS,3 ;SHOW LINKS STATUS HWORD ARG ;LENGTH OF ARGUMENT BLOCK ENDSTR ;WORDS IN FUNCTION .DNNDI - BEGSTR D1 ;ROUTER INFO, WORD .DNRTR FIELD RCH,1 ;REACHABILITY FILLER 9 ;RESERVED FIELD HOP,8 ;HOPS TO NODE FILLER 2 ;RESERVED FIELD CST,16 ;COST TO NODE ENDSTR BEGSTR D2 ;LLINKS INFO, WORD .DNLLI FIELD VLD,1 ;VALIDITY BIT FILLER 8 ;RESERVED FIELD LNK,9 ;ACTIVE LINKS HWORD DLY ;MILLISECONDS DELAY ENDSTR BEGSTR DS ;.DNSLS ARGUMENT BLOCK ; WORD FLA ;FLAGS, DESCRIBED ABOVE ; ; HWORD JOB ;JOB WHICH CHANNEL BELONGS TO ; HWORD CHN ;CHANNEL WORD NOD ;NODE NAME FOR CONNECT. HWORD DOB ;DESTINATION OBJECT TYPE HWORD SOB ;SOURCE OBJECT TYPE HWORD LSW ;LINK STATUS WORD HWORD STA ;SIXBIT STATE HWORD IQT ;INPUT QUOTA HWORD OQT ;OUTPUT QUOTA WORD SEG ;SEGMENT SIZE HWORD XMF ;XMIT FLOW CONTROL HWORD RCF ;RECV FLOW CONTROL HWORD MRC ;MESSAGES RECEIVED HWORD MXM ;MESSAGES TRANSMITTED WORD MPR ;MONITOR PROCESS WORD ENDSTR SUBTTL DNET. UUO -- Errors DEFINE DNERR(TXT,LONG),< JRST [ MOVX T1,DN'TXT'% RET] > ;Error codes. XP DNADE%,1 ;Address error XP DNWNA%,2 ;Wrong number of arguments XP DNIJN%,3 ;Illegal job number XP DNFNE%,4 ;Illegal function number XP DNILF%,5 ;Illegal flag set XP DNNSN%,6 ;No such node name XP DNNSC%,7 ;No such channel XP DNNDA%,10 ;Node is in different area SUBTTL DNET. UUO -- Processor ;DNET - Main entry from UUOCON ;Call ; From UUOCON, ; T1/ Contents of AC ; M/ MUUO as executed ;Return ; RET ;On failure, error code stored in user's AC ; RETSKP ;on success ; ;Note that this code runs in section one, since most of DECnet-36's ;data base is in extended sections. There are a number of places we ;call routines which must run in section zero; Be careful when modifying ;code here. INTERNAL DNET XRENT DNET IFE FTXMON, ;SWITCH TO DECNET CONTEXT CALL DNETCM ;CALL PROCESSOR (KLUDGE FOR SAVEAC) JRST [MCALL (RG,MCSEC0,STOTAC##) ;STORE ERROR CODE IN USER'S AC RET] RETSKP ;SUCCESS DNETCM: SAVEAC ;PRESERVE ALL ACS HRR M,T1 ;SET UP POINTER TO UUO ARGUMENT BLOCK MCALL (RG,MSEC1,GETWRD##) ;GET FIRST WORD OF ARGUMENT BLOCK DNERR ADE,
MOVE P1,T1 ;SAVE THIS WORD FOR POSTERITY LOAD T1,FLARG,+P1 ;GET THE LENGTH OF THE ARGUMENT BLOCK SOSG W,T1 ;SET UP W WITH NUMBER OF WORDS LEFT IN BLOCK DNERR WNA, ;WE'VE USED UP ONE ALREADY. LOAD T1,FLFNC,+P1 ;GET THE FUNCTION CODE CAXL T1,.DNLNN ;RANGE CAXLE T1,.DNSLS ; CHECK DNERR FNE, JRST @.+1-.DNLNN(T1) ;DISPATCH ON FUNCTION IFIW DNULNN ;.DNLNN IFIW DNUNDI ;.DNNDI IFIW DNUSLS ;.DNSLS SUBTTL DNET. uuo -- .DNLNN - List node names ;DNULNN - Return list of node names ;Call ; M/ Pointer to uuo argument block ; W/ Count of words left in block ; P1/Flags word of argument block ;Return ; RET ;On failure, T1 contains error code ; RETSKP ;On success ; DNULNN: SAVEAC ;SAVE ACS LOAD T1,FLFLA,+P1 ;GET FLAGS FOR FUNCTION TXNE T1, ;MAKE SURE ONE OF THESE IS LIT TXNE T1,^- ;AND MAKE SURE NOTHING ELSE IS DNERR ILF, TXNE T1,FL%FLE ;LIMITED TO EXECUTOR? MOVX P2,<1B1> ;YES, SET FLAG FOR LOCAL [RNLCL] TXNE T1,FL%FLR ;LIMITED TO ACTIVE (REACHABLE)? MOVX P2,<1B0> ;YES, SET FLAG FOR REACHABLE [RNRCH] TXNE T1,FL%FLK ;LIMITED TO KNOWN? MOVX P2,-1 ;YES, MAKE SURE NON-ZERO WORD. SETZ T1, ;CLEAN CALL DNPNWR ;STORE A ZERO IN .DNCNT TEMPORARILY DNERR WNA, MOVE P4,M ;SAVE POINTER TO .DNCNT WORD SETZ P3, ;START AT NODE 0. (HOME AREA) DNULN3: AOS T2,P3 ;BUMP NODE NUMBER ADD T2,RTRNRV## ;POINT TO WORD IN ROUTER VECTOR TDNN P2,(T2) ;TEST ROUTER FLAGS FOR APPLICABILITY JRST DNULN9 ;NOT APPLICABLE TO US, STEP TO NEXT MOVE T1,P3 ;GET NODE NUMBER CALL SCTA2N ;CONVERT NODE NUMBER INTO NODE NAME SKIPA ;NO NAME, TEST IF REACHABLE JRST DNULN8 ;HAVE NAME, GO STORE IN ARG BLOCK MOVE T2,P3 ;GET NODE NUMBER AGAIN ADD T2,RTRNRV## ;POINT TO WORD IN ROUTER VECTOR SKIPL (T2) ;IF [RNRCH] IS SET, NODE IS "ACTIVE" JRST DNULN9 ;NO - IGNORE THIS NODE MOVE T1,P3 ;COPY NODE NUMBER IN PLACE OF NAME MOVE T2,RTRHOM ;INCLUDE HOME AREA DPB T2,[POINTR (T1,RN%ARE)] ;... DNULN8: CALL DNPNWR ;PUT THIS NAME ON LIST RETURNED TRN ;IGNORE FAILURE - WE STILL WANT TO COUNT DNULN9: CAMG P3,RTRMXN## ;WILL WE REACH MAXIMUM NODE NUMBER? JRST DNULN3 ;NO, LOOP AND GET NEXT SUB M,P4 ;NUMBER OF NODE NAMES WE PUT AWAY. UMOVEM M,0(P4) ;STORE NUMBER OF NODES IN ARG BLOCK. RETSKP ;AND RETURN HAPPILY. SUBTTL DNET. uuo -- .DNNDI - Return node info ;DNUNDI - Return detailed info about a node ;Call ; M/ Pointer to uuo argument block ; W/ Count of words left in block ; P1/Flags word of argument block ;Return ; RET ;On failure, T1 contains error code ; RETSKP ;On success ; DNUNDI: SAVEAC ;SAVE ACS LOAD T1,FLFLA,+P1 ;GET FLAGS TXNE T1,FL%FLS ;IS STEP SET? TXNE T1, ;YES, MAKE SURE AT LEAST ONE QUALIFIER TXNE T1,^- ;MAKE SURE NO EXTRANEOUS BITS DNERR ILF, CALL DNGNWR ;GET THE NODE NAME DNERR WNA, TXNE P1,FLFLS ;STEP SET? JUMPE T1,DNUND2 ;IF SO AND NODE NAME 0, SKIP CONVERSION TLNN T1,-1 ;ANYTHING IN LEFT HALF? JRST DNUND1 ;IF NOT, MUST BE AN ADDRESS CALL SCTN2A## ;CONVERT NAME TO ADDRESS DNERR NSN, DNUND1: LDB T2,[POINTR(T1,RN%ARE)] ;GET AREA NUMBER SKIPE T2 ;DEFAULT TO OUR AREA? CAMN T2,RTRHOM## ;OR SPECIFYING OUR HOME AREA? SKIPA ;YES, ALL OK DNERR NDA, ANDX T1,RN%NOD ;MASK TO JUST NODE WITHIN AREA CAMLE T1,RTRMXN ;CHECK FOR OUT OF RANGE DNERR NSN, DNUND2: MOVE P2,T1 ;SAVE NODE NUMBER SOMEWHERE SAFE TXNN P1,FLFLS ;STEP SET? JRST DNUND4 ;NO, SKIP STEP CODE TXNE P1,FLFLE ;LIMITED TO EXECUTOR? MOVX T3,<1B1> ;YES, SET FLAG FOR LOCAL [RNLCL] TXNE P1,FLFLR ;LIMITED TO ACTIVE (REACHABLE)? MOVX T3,<1B0> ;YES, SET FLAG FOR REACHABLE [RNRCH] TXNE P1,FLFLK ;LIMITED TO KNOWN? MOVX T3,-1 ;YES, MAKE SURE NON-ZERO WORD. DNUND3: AOS T2,P2 ;BUMP NODE NUMBER CAMLE T2,RTRMXN## ;BEYOND MAXIMUM NODE NUMBER? JRST [ SETZ T1, ;NODE NAME OF ZERO MCALL (RG,MSEC1,PUTWRD##) ;STORE WORD DNERR ADE,
RETSKP] ;AND RETURN ADD T2,RTRNRV## ;POINT TO ENTRY IN ROUTER VECTOR TDNN T3,(T2) ;TEST FOR OUT CONDITION JRST DNUND3 ;NOT GOOD, TRY FOR ANOTHER DNUND4: MOVE T1,RTRHOM ;SET UP CORRECT AREA NUMBER DPB T1,[POINTR (P2,RN%ARE)] ;... MOVE T1,P2 ;GET NODE NUMBER CALL SCTA2N ;CONVERT NODE NUMBER INTO NODE NAME MOVE T1,P2 ;USE NODE NUMBER IF NO NODE NAME MCALL (RG,MSEC1,PUTWRD##) ;STORE NODE NAME BACK IN ARG BLOCK DNERR ADE,
MOVE T2,P2 ;COPY NODE ADDRESS ANDX T2,RN%NOD ;MASK TO JUST NODE NUMBER WITHIN AREA ;.DNRTR SETZ T1, ;CLEAR DESTINATION WORD ADD T2,RTRNRV## ;POINT TO ROUTER WORD LDB T3,RTNRCH## ;GET REACHABILITY OF THIS NODE STOR T3,D1RCH,+T1 ;SET THE REACHABILITY BIT LDB T3,RTNHOP## ;GET NUMBER OF HOPS STOR T3,D1HOP,+T1 ;STORE HOPS LDB T3,RTNCST## ;GET COST TO NODE STOR T3,D1CST,+T1 ;STORE COST CALL DNPNWR ;STORE THIS IN USER'S ARGUMENT BLOCK RETSKP ;MUST BE DONE, EXIT SUCCESSFULLY ;.DNLLI SETZ U, ;CLEAR DESTINATION WORD MOVE T1,P2 ;SET UP NODE NUMBER FOR SRHNOD CALL SRHNOD## ;SEARCH FOR THE LLINKS NODE DATABASE JRST DNUND5 ;NO LLINKS DATABASE FOR NODE, SKIP THIS LOAD T3,NNDLY,(T1) ;GET THE DELAY STOR T3,D2DLY,+U ;SAVE IN DESTINATION WORD LOAD T3,NNLKC,(T1) ;GET THE NUMBER OF LINKS TO NODE STOR T3,D2LNK,+U ;SAVE... TQO D2VLD,+U ;INDICATE VALID INFORMATION DNUND5: MOVE T1,U ;GET WORD TO STORE CALL DNPNWR ;PUT THIS WORD IN USERS ARG BLOCK RETSKP ;END OF ARG BLOCK, RETURN ;.DNADR MOVE T1,P2 ;COPY NODE ADDRESS CALL DNPNWR ;STORE ADDRESS RETSKP ;IF WON'T FIT, FINISHED. ;.DNCKT MOVE T2,P2 ;GET NODE NUMBER ANDX T2,RN%NOD ;MASK TO JUST NODE NUMBER WITHIN AREA ADD T2,RTRNRV## ;POINT TO WORD IN NORMAL ROUTING VECTOR LDB T3,RTNRCH## ;GET THE REACHABILITY BIT LDB T1,RTNLCL## ;GET THE LOCAL BIT ANDCM T3,T1 ;TRUTH TABLE JUMPE T3,[ SKIPE T1 ;WAS IT LOCAL? MOVE T1,[ASCII \local\] ;YES CALL DNPNWR ;STORE INFO IN ARG BLOCK RETSKP ;END OF ARG BLOCK, FINIT. JRST DNUND8] ;AND CLEAN UP. MOVE T1,P2 ;GET NODE NUMBER CALL RTNLID## ;GET LINE ID OF ROUTE TO NODE JRST DNUND8 ;NO LINE ID? OH WELL STKVAR <> ;TEMPORARY AREA FOR CIRCUIT NAME MOVEI T2,TXTBUF ;MAKE A LOCAL POINTER TO TXTBUF HRLI T2,(POINT 8,) ;BYTE POINTER TO BUFFER IFN <!>, CALL [SAVEAC ;TRASHED BY NTMAN CALLRET NMXC2N##] ;CONVERT LINE ID TO NAME RET ;SOMETHING WRONG. NMXC2N BUGCHKED MOVE P1,[POINT 8,TXTBUF];(OK TO TRASH P1 NOW - DON'T NEED FLAGS) ILDB F,P1 ;GET NUMBER OF BYTES SETZ U, ;CLEAR TEMPORARY FOR DNPNAB DNUND7: ILDB T1,P1 ;GET A BYTE OF TEXT CALL DNPNAB ;PUT IT INTO USER STREAM RETSKP ;END OF ARG BLOCK, EXIT SOJG F,DNUND7 ;AND LOOP CALL DNPNAC ;TERMINATE STRING RETSKP ;END OF ARG BLOCK, RETURN ENDSV. ;END STKVAR DNUND8: SETZ T1, ;ZERO CALL DNPNWR ;STORE IN USER AREA RETSKP ;RETURN RETSKP ;ALSO RETURN SUBTTL DNET. uuo -- .DNSLS - Show link status ;DNUSLS - Show status about a link ;Call ; M/ Pointer to uuo argument block ; W/ Count of words left in block ; P1/Flags word of argument block ;Return ; RET ;On failure, T1 contains error code ; RETSKP ;On success ; DNUSLS: SAVEAC ;STORAGE LOAD T1,FLFLA,+P1 ;GET FLAGS FIELD TXNE T1,^-FL%FLS ;MAKE SURE NO EXTRANEOUS BITS SET DNERR ILF, CALL DNGNWR ;GET THE JOB/CHANNEL WORD DNERR WNA, MOVE P2,T1 ;SAVE WORD IN SAFE PLACE STKVAR <> ;GET US SOME STORAGE CALL GETCHN ;GET THE CHANNEL NUMBER DNERR NSC, ;Give error return JUMPE P2,DNUSL7 ;IF CHANNEL&JOB 0, WE HAVE FINISHED LOAD T1,SLPKS,(T2) ;#GET NUMBER OF MESSAGES SENT LOAD T3,SLPKR,(T2) ;#NUMBER OF MESSAGES RECEIVED HRL T3,T1 ;#MAKE AN XWD OF TWO FIELDS DNUSL4: MOVEM T3,DS.MRC+DSARG ;#SAVE IN ARG BLOCK D36ON ;#ALLOW INTERUPTS AGAIN. ;NOTE - The SLB is now unsafe. It can be trashed while we are looking at it. ; This is unimportant in the normal case, but if there are any pointers ; to be traced, they MUST be traced under D36OFF, above. LOAD T1,SLDNA,(T2) ;GET THE NODE NUMBER STOR T1,DSNOD,+DSARG ;STORE FOR LATER USE IFN !, MOVE T1,SL.SOB(T2) ;GET OBJECT TYPES MOVEM T1,DS.SOB+DSARG ;STORE IN OUR ARG BLOCK LOAD T1,SLINQ,(T2) ;GET INPUT QUOTA STOR T1,DSIQT,+DSARG ;STORE IN ARG BLOCK LOAD T1,SLOTQ,(T2) ;GET OUTPUT QUOTA STOR T1,DSOQT,+DSARG ;STORE LOAD T1,SLSIZ,(T2) ;GET SEGMENT SIZE STOR T1,DSSEG,+DSARG ;STORE IN ARGUMENT BLOCK LOAD T1,SLSST,(T2) ;GET SLB FLAGS (BINARY STATE) LOAD T3,SLSTA,(T2) ;GET STATE ORDINAL HLL T1,STASIX-1(T3) ;GET SIXBIT STATE INTO LEFT HALF MOVSM T1,DS.STA+DSARG ;STORE IN OUR ARG BLOCK CAXN T2,.NSSCW ;CONNECT WAIT? JRST [ SETZM DS.XMF+DSARG ;YES, DON'T RETURN FLOW CONTROL JRST DNUSL3] ;AND CONTINUE AFTER LOAD T1,SLXFL,(T2) ;GET TRANSMIT FLOW CONTROL ADDI T1,1 ;OFFSET STOR T1,DSXMF,+DSARG ;STORE LOAD T1,SLRFL,(T2) ;GET RECEIVE FLOW CONTROL ADDI T1,1 ;OFFSET STOR T1,DSRCF,+DSARG ; DNUSL3: SETZ U, ;DON'T NEED THIS ANY MORE. SKIPL P2 ;IS THIS A MONITOR JOB (I.E., NRTSER) JRST DNUSL5 ; HRRZ U,P2 ;COPY CHANNEL NUMBER XCALL (MSEC1,NRTLFC##) ;ASK NRTSER FOR THE TTY NUMBER DNUSL5: STOR U,DSMPR,+DSARG ;NRTLFC RETURNS WORD IN U SKIPE T1,DS.NOD+DSARG ;GET NODE NUMBER CALL SCTA2N## ;CONVERT TO NODE NAME TRNA ;IF THIS HAPPENS, LEAVE NODE NUMBER THERE MOVEM T1,DS.NOD+DSARG ;STORE NODE NAME BACK IN ARG BLOCK MOVE T1,P2 ;GET CURRENT JOB/CHANNEL MCALL (RG,MSEC1,PUTWRD##) ;STORE IT IN USER SPACE DNERR ADE,
MOVE T1,DS.NOD+DSARG ;GET NODE NAME CALL DNPNWR ;STORE IT IN USER BLOCK RETSKP MOVE T1,DS.SOB+DSARG ;GET OBJECT TYPES CALL DNPNWR ;STORE IN USER BLOCK RETSKP MOVE T1,DS.LSW+DSARG ;GET STATUS CALL DNPNWR ;STORE IN USER BLOCK RETSKP MOVE T1,DS.IQT+DSARG ;QUOTAS CALL DNPNWR ;STORE RETSKP MOVE T1,DS.SEG+DSARG ;SEGMENT SIZE CALL DNPNWR ;STORE RETSKP MOVE T1,DS.XMF+DSARG ;FLOW CONTROLS CALL DNPNWR ;STORE RETSKP MOVE T1,DS.MRC+DSARG ;MESSAGES CALL DNPNWR ;STORE RETSKP MOVE T1,DS.MPR+DSARG ;MONITOR PROCESS WORD CALL DNPNWR ;STORE RETSKP RETSKP DNUSL7: SETZ T1, ;CLEAR MCALL (RG,MSEC1,PUTWRD##) ;INDICATE END OF LIST DNERR ADE,
RETSKP ;AND SAY WE DIDN'T FAIL ;GETCHN - Get channel number to talk about. ; ;Call ; P1/ Flags word ; P2/ Job,,channel ;Return ; Ret, no can do. ; RETSKP, success, ; if wrapped, P2/ 0 ; else, D36OFF and ; P2/ Job,,channel as determined ; U/ SJB ; T2/ SLB GETCHN: SAVEAC ;WE USE THESE TXNE P1,FLFLS ;DO WE STEP? ADDI P2,1 ;YES, SKIP PAST CURRENT SLB HLRZ J,P2 ;EXTRACT JOB NUMBER ;GET SJB POINTER GETCH1: CAIN J,-1 ;WAS THIS NRTSER? JRST [ SKIPE U,NRTSJP## ;YES, GET POINTER TO NRT'S SJB JRST GETCH5 ;AND JOIN COMMON CODE LATER JRST GETCH2] ;NO SJB, INCREMENT JOB SKIPE J ;ZERO JOB? CAILE J,JOBMAX## ;WITHIN LIMITS? JRST GETCH2 ;NO, GO TO INCREMENT LOGIC DIRECTLY MCALL (RG,MSEC1,FNDPDB##) ;GET POINTER TO THE PDB JRST GETCH2 ;NO PDB, INCREMENT JOB SKIPE U,.PDSJB(W) ;GET POINTER TO SJB JRST GETCH5 ;HAVE POINTER TO SJB, JOIN COMMON CODE GETCH2: TXNN P1,FLFLS ;DO WE HAVE STEP SET? RET ;NO, WE FAIL SETZ P2, ;CLEAR CHANNEL NUMBER MOVEI J,1(J) ;BUMP THE JOB NUMBER (18 BIT INCREMENT) CAILE J,JOBMAX## ;JOB NUMBER IN RANGE JRST [ MOVEI J,-1 ;NO, SET UP FOR NRTSER JRST GETCH1] ;AND GO THROUGH THE LOOP AGAIN JUMPN J,GETCH1 ;IF JOB NUMBER POSITIVE, LOOP RETSKP ;WRAPPED ALL THE WAY AROUND, SUCCESS WITH 0 ;GET SLB POINTER GETCH5: HRL P2,J ;COPY JOB BACK INTO LOOP POINTER D36OFF ;#TO TOUCH SLB'S, MUST HAVE INTERLOCK LOAD T3,SJCHC,(U) ;#GET NUMBER OF CHANNEL SLOTS IN SJB LOAD T4,SJCHT,(U) ;#GET POINTER TO CHANNEL T4 TRNN P2,-1 ;#DO WE HAVE A CHANNEL NUMBER YET? JRST GETCH7 ;#NO, INCREMENT NOW GETCH6: CAIGE T3,(P2) ;#IS CHANNEL OUT OF RANGE? JRST [ D36ON ;#YES, INCREMENT JOB JRST GETCH2] ;AND TRY NEXT JOB MOVE T1,T4 ;#COPY POINTER TO TABLE ADDI T1,-1(P2) ;#ADD OFFSET TO CHANNEL POINTER SKIPE T2,(T1) ;#GET POINTER TO SLB JRST GETCH8 ;#GOT IT, EXIT GRACEFULLY GETCH7: TXNN P1,FLFLS ;#NO POINTER JRST GETCH9 ;#CAN'T STEP, SO RETURN ERROR HRRI P2,1(P2) ;#18 BIT INCREMENT JRST GETCH6 ;#AND TRY AGAIN GETCH8: LOAD T3,SLCHN,(T2) ;#GET CHANNEL NUMBER FROM SLB CAIE T3,(P2) ;#COMPARE TO CHANNEL WE THINK WE ARE USING BUG.(CHK,SCMBCN,SCMUUO,SOFT,,,< Cause: The channel number obtained from the SLB field SLCHN doesn't match the channel number we thought we were getting. This probably means that the interlocks aren't correctly arranged, and the SLB has changed out from under us. >,GETCH9) RETSKP ;#HAVE POINTERS, RETURN D36OFF GETCH9: D36ON ;#RELEASE INTERLOCK RET ;AND RETURN SUBTTL DNET. uuo -- Conversion from binary to sixbit state STASIX: SIXBIT |CW| ;CONNECT WAIT SIXBIT |CR| ;CONNECT RECEIVED SIXBIT |CS| ;CONNECT SENT SIXBIT |RJ| ;REMOTE REJECTED CONNECT INIT SIXBIT |RN| ;LINK IS UP AND RUNNING SIXBIT |DR| ;DISCONNECT RECEIVED SIXBIT |DS| ;DISCONNECT SENT SIXBIT |DC| ;DISCONNECT CONFIRMED SIXBIT |CF| ;NO CONFIDENCE SIXBIT |LK| ;NO LINK SIXBIT |CM| ;NO COMMUNICATION SIXBIT |NR| ;NO RESOURCES SUBTTL DNET. uuo -- Utility routines ;DNPNAB - Put next ascii byte ;Call ; W/ Number of words left in arg block ; M/ Pointer to word before word to deposit ; U/ Cummulative word ;Return ; RET on end of arg block ; RETSKP succes ; DNERR from calling routine on address error DNPNAB: ROT U,7 ;MAKE ROOM FOR ANOTHER BYTE IOR U,T1 ;OR IT IN TLNN U,(377B7) ;HAVE WE FILLED WORD? RETSKP ;NO, RETURN SUCCESS ROT U,1 ;YES, LEFT JUSTIFY MOVE T1,U ;PUT WORD INTO USEFULL PLACE SETZ U, ;AND CLEAR FOR NEXT SET OF WORDS CALLRET DNPNWR ;AND PUT THE WORD IN USER'S BUFFER. ;Terminate string (finish putting it into user space) DNPNAC: SKIPN T1,U ;PUT WORD WHERE WE CAN PLAY WITH IT CALLRET DNPNWR ;NOTHING THERE, JUST DEPOSIT A ZERO WORD LSH T1,1 ;LEFT JUSTIFY DNPNAD: LSH T1,7 ;MOVE NEXT BYTE INTO TOP TLNN T1,(377B6) ;ANYTHING THERE? JRST DNPNAD ;NOPE, KEEP TRYING ; ... ;FALL THROUGH. ;DNPNWR - Put next word ;Call ; W/ Number of words left in arg block ; M/ Pointer to word before word to store in ; T1/Word to store ;Return ; M incremented always (DNULNN depends on this) ; RET ;On end of arg block ; RETSKP ;success ; DNERR from calling routine on address error DNPNWR: HRRI M,1(M) ;18 BIT INCREMENT SOJL W,RTN ;RETURN IF RAN OUT OF ARG BLOCK MCALL (RG,MSEC1,PUTWRD##) ;STORE THE WORD TRNA ;ARGH. ERROR CONDITION, HANDLE IT. RETSKP ;SUCCESS ADJSP P,-1 ;BLOW AWAY CALL TO THIS ROUTINE. DNERR ADE,
;GIVE ADDRESS CHECK FROM CALLING ROUTINE ;DNGNWR - Get next word ;Call ; W/ Number of words left in arg block ; M/ Pointer to word before word to fetch ;Return ; RET ;on end of arg block ; RETSKP ;success ; DNERR from calling routine on address error DNGNWR: HRRI M,1(M) ;18 BIT INCREMENT SOJL W,RTN ;RETURN IF RAN OUT OF ARG BLOCK MCALL (RG,MSEC1,GETWRD##) ;GET THE WORD TRNA ;ERROR CONDITION, HANDLE IT. RETSKP ;SUCCESS ADJSP P,-1 ;BLOW AWAY CALL TO THIS ROUTINE DNERR ADE,
SUBTTL Impure Storage RESCD ;IMPURE STUFF SCUDFT:: REPEAT 0,> REPEAT 1,> XRESCD ;SO LITERALS ARE PURE SUBTTL End of SCMUUO .XCMSY RESDT SCULOW::! XRESCD END