Google
 

Trailing-Edge - PDP-10 Archives - bb-jr93k-bb - 10,7/mon/monpfh.mac
There are 10 other files named monpfh.mac in the archive. Click here to see a list.
	TITLE	MONPFH	DEFAULT PAGE FAULT HANDLER	V074
	SUBTTL	Tarl Neustaedter/TARL		14 MAR 89

	SEARCH F,S
	$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 1984,1986,1988.
;ALL RIGHTS RESERVED.

.CPYRT<1984,1988>


	XP	VPFH,074
	ENTRY	PFH

	Comment @

	Loose ends outside of this module

GETWRY, make it understand FLTSX returning success
PUTWRY, make it understand FLTSX returning success, and test for write
	locked loseg pages (spy pages).
	@


PTRTYP:	POINT 3,T1,2		;BPT TO EXTRACT TYPE OF PAGE MAP POINTER
PTRIPT:	POINT 9,T1,17		;INDIRECT INDEX INTO PAGE


;Stack offsets used in range-checking cannot-be-paged-out ('CBPO') pages.

PFPJLB==-1		;.JBINT BLOCK BEGIN PAGE
PFPJLE==-0		;.JBINT BLOCK END PAGE
PFPILE==-3		;I/O RANGE BEGIN PAGE
PFPILB==-2		;I/O RANGE END PAGE
PFPBPT==-4		;DDT'S UNSOLICITED BREAKPOINT TRAP ADDRESS
PFPOFS==-5		;OFFSET ON STACK

PFPPLB==PFPOFS-1	;PSI VECTOR BEGIN PAGE
PFPPLE==PFPOFS-0	;PSI VECTOR END PAGE
PFPOFS==PFPOFS-2	;OFFSET ON STACK

;Called from USRFL1. Page fault, no PFH loaded.
;Relevant ACs, T3/ KL form page fail word or zero if time fault
;
;Return
;	CPOPJ,	No implicit access to page, ill mem ref
;	CPOPJ1,	Page is now accessible.

PFH::
IFN FTNET,<NTDBUG NO,EITHER>	;MAKE SURE WE DON'T HAVE THE NETSER INTERLOCK
	SE1ENT			;XADDR
	JUMPE	T3,PFHTIM	;TIME FAULT, DON'T WORRY ABOUT FAULT WORDS
	TDNN	T3,[MXSECN,,777000] ;MAKE SURE OUT OF PAGE ZERO
	STOPCD	.,JOB,PFHZER, 	;++ PAGE FAULT ON PAGE ZERO
	DMOVE	T1,.USPFP	;PC OF LAST PAGE FAULT (IF FROM USRFLT)
	DMOVEM	T1,.USPFF	;SAVE AS PFH PAGE FAULT PC
	PUSHJ	P,SAVE1##	;SOMEWHERE TO PRESERVE PAGE FAULT WORD
	MOVE	P1,T3		;ADDRESS DESIRED
	AOS	T1,.USPFU	;UP COUNT OF PAGE FAULTS
	CAIL	T1,^D1000	;ALLOW UP TO ONE THOUSAND PAGE FAULTS WITHOUT
	JRST	PFHABO		;  FINISHING UUO.
	MOVE	T1,.USLFT	;LAST FAULT TIME
	JUMPE	T1,PFH1		;JUMP IF NOT FIRST FAULT FOR THIS PROGRAM
	PUSHJ	P,FNDPDS##	;ADDRESS OF THE PDB
	SKIPE	.PDTMI##(W)	;IF USER SUPPLIED A VALUE,
	JRST	PFH1		; USE IT INSTEAD
	MOVEI	T1,M.PFHT##	;TICS BEFORE A TIME FAULT
	HRRZM	T1,.PDTMC##(W)	;STORE IN THE TIME COUNTER
	HRRM	T1,.PDTMI##(W)	;AND INCREMENT
PFH1:	PUSHJ	P,PFHPAG	;PAGE THE PAGE IN
	  POPJ	P,		;NO CAN DO, GIVE AN ILL MEM REF
PFHEXI:	TLNN	P1,(PF.BAD)	;WAS THIS A MONITOR UUO?
	JRST	PFHEX2		;NO, RE-EXECUTE THE INSTRUCTION
	DMOVE	T1,.JDAT+JOBPD1## ;[GETPC] GET RETURN PC OF UUO
	SUBI	T2,1		;DECREMENT TO PC OF UUO
	DMOVEM	T1,.USPFF	;[PUTPC] STASH AS PC TO RETURN TO
	CAIA			;SKIP INTO FINAL RETURN TO USER
PFHEX2:	SETZM	.USPFU		;CLEAR RECURSION TRAPPER SINCE USER PAGE FAULT
	USERAC			;SET THE AC SET TO USER
	XJEN	.USPFF		;RETURN TO USER PC
;Here on lots of page faults - assume the worst

PFHABO:	SETZM	.USPFU		;ZERO FAULT COUNTER (GIVE HIM A CHANCE)
	TLO	P1,400000	;PRETEND WE PAGED SOMETHING OUT
	PUSHJ	P,TTYFUW##	;SET UP FOR TYPEOUT ON USER'S TERMINAL
	PUSHJ	P,INLMES##	;TYPE OUT A MESSAGE
	ASCIZ	\?
?Page fault loop. Try larger core limit and type CONTINUE
\
	PUSHJ	P,HOLD0##	;STOP JOB IN CONTINUABLE STATE
	PUSHJ	P,WSCHED##
	JRST	PFHEXI		;AND EXIT, TO RE-EXECUTE PAGE FAULT INSTRUCTION
;Here on a timer fault
;Return non-skip so TIMFLT will return to user

PFHTIM:	MOVEI	T1,(J)		;GET JOB # IN T1
	PUSHJ	P,FPDBT1##	;GET ADDRESS OF PDB
	  POPJ	P,		;THIS IS ALL UNINTERESTING IF NONE
	HLRZ	T1,.PDMVL##(T1)	;GET JOB'S MAXIMUM VIRTUAL LIMIT
	JUMPE	T1,CPOPJ##	;IF NONE, CAN'T PAGE ANYWAY SO DON'T DO THIS
	PUSHJ	P,SAVE4##	;SAVE SOME P REGISTERS
	PUSHJ	P,PGRUPD##	;UPDATE PAGE RATES
	SETOB	P2,P3		;NO LAST PAGE, NO STARTING PAGE
	SETZ	P4,		;SECTION 0 IN CASE NOT A BIG USER
;Set up for range checks for cannot-be-paged-out ('CBPO') pages
	ADJSP	P,-PFPOFS	;MAKE ROOM FOR LIMIT BI-WORDS
	PUSHJ	P,GETJLM	;GET RANGE OF PAGES FOR JOBINT BLOCK
	DMOVEM	T1,PFPJLB(P)	;SET UP FOR CBPO RANGE CHECK
	PUSHJ	P,GETBLM	;GET BREAKPOINT TRAP PAGE
	MOVEM	T1,PFPBPT(P)	;SAVE FOR CBPO RANGE CHECK
	PUSHJ	P,GETPLM	;FIND RANGE OF PAGES FOR PSI VECTOR
	DMOVEM	T1,PFPPLB(P)	;SET UP FOR CBPO RANGE CHECK
;Page out all pages with AA off and turn off AA for all pages in core
	PUSH	P,[-1]		;FLAG OF WHETHER IOWAIT CALLED
	SKIPL	.USBTS		;BIG USER?
	JRST	PFHTI4		;NO, NO NEED TO LOOK AT EXTENDED SECTIONS
	MOVEI	P4,MXSECN	;SECTIONS MXSECN THROUGH 1
PFHTI1:	SKIPE	T1,.UPMP+SECTAB(P4) ;NEXT SECTION POINTER
	TLNE	T1,(<<PM.DCD^!PM.ACD>B2>) ;INDEPENDENT SECTION?
	JRST	PFHTI3		;NON-EXISTANT OR INDIRECT, MOVE ON TO NEXT
	MOVE	T1,P4		;SECTION NUMBER
	IMULI	T1,WSBTBL	;COMPUTE WHICH WSBTAB TO USE
	MOVEI	T1,.WSBNZ-WSBTBL(T1)
	MOVEI	T2,HLGPNO	;HIGHEST PAGE IN THE SECTION
	PUSHJ	P,NXTWSP	;FIND THE HIGHEST PAGE IN THE SECTION
	  JRST	PFHTI3		;THERE AREN'T ANY
	PUSHJ	P,TOUTPG	;PAGE OUT THE PAGE IF AA OFF
	  PUSHJ	P,TCLRAA	;CLEAR AA IF IN CORE AND NOT CBPO PAGE
PFHTI2:	PUSHJ	P,NXTWSC	;GET NEXT PAGE IN SECTION
	  JRST	PFHTI3		;NO MORE LEFT
	PUSHJ	P,TOUTPG	;PAGE OUT THE PAGE IF AA OFF
	  PUSHJ	P,TCLRAA	;CLEAR AA IF IN CORE AND NOT CBPO PAGE
	JRST	PFHTI2		;NEXT PAGE
PFHTI3:	SOJG	P4,PFHTI1	;NEXT SECTION
;Here to do section zero
PFHTI4:	MOVEI	T1,WSBTAB	;SECTION ZERO WORKING SET TABLE
	MOVEI	T2,HLGPNO	;HIGHEST PAGE IN THE SECTION
	PUSHJ	P,NXTWSP	;GET HIGHEST PAGE IN THE SECTION
	  JFCL			;THERE HAS TO BE AT LEAST 1, NAMELY PAGE 0
	JUMPE	T2,PFHTI6	;DONE IF THATS THE ONLY PAGE
	PUSHJ	P,TOUTPG	;PAGE OUT THE PAGE IF AA OFF
	  PUSHJ	P,TCLRAA	;CLEAR AA IF IN CORE AND NOT CBPO PAGE
PFHTI5:	PUSHJ	P,NXTWSC	;GET NEXT WORKING SET PAGE
	  JRST	PFHTI6		;CAN'T HAPPEN
	JUMPE	T2,PFHTI6	;ALL DONE IF THIS IS PAGE 0
	PUSHJ	P,TOUTPG	;PAGE OUT THE PAGE IF AA OFF
	  PUSHJ	P,TCLRAA	;CLEAR AA IF IN CORE AND NOT CBPO PAGE
	JRST	PFHTI5		;LOOP OVER ALL PAGES IN SECTION 0
