Trailing-Edge
-
PDP-10 Archives
-
tops10v704_mpe
-
10,7/mon/cpnser.mac
There are 11 other files named cpnser.mac in the archive. Click here to see a list.
TITLE CPNSER - SECOND PROCESSOR CONTROL V512
SUBTTL M. CHURCH - LNS/MIT P. HURLEY - DEC/JMF/TW/CDO/GMU/TARL 23-AUG-88
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.
;ALL RIGHTS RESERVED.
.CPYRT<1973,1988>
XP VCP1SR,512 ;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, ;++<X> OUT OF RANGE IN ONCPU<X>
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<IO,,0>] ;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 <MOVS T2,-1(T1)> ;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,<SP.CPA>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"
MOVE T1,P1 ;COPY CDB ADDRESS
HRLI T1,.CSCAT ;CODE FOR ATTACH
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,<PUSHJ P,SSEC0##> ;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"
MOVE T1,P1 ;CDB ADDRESS TO T1
HRLI T1,.CSCDT ;CODE FOR DETACH
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:
; MOVE T1,[CODE,,CDB ADDRESS
; PUSHJ P,CPUCSC
; ALWAYS RETURN HERE
CPUCSC: PUSH P,U ;SAVE U
PUSH P,F ; AND F
MOVEI F,0 ;NO DDB ADDRESS FOR THIS ERROR
MOVEI U,.CPLOG##-.CPCDB##(T1) ;U POINTS AT CPU NAME
HRRI T1,.ERCSC ;ERROR CODE FOR DAEMON
PUSHJ P,DAEEIM## ;NOTIFY DAEMON
JRST FUPOPJ## ;RESTORE F AND U AND RETURN
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<SP.CR0>-^L<SP.CJ0>> ;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,<JOB NUMBER>
; PUSHJ P,SCDCSH
; <JOB NOT RUNNABLE W.R.T. CACHE>
; <JOB RUNNALBE W.R.T. CACHE>
; 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,<OLD JOB NUMBER>
; MOVE J,<NEW JOB NUMBER>
; MOVE P4,<CDB ADDRESS>
; PUSHJ P,SETCSN
; <ONLY RETURN>
;
;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,<SEGMENT NUMBER>
; PUSHJ P,SWPCSH
; <JOB CANNOT BE SWAPPED BECAUSE OF CACHE>
; <OK TO SWAP JOB>
;
; 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,<JOB NUMBER>
; PUSHJ P,CHKCSH
; <SUCCESSFUL RETURN> ;JOB IS RUNNABLE, SWAPPABLE W.R.T. CACHE
; <ERROR RETURN> ;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,<JOB NUMBER>
; PUSHJ P,CLCSN
; <ONLY RETURN>
;
; 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
PUSHJ P,DELAY1## ;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
; <RETURN HERE ON EVENTS 1 AND 3>
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
; <RETURN HERE IF OTHERS RUNNING>
; <RETURN HERE IF WE ARE THE ONLY ONE>
;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,<HLCSAD##/PAGSIZ>-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
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
PUSHJ P,PCRLF## ;AND A CRLF
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
;RESET EDV STUFF 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