(FILECREATED " 6-AUG-83 22:47:24" {PHYLUM}<LISPCORE>SOURCES>LLFAULT.;28 275476Q changes to: (FNS \DONEWPAGE \DONEWEPHEMERALPAGE \INVALIDADDR \INVALIDVP) previous date: "12-JUL-83 18:30:45" {PHYLUM}<LISPCORE>SOURCES>LLFAULT.;27) (* Copyright (c) 1982, 1983 by Xerox Corporation) (PRETTYCOMPRINT LLFAULTCOMS) (RPAQQ LLFAULTCOMS [(FNS \FAULTHANDLER) (VARS (FAULTTEST T)) (FNS \FAULTINIT \D01.FAULTINIT \DL.FAULTINIT \DL.NEWFAULTINIT \D01.ASSIGNBUFFERS \DL.ASSIGNBUFFERS) (FNS \PAGEFAULT \INVALIDADDR \INVALIDVP \FLUSHPAGE \LOADVMEMPAGE \LOOKUPPAGEMAP \MARKPAGEVACANT \SELECTREALPAGE \SPECIALRP \TRANSFERPAGE \MOVEPAGE \ZEROPAGE \UPDATECHAIN) (FNS \NEWPAGE \DONEWPAGE \MAKESPACEFORLOCKEDPAGE \NEWEPHEMERALPAGE \DONEWEPHEMERALPAGE \LOCKPAGES \DOLOCKPAGES \TEMPLOCKPAGES \TEMPUNLOCKPAGES \UNLOCKPAGES \FLUSHVM \LOGOUT0 \DOFLUSHVM \RELEASEWORKINGSET \WRITEDIRTYPAGE \WRITEDIRTYPAGE1 \NPAGESBIT) (INITVARS (\UPDATECHAINFREQ 100) (\PAGEFAULTCOUNTER 0) (\DIRTYPAGECOUNTER 0) (\DIRTYPAGEHINT 0) (\LASTACCESSEDVMEMPAGE 0) (\MAXSHORTSEEK 1000) (\MINSHORTSEEK 20) (\MAXCLEANPROBES 20) (\VMEM.INHIBIT.WRITE) (\DOFAULTINIT 0) (\FPTOVP) (\VMEMACCESSFN) (\SYSTEMCACHEVARS)) (INITVARS (\LASTDIRTYCNT) (\LASTDIRTYFOUND) (\LASTDIRTYSCANPTR) (\DIRTYSEEKMAX 50)) (COMS (* Errors) (FNS \MP.ERROR) (DECLARE: EVAL@COMPILE DONTCOPY (CONSTANTS * \MPERRORS))) (COMS (* Debugging) (FNS \ACTONVMEMFILE \SHOWPAGETABLE CHECKPAGEMAP CHECKFPTOVP \LOCKED?STRING \PRINTFPTOVP \PRINTVP)) (E (RESETSAVE (RADIX 8))) (DECLARE: EVAL@COMPILE DONTCOPY (MACROS \ACTONVMEMFILE) (COMS (* Virtual page flags) (CONSTANTS \VMAP.DIRTY \VMAP.CLEAN \VMAP.REF \VMAP.VACANT \VMAP.FLAGS \VMAP.NOTFLAGS) (RECORDS VMEMFLAGS) (MACROS LOGNOT16)) (COMS (* RPT constants) (CONSTANTS \PAGEMAPLOCKBIT \RPT.EMPTY \RPT.UNAVAILABLE \PAGETABLESTOPFLG \RPTENTRYLENGTH) (RECORDS RPT) (MACROS RPFROMRPT RPTFROMRP)) (COMS (* Virtual to file pagemap) (CONSTANTS \MAXVMPAGE \MAXVMSEGMENT \EMPTYPMTENTRY) (RECORDS VP PAGEMAPENTRY)) (COMS (* FP to VP stuff) (RECORDS FPTOVP) (CONSTANTS \NO.VMEM.PAGE) (MACROS DLRPFROMFP DLFPFROMRP)) (PROP DOPVAL \TOUCHPAGE TIMES3) (CONSTANTS \MAXDIRTYSCANCOUNT \MINVMEMSPAREPAGES \DLBUFFERPAGES) (GLOBALVARS \UPDATECHAINFREQ \REALPAGETABLE \RPOFFSET \RPTSIZE \EMBUFBASE \EMBUFVP \EMBUFRP \PAGEFAULTCOUNTER \LASTDIRTYCNT \LASTDIRTYFOUND \LASTDIRTYSCANPTR \MACHINETYPE \LASTACCESSEDVMEMPAGE \MAXSHORTSEEK \MAXCLEANPROBES \MINSHORTSEEK \DIRTYSEEKMAX \DIRTYPAGECOUNTER \DIRTYPAGEHINT \VMEM.INHIBIT.WRITE \KBDSTACKBASE \MISCSTACKBASE \DOFAULTINIT \FPTOVP \VMEMACCESSFN \SYSTEMCACHEVARS) (GLOBALVARS \#SWAPBUFFERS \#EMUBUFFERS \#DISKBUFFERS \EMUSWAPBUFFERS \EMUBUFFERS \TELERAIDBUFFER \EMUDISKBUFFERS \EMUDISKBUFEND)) [COMS (* * MAKEINIT stuff) (FNS ADDPME CHECKIFPAGE FIXIFPAGE DUMPINITPAGES MAKEROOMFORPME MAPPAGES READPAGEMAP READPAGEMAPBLOCK SETUPPAGEMAP) (DECLARE: DONTCOPY (MACROS CHECKIF) (ADDVARS (INEWCOMS (FNS DUMPINITPAGES) (VARS INITCONSTANTS) (FNS SETUPPAGEMAP ADDPME MAKEROOMFORPME MAPPAGES)) (RDCOMS (FNS READPAGEMAP READPAGEMAPBLOCK CHECKIFPAGE FIXIFPAGE)) (EXPANDMACROFNS CHECKIF) (MKI.SUBFNS (\NEWPAGE . MKI.NEWPAGE) (\LOCKPAGES . MKI.LOCKPAGES)) (RD.SUBFNS (\NEWPAGE . VNEWPAGE) (\LOCKPAGES . VLOCKPAGES))) EVAL@COMPILE (ADDVARS (DONTCOMPILEFNS DUMPINITPAGES SETUPPAGEMAP ADDPME MAKEROOMFORPME MAPPAGES READPAGEMAP READPAGEMAPBLOCK CHECKIFPAGE] (FNS \LOCKFN \LOCKCODE \LOCKVAR \LOCKCELL \LOCKWORDS) [DECLARE: DONTCOPY (ADDVARS (INEWCOMS (ALLOCAL (ADDVARS (LOCKEDFNS \FAULTHANDLER \FAULTINIT \D01.FAULTINIT \DL.FAULTINIT \MAKESPACEFORLOCKEDPAGE \PAGEFAULT \READRP \READFLAGS \WRITEMAP \LOOKUPPAGEMAP \LOADVMEMPAGE \INVALIDADDR RAID \INVALIDVP \SELECTREALPAGE \TRANSFERPAGE \UPDATECHAIN \MARKPAGEVACANT \FLUSHPAGE \MOVEPAGE \ZEROPAGE \FLUSHVM \DONEWPAGE \DONEWEPHEMERALPAGE \WRITEDIRTYPAGE1 \COPYSYS0 \COPYSYS0SUBR \RELEASEWORKINGSET \DOFLUSHVM \DOLOCKPAGES \TEMPLOCKPAGES \TEMPUNLOCKPAGES \MP.ERROR \DL.NEWFAULTINIT \DL.ASSIGNBUFFERS \D01.ASSIGNBUFFERS) (LOCKEDVARS \REALPAGETABLE \PAGEFAULTCOUNTER \UPDATECHAINFREQ \RPOFFSET \RPTSIZE \EMBUFBASE \EMBUFVP \EMBUFRP \LASTACCESSEDVMEMPAGE \MAXSHORTSEEK \MAXCLEANPROBES \MINSHORTSEEK \DIRTYPAGECOUNTER \DIRTYPAGEHINT \VMEM.INHIBIT.WRITE \KBDSTACKBASE \MISCSTACKBASE \DOFAULTINIT \FPTOVP \MACHINETYPE \VMEMACCESSFN \TELERAIDBUFFER \EMUDISKBUFFERS \EMUDISKBUFEND))) (FNS \LOCKFN \LOCKVAR \LOCKCELL \LOCKWORDS \LOCKCODE] (COMS (* Clock stuff) (FNS \CLOCK0 \DAYTIME0 \GETINTERNALCLOCK \SETDAYTIME0 \CLOCKDIFFERENCE \RCLOCK0) (FNS CLOCK0) (MACROS \RCLOCK0) (DECLARE: DONTCOPY (EXPORT (MACROS \UPDATETIMERS))) [DECLARE: DONTEVAL@LOAD DOCOPY (P (MOVD (QUOTE \DAYTIME0) (QUOTE DAYTIME0] (VARS (\RCLKMILLISECOND 1680)) (GLOBALVARS \RCLKSECOND \RCLKMILLISECOND) (DECLARE: DONTCOPY (* Locations in alto emulator) (EXPORT (CONSTANTS (\RTCSECONDS 378) (\RTCMILLISECONDS 380) (\RTCBASE 382) (\OFFSET.SECONDS 0) (\OFFSET.MILLISECONDS 2) (\OFFSET.BASE 4) (\ALTO.RCLKSECOND 1680000) (\ALTO.RCLKMILLISECOND 1680) (\DLION.RCLKMILLISECOND 35) (\DLION.RCLKSECOND 34746))) (* Locked stuff. Have to lock anything used by pagefault code, including the ufns that they use until all microcodes have them) (ADDVARS (INEWCOMS (ALLOCAL (ADDVARS (LOCKEDFNS \CLOCK0 \GETINTERNALCLOCK \BOXIDIFFERENCE \BOXIPLUS \BLT \SLOWIQUOTIENT) (LOCKEDVARS \RCLKSECOND \RCLKMILLISECOND \MISCSTATS]) (DEFINEQ (\FAULTHANDLER [LAMBDA NIL (* bvm: "31-MAR-83 17:34") (PROG NIL LP [OR (AND \DOFAULTINIT (\FAULTINIT)) (\PAGEFAULT (\VAG2 (fetch (IFPAGE FAULTHI) of \InterfacePage) (fetch (IFPAGE FAULTLO) of \InterfacePage] (\CONTEXTSWITCH \FAULTFXP) (GO LP]) ) (RPAQQ FAULTTEST T) (DEFINEQ (\FAULTINIT [LAMBDA NIL (* bvm: "31-MAR-83 17:42") (* * retrieves some constants from Interface page for the swapper and performs other initialization that must happen immediately. Called when starting up, and also when \FAULTHANDLER context starts, in case init hasn't happened yet, as e.g. from MAKEINIT) (SETQ \FPTOVP (AND (NOT (ZEROP (fetch FPTOVPStart of \InterfacePage))) (create POINTER PAGE# ← \VP.FPTOVP))) (SETQ \LASTDIRTYSCANPTR) (SELECTC (SETQ \MACHINETYPE (fetch MachineType of \InterfacePage)) (\DANDELION (\DL.FAULTINIT)) (\D01.FAULTINIT)) (COND ((EQ (PROG1 \DOFAULTINIT (SETQ \DOFAULTINIT NIL)) T) (* true after \FLUSHVM. Need to rebuild some contexts) (replace (IFPAGE KbdFXP) of \InterfacePage with (\MAKEFRAME (COND ((fetch (LITATOM CCODEP) of (QUOTE \KEYHANDLER)) (FUNCTION \KEYHANDLER)) (T (QUOTE \DUMMYKEYHANDLER))) \KBDSTACKBASE (IPLUS \KBDSTACKBASE \StackAreaSize) 0 0)) (replace (IFPAGE MiscFXP) of \InterfacePage with (\MAKEFRAME (FUNCTION \DOMISCAPPLY) \MISCSTACKBASE (IPLUS \MISCSTACKBASE \StackAreaSize) 0 0)) T]) (\D01.FAULTINIT [LAMBDA NIL (* bvm: "12-JUL-83 18:25") (SETQ \VMEMACCESSFN (FUNCTION \M44ACTONVMEMFILE)) (SETQ \REALPAGETABLE (EMPOINTER (fetch (IFPAGE REALPAGETABLE) of \InterfacePage))) (* Note: these SETQ's do not reference count, since the values are all smallp's and emulator addresses (in atom space)) (SETQ \RPOFFSET (SIGNED (fetch (IFPAGE RPOFFSET) of \InterfacePage) BITSPERWORD)) (SETQ \RPTSIZE (fetch (IFPAGE RPTSIZE) of \InterfacePage)) (* Initialize the software clocks from alto emulator) (\BLT (LOCF (fetch SECONDSCLOCK of \MISCSTATS)) (EMADDRESS \RTCSECONDS) (UNFOLD 3 WORDSPERCELL)) (SETQ \RCLKMILLISECOND \ALTO.RCLKMILLISECOND) (* Initialize SECOND and MILLISECOND constants. \RCLKSECOND is large and has to live on \MISCSTATS, since there is no convenient way to lock a random cell) (SETQ.NOREF \RCLKSECOND (LOCF (fetch RCLKSECOND of \MISCSTATS))) (* If it were SETQ, it could reference count, which could fault...) (\PUTBASE \RCLKSECOND 0 (LRSH \ALTO.RCLKSECOND 16)) (\PUTBASE \RCLKSECOND 1 (LOGAND \ALTO.RCLKSECOND 65535)) (\D01.ASSIGNBUFFERS]) (\DL.FAULTINIT [LAMBDA NIL (* bvm: " 8-APR-83 14:52") (SETQ \VMEMACCESSFN (FUNCTION \DL.ACTONVMEMFILE)) (SETQ \IOCBPAGE (create POINTER PAGE# ← \VP.IOCBS)) (COND ((NEQ (fetch (IFPAGE Key) of \InterfacePage) \IFPValidKey) (\MP.ERROR \MP.INVALIDVMEM))) (COND ((NULL \FPTOVP) (SETQ \REALPAGETABLE (EMPOINTER (fetch (IFPAGE REALPAGETABLE) of \InterfacePage))) (SETQ \RPOFFSET (SIGNED (fetch (IFPAGE RPOFFSET) of \InterfacePage) BITSPERWORD)) (SETQ \RPTSIZE (fetch (IFPAGE RPTSIZE) of \InterfacePage)) (SETQ \EMBUFVP (fetch (IFPAGE EMBUFVP) of \InterfacePage)) (SETQ \EMBUFBASE (EMPOINTER (UNFOLD \EMBUFVP WORDSPERPAGE))) (SETQ \EMBUFRP (\READRP \EMBUFVP)) (* * the bootstrapping process leaves some information about the disk in page 1 of the display bank. BLT this up into the IOCB page) (\BLT \IOCBPAGE (create POINTER PAGE# ←(ADD1 \VP.DISPLAY)) WORDSPERPAGE)) (T (\DL.NEWFAULTINIT))) (SETQ \RCLKMILLISECOND \DLION.RCLKMILLISECOND) (* These are fortunately both small) (SETQ \RCLKSECOND \DLION.RCLKSECOND) (\RCLK (LOCF (fetch BASECLOCK of \MISCSTATS))) (* Reset base clock) [COND ((ZEROP (fetch DLTODVALID of \IOPAGE)) (* Time not valid, so store zero in the clock) (\PUTBASEPTR (LOCF (fetch SECONDSCLOCK of \MISCSTATS)) 0 NIL)) (T (bind TMP (BASE ←(LOCF (fetch SECONDSCLOCK of \MISCSTATS))) do (* Loop until clock reads the same as we wrote, in case it was being updated) (\PUTBASE BASE 1 (SETQ TMP (fetch DLTODLO of \IOPAGE))) (\PUTBASE BASE 0 (fetch DLTODHI of \IOPAGE)) repeatuntil (EQ (fetch DLTODLO of \IOPAGE) TMP] (\PUTBASEPTR (LOCF (fetch MILLISECONDSCLOCK of \MISCSTATS)) 0 NIL) (* Clear the milliseconds timer) (repeatwhile (IGEQ (fetch DLPROCESSORCMD of \IOPAGE) \DL.PROCESSORBUSY)) (* Wait for IOP readiness) (replace DLPROCESSORCMD of \IOPAGE with \DL.READPID) (* Ask it to give the processor ID (3 words)) (repeatwhile (IGEQ (fetch DLPROCESSORCMD of \IOPAGE) \DL.PROCESSORBUSY)) (replace NSHost0 of \InterfacePage with (fetch DLPROCESSOR0 of \IOPAGE)) (replace NSHost1 of \InterfacePage with (fetch DLPROCESSOR1 of \IOPAGE)) (replace NSHost2 of \InterfacePage with (fetch DLPROCESSOR2 of \IOPAGE)) (\DL.DISKINIT T]) (\DL.NEWFAULTINIT [LAMBDA NIL (* bvm: " 7-APR-83 01:24") (* We have just started up on a DLion. Boot code has loaded the first n pages of the sysout into pages 2 thru n-3, except for the area covered by the map and IO page, and has built the map accordingly. Our principal task is to build \REALPAGETABLE) (PROG ((NREALPAGES (fetch (IFPAGE NRealPages) of \InterfacePage)) (FIRSTBUFFERRP \RP.STARTBUFFERS) (SCRATCHVP \VP.INITSCRATCH) (SCRATCHBASE (create POINTER PAGE# ← \VP.INITSCRATCH)) (DISPLAYBASE (create POINTER PAGE# ← \VP.DISPLAY)) FIRSTUSEFULRP IFPAGERP IOCBRP RPTPAGES RPTBASE VP) [do (COND ((for I from 0 to (SUB1 \DLBUFFERPAGES) as (FPBASE ←(\ADDBASE \FPTOVP (DLFPFROMRP FIRSTBUFFERRP))) by (\ADDBASE FPBASE 1) do (COND ((OR (NOT (fetch FPOCCUPIED of FPBASE)) (fetch FPLOCKED of FPBASE)) (* Can't use as buffer. This is just a check for consistency; you should pick \RP.STARTBUFFERS so that this isn't a problem) (RETURN T))) (* Unmap this page so we can use it for buffers) (\WRITEMAP (fetch FPVIRTUALPAGE of FPBASE) 0 \VMAP.VACANT)) (* Bad starting place, try again) (add FIRSTBUFFERRP 1)) (T (RETURN] (SETQ FIRSTUSEFULRP (IPLUS FIRSTBUFFERRP \DLBUFFERPAGES)) (PROGN (* Copy vital info that booting left in page 1) (SETQ IOCBRP (IPLUS (LOGAND (SUB1 NREALPAGES) 177400Q) \VP.IOCBS)) (* Temporary until Steve fixes swap code to not care what RP contains IOCB's) (SETQ VP (\GETBASE \FPTOVP (DLFPFROMRP IOCBRP))) (COND ((fetch LOCKEDP of VP) (\MP.ERROR \MP.IOCBPAGE)) (T (\WRITEMAP VP 0 \VMAP.VACANT))) (* Unmap whoever lived in our target page) (\WRITEMAP \VP.IOCBS IOCBRP \VMAP.CLEAN) (\WRITEMAP SCRATCHVP 1 \VMAP.CLEAN) (\BLT \IOCBPAGE SCRATCHBASE WORDSPERPAGE)) (PROGN (* Copy InterfacePage out of segment zero) (\WRITEMAP SCRATCHVP FIRSTBUFFERRP \VMAP.CLEAN) (\BLT SCRATCHBASE \InterfacePage WORDSPERPAGE) (\WRITEMAP \VP.IFPAGE (SETQ IFPAGERP FIRSTBUFFERRP) \VMAP.CLEAN) (add FIRSTBUFFERRP 1)) (for (FP ←(ADD1 \FP.IFPAGE)) to (DLFPFROMRP \RP.IOPAGE) as (FPBASE ←(\ADDBASE \FPTOVP (ADD1 \FP.IFPAGE))) by (\ADDBASE FPBASE 1) when (fetch FPOCCUPIED of FPBASE) do (* Unmap everything that might have been mapped into real segment zero or to map or IOPAGE) (\WRITEMAP (fetch FPVIRTUALPAGE of FPBASE) 0 \VMAP.VACANT)) (PROGN (* Copy Display into segment zero) (for I from 0 to (SUB1 \NP.DISPLAY) do (\WRITEMAP (IPLUS SCRATCHVP I) (IPLUS \RP.DISPLAY I) \VMAP.CLEAN)) (* Point scratch area at real segment zero) (\BLT SCRATCHBASE DISPLAYBASE (UNFOLD \NP.DISPLAY WORDSPERPAGE)) (* Copy display from wherever boot put it) (for I from 0 to (SUB1 \NP.DISPLAY) do (\WRITEMAP (IPLUS SCRATCHVP I) 0 \VMAP.VACANT) (\WRITEMAP (IPLUS \VP.DISPLAY I) (IPLUS \RP.DISPLAY I) \VMAP.CLEAN)) (* Display is now where hardware wants it) ) (PROGN (* Construct real page table in segment zero after the display) (SETQ \RPTSIZE (IDIFFERENCE NREALPAGES (SETQ \RPOFFSET -1))) (SETQ RPTPAGES (FOLDHI (TIMES3 \RPTSIZE) WORDSPERPAGE)) (COND ((IGREATERP (IPLUS RPTPAGES \RP.AFTERDISPLAY) PAGESPERSEGMENT) (\MP.ERROR \MP.NORPT "No space for RPT"))) (for I from 0 to (SUB1 RPTPAGES) do (\WRITEMAP (IPLUS \VP.RPT I) (IPLUS \RP.AFTERDISPLAY I) \VMAP.CLEAN)) (SETQ \REALPAGETABLE (create POINTER PAGE# ← \VP.RPT)) [\ZEROWORDS \REALPAGETABLE (\ADDBASE \REALPAGETABLE (SUB1 (TIMES3 \RPTSIZE] (* Clear it out for reduction of confusion; not logically necessary) ) [PROGN (* Fill in RPT with info from \FPTOVP) (SETQ RPTBASE \REALPAGETABLE) [for I from 0 to (SUB1 \NP.DISPLAY) do (SETQ RPTBASE (\ADDBASE RPTBASE \RPTENTRYLENGTH)) (* Fill in Display pages) (replace (RPT VP) of RPTBASE with (IPLUS \VP.DISPLAY I)) (replace (RPT FILEPAGE&LOCK) of RPTBASE with (LOGOR \PAGEMAPLOCKBIT (DLFPFROMRP (IPLUS \RP.TEMPDISPLAY I] (for I from \NP.DISPLAY to \RP.IOPAGE do (SETQ RPTBASE (\ADDBASE RPTBASE \RPTENTRYLENGTH)) (* Mark rest of segment zero plus Map and IOPAGE unavailable) (replace (RPT UNAVAILABLE) of RPTBASE with T)) (for I from (ADD1 \RP.IOPAGE) to (SUB1 NREALPAGES) as [FPBASE ←(\ADDBASE \FPTOVP (DLFPFROMRP (ADD1 \RP.IOPAGE] by (\ADDBASE FPBASE 1) do (SETQ RPTBASE (\ADDBASE RPTBASE \RPTENTRYLENGTH)) (* Fill in rest of RPT from \FPTOVP. Could optimize this a little by special casing the area occupied by the display, but this is simpler) (COND ((AND (fetch FPOCCUPIED of FPBASE) [NOT (fetch (VMEMFLAGS VACANT) of (\READFLAGS (SETQ VP (fetch FPVIRTUALPAGE of FPBASE] (EQ I (\READRP VP))) (* There is a VP assigned to this filepage, and it is still there. False for display that got moved and any real pages that didn't get filled) (replace (RPT VP) of RPTBASE with VP) (replace (RPT FILEPAGE) of RPTBASE with (DLFPFROMRP I)) (replace (RPT LOCKED) of RPTBASE with (fetch FPLOCKED of FPBASE))) (T (replace (RPT EMPTY) of RPTBASE with T] (PROGN (* Touch up RPT with the exceptions) (SETQ RPTBASE (fetch RPTRBASE of (RPTFROMRP IFPAGERP))) (* Interface Page) (replace (RPT VP) of RPTBASE with \VP.IFPAGE) (replace (RPT FILEPAGE&LOCK) of RPTBASE with (LOGOR \PAGEMAPLOCKBIT \FP.IFPAGE)) (replace (RPT UNAVAILABLE) of (fetch RPTRBASE of (RPTFROMRP IOCBRP)) with T) (* \IOCBPAGE) (for (RP ← FIRSTBUFFERRP) to (SUB1 FIRSTUSEFULRP) do (* buffer pages unavailable to swapper) (replace (RPT UNAVAILABLE) of (fetch RPTRBASE of (RPTFROMRP RP)) with T))) (PROG ((LASTEMPTY \REALPAGETABLE) (LASTUSED (\ADDBASE \REALPAGETABLE 1)) LASTUSEDRP) (* Chain RPT pages together) (SETQ RPTBASE (fetch RPTRBASE of (RPTFROMRP \RP.IOPAGE))) [for I from (ADD1 \RP.IOPAGE) to (SUB1 NREALPAGES) do (SETQ RPTBASE (\ADDBASE RPTBASE \RPTENTRYLENGTH)) (COND ((fetch (RPT UNAVAILABLE) of RPTBASE)) ((fetch (RPT EMPTY) of RPTBASE) (replace (RPT NEXTRP) of LASTEMPTY with (RPTFROMRP I)) (SETQ LASTEMPTY RPTBASE)) (T (replace (RPT NEXTRP) of LASTUSED with (RPTFROMRP I)) (SETQ LASTUSED RPTBASE) (SETQ LASTUSEDRP I] (* Finally, link the end of empty chain to front of in use chain) (replace (RPT NEXTRP) of LASTEMPTY with (fetch (RPT NEXTRP) of (\ADDBASE \REALPAGETABLE 1))) (replace (IFPAGE RPTLAST) of \InterfacePage with (RPTFROMRP LASTUSEDRP)) (replace (RPT UNAVAILABLE) of \REALPAGETABLE with T) (* Dummy first entry) ) (PROG ((NBUFFERS (IDIFFERENCE FIRSTUSEFULRP FIRSTBUFFERRP))) (* Allocate buffers) (for I from 0 to (SUB1 NBUFFERS) do (\WRITEMAP (IPLUS \VP.BUFFERS I) (IPLUS FIRSTBUFFERRP I) \VMAP.CLEAN)) (\DL.ASSIGNBUFFERS (create POINTER PAGE# ← \VP.BUFFERS) NBUFFERS]) (\D01.ASSIGNBUFFERS [LAMBDA NIL (* bvm: "12-JUL-83 18:25") (PROGN (* Assign swap buffer) (SETQ \EMBUFVP (fetch (IFPAGE EMBUFVP) of \InterfacePage)) (SETQ \EMBUFBASE (EMPOINTER (UNFOLD \EMBUFVP WORDSPERPAGE))) (SETQ \EMBUFRP (\READRP \EMBUFVP))) (PROG ((EMBUF (fetch (IFPAGE EMUBUFFERS) of \InterfacePage)) (EMLEN (fetch (IFPAGE EMUBUFLENGTH) of \InterfacePage)) EXTRALEN NPAGES) [add EMLEN (IDIFFERENCE EMBUF (SETQ EMBUF (CEIL EMBUF WORDSPERPAGE] (* Round up to a page boundary and throw out the excess) (SETQ EXTRALEN (IMOD EMLEN WORDSPERPAGE)) (add EXTRALEN (COND ((ILESSP EXTRALEN 100) (TIMES 2 WORDSPERPAGE)) (T WORDSPERPAGE))) (SETQ NPAGES (FOLDLO (SETQ EMLEN (IDIFFERENCE EMLEN EXTRALEN)) WORDSPERPAGE)) (OR (IGEQ NPAGES 4) (RAID "No swap buffer space")) (SETQ \TELERAIDBUFFER (EMPOINTER EMBUF)) (SETQ \EMUBUFFERS (\ADDBASE \TELERAIDBUFFER WORDSPERPAGE)) (SETQ \#EMUBUFFERS (SETQ NPAGES (SUB1 NPAGES))) (SETQ \#SWAPBUFFERS (IMIN \MAXSWAPBUFFERS (IQUOTIENT NPAGES 2))) (SETQ \#DISKBUFFERS (IDIFFERENCE \#EMUBUFFERS \#SWAPBUFFERS)) (SETQ \EMUDISKBUFFERS \EMUBUFFERS) (SETQ \EMUDISKBUFEND (\ADDBASE \EMUDISKBUFFERS (UNFOLD \#DISKBUFFERS WORDSPERPAGE))) (SETQ \EMUSWAPBUFFERS \EMUDISKBUFEND) (\INITBFS (\ADDBASE \EMUBUFFERS (UNFOLD NPAGES WORDSPERPAGE)) EXTRALEN T]) (\DL.ASSIGNBUFFERS [LAMBDA (BASE NPAGES) (* bvm: "12-JUL-83 17:13") (PROGN (* Allocate a page to hold name and password, and perhaps other ephemeral things) (\ZEROWORDS BASE (\ADDBASE BASE (SUB1 WORDSPERPAGE))) (replace (IFPAGE UserNameAddr) of \InterfacePage with (\LOLOC (\ADDBASE BASE 1))) (replace (IFPAGE UserPswdAddr) of \InterfacePage with (\LOLOC (\ADDBASE BASE 33))) (SETQ BASE (\ADDBASE BASE WORDSPERPAGE)) (add NPAGES -1)) (PROGN (* Assign swap buffer) (SETQ \EMBUFBASE BASE) (SETQ \EMBUFVP (fetch (POINTER PAGE#) of BASE)) (SETQ \EMBUFRP (\READRP \EMBUFVP)) (SETQ BASE (\ADDBASE BASE WORDSPERPAGE)) (add NPAGES -1)) (PROGN (* Assign ether buffers) (replace (IFPAGE MDSZoneLength) of \InterfacePage with (UNFOLD 2 WORDSPERPAGE)) (replace (IFPAGE MDSZone) of \InterfacePage with (\LOLOC BASE)) (SETQ BASE (\ADDBASE BASE (UNFOLD 2 WORDSPERPAGE))) (SETQ \TELERAIDBUFFER BASE) (SETQ BASE (\ADDBASE BASE WORDSPERPAGE)) (add NPAGES -3)) (PROGN (* Divvy up buffer space) (SETQ \#SWAPBUFFERS (SETQ \#EMUBUFFERS NPAGES)) (SETQ \#DISKBUFFERS 0) (SETQ \EMUSWAPBUFFERS (SETQ \EMUBUFFERS BASE]) ) (DEFINEQ (\PAGEFAULT [LAMBDA (PTR) (* bvm: " 1-APR-83 15:30") (\CLOCK0 (LOCF (fetch SWAPTEMP0 of \MISCSTATS))) (* Note time of start) (PROG ((VP (fetch (POINTER PAGE#) of PTR)) FLAGS FILEPAGE) (COND ((fetch (VP INVALID) of VP) (* Map out of bounds on Dolphin always produces -1 as the vp. Don't know about other machines) (\MP.ERROR \MP.MOB "Page Fault: Map out of bounds" (AND (NEQ VP 177777Q) PTR) T)) ([NOT (fetch (VMEMFLAGS VACANT) of (SETQ FLAGS (\READFLAGS VP] (\MP.ERROR \MP.RESIDENT "Fault on resident page" PTR T)) ((ZEROP (SETQ FILEPAGE (\LOOKUPPAGEMAP VP))) (\INVALIDADDR PTR)) (T (COND ((EQ (\HILOC PTR) \STACKHI) (* should never happen. For debugging) (\MP.ERROR \MP.STACKFAULT "Fault on stack" PTR T))) (\LOADVMEMPAGE VP FILEPAGE))) [\BOXIPLUS (LOCF (fetch SWAPWAITTIME of \MISCSTATS)) (\BOXIDIFFERENCE (\CLOCK0 (LOCF (fetch SWAPTEMP1 of \MISCSTATS))) (LOCF (fetch SWAPTEMP0 of \MISCSTATS] (* Count the time used.) (RETURN PTR]) (\INVALIDADDR [LAMBDA (ADDR) (* bvm: " 6-AUG-83 22:25") (\MP.ERROR \MP.INVALIDADDR "Invalid address" ADDR T]) (\INVALIDVP [LAMBDA (VP) (* bvm: " 6-AUG-83 22:25") (\MP.ERROR \MP.INVALIDVP "Invalid VP" VP]) (\FLUSHPAGE [LAMBDA (RPTINDEX UPDATEKEY) (* bvm: "12-JUL-83 16:44") (* Write out real page RPTINDEX if it is dirty. If so, and vmem used to be consistent, and UPDATEKEY is true, also mark vmem inconsistent) (PROG ((RPTR (fetch RPTRBASE of RPTINDEX)) VP) (COND ([AND (fetch (RPT OCCUPIED) of RPTR) (fetch (VMEMFLAGS DIRTY) of (\READFLAGS (SETQ VP (fetch (RPT VP) of RPTR] (* Yes, page is dirty) (\TRANSFERPAGE VP (fetch (RPT FILEPAGE) of RPTR) RPTINDEX T NIL) (* Write it out) (COND ((IGREATERP \DIRTYPAGEHINT 0) (add \DIRTYPAGEHINT -1))) (COND ((AND UPDATEKEY (EQ (fetch (IFPAGE Key) of \InterfacePage) \IFPValidKey)) (replace (IFPAGE Key) of \InterfacePage with (LOGNOT16 \IFPValidKey)) (* Invalidate vmem and write out the Interface page) (SETQ \DIRTYPAGEHINT 0) (* So that the dirty page background writer wakes up) (\TRANSFERPAGE (SETQ VP (fetch (POINTER PAGE#) of \InterfacePage)) \FirstVmemBlock (RPTFROMRP (\READRP VP)) T NIL]) (\LOADVMEMPAGE [LAMBDA (VPAGE FILEPAGE NEWPAGEFLG SPECIALRP DONTMOVETOPFLG) (* bvm: "31-MAR-83 15:07") (COND ((IGREATERP \PAGEFAULTCOUNTER \UPDATECHAINFREQ) (\UPDATECHAIN))) (add \PAGEFAULTCOUNTER 1) (PROG ((PREVRP (\SELECTREALPAGE (fetch FILEPAGEONLY of FILEPAGE))) RPTINDEX RPTRBASE) (SETQ RPTINDEX (fetch (RPT NEXTRP) of PREVRP)) (SETQ RPTRBASE (fetch RPTRBASE of RPTINDEX)) (COND ((NOT DONTMOVETOPFLG) (replace (RPT NEXTRP) of PREVRP with (fetch (RPT NEXTRP) of RPTRBASE)) (* Splice RPTINDEX out of chain) (replace (RPT NEXTRP) of (fetch RPTRBASE of (fetch (IFPAGE RPTLAST) of \InterfacePage)) with RPTINDEX) (* Put new page at end of chain) (replace (IFPAGE RPTLAST) of \InterfacePage with RPTINDEX) (replace (RPT NEXTRP) of RPTRBASE with 0))) [COND (SPECIALRP (* Must actually put FILEPAGE into special RP, and thus move old contents of SPECIALRP into RPTINDEX) (PROG ((SRINDEX (RPTFROMRP SPECIALRP)) SRPTR SVP NEWFLAGS) (* SPECIALRP is a "real page", while RPTINDEX is an index into the real page table) (SETQ SRPTR (fetch RPTRBASE of SRINDEX)) (SETQ SVP (fetch (RPT VP) of SRPTR)) (replace (RPT VP) of RPTRBASE with SVP) (* Copy info about old occupants of SPECIALRP into selected RP) (replace (RPT FILEPAGE&LOCK) of RPTRBASE with (fetch (RPT FILEPAGE&LOCK) of SRPTR)) (COND ((fetch (RPT OCCUPIED) of SRPTR) (* THERE WAS ACTUALLY A PAGE THERE) (SETQ NEWFLAGS (\READFLAGS SVP)) (\WRITEMAP \EMBUFVP (RPFROMRPT RPTINDEX) 0) (* Map buffer to target page) (\MOVEPAGE \EMBUFVP SVP) (* MOVE DATA TO BUFFER PAGE) (\WRITEMAP \EMBUFVP \EMBUFRP 0) (* Restore buffer to its proper page) (\WRITEMAP SVP (RPFROMRPT RPTINDEX) NEWFLAGS) (* Set flags for page) )) (SETQ RPTINDEX SRINDEX) (SETQ RPTRBASE SRPTR] (* Fill in new RPTINDEX with appropriate data) (replace (RPT VP) of RPTRBASE with VPAGE) (replace (RPT FILEPAGE&LOCK) of RPTRBASE with FILEPAGE) (* This sets both FILEPAGEONLY and LOCKEDP) (\TRANSFERPAGE VPAGE (fetch FILEPAGEONLY of FILEPAGE) RPTINDEX NIL NEWPAGEFLG]) (\LOOKUPPAGEMAP [LAMBDA (VP) (* bvm: "13-OCT-82 15:21") (* Returns the pagemap entry for VP, which is expected to be in bounds. High bit of result is the lock bit. Zero denotes absence) (PROG [(PRIMENTRY (\GETBASE \PageMapTBL (fetch (VP PRIMARYKEY) of VP] (RETURN (COND ((EQ PRIMENTRY \EMPTYPMTENTRY) 0) (T (\GETBASE \PAGEMAP (IPLUS PRIMENTRY (fetch (VP SECONDARYKEY) of VP]) (\MARKPAGEVACANT [LAMBDA (RPTR) (* bvm: " 8-APR-82 16:06") (* * Marks the real page in this pagemap table entry VACANT) (CHECK (NOT \INTERRUPTABLE)) (\WRITEMAP (fetch (RPT VP) of RPTR) 0 \VMAP.VACANT) (replace (RPT EMPTY) of RPTR with T]) (\SELECTREALPAGE [LAMBDA (NEWFP) (* bvm: " 1-APR-83 15:21") (* Selects a real page, flushing it if necessary, and returns the pagenumber of the PREVIOUS page in the chain, so it can be easily spliced out. NEWFP, if supplied, is the filepage that will be read into here. This might influence page choice by minimizing seek time) (PROG (LAST RP RPTR FLAGS (TRIES 0) (CNTR \MAXCLEANPROBES) (DISTANCE \MINSHORTSEEK)) RETRY (SETQ LAST \REALPAGETABLE) (RETURN (until (EQ (SETQ RP (fetch (RPT NEXTRP) of LAST)) \PAGETABLESTOPFLG) do (SETQ RPTR (fetch RPTRBASE of RP)) [COND ((fetch (RPT EMPTY) of RPTR) (RETURN LAST)) ((NOT (fetch (RPT OCCUPIED) of RPTR)) (\MP.ERROR \MP.CHAIN.UNAVAIL "UNAVAILABLE page on Chain")) ([AND (NOT (fetch (RPT LOCKED) of RPTR)) (NOT (fetch (VMEMFLAGS REFERENCED) of (SETQ FLAGS (\READFLAGS (fetch (RPT VP) of RPTR] (* Page is unlocked and unreferenced, so is good candidate for flushing) (COND ((OR (NOT (fetch (VMEMFLAGS DIRTY) of FLAGS)) (COND (\VMEM.INHIBIT.WRITE (* We are forbidden from writing this filepage) NIL) ((OR (ILEQ CNTR 0) (NULL NEWFP) (ILESSP (IABS (IDIFFERENCE (fetch (RPT FILEPAGE) of RPTR) NEWFP)) DISTANCE)) (* Page is too far away from replacement page) (SETQ CNTR (SUB1 CNTR)) [COND ((ILESSP DISTANCE \MAXSHORTSEEK) (* Get more liberal) (SETQ DISTANCE (LLSH DISTANCE 1] NIL) (T T))) (\FLUSHPAGE RP T) (\MARKPAGEVACANT RPTR) (RETURN LAST] (SETQ LAST RPTR) finally (* Couldn't find an unreffed page because all pages were touched since last \UPDATECHAIN. Do another, which clears ref bits, and try again) (COND ((EQ TRIES 0) (SETQ TRIES 1) (\UPDATECHAIN) (GO RETRY)) ((AND (EQ TRIES 1) \VMEM.INHIBIT.WRITE) (SETQ \VMEM.INHIBIT.WRITE) (COND ((NEQ \MACHINETYPE \DANDELION) (RAID "No clean vmem pages to reuse, must write one. ↑N to continue"))) (GO RETRY)) (T (\MP.ERROR \MP.SELECTLOOP "Loop in \SELECTREALPAGE"]) (\SPECIALRP [LAMBDA (VP) (* bvm: "29-MAR-83 17:43") (* for \DANDELION, some virtual pages must be mapped into special real pages. This function returns the corresponding real page) (COND ((AND (IGEQ VP \VP.STACK) (ILESSP VP (IPLUS \VP.STACK PAGESPERSEGMENT))) (IPLUS \RP.STACK (IDIFFERENCE VP \VP.STACK]) (\TRANSFERPAGE [LAMBDA (VP FILEPAGE RPTINDEX WRITE? NEWPAGE?) (* bvm: "31-MAR-83 14:55") (* Transfers virtual page VP between page FILEPAGE of the vmem and real page RPTINDEX. WRITE? indicates direction of transfer. If NEWPAGE?, then page does not exist on file, and is simply cleared) (PROG (NEWFLAGS) (COND (WRITE? (FLIPCURSORBAR 17Q)) (T (FLIPCURSORBAR 0))) (SETQ NEWFLAGS (COND (NEWPAGE? \VMAP.DIRTY) (WRITE? (LOGAND (\READFLAGS VP) (LOGNOT16 \VMAP.DIRTY))) (T 0))) (\INSUREVMEMFILE FILEPAGE FILEPAGE) (* Make sure vmem knows about page. This may extend the file) (COND ((AND WRITE? (fetch (RPT LOCKED) of (fetch RPTRBASE of RPTINDEX))) (* Writing a locked page: can't diddle map, because others might die, so do this in the straightforward way) (\MOVEPAGE \EMBUFVP VP) (* Copy page into buffer, then write the buffer out) (\ACTONVMEMFILE FILEPAGE \EMBUFBASE 1 T) (SETQ \LASTACCESSEDVMEMPAGE FILEPAGE)) ((NOT NEWPAGE?) (* Map the buffer page into the target real page, read/write the page, then set the map back) (\WRITEMAP VP 0 \VMAP.VACANT) (* Unmap VP so that we don't have two virtual pages pointing at same real page) (\WRITEMAP \EMBUFVP (RPFROMRPT RPTINDEX) 0) (* Map buffer to target page) (\ACTONVMEMFILE FILEPAGE \EMBUFBASE 1 WRITE?) (* Do the i/o) (\WRITEMAP \EMBUFVP \EMBUFRP 0) (* Restore buffer to its proper page) (SETQ \LASTACCESSEDVMEMPAGE FILEPAGE))) (\WRITEMAP VP (RPFROMRPT RPTINDEX) NEWFLAGS) (* Set flags for page) (COND (NEWPAGE? (* Not on file yet, so clear it. Couldn't do this sooner because the flags weren't set) (\ZEROPAGE VP))) (COND (WRITE? (FLIPCURSORBAR 17Q) (\BOXIPLUS (LOCF (fetch SWAPWRITES of \MISCSTATS)) 1)) (T (FLIPCURSORBAR 0) (\BOXIPLUS (LOCF (fetch PAGEFAULTS of \MISCSTATS)) 1]) (\MOVEPAGE [LAMBDA (TOVP FROMVP) (* bvm: "27-JUN-82 15:56") (\BLT (create POINTER PAGE# ← TOVP) (create POINTER PAGE# ← FROMVP) WORDSPERPAGE]) (\ZEROPAGE [LAMBDA (VP) (* bvm: "18-JUL-82 16:15") (bind (BASE ←(create POINTER PAGE# ← VP)) from 1 to CELLSPERPAGE do (* Do two at a time by storing NILs) (\PUTBASEPTR BASE 0 NIL) (SETQ BASE (\ADDBASE BASE WORDSPERCELL]) (\UPDATECHAIN [LAMBDA NIL (* bvm: "31-MAR-83 14:56") (* Sorts the page chain by reference bit) (CHECK (NOT \INTERRUPTABLE)) (PROG ((RPTINDEX (fetch (RPT NEXTRP) of \REALPAGETABLE)) (CHAIN0 \REALPAGETABLE) (CHAIN1 \EMBUFBASE) RPTR VP FLAGS HEAD1) (SETQ HEAD1 CHAIN1) (* HEAD1 = CHAIN1 is just a holding cell for the second Chain we temporarily create inside here. Has to be something that doesn't fault, so use the swap buffer for it) (replace (RPT NEXTRP) of CHAIN0 with \PAGETABLESTOPFLG) (replace (RPT NEXTRP) of CHAIN1 with \PAGETABLESTOPFLG) (do (SETQ RPTR (fetch RPTRBASE of RPTINDEX)) (SETQ VP (fetch (RPT VP) of RPTR)) [SETQ FLAGS (COND ((fetch (RPT EMPTY) of RPTR) 0) (T (\READFLAGS VP] (COND ((OR (fetch (VMEMFLAGS REFERENCED) of FLAGS) (fetch (RPT LOCKED) of RPTR)) (* Page referenced or locked, put on CHAIN1) (\WRITEMAP VP (RPFROMRPT RPTINDEX) (LOGAND FLAGS (LOGNOT16 \VMAP.REF))) (* Turn off ref bit) (replace (RPT NEXTRP) of CHAIN1 with RPTINDEX) (SETQ CHAIN1 RPTR)) (T (* Page was not referenced recently, put on CHAIN0) (replace (RPT NEXTRP) of CHAIN0 with RPTINDEX) (SETQ CHAIN0 RPTR))) (SETQ RPTINDEX (fetch (RPT NEXTRP) of RPTR)) (* Look at next page in old chain) repeatuntil (EQ RPTINDEX \PAGETABLESTOPFLG)) (replace (RPT NEXTRP) of CHAIN1 with \PAGETABLESTOPFLG) (* End of the line) (replace (RPT NEXTRP) of CHAIN0 with (fetch (RPT NEXTRP) of HEAD1)) (* Link end of CHAIN0 to beginning of CHAIN1) (replace (IFPAGE RPTLAST) of \InterfacePage with (IQUOTIENT (IDIFFERENCE (LOLOC (COND ((EQ HEAD1 CHAIN1) (* Nothing on CHAIN1 ??!!) CHAIN0) (T CHAIN1))) (LOLOC \REALPAGETABLE)) 3)) (* Pointer to end of complete chain) (SETQ \DIRTYPAGECOUNTER (SETQ \PAGEFAULTCOUNTER 0]) ) (DEFINEQ (\NEWPAGE [LAMBDA (BASE NOERROR LOCK?) (* bvm: " 1-APR-83 15:22") (* * Creates and returns a new page located at virtual addr BASE) (UNINTERRUPTABLY (PROG (FILEPAGE) [COND [(NOT (SETQ FILEPAGE (\MISCAPPLY*(FUNCTION \DONEWPAGE) BASE LOCK?))) (* Failed, page exists) (COND ((NOT NOERROR) (\MP.ERROR \MP.NEWPAGE "Attempt to allocate already existing page" BASE T))) (COND (LOCK? (\LOCKPAGES BASE 1] (T (COND ((SETQ FILEPAGE (\MAYBE.EXTENDVMEMFILE (IPLUS FILEPAGE \MINVMEMSPAREPAGES))) (\DISKERROR FILEPAGE] (RETURN BASE)))]) (\DONEWPAGE [LAMBDA (BASE LOCK?) (* bvm: " 6-AUG-83 22:23") (* * Allocates new page at BASE, locking it if LOCK? is true. Returns vmemfile page# on success, NIL if page already exists. Must be run in safe context! because it can cause vmem activity) (AND \DOFAULTINIT (\FAULTINIT)) (* Only an issue when INIT.SYSOUT starts. Perhaps there is a better place to put this) (PROG ((VP (fetch (POINTER PAGE#) of BASE)) MAPBASE FILEPAGE NEXTPM ERRCODE) (RETURN (COND ((fetch (VP INVALID) of VP) (\INVALIDVP VP) NIL) (T (SETQ MAPBASE (\GETBASE \PageMapTBL (fetch (VP PRIMARYKEY) of VP))) (COND ((EQ MAPBASE \EMPTYPMTENTRY) (* Need to create a new second-level block) (SETQ NEXTPM (fetch (IFPAGE NxtPMAddr) of \InterfacePage)) [COND ((EVENP NEXTPM WORDSPERPAGE) (* New page map page) (OR (\DONEWPAGE (\ADDBASE \PAGEMAP NEXTPM) T) (RETURN (\MP.ERROR \MP.NEWMAPPAGE "\DONEWPAGE failed to allocate new map page"] (\PUTBASE \PageMapTBL (fetch (VP PRIMARYKEY) of VP) NEXTPM) (replace (IFPAGE NxtPMAddr) of \InterfacePage with (IPLUS NEXTPM \PMblockSize)) (SETQ MAPBASE NEXTPM))) [SETQ MAPBASE (\ADDBASE \PAGEMAP (IPLUS MAPBASE (fetch (VP SECONDARYKEY) of VP] (COND ((NEQ (\GETBASE MAPBASE 0) 0) (* Page exists) (RETURN NIL))) (SETQ FILEPAGE (add (fetch (IFPAGE NActivePages) of \InterfacePage) 1)) (replace (IFPAGE NDirtyPages) of \InterfacePage with FILEPAGE) (* Currently a redundant field) [COND (LOCK? (SETQ FILEPAGE (\MAKESPACEFORLOCKEDPAGE VP FILEPAGE] [AND \FPTOVP (\PUTBASE \FPTOVP FILEPAGE (COND (LOCK? (LOGOR VP \PAGEMAPLOCKBIT)) (T VP] (\PUTBASE MAPBASE 0 (COND (LOCK? (SETQ FILEPAGE (LOGOR FILEPAGE \PAGEMAPLOCKBIT))) (T FILEPAGE))) (* (COND ((AND (IGEQ VP \VP.DISPLAY) (ILESSP VP (IPLUS \VP.DISPLAY PAGESPERSEGMENT))) (* display pages are not on the chain, and if unmapped are otherwise unavailable) (\TRANSFERPAGE VP FILEPAGE (SETQ RP (IPLUS \RP.DISPLAY (IDIFFERENCE VP \VP.DISPLAY))) NIL T) (* * now fix up RPT to point to this VP) (SETQ MAPBASE (fetch RPTRBASE of (IDIFFERENCE RP \RPOFFSET))) (replace VP of MAPBASE with VP) (replace FILEPAGE&LOCK of MAPBASE with FILEPAGE) (RETURN (fetch FILEPAGEONLY of FILEPAGE))))) (\LOADVMEMPAGE VP FILEPAGE T (AND (EQ \MACHINETYPE \DANDELION) (\SPECIALRP VP))) (fetch FILEPAGEONLY of FILEPAGE]) (\MAKESPACEFORLOCKEDPAGE [LAMBDA (VP FILEPAGE) (* bvm: " 4-APR-83 11:59") (* VP is a page to be locked, FILEPAGE its home. Returns a possibly new file page where VP will now live, after having kicked the former resident of the new file page into VP's old FILEPAGE) (COND ((NOT \FPTOVP) (* Old sysout) FILEPAGE) (T (PROG ((RP (\SPECIALRP VP)) DESIREDFP OLDVP FLAGS FPBASE) [SETQ DESIREDFP (COND (RP (* Dlion has constraints about the real page, hence about FP) (DLFPFROMRP RP)) ((AND (ILEQ FILEPAGE (fetch LastLockedFilePage of \InterfacePage)) (IGREATERP FILEPAGE (DLFPFROMRP \RP.TYPETABLE))) (* Page is in a good place already. It probably was once locked, then unlocked) (RETURN FILEPAGE)) (T (* Put it after all the other locked pages) (add (fetch LastLockedFilePage of \InterfacePage) 1] (COND ((AND (fetch FPOCCUPIED of (SETQ FPBASE (\ADDBASE \FPTOVP DESIREDFP))) (NEQ (SETQ OLDVP (fetch FPVIRTUALPAGE of FPBASE)) VP)) (* Someone else lives here, so move it out) (COND ((fetch FPLOCKED of FPBASE) (\MP.ERROR \MP.BADLOCKED "Locked page is in the way" OLDVP))) (COND ((fetch (VMEMFLAGS VACANT) of (SETQ FLAGS (\READFLAGS OLDVP))) (* Page not resident, so pull it in) (\LOADVMEMPAGE OLDVP DESIREDFP) (SETQ FLAGS \VMAP.CLEAN))) (\WRITEMAP OLDVP (SETQ RP (\READRP OLDVP)) (LOGOR FLAGS \VMAP.DIRTY)) (* Mark page dirty, so that it will eventually be written to its new home) (replace (RPT FILEPAGE) of (fetch RPTRBASE of (RPTFROMRP RP)) with FILEPAGE) (* Tell RPT where OLDVP now lives) (\PUTBASE \PAGEMAP (IPLUS (\GETBASE \PageMapTBL (fetch (VP PRIMARYKEY) of OLDVP)) (fetch (VP SECONDARYKEY) of OLDVP)) FILEPAGE) (* Tell \PAGEMAP about it) (\PUTBASE \FPTOVP FILEPAGE OLDVP) (* ... and \FPTOVP) )) (RETURN DESIREDFP]) (\NEWEPHEMERALPAGE [LAMBDA (BASE NOERROR) (* bvm: "26-NOV-82 15:40") (* * Creates and returns a new page located at virtual addr BASE, mapping it permanently into some real page but leaving it out of the vmem file) (\MISCAPPLY*(FUNCTION \DONEWEPHEMERALPAGE) BASE NOERROR]) (\DONEWEPHEMERALPAGE [LAMBDA (BASE NOERROR) (* bvm: " 6-AUG-83 22:24") (* * Creates and returns a new page located at virtual addr BASE, mapping it permanently into some real page but leaving it out of the vmem file) (PROG ((VP (fetch (POINTER PAGE#) of BASE)) MAPBASE PREVRP RPTINDEX RPTR) (RETURN (COND ((fetch (VP INVALID) of VP) (\INVALIDVP VP) NIL) (T (SETQ MAPBASE (\GETBASE \PageMapTBL (fetch (VP PRIMARYKEY) of VP))) (* First check that the page doesn't exist) (COND ([OR [AND (NEQ MAPBASE \EMPTYPMTENTRY) (NOT (ZEROP (\GETBASE \PAGEMAP (IPLUS MAPBASE (fetch (VP SECONDARYKEY) of VP] (NOT (fetch (VMEMFLAGS VACANT) of (\READFLAGS VP] (* Page is in the vmem already, so no hope) (COND ((NOT NOERROR) (\MP.ERROR \MP.NEWPAGE "Page already exists " BASE T))) (RETURN BASE))) (COND ((IGREATERP \PAGEFAULTCOUNTER \UPDATECHAINFREQ) (\UPDATECHAIN))) (add \PAGEFAULTCOUNTER 1) (SETQ PREVRP (\SELECTREALPAGE)) (* Find a page to put this in) (SETQ RPTINDEX (fetch (RPT NEXTRP) of PREVRP)) (SETQ RPTR (fetch RPTRBASE of RPTINDEX)) (replace (RPT NEXTRP) of PREVRP with (fetch (RPT NEXTRP) of RPTR)) (* Splice RPTINDEX out of chain) (replace (RPT NEXTRP) of RPTR with 0) (* Fill in new RPTINDEX with appropriate data) (replace (RPT VP) of RPTR with \RPT.UNAVAILABLE) (replace (RPT FILEPAGE&LOCK) of RPTR with VP) (* For debugging only) (FLIPCURSORBAR 0) (\WRITEMAP VP (RPFROMRPT RPTINDEX) \VMAP.DIRTY) (* Set flags for page) (\ZEROPAGE VP) (* Clear new page) (FLIPCURSORBAR 0) (\BOXIPLUS (LOCF (fetch PAGEFAULTS of \MISCSTATS)) 1) BASE]) (\LOCKPAGES [LAMBDA (BASE NPAGES) (* bvm: "26-NOV-82 15:17") (* Needs to be done in safe stack context because might cause vmem transfer) (\MISCAPPLY*(FUNCTION \DOLOCKPAGES) BASE NPAGES) BASE]) (\DOLOCKPAGES [LAMBDA (BASE NPAGES) (* bvm: "31-MAR-83 18:20") (for I from 0 to (SUB1 NPAGES) bind (VP ←(fetch (POINTER PAGE#) of BASE)) FILEPAGE MAPBASE do [COND ((fetch (VP INVALID) of VP) (\INVALIDVP VP)) [(EQ (SETQ MAPBASE (\GETBASE \PageMapTBL (fetch (VP PRIMARYKEY) of VP))) \EMPTYPMTENTRY) (\INVALIDADDR (ADDBASE BASE (UNFOLD I WORDSPERPAGE] (T [SETQ MAPBASE (\ADDBASE \PAGEMAP (IPLUS MAPBASE (fetch (VP SECONDARYKEY) of VP] (SETQ FILEPAGE (\GETBASE MAPBASE 0)) (COND ((NOT (fetch (PAGEMAPENTRY LOCKEDP) of FILEPAGE)) (* Not locked yet) [COND ((fetch VACANT of (\READFLAGS VP)) (* Bring locked page into core so we can move it if necessary) (\LOADVMEMPAGE VP (LOGOR FILEPAGE \PAGEMAPLOCKBIT) NIL (AND (EQ \MACHINETYPE \DANDELION) (\SPECIALRP VP] [COND ((NEQ FILEPAGE (SETQ FILEPAGE (\MAKESPACEFORLOCKEDPAGE VP FILEPAGE))) (* Moving to a new page, so have to mark this locked page dirty so that it will eventually get written to its new home) (\WRITEMAP VP (\READRP VP) (LOGOR \VMAP.DIRTY \VMAP.REF] (AND \FPTOVP (\PUTBASE \FPTOVP FILEPAGE (LOGOR VP \PAGEMAPLOCKBIT))) (\PUTBASE MAPBASE 0 (SETQ FILEPAGE (LOGOR FILEPAGE \PAGEMAPLOCKBIT))) (* Set lock bit in page map) (replace (RPT FILEPAGE&LOCK) of (fetch RPTRBASE of (RPTFROMRP (\READRP VP))) with FILEPAGE] (add VP 1]) (\TEMPLOCKPAGES [LAMBDA (BASE NPAGES) (* bvm: "31-MAR-83 15:01") (* "Temporarily" locks BASE for NPAGES, i.e. ensures that the swapper will not move the pages. Information vanishes at logout etc. This function must be locked because it manipulates the page table) (while (IGREATERP NPAGES 0) bind (VP ←(fetch (POINTER PAGE#) of BASE)) RPTR do (UNINTERRUPTABLY (\TOUCHPAGE BASE) (* Touch page in case not resident) (COND ((AND (NEQ (SETQ RPTR (\READRP VP)) 0) (EQ [fetch (RPT VP) of (SETQ RPTR (fetch RPTRBASE of (RPTFROMRP RPTR] VP)) (replace (RPT LOCKED) of RPTR with T)) (T (HELP "Page table changed out from under me!" VP)))) (add VP 1) (add NPAGES -1) (SETQ BASE (\ADDBASE BASE WORDSPERPAGE]) (\TEMPUNLOCKPAGES [LAMBDA (BASE NPAGES) (* bvm: "31-MAR-83 15:01") (* Unlocks pages that were locked by \TEMPLOCKPAGES. This function must be locked because it manipulates the page table) (while (IGREATERP NPAGES 0) bind (VP ←(fetch (POINTER PAGE#) of BASE)) RPTR do (UNINTERRUPTABLY (\TOUCHPAGE BASE) (* Touch page in case not resident. Should only happen if page wasn't locked to begin with) (COND ((AND (NEQ (SETQ RPTR (\READRP VP)) 0) (EQ [fetch (RPT VP) of (SETQ RPTR (fetch RPTRBASE of (RPTFROMRP RPTR] VP)) (replace (RPT LOCKED) of RPTR with NIL)) (T (HELP "Page table changed out from under me!" VP)))) (add VP 1) (add NPAGES -1) (SETQ BASE (\ADDBASE BASE WORDSPERPAGE]) (\UNLOCKPAGES [LAMBDA (BASE NPAGES) (* bvm: " 4-APR-83 12:00") (* * Unlocks NPAGES virtual pages from BASE onward) (UNINTERRUPTABLY (for I from 0 to (SUB1 NPAGES) bind (VP ←(fetch (POINTER PAGE#) of BASE)) MAPBASE FILEPAGE do [COND ((fetch (VP INVALID) of VP) (\INVALIDVP VP)) [(EQ (SETQ MAPBASE (\GETBASE \PageMapTBL (fetch (VP PRIMARYKEY) of VP))) \EMPTYPMTENTRY) (\INVALIDADDR (\ADDBASE BASE (UNFOLD I WORDSPERPAGE] (T [SETQ MAPBASE (\ADDBASE \PAGEMAP (IPLUS MAPBASE (fetch (VP SECONDARYKEY) of VP] (SETQ FILEPAGE (\GETBASE MAPBASE 0)) (COND ((fetch (PAGEMAPENTRY LOCKEDP) of FILEPAGE) (* Yes, page was locked, so turn the bit off now) (SETQ FILEPAGE (fetch (PAGEMAPENTRY FILEPAGEONLY) of FILEPAGE)) (\PUTBASE MAPBASE 0 FILEPAGE) (* Update pagemap, then update real page table) (AND \FPTOVP (replace FPLOCKED of (\ADDBASE \FPTOVP FILEPAGE) with NIL)) (* Remove Lock bit in \FPTOVP) (replace (RPT LOCKED) of (fetch RPTRBASE of (RPTFROMRP (\READRP VP))) with NIL] (add VP 1)))]) (\FLUSHVM [LAMBDA NIL (* bvm: "12-JUL-83 16:55") (* Writes out all dirty pages to vmem, making it consistent. Returns NIL now, T if Bcpl starts up the vmem) (UNINTERRUPTABLY (* Write stuff out from a safe place) (PROG1 (COND ((\MISCAPPLY*(FUNCTION \DOFLUSHVM)) (* Return from Bcpl startup. Need to rebuild the context, since it was not written out consistently) (SETQ \DOFAULTINIT T) (* Tell pagefault handler to initialize itself. Want the initialization to happen in Fault context to avoid stack overflow messiness) (\CONTEXTSWITCH \FAULTFXP) (for VAR in \SYSTEMCACHEVARS do (SET VAR NIL)) T)) (SETQ \DIRTYPAGEHINT 32767)))]) (\LOGOUT0 [LAMBDA (FAST) (* bvm: "29-MAR-83 18:06") [COND ((NEQ (fetch MachineType of \InterfacePage) \DANDELION) (* update alto clock) (\BLT (EMADDRESS \RTCSECONDS) (LOCF (fetch SECONDSCLOCK of \MISCSTATS)) (UNFOLD 3 WORDSPERCELL] (UNINTERRUPTABLY (OR (AND (OR (NOT FAST) (AND (EQ FAST (QUOTE ?)) (NEQ (fetch (IFPAGE Key) of \InterfacePage) \IFPValidKey))) (\FLUSHVM)) (\LISPFINISH)))]) (\DOFLUSHVM [LAMBDA NIL (* bvm: "31-MAR-83 15:03") (* * Write everything out in a resumable way. Value is NIL if returned from directly, T if from saved state. Always invoked via \MISCAPPLY*) (CHECK (NOT \INTERRUPTABLE)) (* NOTE: need stats gathering off in here. Also avoid touching pages) (PROG ((IFPVP (fetch (POINTER PAGE#) of \InterfacePage)) (SCRATCHBUF \EMUSWAPBUFFERS) (SCRATCHVP (fetch (POINTER PAGE#) of \EMUSWAPBUFFERS))) (replace (IFPAGE MISCSTACKRESULT) of \InterfacePage with T) (* This will make it look like we have returned from BCPL if caller gets control from the saved state) (COND ((EQ (fetch (IFPAGE Key) of \InterfacePage) \IFPValidKey) (replace (IFPAGE Key) of \InterfacePage with (LOGNOT16 \IFPValidKey)) (* Invalidate vmem and write out the Interface page) (\TRANSFERPAGE IFPVP \FirstVmemBlock (RPTFROMRP (\READRP IFPVP)) T NIL))) (for RP from 0 to (SUB1 \RPTSIZE) do (\FLUSHPAGE RP)) (replace (IFPAGE Key) of \InterfacePage with \IFPValidKey) (\MOVEPAGE SCRATCHVP IFPVP) (* Make its current fx point at user context, i.e. the \FLUSHVM frame) (replace (IFPAGE CurrentFXP) of SCRATCHBUF with (fetch (IFPAGE MiscFXP) of \InterfacePage)) (\ACTONVMEMFILE (fetch FILEPAGEONLY of (\LOOKUPPAGEMAP IFPVP)) SCRATCHBUF 1 T) (* Write the page out from a safe place) (RETURN NIL]) (\RELEASEWORKINGSET [LAMBDA NIL (* bvm: "31-MAR-83 15:03") (COND ((\FLUSHVM) (* Returning from Lisp startup) T) (T (* Unmap any unlocked page) (for RPTINDEX from 0 to (SUB1 \RPTSIZE) bind RPTR when (AND (fetch (RPT OCCUPIED) of (SETQ RPTR (fetch RPTRBASE of RPTINDEX))) (NOT (fetch (RPT LOCKED) of RPTR))) do (\WRITEMAP (fetch (RPT VP) of RPTR) (RPFROMRPT RPTINDEX) \VMAP.VACANT) (replace (RPT EMPTY) of RPTR with T]) (\WRITEDIRTYPAGE [LAMBDA (MINDIRTY) (* bvm: "26-NOV-82 15:46") (COND ((NEQ (fetch (IFPAGE Key) of \InterfacePage) \IFPValidKey) (PROG ((RPTR (OR \LASTDIRTYSCANPTR \REALPAGETABLE)) (NUMDIRTY (OR \LASTDIRTYCNT 0)) (CNT \MAXDIRTYSCANCOUNT) RP FLAGS) [COND ((AND (NULL \LASTDIRTYSCANPTR) (IGREATERP (IPLUS (add \DIRTYPAGECOUNTER 1) \PAGEFAULTCOUNTER) \UPDATECHAINFREQ)) (* Take this time to update the page chain instead) (RETURN (\UPDATECHAIN] (OR MINDIRTY (SETQ MINDIRTY 1)) LP [COND [(EQ (SETQ RP (fetch (RPT NEXTRP) of RPTR)) \PAGETABLESTOPFLG) (* Hit end of chain. Write out what we found if enough were dirty) (COND ((OR (ILESSP NUMDIRTY MINDIRTY) (ZEROP NUMDIRTY) (NOT (SETQ RP \LASTDIRTYFOUND))) (SETQ \LASTDIRTYSCANPTR (SETQ \LASTDIRTYCNT (SETQ \LASTDIRTYFOUND NIL))) [COND ((AND (NEQ NUMDIRTY 0) (ILESSP \DIRTYSEEKMAX (LRSH MAX.SMALL.INTEGER 1))) (* Failed because page not close enough, so widen the tolerance) (SETQ \DIRTYSEEKMAX (LLSH \DIRTYSEEKMAX 1] (RETURN)) (T (GO GOTPAGE] ((fetch (RPT EMPTY) of (SETQ RPTR (fetch RPTRBASE of RP))) (* Page is empty. Should never happen if key is valid) (RETURN)) ((NOT (fetch (RPT LOCKED) of RPTR)) (* Don't bother writing out locked pages, since they don't help us in our swapping quest) (SETQ FLAGS (\READFLAGS (fetch (RPT VP) of RPTR))) (COND ((NOT (fetch (VMEMFLAGS DIRTY) of FLAGS)) (* Page not dirty; skip) ) [(IGREATERP (IABS (IDIFFERENCE (fetch (RPT FILEPAGE) of RPTR) \LASTACCESSEDVMEMPAGE)) \DIRTYSEEKMAX) (* Page too far away, don't write it) (COND ((fetch (VMEMFLAGS REFERENCED) of FLAGS) (* but still count it) (add NUMDIRTY 1] ((fetch (VMEMFLAGS REFERENCED) of FLAGS) (* Page dirty but referenced. Note it, but keep looking for a better one) (COND ((ZEROP NUMDIRTY) (SETQ \LASTDIRTYFOUND RP))) (add NUMDIRTY 1)) (T (* Dirty, not referenced: do it) (GO GOTPAGE] (COND ((ZEROP (add CNT -1)) (* Scanned for long enough; don't lock user out) (SETQ \LASTDIRTYSCANPTR RPTR) (SETQ \LASTDIRTYCNT NUMDIRTY) (RETURN))) (GO LP) GOTPAGE (UNINTERRUPTABLY (SETQ \LASTDIRTYSCANPTR RPTR) (* Keep traveling pointer) (SETQ \LASTDIRTYCNT (SETQ \LASTDIRTYFOUND NIL)) (COND ((ILEQ (IABS (IDIFFERENCE (fetch (RPT FILEPAGE) of RPTR) \LASTACCESSEDVMEMPAGE)) \DIRTYSEEKMAX) (* Could fail if swapping since the selection has moved the disk arm too far) (\MISCAPPLY*(FUNCTION \WRITEDIRTYPAGE1) RP RPTR))) (SETQ \DIRTYSEEKMAX \MAXSHORTSEEK)) (RETURN T]) (\WRITEDIRTYPAGE1 [LAMBDA (RP RPTR) (* bvm: "20-APR-82 15:21") (* Write out buffer RP. This fn is locked and uninterruptable) (COND ([AND (NOT (fetch (RPT LOCKED) of RPTR)) (fetch (VMEMFLAGS DIRTY) of (\READFLAGS (fetch (RPT VP) of RPTR] (* Verify that the page is still a candidate, so previous loop could be interruptable) (\FLUSHPAGE RP]) (\NPAGESBIT [LAMBDA (FLG) (* bvm: "21-APR-82 14:27") (* Count number of real pages satisfying FLG: 0 = ref, 1 = dirty, 2 = locked) (bind RPTR←\REALPAGETABLE RP until (EQ (SETQ RP (fetch (RPT NEXTRP) of RPTR)) \PAGETABLESTOPFLG) count (AND (fetch (RPT OCCUPIED) of (SETQ RPTR (fetch RPTRBASE of RP))) (SELECTQ FLG [0 (fetch (VMEMFLAGS REFERENCED) of (\READFLAGS (fetch (RPT VP) of RPTR] [1 (fetch (VMEMFLAGS DIRTY) of (\READFLAGS (fetch (RPT VP) of RPTR] (2 (fetch (RPT LOCKED) of RPTR)) (\ILLEGAL.ARG FLG]) ) (RPAQ? \UPDATECHAINFREQ 100) (RPAQ? \PAGEFAULTCOUNTER 0) (RPAQ? \DIRTYPAGECOUNTER 0) (RPAQ? \DIRTYPAGEHINT 0) (RPAQ? \LASTACCESSEDVMEMPAGE 0) (RPAQ? \MAXSHORTSEEK 1000) (RPAQ? \MINSHORTSEEK 20) (RPAQ? \MAXCLEANPROBES 20) (RPAQ? \VMEM.INHIBIT.WRITE ) (RPAQ? \DOFAULTINIT 0) (RPAQ? \FPTOVP ) (RPAQ? \VMEMACCESSFN ) (RPAQ? \SYSTEMCACHEVARS ) (RPAQ? \LASTDIRTYCNT ) (RPAQ? \LASTDIRTYFOUND ) (RPAQ? \LASTDIRTYSCANPTR ) (RPAQ? \DIRTYSEEKMAX 50) (* Errors) (DEFINEQ (\MP.ERROR [LAMBDA (CODE STRING ARG1 ARG2) (* bvm: " 1-APR-83 15:03") (COND ((EQ \MACHINETYPE \DANDELION) ((OPCODES RAID) CODE)) (T (RAID STRING ARG1 ARG2]) ) (DECLARE: EVAL@COMPILE DONTCOPY (RPAQQ \MPERRORS ((\MP.NORPT 1 "No space for Real Page Table") (\MP.INVALIDVMEM 2) (\MP.IOCBPAGE 3 "No place for IOCB page at startup") (\MP.MOB 4 "Map out of bounds") (\MP.INVALIDADDR 5) (\MP.INVALIDVP 6) (\MP.CHAIN.UNAVAIL 7 "Unavailable page on real page table chain") (\MP.SELECTLOOP 8 "Loop in \SELECTREALPAGE") (\MP.NEWPAGE 9 "Attempt to allocate already existing page") (\MP.NEWMAPPAGE 10 "\DONEWPAGE failed to allocate new map page") (\MP.BADLOCKED 11 "Locked page occupies a file page needed to lock another") (\MP.CLOCK0 12 "Arg to CLOCK0 not an integer box") (\MP.RESIDENT 13 "Fault on resident page") (\MP.STACKFAULT 14 "Fault on stack") (\MP.INVALIDVMEM 15 "Vmem inconsistent at startup"))) (DECLARE: EVAL@COMPILE (RPAQ \MP.NORPT 1 "No space for Real Page Table") (RPAQQ \MP.INVALIDVMEM 2) (RPAQ \MP.IOCBPAGE 3 "No place for IOCB page at startup") (RPAQ \MP.MOB 4 "Map out of bounds") (RPAQQ \MP.INVALIDADDR 5) (RPAQQ \MP.INVALIDVP 6) (RPAQ \MP.CHAIN.UNAVAIL 7 "Unavailable page on real page table chain") (RPAQ \MP.SELECTLOOP 8 "Loop in \SELECTREALPAGE") (RPAQ \MP.NEWPAGE 9 "Attempt to allocate already existing page") (RPAQ \MP.NEWMAPPAGE 10 "\DONEWPAGE failed to allocate new map page") (RPAQ \MP.BADLOCKED 11 "Locked page occupies a file page needed to lock another") (RPAQ \MP.CLOCK0 12 "Arg to CLOCK0 not an integer box") (RPAQ \MP.RESIDENT 13 "Fault on resident page") (RPAQ \MP.STACKFAULT 14 "Fault on stack") (RPAQ \MP.INVALIDVMEM 15 "Vmem inconsistent at startup") (CONSTANTS (\MP.NORPT 1 "No space for Real Page Table") (\MP.INVALIDVMEM 2) (\MP.IOCBPAGE 3 "No place for IOCB page at startup") (\MP.MOB 4 "Map out of bounds") (\MP.INVALIDADDR 5) (\MP.INVALIDVP 6) (\MP.CHAIN.UNAVAIL 7 "Unavailable page on real page table chain") (\MP.SELECTLOOP 8 "Loop in \SELECTREALPAGE") (\MP.NEWPAGE 9 "Attempt to allocate already existing page") (\MP.NEWMAPPAGE 10 "\DONEWPAGE failed to allocate new map page") (\MP.BADLOCKED 11 "Locked page occupies a file page needed to lock another") (\MP.CLOCK0 12 "Arg to CLOCK0 not an integer box") (\MP.RESIDENT 13 "Fault on resident page") (\MP.STACKFAULT 14 "Fault on stack") (\MP.INVALIDVMEM 15 "Vmem inconsistent at startup")) ) ) (* Debugging) (DEFINEQ (\ACTONVMEMFILE [LAMBDA (FILEPAGE BUFFER NPAGES WRITEFLAG) (* bvm: "28-MAR-83 16:17") (COND ((EQ \MACHINETYPE \DANDELION) (\DL.ACTONVMEMFILE FILEPAGE BUFFER NPAGES WRITEFLAG)) (T (\M44ACTONVMEMFILE FILEPAGE BUFFER NPAGES WRITEFLAG]) (\SHOWPAGETABLE [LAMBDA (MODE FILE) (* bvm: "23-SEP-82 18:51") (RESETFORM (OUTPUT FILE) (PROG ((RPTR \REALPAGETABLE) (RP 0) FLAGS VP STATE FIRSTONE LASTONE) (printout NIL " RP VP FilePage Status" T) (until (SELECTQ MODE (CHAIN (EQ (SETQ RP (fetch (RPT NEXTRP) of RPTR)) \PAGETABLESTOPFLG)) (NIL (add RP 1) (IGREATERP RP \RPTSIZE)) (\ILLEGAL.ARG MODE)) do (SETQ RPTR (fetch RPTRBASE of RP)) (SETQ VP (fetch (RPT VP) of RPTR)) (COND ((AND (NULL MODE) (EQ VP STATE)) (SETQ LASTONE RP)) (T (COND (LASTONE (printout NIL "ditto thru " LASTONE T) (SETQ LASTONE NIL))) (SETQ FIRSTONE RP) (SETQ STATE VP) (printout NIL .I7 RP) [COND ((fetch (RPT EMPTY) of RPTR) (PRIN1 " Empty")) ((NOT (fetch (RPT OCCUPIED) of RPTR)) (PRIN1 " Unavailable")) (T (printout NIL .I8 VP .I8 (fetch (RPT FILEPAGE) of RPTR) ,,) (COND ((fetch (RPT LOCKED) of RPTR) (PRIN1 "Locked "))) (COND ((fetch (VMEMFLAGS REFERENCED) of (SETQ FLAGS (\READFLAGS VP))) (PRIN1 "Ref "))) (COND ((fetch (VMEMFLAGS DIRTY) of FLAGS) (PRIN1 "Dirty"] (TERPRI]) (CHECKPAGEMAP [LAMBDA NIL (* bvm: " 4-APR-83 12:26") (RESETFORM (RADIX 10Q) (PROG (VP FP RPTR FPBASE LOCKED) [COND (\FPTOVP (for FP from 1 to (fetch NActivePages of \InterfacePage) as (FPBASE ←(\ADDBASE \FPTOVP 1)) by (\ADDBASE FPBASE 1) when (fetch FPOCCUPIED of FPBASE) do (CHECKFPTOVP FP (fetch FPVIRTUALPAGE of FPBASE) (fetch FPLOCKED of FPBASE] (for RP from 0 to (SUB1 \RPTSIZE) when (fetch (RPT OCCUPIED) of (SETQ RPTR (fetch RPTRBASE of RP))) do (SETQ VP (fetch (RPT VP) of RPTR)) (SETQ FP (fetch (RPT FILEPAGE) of RPTR)) (SETQ LOCKED (fetch (RPT LOCKED) of RPTR)) (OR (CHECKFPTOVP FP VP LOCKED RP) (COND ([AND \FPTOVP (OR [NEQ VP (fetch FPVIRTUALPAGE of (SETQ FPBASE (\ADDBASE \FPTOVP FP] (NEQ LOCKED (fetch FPLOCKED of FPBASE] (printout T "RPT for RP " (RPFROMRPT RP) " says VP ") (\PRINTVP VP T) (printout T (\LOCKED?STRING LOCKED) " lives in FP " FP "; but FP Map says that FP contains ") (\PRINTVP (fetch FPVIRTUALPAGE of FPBASE) T) (printout T (\LOCKED?STRING (fetch FPLOCKED of FPBASE)) T]) (CHECKFPTOVP [LAMBDA (FP VP LOCKED RPTINDEX) (* bvm: "31-MAR-83 15:05") (PROG ((FP2 (\LOOKUPPAGEMAP VP))) (RETURN (COND ((OR (NEQ (fetch FILEPAGEONLY of FP2) FP) (NEQ (fetch LOCKEDP of FP2) LOCKED)) (COND (RPTINDEX (printout T "RPT for RP " (RPFROMRPT RPTINDEX))) (T (printout T "FP map"))) (printout T " says FP " FP " contains VP ") (\PRINTVP VP T) (printout T (\LOCKED?STRING LOCKED) "; but PageMap says that page is in FP " (fetch FILEPAGEONLY of FP2) (\LOCKED?STRING (fetch LOCKEDP of FP2)) T) T]) (\LOCKED?STRING [LAMBDA (LOCKEDP) (* bvm: "31-MAR-83 14:20") (COND (LOCKEDP " (locked)") (T " (unlocked)"]) (\PRINTFPTOVP [LAMBDA (BASE NWORDS STREAM) (* bvm: "30-MAR-83 11:48") (SETQ STREAM (GETSTREAM STREAM (QUOTE OUTPUT))) (RESETFORM (RADIX 10Q) (PROG (FIRSTFP FIRSTVP (LASTVP -2) (NEXTFP 0) NEXTVP LOCKEDP NEXTLOCKED) (while (IGEQ NWORDS 0) do (add NEXTFP 1) [COND ((ZEROP NWORDS) (SETQ NEXTVP -1)) (T (SETQ NEXTVP (\GETBASE (SETQ BASE (\ADDBASE BASE 1)) 0)) (SETQ NEXTLOCKED (fetch LOCKEDP of NEXTVP] [COND ([COND ((EQ NEXTVP \NO.VMEM.PAGE) (NEQ LASTVP \NO.VMEM.PAGE)) (T (OR (NEQ (SETQ NEXTVP (fetch FILEPAGEONLY of NEXTVP)) (ADD1 LASTVP)) (NEQ NEXTLOCKED LOCKEDP] [COND ((IGEQ LASTVP 0) (COND (FIRSTFP (printout STREAM FIRSTFP "-"))) (printout STREAM (SUB1 NEXTFP) 14Q) (COND ((EQ LASTVP \NO.VMEM.PAGE) (printout STREAM "empty")) (T (COND (FIRSTFP (\PRINTVP FIRSTVP STREAM) (PRIN1 "-" STREAM))) (\PRINTVP LASTVP STREAM) (COND (LOCKEDP (PRIN1 (QUOTE *) STREAM] (SETQ FIRSTFP) (TERPRI STREAM) (SETQ FIRSTVP NEXTVP)) (T (* in a run) (OR FIRSTFP (SETQ FIRSTFP (SUB1 NEXTFP] (SETQ LASTVP NEXTVP) (SETQ LOCKEDP NEXTLOCKED) (add NWORDS -1]) (\PRINTVP [LAMBDA (VP STREAM) (* bvm: "28-MAR-83 12:40") (printout STREAM "{" (LRSH VP 8) "," (LOGAND VP 255) "}"]) ) (DECLARE: EVAL@COMPILE DONTCOPY (DECLARE: EVAL@COMPILE (PUTPROPS \ACTONVMEMFILE MACRO ((X . Y) (SPREADAPPLY* \VMEMACCESSFN X . Y))) ) (* Virtual page flags) (DECLARE: EVAL@COMPILE (RPAQQ \VMAP.DIRTY 10000Q) (RPAQQ \VMAP.CLEAN 0) (RPAQQ \VMAP.REF 100000Q) (RPAQQ \VMAP.VACANT 30000Q) (RPAQQ \VMAP.FLAGS 170000Q) (RPAQQ \VMAP.NOTFLAGS 7777Q) (CONSTANTS \VMAP.DIRTY \VMAP.CLEAN \VMAP.REF \VMAP.VACANT \VMAP.FLAGS \VMAP.NOTFLAGS) ) [DECLARE: EVAL@COMPILE (ACCESSFNS VMEMFLAGS ((VACANT (EQ (LOGAND DATUM \VMAP.VACANT) \VMAP.VACANT)) (DIRTY (NEQ (LOGAND DATUM \VMAP.DIRTY) 0)) (REFERENCED (NEQ (LOGAND DATUM \VMAP.REF) 0)))) ] (DECLARE: EVAL@COMPILE (PUTPROPS LOGNOT16 MACRO ((X) (LOGXOR X 177777Q))) ) (* RPT constants) (DECLARE: EVAL@COMPILE (RPAQQ \PAGEMAPLOCKBIT 100000Q) (RPAQQ \RPT.EMPTY 40000Q) (RPAQQ \RPT.UNAVAILABLE 40400Q) (RPAQQ \PAGETABLESTOPFLG 0) (RPAQQ \RPTENTRYLENGTH 3) (CONSTANTS \PAGEMAPLOCKBIT \RPT.EMPTY \RPT.UNAVAILABLE \PAGETABLESTOPFLG \RPTENTRYLENGTH) ) [DECLARE: EVAL@COMPILE (BLOCKRECORD RPT ((NEXTRP WORD) (* rp of next entry in page chain) (VP WORD) (* Virtual page number occupying this real page) (LOCKED FLAG) (FILEPAGE BITS 17Q) (* Page in Lisp.VirtualMem) ) (BLOCKRECORD RPT ((NIL WORD) (NIL WORD) (FILEPAGE&LOCK WORD))) [ACCESSFNS RPT ((RPTRBASE (\ADDBASE \REALPAGETABLE (TIMES3 DATUM))) [EMPTY (EQ (fetch (RPT VP) of DATUM) \RPT.EMPTY) (COND (NEWVALUE (replace (RPT VP) of DATUM with \RPT.EMPTY)) (T (ERROR "Invalid replace of RPT.EMPTY" DATUM] [UNAVAILABLE (EQ (fetch (RPT VP) of DATUM) \RPT.UNAVAILABLE) (COND (NEWVALUE (replace (RPT VP) of DATUM with \RPT.UNAVAILABLE)) (T (ERROR "Invalid replace of RPT.UNAVAILABLE" DATUM] (OCCUPIED (ILESSP (fetch (RPT VP) of DATUM) \RPT.EMPTY] (* Given a RP, RPTRBASE produces a pointer to its entry in the real page table) ) ] (DECLARE: EVAL@COMPILE (PUTPROPS RPFROMRPT MACRO ((RPTINDEX) (IPLUS RPTINDEX \RPOFFSET))) (PUTPROPS RPTFROMRP MACRO ((RP) (IDIFFERENCE RP \RPOFFSET))) ) (* Virtual to file pagemap) (DECLARE: EVAL@COMPILE (RPAQQ \MAXVMPAGE 37777Q) (RPAQQ \MAXVMSEGMENT 77Q) (RPAQQ \EMPTYPMTENTRY 177777Q) (CONSTANTS \MAXVMPAGE \MAXVMSEGMENT \EMPTYPMTENTRY) ) [DECLARE: EVAL@COMPILE (ACCESSFNS VP ((PRIMARYKEY (LRSH DATUM 5)) (SECONDARYKEY (LOGAND DATUM 37Q)) (INVALID (IGREATERP DATUM \MAXVMPAGE)))) (ACCESSFNS PAGEMAPENTRY [(FILEPAGEONLY (LOGAND DATUM 77777Q)) (LOCKEDP (NOT (ZEROP (LOGAND DATUM 100000Q]) ] (* FP to VP stuff) [DECLARE: EVAL@COMPILE (BLOCKRECORD FPTOVP ((FPLOCKED FLAG) (NIL FLAG) (FPVIRTUALPAGE BITS 16Q)) [ACCESSFNS FPTOVP ((FPOCCUPIED (NEQ (\GETBASE DATUM 0) \NO.VMEM.PAGE]) ] (DECLARE: EVAL@COMPILE (RPAQQ \NO.VMEM.PAGE 177777Q) (CONSTANTS \NO.VMEM.PAGE) ) (DECLARE: EVAL@COMPILE (PUTPROPS DLRPFROMFP MACRO ((FP) (ADD1 FP))) (PUTPROPS DLFPFROMRP MACRO ((RP) (SUB1 RP))) ) (PUTPROPS \TOUCHPAGE DOPVAL (1 GETBASE.N 0)) (PUTPROPS TIMES3 DOPVAL (1 COPY LLSH1 IPLUS2)) (DECLARE: EVAL@COMPILE (RPAQQ \MAXDIRTYSCANCOUNT 144Q) (RPAQQ \MINVMEMSPAREPAGES 144Q) (RPAQQ \DLBUFFERPAGES 20Q) (CONSTANTS \MAXDIRTYSCANCOUNT \MINVMEMSPAREPAGES \DLBUFFERPAGES) ) (DECLARE: DOEVAL@COMPILE DONTCOPY (ADDTOVAR GLOBALVARS \UPDATECHAINFREQ \REALPAGETABLE \RPOFFSET \RPTSIZE \EMBUFBASE \EMBUFVP \EMBUFRP \PAGEFAULTCOUNTER \LASTDIRTYCNT \LASTDIRTYFOUND \LASTDIRTYSCANPTR \MACHINETYPE \LASTACCESSEDVMEMPAGE \MAXSHORTSEEK \MAXCLEANPROBES \MINSHORTSEEK \DIRTYSEEKMAX \DIRTYPAGECOUNTER \DIRTYPAGEHINT \VMEM.INHIBIT.WRITE \KBDSTACKBASE \MISCSTACKBASE \DOFAULTINIT \FPTOVP \VMEMACCESSFN \SYSTEMCACHEVARS) ) (DECLARE: DOEVAL@COMPILE DONTCOPY (ADDTOVAR GLOBALVARS \#SWAPBUFFERS \#EMUBUFFERS \#DISKBUFFERS \EMUSWAPBUFFERS \EMUBUFFERS \TELERAIDBUFFER \EMUDISKBUFFERS \EMUDISKBUFEND) ) ) (* * MAKEINIT stuff) (DEFINEQ (ADDPME [LAMBDA (VP NEWPAGEOK) (* bvm: "29-MAR-83 17:10") (* add an entry for VP to the PAGEMAP. Called only under MAKEINIT) (PROG (PX PMP) [COND ((IEQ (SETQ PMP (\GETBASE \PageMapTBL (fetch (VP PRIMARYKEY) of VP))) \EmptyPMTEntry) (* empty entries in the PageMapTBL have 177777q as their value) (COND ((EVENP NEXTPM WORDSPERPAGE) (* must add a new page map page) (SETQ PX (\ADDBASE \PAGEMAP NEXTPM)) (OR NEWPAGEOK (IGREATERP (PAGELOC PX) VP) (HELP "page map needs new page after page map written out")) (\NEWPAGE PX NIL T))) (\PUTBASE \PageMapTBL (fetch (VP PRIMARYKEY) of VP) (SETQ PMP NEXTPM)) (SETQ NEXTPM (IPLUS NEXTPM \PMblockSize] (SETQ PX (IPLUS PMP (fetch (VP SECONDARYKEY) of VP))) [COND ((NEQ (\GETBASE \PAGEMAP PX) 0) (HELP "page already in pagemap" VP)) (T (\PUTBASE \PAGEMAP PX (COND ((LOCKEDPAGEP VP) (IPLUS \PAGEMAPLOCKBIT NEXTVMEM)) (T NEXTVMEM] (SETQ NEXTVMEM (ADD1 NEXTVMEM]) (CHECKIFPAGE [LAMBDA NIL (* lmm "20-AUG-81 13:11") (CHECKIF LVersion EQUAL \LispVersion "Lisp Version") (CHECKIF Key EQUAL \IFPValidKey "Interface page key"]) (FIXIFPAGE [LAMBDA (RPT RPTSIZE RPOFFSET RPTLAST EMBUFVP) (* lmm "17-JUN-82 00:03") (* for DANDELION only - called, renamed, by DLFILEBUILD) (replace RVersion of \InterfacePage with \MinRamVersion) (replace BVersion of \InterfacePage with 177777Q) (replace MachineType of \InterfacePage with \DANDELION) (replace SerialNumber of \InterfacePage with 0) (replace EmulatorSpace of \InterfacePage with 0) (replace ScreenWidth of \InterfacePage with 100Q) (replace UserNameAddr of \InterfacePage with 0) (replace UserPswdAddr of \InterfacePage with 0) (replace REALPAGETABLE of \InterfacePage with RPT) (replace RPTSIZE of \InterfacePage with RPTSIZE) (replace RPOFFSET of \InterfacePage with (UNSIGNED RPOFFSET BITSPERWORD)) (replace RPTLAST of \InterfacePage with RPTLAST) (replace EMBUFVP of \InterfacePage with EMBUFVP) (* (replace NSHost0 of \InterfacePage with NSHost0) (replace NSHost1 of \InterfacePage with NSHost1) (replace NSHost2 of \InterfacePage with NSHost2)) NIL]) (DUMPINITPAGES [LAMBDA (CODESTARTOFFSET CODELASTPAGE) (* bvm: "30-MAR-83 12:15") (* called only under MAKEINIT) (ADDPME (PAGELOC \InterfacePage) T) (* THE INTERFACE PAGE MUST BE THE FIRST PAGE) (for I from (IPLUS (UNFOLD \ARRAYspace PAGESPERSEGMENT) CODESTARTOFFSET) to CODELASTPAGE do (* add the pagemap entries for the pages which were written directly to the file) (ADDPME I T)) (MAPPAGES 0 (ADD1 \MAXVMPAGE) (FUNCTION MAKEROOMFORPME)) (MAPPAGES 0 (ADD1 \MAXVMPAGE) (FUNCTION ADDPME)) (PROGN (* set interface page locations - stack pointers already set up IN SETUPSTACK) (replace (IFPAGE NxtPMAddr) of \InterfacePage with NEXTPM) (replace (IFPAGE NActivePages) of \InterfacePage with (SUB1 NEXTVMEM)) (replace (IFPAGE NDirtyPages) of \InterfacePage with (SUB1 NEXTVMEM)) (replace (IFPAGE filePnPMP0) of \InterfacePage with (fetch FILEPAGEONLY of (\GETBASE \PAGEMAP 0))) [replace (IFPAGE filePnPMT0) of \InterfacePage with (fetch FILEPAGEONLY of (\GETBASE \PAGEMAP (\GETBASE \PageMapTBL (fetch PRIMARYKEY of (PAGELOC \PageMapTBL] (replace (IFPAGE LVersion) of \InterfacePage with \LispVersion) (replace (IFPAGE MinRVersion) of \InterfacePage with \MinRamVersion) (replace (IFPAGE MinBVersion) of \InterfacePage with \MinBcplVersion) (replace (IFPAGE Key) of \InterfacePage with \IFPValidKey)) (MAPPAGES 0 (ADD1 \MAXVMPAGE) (FUNCTION DUMPVP)) (SETFILEPTR (OUTPUT) MKI.Page0Byte) (DUMPVP (PAGELOC \InterfacePage]) (MAKEROOMFORPME [LAMBDA (VP) (* bvm: "29-MAR-83 17:11") (* make sure that the pagemap-page for page VP exists; we later will want to add it to the pagemap) (COND ((IEQ (\GETBASE \PageMapTBL (fetch (VP PRIMARYKEY) of VP)) \EmptyPMTEntry) (* empty entries in the PageMapTBL have 177777q as their value) (COND ((EVENP NEXTPM WORDSPERPAGE) (* must add a new page map page) (\NEWPAGE (\ADDBASE \PAGEMAP NEXTPM) NIL T))) (\PUTBASE \PageMapTBL (fetch (VP PRIMARYKEY) of VP) NEXTPM) (SETQ NEXTPM (IPLUS NEXTPM \PMblockSize]) (MAPPAGES [LAMBDA (BOT TOP FN) (* lmm "26-MAR-81 12:23") (PROG ((VP BOT) (IVP (PAGELOC \InterfacePage))) LP (COND ((AND (SETQ VP (MKI.NEXTPAGE VP)) (IGREATERP TOP VP)) (COND ((NOT (IEQ VP IVP)) (APPLY* FN VP))) (SETQ VP (ADD1 VP)) (GO LP]) (READPAGEMAP [LAMBDA NIL (* bvm: " 7-APR-82 14:35") (* called only under READSYS) (PROG (FIRSTPMT D) (LOCAL (MAPVMPAGE (fetch (POINTER PAGE#) of \InterfacePage) 1)) (* Install interface page by magic) (CHECKIFPAGE) [LOCAL (MAPVMPAGE (PAGELOC \PAGEMAP) (SUB1 (fetch (IFPAGE filePnPMP0) of \InterfacePage] (* map in page map) (SETQ FIRSTPMT (SUB1 (fetch (IFPAGE filePnPMT0) of \InterfacePage))) (LOCAL (SETVMPTR \PAGEMAP)) (READPAGEMAPBLOCK (fetch (POINTER PAGE#) of \PAGEMAP)) (* read in all the page map table pages) [for J from 0 to (SUB1 \NumPMTpages) do (LOCAL (MAPVMPAGE (IPLUS (PAGELOC \PageMapTBL) J) (IPLUS FIRSTPMT J] (for I from 0 to (SUB1 (UNFOLD \NumPMTpages WORDSPERPAGE)) do (COND ((IEQ (SETQ D (GETBASE \PageMapTBL I)) \EmptyPMTEntry)) (T (LOCAL (SETVMPTR (ADDBASE \PAGEMAP D))) (READPAGEMAPBLOCK (UNFOLD I \PMblockSize]) (READPAGEMAPBLOCK [LAMBDA (VP) (* lmm " 4-MAY-82 21:12") (PROG ((B VP) P) (FRPTQ \PMblockSize [COND ((NEQ (SETQ P (VBIN2)) 0) (LOCAL (MAPVMPAGE B (SUB1 P] (SETQ B (ADD1 B]) (SETUPPAGEMAP [LAMBDA NIL (* bvm: "29-MAR-83 17:11") (* called only from MAKEINIT to initialize the page map) (PROG (VPX) (* set up page map) (\NEWPAGE \PAGEMAP NIL T) (CREATEPAGES \PageMapTBL \NumPMTpages NIL T) (* init PageMapTBL pages to 177777q) (for I from 0 to (SUB1 (UNFOLD \NumPMTpages WORDSPERPAGE)) do (\PUTBASE \PageMapTBL I \EmptyPMTEntry)) (SETQ NEXTPM 0) (SETQ VPX (fetch (VP PRIMARYKEY) of (PAGELOC \PAGEMAP))) (for I from 0 to (SUB1 (fetch (VP PRIMARYKEY) of \NumPageMapPages)) do (\PUTBASE \PageMapTBL (IPLUS VPX I) NEXTPM) (SETQ NEXTPM (IPLUS NEXTPM \PMblockSize))) (* add entry for InterfacePage which must be on FirstVMemBlock) (SETQ NEXTVMEM \FirstVmemBlock]) ) (DECLARE: DONTCOPY (DECLARE: EVAL@COMPILE (PUTPROPS CHECKIF MACRO [(FLD COMPARISON VALUE STR) (COND ((NOT (COMPARISON VALUE (fetch (IFPAGE FLD) of \InterfacePage))) (printout T "Warning: " STR "= " (PROGN VALUE) ", but \InterfacePage says " (fetch (IFPAGE FLD) of \InterfacePage) T]) ) (ADDTOVAR INEWCOMS (FNS DUMPINITPAGES) (VARS INITCONSTANTS) (FNS SETUPPAGEMAP ADDPME MAKEROOMFORPME MAPPAGES)) (ADDTOVAR RDCOMS (FNS READPAGEMAP READPAGEMAPBLOCK CHECKIFPAGE FIXIFPAGE)) (ADDTOVAR EXPANDMACROFNS CHECKIF) (ADDTOVAR MKI.SUBFNS (\NEWPAGE . MKI.NEWPAGE) (\LOCKPAGES . MKI.LOCKPAGES)) (ADDTOVAR RD.SUBFNS (\NEWPAGE . VNEWPAGE) (\LOCKPAGES . VLOCKPAGES)) EVAL@COMPILE (ADDTOVAR DONTCOMPILEFNS DUMPINITPAGES SETUPPAGEMAP ADDPME MAKEROOMFORPME MAPPAGES READPAGEMAP READPAGEMAPBLOCK CHECKIFPAGE) ) (DEFINEQ (\LOCKFN [LAMBDA (FN) (* bvm: "22-NOV-82 17:39") [\LOCKCELL (SETQ FN (fetch (LITATOM DEFINITIONCELL) of (EVQ FN] (COND ((fetch (DEFINITIONCELL CCODEP) of FN) (\LOCKCODE (fetch (DEFINITIONCELL DEFPOINTER) of FN]) (\LOCKCODE [LAMBDA (CODEBLOCK) (* bvm: "22-NOV-82 17:35") (\LOCKWORDS CODEBLOCK (UNFOLD (IDIFFERENCE (fetch (ARRAYBLOCK ARLEN) of (\ADDBASE CODEBLOCK (IMINUS \ArrayBlockHeaderWords))) \ArrayBlockOverheadWords) WORDSPERCELL]) (\LOCKVAR [LAMBDA (VAR) (* lmm " 5-APR-82 00:43") (\LOCKCELL (fetch (LITATOM VCELL) of (EVQ VAR]) (\LOCKCELL [LAMBDA (X NPGS) (* bvm: "22-NOV-82 17:54") (\LOCKPAGES (PAGEBASE X) (OR NPGS 1]) (\LOCKWORDS [LAMBDA (BASE NWORDS) (* bvm: "22-NOV-82 17:35") (\LOCKPAGES (PAGEBASE BASE) (COND (NWORDS (FOLDHI (IPLUS (fetch (POINTER WORDINPAGE) of BASE) NWORDS) WORDSPERPAGE)) (T 1]) ) (DECLARE: DONTCOPY (ADDTOVAR INEWCOMS (ALLOCAL (ADDVARS (LOCKEDFNS \FAULTHANDLER \FAULTINIT \D01.FAULTINIT \DL.FAULTINIT \MAKESPACEFORLOCKEDPAGE \PAGEFAULT \READRP \READFLAGS \WRITEMAP \LOOKUPPAGEMAP \LOADVMEMPAGE \INVALIDADDR RAID \INVALIDVP \SELECTREALPAGE \TRANSFERPAGE \UPDATECHAIN \MARKPAGEVACANT \FLUSHPAGE \MOVEPAGE \ZEROPAGE \FLUSHVM \DONEWPAGE \DONEWEPHEMERALPAGE \WRITEDIRTYPAGE1 \COPYSYS0 \COPYSYS0SUBR \RELEASEWORKINGSET \DOFLUSHVM \DOLOCKPAGES \TEMPLOCKPAGES \TEMPUNLOCKPAGES \MP.ERROR \DL.NEWFAULTINIT \DL.ASSIGNBUFFERS \D01.ASSIGNBUFFERS) (LOCKEDVARS \REALPAGETABLE \PAGEFAULTCOUNTER \UPDATECHAINFREQ \RPOFFSET \RPTSIZE \EMBUFBASE \EMBUFVP \EMBUFRP \LASTACCESSEDVMEMPAGE \MAXSHORTSEEK \MAXCLEANPROBES \MINSHORTSEEK \DIRTYPAGECOUNTER \DIRTYPAGEHINT \VMEM.INHIBIT.WRITE \KBDSTACKBASE \MISCSTACKBASE \DOFAULTINIT \FPTOVP \MACHINETYPE \VMEMACCESSFN \TELERAIDBUFFER \EMUDISKBUFFERS \EMUDISKBUFEND))) (FNS \LOCKFN \LOCKVAR \LOCKCELL \LOCKWORDS \LOCKCODE)) ) (* Clock stuff) (DEFINEQ (\CLOCK0 [LAMBDA (BOX) (* bvm: "13-OCT-82 15:10") (* Stores millisecond clock in BOX. Do this by fetching the current millisecond clock and adding in the number of milliseconds since the clock was last updated) (SETQ BOX (\DTEST BOX (QUOTE FIXP))) (UNINTERRUPTABLY (\GETINTERNALCLOCK \OFFSET.MILLISECONDS BOX) [bind (EXCESS ←(LOCF (fetch EXCESSTIMETMP of \MISCSTATS))) while (OR (IGREATERP EXCESS \RCLKSECOND) (ILESSP EXCESS 0)) do (* Excess time. unsigned, is more than a second, so clock has not been updated in ages (perhaps someone sat in Raid for a while). We don't want IQUOTIENT here to do a CREATECELL, so do some of the division by subtraction. Instead of \RCLKSECOND, it would really be better to use \RCLKMILLISECOND*MAX.SMALL.INTEGER, but this is a rare case already, so be lazy) (\BOXIPLUS BOX 1750Q) (\BOXIDIFFERENCE EXCESS \RCLKSECOND) finally (* Now it is safe to use IQUOTIENT) (RETURN (\BOXIPLUS BOX (IQUOTIENT EXCESS \RCLKMILLISECOND])]) (\DAYTIME0 [LAMBDA (BOX) (* bvm: "24-JUN-82 15:39") (UNINTERRUPTABLY (\GETINTERNALCLOCK \OFFSET.SECONDS (\DTEST BOX (QUOTE FIXP))))]) (\GETINTERNALCLOCK [LAMBDA (CLOCKOFFSET BOX) (* bvm: "24-JUN-82 15:39") (* Stores in BOX the contents of internal timer denoted by CLOCKOFFSET (0 = SECONDS, 2 = MILLISECONDS). Excess time is in EXCESSTIMETEMP. Must be called UNINTERRUPTABLY) (\BLT (LOCF (fetch SECONDSTMP of \MISCSTATS)) (LOCF (fetch SECONDSCLOCK of \MISCSTATS)) (UNFOLD 3 WORDSPERCELL)) (* Copy system clocks into scratch area, so there is no update conflict) (\BLT BOX (\ADDBASE (LOCF (fetch SECONDSTMP of \MISCSTATS)) CLOCKOFFSET) WORDSPERCELL) (* Copy clock to caller) (\BOXIDIFFERENCE (\RCLK (LOCF (fetch EXCESSTIMETMP of \MISCSTATS))) (LOCF (fetch BASETMP of \MISCSTATS))) (* Compute processor time since clock was updated) BOX]) (\SETDAYTIME0 [LAMBDA (BOX) (* bvm: "22-SEP-82 17:42") (* Sets the seconds calendar to contents of BOX) (SETQ BOX (\DTEST BOX (QUOTE FIXP))) (UNINTERRUPTABLY (\RCLK (LOCF (fetch BASETMP of \MISCSTATS))) (* Reset the base; clocks will not be adjusted for at least a second after this) (\BLT (LOCF (fetch SECONDSTMP of \MISCSTATS)) BOX WORDSPERCELL) (\BLT (LOCF (fetch SECONDSCLOCK of \MISCSTATS)) (LOCF (fetch SECONDSTMP of \MISCSTATS)) (UNFOLD 3 WORDSPERCELL)) (* Finally store them all at once, uninterruptably) [COND ((EQ \MACHINETYPE \DANDELION) (* Tell the iop the new time, too) (repeatwhile (IGEQ (fetch DLPROCESSORCMD of \IOPAGE) \DL.PROCESSORBUSY)) (replace DLPROCESSOR2 of \IOPAGE with (\GETBASE BOX 1)) (replace DLPROCESSOR1 of \IOPAGE with (\GETBASE BOX 0)) (replace DLPROCESSORCMD of \IOPAGE with \DL.SETTOD) (replace DLTODVALID of \IOPAGE with 0) (repeatwhile (IGEQ (fetch DLPROCESSORCMD of \IOPAGE) \DL.PROCESSORBUSY)) (repeatwhile (ZEROP (fetch DLTODVALID of \IOPAGE]) BOX]) (\CLOCKDIFFERENCE [LAMBDA (OLDCLOCK) (* bvm: "24-JUN-82 15:40") (UNINTERRUPTABLY (IPLUS (\BOXIDIFFERENCE (\CLOCK0 (LOCF (fetch CLOCKTEMP0 of \MISCSTATS))) OLDCLOCK)))]) (\RCLOCK0 (LAMBDA (BOX) (* JonL "19-APR-83 01:47") (\RCLK (\DTEST BOX (QUOTE FIXP))))) ) (DEFINEQ (CLOCK0 [LAMBDA (BOX) (* bvm: " 1-APR-83 15:26") (* Store millisecond clock at BOX. Unfortunately, there are still a few folks that call this without a true box, so accomodate them for now) (COND ((EQ (NTYPX BOX) \FIXP) (\CLOCK0 BOX)) (T (\MP.ERROR \MP.CLOCK0 "Call to CLOCK0 with arg not a number box. ↑N to continue." BOX) (UNINTERRUPTABLY (\BLT BOX (\CLOCK0 (LOCF (fetch CLOCKTEMP0 of \MISCSTATS))) WORDSPERCELL)) BOX]) ) (DECLARE: EVAL@COMPILE (PUTPROPS \RCLOCK0 DMACRO [(BOX) (\RCLK (\DTEST BOX (QUOTE FIXP]) ) (DECLARE: DONTCOPY (* FOLLOWING DEFINITIONS EXPORTED) (DECLARE: EVAL@COMPILE (PUTPROPS \UPDATETIMERS MACRO [NIL (* * Moves excess time from the processor clock to our software clocks. Needs to be run often, uninterruptably, preferably from the vertical retrace interrupt) (* Get processor clock) (PROG [(EXCESS (\BOXIDIFFERENCE (\RCLK (LOCF (fetch RCLKTEMP0 of \MISCSTATS))) (LOCF (fetch BASECLOCK of \MISCSTATS] (RETURN (COND ((OR (IGEQ EXCESS \RCLKSECOND) (ILESSP EXCESS 0)) (* More than one second has elapsed since we updated clocks) (\BOXIPLUS (LOCF (fetch BASECLOCK of \MISCSTATS)) \RCLKSECOND) (* Increment base by one second) (\BOXIPLUS (LOCF (fetch MILLISECONDSCLOCK of \MISCSTATS)) 1750Q) (* Increment clocks by 1 second) (\BOXIPLUS (LOCF (fetch SECONDSCLOCK of \MISCSTATS)) 1) T]) ) (* END EXPORTED DEFINITIONS) ) (DECLARE: DONTEVAL@LOAD DOCOPY (MOVD (QUOTE \DAYTIME0) (QUOTE DAYTIME0)) ) (RPAQQ \RCLKMILLISECOND 3220Q) (DECLARE: DOEVAL@COMPILE DONTCOPY (ADDTOVAR GLOBALVARS \RCLKSECOND \RCLKMILLISECOND) ) (DECLARE: DONTCOPY (* Locations in alto emulator) (* FOLLOWING DEFINITIONS EXPORTED) (DECLARE: EVAL@COMPILE (RPAQQ \RTCSECONDS 572Q) (RPAQQ \RTCMILLISECONDS 574Q) (RPAQQ \RTCBASE 576Q) (RPAQQ \OFFSET.SECONDS 0) (RPAQQ \OFFSET.MILLISECONDS 2) (RPAQQ \OFFSET.BASE 4) (RPAQQ \ALTO.RCLKSECOND 6321200Q) (RPAQQ \ALTO.RCLKMILLISECOND 3220Q) (RPAQQ \DLION.RCLKMILLISECOND 43Q) (RPAQQ \DLION.RCLKSECOND 103672Q) (CONSTANTS (\RTCSECONDS 572Q) (\RTCMILLISECONDS 574Q) (\RTCBASE 576Q) (\OFFSET.SECONDS 0) (\OFFSET.MILLISECONDS 2) (\OFFSET.BASE 4) (\ALTO.RCLKSECOND 6321200Q) (\ALTO.RCLKMILLISECOND 3220Q) (\DLION.RCLKMILLISECOND 43Q) (\DLION.RCLKSECOND 103672Q)) ) (* END EXPORTED DEFINITIONS) (* Locked stuff. Have to lock anything used by pagefault code, including the ufns that they use until all microcodes have them) (ADDTOVAR INEWCOMS (ALLOCAL (ADDVARS (LOCKEDFNS \CLOCK0 \GETINTERNALCLOCK \BOXIDIFFERENCE \BOXIPLUS \BLT \SLOWIQUOTIENT) (LOCKEDVARS \RCLKSECOND \RCLKMILLISECOND \MISCSTATS)))) ) (PUTPROPS LLFAULT COPYRIGHT ("Xerox Corporation" 3676Q 3677Q)) (DECLARE: DONTCOPY (FILEMAP (NIL (14066Q 14661Q (\FAULTHANDLER 14100Q . 14657Q)) (14713Q 60233Q (\FAULTINIT 14725Q . 17602Q) (\D01.FAULTINIT 17604Q . 22525Q) (\DL.FAULTINIT 22527Q . 30146Q) (\DL.NEWFAULTINIT 30150Q . 52013Q) (\D01.ASSIGNBUFFERS 52015Q . 55233Q) (\DL.ASSIGNBUFFERS 55235Q . 60231Q)) (60234Q 117243Q ( \PAGEFAULT 60246Q . 63000Q) (\INVALIDADDR 63002Q . 63255Q) (\INVALIDVP 63257Q . 63515Q) (\FLUSHPAGE 63517Q . 66225Q) (\LOADVMEMPAGE 66227Q . 74174Q) (\LOOKUPPAGEMAP 74176Q . 75167Q) (\MARKPAGEVACANT 75171Q . 75726Q) (\SELECTREALPAGE 75730Q . 103133Q) (\SPECIALRP 103135Q . 104070Q) (\TRANSFERPAGE 104072Q . 111013Q) (\MOVEPAGE 111015Q . 111344Q) (\ZEROPAGE 111346Q . 112110Q) (\UPDATECHAIN 112112Q . 117241Q)) (117244Q 175237Q (\NEWPAGE 117256Q . 120540Q) (\DONEWPAGE 120542Q . 126363Q) ( \MAKESPACEFORLOCKEDPAGE 126365Q . 133376Q) (\NEWEPHEMERALPAGE 133400Q . 134141Q) (\DONEWEPHEMERALPAGE 134143Q . 140725Q) (\LOCKPAGES 140727Q . 141447Q) (\DOLOCKPAGES 141451Q . 145043Q) (\TEMPLOCKPAGES 145045Q . 146712Q) (\TEMPUNLOCKPAGES 146714Q . 150671Q) (\UNLOCKPAGES 150673Q . 153511Q) (\FLUSHVM 153513Q . 155414Q) (\LOGOUT0 155416Q . 156524Q) (\DOFLUSHVM 156526Q . 162272Q) (\RELEASEWORKINGSET 162274Q . 163574Q) (\WRITEDIRTYPAGE 163576Q . 172461Q) (\WRITEDIRTYPAGE1 172463Q . 173613Q) ( \NPAGESBIT 173615Q . 175235Q)) (176277Q 176637Q (\MP.ERROR 176311Q . 176635Q)) (203446Q 216710Q ( \ACTONVMEMFILE 203460Q . 204103Q) (\SHOWPAGETABLE 204105Q . 207001Q) (CHECKPAGEMAP 207003Q . 211702Q) (CHECKFPTOVP 211704Q . 213207Q) (\LOCKED?STRING 213211Q . 213467Q) (\PRINTFPTOVP 213471Q . 216403Q) ( \PRINTVP 216405Q . 216706Q)) (227331Q 250226Q (ADDPME 227343Q . 231723Q) (CHECKIFPAGE 231725Q . 232274Q) (FIXIFPAGE 232276Q . 234766Q) (DUMPINITPAGES 234770Q . 240751Q) (MAKEROOMFORPME 240753Q . 242401Q) (MAPPAGES 242403Q . 243125Q) (READPAGEMAP 243127Q . 245625Q) (READPAGEMAPBLOCK 245627Q . 246206Q) (SETUPPAGEMAP 246210Q . 250224Q)) (252077Q 254422Q (\LOCKFN 252111Q . 252603Q) (\LOCKCODE 252605Q . 253325Q) (\LOCKVAR 253327Q . 253545Q) (\LOCKCELL 253547Q . 254001Q) (\LOCKWORDS 254003Q . 254420Q)) (256563Q 266720Q (\CLOCK0 256575Q . 261107Q) (\DAYTIME0 261111Q . 261425Q) ( \GETINTERNALCLOCK 261427Q . 263302Q) (\SETDAYTIME0 263304Q . 266103Q) (\CLOCKDIFFERENCE 266105Q . 266473Q) (\RCLOCK0 266475Q . 266716Q)) (266721Q 270023Q (CLOCK0 266733Q . 270021Q))))) STOP