PFHTI6:	ADJSP	P,PFPOFS-1	;THROW AWAY RANGE CHECK WORDS ON STACK
	SETZ	P1,		;FLAG END
	PUSHJ	P,OUTPAG	;AND FLUSH ANY PENDING PAGES
	PJRST	ADJANA##	;ADJUST .USANA AND RETURN
;Clear access allowed if possible
TCLRAA:	MOVE	T2,@[IW MS.MAP,UMAPS(P1)]
	TLC	T2,(PM.COR!PM.AAB) ;ALL THESE BITS MUST BE ON
	TLCE	T2,(PM.COR!PM.AAB!1B1) ;WERE THEY?
	POPJ	P,		;NOPE, TRY NEXT PAGE
	CAME	P1,PFPJLB-2(P)	;IS THIS FIRST PAGE OF .JBINT BLOCK?
	CAMN	P1,PFPJLE-2(P)	;OR LAST PAGE OF .JBINT?
	POPJ	P,		;YES, LEAVE IT ALONE
	CAMN	P1,PFPBPT-2(P)	;IS THIS THE BREAKPOINT TRAP ADDRESS?
	POPJ	P,		;YES, CAN'T PAGE OUT
	CAML	P1,PFPPLB-2(P)	;IS THIS PAGE BELOW RANGE OF PSI VECTOR
	CAMLE	P1,PFPPLE-2(P)	;OR ABOVE IT?
	TRNA			;NOT IN RANGE OF PSI VECTOR
	POPJ	P,		;IN PSI VECTOR, LEAVE IT ALONE
	PUSHJ	P,SAVT##	;SAVE VOLATLE ACS
	AOSG	-6(P)		;CALLED IOWAIT ALREADY?
	S0PSHJ	IOWAIT##	;NO, WAIT FOR ALL I/O TO STOP BEFORE DINKING BITS
	MOVSI	T2,(<PM.DCD>B2!PM.AAB) ;CLEAR ACCESS ALLOWED
	ANDCAM	T2,@[IW MS.MAP,UMAPS(P1)] ;CLEAR THE BITS
	MOVE	T2,P1		;PAGE NUMBER
	LSH	T2,P2WLSH##	;VIRTUAL ADDRESS
	EXCTUU	<CLRPT (T2)>	;FLUSH PAGING MEMORY'S REMEMBERANCE OF THIS PAGE
	AOS	.USANA		;INCREMENT INACCESSIBLE PAGES
	POPJ	P,		;RETURN

;Output page if access allowed off (returns CPOPJ1 if a page was paged out)
TOUTPG:	MOVE	P1,P4		;SECTION NUMBER
	LSH	P1,S2PLSH	;POSITION IT TO SECTION NUMBER FIELD
	IOR	P1,T2		;PAGE NUMBER
	MOVE	T2,@[IW MS.MAP,UMAPS(P1)]
	TLC	T2,(PM.COR)	;INVERT PAGE-IN-CORE BIT
	TLNE	T2,(PM.COR!1B1!PM.AAB) ;IS IT IN CORE AND AA OFF?
	POPJ	P,		;NO
	PUSHJ	P,SAVT##	;YES, SAVE VOLATILE ACS AND FALL INTO OUTPAG
	AOS	(P)		;SKIP CALL TO TCLRAA
;	PJRST	OUTPAG		;PAGE OUT THIS PAGE
;OUTPAG - Utility routine for PFHTIM.
;Call
;	P1/ Page to page out
;or	P1/ -1 indicating we should flush cache
;	P2/ Last page OUTPAG was called for
;	P3/ First page in current group
;return
;	Non skip always

