TITLE CPNSER - SECOND PROCESSOR CONTROL V516 SUBTTL M. CHURCH - LNS/MIT P. HURLEY - DEC/JMF/TW/CDO/GMU/TARL 17-APR-90 SEARCH F,S,DEVPRM $RELOC $HIGH ;THIS SOFTWARE IS FURNISHED UNDER A LICENSE AND MAY BE USED ; OR COPIED ONLY IN ACCORDANCE WITH THE TERMS OF SUCH LICENSE. ; ;COPYRIGHT (c) DIGITAL EQUIPMENT CORPORATION ; 1973,1974,1975,1976,1977,1978,1979,1982,1984,1986,1988,1990. ;ALL RIGHTS RESERVED. .CPYRT<1973,1990> XP VCP1SR,516 ;VERSION NUMBER FOR LOADER STORAGE MAP CPNSER::ENTRY CPNSER ;LOAD IF SPECIFIED BY COMMON SUBTTL SCHEDULER ROUTINES ;ROUTINE TO SETUP THE SUBQUEUE SCHEDULING SCAN TABLE FOR CPU1 ; CALLED ONCE EVERY SCDINT TICKS BY SCHED1 SCDSS1::ILDB T1,SSPNT1## ;GET NEXT PRIMARY SUBQUEUE MOVEI T4,SSSCN1## ;ADDRESS OF SCHEDULING SCAN TABLE PJRST SCDSST## ;LET SCHED1 DO THE WORK ;SUBROUTINE TO INSURE THAT A JOB IS ON CPU0 ;CALLING SEQUENCE: ; PUSHJ P,ONCPU0 ;ALWAYS RETURNS CPOPJ ON CPU0 ONCPU0::PUSH P,T1 ;SAVE CALLERS T1 PUSH P,T2 ;SAVE ANOTHER MOVE T2,.CPJOB## ;GET CURRENT JOB MOVSI T1,(SP.ROP) ;RUN ONLY ON POLICY CPU IORM T1,JBTSPS##(T2) ;LIGHT FOR BECOM0 FIXUPS MOVE T1,BOOTCP## ;GET CURRENT POLICY CPU PUSHJ P,ONCPUN ;GET ON CORRECT CPU, NOT RUNNABLE ANYWHERE ELSE JRST TTPOPJ## ;RETURN WHEN ON CPUN ;ROUTINE TO GET ON CPU OWNING A TERMINAL ;U POINTS TO LDB ONCPUL::LDB T1,LDPCPU## ;GET THE NUMBER OF THE OWNING CPU CAIN T1,PCLCP0## ;GENERIC BOOT CPU? JRST ONCPU0 ;YES, HANDLE DIFFERENTLY PJRST ONCPUN ;NO, GET ON THAT CPU ;ROUTINE TO GET ON CPUN BUT FAIL IF CPU IS NOT RUNNING ;CALLED FROM UUO'S LIKE PERF. AND DTE. ; T1 = CPU NUMBER ; PUSHJ P,ONCPUS ; HERE IF CPU IS NOT RUNNING ( OR GOING AWAY ) ; HERE WHEN ON CPUN ONCPUS::CAIN T1,PCLCP0## ;BOOT CPU? JRST [AOS (P) ;YES, SUCCEED JRST ONCPU0] ;AND GET THERE CAIL T1,M.CPU## ;IN LEGAL RANGE? POPJ P, ;NO, FAIL PUSH P,T1 ;SAVE CPU NUMBER IMULI T1,.CPLEN## ;OFFSET FROM CPU0 CDB SKIPL .C0RUN##(T1) ;CPU MARKED TO GO AWAY SKIPLE .C0OK##(T1) ;OR ALREADY DEAD JRST TPOPJ## ;YES, FAIL RETURN POP P,T1 ;RESTORE CPU NUMBER AOS (P) ;GIVE GOOD RETURN ;FALL INTO ONCPUN ;CALLED TO REQUEUE CURRENT JOB TO CPUN (UUO LEVEL CALL ONLY) ;T1=NUMBER OF DESIRED CPU ONCPUN::CAIN T1,PCLCP0## ;BOOT CPU? JRST ONCPU0 ;YES, HANDLE DIFFERENTLY CAIL T1,M.CPU## ;NO, ARGUMENT IN LEGAL RANGE? STOPCD CPOPJ##,JOB,ONCPUX, ;++ OUT OF RANGE IN ONCPU PUSHJ P,SETCPN ;MAKE RUNNABLE ONLY ON THE RIGHT CPU CAMN T1,.CPCPN## ;ARE WE ON THE RIGHT CPU? POPJ P, ;YES, RETURN PUSHJ P,UUOLVL## ;CALLED AT INTERRUPT LEVEL? STOPCD .,STOP,ONCPUI ;++ONCPU CALLED AT INTERRUPT LEVEL PUSH P,.USMUO ;SAVE FLAGS PUSH P,.USMUP ;SAVE UUO PC MOVEM 17,.JDAT+JOBD17## ;SAVE ACS MOVEI 17,.JDAT+JOBDAC## BLT 17,.JDAT+JOBD16## MOVE J,.CPJOB## ;SET SO WILL RESCHEDULE TO RIGHT CPU LDB T1,[POINT 5,.USUPF,17] ;SET PCS TLO T1,(IC.UOU) ;LITE USRIOT XMOVEI T2,ONCPU1 DMOVEM T1,.CPPC## JRST CLKSPD## ;RESCHED TO RIGHT CPU ;HERE ON CPU N ONCPU1: POP P,.USMUP ;RESTORE UUO PC POP P,.USMUO ;AND FLAGS POPJ P, ;AND CONTINUE, ON CORRECT CPU SUBTTL MULTIPROCESSING I/O CONTROL ;SUBROUTINE TO CHECK IF ON THE RIGHT CPU FOR IO ;T1 RETURNS MASK OF WHICH CPU'S CAN DO THE IO ;PRESERVES T2,T3 CHKCPI::LDB T4,DEYCPF## ;GET NUMBER OF 1ST CPU OWNING DEVICE CAIE T4,CPFBIT## ;USE BIT MASK? JRST CHKCP2 ;NO, DO IT THE OLD WAY LDB T4,PDVTYP## ;GET DEVICE TYPE CAIN T4,.TYMTA ;MAGTAPE? PJRST TAPCPI## ;ASK TAPSER HRRZ T4,DEVUNI##(F) ;YES, MUST BE A DISK JUMPE T4,CHKCP7 MOVE T1,UDBCAM(T4) ;GET MASK FOR PRIME PORT IFN FTDUAL,< SKIPE T4,UNI2ND(T4) ;DUAL PORTED? IOR T1,UDBCAM(T4) ;YES, ADD MASK FOR SECOND PORT > CHKCP8: TDNE T1,.CPBIT## ;CAN THIS CPU DO IT? AOS (P) ;YES POPJ P, ;NO ;HERE IF DEVUNI IS ZERO (CAN HAPPEN IF ;CONCATENATING THE UFDS FROM SEVERAL STRS) CHKCP7: MOVEI T1,<1_M.CPU##>-1 ;LIE, SAY ALL CPUS JRST CPOPJ1## ;HERE FOR AN OLD STYLE DEVICE THAT DOES NOT HAVE A BIT MASK CHKCP2: CAIN T4,CPFBOO## ;DEVICE ON GENERIC BOOT CPU MOVE T4,BOOTCP## ;YES, GET CPU NUMBER MOVEI T1,1 ;BUILD A MASK LSH T1,(T4) REPEAT 0,< ;UNTIL WE GET ANOTHER DEVICE THAT LIGHTS DEPCPS MOVE T4,DEVCPU(F) ;DUAL PORTED DEVICE? TLNN T4,DEPCPS JRST CHKCP8 ;NO PUSH P,T3 ;YES, SAVE AN AC LDB T4,DEYCPS## ;GET 2ND CPU WHICH OWNS DEVICE MOVEI T3,1 ;BUILD A MASK LSH T3,(T4) OR T1,T3 ;BOTH MASKS TOGETHER POP P,T3 > ;END OF REPEAT 0 JRST CHKCP8 SETCPN::PUSHJ P,SAVE1## ;SAVE P1 PUSH P,J ;SAVE J MOVE J,.CPJOB## MOVEI P1,SP.CP0 ;RIGHTMOST BIT IS CPU0 (=1) LSH P1,(T1) ;POSITION BIT FOR RIGHT CPU TRC P1,SP.CPA ;NOT RUNNABLE FOR ALL OTHER CPUS DPB P1,MPYNRN## ;NOT RUNNABLE ON ALL BUT CPU N JRST JPOPJ## ;RETURN ;ROUTINE TO SEE IF ALL OF THE CPU'S ARE DEAD ;T1 PASSES BIT MASK FOR CPU'S TO BE TESTED (NOT PRESERVED) ;SKIP IF AT LEAST ONE CPU IS OK ;T1 RETURNS THE NUMBER OF THE CPU THAT IS KNOWN TO BE ALIVE CPUOK:: TDNE T1,.CPBIT## ;US? JRST [MOVE T1,.CPCPN## ;GET OUR CPU NUMBER JRST CPOPJ1##] ;RETURN WITH ANSWER IN T1 PUSH P,T2 ;SAVE T2 PUSH P,T3 ;SAVE T3 PUSH P,T4 ;SAVE T4 SETZ T3, ;WILL COUNT BITS SO FAR CPUOK1: JFFO T1,CPUOK2 ;FIND A BIT JRST CPUOK3 ;NONE LEFT, ALL DEAD CPUOK2: LSH T1,1(T2) ;SHIFT PAST THAT BIT ADDI T3,1(T2) ;COUNT BITS THAT WERE SHIFTED MOVEI T4,^D36 ;FIND THAT CDB SUB T4,T3 IMULI T4,.CPLEN## SKIPL .C0OK##(T4) ;IS CPU OK? JRST CPUOK1 ;NO, KEEP LOOKING MOVE T1,.C0CPN##(T4) ;GET CPU NUMBER AOS -3(P) ;SKIP CPUOK3: POP P,T4 ;RESTORE T4 POP P,T3 ;RESTORE T3 POP P,T2 ;RESTORE T2 POPJ P, ;RETURN WITH ANSWER IN T1 ;ROUTINE TO CONVERT A BIT MASK INTO A CPU NUMBER ;THIS ROUTINE WILL CHOOSE A RUNNING CPU IF POSSIBLE ;T1 PASSES BIT MASK ;T1 RETURNS THE NUMBER OF THE CPU ;ALWAYS RETURNS CPOPJ CAMCPU::PUSH P,T1 ;SAVE MASK PUSHJ P,CPUOK ;TRY TO FIND A LIVE CPU JRST CAMCP0 ;ALL DEAD POP P,(P) ;PHASE STACK POPJ P, ;RETURN WITH CPU NUMBER IN T1 CAMCP0: MOVE T1,T2 ;COPY T2 EXCH T1,(P) ;SAVE AC AND GET MASK BACK JFFO T1,CAMCP1 ;FIND A BIT SKIPA T2,.CPCPN## ;NONE AT ALL, TELL HIM THIS CPU CAMCP1: SUBI T2,^D35 ;CONVERT BIT NUMBER TO CPU NUMBER MOVM T1,T2 ; JRST T2POPJ## ;RESTORE T2 AND RETURN W/ANSWER IN T1 ;ROUTINE TO BUILD A COMBINED BIT MASK FOR A DUAL PORTED DRIVE ;T1 RETURNS THE MASK GETCAM::MOVE T1,UDBCAM(U) ;1ST MASK IFN FTDUAL,< SKIPE T2,UNI2ND(U) ;2ND UDB IOR T1,UDBCAM(T2) ;2ND MASK > POPJ P, ;ROUTINES TO KEEP THE NUMBER OF BUFFERS SWEPT FOR, AND THOSE WE CAN DO, CORRECT IFN FTKL10,< ;SUBROUTINE TO SAVE THE VITAL INFORMATION ABOUT BUFFERS IN THE DDB ;CALLED BY THE FILLER, CHECKED BY THE EMPTIER STONBF::LDB T1,PJOBN## ;JOB NUMBER MOVE T1,JBTST3##(T1) ;CPU JOB LAST RAN ON LDB T2,[POINT 1,S,^L] ;IF A SWEEP IS IN PROGRESS TRNE S,IOACT ; IT MIGHT BE PAST USERS BUFFER. SINCE CONSO APR,LP.CSB+LP.CSD ; WE DON"T SWEEP AGAIN IF IOACT IS ON, SETZ T2, ; REQUIRE 1 MORE SWEEP FOR OUTPUT ADD T2,.CPCSN##-.CPCDB##(T1) ;SWEEP SERIAL NUMBER NBFOFF MOVEM T2,DEVCSN(F) ;SAVE IN DDB MOVE T2,.CPCPN##-.CPCDB##(T1) ;CPU JOB LAST RAN ON DPB T2,DEYCPU## ;SAVE IN DDB JRST ONPOPN## ;SUBROUTINE TO CHECK THAT WE CAN HAVE THE BUFFERS ;UPDATES LH(DEVNBF) TO REFLECT ALL THE BUFFERS WHICH HAVE BEEN SWEPT FOR ;PRESERVES T2 CKNBF:: PUSHJ P,CHKCPI ;IF WE ARE ON THE CPU WHICH OWNS THE DEVICE JRST CHKNB CAMN T1,.CPBIT## ;ARE WE THE ONLY CPU? JRST ADDNBF ;YES, IT'S OK TLNN S,IO JRST CHKNB LDB T1,DEYPCL## ;CPU WHICH STARTED IO CAIN T1,PCLCP0## ;7 IS A SUBSTITUTE FOR 0 MOVEI T1,0 TRNE S,IOACT CAMN T1,.CPCPN## JRST ADDNBF ; THEN ALL BUFFERS ARE USABLE ;PRESERVES T3,T2 CHKNB:: NBFOFF LDB T1,DEYCPU## ;CPU JOB STARTED IO ON LDB T4,PJOBN## ;IF NOT WHERE JOB NOW IS, MOVE T4,JBTST3##(T4) CAME T1,.CPCPN##-.CPCDB##(T4) JRST ADDNB1 ; WE HAVE SWEPT, SO ADD TO LH IMULI T1,.CPLEN## MOVE T1,.C0CSN##(T1) ;CURRENT SWEEP SERIAL NUMBER ON THAT CPU CAMG T1,DEVCSN(F) ;IF THEY ARE THE SAME JRST ONPOPN## ; THAT CPU HASN'T SWEPT, CAN'T HAVE EXTRA BUFFERS JRST ADDNB1 ;SUBROUTINE TO UPDATE THE LH(DEVNBF) AND CLEAR THE RH ;PRESERVES T2,T3 ADDNBF: NBFOFF ADDNB1: HRRZ T1,DEVNBF(F) ;NUMBER OF BUFFERS TO UPDATE BY JUMPE T1,ONPOPN## ;GO IF NOTHING TO ADD MOVN T4,T1 ;SET TO CLEAR RH HRLI T4,-1(T1) ;OVERFLOW FROM RH WILL GET THE LAST ONE ADDM T4,DEVNBF(F) ;UPDATE DEVNBF JRST ONPOPN## ;AND RETURN ; STILL IN FTKL10 CONDITIONAL ;SUBROUTINE TO CHECK IF AN INPUT BUFFER IS OK WITH RESPECT TO CACHE ;ENTER T1=BUFFER ADDRESS ;CPOPJ EXIT IF BUFFER ISN'T RIGHT, CPOPJ1 IF IT IS BUFSSN::PUSH P,T1 PUSHJ P,MLSCSH ;IS LOW SEG CACHED? SKIPA T3,.USJOB ;NO,GET JOB NUMBER JRST TPOPJ1## ;YES,DOWN TO ONE CPU, DON'T WORRY POP P,T1 ;RESTORE ADDR OF BUFFER HRRZ T3,JBTST3##(T3) ;GET CPU JOB LAST RAN ON (OR IS RUNNING ON) CAMN T3,.CPSLF## ;DID IT RUN WHERE THE IO WILL HAPPEN? JRST CPOPJ1## ;YES, CACHE IS RIGHT (OR WILL BE WHEN IO IS DONE) MOVE T4,.CPCPN##-.CPCDB##(T3) ;NO. GET CPU NUMBER EXCTUX ;GET S-WORD OF BUFFER TRZE T2,IO ;DID UUOCON LAST SAVE SWEEP NUMBER? CAIE T4,(T2) ;YES. WAS IT ON THE CURRENT CPU? JRST BUFSS1 ;NO. THIS BUFFER IS OK TO FILL HLRZS T2 ;YES. ISOLATE SWEEP NUMBER HRRZ T3,.CPCSN##-.CPCDB##(T3) ;GET CURRENT SWEEP NUMBER FOR THAT CPU CAME T2,T3 ;WAS CACHE SWEPT AFTER BUF BECAME AVAILABLE? BUFSS1: AOS (P) ;YES. BUFFER IS USABLE SUBI T1,1 ;WE REFERENCED THAT CACHE LINE, PJRST OUCHE## ; SO GET IT OUT OF CACHE AND RETURN >;END FTKL10 ;SUBROUTINE TO GET JOB ON RIGHT CPU FOR FILE OPERATION ;CALL WITH F = DDB ;PRESERVES T1,T4(I KNOW..) SETCPF::PUSHJ P,SAVT## ;SAVE CALLERS SETCF1: PUSHJ P,SETCF2 SKIPA T1,[DVOFLN,,0] ;GET OFFLINE BIT POPJ P, ;IT'S ALIVE IORM T1,DEVCHR(F) ;LIGHT IN DDB PUSHJ P,CPUOFS ;GET OFFSET TO CPU'S CDB MOVSI T2,(CR.DET) ;CPU DETACHED BIT TDNN T2,.C0RUN##(T1) ;IS THIS CPU DETACHED JRST [PUSHJ P,HNGSTP## ;COMPLAIN TO USER AND OPERATOR JRST SETCF1] ;AND TRY ALL OVER AGAIN PUSHJ P,RTNEVM## ;RETURN EUM MOVEI T4,'IDC' ;"IO TO DETACHED CPU" CODE PUSHJ P,PSIJBI## ;SEE IF USER WANTS THE TRAP JRST [TRO S,IOIMPM!IODERR!IODTER!IOBKTL ;YES, GET ERROR BITS PUSHJ P,CLRACT## ;FOR ANY CORRECTION THE USER MAY WANT JRST ERRGOU##] ;TAKE OFF WITH THE TRAP JSP T1,ERRPNT## ;USER NOT WANT TRAP, PRINT MESSAGE ASCIZ /CPU failed for / PJRST DEVEXC## ;AND STOP HIM SETCPP::PUSHJ P,SAVT## ;SAVE T1-T4 SETCF2: LDB T1,DEYPCL## ;IF QUEUED PROTOCOL JUMPN T1,CPOPJ1## ; IT CAN RUN ON ANY CPU PUSHJ P,CHKCPI PUSHJ P,GETCP1 ;GET OWNING CPU MOVE T1,.CPCPN## PUSHJ P,ONCPUS ;GET ON CORRECT CPU POPJ P, ;CPU NOT RUNNING JRST CPOPJ1## ;RETURN WHEN ON CPUN ;SUBROUTINE TO RING THE DOORBELL SETQPB::PUSHJ P,CPUOFS ;GET RIGHT CPU SETQP1::MOVE T1,.C0QPC##(T1) ;DOORBELL BITS FOR ALL OTHER CPUS IORM T1,DOORBL## ;RING RING POPJ P, ;ROUTINE TO RETURN THE OFFSET FROM CPU0 CDB TO THE CURRENT CPU CDB CPUOFS::PUSHJ P,GETCPF ;CPU OWNING THE DEVICE IMULI T1,.CPLEN## ;MULTIPLY BY LENGTH OF CDB POPJ P, ;RETURN ;ROUTINE TO GET (THE ONE AND ONLY) CPU NUMBER ;T1 RETURNS THE CPU NUMBER GETCP1: AOS (P) ;SKIP RETURN GETCPF: LDB T1,DEYCPF## ;GET THE CPU NUMBER CAIE T1,CPFBIT## ;IS THERE MORE THAN ONE? POPJ P, ;ONLY ONE PUSHJ P,CHKCPI ;GET THE BIT MASK AGAIN TRNA ;NOT REACHABLE HERE SKIPA T1,.CPCPN## ;WE CAN DO THE I/O, DON'T ASK ANYONE ELSE PUSHJ P,CAMCPU ;FIND SOME CPU WHO CAN DO THE I/O POPJ P, ;RETURN TARGET CPU NUMBER IN T1 ;CODE CALLED FROM USRXIT TO SEE IF MUST RESCHEDULE UXITMP::SKIPGE .CPRUN## ;CAN THIS CPU RUN JOBS PJRST DPXST ;NO, MUST RESCHEDULE IFE SP.CR0-1,< MOVE T1,.CPBIT## ;BIT POSITION FOR CURRENT CPU > IFN SP.CR0-1,< MOVEI T1,SP.CR0 ;BIT FOR CAN RUN ON CPU0 LSH T1,@.CPCPN## ;POSITION FOR CPU PROCESSING UUO > TDNE T1,JBTSPS##(J) ;CAN JOB CONTINUE TO RUN HERE AOS (P) ;YES HE CAN, SKIP RETURN ;FALL INTO "DPXST" ;HERE FROM COMCON, RUN UUO, AND TO CLEAR SP.NR0 AT END OF A UUO DPXST:: MOVSI T1,(SP.NRA!SP.ROP) ANDCAM T1,JBTSPS##(J) POPJ P, ;ROUTINE TO CHECK IF JOB CAN RUN ON EITHER OR BOTH CPUS ;CALL: MOVE J,JOB NUMBER ; PUSHJ P,CHKCPU ; JOB IS SET TO RUN ONLY CPU1 ; JOB WAS SET TO RUN ON ALL CPUS OR LOCKED ON A CPU - T1=CPU ;CALLED BY TRPSET AND RTTRP CHKCPU::MOVE T1,.CPCPN## PUSHJ P,CPLCK ;ONLY ON THIS CPU SKIPA T1,JBTSPS##(J) ;JOB CAN RUN BITS IN SECOND CPU STATUS JRST CPOPJ1## TRNN T1,SP.CR0 ;CAN JOB RUN ON CPU0 POPJ P, ;NO, RETURN ON CPU1 ONLY MOVEI T1,SP.CRA-SP.CR0 ;CLEAR CAN RUN ON CPU1 ANDCAM T1,JBTSPS##(J) ;SO WILL ONLY RUN ON CPU0 SETZ T1, JRST CPOPJ1## ;RETURN ON CPU0 ONLY ;SUBROUTINE TO SEE IF A JOB IS LOCKED ON THE CURRENT CPU CPLCK:: PUSHJ P,SAVE1## IFE SP.CR0-1,< MOVE P1,.CPBIT## ;BIT POSITION FOR CURRENT CPU > IFN SP.CR0-1,< MOVEI P1,SP.CR0 ;POSITION A BIT LSH P1,@.CPCPN ; FOR THE CURRENT CPU > TRC P1,SP.CRA ;ALL BITS EXCEPT FOR OUR CPU TDNN P1,JBTSPS##(J) ;IF ALL BITS ARE OFF AOS (P) ; IT CAN RUN ONLY ON THIS CPU POPJ P, ;HERE FROM COMCON TO TEST IF JOB ON SLAVE, BEFORE DOING CONTROL C SPSTOP::PUSHJ P,LOKSCD ;TURN ON INTERLOCK MOVSI T2,(SP.CC1) ;SET THE CONTROL C BIT SO SLAVE CANNOT RUN JOB IORM T2,JBTSPS##(J) ;AVOID SLAVE PICKING JOB UP BEFORE IT IS STOPPED MOVSI T2,(SP.CJ0) ;TEST IF JOB IS CURRENT JOB ON SLAVE PROCESSOR LSH T2,@BOOTCP## ;POSITION BIT FOR BOOT CPU TLC T2,(SP.CJA) ;WANT TO ASK IF CURRENT JOB ON ANY OTHER PROCESSOR TDNN T2,JBTSPS##(J) AOS (P) ;NO, SKIP RETURN AND DONT DELAY COMMAND JRST ULKSCD ;TURN OFF INTERLOCK ;HERE TO CLEAR MULTIPROCESSOR STATUS BITS CLRJSP::PUSH P,T2 ;SAVE A WORKING AC MOVSI T2,(SP.CC1) ;CLEAR LEFT HALF ERROR BITS ANDCAM T2,JBTSPS##(J) JRST T2POPJ## ;RESTORE T2 AND RETURN ;ROUTINE TO SET INITIAL CONDITIONS FOR CPU RUNNABILITY ;CALLED FROM CLOCK1 - CLRJBT SETJSP::MOVEI T1,SP.SCA+SP.CPA ;MAKE JOB RUNNABLE ON ALL CPU'S MOVEM T1,JBTSPS##(J) POPJ P, ;AND RETURN ;SUB TO MAKE JOB RUNNABLE ON ALL CPUS ;CLEARING BITS IN LH OF JBTSPS(CALLED FROM COMCON ON KJOB SO LOGOUT CAN RUN ; NO MATER WHAT CPU SPECIFICATION USER MAY HAVE CHANGED TO) ALLJSP::SKIPA T1,ALCPUS ;MAKE JOB RUNABLE ON ALL CPUS ; SKIP INTO CRESET ;SUBROUTINE TO RETURN CPU SPECIFICATION TO THAT SET ;BY LAST "SET CPU" COMMAND. CALLED FROM "RESET" IN UUOCON CRESET::LDB T1,[POINT 6,JBTSPS##(J),29] ;GET LAST COMMAND SET SPECIFICATION DPB T1,[POINT 6,JBTSPS##(J),35] ;OVERRIDE LAST SETUUO ALCPUS: POPJ P,B29+SP.CPA ;CAN RUN ON CPU0 AND 1 ;ROUTINE TO CLEAR CONTROL C TYPED BIT ;CALLED FROM CLOCK1-WHEN JOB CAN BE STOPPED CLRCCB::MOVSI T1,(SP.CC1) ;THIS ROUTINE IS CALLED TO CLEAR SP.CC1 BIT ANDCAM T1,JBTSPS##(J) ;CONTROL C TYPED, SO DON'T RUN ON CPU1. POPJ P, ;AND RETURN ;HERE FROM ANYDEV TO MAKE IT LOOK LIKE JOB HAS ACTIVE DEVICES ;IF JOB IS CURRENTLY BEING RUN ON THE SLAVE PROCESSOR ;NOTE: IF CALLED AT ANYRN WITH A HIGH SEG, ON EXIT P2 WILL CONTAIN ;THE ADDRESS OF THE HIGH SEG DATA BLOCK FOR THE JOB WHICH HAD THE ;SEGMENT IN QUESTION ANYRUN::PUSHJ P,SAVE2## ;SAVE A COUPLE OF WORKING REGS MOVEI P1,.C0CDB## ;START WITH CPU0'S CDB ANYRN: PUSHJ P,LOKSCD ;TURN ON INTERLOCK ANYRN1: CAMN P1,.CPSLF## ;SKIP CALLING CPU JRST ANYRN2 ;STEP TO NEXT CAMN J,.CPSTS##-.CPCDB##(P1) ;STOPPING TIMESHARING FOR THIS JOB JRST ULKSCD ;YES, GO ULKSCD AND POPJ RETURN MOVE P2,.CPJOB##-.CPCDB##(P1) ;GET JOB CURRENTLY ON THIS CPU CAILE J,JOBMAX## ;CALLER WANT JOB OR SEGMENT NUMBER HRRO P2,JBTSGN##(P2) ;GET HIGH SEGMENT NUMBER FOR THAT JOB CAIN P2,(J) ;IS JOB RUNNING OR USING SAME SEGMENT JRST ULKSCD ;YES, GIVE NO SWAP RETURN TLZE P2,-1 ;CHECKING HIGH SEGS? TRNN P2,-1 ;YES, ARE THERE ANY? JRST ANYRN2 ;CHECKING JOBS OR NO HIGH SEGS ANYR1A: SKIPLE .HBSGN(P2) ;SPY SEGMENT? CAIE J,@.HBSGN(P2) ;NO, IS THIS THE SEGMENT IN QUESTION? CAIA ;SPY OR NO MATCH, CHECK NEXT HIGH SEG THIS JOB JRST ULKSCD ;A MATCH, GIVE NO SWAP RETURN HRRZ P2,.HBLNK(P2) ;POINT TO NEXT HIGH SEG JUMPN P2,ANYR1A ;CONTINUE IF ANOTHER HIGH SEG ANYRN2: HLRZ P1,.CPCDB##-.CPCDB##(P1) ;STEP TO NEXT CDB IN SYSTEM JUMPN P1,ANYRN1 ;AND CONTINUE LOOKING AOS (P) ;OK TO SWAP THIS JOB JRST ULKSCD ;UNLOCK SCHEDULER AND RETURN SUBTTL MULTIPROCESSING OPR/USER FAILING CPU INTERFACE ;HERE ON BOOT CPU FROM CLOCK1 ONCE A MINUTE TO CHECK IF OTHER CPU'S ARE RUNNING ;IF CPUN IS NOT RUNNING, TYPE OUT APPROPRIATE MESSAGES TO OPERATOR/USER CP1CHK::PUSHJ P,CPRMIN ;CHECK TO SEE IF ALL JOBS HAVE RUNNABLE SPECIFICATIONS PUSHJ P,SAVE1## ;SAVE P1 MOVEI P1,.C0CDB## ;ADDRESS OF CPU0'S CDB (START THERE) CP1CH1: SKIPLE .CPOK##-.CPCDB##(P1) ;THIS CPU OK? SKIPGE T1,.CPRUN##-.CPCDB##(P1) ;NO, SHOULD IT BE COUNTING ITS OK WORD? JRST CP1CH6 ;EITHER RUNNING OR SHOULDN'D BE, TRECK ON TLNE T1,(CR.RMV!CR.DET!CR.SPD) JRST CP1CH6 MOVE U,OPRLDB## ;ADDRESS OF THE OPR LDB MOVEI T1,[ASCIZ / %Problem on /] ;TEXT FOR COMPLAINT PUSHJ P,CONMES## ;GO TELL THE OPR THAT THE CPU DIED MOVE T2,.CPLOG##-.CPCDB##(P1) ;LOGICAL NAME OF THE DEAD CPU PUSHJ P,PRNAME## ;TELL THE OPERATOR THAT MOVEI T1,[ASCIZ/ serial #/] ;TEXT PUSHJ P,CONMES## ;EXPLAINATION OF THE NEXT NUMBER MOVE T1,.CPASN##-.CPCDB##(P1) ;DEAD CPU'S SERIAL NUMBER PUSHJ P,RADX10## ;TELL THE OPERATOR THAT SINCE IT MAY NOT BE OBVIOUS PUSHJ P,PCRLF## ;COMPLETE THE LINE MOVE J,HIGHJB## ;HIGHEST JOB ON THE SYSTEM CP1CH2: PUSHJ P,RWRTCH ;JOB RIGHT WITH RESPECT TO THE CACHE ON THE DEAD CPU? JRST CP1CH4 ;YES, IT CAN STILL RUN CAMN J,MMUSER## ;OWN THE MM RESOURCE? JRST CP1CH3 ;YES, THAT WOULD HANG THE SYSTEM SO WARN THE OPR PUSHJ P,FLSDR## ;DOES THE JOB OWN A RESOURCE? JRST CP1CH4 ;NO, JOB DOESN'T JEOPARDIZE THE SYSTEM CP1CH3: MOVEI T1,[ASCIZ /(system will do no useful work until /] PUSHJ P,CONMES## ;EXPLAIN THE PROBLEM TO THE OPERATOR MOVE T2,.CPLOG##-.CPCDB##(P1) ;SICK CPU'S NAME PUSHJ P,PRNAME## ;TELL THE OPR AGAIN MOVEI T1,[ASCIZ / is restarted at 400 or DETACHed) /] PUSHJ P,CONMES## ;TELL THE OPR HOW TO GET IT GOING AGAIN JRST CP1CH5 ;OPR HAS BEEN TOLD, DON'T COMPLAIN AGAIN ABOUT THIS CPU CP1CH4: SOJG J,CP1CH2 ;LOOP OVER ALL CPUS CP1CH5: MOVE T1,STATES## ;CURRENT STATES SETTING TRNE T1,ST.NOP ;IS THERE AN OPERATOR IN ATTENDANCE? PUSHJ P,[PUSHJ P,FRCSET## ;SETUP TO A TYPE A COMMAND ON FRCLIN PUSHJ P,INLMES## ;DETACH CPUN ASCIZ /Detach / MOVE T2,.CPLOG##-.CPCDB##(P1) ;CPUN PUSHJ P,PRNAME## ;ADD THAT TO THE COMMAND PJRST PCRLF##] ;END THE COMMAND WITH A BREAK CP1CH6: HLRZ P1,.CPCDB##-.CPCDB##(P1) ;NEXT CPU'S CDB ADDRESS JUMPN P1,CP1CH1 ;LOOP IF THERE IS YET ANOTHER CPU POPJ P, ;RETURN ;SUBROUTINE TO CHECK IF THIS JOB IS RUNNABLE W.R.T. THE CACHE ON THE ; CPU WHOSE CDB IS IN P1 ;CALLING SEQUENCE: ; MOVEI P1,CDB OF THE CPU IN QUESTION ; MOVE J,JOB NUMBER OF JOB IN QUESTION ; PUSHJ P,RWRTCH ; OK TO RUN ON OTHER CPUS ; RUNNABLE ONLY W.R.T. P1 CPUS CACHE ; RWRTCH::MOVEI T3,SP.CR0 ;BIT FOR CPU0 LSH T3,@.CPCPN##-.CPCDB##(P1) ;MASK FOR THIS CPU'S BITS TRC T3,SP.CPA ;MAKE "ANYWHERE BUT HERE" MASK LDB T4,MPYNRN## ;JOB'S NOT RUNNABLE BITS CAIN T3,(T4) ;RUNNABLE ONLY HERE? POPJ P, ;YES, MUST ZAP IT IFN FTKL10,< HRRZ T3,JBTST3##(J) ;CDB OF LAST CPU JOB RAN ON SKIPE JBTADR##(J) ;RUNNABLE ON ALL CPUS IF SWAPPED CAME T3,P1 ;DID JOB LAST RUN ON CPU IN QUESTION? POPJ P, ;NO, JOB IS RUNNABLE W.R.T. P1 CPUS CACHE MOVE T4,.CPCSN##-.CPCDB##(P1) ;CACHE SWEEP SERIAL NUMBER FOR P1 CPU CAMLE T4,JBTCSN##(J) ;DID P1 CPU SWEEP SINCE THE LAST TIME IT RAN THIS JOB? > CAMN J,.CPJOB##-.CPCDB##(P1) ;CURRENT JOB ON DEAD CPU? AOS (P) ;NO, ONLY RUNNABLE W.R.T. P1 CPUS CACHE POPJ P, ;RETURN ;ROUTINE TO FIND NEXT STR WHICH CAN NO LONGER BE ACCESSED BECAUSE OF ; A DEAD CPU ;CALLING SEQUENCE: ; MOVEI P1,CDB OF THE DEAD CPU ; PUSHJ P,DEDSTR ; HERE IF NONE (LEFT) ; HERE IF ONE FOUND, T1=STR NAME DEDSTR: MOVE T4,STRAOB## ;POINTER TO TABSTR DEDST1: SKIPN T2,TABSTR##(T4) ;NEXT STR DATA BLOCK JRST DEDST4 ;THAT ENTRY IS ZERO HLRZ T2,STRUNI##(T2) ;FIRST UNIT IN THE FILE STR DEDST2: PUSHJ P,DEDUNI ;SEE IF UNIT CAN STILL BE ACCESSED JRST DEDST3 ;YES, ALL IS WELL SO FAR MOVE T1,@TABSTR##(T4);FILE STRUCTURE NAME JRST CPOPJ1## ;FILE STRUCTURE CANNOT BE ACCESSED DEDST3: HLRZ T2,UNISTR(T2) ;NEXT UNIT JUMPN T2,DEDST2 ;CHECK IT IF THERE IS ONE DEDST4: AOBJN T4,DEDST1 ;NEXT FILE STRUCTURE POPJ P, ;ALL HAVE BEEN REMOVED ;SUBROUTINE TO SEE IF THERE IS STILL A PATH TO A UNIT AFTER A CPU HAS ; DIED ;CALLING SEQUENCE: ; MOVEI P1,CDB OF THE CPU IN QUESTION ; MOVE T2,ADDRESS OF UDB FOR UNIT IN QUESTION ; PUSHJ P,DEDUNI ; RETURNS HERE IF UNIT CAN STILL BE ACCESSED ; HERE IF NO PATH TO THE UNIT ;RETURNS T2 = UDB ;PRESERVES T4 DEDUNI: MOVE T1,UDBCAM(T2) ;CPU THIS UNIT LIVES ON CAME T1,.CPBIT##-.CPCDB##(P1);ONLY THIS CPU? POPJ P, ;NO, OTHERS AS WELL IFN FTDUAL,< SKIPN T3,UNI2ND(T2) ;SECOND PORT, IS THERE ONE? JRST CPOPJ1## ;NO MOVE T3,UDBCAM(T3) ;SECOND PORT CPU CAME T3,.CPBIT##-.CPCDB##(P1) ;STILL GET AT THE SECONDARY PORT? POPJ P, ;YES > JRST CPOPJ1## ;NO PATH TO THE UNIT ;COMMAND LEVEL ENTRY POINT TO ATTACH A CPU - CPU NUMBER IN T1 CPUATT::IMULI T1,.CPLEN## ;OFFSET TO CPU CDB ADDI T1,.C0CDB## ;ADDRESS OF CDB SKIPG .CPOK##-.CPCDB##(T1) ;THIS CPU OK? JRST [MOVEI T1,[ASCIZ /CPU is already running/] PJRST ERRCRL##] ;REPORT ERROR AND RETURN MOVE S,.CPCPN##-.CPCDB##(T1) ;COPY CPU NUMBER JSP T2,SAVCTX## ;START THE MONITOR JOB MOVE T1,S ;GET CPU NUMBER BACK PUSHJ P,CPUATU ;ATTACH VIA COMMON CODE CAIA ;ERROR RETURN POPJ P, ;GOOD RETURN - ALL DONE JSP T1,ERRCRL## ;GIVE ERROR ASCIZ /ATTACH CPU failed/ ;UUO LEVEL ENTRY POINT TO ATTACH A CPU - CPU NUMBER IN T1 CPUATU: PUSHJ P,SAVE2## ;FREE UP AN AC OR TWO MOVE P1,T1 ;COPY CDB NUMBER SOMEWHERE SEMI-PERMANENT IMULI P1,.CPLEN## ;OFFSET TO CPU CDB ADDI P1,.C0CDB## ;ADDRESS OF CDB MOVSI T1,(CR.RMV!CR.DET) ;REMOVED AND DETACHED BITS TDNN T1,.CPRUN##-.CPCDB##(P1) ;IS THE CPU DETACHED? JRST DIAAAF## ;NO--ATTACH FAILURE PUSHJ P,RECROM## ;RUN ONLY ME JRST DIAAAF## ;ATTACH FAILURE PUSHJ P,RCNIOW## ;WAIT FOR I/O TO STOP SETZ T2, ;INDICATE TO UNCACHE PUSHJ P,SETCSB ;CLEAR TEMPORARILY CACHED PAGES JFCL ;IGNORE ERROR AOS NCPRUN## ;INCREMENT NUMBER OF "RUNNABLE" CPUS IFN FTKL10,< MOVE T1,[JRST SYSTOP##] ;MAKE WARM RESTART MOVEM T1,WRSINS ; DO A JUMP 407 > ;END IFN FTKL10 MOVSI T1,(CR.ATO) ;DRIVERS MUST WAIT FOR AUTCON TO RUN IORM T1,.CPRUN##-.CPCDB##(P1) MOVSI T1,(CR.RMV!CR.DET!CR.NRN) ;GET BITS WHICH PREVENT RUNNING ANDCAM T1,.CPRUN##-.CPCDB##(P1) ;ALLOW THE CPU TO START MOVEI P2,^D10 ;DON'T LET THE SYSTEM IDLE FOREVER CPUAT1: MOVE T1,.CPCPN##-.CPCDB##(P1) ;GET CPU NUMBER PUSHJ P,ONCPUS ;TRY TO RESCHEDULE THIS JOB ON CPUN JRST [MOVEI T1,1 ;FAILED, SLEEP FOR A SECOND PUSHJ P,SLEEP## SOJG P2,CPUAT1 ;TRY AGAIN IF TIME IS LEFT JRST CPUAT2] ;CPUN DIDN'T START IFN FTKL10,< MOVEI T1,1 ;WAIT FOR SETSPD TASK TO RUN AND PUSHJ P,SLEEP## ; CFE TO SETTLE DOWN >; END IFN FTKL10 PUSHJ P,AUTCPU## ;CONFIGURE DEVICES WHILE SYSTEM IS IDLE PUSHJ P,RECCRM## ;CLEAR "RUN ONLY ME" XMOVEI T2,CPATBL ;POINT TO TRANSFER TABLE AOS (P) ;SKIP RETURN FOR SUCCESS PJRST CPUCSC ;LOG ATTACH AND RETURN ;CPUN DIDN'T START IN THE ALLOTTED TIME. "LOGICALLY" DETACH IT ;(UNDO THE WORK WE JUST DID) AND LET THE OPERATOR TRY AGAIN AT ;A MORE OPPORTUNE TIME. CPUAT2: PUSHJ P,CPUDXX ;DETACH CPUN AND UNDO THE WORK WE DID PUSHJ P,RECCRM## ;CLEAR "RUN ONLY ME" JRST DIAAAF## ;NOTIFY CALLER OF FAILURE ;HERE FROM COMMAND TO DETACH A CPU ;CALL WITH CPU NUMBER IN T1 CPUDET::MOVE S,T1 ;SAVE CPU NUMBER JSP T2,SAVCTD## ;MUST BE AT UUO LEVEL TO REMOVE FILE STRUCTURES MOVE T1,S ;GET COU NUMBER BEING REMOVED BACK PUSHJ P,CPUDTU ;CALL THE UUO CODE CAIA ;ERROR RETURN POPJ P, ;GOOD RETURN - ALL DONE JSP T1,ERRCRL## ;GIVE ERROR ASCIZ /DETACH CPU failed/ ;UUO CODE TO HANDLE DETACHING A CPU ;CALL WITH CPU NUMBER TO DETACH IN T1 ;IT IS THE CALLER'S RESPONSIBILITY TO ENSURE THAT THE CPU'S OK WORD IS POSITIVE CPUDTU: PUSHJ P,SAVE4## ;DODELE CLOBBERS P ACS MOVE P1,T1 ;CPU NUMBER IMULI P1,.CPLEN## ;CDB OFFSET ADDI P1,.C0CDB## ;FORM ADDRESS OF THE CDB SETZ T1, ;PICK A CPU, ANY CPU CPUDT1: CAME T1,.CPCPN##-.CPCDB##(P1) ;THE CPU DEING REMOVED? PUSHJ P,ONCPUS ;NO, TRY TO GET ON IT CAIA ;NOT RUNNING - TRY ANOTHER JRST CPUDT2 ;GOT THERE OK - CONTINUE CAIGE T1,M.CPU##-1 ;TRIED THEM ALL? AOJA T1,CPUDT1 ;NO, TRY NEXT JRST DIAADF## ;YES, WE TRIED CPUDT2: PUSHJ P,RECROM## ;RUN ONLY ME JRST DIAADF## ;DETACH FAILURE IFN FTXMON, ;RUN IN SECTION ZERO SKIPG .CPOK##-.CPCDB##(P1) ;IS THE CPU CURRENTLY RUNNING? JRST CPUDT5 ;YES, DON'T WORRY ABOUT I/O HANGING PUSH P,F ;SAVE TTY DDB HLRZ F,DEVLST## ;START OF DEVICE CHAIN CPUDT3: LDB T1,PDVTIM## ;GET HUNG TIMER JUMPE T1,CPUDT4 ;IGNORE DEVICES WHICH CAN'T HANG PUSHJ P,CHKCPI ;GET CPU ACCESSABILITY MASK TRNA ;OK IF WE CAN'T DO THE I/O JRST CPUDT4 ;WE CAN DO THE I/O--FORGET THIS ONE TDNN T1,.CPBIT##-.CPCDB##(P1) ;ACCESSIBLE ON DEAD CPU? JRST CPUDT4 ;NO--LOOK AT NEXT DEVICE MOVE S,DEVIOS(F) ;I/O STATUS PUSHJ P,CPUOK ;YES--CAN A LIVE CPU DO ITS I/O? TRNN S,IOACT ;NO--WAS I/O ACTIVE WHEN CPU STOPPED? JRST CPUDT4 ;NO,LOOK AT NEXT DEVICE PUSHJ P,DEVERR## ;CLEAR IOACT/SET TROUBLE CPUDT4: HLRZ F,DEVSER(F) ;NEXT DEVICE JUMPN F,CPUDT3 ;LOOP IF THERE IS ONE POP P,F ;RESTORE TTY DDB AND CONTINUE CPUDT5: PUSHJ P,RCNIOW## ;WAIT FOR I/O TO STOP ;NOW REMOVE INACCESSIBLE STRUCTURES CPUDT6: PUSHJ P,DEDSTR ;SEE IF ANY STRS WHICH CANNOT BE ACCESSED JRST CPUDT7 ;NONE OR FINISHED PUSHJ P,RMVSTR## ;REMOVE THE INACCESSIBLE FILE STRUCTURE JFCL ;MIGHT NOT SKIP JRST CPUDT6 ;NEXT STR ;HERE TO SEE THAT SWAPPING SPACE IS NOT ALLOCATED ON INACCESSIBLE UNITS CPUDT7: MOVEI T4,0 ;START AT FIRST ENTRY IN SWPTAB CPUDT8: SKIPLE T2,SWPTAB##(T4) ;NEXT UNIT IN THE ACTIVE SWAPPING LIST PUSHJ P,DEDUNI ;STILL ABLE TO GET AT THIS UNIT? JRST CPUDT9 ;YES, LOOP ON MOVEI P2,-1 ;+ INFINITY MOVE U,T2 ;UNIT PUSH P,T4 ;DON'T COUNT ON DODELE PRESERRVING T4 PUSH P,P1 ;OR P1 EITHER PUSHJ P,[PUSHJ P,GGVMM ;OBTAIN MM INTERLOCK JRST DODELE##] ;REMOVE DORMANT SEGMENTS FROM UNREACHABLE UNIT JFCL ;SHOULD NEVER SKIP POP P,P1 POP P,T4 MOVN T1,UNIFKS(T2) ;FREE SWAPPING SPACE ON THIS UNIT ADDM T1,UNIFKS(T2) ;ZAP, NO FREE SPACE ADDM T1,VIRTAL## ;AND DECREMENT TOTAL AMOUNT OF FREE SPACE AVAILABLE SETOM SWPTAB##(T4) ;FLAG UNIT DEAD CPUDT9: CAIGE T4,SWPMAX## ;LOOKED AT ALL THE UNITS IN THE A.S.L.? AOJA T4,CPUDT8 ;NO, LOOK AT THE NEXT UNIT ;NOW DETACH ALL DISK PORTS CONNECTED TO THE CPU BEING REMOVED ; NECESSARY SO THAT PULSAR WILL KNOW THEY HAVE GONE AWAY MOVEI J,KDBTAB##+.TYDSK-KDBNXT ;START AT FIRST KONTROLLER CPUD10: SKIPN J,KDBNXT(J) ;NEXT KONTROLLER JRST CPUD12 ;GO IF DONE MOVE T1,KDBCAM(J) ;CPU(S) OWNING THIS KONTROLLER CAME T1,.CPBIT##-.CPCDB##(P1) ;SAME AS THE CPU BEING DETACHED? JRST CPUD10 ;NO, LOOK AT THE NEXT KONTROLLER MOVE T1,KDBIUN(J) ;AOBJN POINTER TO UNIT TABLE SKIPN U,(T1) ;A UNIT THERE? CPUD11: AOBJN T1,.-1 ;NO, LOOK AT THE NEXT SLOT JUMPGE T1,CPUD10 ;GO IF ALL UNITS ON THE KONTROLLER HAVE BEEN LOOKED AT PUSH P,T1 ;SAVE AOBJN POINTER SKIPGE UNI2ND(U) ;IS THIS THE ALTERNATE PORT? TLO U,400000 ;YES, DETDSK WANTS U NEGATIVE TO INDICATE THAT PUSHJ P,DETCPD## ;DETACH THE UNIT JFCL ;WE TRIED JFCL ;IGNORE ERROR POP P,T1 ;RESTORE AOBJN POINTER MOVE J,UDBKDB(U) ;DETCPD MAY CLOBBER J JRST CPUD11 ;SEE IF ANY UNITS LEFT ON THIS KONTROLLER CPUD12: MOVE T2,[CPUDCL,,1] ;WHERE TO GO,,IN 1 TICK SYSPIF ;'CAUSE 2-WORD ENTRIES IDPB T2,CLOCK## ;STORE TIMER + ROUTINE IDPB P1,CLOCK## ;AND CDB + STATUS SETOM CLKNEW## ;NEW SYSTEM CLOCK QUEUE ENTRY SYSPIN ;ALLOW OTHERS AGAIN PUSHJ P,CPUDXX ;DO THE WORK OF DETACHING THE CPU PUSHJ P,RECCRM## ;CLEAR "RUN ONLY ME" XMOVEI T2,CPDTBL ;POINT TO TRANSFER TABLE PUSHJ P,CPUCSC ;LOG DETACH AOS (P) ;SKIP FOR GOOD RETURN MOVE U,OPRLDB## ;OPR'S LDB MOVE T2,.CPLOG##-.CPCDB##(P1) ;CPU'S NAME PUSHJ P,PRNAME## ;TELL THE OPR WHAT CPU PJSP T1,CONMES## ; WAS DETACHED ASCIZ / Detached / ;HERE TO LOGICALLY DETACH A CPU CPUDXX: MOVSI T1,(CR.RMV!CR.DET!CR.NRN) ;GET BITS WHICH PREVENT RUNNING IORM T1,.CPRUN##-.CPCDB##(P1) ;INDICATE CPU IS REMOVED MOVEI T1,1 ;SLEEP FOR A SECOND TO LET CPUN HIT RMVCPU PUSHJ P,SLEEP## ;WAIT FOR DETACH TO HAPPEN SOS NCPRUN## ;DECREMENT NUMBER OF "RUNNABLE" CPUS MOVEI T2,1 ;SET TO CACHE THE LOW SEG (IF DOWN TO 1 CPU) PUSHJ P,SETCSB ;TWIDDLE CACHE BITS AS APPROPRIATE JFCL ;IGNORE ERROR (MORE THAN 1 CPU LEFT RUNNING) POPJ P, ;RETURN ;HERE TO DO CLOCK-LEVEL THINGS FOR DETACHING A CPU CPUDCL: MOVE P1,T1 ;GET SAVED CDB ADDRESS PUSH P,J ;SAVE JOB NUMBER MOVE J,HIGHJB## ;HIGHEST JOB ON THE SYSTEM CPUDC1: PUSHJ P,RWRTCH ;JOB RUNNABLE W.R.T. THE CACHE ON THE DEAD CPU? CAIA ;YES PUSHJ P,CPUZAP ;NO, ZAP THE JOB SOJG J,CPUDC1 ;LOOP OVER ALL JOBS POP P,J ;RESTORE JOB NUMBER SETZM .CPJOB##-.CPCDB##(P1) ;ZERO CURRENT JOB ON DEAD CPU POPJ P, ;RETURN - CPU REMOVED ;SUBROUTINE TO ZAP THE CURRENT JOB ON A DEAD CPU, OR TO ZAP A JOB WHICH ; MIGHT HAVE DATA IN THE DEAD CPU'S CACHE ;CALLING SEQUENCE: ; MOVE J,JOB NUMBER ; PUSHJ P,CPUZAP ; ALWAYS RETURN HERE CPUZAP::PUSHJ P,SVEUB## ;MAKE SURE THE JOB IS ADDRESSABLE PUSHJ P,ZAPZAP## ;BLOW AWAY HIS CORE IMAGE MOVSI T1,(SP.CJ0) ;CURRENT JOB ON CPU0 BIT LSH T1,@.CPCPN##-.CPCDB##(P1) ;POSITION IT TO DEAD CPU TLO T1,(SP.NRA!SP.ROP) ;CLEAR NOT RUNNABLE BITS TOO ANDCAM T1,JBTSPS(J) ;CLEAR CURRENT JOB ON DEAD CPU BIT MOVSI T1,JERR ;DON'T ALLOW TRAPS IORM T1,JBTSTS##(J) JSP T1,ERRPNT## ;INFORM THE USER ASCIZ /CPU failed/ PJRST PCSTOP## ;TELL THE USER THE PC AND STOP THE JOB ;SUBROUTINE TO MAKE A DAEMON ENTRY FOR CPU ATTACH/DETACH. ;CALLING SEQUENCE: ; XMOVEI T1,TRANSFER TABLE ; PUSHJ P,CPUCSC ; ALWAYS RETURN HERE CPUCSC: SETZ T1, ;CAUSE SEB ALLOCATION TO HAPPEN PUSHJ P,XFRSEB## ;FILL AND QUEUE UP RECORD JFCL ;NO CORE POPJ P, ;RETURN ;CPU ONLINE TRANSFER TABLE FOR ERROR.SYS LOGGING CPATBL: SEBTBL (.ERCSC,CPAEND,) MOVE .CPLOG## ;(R00) CPU NAME MOVE .CPASN## ;(R01) ADDITIONAL INFO (SERIAL NUMBER) MOVSI .CSCAT ;(R02) REASON CODE CPAEND:! ;END OF TABLE ;CPU OFFLINE TRANSFER TABLE FOR ERROR.SYS LOGGING CPDTBL: SEBTBL (.ERCSC,CPDEND,) MOVE .CPLOG## ;(R00) CPU NAME MOVE .CPASN## ;(R01) ADDITIONAL INFO (SERIAL NUMBER) MOVSI .CSCDT ;(R02) REASON CODE CPDEND:! ;END OF TABLE SUBTTL INTERLOCK ROUTINES $CSUB ;MUST BE ADDRESSABLE BY ALL CODE SEGMENTS ;INTERLOCK ROUTINES - LOKSCD, ULKSCD ;CALLED BY PUSHJ TO ENTER CODE WHICH MUST RUN TO COMPLETION ;ON THE CURRENT PROCESSOR BEFORE IT (OR ANY INTERLOCKED ;SECTIONS) IS ENTERED BY THE OTHER PROCESSOR. ; ; PUSHJ P,LOKSCD ; ...INTERLOCKED CODE... ; PUSHJ P,ULKSCD ; ;THERE IN FACT CAN EXIST SEVERAL LEVELS OF INTERLOCK, OF WHICH ;ONLY THE LOWEST LEVEL IS REAL, REST ARE VIRTUAL. NECESSARY ;BECAUSE OF THE EXISTENCE OF ROUTINES WHICH MUST THEMSELVES ;BE INTERLOCKED BUT WHICH ARE CALLED BOTH BY INTERLOCKED CODE ;AND UN-INTERLOCKED CODE. (EXAMPLE: QQXFER) ;THE LOCATIONS .C0SCD,.C1SCD SHOULD BE INITIALIZED TO -1 ;AT SYSTEM STARTUP TIME. LOKSCD::CONO PI,SYSOFF## ;TURN PI SYSTEM OFF AOSE .CPSCD## ;BUMP LEVEL OF INTERLOCK POPJ P, ;JUST NESTING, STILL HAVE INTERLOCK LOKSC1: CONO PI,SYSOFF## SKIPGE SCDLOK## ;DON'T TRY IF NO CHANCE OF GETTING IT (TIES UP MEMORY) AOSE SCDLOK## ;GET SYSTEM INTERLOCK AOSA .CPLLC## ;COUNT INTERFERENCE AOSA .CPRSI## ;GOT IT, FILL IN CPU ID JRST [CONO PI,SYSON##-PI.SC7 ;TURN PI'S ON EXCEPT FOR SCHEDULER JRST LOKSC1] ;TRY AGAIN APRID INOSCD## POPJ P, ;RETURN WITH INTERLOCK ;ROUTINE TO LOKSCD, DISPATCH, ULKSCD, AND RETURN. ; CALLED FROM ANY ROUTINE WHICH IS CALLED BY A PUSHJ ; AND EXPECTS TO RETURN WITH POPJ OR AOS (P), POPJ. SBSCD:: PUSHJ P,LOKSCD ;TURN ON INTERLOCK PUSHJ P,@(P) ;DISPATCH TO ROUTINE CAIA AOS -1(P) ;PROVIDE FOR SKIP RETURN POP P,(P) ;FIX PUSHDOWN TO RETURN TO ORIGINAL CALLER ULKSCD::PUSH P,T1 ;SAVE AN AC SOSL T1,.CPSCD## ;DECREMENT LEVEL JRST TPOPJ## ;STILL NESTED ON THIS CPU, RETURN SETOM INOSCD## ;TELL THE WORLD WE DON'T OWN IT EXCH T1,SCDLOK## ;RELEASE SYSTEM INTERLOCK CONO PI,SYSON## JUMPGE T1,TPOPJ## ;ALL IS WELL IF INTERLOCK TAKEN STOPCD TPOPJ##,DEBUG,SAU, ;++SCHEDULER ALREADY UNLOCKED ;ROUTINE TO CHECK OWNERSHIP OF THE SCHEDULER INTERLOCK ; RETURN CPOPJ IF OWNED, CPOPJ1 IF NOT SCDOWN::PUSH P,T1 ;ITS TRADITIONAL NOT TO CLOBBER AC'S APRID T1 CAME T1,INOSCD## ;OWN INTERLOCK? JRST TPOPJ1## ;NO JRST TPOPJ## ;YES ;ROUTINE TO OBTAIN THE DIE INTERLOCK LOKDIE::AOSE .CPDIE## ;OWN INTERLOCK? POPJ P, ;JUST NESTING, RETURN SKIPGE INTDIE## ;INTERLOCK AVAILABLE? AOSE INTDIE## ;TRY TO GET IT JRST .-2 ;NOT AVAILABLE APRID INODIE## ;REMEMBER WHO OWNS IT SETOM DIEFLG## ;FLAG A STOPCODE IS HAPPENING POPJ P, ;RETURN ;ROUTINE TO RELEASE THE DIE INTERLOCK ULKDIE::PUSH P,T1 ;SAVE AN AC SOSL T1,.CPDIE## ;COUNT DOWN A LEVEL OF NESTING JRST TPOPJ## ;STILL NESTING, RETURN SETOM INODIE## ;NO ONE OWNS IT NOW SETZM DIEFLG## ;CLEAR STOPCODE IN PROGRESS FLAG EXCH T1,INTDIE## ;RELEASE INTERLOCK JUMPGE T1,TPOPJ## ;OK IF WAS LOCKED PREVIOUSLY STOPCD TPOPJ##,DEBUG,DAU, ;++DIE ALREADY UNLOCKED ;ROUTINE TO BREAK THE DIE INTERLOCK BRKDIE::SETOM INODIE## ;NO ONE OWNS IT NOW SETZM DIEFLG## ;CLEAR STOPCODE IN PROGRESS FLAG SETOM INTDIE## ;RELEASE INTERLOCK POPJ P, ;RETURN ;ROUTINE TO ATTEMPT TO OBTAIN THE CORE ALLOCATION RESOURCE ; IN SCHEDULAR CONTEXT ;N.B. MUST OWN THE SCHEDULAR INTERLOCK WHEN CALLING SCDMM ;CALLING SEQUENCE: ; PUSHJ P,GETMM ; RETURNS HERE IF RESOURCE IS NOT CURRENTLY AVAILABLE ; RETURNS HERE, CALLER OWNS THE RESOURCE ;NOTE, THE CALLER MUST TAKE RESPONSIBILITY FOR TRYING AGAIN ; LATER (DLYCOM, SWAPPER, ETC.) IF THE RESOURCE IS NOT CURRENTLY ; AVAILABLE. ANY ROUTINE WHICH OBTAINS THE LOCK BY CALLING GETMM ; MUST GIVE IT UP BY CALLING GIVMM GETMM:: PUSHJ P,SBSCD ;CALL COROUTINE TO GET THE SCHEDULER INTERLOCK ;HERE IF SCHEDULER INTERLOCK IS ALREADY OWNED SCDMM:: AOSE MMREQ## ;SEE IF THE RESOURCE IS AVAILABLE SKIPE MMAVAL## ;OR AVAILABLE, DIDN'T GIVE IT TO A JOB ; WAITING FOR IT BECAUSE IT WAS BEING SWAPPED, ETC. AOSA (P) ;AVAILABLE, SET FOR RESOURCE AVAILABLE RETURN JRST SCDMM1 ;NOT NOW, UNDO THE AOS SETZM MMAVAL## ;MAKE SURE THE SCHEDULAR DOESN'T GIVE IT ; TO A UUO LEVEL WAITER UNTIL WE GIVE IT UP ;MUST HAVE THE SCHEDULAR INTERLOCK TO DO THIS IFN FTKL10,< PUSH P,CORTAL## ;CURRENT VALUE OF CORTAL POP P,SAVCTL## ;SAVE IT TO DETERMINE IF A SWEEP IS NECESSARY ; WHEN THE MM IS GIVEN UP > APRID INTLMO## ;NOTE THAT THIS CPU IS THE OWNER POPJ P, ;RETURN WITH THE LOCK SCDMM1: SOS MMREQ## ;UNDO THE AOS POPJ P, ;GIVE RESOURCE NOT AVAILABLE RETURN ;SUBROUTINE TO GIVE UP THE MM RESOURCE WHEN IT WAS OBTAINED BY ; CALLING GETMM ;CALLING SEQUENCE: ; PUSHJ P,GIVMM ; ALWAYS RETURNS HERE GIVMM:: SETOM INTLMO## ;MARK THE FACT THAT THIS CPU NO LONGER OWNS IT PJRST DWNMM ;RETURN THE RESOURCE AND RETURN ;SUBROUTINE TO SEE IF THE CURRENT JOB OWNS THE MM RESOURCE. ;CPOPJ IF NOT, CPOPJ1 IF SO MMOWN:: SKIPE DINITF## ;ONCE-ONLY? JRST CPOPJ1## ;YES, JOB OWNS THE MM PUSH P,J ;SAVE J MOVE J,INTLMO## ;OWNER OF THE MM RESOURCE IF OWNED BY A CPU ANDI J,ID.PSN ;ISOLATE THE SERIAL NUMBER CAMN J,.CPASN## ;OWN THE RESOURCE AT INTERRUPT LEVEL? JRST JPOPJ1## ;YES, GIVE OWNED RETURN MOVE J,.CPJOB## ;CURRENT JOB CAMN J,MMUSER## ;OWN THE MEMORY MANAGEMENT RESOURCE? JRST JPOPJ1## ;YES JRST JPOPJ## ;NO ;SUBROUTINE TO SEE IF A JOB OWNS THE MM RESOURCE AND GIVE IT UP IF SO ; THIS ROUTINE REMEMBERS THAT IT WAS OWNED AND A MATCHING CALL TO ; UIFMM MUST FOLLOW IT DIFMM:: PUSHJ P,MMOWN ;OWN THE MM RESOURCE? POPJ P, ;NO PUSH P,T1 ;YES MOVSI T1,(UP.MMO) ;JOB OWNED THE MM BIT IORM T1,.USBTS ;REMEMBER THAT PUSHJ P,DWNMM ;GIVE IT UP JRST TPOPJ## ;RESTORE T1 AND RETURN ;SUBROUTINE TO GET BACK THE MM RESOURCE IF A JOB OWNED IT WHEN DIFMM ; WAS CALLED UIFMM:: PUSH P,T1 ;SAVE T1 MOVSI T1,(UP.MMO) ;JOB OWNED THE MM RESOURCE BIT TDNE T1,.USBTS ;DID THE JOB OWN IT? PUSHJ P,UPMM ;YES, GET IT BACK ANDCAM T1,.USBTS ;CLEAR THE BIT JRST TPOPJ## ;AND RETURN ;COROUTINE TO SAVE AND RESTORE THE STATE OF THE MM RESOURCE REMMM:: PUSHJ P,MMOWN ;OWN MM? POPJ P, ;NO, NOTHING TO DO THEN PUSHJ P,DWNMM ;GIVE UP MM NOW POP P,(P) ;POP CALLER'S RETURN PC PUSHJ P,@1(P) ;RETURN TO CALLER CAIA ;NON- SKIP AOS (P) ;SKIP JRST UPMM ;RESTORE MM ;COROUTINE TO GET THE MM RESOURCE AND GIVE IT UP ON RETURN GGVMM:: SKIPE DINITF## ;ONCE-ONLY? POPJ P, ;YES, AN ELABORATE NO-OP PUSHJ P,UPMM ;GET THE MM RESOURCE POP P,(P) ;POP CALLER'S RETURN PC PUSHJ P,@1(P) ;RETURN TO CALLER CAIA ;NON-SKIP AOS (P) ;SKIP PJRST DWNMM ;GIVE UP THE MM RESOURCE ;SUBROUTINE TO GET THE MM RESOURCE AND WORRY ABOUT CACHE IF PAGES ; ARE DEALLOCATED UPMM:: PUSH P,F ;SAVE F SETZ F, ;SO SRWAIT DOESN'T WORRY ABOUT EVM PUSHJ P,MMWAIT## ;GET THE MM RESOURCE IFN FTKL10,< MOVE F,CORTAL## ;CURRENT NUMBER OF FREE OR FREEABLE PAGES MOVEM F,SAVCTL## ;REMEMBER TO SEE IF CORE WAS DEALLOCATED > JRST FPOPJ## ;RESTORE F AND RETURN ;SUBROUTINE TO GIVE UP THE MM IF OWNED TGVMM::PUSHJ P,MMOWN ;OWN THE MM? POPJ P, ;NO, NOOP ;FALL INTO DWNMM ;SUBROUTINE TO GIVE UP THE MM RESOURCE AND SWEEP THE CACHE IF CORE ; HAS BEEN DEALLOCATED (NECESSARY SINCE WRITTEN BITS MAY BE ON IN DEALLOCATED PAGES) DWNMM:: PUSH P,F ;SAVE F IFN FTKL10,< MOVE F,CORTAL## ;CURRENT CORTAL PUSHJ P,MLSCSH ;IS THE LOW SEGMENT UNCACHED CAMG F,SAVCTL## ;HAS CORTAL INCREASED SINCE CALL TO UPMM? (DEALLOCATION) JRST DWNMM1 ;NO, OR LAST CPU, DON'T BOTHER WITH SWEEP AOS .CPSDA## ;YES, COUNT THE NUMBER OF SWEEPS REQUIRED BY DEALLOCATION PUSHJ P,CSDMP## ;SWEEP - MUST DO IT WHILE STILL OWNING THE MM DWNMM1:> SETZ F, ;ZERO F (NO EVM) PUSHJ P,MMFREE## ;RETURN THE MM JRST FPOPJ## ;RESTORE F AND RETURN $HIGH SUBTTL MULTIPROCESSING SCHEDULING ;THIS ROUTINE IS CALLED AT THE BEGINNING OF SCHED (NXTJOB) ;TO PUT SCAN TABLE ADDRESS INTO AC DAT. THE MASTER PROCESSOR ;IS MADE TO SCAN PQ1,PQ2,PQ3 WHILE THE SLAVE PROCESSOR IS MADE ;TO SCAN PQ3,PQ2,PQ1. IN ADDITION, THIS ROUTINE IS USED ;TO DETERMINE WHETHER TO DO REGULAR SCHEDULING AT THIS TIME ;OR TO RUN EITHER (1) A JOB WHICH HAS STOPPED TIME SHARING ;OR (2) A JOB WHICH WAS RUNNING ON THE SLAVE PROCESSOR THAT ;MUST DO A UUO (PROBABLY FOR I/O) MSCHED::SKIPE J,.CPSTS## ;DID ANYONE STOP TIME SHARING? JRST MRNBL1 ;YES, SEE IF HE IS RUNNABLE PUSHJ P,SCHEDJ## ;DISPATCH TO SCHED CODE MSEL: MOVSI T1,(SP.CJ0) ;PICK UP RUN BIT FOR MASTER PROCESSOR LSH T1,@.CPCPN## ;POSITION FOR THIS PROCESSOR MOVE F,.CPJOB## ;GET LAST JOB NUMBER ANDCAM T1,JBTSPS##(F) ;TURN OFF RUNBIT FOR OLD JOB IORM T1,JBTSPS##(J) ;TURN ON RUNBIT FOR NEW JOB JUMPE J,CPOPJ## ;RETURN IF NULL JOB MOVEI T1,JS.SCN ;SET SCANNED BIT IORM T1,JBTST2##(J) ; FOR THE JOB POPJ P, ;AND RETURN ;TEST IF JOB WHICH STOPPED T/S IS RUNNABLE MRNBL1: MOVE T1,NRNMSK ;GET NON RUNNABLE MASK TDNN T1,JBTSTS##(J) ;IS JOB WAITING TO SHUFFLE,SWAP,EXPAND,LOCK,OR REQUE PUSHJ P,DXRUN ;SECOND STATUS WORD BITS OK? MOVEI J,0 ;JOB UNRUNNABLE, GO RUN NULL JOB JRST MSEL ;JOB RUNNABLE, GO TO IT IFN FTLOCK,< NRNMSK: XWD SWP+SHF+JXPN+JRQ+WTMASK,LOK > IFE FTLOCK,< NRNMSK: XWD SWP+SHF+JXPN+JRQ+WTMASK,0 > ;ROUTINE TO DETERMINE IF JOB IS RUNNABLE WITH RESPECT TO JBTSPS BITS ;CALLED FROM SCHED WHEN SCHED IS ENTERED BY ANY PROCESSOR ;SKIP RETURN IF JOB IS RUNNABLE DXRUN:: PUSH P,T1 ;SAVE WORKING REG PUSH P,T2 ;AND ANOTHER IFE SP.CP0-1,< MOVE T1,.CPBIT## ;BIT MASK FOR THIS CPU > IFN SP.CP0-1,< MOVEI T1,SP.CP0 ;BIT FOR CPU0 ( ** ALSO SP.CR0 ** ) LSH T1,@.CPCPN## ;MASK FOR THIS CPU'S BITS > MOVE T2,T1 ;COPY POSITIVE MASK TRC T1,SP.CPA ;MAKE "ANYWHERE BUT THIS CPU" MASK LDB F,MPYNRN## ;GET JOBS NOT RUNNABLE BITS CAIN F,(T1) ;RUNNABLE ONLY HERE (CONTEXT SWITCHED TO THIS CPU) JRST DXRUN1 ;REALLY GOT TO RUN THIS JOB SKIPL .CPRUN## ;CAN CPU RUN ANY JOBS (SET RUN NO CPUN) TDNN T2,JBTSPS##(J) ;YES, DOES USER WANT THIS CPU (SET CPU COMMAND/UUO) JRST TTPOPJ## ;NO, CANNOT RUN THIS JOB DXRUN1: LSH T1,<^L-^L> ;POSITION MASK TRNN F,(T2) ;MARKED UNRUNNABLE HERE (SWITCHED AWAY) TDNE T1,JBTSPS##(J) ; OR CURRENTLY ON SOME OTHER CPU JRST TTPOPJ## ;YES, CANNOT RUN THIS JOB SKPCPU (1) ;CPU CHECK JRST DXRUN2 ;BOOT, OK TO RUN THIS JOB TRC T2,SP.CPA ;FLIP RUNNABLE MASK MOVSI T1,(SP.CC1) ;CONTROL C BIT CAIE F,(T2) ;MUST RUN UUO TO COMPLETION TDNN T1,JBTSPS##(J) ;NO, WAS ^C TYPED CAIA ;LOOK SOME MORE JRST TTPOPJ## ;DON'T RUN JOB CAMN J,SW0JOB## ;WANT TO SWAP THIS JOB? JRST DXRUN3 ;YES, DONT RUN IT THEN HRRZ F,JBTSGN##(J) ;GET HIGH SEG NO., SPY OR NONE? JUMPE F,DXRUN2 ;NO HIGH SEG OR SPY HI SEG - GIVE CAN RUN RETURN MOVSI T2,SWP!SHF!JXPN ;BITS TO CHECK DXRN1A: SKIPLE T1,.HBSGN(F) ;GET SEGMENT WORD, SPY SEG? TDNN T2,JBTSTS##(T1) ;NO, HIGH SEG BEING MUNGED? CAIA ;SPY OR BEING MUNGED, CHECK NEXT HIGH SEG JRST DXRUN3 ;BEING MANGLED SOMEWHERE, FLAG LOST TIME HRRZ F,.HBLNK(F) ;NEXT SEGMENT JUMPN F,DXRN1A ;CHECK IF THERE IS ONE DXRUN2: AOSA -2(P) ;JOB IS RUNNABLE ON THIS CPU DXRUN3: MOVEM J,.CPPLT## ;FLAG POTENTIALLY LOST IF CAN'T RUN HIM ; BECAUSE OF MONITOR BIND JRST TTPOPJ## ;GIVE CANNOT RUN THIS JOB RETURN ;SUBROUTINE TO CLEAR SP.CJn FOR JOB IN J (CURRENT CPU) CLRSJ0::MOVSI T1,(SP.CJ0) ;PICK UP RUN BIT FOR MASTER PROCESSOR LSH T1,@.CPCPN## ;POSITION FOR THIS PROCESSOR ANDCAM T1,JBTSPS##(J) ;TURN OFF RUNBIT FOR OLD JOB POPJ P, ;SUBROUTINE TO SET SP.CJn FOR JOB IN .CPJOB (CURRENT CPU) SETSJ0::MOVE T2,.CPJOB## ;GET "CURRENT" JOB MOVSI T1,(SP.CJ0) ;PICK UP RUN BIT FOR MASTER PROCESSOR LSH T1,@.CPCPN## ;POSITION FOR THIS PROCESSOR IORM T1,JBTSPS##(T2) ;TURN ON RUNBIT FOR "CURRENT" JOB POPJ P, ;SUBROUTINE TO CHECK IF A JOB IS RUNNABLE ON CPU0 AND IF ; CPU0 IS RUNNING ; EXITS CPOPJ1 IF SO, CPOPJ IF NOT RUNNABLE ON CPU0 OR CPU0 NOT RUNNING ;PRESERVES ALL ACS EXCEPT T3 CP0RC:: MOVEI T3,SP.CR0 ;CAN RUN ON CPU0 BIT TDNE T3,JBTSPS##(J) ;CAN THE JOB RUN ON CPU0? SKIPGE .C0RUN## ;AND IS CPU0 RUNNING? POPJ P, ;CAN'T RUN ON CPU0 OR CPU0 NOT RUNNING JRST CPOPJ1## ;RETURN ;SUBROUTINE TO SEE IF JOB # IN J IS ON ANY CPU ;CALL WITH: ; MOVEI J,JOB-TO-TEST ; PUSHJ P,ANYCPU ; RETURN HERE IF ON A CPU ; RETURN HERE IF NOT ON A CPU ANYCPU::MOVSI T2,(SP.CJA) ;CURRENT JOB ANYWHERE MASK TDNN T2,JBTSPS##(J) ;SEE IF JOB IN J IS ON THE OTHER CPU AOS (P) ;NOT--SKIP RETURN POPJ P, IFN FTLOCK,< ;SUBROUTINE TO COPY A PORTION OF THE USER'S MAP INTO ; ALL CPU'S MAPS ;CALLING SEQUENCE: ; MOVE T1,EXEC VIRTUAL PAGE NUMBER ; MOVE T2,NUMBER OF PAGES ; MOVE T3,USER VIRTUAL ADDRESS ; PUSHJ P,MAPUEC ; ALWAYS RETURN HERE MAPUEC::PUSHJ P,SAVE1## ;SAVE P1 MOVEI P1,.C0CDB## ;START AT CPU0'S CDB MAPUE1: CAME P1,.CPSLF## ;CURRENT CPU? IF SO, THE MAP IS ALREADY SET PUSHJ P,MAPCP ;COPY USER'S MAP TO CPU FOUND'S MAP HLRZ P1,.CPCDB##-.CPCDB##(P1) ;NEXT CPU'S CDB JUMPN P1,MAPUE1 ;DONE IF ALL CDB HAVE BEEN LOOKED AT POPJ P, ;RETURN MAPCP: PUSHJ P,SAVT## ;SAVE T ACCUMULATORS SO CAN CONTINUE ADD T1,.CPMAP##-.CPCDB##(P1) ;ADDRESS OF THE CURRENT CPUS MAP PJRST MAPUEI## ;GO COPY MAP TO MAP ;SUBROUTINE TO MAP A PAGE OF A JOB BEING LOCKED INTO ; ALL CPU'S MAPS ;CALLING SEQUENCE: ; MOVE P1,BYTE POINTER TO CPU'S MAP(P3) ; MOVE T3,CONTENTS OF UPMP MAP SLOT ; PUSHJ P,MAPUC ; ALWAYS RETURN HERE ;PRESERVES T1 MAPUC:: PUSHJ P,SAVE4## ;SAVE P1-P4 MOVEI P4,.C0CDB## ;START AT CPU0'S CDB MAPUC1: MOVE P3,.CPMAP##-.CPCDB##(P4) ;ADDRESS OF CURRENT CPU'S MAP DPB T3,P1 ;STORE MAP CONTENTS IN THAT CPUS EPT HLRZ P4,.CPCDB##-.CPCDB##(P4) ;NEXT CPU JUMPN P4,MAPUC1 ;LOOP OVER ALL CPUS POPJ P, ;AND RETURN > ;SUBROUTINE TO INSURE THAT ALL BUT THE BOOT CPU ARE IN THE ACS BEFORE ; CHANGING THE EXEC MAP. ;CALL: PUSHJ P,CP1STP ; RETURN HERE IF SOME OTHER PROCESSOR STILL RUNNING ; RETURN HERE IF ALL OTHERS IN THE ACS ;PRESERVES ALL ACS CP1STP::PUSHJ P,SAVE2## ;SAVE P1-P2 MOVEI P1,.C0CDB## ;START AT CPU0'S CDB MOVEI P2,SR.ACL ;GET "IN AC LOOP" BIT CP1ST1: CAME P1,.CPSLF## ;POINTING AT OURSELF? SKIPL .CPOK##-.CPCDB##(P1) ;NO, THIS CPU STILL RUNNING? JRST CP1ST2 ;NO, IT PASSES TDNN P2,.CPSBR##-.CPCDB##(P1) ;THIS CPU IN THE AC'S? POPJ P, ;NO CP1ST2: HLRZ P1,.CPCDB##-.CPCDB##(P1) ;GET ADDRESS OF NEXT CDB JUMPN P1,CP1ST1 ;LOOP IF MORE PJRST CPOPJ1## ;GIVE SKIP RETURN SUBTTL MULTIPROCESSING KL10 CACHE CONTROL IFN FTKL10,< ;ROUTINE FOR SCHEDULER TO CHECK THE STATE OF THE CACHE FOR A JOB ; SKIP RETURN MEANS OK, NON-SKIP MEANS JOB IS NOT RUNNABLE ON THIS ; CPU BECAUSE OF CACHE. CALL IS: ; ; MOVE J, ; PUSHJ P,SCDCSH ; ; ; IF ERROR RETURN WAS GIVEN, .CPCLN IS INCREMENTED (# TIMES SCHEDULER ; COULD NOT RUN A JOB BECAUSE OF CACHE) AND .CPCLF IS SET TO THE JOB'S ; NUMBER (POTENTIALLY LOST TIME BECAUSE OF CACHE) SCDCSH::PUSHJ P,CHKCSH ;CHECK STATE OF CACHE JRST CPOPJ1## ;OK, RETURN AOS .CPCLN## ;NOT OK, SCHEDULER HAS TO IGNORE AGAIN MOVEM J,.CPCLF## ;IN CASE NOTHING ELSE IS RUNNABLE POPJ P, ;RETURN AND SAY RUN SOMEONE ELSE ;ROUTINE TO SET UP JBTST3 AND JBTCSN WITH CDB ADDRESS AND CURRENT ; SWEEP SERIAL NUMBER USING CDB IN P4. ; CALL: ; MOVE U, ; MOVE J, ; MOVE P4, ; PUSHJ P,SETCSN ; ; ;CALLED BY CLOCK1 AFTER COMPLETION OF CONTEXT SWITCHING FROM OLD JOB. ; NOT CALLED FOR CONTEXT SWITCH FROM NULL JOB ; MUST BE CALLED INSIDE CPU INTERLOCK ; ANY CACHE SWEEP DONE ON A CPU AFTER THIS ROUTINE IS CALLED ON ; THAT CPU WILL CAUSE JOB THAT THIS ROUTINE WAS CALLED FOR TO BE ; RUNNABLE W.R.T. CACHE ON ANOTHER CPU SETCSN::MOVE T1,.CPSLF## ;THIS CPUS CDB HRRM T1,JBTST3##(U) ;SETUP CDB ADDRESS CONSO APR,LP.CSB+LP.CSD ;SWEEP IN PROGRESS TDZA T1,T1 ;NO, NEXT ONE WILL MAKE JOB RUNNABLE MOVEI T1,1 ;YES, REQUIRE ONE MORE TO BE RUNNABLE ADD T1,.CPCSN## ;COMPUTE SWEEP SERIAL # MOVEM T1,JBTCSN##(U) ;SAVE FOR LATER USE BY SCHED1 POPJ P, ;RETURN ;ROUTINE TO CHECK THE STATE OF CACHE FOR A JOB, CALLED BY SWAPPER ; JUST BEFORE IT IS TO SWAP OUT A JOB OR SEGMENT. ; SKIP RETURN MEANS OK, NON-SKIP MEANS JOB IS NOT SWAPPABLE W.R.T. CACHE. ; CALL IS: ; ; MOVE J, ; PUSHJ P,SWPCSH ; ; ; ; IF ERROR RETURN IS GIVEN, .CPCSD IS INCREMENTED, WHICH IS THE ; NUMBER OF TIMES THE SWAPPER WAS DELAYED FROM SWAPPING A JOB OUT ; BECAUSE OF THE CACHE. SWPCSH::CAILE J,JOBMAX## ;IS THIS A LOWSEG? JRST CPOPJ1## HRRZ T3,JBTST3##(J) ;CDB ADDRESS OF CPU JOB LAST RAN ON JUMPE T3,CPOPJ1## ;CORE 0 IS ALWAYS OK CAMN T3,.CPSLF## ;LAST RUN HERE PUSHJ P,MLSCSH ;YES, DO WE NEED TO WORRY ABOUT THE CACHE PUSHJ P,CHKRCH ;DO THE REAL WORK JRST CPOPJ1## ;EVERY THING IS BEAUTIFUL ; (IN ITS OWN WAY) AOS .CPCSD## ;INCREMENT SWAPPER CACHE DELAY COUNT POPJ P, ;BECAUSE SWAPPER HAS BAD NEWS COMING ;ROUTINE TO CHECK THE STATE OF THE CACHE FOR A JOB ; CALLED ONLY BY SCDCSH, SWPCSH ; CALL: ; MOVE J, ; PUSHJ P,CHKCSH ; ;JOB IS RUNNABLE, SWAPPABLE W.R.T. CACHE ; ;CACHE MUST BE SWEPT ON ANOTHER CPU FOR THIS JOB ; ; SMASHES T3,T4 SBCCSH::PUSHJ P,SBSCD ;GET SCHEDULAR INTERLOCK CHKCSH::HRRZ T3,JBTST3##(J) ;GET CDB ADDR OF LAST CPU JOB RAN ON JUMPE T3,CPOPJ## ;ZERO MEANS SOMEONE SPECIFICALLY GAVE ; THE OK NOT TO SWEEP CACHE CAMN T3,.CPSLF## ;WAS LAST CPU SAME AS THIS ONE? POPJ P, ;YES, ALL IS OK CHKRCH: MOVE T4,.CPCSN##-.CPCDB##(T3) ;NO, MUST CHECK CURRENT SWEEP NUMBER ON OLD CPU CAMLE T4,JBTCSN##(J) ; AGAINST SWEEP NUMBER ON OLD CPU WHEN JOB LEFT IT POPJ P, ;CURRENT SERIAL NUMBER IS LARGER, OLD CPU ; HAS SWEPT SO JOB IS RUNNABLE, SWAPPABLE ;JOB CANNOT BE RUN OR SWAPPED, SO PUT IN A REQUEST TO THE OLD CPU ; TO SWEEP ITS CACHE. MOVEM T4,.CPCSR##-.CPCDB##(T3) ;.CPCSN CAN NEVER BE LESS THAN JBTCSN, SO ; NOW WE KNOW THAT .CPCSN AND JBTCSN ARE EQUAL. ; OTHER CPU WILL SWEEP IF REQUEST IS EQUAL ; OR GREATER IN VALUE THAN CURRENT SWEEP NUMBER ; ON THAT CPU JRST CPOPJ1## ;INDICATE THAT JOB CANNOT BE DEALT ; WITH NOW. ;ROUTINE TO CLEAR JOB'S CACHE SWEEP SERIAL NUMBER DATA, INDICATING ; THAT NO SWEEP NEED BE DONE BEFORE THE JOB SWITCHES CPUS ; CALLED FROM KLSER, COMCON WHEN JOB THROWS AWAY OLD CORE IMAGE. ; CALL: ; MOVE J, ; PUSHJ P,CLCSN ; ; ; RESPECTS ALL ACS CLCSN:: CAIG J,JOBMAX## ;CHECK FOR HIGH SEGMENT NUMBER HLLZS JBTST3##(J) ;JUST CLEAR OUT CDB ADDRESS, MAKING ; JBTCSN ENTRY INVALID POPJ P, ;RETURN ;ROUTINE TO SERVICE CACHE SWEEP REQUEST. CALLED BY ; CLOCK1 BEFORE SCHEDULER IS CALLED SO THAT ; SWEEP REQUESTS CAN BE SERVICED BY ANOTHER CPU BEFORE IT ; ENTERS THE SCHEDULER. ; IF A SWEEP IS DONE, .CPCRN IS INCREMENTED CSREQS::MOVE T1,.CPCSN## ;GET CURRENT SWEEP NUMBER PUSHJ P,CHKNDS ;SEE IF A SWEEP IS NEEDED POPJ P, ;NO REQUESTED CACHE SWEEP THIS TICK CLRPGT ;CLEAR HARDWARE PAGE TABLE AS WELL SINCE EXEC ; MAP MIGHT HAVE CHANGED AS WELL CAML T1,.CPCSW## ;FORCED SWEEP BECAUSE MAPS CHANGED STILL NEED ; TO BE DONE? SETZM .CPCSW## ;NO, GET ANYONE WAITING FOR SWEEP TO GO AGAIN PUSHJ P,CHKNDS ;STILL NEED A SWEEP? POPJ P, ;NO AOSA .CPCRN## ;YES, EQUAL(HAPPENS) OR GREATER (NEVER HAPPENS) ; INCREMENT COUNT OF SWEEPS DONE BY REQUEST ;FALL INTO "CTXSWP", ALWAY SWEEP ;ROUTINE TO ANTICIPATE THE NEED FOR A CACHE SWEEP FOR ANOTHER CPU ; CALLED IN CLOCK1 AFTER OLD JOB'S CONTEXT IS SAVED (IF APPLICABLE) ; AND AFTER SETCSN IS CALLED SO THAT IF A CACHE SWEEP IS DONE IT ; WILL MAKE THE JOB IN QUESTION RUNNABLE ON ANOTHER CPU. ; NOTE THAT IT IS CALLED INSIDE INTERLOCK SO THAT MASTER CPU ; WILL NEVER HAVE TO REQUEST A CACHE SWEEP FOR A JOB THAT DID A ; MASTER UUO ON SLAVE BY GETTING TO SCHEDULER BEFORE CSHUUO IS ; CALLED BY SLAVE. ; A SWEEP IS DONE IF LAST JOB RUN WAS ON ; SLAVE CPU AND DID A UUO WHICH MUST BE EXECUTED ON MASTER. HOPEFULLY, ; THIS SAVES CPU0 FROM WAITING FOR CPU1 TO RUN NULL JOB (COULD BE A WHILE) ; OR SERVICING SWEEP REQUEST (COULD TAKE SEVERAL TICKS, SINCE ITS DONE AT ; PI 7 CTXSWP::PUSHJ P,MLSCSH SWPUA POPJ P, ;SUBROUTINE TO CHECK IF A SWEEP REQUESTED SWEEP MUST BE DONE. IF .CPCSW.NE.0, ; FORCES AT LEAST A CLRPGT. CALL WITH T1=CURRENT SWEEP NUMBER, SKIPS IF SWEEP ; MAY BE NEEDED CHKNDS: CAMLE T1,.CPCSR## ;REQUESTED SWEEP NEEDED? SKIPE .CPCSW## ;OR A FORCED SWEEP? AOS (P) ;YES, SWEEP IS LIKELY TO BE NEEDED POPJ P, ;RETURN ;SUBROUTINE TO SEE IF MONITORS LOW SEGMENT IS CACHED MEANING WE ARE DOWN ; TO ONE PROCESSOR. ;RETURNS: CPOPJ IF NOT CACHED ; CPOPJ1 IF CACHED MLSCSH::PUSH P,T1 ;SAVE T1 MOVSI T1,(ST%LSC) ;LOW SEGMENT CACHED BIT TDNE T1,CNFST2## ;IS IT AOS -1(P) ;YES, GIVE SKIP RETURN JRST TPOPJ## ;RESTORE T1 AND RETURN ;SUBROUTINE TO CALL SETCSN WHEN THE JOB NUMBER ; IS IN J AND THE CONTENTS OF U IS UNKNOWN SETCSJ::PUSHJ P,SBSCD ;INTERLOCK PUSH P,U ;SAVE U MOVE U,J ;ARGUMENT FOR SETCSN PUSHJ P,SETCSN ;MAKE JOB UNRUNNABLE ON THE OTHER ; CPU UNTIL A SWEEP IS DONE PJRST UPOPJ## ;RESTORE U AND RETURN ;SUBROUTINE TO CAUSE HIGH SEGMENT PART OF ALL MAPS TO GET CHANGED WHEN UWP CHANGES ;CALLING SEQUENCE: ; MOVEI T1,PREVIOUS STATE OF UWP (0 IF OFF, 1 IF ON) ; MOVEI T2,ADDR OF HIGH SEG DATA BLOCK FOR SEGMENT THAT CHANGED ; PUSHJ P,CLRCSH ;ALWAYS RETURN HERE (CACHE BITS CLEARED OR SET AS APPROPRIATE) CLRCSH::SKIPLE J,.HBSGN(T2) ;JOB HAVE A HIGH SEGMENT? TLNN J,SHRSEG ; AND IS IT SHARABLE? POPJ P, ;NO, NOTHING TO DO TLNN J,UWPOFF ;IS THE HIGH SEGMENT WRITE PROTECTED? JRST CLRCWL ;YES, SEE IF ANY OTHER JOB HAS IT WRITE ENABLED CLRCWE: JUMPE T1,CPOPJ## ;NOTHING TO DO IF NOTHING CHANGED MOVEI T1,SETNCH ;SUBROUTINE TO SET NO CACHE BITS HRRZS J ;KEEP ONLY SEGMENT # PUSH P,J ;SAVE J PUSHJ P,HGHAPP## ;TURN ON NOCSH!REDOMP FOR ALL JOBS SHARING THIS SEGMENT POP P,J ;RESTORE SEGMENT # PUSHJ P,SAVE2## ;SAVE P1,P2 FOR ANYRN CLRCS1: MOVEI P1,.C0CDB## ;FIRST CDB CLRCS3: PUSHJ P,ANYRN ;SEE IF ANY OTHER RUNNING JOB IS USING THAT SEGMENT SKIPA T2,.CPJOB##-.CPCDB##(P1) ;YES, MUST WAIT; JOB NUMBER USING IT POPJ P, ;NO, EVERYTHING IS OK MOVSI T1,REDOMP ;HAS THE MAP BEEN REDONE FOR THE CPU1 JOB? TDNN T1,.HBSGN(P2) ; ... JRST [HLRZ P1,.CPCDB##-.CPCDB##(P1) ;NEXT CDB JUMPE P1,CPOPJ## ;ALL IS WELL JRST CLRCS3] ;CHECK NEXT CPU AS WELL MOVEI T1,1 ;NO, SLEEP A TIC PUSH P,J ;SAVE J MOVE J,.CPJOB## ;OUR JOB NUMBER PUSHJ P,SLEEP## ;WAIT A WHILE POP P,J ;RESTORE J (SEGMENT #) JRST CLRCS1 ;AND TRY AGAIN CLRCWL: JUMPN T1,CPOPJ## ;RETURN IF NOT CHANGING THE STATE OF UWP MOVEI T1,CHKUWP ;SUBROUTINE TO CHECK IF ANY OTHER JOB HAS UWPOFF PUSH P,J ;SAVE J PUSHJ P,HGHAPP## ;ANY OTHER JOB HAVE UWP OFF FOR THIS SEGMENT? JUMPL J,JPOPJ## ;EXIT IF SOME JOB HAS UWP OFF POP P,J ;GET HISEG AGAIN MOVEI T1,CLRNCH ;CLEAR NOCSH FOR ALL JOBS SHARING THIS SEGMENT PJRST HGHAPP## ;CAUSE MAPS TO BE REDONE WITH CACHE ON SETNCH: MOVSI T1,REDOMP!NOCSH ;DON'T CACHE THE HIGH SEG, CAUSE MAP TO BE REDONE IORM T1,.HBSGN(P2) ;SET BITS IN SEGMENT DATA BLOCK TLZ T1,NOCSH ;AND NOCSH BIT IORM T1,JBTSGN##(J) POPJ P, CHKUWP: MOVSI T1,UWPOFF ;IS USER WRITE PROTECT OFF? TDNE T1,.HBSGN(P2) SETZ J, ;YES, FLAG IT AND STOP SCAN POPJ P, CLRNCH: MOVSI T1,NOCSH ;DON'T CACHE IT ANDCAM T1,.HBSGN(P2) ;CLEAR NO CACHE BIT MOVSI T1,REDOMP ;REDO THE MAP BIT IORM T1,.HBSGN(P2) ;FLAG IT'S THIS SEGMENT IORM T1,JBTSGN##(J) ;CAUSE MAP TO BE REDONE WITH CACHE BITS ON POPJ P, ;SUBROUTINE TO CHECK TO SEE IF A JOB IS ATTACHING TO A SHARABLE ; WRITABLE HIGH SEGMENT (SEGMENT MUST HAVE BEEN JUST ATTACHED TO FOR JOB, ;I.E. FIRSTHIGH SEG DATA BLOCK IN CHAIN) CHKSWS::MOVE J,.CPJOB## ;CURRENT JOB HRRZ T2,JBTSGN##(J) ;GET ADDR OF SEGMENT DATA BLOCK SKIPLE J,.HBSGN(T2) ;GET SEGMENT # TLNN J,SHRSEG ; AND IS IT SHARABLE? POPJ P, ;NO, NOTHING TO DO MOVEI T1,CHKUWP ;ROUTINE TO LOOK FOR UWPOFF PUSHJ P,HGHAPP## ;SET IF ANY JOB HAS UWPOFF FOR THIS SEGMENT JUMPGE J,CPOPJ## ;IF SCAN COMPLETED, NO JOB HAS UWP OFF MOVE J,.CPJOB## ;JOB NUMBER IN QUESTION MOVSI T1,REDOMP!NOCSH ;FORCE MAP TO BE REDONE UNCACHED IORM T1,.HBSGN(T2) ;... TLZ T1,NOCSH ;FORCE MAP WITH NO CACHE IORM T1,JBTSGN##(J) ;UNCACHE HIGH SEGMENT IN THIS JOB'S MAP POPJ P, ;AND RETURN ;SUBROUTINE TO UNCACHE A PAGE OF THE EXEC ADDRESS SPACE ON ALL CPU'S ; IN THE SYSTEM ;CALLING SEQUENCE: ; MOVE T2,BYTE POINTER TO EXEC MAP SLOT RELOCATED BY .CPMAP ; LDB T3,T2 ; TDZE T3,[PM.CSH] ;VERIFIY PAGE IS CACHED ; PUSHJ P,UNCACH ;ITS CACHED, UNCACHE IT ; ALWAYS RETURNS HERE, T3 INTACT ; UNCACH::PUSHJ P,SAVE4## ;SAVE WORKING ACS SE1ENT ;MUST BE IN SECTION 1 TO REFERENCE PAGTAB DMOVE P2,T2 ;SAVE ARGUMENTS MOVSI P1,(ST%LSC) ;LOW SEGMENT IS CACHED BIT TDNE P1,CNFST2## ;IS THE LOW SEGMENT CACHED? (ONLY ONE CPU RUNNING) JRST [ANDI P3,17777 ;ISOLATE PAGE NUMBER MOVSI P1,TNCSHB ;TEMPORARY UNCACHED BIT SSX P3,MS.MEM ;PAGTAB SECTION IORM P1,PAGTAB(P3) ;LITE IN CASE CPU GETS "ADDED" POPJ P,] ;RETURN, LEAVING CACHE ON FOR NOW PUSH P,T1 ;SAVE T1 PUSHJ P,FIXOTB ;FIXUP OUCHE TABLE SUB P2,.CPMAP## ;UNRELOCATE, RELOCATED DIFFERENTLY BELOW TLO P2,P4 ;BYTE POINTER INDEXED BY P4 MOVEI T1,UNCACC ;ROUTINE TO REALLY DO THE WORK PUSHJ P,CPUAPP## ;UNCACHE THE PAGE IN EVERY CPU'S MAP MOVE T3,P3 ;RESTORE MAP CONTENTS JRST TPOPJ## ;AND RETURN ;SUBROUTINE TO STORE A PAGE IN A MAP AND INSURE THAT ALL CPU'S SEE THE NEW MAPPING STMPEC::SKIPA P4,.CPEPT##-.CPCDB##(P1) ;ADDRESS OF THIS CPU'S EPT ;SUBROUTINE TO UNCACHE A PAGE IN EVERY CPU'S MAP UNCACC: MOVE P4,.CPMAP##-.CPCDB##(P1) ;ADDRESS OF THIS CPU'S EXEC MAP DPB P3,P2 ;STORE MAPPING IN THIS CPU'S MAP (PM.CSH OFF) SKIPLE ONCCOM## ;IF IN ONCE ONLY PUSHJ P,UUOLVL## ;OR AT UUO LEVEL, POPJ P, ;DON'T WAIT FOR OTHER CPUS MOVE P4,.CPCSN##-.CPCDB##(P1) ;CURRENT CACHE SWEEP SERIAL NUMBER ON THIS CPU ADDI P4,2 ;ONE MORE SWEEP AND IN CASE ONE COULD BE IN PROGRESS MOVEM P4,.CPCSW##-.CPCDB##(P1) ;REQUEST THAT CPU TO SWEEP MOVSI T1,-1 ;MAKE HIM NON-CONTRL-CABLE ADDM T1,JBTCCC##(J) ;.. UNCAC1: SKIPGE .CPOK##-.CPCDB##(P1) ;DON'T WORRY ABOUT CPUS THAT AREN'T RUNNING SKIPN .CPCSW##-.CPCDB##(P1) ;HAS HE SWEPT YET? JRST DECCCC## ;LET HIM ^C NOW MOVEI T1,0 ;0 SLEEP TIME (1 TIC) PUSHJ P,SLEEPF## ;WAIT FOR HIM TO SWEEP JRST UNCAC1 ;NO, WAIT SOME MORE ;SUBROUTINE TO FIXUP OUCHTB WHEN TURNING OFF THE CACHE FOR SOME PAGE ; SO THAT OUCHE ALWAYS REFERENCES THROUGH EIGHT CACHED PAGES ;MUST BE CALLED IN SECTION 1 IN A KL PAGING MONITOR FOR THE REFERENCE ; TO PAGTAB FIXOTB: PUSHJ P,SAVE4## ;ONLY REASON THIS IS A SUBROUTINE MOVE P1,[POINT 36,MONORG##/PAGSIZ] ADD P1,.CPMAP## ;POINT AT THIS CPU'S MAP MOVEI P2,MONORG##-PAGSIZ ;STARTING VIRTUAL ADDRESS ANDI P3,17777 ;PAGE CACHE IS BEING TURNED OFF FOR MOVEI P4,10 ;NEED 8 CACHED PAGES FIXOT1: ADDI P2,PAGSIZ ;NEXT VIRTUAL ADDRESS CAML P2,MONVFF## ;RUN OUT OF MONITOR PAGES? STOPCD CPOPJ##,JOB,N8C,;++NOT 8 CACHED PAGES ILDB T1,P1 ;NEXT PAGE TDNN T1,[PM.CSH] ;IS IT CACHED? JRST FIXOT1 ;NO, CAN'T USE IT ANDI T1,17777 ;JUST THE PHYSICAL PAGE NUMBER SSX T1,MS.MEM ;PAGTAB SECTION MOVE T2,PAGTAB(T1) ;PAGTAB ENTRY TLNN T2,TNCSHB ;DON'T USE THIS PAGE IF IT MIGHT GET UNCACHED CAIN P3,(T1) ;IS IT THE PAGE THATS BEING UNCACHED? JRST FIXOT1 ;YES, CAN'T USE THAT PAGE EITHER HRRM P2,OUCHTB##-1(P4) ;OUCHE CAN USE THIS VIRTUAL ADDRESS SOJG P4,FIXOT1 ;FIND A TOTAL OF 8 CACHED PAGES POPJ P, ;ALL DONE, RETURN ;ROUTINE TO HANDLE SETUUO #40 (.STCSB) ; SET/CLEAR CACHE BITS FOR TEMPORARILY UNCACHED PAGED SETCSB::PUSHJ P,SAVE3## ;SAVE P1,P2,P3 SE1ENT ;MUST BE IN SECTION 1 TO REFERENCE PAGTAB AND CALL FIXOTB MOVE P1,NCPRUN## ;NAME OF RUNNABLE CPU'S SOJG P1,ECOD0## ;FAIL IF MORE THAN 1 HRRZ P1,.CPMAP## ;ADDRESS OF THE SECTION ZERO MAP MOVE T4,[POINT 36,(P1)] ;BYTE POINTER TO IT MOVE P2,SYSSIZ## ;LAST ADDRESS LSH P2,W2PLSH ;P2=# OF PAGES TO DO PUSHJ P,SETCS1 ;SET/CLEAR CACHE FOR THE LOW SEGMENT MOVE T4,[POINT 36,MONORG/PAGSIZ(P1)] MOVE P2,MONVFF## ;LAST LOCATION OF DATA BEYOND HIGH SEGMENT SUBI P2,MONORG ;NUMBER OF WORDS ALLOCATED LSH P2,W2PLSH ;CONVERT TO PAGES OF MONITOR HIGHSEG PUSHJ P,SETCS1 ;CLEAR/SET CACHE BITS FOR LDB'S, ETC... MOVE T4,[POINT 36,.EVCDB##/PAGSIZ(P1)] MOVEI P2,CDBPGS## ;NUMBER OF CDB PAGES PUSHJ P,SETCS1 ;SET/CLEAR CACHE BIT IN POINTERS MAPPING THE CDB MOVE P3,.CPEPT## ;OUR EPT ADDI P3,<(MS.FMD)>+1 ;START AT SECTION 3 (SKIP EXTENDED HIGH SEGMENT) SETCB1: SKIPE T1,SECTAB(P3) ;A SECTION MAP? TLNN T1,(PM.CSH) ;YES, ALLOW FOR AN UNCACHED SECTION JRST SETCB2 ;SKIP THIS SECTION MOVE T3,.CPMAP## ;MAKE MAP ADDRESSABLE MOVEM T1,.EUPMP/PAGSIZ(T3) CLRPT .EUPMP MOVE T4,[POINT 36,.EUPMP] MOVEI P2,^D512 ;ALL THE PAGES IN THE SECTION MOVE T1,.CPEPT## ;ADDRESS OF OUT EPT CAIN P3,MXSECN(T1) ;SECTION 37? JRST [ADDI T4,UMAPS/PAGSIZ ;YES, SECTION 37 IS SPECIAL MOVEI P2,PAGSIZ-UMAPS/PAGSIZ ;NUMBER OF PAGES MAPPED JRST .+1] ;IN SECTION 37 PUSHJ P,SETCS1 ;SET/CLEAR BITS SETCB2: MOVE T1,.CPEPT## CAIGE P3,MXSECN(T1) ;LOOKED AT EVERY SECTION? AOJA P3,SETCB1 ;NO, LOOK ON CLRPGT ;LET HARDWARE SEE CHANGES MOVSI T1,(ST%LSC) ;LOW SEGMENT IS CACHED BIT TRNN T2,1 ;SETTING CACHE ON OR OFF SKIPA T2,[ANDCAM T1,CNFST2##] ;OFF, SET TO CLEAR BIT MOVE T2,[IORM T1,CNFST2##] ;ON, SET TO LIGHT BIT PUSHJ P,CSDMP## ;ALWAYS SWEEP THE CACHE XCT T2 ;SET/CLEAR BIT IN STATES PUSHJ P,FIXOTB ;MAKE SURE "OUCHE" WORKS JRST CPOPJ1## ;GIVE GOOD RETURN TO UUO SETCS1: ILDB T3,T4 ;GET MAP ENTRY JUMPE T3,SETCS3 ;IGNORE IF NOT MAPPED LDB T1,[POINT 3,T3,2] ;GET POINTER TYPE CAIN T1,PM.ICD ;IF INDIRECT, JUST DO IT JRST SETCS2 ; .. HRRZ T1,T3 ;GET PHYSICAL PAGE # ANDI T1,17777 ;ISOLATE PAGE NUMBER SSX T1,MS.MEM ;PAGTAB SECTION MOVE T1,PAGTAB(T1) ;GET BITS FOR PAGE TLNN T1,TNCSHB ;PAGE TEMPORARILY UNCACHED JRST SETCS3 ;NO, LEAVE IT ALONE SETCS2: TRNN T2,1 ;WANT CACHE ON OR OFF TDZA T3,[PM.CSH] ;OFF, CLEAR BIT TDO T3,[PM.CSH] ;ON, SET IT DPB T3,T4 ;PUT ENTRY BACK IN MAP SETCS3: SOJG P2,SETCS1 ;TRY NEXT PAGE POPJ P, ;RETURN >;END IFN FTKL10 ;ROUTINE TO HANDLE SETUUO #52 (.STPCP) ; SET POLICY CPU SETPCP::PUSHJ P,PRVJ## ;PRIVILEGED? SKIPA T1,T2 ;YES, PROCEDE - T1 = NEW POLICY CPU NUMBER JRST SETCP0 ;NO, ERROR RETURN CAMN T2,BOOTCP## ;ALREADY THE BOOT CPU? JRST CPOPJ1## ;OK, THAT'S ALL RIGHT CAIGE T1,M.CPU## ;CPU NUMBER IN RANGE? PUSHJ P,ONCPUS ;GET ON THAT CPU IF ITS RUNNING JRST SETCP4 ;NOT A LEGAL CPU OR CPU ISN'T RUNNING SKIPE MOFLPG## ;FLAG FREE? PUSHJ P,DELAY1## ;NO, WAIT UNTIL IT IS HRROM T1,MOFLPG## ;FLAG TO SAY CHANGING POLICY CPU TO US PUSHJ P,CP1STP ;SEE IF ALL OTHER CPUS ARE IN THEIR ACS JRST .-1 ;NO, GIVE THEM A CHANCE PUSHJ P,BECOM0 ;BECOME THE POLICY CPU SETZM MOFLPG## ;LET EVERYONE ELSE RUN AGAIN JRST CPOPJ1## ;TELL USER HE DID GOOD SUBTTL MULTIPROCESSING STOPCD PROCESSING ;ROUTINE TO WAIT FOR ANOTHER CPU TO FINISH PROCESSING A STOPCD. CALLED ;FROM APR INTERRUPT LEVEL ON EACH PROCESSOR IF INTDIE GOES POSITIVE. ;WAITS FOR ONE OF THE FOLLOWING EVENTS: ; 1. INTDIE GOES NEGATIVE ; 2. CRSHWD GOES NON-ZERO (GO DIRECTLY TO REBOOT IN THIS CASE) ; 3. INTDIE STAYS POSITIVE TOO LONG (CPU DIED IN DIE) ;CALL: PUSHJ P,CHKDIE ; CHKDIE::SKIPGE INTDIE## ;STILL LOCKED? POPJ P, ;NO, IGNORE SKIPN T1,DIEFLG## ;YES, DO WE KNOW WHY? JRST CHKDIE ;NO, WAIT FOR REAL ENTRY OR EXIT FROM DIE JUMPG T1,CPOPJ## ;YES, EXIT NOW IF MERELY AN EVENT CONO PI,PI.OFF ;NO, STOPCD, TURN OFF THE PI SYSTEM JSR .CPSVA## ;SAVE ALL AC SETS PUSHJ P,SAVT## ;SAVE T1-T4 PUSHJ P,RCDSTB## ;READ CPU AND DEVICE STATUS BLOCKS HRROS .CPSBR## ;INTERLOCK CALL AT REBOOT IFN FTKL10,< PUSHJ P,CSDMP## ;DUMP CACHE PUSHJ P,CHKDI1 ;CALL ROUTINE TO DO THE WORK JRST CHKDI5 ;AND EXIT CHKDI1: PUSHJ P,SVPPC## ;SAVE PROTOCOL, ENTER SECONDARY >; END IFN FTKL10 CHKDI2: MOVE T1,[^D25000000] ;WAIT THIS LONG FOR INTERLOCK TO CLEAR ;(ABOUT 45 SECONDS ON A MODEL B KL) CHKDI3: SKIPE CRSHWD ;RELOADING SYSTEM BECAUSE OF STOPCD? PJRST REBOOT## ;YES SKIPGE INTDIE## ;CPU FINISHED WITH STOPCD YET? JRST CHKDI4 ;YES SOJG T1,CHKDI3 ;NO, COUNT DOWN AND LOOP PUSHJ P,BRKDIE ;TOO LONG, BREAK INTERLOCK JRST CHKDI2 ;INSURE THAT ANOTHER WASN'T WAITING CHKDI4: HRRZS .CPSBR## ;LET STATUS BLOCKS BE READ AGAIN IFN FTKL10,< POPJ P, CHKDI5: > CONO PI,PI.ON ;TURN ON PI SYSTEM AGAIN POPJ P, ;AND RETURN ;ROUTINE TO SEE IF WE ARE THE LAST CPU RUNNING IN A MULTIPROCESSOR ;SYSTEM. ;CALL: PUSHJ P,LSTCPU ; ; ;PRESERVES ALL BUT T1 LSTCPU::MOVEI T1,.C0CDB## ;START AT CPU0 CDB LSTCP1: CAMN T1,.CPSLF## ;IS THIS ME? JRST LSTCP2 ;YES, DOESN'T COUNT SKIPGE .CPOK##-.CPCDB##(T1) ;THIS CPU STILL RUNNING? POPJ P, ;YES, AT LEAST ONE STILL RUNNING LSTCP2: HLRZ T1,.CPCDB##-.CPCDB##(T1) ;GET ADDRESS OF NEXT CDB JUMPN T1,LSTCP1 ;LOOP IF MORE JRST CPOPJ1## ;WE ARE THE ONLY ONE LEFT $LIT SUBTTL INITIALIZE CPU'S MAP FROM BOOT CPU'S MAP $LOW ;SUBROUTINE TO INITIALIZE THIS CPU'S MAP FROM BOOT CPU'S MAP ;NOTE THAT MAPINI WILL NOT HANDLE THE CASE OF CHANGING THE PAGE ;USED FOR A CPU'S CDB, BUT ODDS ARE THE CPU WOULDN'T BE ABLE TO ;GET HERE IN THE FIRST PLACE SO WHO CARES? MAPINI::SKPCPU (1) ;WE THE BOOT CPU? POPJ P, ;DO NOTHING PUSH P,T1 PUSH P,T2 PUSH P,T3 PUSH P,T4 ;FIRST COPY ALL DATA SECTION ENTRIES FROM THE BOOT CPU'S EPT. ;ALL DATA SECTIONS ARE IDENTICAL AMONG CPUS. IFN FTXMON,< MOVE T1,BOOTCP## ;CPU'S MAP TO COPY IMULI T1,.CPLEN## ;OFFSET INTO ITS CDB MOVE T1,.C0EPT##(T1) ;BOOT CPU'S EPT ADDI T1,<(MS.FMD)>+1 ;SKIP CODE SECTION POINTERS MOVE T2,.CPEPT## ;OUR EPT ADDI T2,<(MS.FMD)>+1 ;SKIP CODE SECTION POINTERS MOVEI T3,<(MS.FMD)>+1 ;FIRST SECTION WE'LL COPY MAPIN1: SKIPE T4,SECTAB(T1) ;SECTION POINTER FROM BOOT CPU'S MAP SKIPN .CPKPM## ;MCA25 INSTALLED? TLZA T4,(PM.KPM) ;NO, DON'T TURN ON "KEEP ME" IN SECTION POINTER TLO T4,(PM.KPM) ;YES, TAKE ADVANTAGE OF IT MOVEM T4,SECTAB(T2) ;STORE POINTER INTO OUR MAP AOS T1 ;NEXT SECTAB ENTRY AOS T2 ;... CAIGE T3,MXSECN-1 ;DONE EVERYTHING UP TO SECTION 37? AOJA T3,MAPIN1 ;NO, LOOP FOR REMAINDER ;FIXUP SECTION 37 MAPPING FOR PER-CPU CODE/DATA SECTIONS MOVE T1,.CPEPT## ;POINT TO OUR EPT ADDI T1,SECTAB ;OFFSET TO SECTION POINTERS HRLZS T1 ;PUT IN LH HRRI T1,.CPMMA## ;MAKE A BLT POINTER BLT T1,.CPMMA##+<(MS.FMD)> ;COPY POINTERS ;FIXUP SECTION 37 MAPPING FOR COMMON DATA SECTIONS MOVE T1,BOOTCP## ;CPU'S MAP TO COPY IMULI T1,.CPLEN## ;OFFSET INTO ITS CDB MOVSI T2,.C0MMA##+<(MS.FMD)>+1(T1) ;BOOT CPU'S SECTION MAPPING WORDS HRRI T2,.CPMMA##+<(MS.FMD)>+1 ;MAKE A BLT POINTER BLT T2,.CPMMA##+MXSECN-1 ;COPY POINTERS ;SET UP MAPPING FOR CDB IN S2 MOVE T3,.CPEPT## ;GET ADDRESS OF EPT HRRZ T3,SECTAB+<(MS.HGH)>(T3) ;GET PAGE NUMBER OF S2 MAP LSH T3,P2WLSH ;MAKE IT AN ADDRESS MOVE T4,.CPMAP## ;GET ADDRESS OF S0/S1 MAP MOVE T1,.EVCDB##/PAGSIZ(T4) ;GET MAPPING FOR CDB HRLI T3,-CDBPGS## ;NUMBER OF MAP ENTRIES TO COPY MOVEM T1,.EVCDB##/PAGSIZ(T3) ;STORE IN S2 MAP AOBJP T3,.+2 ;QUIT WHEN ALL CDB MAPPING HAS BEEN COPIED AOJA T1,.-2 ;LOOP FOR ANOTHER CLRPGT ;MAKE NEW MAPPING VISIBLE >; END IFN FTXMON ;NOW COPY MAPPING FOR NON-EVA CODE ADDRESSES FOR SECTIONS 0/1 AND 2 MOVEI T1,0 ;SECTION MAP TO COPY PUSHJ P,MAPINS ;DO IT IFN FTXMON,< MOVEI T1,(MS.HGH) ;SECTION MAP TO COPY PUSHJ P,MAPINS ;DO IT >; END IFN FTXMON IFN FTXMON,< > ;END IFN FTXMON POP P,T4 POP P,T3 POP P,T2 POP P,T1 POPJ P, ;RETURN ;HELPER ROUTINE FOR MAPINI TO COPY A CODE SECTION MAP. ;CALLED WITH T1 CONTAINING THE SECTION NUMBER. MAPINS: MOVE T3,.CPMAP## ;GET OUR MAP MOVE T2,BOOTCP## ;BOOT CPU'S CPU NUMBER IMULI T2,.CPLEN## ;OFFSET INTO ITS CDB MOVE T2,.C0EPT##(T2) ;ADDRESS OF ITS EPT ADD T2,T1 ;OFFSET FOR DESIRED SECTION MOVE T2,SECTAB(T2) ;GET SECTION TABLE ENTRY MOVEM T2,.EUPMP/PAGSIZ(T3) ;BOOT CPU'S SECTION MAP ADDRESSABLE VIA .EUPMP CLRPT .EUPMP ;MAKE NEW MAPPING VISIBLE ADD T1,.CPEPT## ;OFFSET OUR EPT ADDRESS FOR DESIRED SECTION MOVE T1,SECTAB(T1) ;GET SECTION TABLE ENTRY MOVEM T1,.ECKSM/PAGSIZ(T3) ;OUR SECTION MAP ADDRESSABLE VIA .ECKSM CLRPT .ECKSM ;MAKE NEW MAPPING VISIBLE MOVEI T3,0 ;STARTING AT THE BEGINNING OF THE MAP MAPIS1: MOVE T1,.EUPMP(T3) ;GET ENTRY FROM BOOT CPU'S SECTION MAP LDB T2,[POINT 3,T1,2] ;GET POINTER TYPE CAIE T2,PM.NCD ;NO ACCESS OR CAIN T2,PM.DCD ; DIRECT POINTER? JRST MAPIS2 ;YES, JUST STORE IT AS IS CAIE T2,PM.ICD ;INDIRECT IS ONLY OTHER TYPE WE KNOW OF STOPCD .,STOP,IPT, ;++ILLEGAL POINTER TYPE TRNN T1,777770 ;IS THIS AN SPTTAB INDEX? JRST MAPIS2 ;YES, NO ADJUSTMENT NEEDED MOVE T2,.CPCPN## ;OUR CPU NUMBER HRRI T1,SPTLOW##-SPTTAB##(T2) ;SPT INDEX MAPIS2: MOVEM T1,.ECKSM(T3) ;STORE ENTRY IN OUR SECTION MAP CAIGE T3,-1 ;DONE ALL CODE ADDRESSES? AOJA T3,MAPIS1 ;NO, LOOP FOR NEXT ENTRY CLRPGT ;MAKE NEW MAPPING VISIBLE POPJ P, ;RETURN SUBTTL TELL OPERATOR CURRENT CPU'S NAME ;ROUTINE TO TELL THE OPERATOR THE CURRENT CPUS NAME UPON STARTUP PRTCPU::MOVEI T1,[ASCIZ/ [/] ;START ON A NEW LINE WITH OPEN SQUARE BRACKET PUSHJ P,CTYTYP## ;TYPE THAT MOVE T2,.CPLOG## ;CPU'S LOGICAL NAME PRTCP1: MOVEI T1,0 ;ZERO PREVIOUS CHARACTER LSHC T1,6 ;SHIFT IN NEW CHARACTER MOVEI T3,40(T1) ;MAKE IT ASCIZ PUSHJ P,CTYWAT## ;TYPE IT JUMPN T2,PRTCP1 ;JUMP IF YET ANOTHER SIXBIT CHARACTER MOVEI T1,[ASCIZ/] /] ;CLOSE OFF WITH CLOSING SQUARE BRACKET AND NEW LINE PJRST CTYTYP## ;TYPE THAT SUBTTL ASSUME ROLE OF THE BOOT CPU ;SUBROUTINE TO ASSUME THE ROLE OF THE BOOT CPU ; CALLED WHEN THE BOOT CPU'S OK WORD FLIPPED FROM ; NEGATIVE TO ZERO (CALL IS INTERLOCKED BY BOOT CPU'S OK WORD) BECOM0::PUSHJ P,SAVT## ;SAVE THE T REGS SKIPL DEBUGF## ;DEBUGGING? JRST BECOM1 ;NO MOVE T1,DEBCPU## ;GET CPU WHICH MAY BECOME THE POLICY CPU CAME T1,.CPCPN## ;SAME AS ME? POPJ P, ;NOPE BECOM1::MOVSI T1,(1B0) ;GET BIT FOR BREAKPOINT ON CPU0 MOVN T2,BOOTCP## ;-BOOT CPU NUMBER LSH T1,(T2) ;SHIFT TO BIT FOR BOOT CPU TDNE T1,CPNDDT ;BOOT CPU AT A BREAKPOINT? POPJ P, ;YES, DON'T ASSUME THE ROLE SE1ENT ;ENTER SECTION 1 PUSH P,U ;SAVE U MOVEI T1,LDRCTY## ;THIS IS THE CTY BIT MOVE U,BOOTCT## ;LINE NUMBER OF THE CTY ON THE CPU THAT DIED MOVE U,LINTAB##(U) ;ADDRESS OF THE LDB ANDCAM T1,LDBDCH##(U) ;ZAP, NO LONGER THE CTY HRRZ T2,.CPCTN## ;OUR CTY LINE NUMBER MOVEM T2,BOOTCT## ;MAKE IT THE "CTY" MOVE T2,LINTAB##(T2) ;LDB FOR OUR CTY CAMN U,OPRLDB## ;WAS "OPR" THE CTY ON THE CPU WHICH WENT AWAY? MOVEM T2,OPRLDB## ;YES, MAKE "OPR" BE OUR CTY IORM T1,LDBDCH##(T2) ;ZAP, WE'RE THE NEW CTY PUSH P,T2 ;SAVE NEW CTY LDB PUSHJ P,TTYNAM## ;MAKE TTY NAME FOR OLD CTY HRRZ U,LDBDDB##(U) ;FIND DDB ATTACHED SKIPE U ;IS THERE ONE MOVEM T2,DEVNAM(U) ;YES, CHANGE NAME MOVSI T1,'CTY' ;NAME OF NEW CTY POP P,T2 ;NEW CTY LDB HRRZ T2,LDBDDB##(T2) ;FIND ATTACHED DDB SKIPE T2 ;ANY DDB THERE MOVEM T1,DEVNAM(T2) ;YES, CHANGE IT IFN FTNET,< MOVE U,OPRLDB## ;GET LOCAL OPR LDB PUSHJ P,NETOPR## ;TELL NETSER IN CASE IT CHANGED JFCL ;ALWAYS SKIPS > POP P,U ;RESTORE U PUSH P,J ;SAVE J (NEED FOR MPYNRN) MOVE J,HIGHJB## ;FOR EVERY JOB IN THE SYSTEM MOVEI T1,SP.CP0 ;BIT FOR CPU0 (1B35) LSH T1,@.CPCPN## ;BIT FOR NEW POLICY CPU TRC T1,SP.CPA ;NOT RUNNABLE ANYWHERE BUT... MOVSI T2,(SP.ROP) ;FORCED TO POLICY CPU BIT TDNE T2,JBTSPS##(J) ;JOB FORCED? DPB T1,MPYNRN## ;YES, SET NEW NOT-RUNNABLE SOJG J,.-2 ;GET ALL THE JOBS POP P,J ;RESTORE J SETOM CLKNEW## ;RECOMP "SYSTEM" CLOCK QUEUE MOVE T1,BOOTCP## ;OLD "CPU0" IMULI T1,.CPLEN## ;TO CDB OFFSET MOVEI T1,.C0CDB##(T1) ;POINT TO CDB CAMN T1,.CPSLF## ;ARE WE ALREADY "CPU0" POPJ P, ;YES, SYSINI IS FIXING THE CTY SKIPL MOFLPG## ;DON'T BREAK LOCKS IF JUST CHANGING POLICY CPU PUSHJ P,BRKLO2 ;RETURN INTERLOCK MOVE T1,DATE## ;GET CURRENT UNIVERSAL DATE/TIME MOVEM T1,RSDTTM## ;SAVE FOR CRASH ANALYSIS MOVE T1,[BECOM7,,1] ;WHERE TO GO AND TIMER MOVE T2,.CPSLF## ;GET OUR CDB ADDRESS SYSPIF ;INTERLOCK CLOCK QUEUE ADDITIONS IDPB T1,CLOCK## ;SAVE TIMER+ROUTINE IDPB T2,CLOCK## ;AND DATUM+STATUS ;SETOM CLKNEW ;JUST DID THIS ABOVE SYSPIN ;ALLOW OTHERS AGAIN TDZA T1,T1 ;CALLED AFTER STARTUP BCOM0:: MOVEI T1,1 ;CALLED DURING STARTUP PUSH P,T1 ;REMEMBER HOW WE GOT HERE MOVE T1,.CPCPN## ;OUR CPU NUMBER MOVEM T1,BOOTCP## ;STORE AS NEW "CPU0" MOVE T1,.CPASN## ;OUR SERIAL NUMBER MOVEM T1,SERIAL## ;STORE IN OLD GETTAB MOVEI T1,.C0CDB## ;START OF THE CDB'S MOVE T2,.CPSLF## ;OUR OWN CDB BECOM2: MOVSI T3,(CAI) ;"SKPCPU(0)" FOR THIS CPU MOVSI T4,(CAIA) ;"SKPCPU(1)" CAMN T2,.CPSLF##-.CPCDB##(T1) ;LOOKING AT OURSELF EXCH T3,T4 ;YES, MAKE "SKPCPU(0)" WORK FOR US DMOVEM T3,.CPSK0##-.CPCDB##(T1) ;AND FIX SKIP CPU WORDS MOVEI T3,.CPOK##-.CPCDB##(T2) ;OUR OK WORD'S ADDRESS MOVEM T3,.CPOK1##-.CPCDB##(T1) ;POINT OK WORDS AT THIS CDB MOVEI T3,SSCAN## ;POLICY CPU SCHEDULER SCAN TABLE CAME T2,.CPSLF##-.CPCDB##(T1) ;LOOKING AT OURSELF MOVE T3,SSCN##(T3) ;NO, USE SECONDARY (REVERSED) TABLE MOVEM T3,.CPSCN##-.CPCDB##(T1) ;STORE SCAN TABLE ADDRESS HLRZ T1,.CPCDB##-.CPCDB##(T1) ;STEP TO NEXT CDB JUMPN T1,BECOM2 ;AND FIX IT UP POP P,T1 ;GET FLAG PJUMPE T1,SETEDV## ;RESET EDV IF NOT SYSINI POPJ P, ;RETURN ;HERE TO TYPE A MESSAGE FOR THE OPERATOR AT CLOCK LEVEL WHEN ASSUMING POLICY BECOM7: CAME T1,.CPSLF## ;IF CLOCK ENTRY WAS MADE BY A NOW-DEAD CPU, POPJ P, ;THEN IGNORE IT AND WAIT FOR OUR OWN SE1ENT ;THE ROUTINES WE CALL WILL APPRECIATE THIS PUSHJ P,FRCSET## ;SETUP U TO POINT TO FRCLIN PUSHJ P,INLMES## ASCIZ/SEND CTY / ;SEND MESSAGE TO NEW CTY MOVE T2,.CPLOG## ;GET NAME OF THIS CPU PUSHJ P,PRNAME## ;PUT INTO MESSAGE PUSHJ P,INLMES## ASCIZ/ has assumed the role of policy CPU on / ;TELL WHAT HAPPENED PUSHJ P,DATIME## ;ADD DATE/TIME PJRST PCRLF## ;END THE LINE AND RETURN XLIST ;DUMPED LITERALS LIT LIST $HIGH ;BACK TO THE HIGH SEGMENT SUBTTL BREAK SOFTWARE INTERLOCKS ;HERE WHEN BOOT CPU COUNTS ANOTHERS OK WORD TO 1 SEC ; ASSUME THAT THE CPU IS DOWN AND BREAK INTERLOCKS ;CALL T1=CDB OF THAT CPU BRKLOK::PUSHJ P,SAVT## ;SAVE THE T REGS SKIPL DEBUGF## ;DEBUGGING? JRST BRKLO1 ;NO MOVE T2,DEBCPU## ;GET ONLY CPU WHICH MAY BECOME POLICY CAME T2,.CPCPN## ;IS IT ME? POPJ P, ;NO BRKLO1: MOVSI T2,(1B0) ;GET BIT FOR CPU0 AT A BREAKPOINT MOVN T3,.CPCPN##-.CPCDB##(T1) ;-CPU NUMBER FOR CPU IN QUESTION LSH T2,(T3) ;SHIFT TO BIT FOR THAT CPU SKIPN MOFLPG## ;DON'T BREAK LOCKS IF SETTING MONITOR MEMORY OFF TDNE T2,CPNDDT ;CPU AT A BREAKPOINT? POPJ P, ;YES, DON'T BREAK INTERLOCKS BRKLO2: SETOM .CPDRQ##-.CPCDB##(T1) ;INDICATE DISKS NEED RESCUING PUSHJ P,BRKSI1 ;BREAK THE SOFTWARE INTERLOCKS MOVE T2,INODIE## ;CPU OWNING DIE INTERLOCK ANDI T2,ID.PSN ;ISOLATE SERIAL NUMBER CAMN T2,.CPASN##-.CPCDB##(T1) ;THIS CPU OWN THE DIE INTERLOCK? PUSHJ P,BRKDIE ;YES, BREAK IT IFN FTNET,< PUSHJ P,BRKFEK## ;DECLARE THE FEKS DOWN > IFN FTKL10,< MOVE T1,.CPCPN##-.CPCDB##(T1) ;GET NUMBER OF DYING CPU. IFN FTENET,< PUSHJ P,KNIDED## ;CLEAR KLNI ON DEAD CPU >; END IFN FTENET S0PSHJ KILDTE## ;CLEAR ALL DTE'S FOR THE DYING CPU >; END IFN FTKL10 POPJ P, ;ROUTINE TO RETURN THE SOFTWARE INTERLOCKS OWNED BY THIS CPU. ;CALL PUSHJ P,GIVLOK ; RETURN HERE ALWAYS GIVLOK::HRRZ T1,.CPSLF## ;GET ADDRESS OF OUR CDB PUSHJ P,BRKSIW ;BREAK THE LOCKS SETZM .CPNBI## ;WE KNOW WE JUST BROKE THEM POPJ P, ;RETURN ;ROUTINE TO BREAK THE SOFTWARE INTERLOCKS FOR A CPU THAT HAS GONE ;DOWN OR FROM A JOB STOPCD. ;CALL T1=CDB ADDRESS OF THE CPU BRKSIW: PUSHJ P,SAVT## ;SAVE T1-T4 BRKSI1: MOVE T2,.CPASN##-.CPCDB##(T1) ;GET APR ID OF DOWN CPU MOVEI T3,INTRLK## ;FIRST SYSTEM INTERLOCK BRKSI2: SKIPGE 0(T3) ;INTERLOCK TAKEN JRST BRKSI3 ;NO, LOOK AT NEXT MOVE T4,INTOLK##-INTRLK##(T3) ;OWNER OF THIS INTERLOCK ANDI T4,ID.PSN ;ISOLATE SERIAL NUMBER CAIE T2,(T4) ;THAT CPU OWN THE INTERLOCK JRST BRKSI3 ;NO, CONTINUE AOS .CPNBI##-.CPCDB##(T1) ;COUNT THE BROKEN INTERLOCK SETOM 0(T3) ;YES, FREE IT BRKSI3: CAIE T3,INTOLK##-1 ;DO LAST INTERLOCK AOJA T3,BRKSI2 ;NO, GET THEM ALL MOVE T4,INTLMO## ;CPU OWNING "MM" RESOURCE ANDI T4,ID.PSN ;ISOLATE SERIAL NUMBER CAIN T2,(T4) ;DOES IT OWN THE INTERLOCK PUSHJ P,[AOS .CPNBI##-.CPCDB##(T1) ;COUNT THE BROKEN INTERLOCK PJRST GIVMM] ;AND LET THE SWAPPER BACK IN; MOVE T2,.CPCPN##-.CPCDB##(T1) ;CPU NUMBER OF LOST CPU CAME T2,SCNOWN## ;DOES IT OWN SWAPPER RESOURCE POPJ P, ;NO, RETURN SETOM SCNOWN## ;YES, ALLOW SWAPPING AGAIN SETOM SCNCNT## ;... AOS .CPNBI##-.CPCDB##(T1) ;COUNT THE BROKEN INTERLOCK POPJ P, ;RETURN SUBTTL WAIT WHILE MEMORY IF BEING SET OFF-LINE ;ROUTINE TO WAIT IN THE AC'S WHILE MEMORY IS BEING SET OFF-LINE ;BY THE BOOT CPU. ACS MUST BE EXEC ACS AND MUST BE USABLE WITHOUT SAVING THEM. ;CALL: JRST CP1MFL ; RETURNS TO SAVPC2 IN CLOCK1 CP1MFL::CONO PI,PI.OFF ;TURN OFF PI SYSTEM IFN FTKL10,< PUSHJ P,CP1MF1 ;CALL ROUTINE TO WAIT JRST CP1MF3 ;AND JUMP AROUND CODE CP1MF1: SKIPL MOFLPG## ;DON'T SAY DEC10 NO RUNNING IF JUST POLICY SWITCHING PUSHJ P,SVPPC## ;SAVE PROTOCOL, ENTER SECONDARY PUSHJ P,CSDMP## ;INSURE IT'S ALL IN CORE > MOVEM P,.CPCA1##+P ;SAVE P BEFORE LOADING AC LOOP MOVE 6,[MFLOOP,,2] BLT 6,6 ;LOAD THE AC LOOP MOVEI 17,SR.ACL ;TELL OTHER CPU'S IORM 17,.CPSBR## ;THAT WE'RE IN THE AC'S JRST 2 ;AND GO THERE $LOW CP1MF2: MOVE P,.CPCA1##+P ;RESTORE P PUSHJ P,MAPINI ;MAP MAY HAVE CHANGED IFN FTKL10,< POPJ P, CP1MF3: > MOVEI 17,SR.ACL ;NO LONGER IN ANDCAM 17,.CPSBR## ; THE AC'S CONO PI,PI.ON ;TURN PI SYSTEM BACK ON JRST SAVPC2## ;RETURN $HIGH SUBTTL WAIT WHILE A CPU IS AT A BREAKPOINT ;ROUTINE TO WAIT IN THE AC'S WHILE ANOTHER CPU IS AT A BREAKPOINT. ;CALL: JRST CPNBPT ; RETURNS @.CPABK CPNBPT::CONO PI,PI.OFF ;TURN OFF PI SYSTEM JSR .CPSVA## ;SAVE ALL AC SETS MOVE P,.CPEPD## ;INSURE A PDL IS SETUP IFN FTKL10,< PUSHJ P,CPNBP1 ;CALL ROUTINE TO DO THE WORK JRST CPNBP3 ;AND SKIP THE SUBROUTINE CPNBP1: PUSHJ P,SVPPC## ;SAVE PROTOCOL, ENTER SECONDARY PUSHJ P,CSDMP## ;MAKE SURE IT'S ALL IN CORE > MOVE 6,[BPLOOP,,2] ;SETUP TO LOAD THE AC LOOP BLT 6,6 ;MOVE IN THE AC LOOP MOVEI 17,SR.ACL ;GET BIT TO TELL OTHERS THAT WE ARE IORM 17,.CPSBR## ;LOOPING IN THE AC'S JRST 2 ;AND GO WAIT $LOW CPNBP2: PUSHJ P,MAPINI ;INSURE THE MAP IS SETUP CORRECTLY IFN FTKL10,< POPJ P, ;RETURN FROM SUBROUTINE IF KL10 CPNBP3: > MOVEI 17,SR.ACL ;NO LONGER LOOPING ANDCAM 17,.CPSBR## ; IN THE AC'S HRLZ 17,.CPACA## ;WHERE TO RESTORE THE AC'S FROM BLT 17,17 ;RESTORE THEM ALL CONO PI,PI.ON ;TURN ON PI SYSTEM JRST APRABK## ;RETURN TO APR INTERRUPT PROCESSING $HIGH SUBTTL WAIT FOR SYSTEM RELOAD OR CPU RESTART ;HERE ON ALL CPU'S BUT THE BOOT CPU WITH THE AC'S AND MACHINE ;STATE SAVED TO LOOP IN THE AC'S WAITING FOR THE SYSTEM TO BE RELOADED ;OR FOR THE OPERATOR TO RESTART THE CPU. IF SR.DIE IS SET IN .CPSBR, ;THE PROCESSOR WILL NOT RESTART (EVEN AFTER A RELOAD) UNLESS THE ;OPERATOR MANUALLY STARTS IT AT 400. CP1CRS:: IFN FTKL10,< MOVE P,.CPEPD## ;INSURE STACK IS SETUP PUSHJ P,ENTSPC## ;ENTER SECONDARY PROTOCAL > MOVEI 17,SR.ACL ;GET LOOPING IN THE AC'S BIT IORM 17,.CPSBR## ; AND TELL OTHERS MOVEI T1,SR.DIE ;BIT TELLING US NOT TO RESTART TDNE T1,.CPSBR## ;SET FOR THIS CPU? PJRST RMVCPU## ;YES, JRST 1 FOREVER MOVE 12,[ACLOOP,,2] ;LOAD BLT POINTER TO AC LOOP BLT 12,12 ;LOAD THE AC LOOP JRST 2 ;JUMP INTO THE AC'S $LIT SUBTTL WAIT LOOPS LOADED INTO AC'S $LOW ;THE FOLLOWING LOOPS ARE LOADED INTO THE AC'S WHEN A CPU WANTS TO ;WAIT FOR AN EVENT. ACLOOP AND BP LOOP ARE BOTH ENTERED WITH AC ;17 CONTAINING SR.ACL. ACLOOP::MOVEI 1,20 ;2 INITIALIZE ITERATION COUNT MOVE 0,.CPOK## ;3 GET CURRENT .C1OK CAMN 0,.CPOK## ;4 SEE IF .C1OK HAS CHANGED JRST 4 ;5 NO, WAIT UNTIL IT DOES CHANGE AOS 0 ;6 COUNT OLD .C1OK BY ONE CAME 0,.CPOK## ;7 DID .C1OK INCREASE BY EXACTLY ONE JRST 2 ;10 NO, START OVER AGAIN SOJG 1,4 ;11 WAIT FOR 20 COUNTS TO BE SURE JRST SYSDSP## ;12 GO RESTART SLAVE BPLOOP: SKIPE CPNDDT ;2 IS DDT FINISHED YET? JRST 2 ;3 NO, LOOP TDNE 17,.CPSBR## ;4 IF NOT STILL SET, WE RELOADED JRST CPNBP2 ;5 RETURN TO CALLER JRST SYSDSP## ;6 GO RESTART CPU MFLOOP: SKIPE MOFLPG## ;2 MONITOR MEMORY SET OFF LINE YET? JRST 2 ;3 NO, LOOP TDNE 17,.CPSBR## ;4 IF NOT STILL SET, WE RELOADED JRST CP1MF2 ;5 RETURN TO CALLER JRST SYSDSP## ;6 GO RESTART CPU ;NOTE THAT WE ENTER AT 3 THE FIRST TIME, WITH 0 NON-0 ONCLOP::MOVE 0,.CPOK## ;1 RESYNCHRONIZE SKIPE 17 ;2 DID BOOTS ZERO CORE? MOVE 17,[1] ;3 NO. THIS LITERAL SHOULD BE RIGHT IF SAME MONITOR CAMN 0,.CPOK## ;4 WAIT TILL .CPOK COUNTS UP BY 1 JRST 2 ;5 DIDNT COUNT, WAIT A WHILE AOS 0 ;6 COUNTED. BY 1? CAME 0,.CPOK## ;7 JRST 1 ;10 NO, WAIT TILL IT COUNTS BY EXACTLY 1 MOVE 0,[1] ;11 IS THE LITERAL STILL INTACT? SOJN 0,1 ;12 NO, DIFFERENT MONITOR WAS LOADED JUMPE 17,SYSDSP## ;13 YES, 17=0 IF BOOTS RELOADED THE MONITOR SKIPE ONCCOM## ;14 ALL SEEMS OK. SOMETHING FOR US TO DO? JRST SPROIO## ;15 YES, GO DO WHAT CPU0 TELLS US JRST 1 ;16 NOTHING TO DO, WAIT SOME MORE LIT $HIGH SUBTTL MULTIPROCESSING COMMANDS AND UUOS ;CODE TO IMPLEMENT THE SETUUO'S NUMBER 14 (.STCPU) ;AND 15 (.STCRN) SETCRN::MOVEI T4,.C0CDB## ;ADDRESS OF FIRST CDB SETCR1: MOVE T3,.CPRUN##-.CPCDB##(T4) ;GET RUN BIT FOR CPU TRNE T2,1 ;CHECK BIT FOR CPU RUNNABILITY TLZA T3,(CR.NRN) ;CLEAR SIGN BIT TO ALLOW CPU TO RUN TLO T3,(CR.NRN) ;SET SIGNBIT TO TURN CPU OFF MOVEM T3,.CPRUN##-.CPCDB##(T4) ;PUT BACK IN CDB HLRZ T4,.CPCDB##-.CPCDB##(T4) ;GET ADDRESS OF NEXT CDB PJUMPE T4,CPOPJ1## ;NO ERROR RETURNS LSH T2,-1 ;MOVE NEXT BIT TO 35 JRST SETCR1 ;AND CHECK OUT THIS ONE .ERNAR==0 ;NONE ARE RUNNING ERROR CODE .ERDHP==1 ;DOESN'T HAVE PRIVILEGES ERROR ;ROUTINE TO HANDLE SETUUO #14 (.STCPU) USER SET ;CPU SPECIFICATION SETCPU::MOVSI T3,JP.CCC ;CAN CHANGE CPU SPECIFICATION BIT TDNE T3,JBTPRV##(J) ;USER PRIVILEGED TO CHANGE? JRST SETCP1 ;YES, PROCEED PUSHJ P,PRVJ## ;NO, IS HE [1,2] OR IS JACCT SET? JRST SETCP1 ;YES, OK TO PROCEED SETCP0: MOVEI T1,.ERDHP ;NO, GIVE ERROR RETURN PJRST STOTAC## ;WITH DOESN'T HAVE PRIVILEGE CODE SETCP1: MOVE T1,T2 ;HOLD BITS IN T1 MOVEI T4,.C0CDB## ;GET ADDRESS OF CPU0 CDB TRZ T2,777700 ;EXTRACT THE BITS WE WANT SETCP2: TRNE T2,1 ;DO WE CARE ABOUT THIS CPU? SKIPGE .CPRUN##-.CPCDB##(T4) ;YES, IS IT RUNNING? JRST SETCP3 ;NO, CHECK NEXT DPB T1,[POINT 6,JBTSPS##(J),35] ;YES, WE ARE SATISFIED. JRST CPOPJ1## ;AND SKIP RETURN SETCP3: HLRZ T4,.CPCDB##-.CPCDB##(T4) ;GET ADDRESS OF NEXT CDB JUMPE T4,SETCP4 ;IF NO MORE, ERROR LSH T2,-1 ;MOVE NEXT BIT INTO POSITION JRST SETCP2 SETCP4: MOVEI T1,.ERNAR ;GET NONE ARE RUNNING CODE PJRST STOTAC## ;GIVE TO USER AND CPOPJ ;ROUTINE TO HANDLE SETUUO #37 (.STCDN) ; SET CPU UP/DOWN STATUS SETCDN::HRRZ T1,T2 ;COPY CPU NUMBER TRZE T1,1B19 ;SUPPEND A CPU? JRST SETCD3 ;YES TRZN T1,1B18 ;ADD OR REMOVE A CPU JRST SETCD1 ;ADDING MOVE T3,[SOS T2,NCPRUN##] ;REMOVE, SET TO DECREMENT MOVE T4,NCPRUN## ;HOW MANY CPUS ARE LEFT SOJLE T4,ECOD0## ;CAN'T REMOVE THE LAST JRST SETCD2 ;JOIN COMMON PART SETCD1: MOVE T3,[AOS T2,NCPRUN##] ;ADD, SET TO BUMP COUNT MOVSI T4,(ST%LSC) ;LOW SEG CACHED BIT TDNN T4,CNFST2## ;CACHE RIGHT FOR ADDING SETCD2: CAIL T1,M.CPU## ;RANGE CHECK CPU NUMBER JRST ECOD0## ;CACHE WRONG OR BAD CPU IMULI T1,.CPLEN## ; TO CDB OFFSET FROM CPU0'S SKIPL T4,.C0RUN##(T1) ;GET RUN BITS FOR CPU TRNN T2,1B18 ;STILL RUNNABLE, TRYING TO ADD SKIPA ;YES, ALWAYS OK TO ADD A CPU JRST ECOD0## ;CPU STILL RUNNABLE, IGNORE TRNN T2,1B18 ;ADDING OR REMOVING IT TLZA T4,(CR.RMV) ;ADD, CLEAR "GO AWAY" BIT TLO T4,(CR.RMV) ;MARK FOR REMOVAL CAME T4,.C0RUN##(T1) ;DID WE CHANGE STATES XCT T3 ;YES, ADJUST COUNT OF CPUS MOVEM T4,.C0RUN##(T1) ;STORE NEW BITS IFN FTKL10,< CAIE T2,1 ;DOWN TO 1 CPU? SKIPA T2,[JRST SYSTOP##] ;NO, HAVE WARM RESTART=J407 MOVE T2,[JRST APRWRS##] ;YES, WR SHOULD DO ALL MOVEM T2,WRSINS ;STORE AS WHERE TO GO ON WR > JRST CPOPJ1## ; AND ALL DONE SETCD3: CAIL T1,M.CPU## ;LEGAL CPU NUMBER? JRST ECOD0## ;NO, ERROR RETURN IMULI T1,.CPLEN## ;OFFSET INTO THE APPROPRIATE CDB MOVSI T2,(CR.SPD) ;CPU IS TO BE SUPPENDED BIT IORM T2,.C0RUN##(T1) ;LITE THE BIT JRST CPOPJ1## ;TELL THE USER HE DID GOOD ;HERE FROM CLOCK1 WHEN ITS TIME TO REMOVE THIS CPU OR ON A CPU STOPCODE CPUCMD::PUSHJ P,SAVE1## ;SAVE P1 MOVSI P1,JP.CCC ;GET CAN CHANGE CPU SPECIFICATION BIT PUSHJ P,SETLGL## ;IS THIS THE OPR OR A [1,2] JOB, TDNE P1,JBTPRV##(J) ; OR DOES THE JOB HAVE PRIVILEGES? JRST CPUCM1 ;YES, PROCEED PJSP T1,ERRMES## ;NO, ERROR MESSAGE ASCIZ /No privileges to SET CPU / CPUCM1: PUSHJ P,CTEXT## ;GET NEXT ARGUMENT MOVE P1,T2 ;SAVE IN P1 PUSHJ P,CPUFND ;SEE IF IT IS CPXN JRST CPUCM2 ;NO, GET REST OF COMMAND IORM T3,JBTSPS##(J) ;WAS SET CPU CPXN, BITS IN T3 JRST CPUCM5 ;AND RETURN CPUCM2: PUSHJ P,CTEXT## ;GET NEXT ARGUMENT JUMPE T2,CPUCM4 ;NO MORE, MUST BE SET CPU ALL PUSHJ P,CPUFND ;FIND CPU AND SET MASK BITS PJRST COMERR## ;NOT FOUND, ERROR CAME P1,[SIXBIT /NO/] ;WAS THIRD ARGUMENT "NO"? JRST CPUCM3 ;NO, CHECK OTHERS ANDCAM T3,JBTSPS##(J) ;YES, CHANGE SPECIFICATION JRST CPUCM5 ;AND RETURN CPUCM3: CAME P1,[SIXBIT /ONLY/] ;WAS THIRD ARGUMENT ONLY? PJRST COMERR## ;NO, ERROR DPB T3,[POINT 12,JBTSPS##(J),35] ;CHANGE SPECIFICATION JRST CPUCM5 ;AND RETURN. CPUCM4: CAME P1,[SIXBIT/ALL/];ARGUMENT #3 MUST BE "ALL" PJRST COMERR## ;WASN'T, ERROR MOVEI T3,7777 ;GET BITS FOR ALL POSSIBLE CPU'S DPB T3,[POINT 12,JBTSPS##(J),35] ;CHANGE SPECIFICATION CPUCM5: PUSHJ P,CPRONE ;CHECK TO SEE IF NEW SPECIFICATION IS VALID PJRST CPOPJ1## ;AND RETURN ;SUBROUTINE TO DETERMINE IF CPU DESIGNATOR IN SET CPU COMMAND ;IS LOGICAL OR PHYSICAL CPU NAME. IF PHYSICAL, MAKE SURE IT EXISTS AND ;SET UP BIT MASK FOR JBTSPS. CALLED WITH SIXBIT ARGUMENT IN T2, ;CPU NUMBER RETURNED IN T1, T2 RETURNED WITH ORIGINAL ARGUMENT, BIT MASK ;RETURNED IN AC T3. T4 RESPECTED. CPUFND::HLLZ T1,T2 ;GET LEFT MOST 3 CHARACTERS CAMN T1,[SIXBIT /CPU/] ;IS ARGUMENT LOGICAL NAME? JRST CPUFN2 ;YES, DOESN'T MATTER IF IT EXISTS MOVEI T3,.C0CDB## ;GET ADDRESS OF FIRST CDB CPUFN1: CAMN T2,.CPPHY##-.CPCDB##(T3) ;THIS CPU? JRST CPUFN2 ;YES, OK TO PROCEED HLRZ T3,.CPCDB##-.CPCDB##(T3) ;GET ADDRESS OF NEXT CDB JUMPE T3,CPOPJ## ;NON-SKIP RETURN IF NON EXISTANT JRST CPUFN1 ;GO LOOK AT NEXT CPUFN2: HRRZ T1,T2 ;CPU NAME OK, MAKE A BIT MASK LSH T1,-14 ;GET SIXBIT NUMBER RIGHT JUSTIFIED SUBI T1,20 ;REDUCE TO BINARY CAIG T1,5 ;LEGAL CPU NUMBER? SKIPGE T1 ; POPJ P, ;ERROR RETURN IF NON EXISTANT MOVEI T3,101 ;MASK FOR CPU0 LSH T3,(T1) ;POSITION MASK JRST CPOPJ1## ;AND GIVE FOUND RETURN ;SUBROUTINE CALLED BY SIMCHK IN CLOCK1 TO SEE IF JOB WITH EXEC ;MODE PC HAS A RUNNABLE CPU SPECIFICATION. RETURN CPOPJ IF NONE, CPOPJ1 IF RUNNABLE CPSCHK::PUSHJ P,CPRBIT ;SET UP MASK OF RUNNING CPU'S TDNN T2,JBTSPS##(J) ;SKIP IF JOB HAS A RUNNABLE CPU POPJ P, ;NO RUNNABLE CPU'S, STOP JOB MOVE T2,JBTSPS##(J) ;PICK UP SECOND PROCESSOR STATUS TLNE T2,(SP.CC1) ;SKIP IF CONTROL C NOT ON CPU1 TLNE T2,(SP.NR1) ;WAS ON CPU1, SKIP IF NOT IN MIDDLE OF UUO JRST CPOPJ1## ;IS RUNNABLE, CATCH AT UUO EXIT TRNN T2,SP.CR0 ;SINCE CAN'T RUN ON CPU1, SKIP IF RUNNABLE ONCPU0 POPJ P, ;IS NOT RUNNABLE, STOP JOB. JRST CPOPJ1## ;JOB IS RUNNABLE, DEFER STOPPING. ;SUBROUTINE TO BUILD A BIT MASK FOR TESTING JBTSPS ENTRIES. AN ;APPROPRIATE BIT IS SET FOR EACH RUNNING CPU. RETURNS MASK IN T2. CPRBIT: MOVEI T4,.C0CDB## ;GET ADDRESS OF FIRST CDB MOVEI T3,1 ;GET BIT INDICATING CPU0 IS RUNNING SETZ T2, ;CLEAR T2 CPRBT1: SKIPL .CPRUN##-.CPCDB##(T4) ;SKIP IF CPU NOT RUNNING ADD T2,T3 ;SET BIT IN MASK HLRZ T4,.CPCDB##-.CPCDB##(T4) ;GET ADDRESS OF NEXT CDB JUMPE T4,CPOPJ## ;EXIT IF THROUGH LSH T3,1 ;MOVE BIT TO NEXT POSITION JRST CPRBT1 ;AND LOOK AT NEXT CPU ;SUBROUTINE TO CHECK IF A JOB IS RUNNABLE ON ANY PROCESSOR CALLED ;WITH MASK OF RUNNING PROCESSORS IN AC T2 AND JOB NUMBER TO CHECK IN J. CPRONE: PUSHJ P,CPRBIT ;SET UP MASK OF RUNNING CPU'S CPRCHK: TDNE T2,JBTSPS##(J) ;SKIP IF NO RUNNABLE CPU FOR THIS JOB POPJ P, ;OK, RETURN SKIPE U,TTYTAB##(J) ;GET TTY DDB MOVE U,DDBLDB##(U) ;LDB ADDRESS JUMPE U,CPOPJ## ;NO MESSAGE IF NO TTY PJSP T1,CONMES## ;PRINT MESSAGE TO USER AND CPOPJ ASCIZ /%No Running CPUs in specification / CPRMIN: PUSHJ P,CPRBIT ;GET MASK FOR TESTING JBTSPS SKIPLE J,HIGHJB## ;GET HIGHEST USED JOB NUMBER ; -1 IF NO JOBS HAVE LOGGED IN YET PUSHJ P,CPRCHK ;CHECK TO SEE IF RUNNABLE ON SOME CPU SOJG J,.-1 ;NEXT? POPJ P, ;NO, EXIT SUBTTL DIAG. UUO INTERFACE CPUDIA::EXP MCSEC1+CPUPPR ;PREPROCESSOR ROUTINE DIAFNC (SDS,CPUSDS,CPUSDS) ;SET DEVICE STATUS DIAFNC ;TERMINATE TABLE CPUPPR: JRST (P3) ;GO PROCESS DIAG. UUO ;SET DEVICE STATUS CPUSDS: PUSHJ P,GETWD1## ;GET NEXT ARGUMNET CAIL T1,0 ;RANGE CAILE T1,SDSLEN ; CHECK JRST DIAABA## ;BAD ARGUMENT LIST MOVE T2,T1 ;PUT IN A BETTER PLACE MOVEI T1,(U) ;COPY CPU NUMBER PJRST @SDSTAB(T2) ;GO SET STATUS SDSTAB: IFIW DIAABA## ;SET IGNORE IFIW DIAABA## ;CLEAR IGNORE IFIW CPUDTU ;SET DETACHED IFIW CPUATU ;SET ATTACHED SDSLEN==.-SDSTAB ;LENGTH OF TABLE $LIT ;GENERATE LITERALS SO CAN CHECK ASCII OCTAL CPNEND: END