OUTPAG:	AOJLE	P2,OUTPA1	;PREINCREMENT LAST PAGE CALLED
	CAIN	P2,(P1)
	POPJ	P,		;YES, RETURN
	MOVE	T1,[XWD 0,JOBUAL##] ;PAGE. ARG BLOCK
	MOVE	T2,P3		;FIRST PAGE THAT WILL BE DONE
	SUB	T2,P2		;MAKE IT NEGATIVE COUNT OF PAGES TO DO
	MOVE	T3,P3		;STARTING PAGE TO PAGE OUT
	TLO	T3,(PG.GAF)	;FLAG PAGES ARE TO GO OUT
	PUSHJ	P,DOPAGE	;PAGE THEM OUT
OUTPA1:	JUMPE	P1,CPOPJ##	;(FLUSH CALL)
	HRRE	P3,P1		;SET UP FIRST PAGE IN GROUP
	HRRE	P2,P1		;SET UP LAST PAGE IN GROUP
	POPJ	P,		;RETURN
;Subroutine to find the next bit in a table scanning table from right to left.
; Call first time at NXTWSP, T1=address of table, T2=starting bit position
; within table, call subsequent times at NXTWSC with T1, T3, and T4 preserved
; from previous call. Returns CPOPJ1 with T2=position of next non-zero bit in
; the table, CPOPJ if no more bits.

NXTWSP:	MOVEM	T1,.USTMP+5	;SAVE ADDRESS OF TABLE
	MOVE	T3,T2		;STARTING BIT POSITION
	IDIVI	T3,^D36		;WORD WITHIN THE TABLE
	ADD	T3,T1		;WHERE TO START IN THE TABLE
	SUBI	T4,^D35		;NUMBER OF BITS TO THE LEFT
	MOVE	T1,(T3)		;GET STARTING WORD FROM TABLE
	LSH	T1,(T4)		;POSITION IT (STARTING BIT = LSB)
	MOVMS	T4		;BIT NUMBER
	JRST	NXTWSC		;SEE IF THERE ARE INY IN THIS WORD
NXTWP1:	SKIPN	T1,(T3)		;NEXT WORD, DOES IT CONTAIN ANY BITS?
	JRST	NXTWP2		;NO
	SETZ	T4,		;YES, STARTING AT THE LSB
NXTWSC:	JUMPE	T1,NXTWP2	;JUMP IF NO MORE BITS IN THIS WORD
	LSHC	T1,-1		;SHIFT LSB INTO SIGN BIT OF T2
	JUMPL	T2,NXTWP3	;JUMP IF THE BIT IS ON
	AOJA	T4,NXTWSC	;COUNT THIS ZERO BIT AND NEXT BIT
NXTWP2:	CAMLE	T3,.USTMP+5	;LOOKED AT ENTIRE TABLE?
	SOJA	T3,NXTWP1	;NO, LOOK ON
	POPJ	P,		;NO BITS FOUND
NXTWP3:	MOVEI	T2,1(T3)	;CALCULATE BIT POSITION WITHIN TABLE
	SUB	T2,.USTMP+5	;WORD WITHIN TABLE
	IMULI	T2,^D36		;36 BITS PER WORD
	SUBI	T2,1(T4)	;SINCE REALLY COUNTING FROM 1 TO 44
	AOJA	T4,CPOPJ1##	;NEXT BIT NEXT TIME
;PFHPAG - Page in a page which has caused a page fault
;Call
;	P1/ Page fail word (direct from .USPFW)
;Return
;	RET	Can't do, no room, no such page
;	RETSKP	page is accessible
;

PFHPAG:	LDB	T3,[POINT UPGWID,P1,26] ;GET VIRTUAL PAGE NUMBER
	MOVE	T1,T3		;COPY TO T1
	LSH	T1,P2SLSH	;GET SECTION #
	SKIPN	.UPMP+SECTAB(T1) ;DOES SECTION EXIST?
	POPJ	P,		;NO, DON'T GENERATE A SECOND PAGE FAULT
	ADD	T3,[MS.MAP+UMAPS];POINT TO PAGE MAP ENTRY FOR PAGE
	SKIPN	T1,(T3)		;GET PAGE MAP ENTRY
	POPJ	P,		;ILL MEM REF IF PAGE IS NON-EXISTANT
	TDNN	T1,[PM.ADR-PM.ZER];ALLOCATED BUT ZERO PAGE?
	JUMPN	T1,PFHABZ	;YES, CREATE IT.
	LDB	T2,PTRTYP       ;GET TYPE OF POINTER
	JUMPN	T2,CPOPJ##	;[PM.NCD] IF POINTER EXISTS, NOTHING TO DO
	TLNN	T1,(PM.COR)	;PAGE IN CORE?
	JRST	PFHOUT		;NOPE, IT'S PAGED OUT.
	TLNN	T1,(PM.AAB)	;ACCESS ALLOWED ON?
	JUMPN	T1,PFHAAF	;YES, IS ACCESS ALLOWED FAULT
	POPJ	P,		;NOT SOLVABLE FAULT
;Here when page is allocated but zero.
;Call
;	P1/ Virtual address desired (With some flags)
;Return
;	CPOPJ,  no room for page.
;	CPOPJ1, page has been allocated.
;

PFHABZ:	PUSHJ	P,CHKLIM	;GET US ENOUGH ROOM TO CREATE THE PAGE
	  JRST	PFHABO		;LOOP IN PFH
	DMOVE	T1,[1,,JOBUAL##	;.PAGCD,,AC 1
		   1]		;ONE PAGE
	LDB	T3,[POINT UPGWID,P1,26] ;GET PAGE NUMBER
	PUSHJ	P,DOPAGE	;CREATE THE PAGE
	SETZM	.USPFU		;RESTART PAGE FAULT COUNT--WE'RE NOT LOOPING YET
	JRST	PFHXCN		;COUNT FAULT AND EXIT
;Here when page has access allowed turned off
;Call
;	P1/ Virtual address desired (with some flags)
;	T3/ Pointer to map slot
;Return
;	CPOPJ, never.
;	CPOPJ1, aa turned on

PFHAAF:	PUSHJ	P,SAVE1##	;P1 NEEDS TO BE PRESERVED
	SOS	.USANA		;DECR NO OF NOT-ACCESSABLE PAGES
	MOVSI	T2,(<PM.DCD>B2+PM.AAB) ;ACCESS ALLOWED
	IORM	T2,(T3)		;TURN ON IN PAGE MAP ENTRY
	TLZ	P1,-1-MXSECN	;CLEAR EXTRANEOUS BITS
	EXCTUU	<CLRPT (P1)>	;REFRESH PAGER'S ASSOC MEMORY, THIS PAGE ONLY
	PUSHJ	P,ADJANA##	;ADJUST .USVRT
	JRST	PFHXCI		;COUNT FAULT AND RETURN TO USER
;Here when page is paged out
;Call
;	P1/ Virtual address desired (with some flags)
;Return
;	CPOPJ,  no room for page
;	CPOPJ1, page has been paged in

PFHOUT:	PUSHJ	P,CHKLIM	;MAKE ROOM FOR PAGE WE WILL HAVE TO PAGE IN
	  JRST	PFHABO		;LOOP IN PFH
	DMOVE	T1,[0,,JOBUAL##  ;.PAGIO,,AC 1
		   1]		;ONE PAGE, IN.
	LDB	T3,[POINT UPGWID,P1,26] ;GET PAGE NUMBER
	PUSHJ	P,DOPAGE	;PAGE HIM IN
	JRST	PFHXCN		;COUNT FAULT AND CONTINUE
;Here to put us n pages below limit
;Call
;	MOVEI	T3,amount of increase	;Only for call to CHKLIN
;	PUSHJ	P,CHKLIM/CHKLIN	;CHKLIM assumes one page increase
;Return
;	RET		;Can't make room for another page
;	RETSKP		;There is now room for at least one page

CHKLIM:	MOVEI	T3,1		;ONE PAGE OF INCREASE
CHKLIN::SE1ENT			;MUST BE IN SECTION 1
	PUSHJ	P,SAVE3##	;PRESERVE ACS USED
	MOVE	P2,T3		;SAVE IN MORE PERMANENT PLACE
	SETZ	P3,		;FIRST TIME THROUGH

;Set up for range checks for cannot-be-paged-out ('CBPO') pages

	ADJSP	P,-PFPOFS	;MAKE ROOM FOR LIMIT BI-WORDS
	PUSHJ	P,GETJLM	;GET RANGE OF PAGES FOR JOBINT BLOCK
	DMOVEM	T1,PFPJLB(P)	;SET UP FOR CBPO RANGE CHECK
	PUSHJ	P,GETBLM	;GET BREAKPOINT TRAP PAGE
	MOVEM	T1,PFPBPT(P)	;SAVE FOR CBPO RANGE CHECK
	PUSHJ	P,GETPLM	;FIND RANGE OF PAGES FOR PSI VECTOR
	DMOVEM	T1,PFPPLB(P)	;SET UP FOR CBPO RANGE CHECK

	LDB	P1,IMGIN##	;LOSEG SIZE = COUNT OF CANDIDATE PAGES

;Continued on next page
;Continued from previous page

CHKLI1:	MOVEI	T3,(P2)		;AMOUNT OF INCREASE
	PUSHJ	P,GSIZI##	;WILL WE STILL FIT IN CORE?
	  JFCL			;WILL NEVER FIT
	  TRNA			;LESSER THAN LIMITS
	  JRST	CHKL10		;WILL FIT, RETURN NOW

;Here when we will have to page things out.

CHKLI2:	SOJLE	P1,CHKL11	;GIVE UP AFTER CHECKING ALL CANDIDATE PAGES
CHKLI3:	SOSG	T2,.USPFL	;GET PAGE WE LAST PAGED OUT
	JRST	[SKIPL	.USBTS	;A BIG USER?
		 SKIPA	T2,[HLGPNO+1] ;NO, JUST LOOK AT SECTION 0
		 MOVEI	T2,HLGPGS+1 ;RE-START AT TOP PAGE
		 JRST	CHKLI5]	;AND CONTINUE FROM THE TOP
	LDB	T2,[POINT 5,T2,26] ;GET SECTION NUMBER
	LDB	T2,[POINT 3,.UPMP+SECTAB(T2),2] ;GET POINTER TYPE
	CAIN	T2,PM.DCD	;DIRECT POINTER
	JRST	CHKLI6		;YES, TRY IT
CHKLI4:	MOVE	T2,.USPFL	;GET LAST PAGE PAGED OUT
	TRZ	T2,HLGPNO	;ROUND DOWN TO BOTTOM OF BAD SECTION
CHKLI5:	MOVEM	T2,.USPFL	;AND SAVE IT
	JRST	CHKLI3		;AND LOOP

CHKLI6:	MOVE	T2,.USPFL	;PAGE TO CONSIDER
	TRC	T2,PG.BDY	;STARTING A NEW SECTION?
	TRCE	T2,PG.BDY	;  ..
	JUMPN	P3,CHKLI7	;OR NOT THE FIRST TIME THROUGH?
	LDB	T1,[POINT 5,T2,26] ;GET SECTION NUMBER
	SKIPE	T1		;SECTION ZERO IS DIFFERENT
	JRST	[IMULI T1,WSBTBL;COMPUTE WHICH WSBTAB TO USE
		 MOVEI T1,.WSBNZ-WSBTBL(T1)
		 JRST .+2]	;AND CONTINUE
	MOVEI	T1,WSBTAB	;SECTION 0 WSBTAB
	ANDI	T2,PG.BDY	;STARTING PAGE WITHIN SECTION
	PUSHJ	P,NXTWSP	;GET FIRST PAGE IN THIS SECTION
	  JRST	CHKLI4		;THERE AREN'T ANY
	JRST	CHKLI8		;SEE IF ITS A CANDIDATE
CHKLI7:	PUSHJ	P,NXTWSC	;GET NEXT WORKING SET PAGE
	  JRST	CHKLI4		;NO MORE IN THIS SECTION
;This is just a sanity check which set P3 non-zero. If its in the WS,
; its in core.
CHKLI8:	DPB	T2,[POINT 9,.USPFL,35] ;STORE PAGE NUMBER IN .USPFL
	MOVE	T2,.USPFL	;GET EXTENDED PAGE NUMBER
	JUMPE	T2,CHKLI3	;GO IF THIS IS PAGE 0 IN SECTION 0
	MOVE	P3,@[IW MS.MAP,UMAPS(T2)] ;GET PAGE MAP ENTRY
	TLC	P3,(PM.COR)	;IN-CORE BIT
	TLNE	P3,(PM.COR!1B1)	;IS IT IN CORE?
	JRST	CHKLI3		;NO, TRY AGAIN
CHKLI9:	CAME	T2,PFPJLB(P)	;IS THIS FIRST PAGE OF .JBINT BLOCK?
	CAMN	T2,PFPJLE(P)	;OR LAST PAGE OF .JBINT?
	JRST	CHKLI2		;YES, LEAVE IT ALONE
	CAMN	T2,PFPBPT(P)	;BREAKPOINT TRAP ADDRESS?
	JRST	CHKLI2		;YES, LEAVE IT FOR DDT
	CAML	T2,PFPPLB(P)	;IS THIS PAGE BELOW RANGE OF PSI VECTOR
	CAMLE	T2,PFPPLE(P)	;OR ABOVE IT?
	TRNA			;NOT IN RANGE OF PSI VECTOR
	JRST	CHKLI2		;IN PSI VECTOR, LEAVE IT ALONE
	PUSHJ	P,CKLDPG	;DO THE PAGE OUT
	JRST	CHKLI1		;MAKE SURE WE ARE BELOW LIMIT NOW

CHKL10:	AOS	PFPOFS(P)	;SET UP FOR SKIP RETURN
CHKL11:	ADJSP	P,PFPOFS	;THROW AWAY CHECK WORDS ON STACK
	POPJ	P,		;RETURN

;Here to page out the page, page number in T2.
CKLDPG:	PUSHJ	P,SAVT##	;MUST SAVE T1 ACS FOR NXTWSC
	MOVEM	T2,.USPFL	;REMEMBER AS LAST PAGE PAGED OUT
	MOVE	T3,T2		;FOR DOPAGE
	TLO	T3,(PG.GAF)	;FLAG THAT THIS PAGE GETS PAGED OUT
	DMOVE	T1,[0,,JOBUAL## ;.PAGIO,, AC 1
		    1]		;ONE PAGE
	PUSHJ	P,DOPAGE	;AND PAGE IT OUT
	PJRST	SCDCHK##	;LET OTHER USERS RUN JUST IN CASE
;Subroutine to get starting and ending page number of pages which can't be
; paged out (JOBINT block). Returns results in T1, T2

GETJLM::HRRZ	T1,.JDAT+JOBINT##;GET ADDRESS OF JOBINT BLOCK
	HRRZI	T2,3(T1)	;END ADDRESS OF JOBINT BLOCK
	TRZ	T1,PG.BDY	;MAKE START ADDRESS A PAGE BOUNDARY
	LSHC	T1,W2PLSH	;CONVERT BOTH TO PAGE NUMBERS
	POPJ	P,		;AND RETURN

;Subroutine to get page number of DDT breakpoint trap word (for JSR)

GETBLM::MOVE	T1,.JDAT+.JBBPT## ;FETCH JSR TARGET ADDRESS
	LSH	T1,W2PLSH	;CONVERT TO PAGE NUMBER
	MOVE	T2,T1		;DON'T CONFUSE GETRSN
	PJRST	GETRSN		;RETURN INDPENDENT PAGE NUMBER


;Subroutine to get starting and ending page number of pages which can't be
; paged out (PSI vector). Returns results in T1, T2

GETPLM::PUSHJ	P,PSIIVR##	;FIND RANGE OF PAGES FOR PSI VECTOR
	HLRZ	T2,T1		;GET ENDING PAGE
	HRRZS	T1		;MAKE THIS STARTING PAGE ONLY
;	PJRST	GETRSN		;CONVERT TO REAL SECTION NUMBERS AND RETURN


;Subroutine to convert page numbers in T1 andd T2 to page numbers with all
; section indirection resolved (real section numbers)

GETRSN:	PUSH	P,T2		;THE INTERFACE TO RSECT4 IS WIERD
	PUSH	P,T4		;IT WANTS THE ARGUMENT IN T4
	LDB	T4,[POINT 5,T1,26] ;SECTION SPECIFIED
	PUSHJ	P,RSECT4##	;FOLLOW ANY INDIRECT SECTION POINTERS TO A
				; DIRECT POINTER
	  JFCL			;I TOLD YOU THE INTERFACE WAS WIERD
	DPB	T4,[POINT 5,T1,26] ;STORE REAL SECTION NUMBER

;Doing this assumes that a block could cross a section boundary which it can't,
; but might as well be general.

	LDB	T4,[POINT 5,-1(P),26] ;FOR T2 ARGUMENT AS WELL
	PUSHJ	P,RSECT4##	;FOLLOW ANY INDIRECT SECTION POINTERS TO A
				; DIRECT POINTER
	  JFCL			;I TOLD YOU THE INTERFACE WAS WIERD
	DPB	T4,[POINT 5,-1(P),26] ;STORE ANSWER
	POP	P,T4		;RESTORE T4
	JRST	T2POPJ##	;RESTORE T2 AND RETURN
;Do a page uuo.
;Call
;	T1/ Function,, JOBUAL##
;	T2/ Number of pages to do (1 or negative number)
;	T3/ Page to do, possibly with PG.GAF lit.
;Return
;	RET, done
;If the page uuo fails, this routine stopcodes and does not return

DOPAGE:
IFN FTXMON,<
	MOVE	T4,T1		;SAVE FUNCTION
	MOVEI	T1,0		;SET PCS TO ZERO
	PUSHJ	P,SVPCS##	;SINCE ARGUMENT LIST WILL BE AT JOBUAL IN S0
	MOVE	T1,T4		;RESTORE T1
>
	PUSHJ	P,SAVUM##	;TRASHED BY VMSER
	MOVEI	T4,JS.ASA	;SHADOW ACS BIT
	TDNE	T4,JBTSTS##(J)	;IS IT SET?
	JRST	DOPAG1		;YES, USE SHADOW AREA
	UMOVE	T4,0		;GET USER AC ZERO
	UMOVEM	T1,0		;SET UP USER AC
	JRST	DOPAG2		;STORE ARGS
DOPAG1:	MOVE	T4,.JDAT	;SAVE SHADOW AC 0
	MOVEM	T1,.JDAT	;STORE FUNCTION,,ADDRESS
DOPAG2:	DMOVEM	T2,.JDAT+JOBUAL## ;STASH ARGS IN WORK AREA
	PUSH	P,T4		;SAVE USER'S AC ZERO
	PUSH	P,F		;SAVE OUR DDB POINTER
	PUSH	P,S		;AND DEVIOS
	SETZ	M,		;LOOK IN AC 0 FOR ARGS
	S0PSHJ	UPAGE.##	;AND DO THE PAGE.
	  JRST	DOPAG4		;ANALYZE THE ERROR
	POP	P,S		;RESTORE DEVIOS
	POP	P,F		;RESTORE DDB POINTER
	POP	P,T4		;GET BACK USER'S AC ZERO
	MOVEI	T1,JS.ASA	;ACS IN THE SHADOW AREA BIT
	TDNE	T1,JBTSTS##(J)	;ARE THEY?
	JRST	DOPAG3		;YES, RESTORE THERE
	UMOVEM	T4,0		;STASH AWAY AGAIN
	POPJ	P,		;RETURN
DOPAG3:	MOVEM	T4,.JDAT	;STASH AWAY AGAIN
	POPJ	P,		;AND RETURN

;Here to analyze the error code returned from the PAGE. UUO.
DOPAG4:
;	UMOVE	T1,0		;GET ERROR CODE
	CAIE	T1,PAGIO%	;PAGING I/O ERROR? ANYTHING ELSE IS FATAL
	STOPCD	.,JOB,PFHUUO,	;++ PAGE UUO FAILED
	JSP	T1,ERRPNT##	;TELL THE USER ABOUT THE PROBLEM
	ASCIZ	\Paging I/O error\
	PJRST	PCSTOP##	;TELL THE USER THE PC AND STOP THE JOB
;Here to count an in working set page fault
PFHXCI:	AOSA	SYSIWS##	;COUNT "IN WORKING SET" FAULT

;Here to count a not in working set page fault
PFHXCN:	AOSA	SYSNIW##	;COUNT "NOT IN WORKING SET" FAULT
	SKIPA	T1,[1]		;COUNTS IN THE RIGHT HALF
	MOVSI	T1,1		;COUNTS IN THE LEFT HALF
	ADDM	T1,.USVCT	;UPDATE USER TOTAL
	ADDM	T1,SYSVCT##	;TALLY UP OLD COUNTER TOO
	JRST	CPOPJ1##	;RETURN


;PFHGWD - GETWRD routine specifically for PFH. Make sure that we fault
;	gently, and pull the page in without trying to re-start the uuo.

PFHGW1::HRRI	M,1(M)		;BUMP THE ADDRESS
PFHGWD::TRNN	M,^-17		;IS THIS AN AC REFERENCE?
	PJRST	GETWRD##	;YES, DO IT THE OLD WAY
	SE1ENT			;NO, USE SECTION 1 FOR ADDRESSING
	PUSH	P,M		;SAVE M
	HRLI	M,(IFIW)	;MAKE VALID IW
	PUSHJ	P,PFHXW0	;FETCH
	  JRST	MPOPJ##		;PROPAGATE FAILURE
	JRST	MPOPJ1##	;AND SUCCESS

PFHGWF:	SE1ENT			;MUST BE IN SECTION 1
	PUSH	P,P1		;SAVE AN AC
	MOVE	P1,.USPFW	;GET PAGE FAIL CODE
	TLNN	P1,(PF.BAD)	;DON'T BOTHER IF SOMETHING REALLY BAD
	PUSHJ	P,PFHPAG	;PAGE IT IN
	  JRST	P1POPJ##	;ERROR IN ADDRESS
	POP	P,P1		;GET BACK SAVED AC
PFHXW0:	UMOVE	T1,@M		;GET THE WORD FROM USER MEMORY
	  ERJMP	PFHGWF		;FAILED, TRY TO PAGE IT IN
	RETSKP			;AND RETURN SUCCESS

IFN FTXMON,<
PFHXW1::SKIPL	M		;IS THIS AN IFIW?
	AOSA	M		;NO, BUMP GLOBALLY
	HRRI	M,1(M)		;YES, BUMP LOCALLY
	TRNN	M,-1		;IF HIT A SECTION BOUNDARY,
	SKIPGE	M		;AND DIDN'T WRAP,
	JRST	PFHXWD		; (NO)
	PUSHJ	P,SMPCS##	;THEN MAKE SURE IT'S VALID
	  POPJ	P,		;PROPAGATE FAILURE
	;FALL INTO PFHXWD

;PFHXWD - The PFH version of GETXWD

PFHXWD::TDNN	M,[^-<IFIW!<1,,17>>] ;IS THIS AN AC REFERENCE?
	PJRST	GETWRD##	;YES, HANDLE IT THE OLD WAY
	SE1ENT			;MUST BE IN S1
	JRST	PFHXW0		;GO FETCH IT


;PFHMWD - like PFHGWD but gets the word from section specified by M

PFHMWD::SE1ENT			;WE WANT NZS ADDRESSING
	LDB	T1,[POINT 5,M,17] ;WHAT PCS SHOULD BE TO FETCH THE WORD
	PUSHJ	P,SVPCS##	;SAVE PCS AND SET PCS TO VALUE FROM M
	JRST	PFHGWD		;GET THE WORD
> ;END IFN FTXMON

;PFHPWD - The PFH version of PUTWRD

PFHPW1::HRRI	M,1(M)		;ADVANCE THE POINTER
PFHPWD::PUSH	P,T1		;SAVE VALUE TO DEPOSIT
	PUSHJ	P,PFHGWD	;MAKE SURE THE WORD IS IN CORE
	  JRST	TPOPJ##		;PROPAGATE FAILURE
	POP	P,T1		;RESTORE VALUE TO STORE
	PJRST	PUTWRD##	;NOW GO STUFF IT IN

IFN FTXMON,<
;PFHPMW - The PFH version of PUTMWD

PFHPMW::PUSH	P,T1		;SAVE VALUE TO DEPOSIT
	PUSHJ	P,PFHMWD	;MAKE SURE THE WORD IS IN CORE
	  JRST	TPOPJ##		;PROPAGATE FAILURE
	POP	P,T1		;RESTORE VALUE TO STORE
	PJRST	PUTMWD##	;NOW GO STUFF IT IN

;PFHPXW - The PFH version of PUTEWD

PFHPX1::SKIPL	M		;AN IFIW?
	AOSA	M		;NO, ADVANCE GLOBALLY
	HRRI	M,1(M)		;YES, ADVANCE LOCALLY
	TRNN	M,-1		;IF HIT A SECTION BOUNDARY,
	SKIPGE	M		;AND CROSSED IT
	JRST	PFHPXW		;(NO)
	PUSHJ	P,SMPCS##	;MAKE SURE IT'S VALID
	  POPJ	P,		;PROPAGATE FAILURE
PFHPXW::PUSH	P,T1		;SAVE VALUE TO STORE
	PUSHJ	P,PFHXWD	;MAKE SURE THE WORD'S IN CORE
	  JRST	TPOPJ##		;PROPAGATE FAILURE
	POP	P,T1		;RESTORE VALUE TO DEPOSIT
	PJRST	PUTEWD##	;AND GO STUFF IT IN
> ;END IFN FTXMON

IFE FTXMON,<
XP	PFHMWD,PFHGWD
XP	PFHXWD,PFHGWD
XP	PFHXW1,PFHGW1
XP	PFHPMW,PFHPWD
XP	PFHPXW,PFHPWD
XP	PFHPX1,PFHPW1
> ;END IFE FTXMON
;PFHDMP - Dump mode IO. This routine replaces DMPIO.
;Call
;	T1/ IO routine
;	F,U,M/ UUO normal
;Return
;	RET,	 I/O has been done.
;
;If an error occurrs at any point, it returns then and there,
;to let the higher levels catch it.

PFDBAS==0		;BASE ADDRESS OF IOWDS
PFDISP==1		;DISPATCH ADDRESS
PFDCNT==2		;COUNT OF IOWDS PROCESSED
PFDEVM==3		;AMOUNT OF EVM USED LAST TIME, IF ANY
PFDRSN==4		;REASON NOT IN CORE
PFDSNI==5		;STARTING PAGE NOT IN CORE
PFDPNI==6		;PREVIOUS PAGE NOT IN CORE
PFDSIZ==7		;SIZE OF BLOCK TO ALLOCATE (used by pfhmsi)

PFHDMP::SE1ENT			;WE TOUCH PAGE MAPS, RUN IN SECTION 1
	PUSHJ	P,SAVE4##	;SAVE PERM ACS THAT WE USE
	MOVE	P1,T1		;SAVE DEVICE DISPATCH ADDRESS
IFN FTXMON,<
	TLO	F,(1B0)		;TURN ON THE SIGN BIT FOR INDEXING (UINITB)
	HRRZ	T1,DEVISN(F)	;IO SECTION NUMBER
	PUSHJ	P,SVPCS##	;SAVE PCS AND SET UP
>
	XMOVEI	P4,1(P)		;POINT AT AVAILABLE STACK AREA
	ADJSP	P,PFDSIZ	;RESERVE ROOM FOR DATA ON STACK
	MOVEM	P1,PFDISP(P4)	;SAVE DISPATCH ADDRESS
	SETZM	PFDEVM(P4)	;NO EVM YET
	MOVEI	T1,^D1000	;MAXIMUM NUMBER OF IOWDS TO ALLOW
	MOVEM	T1,PFDCNT(P4)	;STORE THAT
PFHDM1:	PUSHJ	P,PFHGWD	;GET IOWD
	  JRST	UADERR##	;SHOULDN'T HAPPEN
	JUMPE	T1,PFHDM4	;DONE, CLEAN UP
	TLNN	T1,-1		;A GOTO WORD?
	JRST	[HRRI M,(T1)	;YES, POINT TO NEXT IOWD
		JRST PFHDM3]	;AND CONTINUE
	HLRO	P2,T1		;SIZE OF IOWD
	MOVEI	T1,1(T1)	;POINT TO FIRST WORD TOUCHED BY IO
	HRL	T1,DEVISN(F)	;GET SECTION NUMBER
	MOVEM	T1,PFDBAS(P4)	;STASH WHERE PFHIOD CAN FIND IT
	MOVE	P1,PFDBAS(P4)	;POINT AT FIRST WORD AFFECTED BY IO
	SETCA	P2,		;COUNT OF WORDS AFFECTED
	ADD	P2,PFDBAS(P4)	;POINT AT LAST WORD AFFECTED BY IO
	SETZ	P3,		;NOTHING ACCUMULATED YET
	XOR	T1,P2		;SEE IF SECTIONS CHANGED
	TLNE	T1,-1		;IF SO, THIS IS BAD FOR AN OLD-STYLE IOWD
	S0JRST	ADRERR##	;SO GIVE HIM THE BAD NEWS
	PUSHJ	P,PFHIOD	;DO THE IO FOR THIS IOWD
	  JRST	PFHDM4		;DIDN'T MAKE IT, LET TOP LEVEL FIND ERROR
	HRRI	M,1(M)		;POINT TO NEXT IOWD
PFHDM3:	SOSL	PFDCNT(P4)	;DECREMENT COUNT OF IOWDS
	JRST	PFHDM1		;GET NEXT IOWD IN LIST
	JRST	ADRERR##	;MORE THAN A THOUSAND IOWDS, PROBABLY LOOP

PFHDM4:	ADJSP	P,-PFDSIZ	;GIVE BACK STORAGE ON STACK
	S0PSHJ	WAIT1##		;WAIT FOR DEVICE TO QUIESCE
	S0JRST	RTNEVM##	;RETURN ANY EVM LEFT OVER
;PFHMSI - Multi section I/O
;This routine breaks down a multi-section io list into chunks small
;enough for filser to handle them, at the same time making sure the
;right amounts of everything is paged in.
;Call
;	T1/ IO routine
;	F,U,M/ UUO normal
;Return
;	RET, IO has been done
;If an IO error occurrs, we stop io then and there, and return to top level

PFHMSI::SE1ENT			;WE TOUCH MAPS, RUN IN SECTION 1
	PUSHJ	P,SAVE4##	;SAVE PERM ACS THAT WE USE
	MOVE	P1,T1		;SAVE DEVICE DISPATCH ADDRESS
IFN FTXMON,<
	TLO	F,(1B0)		;TURN ON THE SIGN BIT FOR INDEXING (UINITB)
	HRRZ	T1,DEVISN(F)	;IO SECTION NUMBER
	PUSHJ	P,SVPCS##	;SAVE AND SET UP PCS
>
	XMOVEI	P4,1(P)		;POINT AT AVAILABLE STACK AREA
	ADJSP	P,PFDSIZ+1	;RESERVE ROOM FOR DATA ON STACK
	MOVEM	P1,PFDISP(P4)	;SAVE DISPATCH ADDRESS
	MOVEI	T1,^D1000	;MAXIMUM NUMBER OF IOWDS TO ALLOW
	MOVEM	T1,PFDCNT(P4)	;STORE THAT
	SETZM	PFDEVM(P4)	;NO EVM YET
PFHMS1:	PUSHJ	P,PFHMWD	;GET FIRST HALF OF EXTENDED IOWD
	  JRST	UADERR##	;SHOULDN'T HAPPEN
	MOVE	P2,T1		;SAVE AS SIZE OF IOWD
	AOS	M		;POINT M AT SECOND HALF
	PUSHJ	P,PFHMWD	;GET SECOND HALF OF EXTENDED IOWD
	  JRST	UADERR##	;SHOULDN'T HAPPEN
	JUMPE	P2,PFHMS2	;A GOTO WORD?
	MOVEM	T1,PFDBAS(P4)	;STASH WHERE PFHIOD CAN FIND IT
PFHM1A:	MOVE	P1,PFDBAS(P4)	;FIRST WORD AFFECTED BY IO
	MOVEM	P2,PFDSIZ(P4)	;STASH TOTAL IOWD SIZE
	CAILE	P2,400000	;MAXIMUM IOWD SIZE
	MOVEI	P2,400000	;MAKE SURE WE DON'T EXCEED IT
	ADD	P2,PFDBAS(P4)	;POINT AT LAST WORD PLUS ONE
	SOS	P2		;LAST WORD AFFECTED BY IO
	SETZ	P3,		;NOTHING ACCUMULATED YET
	PUSHJ	P,PFHIOD	;DO THE IO FOR THIS IOWD
	  JRST	PFHMS4		;DIDN'T MAKE IT, LET TOP LEVEL FIND ERROR
	MOVE	P2,PFDSIZ(P4)	;GET SIZE OF THAT IOWD
	SUBI	P2,400000	;DECREMENT MAX AMOUNT WE WOULD HAVE DONE
	JUMPG	P2,PFHM1A	;AND LOOP IF ANYTHING LEFT TO DO
	AOSA	T1,M		;POINT TO NEXT IOWD
PFHMS2:	JUMPE	T1,PFHMS4	;GOTO ZERO MEANS END OF IOWD LIST
	DPB	T1,[POINT 23,M,35] ;POINT AT NEXT IOWD
PFHMS3:	SOSL	PFDCNT(P4)	;DECREMENT COUNT OF IOWDS
	JRST	PFHMS1		;GET NEXT IOWD IN LIST
	JRST	ADRERR##	;MORE THAN A THOUSAND IOWDS, PROBABLY LOOP

PFHMS4:	ADJSP	P,-PFDSIZ-1	;GIVE BACK STORAGE ON STACK
	S0PSHJ	WAIT1##		;WAIT FOR DEVICE TO QUIET DOWN
	S0JRST	RTNEVM##	;RETURN ANY EVM LEFT OVER
	SUBTTL	PFHIOD - Dump mode iowds.

Comment	@ Loose description of dump mode i/o breakdown algorithm.

check iowd pages
	set current address to starting io address
	call next iowd page
	return

next iowd page
	look at page
	if aa off, make aa on
	if not in core, request pagein
	if end, do accumulated pagein, do accumulated io and return
	incr current address to start of next page
	go back to next iowd page

request pagein
	if reason not in core different than previous reason
	or current page different than previous page + 1,
	   do accumulated pagein
	   stash starting page not in core
	   stash reason not in core and current page
	return

do accumulated pagein
	if enough room for all pages, page them in and return
	make room, and go back to do accumulated pagein

make room
	preserve end accumulated io pointer, to be restored on return
	loop from .uspfl down
	  accumulating valid pages to page out (not in iowd or vectors)
	  if gsizi cries uncle, page out accumulated pageout and return
	  until looped over entire image
	page out accumulated pageout
	binary search from number of pages we want in,
	  calling gsizi until we find out how much maximum will fit
	page in that many pages
	set starting page not in core to first page not paged in
	set up end accumulated io pointer to within last page we paged in
	do accumulated io and return

do accumulated io
	do io from starting io address to ending io address
	set starting io address to ending io address + 1
	return

	@
;PFHIOD - Dump mode iowds
;Here to check paged-in dump i/o lists.
;Call
;	P4/ Pointer to block of stack space with
;	    PFDBAS(P4)/ Address of first word touched by this IOWD
;	    PFDISP(P4)/ Address of routine to call to do IO
;	P3/ undefined
;	P2/ Last word affected by IO
;	P1/ First word affected by IO
;Return
;	RET	Some error occurred, propagate it to top
;	RETSKP	IO done, no problems yet
;
;Note that all addresses are full 30 bit addresses - Even if you want to do
;local addressing, you must supply a full extended address.

PFHIOD:	PUSHJ	P,SAVUM##	;WE USE UP M IN HERE
	SETZM	PFDRSN(P4)	;NO CURRENT PAGED-OUT-REASON
	SETZM	PFDPNI(P4)	;NO PREVIOUS PAGE
	PUSHJ	P,PFHNXI	;DO THIS IOWD
	  SKIPA			;HMM. ERROR RETURN
	AOS	(P)		;PROPAGATE SKIP RETURN
	POPJ	P,		;AND RETURN

PFHNXI:	LDB	T2,[POINT UPGWID,P1,26] ;GET VIRTUAL PAGE NUMBER
	MOVE	T1,@[IW MS.MAP,UMAPS(T2)] ;GET PAGE MAP ENTRY
	  ERJMP	PFHIOX		;ILL MEM REF
	JUMPE	T1,PFHIOX	;ILL MEM REF
	MOVSI	T3,(<<PM.DCD>B2>!PM.AAB)  ;BE SURE ACCESS ALLOWED IS ON
	TLNE	T1,(PM.COR!<<PM.ACD^!PM.DCD>B2>) ;IN CORE OR INDIRECT?
				;(IF IT PASSED THIS FAR, LET IT THROUGH)
	JRST	PFHNX2		;YES, USE IT
	PUSHJ	P,PFHPIN	;NO, FILE A REQUEST TO PAGE IT IN
	  POPJ	P,		;HMM. AN ERROR OF SOME VARIETY. CUTE.
	LDB	T2,[POINT UPGWID,P1,26] ;GET VIRTUAL PAGE NUMBER
	MOVE	T1,@[IW MS.MAP,UMAPS(T2)] ;GET PAGE MAP ENTRY
	  ERJMP	PFHIOX		;ILL MEM REF
	JUMPE	T1,PFHIOX	;ILL MEM REF
	MOVSI	T3,(PM.AAB)	;BE SURE DCD COMES ON WHEN PAGE COMES IN
PFHNX2:	TLNE	T1,(<PM.ACD^!PM.DCD>B2!PM.AAB)	;DOES PAGE HAVE ACCESS ALLOWED ON?
	JRST	PFHNX3		;YES, JUST USE IT
	IORM	T3,@[IW MS.MAP,UMAPS(T2)] ;TURN ON IN MAP
	SOS	.USANA		;DECREMENT NUMBER OF NON-ACCESSIBLE PAGES
	PUSHJ	P,ADJANA##	;ADJUST .USVRT
PFHNX3:	TRO	P1,PG.BDY	;BUMP UP TO PAGE BOUNDARY
	ADDI	P1,1		;AND UP TO FIRST WORD OF NEXT PAGE
	CAMLE	P1,P2		;DID WE OVERFLOW?
       	SKIPA	P1,P2		;YES, BACK DOWN TO LAST WORD
	JRST	PFHNXI		;NO, LOOP CHECKING PAGES
	AOS	PFDPNI(P4)	;PROTOCOL REQUIRES BUMPING THIS COUNTER
	PUSHJ	P,PFHACP	;DO ACCUMULATED PAGE IN
	  POPJ	P,		;ARGH. ERROR
	PJRST	PFDOIO		;DO THE I/O AND RETURN
;PFHPIN - Request page-in of a page
;Call
;	T1/ Contents of map for page
;	T2/ Page number
;	P1/ Virtual address we are looking at
;	P4/
;	   PFDBAS(P4)/ Start word of io
;	   PFDRSN(P4)/ Reason previous page was paged out
;	   PFDSNI(P4)/ Start not-in-core page
;	   PFDPNI(P4)/ Previous not-in-core page
;Return
;	RET	An I/O error of some sort
;	RETSKP	With request filed (and possibly some pages paged in);
;	    or	I/O done up to previous page and PFDBAS adjusted to reflect
;		the fact.

PFHPIN:	TDNN	T1,[PM.ADR-PM.ZER] ;IS PAGE ABZ?
	SKIPA	P3,[1,,JOBUAL##] ;ABZ,   .PAGCD,,AT JOBUAL
	MOVE	P3,[0,,JOBUAL##] ;OUT,   .PAGIO,,AT JOBUAL
	AOS	T3,PFDPNI(P4)	;YES, ASSUME THIS IS EXACT NEXT PAGE
	CAME	P3,PFDRSN(P4)	;IS REASON SAME AS EXISTING STUFF?
	JRST	PFHPI2		;NO, FLUSH PENDING PAGEINS
	CAMN	T3,T2		;IS THIS THAT EXACT PAGE?
	RETSKP			;YES, ALL DONE.

PFHPI2:	PUSHJ	P,PFHACP	;DO ACCUMULATED PAGEIN
	  POPJ	P,		;SOMETHING FAILED DEEP DOWN
	MOVEM	P3,PFDRSN(P4)	;STASH NEW REASON/FUNCTION
	LDB	T1,[POINT UPGWID,P1,26] ;GET THIS PAGE'S NUMBER
	MOVEM	T1,PFDSNI(P4)	;SAVE AS STARTING PAGE NOT IN CORE
	MOVEM	T1,PFDPNI(P4)	;SAVE AS PREVIOUS PAGE NOT IN CORE
	RETSKP			;AND RETURN
;PFHACP - Do accumulated pagein
;Call
;	P4/
;	   PFDRSN - Function code to use for page. uuo
;	   PFDSNI - Starting page for page.
;	   PFDPNI - Last page to do plus one
;Return
;	RET	I/O error deep down
;	RETSKP	pages are in core (may have done i/o and paged stuff out)
;

PFHACP:	SKIPN	PFDRSN(P4)	;MAKE SURE THERE IS SOMETHING TO DO
	RETSKP			;NOPE, JUST RETURN
	MOVE	T3,PFDPNI(P4)	;GET LAST PLUS ONE PAGE
	SUB	T3,PFDSNI(P4)	;COMPUTE NUMBER OF PAGES COMING IN
	PUSHJ	P,GSIZI##	;MAKE SURE WE HAVE ENOUGH ROOM
	  JFCL			;WILL NEVER FIT
	  JRST	PFHAC2		;DO CURRENTLY ACCUMULATED I/O FIRST
	MOVE	T1,PFDRSN(P4)	;GET FUNCTION CODE
	MOVN	T2,T3		;NUMBER OF PAGES TO DO
	MOVE	T3,PFDSNI(P4)	;GET STARTING PAGE NUMBER
	PUSHJ	P,DOPAGE	;DO THE PAGE UUO
	RETSKP			;DONE, RETURN

PFHAC2:	PUSHJ	P,PFHMKR	;MAKE ROOM
	  POPJ	P,		;URP. I/O ERROR IN BOWELS.
	JRST	PFHACP		;AND LOOP TRYING TO PAGE THEM IN
;PFHMKR - Make room for pagein by paging other unused stuff out
;Call
;	P4/
;	   PFDBAS/ Starting place of IO
;	   PFDRSN/ Function to page pages in
;	   PFDSNI/ Start not-in-core page
;	   PFDPNI/ Last not-in-core page plus 1
;	P1/ Highest virtual address currently being looked-at
;Return
;	RET	Some type of i/o error
;	RETSKP	pages up to PFDPNI have been paged in, we might have
;		had to do some i/o and page out earlier pages

PFHMKR:	PUSHJ	P,SAVE3##	;SAVE SOME WORK REGISTERS

;Set up for range checks for cannot-be-paged-out ('CBPO') pages

	ADJSP	P,-PFPOFS	;MAKE ROOM FOR CBPO BI-WORDS
	PUSHJ	P,GETJLM	;GET RANGE OF PAGES FOR JOBINT BLOCK
	DMOVEM	T1,PFPJLB(P)	;SET UP FOR CBPO RANGE CHECK
	PUSHJ	P,GETBLM	;GET BREAKPOINT TRAP PAGE
	MOVEM	T1,PFPBPT(P)	;SAVE FOR CBPO RANGE CHECK
	LDB	T1,[POINT UPGWID,PFDBAS(P4),26] ;STARTING PAGE OF IOWD
	MOVEM	T1,PFPILB(P)	;SAVE LOWER-LIMIT OF IOWD-ADDRESSED RANGE
	LSH	P1,W2PLSH	;CONVERT TO HIGHEST PAGE
	MOVEM	P1,PFPILE(P)	;SAVE UPPER-LIMIT OF IOWD-ADDRESSED RANGE
	PUSHJ	P,GETPLM	;FIND RANGE OF PAGES FOR PSI VECTOR
	DMOVEM	T1,PFPPLB(P)	;SET UP FOR CBPO RANGE CHECK

	LDB	P1,IMGIN##	;LOSEG SIZE = COUNT OF CANDIDATE PAGES
	SETZB	P2,P3		;NO PAGES TO PAGE OUT ACCUMULATED YET
	TLO	P4,400000	;FIRST TIME THROUGH FLAG

;Continued on next page
;Continued from previous page

;Loop trying to find pages to page out

PFHMK1:	SOJLE	P1,PFHBRK	;AFTER TRYING ALL PAGES, BREAK THE IOWD DOWN
PFHMK2:	SOSG	T2,.USPFL	;GET PAGE WE LAST PAGED OUT
	JRST	[SKIPL	.USBTS	;A BIG USER?
		 SKIPA	T2,[HLGPNO+1] ;NO, JUST LOOK AT SECTION 0
		 MOVEI	T2,HLGPGS+1 ;RE-START AT TOP PAGE
		 JRST	PFHMK4]	;AND CONTINUE FROM THE TOP
	LDB	T2,[POINT 5,T2,26] ;GET SECTION NUMBER
	LDB	T2,[POINT 3,.UPMP+SECTAB(T2),2] ;GET POINTER TYPE OF SECTION
	CAIN	T2,PM.DCD	;A DIRECT POINTER
	JRST	PFHMK5		;YES, TRY IT
PFHMK3:	MOVE	T2,.USPFL	;GET PAGE NUMBER AGAIN
	TRZ	T2,HLGPNO	;ROUND DOWN TO BOTTOM OF BAD SECTION
PFHMK4:	MOVEM	T2,.USPFL	;SET NEW "LAST" CANDIDATE PAGE NUMBER
	JRST	PFHMK2		;AND LOOP

PFHMK5:	MOVE	T2,.USPFL	;PAGE TO CONSIDER
	TRC	T2,PG.BDY	;STARTING A NEW SECTION?
	TRCE	T2,PG.BDY	;  ..
	JUMPGE	P4,PFHMK6	;OR NOT THE FIRST TIME THROUGH?
	TLZ	P4,400000	;NOT FIRST TIME NEXT TIME
	LDB	T1,[POINT 5,T2,26] ;GET SECTION NUMBER
	SKIPE	T1		;SECTION ZERO IS DIFFERENT
	JRST	[IMULI T1,WSBTBL;COMPUTE WHICH WSBTAB TO USE
		 MOVEI T1,.WSBNZ-WSBTBL(T1)
		 JRST .+2]	;AND CONTINUE
	MOVEI	T1,WSBTAB	;SECTION 0 WSBTAB
	ANDI	T2,PG.BDY	;STARTING PAGE WITHIN SECTION
	PUSHJ	P,NXTWSP	;GET FIRST PAGE IN THIS SECTION
	  JRST	PFHMK3		;NONE THERE
	JRST	PFHMK7		;SET IF CAN PAGE THIS ONE OUT
PFHMK6:	PUSHJ	P,NXTWSC	;GET NEXT WORKING SET PAGE
	  JRST	PFHMK3		;NO MORE IN THIS SECTION
PFHMK7:	DPB	T2,[POINT 9,.USPFL,35] ;STORE PAGE NUMBER WITHIN SECTION
	MOVE	T2,.USPFL	;GET EXTENDED PAGE NUMBER
	JUMPE	T2,PFHMK2	;NEXT PAGE IF THIS IS REALLY PAGE 0
	CAML	T2,PFPILB(P)	;IS THIS PAGE BELOW RANGE OF OUR IOWD?
	CAMLE	T2,PFPILE(P)	;OR ABOVE IT?
	JRST	PFHMK8		;NOT WITHIN IOWD-ADDRESSED RANGE
	JRST	PFHMK1		;TRY NEXT PAGE (CAN'T SKIP IOWD SINCE COUNTED IN P1)
PFHMK8:	CAME	T2,PFPJLB(P)	;IS THIS FIRST PAGE OF .JBINT BLOCK?
	CAMN	T2,PFPJLE(P)	;OR LAST PAGE OF .JBINT?
	JRST	PFHMK1		;YES, LEAVE IT ALONE
	CAMN	T2,PFPBPT(P)	;BREAKPOINT TRAP ADDRESS?
	JRST	PFHMK1		;YES, LEAVE IT FOR DDT
	CAML	T2,PFPPLB(P)	;IS THIS PAGE BELOW RANGE OF PSI VECTOR
	CAMLE	T2,PFPPLE(P)	;OR ABOVE IT?
	TRNA			;NOT IN RANGE OF PSI VECTOR
	JRST	PFHMK1		;IN PSI VECTOR, LEAVE IT ALONE


;Continued on next page
;Continued from previous page

;Here when we have a page to page out

	MOVEM	T2,.USPFL	;STORE THIS PAGE FOR NEXT TIME THROUGH
	CAIE	P3,1(T2)	;IS THIS PAGE DIRECTLY BELOW PREVIOUS PAGE?
	PUSHJ	P,PFHMKO	;NO, OUTPUT ACCUMULATION
	SOS	P2		;INCREMENT NUMBER OF PAGES TO PAGE OUT
	PUSHJ	P,PFGSI		;CHECK FOR A FIT
	  JRST	PFHMK9		;IT DOES, PAGE OUT ACCUMULATION
	MOVE	P3,T2		;NEW LOWEST PAGE
	JRST	PFHMK1		;AND LOOP LOOKING FOR MORE PAGES

PFHMK9:	MOVE	P3,T2		;RE SET UP LOWEST PAGE
	ADJSP	P,PFPOFS	;RETURN CHECK WORDS TO STACK
	PUSHJ	P,PFHMKO	;PAGE OUT ACCUMULATION
	RETSKP			;AND RETURN SUCCESS


PFHMKO:	JUMPE	P2,CPOPJ##	;IF NOTHING TO PAGE OUT, JUST RETURN
	PUSHJ	P,SAVT##	;SAVE T ACS FOR NXTWS?
	MOVE	T1,[.PAGIO,,JOBUAL##] ;PAGE UUO ARGUMENT
	DMOVE	T2,P2		;NUMBER OF PAGES, LOWEST PAGE
	TLO	T3,(PG.GAF)	;INDICATE PAGING OUT
	PUSHJ	P,DOPAGE	;DO THE PAGE UUO
	SETZ	P2,		;INDICATE NO PAGES ACCUMULATED YET
	POPJ	P,		;RETURN

PFGSI:	PUSHJ	P,SAVT##	;SAVE ACS FOR NXTWS?
	MOVE	T3,PFDPNI(P4)	;GET LAST PAGE NEEDED PLUS ONE
	SUB	T3,PFDSNI(P4)	;GET NUMBER OF PAGES INCREASE WE NEED
	ADD	T3,P2		;MINUS PAGES WE CAN PAGE OUT
	PUSHJ	P,GSIZI##	;WILL WE FIT NOW?
	  JRST	CPOPJ1##	;STILL NOT
	  JRST	CPOPJ1##	;STILL NOT
	POPJ	P,		;WE WILL FIT IF WE DO ACCUMULATED PAGEOUT
;At this point, we have paged out everything possible and we STILL don't
;have enough room. We will page in everything we possibly can, and then
;do as much io as we can into those pages. This is where we finally have
;to break down and split up the iowd.

PFHBRK:	MOVE	T1,PFPILE(P)	;GET UPPER LIMIT OF IOWD-ADDRESSED SPACE
	ADJSP	P,PFPOFS	;RETURN PFHMKR'S CHECK WORDS TO STACK
	JUMPN	P2,PFHBR1	;IF SOMETHING COULD BE PAGED OUT, WORK WITH THAT
	MOVE	P3,PFDPNI(P4)	;FIRST IN-CORE PAGE
	MOVE	P2,P3		;COPY IT
	SUB	P2,T1		;PAGES IN IOWD SPACE TO PAGE OUT TO MAKE ROOM
	JUMPGE	P2,PFHBR5	;IF NOTHING COULD BE PAGED OUT, NOTHING CAN BE
				; PAGED IN. DO WHAT I/O CAN BE DONE
	MOVEM	T1,PFDPNI(P4)	;SET TO TOP OF IOWD
PFHBR1:	PUSHJ	P,PFHMKO	;PAGE OUT ACCUMULATION
	MOVE	T3,PFDPNI(P4)	;GET LAST PAGE NEEDED PLUS ONE
	SUB	T3,PFDSNI(P4)	;GET NUMBER OF PAGES INCREASE WE NEED
	ADDI	T3,1		;PREINCREMENT BEFORE BINARY SEARCH SETUP
	JFFO	T3,.+1		;FIND HIGH ORDER BIT
	MOVSI	T3,(1B0)	;A BIT
	MOVNS	T4		;MAKE THIS NEGATIVE SHIFT
	LSH	T3,(T4)		;AND GET STARTING QUANTITY TO USE
	MOVE	T2,T3		;COPY STARTING QUANTITY
PFHBR2:	ASH	T2,-1		;HALF QUANTITY
	PUSHJ	P,GSIZI##	;CAN WE FIT THIS MUCH IN?
	  JFCL			;NO
	  JRST	PFHBR3		;DECREMENT AMOUNT WE ARE ASKING FOR
	ADD	T3,T2		;IT FITS, TRY FOR SOME MORE
	JUMPN	T2,PFHBR2	;AND LOOP
	JRST	PFHBR4		;DONE, JOIN COMMON CODE
PFHBR3:	SUB	T3,T2		;DOESN'T FIT, TRY A LITTLE LESS
	JUMPN	T2,PFHBR2	;AND LOOP TRYING TO FIND IDEAL SIZE
	SUBI	T3,1		;DIDN'T FIT, BACK IT DOWN TO PREVIOUS SIZE
	JUMPE	T3,CPOPJ##	;ERROR IF NOTHING FOUND TO PAGE OUT
;Bring what we can into core
PFHBR4:	MOVE	T1,PFDRSN(P4)	;FUNCTION CODE FOR PAGE. UUO
	MOVN	T2,T3		;NUMBER OF PAGES TO DO
	ADD	T3,PFDSNI(P4)	;POINT TO FIRST PAGE AFTER WHAT WE WILL DO
	EXCH	T3,PFDSNI(P4)	;STARTING PAGE TO PAGE IN
	PUSHJ	P,DOPAGE	;DO THE PAGE UUO
PFHBR5:	MOVE	T1,PFDSNI(P4)	;GET FIRST INACCESSIBLE PAGE
	SUBI	T1,1		;MAKE IT LAST ACCESSIBLE PAGE
	MOVE	P1,PFDBAS(P4)	;GET STARTING LOCATION FOR DUMP IO
	DPB	T1,[POINT UPGWID,P1,26] ;MAKE A POINTER TO LAST ACCESSIBLE PAGE
	CAMG	P1,PFDBAS(P4)	;MAKE SURE WE ENDED UP WITH SOMETHING HIGHER
	  STOPCD	.,JOB,PFNOIO, ;++ PFH HAS NO IO TO DO (I'M STUCK!)
	SOS	P1		;BACK DOWN TO DO EXACT MULTIPLE OF PAGESIZE
;	PJRST	PFDOIO		;FALL INTO PFDOIO, DO THE IO AND RETURN
;PFDOIO - Do accumulated IO.
;Call
;	P4/ Block, with
;	    PFHBAS(P4)/ First word affected by IO. Updated at end of call.
;	    PFDEVM(P4)/ Amount of EVM we have, if any. Updated if necessary.
;	    PFDISP(P4)/ Address of filio routine to dispatch to
;	P1/ Last address checked
;Return
;	RET	On an IO error of some kind
;	RETSKP	everything o.k., PFDBAS points at new address

PFDOIO:	PUSH	P,P3		;SAVE P REGISTER THAT WE TRASH
	MOVE	P3,P1		;LAST WORD CHECKED
	SUB	P3,PFDBAS(P4)	;NUMBER OF WORDS TO DO MINUS ONE
	HLRZ	T1,PFDBAS(P4)	;GET SECTION NUMBER
	HRRM	T1,DEVISN(F)	;STASH IT IN DDB
	MOVEI	T1,DEPEVM	;"DOES NOT NEED EVM" BIT
	TDNN	T1,DEVTYP(F)	;DO WE NEED TO GET EVM?
	CAML	P3,PFDEVM(P4)	;YES, DO WE ALREADY HAVE ENOUGH?
	JRST	DOIO2		;SAFE, JUST DO THE IO
	PUSHJ	P,RTNEVM##	;CURRENT EVM ISN'T ENOUGH, GIVE IT BACK
	MOVEI	T1,1(P3)	;AMOUNT OF EVM WE WILL NEED
	MOVE	T3,PFDBAS(P4)	;WHERE WE ARE GOING TO DO IO
	PUSHJ	P,GTEVBF##	;GET EVM FOR IT
	  JRST	UADERR##	;NO CAN GET, BOMB OUT
	MOVEM	P3,PFDEVM(P4)	;INDICATE HOW MUCH EVM WE HAVE
DOIO2:
IFN FTXMON,<
	HRRZ	T1,DEVISN(F)	;SECTION NUMBER FOR I/O
	PUSHJ	P,STPCS##	;SETUP PCS FOR THAT SECTION
>
	HRRZ	T1,PFDBAS(P4)	;FIRST WORD TOUCHED BY I/O
	ADDM	P3,PFDBAS(P4)	;POINT TO ENDING WORD
	SKIPGE	USRHCU##	;IF SAVE IN PROGRESS,
	JRST	DOIO3		;ASSUME COMCON KNOW'S WHAT IT'S DOING
	MOVE	T2,T1		;COPY RELATIVE STARTING ADDRESS
	ADD	T2,P3		;MAKE RELATIVE ENDING ADDRESS FOR ZRNGE
	PUSH	P,T1		;ZRNGE CLOBBERS T1
	SKIPE	.USWLP		;IF ANY WRITE LOCKED PAGES,
	PUSHJ	P,ZRNGE##	;MAKE SURE THEY ARE ALL WRITE ENABLED
	  JFCL			;ALLOW FOR SKIP RETURN
IFN FTXMON,<
	HRRZ	T1,DEVISN(F)	;GET STARTING SECTION AGAIN
	SKIPN	T1		;IF FROM S0,
	TLNN	T2,-1		;AND CROSSED A SECTION BOUNDARY
	TRNA			;(NSZ OR SINGLE-SECTION IS OK)
	S0JRST	ADRERR##	;COMPLAIN ABOUT I/O TO THE ACS
> ;END IFN FTXMON
	POP	P,T1		;RESTORE T1
DOIO3:	AOS	PFDBAS(P4)	;POINT TO FIRST WORD BEYOND THIS TRANSFER
	HRLO	P3,P3		;NUMBER OF WORDS TO DO
	EQV	T1,P3		;MAKE AN IOWD OUT OF IT
	HRRI	T1,-1(T1)	;IOWD POINTS AT ADDR-1
	SETZ	T2,		;IOWD TERMINATOR
	DMOVEM	T1,.JDAT+JOBUAL## ;STASH FOR FILIO
	LDB	T1,PJOBN##	;GET JOB NUMBER FOR THIS DEVICE
	CAME	T1,.CPJOB##	;MAKE SURE IT BELONGS TO US
	STOPCD	.,JOB,PFHJOB,	;++ WRONG JOB OWNS DEVICE
IFN FTXMON,<
	SETZ	T1,		;JOBUAL IS IN S0
	PUSHJ	P,STPCS##	;MAKE SURE DRIVER KNOWS THAT
>
	MOVE	T1,PFDISP(P4)	;GET DISPATCH ADDRESS
	MOVEI	M,JOBUAL##	;POINT TO IOWD
	S0PSHJ	0(T1)		;AND DISPATCH.
	MOVE	J,.CPJOB##	;GET BACK JOB NUMBER (TRASHED BY IO ROUTINES)
	MOVE	R,JBTADR##(J)	;DITTO
	PUSHJ	P,WAIT1##	;LET THINGS QUIET DOWN
	POP	P,P3		;RESTORE TRASHED P REGISTER, FIXUP STACK
	TRNE	S,IOBKTL+IODTER+IODERR+IOIMPM+IODEND ;ANY ERRORS?
	POPJ	P,		;UH OH, AN ERROR, RETURN NON-SKIP
	RETSKP			;DONE, EVERYTHING HUNKY DORY
;PFHIOX - Cause an ill addr in uuo
;Call
;	P1/ Address which we believe will cause an ill mem ref
;Return
;	you can't.

PFHIOX:	MOVE	M,P1		;ADDRESS WHICH FAILS
	PJRST	UADERR##	;GIVE THE USER THE BAD NEWS
	SUBTTL	MIGRATION

;Routine to handle bad page migration. Called at clock level.

PFHMIG::PUSHJ	P,SVEUB##
	SKIPN	.USVRT		;VIRTUAL?
	JRST	CPOPJ1##	;NO, CAN'T HAVE ANY BAD PAGES THEN
	SE1ENT
	PUSHJ	P,SAVE4##	;SAVE SOME ACS
	PUSHJ	P,SAVT##
	MOVE	R,JBTADR##(J)	;LOAD R FOR UPAGE.
	SETZB	M,.USSPT	;START WITH SECTION 0
PFHMI0:	PUSHJ	P,NXTNWS##	;GET A NON-WORKING SET PAGE
	CAIA			;(FIRST TIME AROUND)
PFHMI1:	PUSHJ	P,NXTNW3##	;GET NEXT NON-WORKING SET PAGE
	JUMPE	T4,PFHMI6	;DONE THIS SECTION
	PUSHJ	P,TSTUN##	;ON BAD UNIT?
	  CAIA			;YES, NEED TO DO SOMETHING
	JRST	PFHMI1		;NOT ON BAD UNIT, LOOK AGAIN
	TLOE	M,2		;SET WE NEED TO DO SOMETHING
	JRST	PFHM5A		;DON'T DO THIS STUFF AGAIN
	PUSH	P,T1		;SAVE ACS USED BY SIMCHK
	PUSH	P,T2
	PUSHJ	P,SIMCHK##	;CAN JOB BE STOPPED NOW (OK TO DIDDLE WS)?
	  JRST	PFHMI5		;OK TO STOP JOB
	ADJSP	P,-2		;FIX STACK
	TLO	J,400000	;SET SIGN BIT
	JRST	CPOPJ1##
PFHMI5:	SETOB	P2,P3		;ACS FOR OUTPAG
	MOVEI	P4,-1(P)	;BLOCK FOR SAVING WORKING SET INFO
	ADJSP	P,5-2		;T1-T3,M,.USSPT
	PUSHJ	P,EXCHT1	;SAVE THE INFO
	PUSHJ	P,GETPLM	;PSI VECTOR
	PUSH	P,T1
	PUSH	P,T2		;SAVE START, END
	PUSHJ	P,GETJLM	;JOBINT VECTOR
	PUSH	P,T1
	PUSH	P,T2
	HRRZ	T1,.USPFH	;USER PFH, IF ANY
	PUSH	P,T1
	HLRZ	T1,.USPFH
	PUSH	P,T1
	MOVE	T1,JBTIMI##(J)	;SAVE JBTIMI NOW
	PUSH	P,T1
	SETZB	M,.USSPT	;JUNK STORED BY EXCHT
	PUSHJ	P,NXTWSB##	;START LOOKING FOR LEGIT PAGE-OUT PAGES
	CAIA			;(ALREADY EXCH'D)
PFHM5A:	PUSHJ	P,EXCHT		;SAVE NWS INFO, GET WS INFO
PFHMI2:	PUSHJ	P,NXTWS3##	;GET NEXT WORKING SET PAGE
				;(SKIP REAL PAGE 0 ONLY)
PFHMI3:	TRNE	M,<-1^!HLGPNO>	;USER PAGE?
	JRST	PFHMI4		;NO
	MOVE	P1,.USSPT	;SECTION
	LSH	P1,S2PLSH	;PAGE
	IORI	P1,(M)
	CAML	P1,-6(P)	;IN THE PSI VECTOR?
	CAMLE	P1,-5(P)
	CAIA			;NO
	JRST	PFHMI2
	CAML	P1,-4(P)
	CAMLE	P1,-3(P)	;OR THE JOBINT VECTOR?
	SKIPA	T4,(T4)		;GET PAGE MAP ENTRY FOR NEXT TEST
	JRST	PFHMI2
	CAML	P1,-2(P)	;FINALLY A USER PFH
	CAMLE	P1,-1(P)
	TLNN	T4,(PM.COR)	;IS PAGE IN CORE (OR DID WE SET TO PAGE THIS IN)
	JRST	PFHMI2
	TLO	M,1
	ADJSP	P,3
	DMOVEM	T1,-2(P)
	MOVEM	T3,(P)
	PUSHJ	P,OUTPAG
	DMOVE	T1,-2(P)
	MOVE	T3,(P)		;AND T3
	PUSHJ	P,EXCHT		;NWS ACS
	PUSHJ	P,BTCOM##	;SET BIT
	DMOVEM	T1,-2(P)	;SAVE T1, T2
	MOVEM	T3,(P)		;AND T3
	MOVE	T1,.USSPT
	LSH	T1,S2PLSH
	IORI	T1,(M)		;PAGE #
	PUSHJ	P,INCHJ##
	POP	P,T3
	POP	P,T2
	POP	P,T1
	JRST	PFHMI1		;LOOP FOR ANOTHER NWS PAGE

PFHMI4:	SKIPL	.USBTS		;AN EXTENDED USER?
	JRST	PFHMI8		;NO, CAN'T DO ANYTHING FOR HIM
PFHM4A:	AOS	T4,.USSPT	;INCREMENT SECTION
	CAILE	T4,MXSECN	;OVER THE TOP?
	JRST	PFHMI8		;YES, CAN'T DO ANYTHING THEN
	SKIPE	T1,.UPMP+SECTAB(T4) ;SECTION EXISTS?
	TLNE	T1,(<PM.ACD^!PM.DCD>B2) ;INDIRECT?
	JRST	PFHM4A		;NO
	PUSHJ	P,NXTWSB##	;GET NEXT WORKING SET BIT
	JRST	PFHMI3		;AND LOOK AT IT

PFHMI6:	SKIPL	.USBTS		;EXTENDED USER?
	JRST	PFHMI7		;NO, DONE
PFHM6A:	AOS	T4,.USSPT	;INCREMENT SECTION
	CAILE	T4,MXSECN	;BELOW MAX?
	JRST	PFHMI7		;NO
	SKIPE	T1,.UPMP+SECTAB(T4) ;EXIST?
	TLNE	T1,(<PM.DCD^!PM.ACD>B2) ;INDIRECT?
	JRST	PFHM6A
	JRST	PFHMI0

PFHMI7:	TLNN	M,2		;WANT TO DO ANYTHING
	JRST	CPOPJ1##	;NO, NOTHING TO DO
	PUSHJ	P,EXCHT		;GET THE WS ACS BACK
PFHMI8:	TLNE	M,1		;DO ANYTHING INTERESTING?
	JRST	PFHMI9		;YES
	PUSHJ	P,EXCHT		;GET NWS ACS
	TLNN	M,2		;WANT TO DO ANYTHING INTERESTING
	JRST	CPOPJ1##	;NOTHING TO DO
	PUSHJ	P,BTCOM##	;SET BIT
	AOS	(P)		;INCREMENT SAVED IMGIN
	.CREF	IMGIN
	MOVE	T1,.USSPT
	LSH	T1,S2PLSH
	IORI	T1,(M)		;PAGE #
	PUSHJ	P,INCHJ##
	JRST	PFHM10
PFHMI9:	SETO	P1,
	PUSHJ	P,OUTPAG	;FLUSH PAGES
PFHM10:	LDB	T1,IMGIN##	;SIZE-PAGES PAGED OUT
	DPB	T1,IMGOUT##
	POP	P,JBTIMI##(J)	;(# OF MAPS HASN'T CHANGED)
	.CREF	IMGIN
	ADJSP	P,-<5+6>	;FIX STACK
	POPJ	P,

;Subroutine to save relevant working set information.

EXCHT:	EXCH	T1,(P4)
	EXCH	T2,1(P4)
EXCHT1:	EXCH	T3,2(P4)
	EXCH	M,3(P4)
	PUSH	P,.USSPT
	PUSH	P,4(P4)
	POP	P,.USSPT
	POP	P,4(P4)
	POPJ	P,
	END