// IfsOverlays.bcpl - Interim File System Overlay interface & package // Copyright Xerox Corporation 1979, 1980, 1981, 1982 // last modified May 12, 1982 7:09 PM by Taft get "IfsOverlays.decl" get "IfsVMem.decl" get "SysDefs.d" get "AltoFileSys.d" get "Disks.d" get "IfsXEmulator.decl" external [ //outgoing procedures OvDOPAGEIO; OvCleanupLocks; OvPageType OvPageGroupAlign; OvPageGroupBase; OvPageGroupSize OverlayLockProc; SwappedOut FindOverlayFromPn; GenerateOverlays; DeclareOverlayPresent OverlayFirstPn; OverlayNpages; ReadOverlay; ReleaseOverlay @OverlayFaultProc //incoming procedures @VRRP; LockCell; UnlockCell; CallProc; LoadXM; StoreXM Dequeue; Unqueue; InsertAfter Allocate; Zero; CallersFrame; IFSError; DoubleBlt; DoubleIncrement SetBlock; ActOnDiskPages; Dvec //outgoing statics oVmd; ovPageSize; logOvPageSize; logOvVmPages; ovFirstPage numOvXMPages; numOvXMPagesPerBank; offsetResidentXM // following are for OverlaysInit only @OverlayEntry; @OverlaySave; FirstOD; EndOD; FirstOEP; EndOEP; OverlayFp; OverlayDisk //incoming statics ifsCtxQ; sysZone; CtxRunning; CtxCaller; vmStats ] static [ oVmd // -> VMD for overlays ovPageSize // overlay disk page size logOvPageSize // log of overlay disk page size logOvVmPages // log of VMem pages per overlay disk page ovFirstPage // file page number of first overlay, used to // normalize references in the VMem region numOvXMPages = 0 // number of overlay pages kept in extended memory numOvXMPagesPerBank // number of overlay pages per XM bank offsetResidentXM // offset for resident code moved to XM numOverlaysPresent = 0 // number of overlays presently in memory @OverlayEntry @OverlaySave FirstOD EndOD FirstOEP EndOEP OverlayFp OverlayDisk // MinOverlayLoc = -1 ] structure Ctx: // Context [ next word // queue link stack word // current stack pointer stackMin word // stack limit ] manifest [ jsrRv = #6000 jsrRv370=#6370; sta312=#55001; jsrRv367=#6367; jsrRv366=#6366; ecSwappedOut = 24 ecOverlayAlreadyPresent = 52 ecBadOverlayCall = 53 ecFindOverlayFromPn = 54 ] // Overlay package pages are real disk pages as described in // the "disk" structure. logOvVmPages is a static containing // the log of the number of vmem pages per real disk page. // VMEM interface procedures //---------------------------------------------------------------------------- let ReadOv(od, ctx) = valof //---------------------------------------------------------------------------- // Procedure called via CallProc from OverlayFaultProc to assign storage // for an overlay and read it in. Ctx is the context that suffered the fault. [ LockCell(lv od>>OD.core, OverlayLockProc) let core = VRRP((OverlayFirstPn(od)-ovFirstPage) lshift logOvVmPages + oVmd>>VMD.base) // The following ugly hack ensures that the context that suffered the fault // will be the next one to run. Otherwise the pointer we are passing back // might become invalid because it hasn't been properly installed yet. if ctx ne CtxRunning then [ Unqueue(ifsCtxQ, ctx); InsertAfter(ifsCtxQ, CtxRunning, ctx) ] resultis core ] //---------------------------------------------------------------------------- and OverlayLockProc(lvLock, newAddr, flag) = valof //---------------------------------------------------------------------------- [ let ok = ReleaseOverlay(lvLock-(offset OD.core/16), flag) if ok & flag then UnlockCell(lvLock) resultis ok ] //---------------------------------------------------------------------------- and OvCleanupLocks(vmd) be //---------------------------------------------------------------------------- // Recomputes the onstack bits of all overlays by enumerating all frames // in all contexts' stacks. // We do this differently from the manner described in the Overlay package // documentation because that procedure has a cost proportional to f*n, // where f is the number of active frames and n is the number of overlays. // IFS has a very large number of overlays, so that is much too expensive. // Our procedure has a cost proportional to f+n. // If CtxCaller=0 then we are still initializing and contexts aren't // running yet, so don't enumerate the ifsCtxQ. [ if numOverlaysPresent eq 0 then return // nothing to do! // Build temporary table of pages containing locked overlays. let lenLockTable = 1 lshift (16-logOvPageSize) let lockTable = lenLockTable; Dvec(OvCleanupLocks, lv lockTable) Zero(lockTable, lenLockTable) let ctx = CtxCaller eq 0? CtxRunning, ifsCtxQ!0 while ctx ne 0 do //for all contexts [ let frame = ctx eq CtxRunning? CallersFrame(), ctx>>Ctx.stack while frame ne 0 do [ //lock all pending procedures on stack lockTable!(frame>>FRAME.savedPC rshift logOvPageSize) = true; frame = frame>>FRAME.callersFrame; ] if CtxCaller eq 0 break ctx = ctx>>Ctx.next ] // Transfer information to the Overlay Descriptors let od = FirstOD while od ne EndOD do [ od>>OD.onstack = false if od>>OD.core ne 0 then for i = 0 to (od+lOD)>>OD.firstPn - od>>OD.firstPn -1 do [ let ovPage = od>>OD.core rshift logOvPageSize + i; if lockTable!ovPage then od>>OD.onstack = true; ] od = od+lOD ] ] //---------------------------------------------------------------------------- and OvPageType(vmd, vPage, wFlag) = 1 //---------------------------------------------------------------------------- //---------------------------------------------------------------------------- and OvPageGroupAlign(vmd, vPage) = 1 lshift logOvVmPages -1 //---------------------------------------------------------------------------- //---------------------------------------------------------------------------- and OvPageGroupBase(vmd, vPage) = vPage //---------------------------------------------------------------------------- // This gets called only for the vPage that faulted, and the overlay package // always touches the first page of the group. //---------------------------------------------------------------------------- and OvPageGroupSize(vmd, vPage) = //---------------------------------------------------------------------------- OverlayNpages(FindOverlayFromPn((vPage-vmd>>VMD.base) rshift logOvVmPages + ovFirstPage)) lshift logOvVmPages //---------------------------------------------------------------------------- and OvDOPAGEIO(vmd, vPage, core, nVPgs, wFlag) be //---------------------------------------------------------------------------- [ let normPage = (vPage-vmd>>VMD.base) rshift logOvVmPages let nPages = nVPgs rshift logOvVmPages test normPage+nPages le numOvXMPages ifso // Read overlay from XM [ DoubleBlt(core, (normPage rem numOvXMPagesPerBank) lshift logOvPageSize, nPages lshift logOvPageSize, normPage/numOvXMPagesPerBank +1) DoubleIncrement(lv vmStats>>VMStats.ovXMReads) ] ifnot // Read overlay from disk [ ReadOverlay(ovFirstPage+normPage, core, nPages) DoubleIncrement(lv vmStats>>VMStats.ovDiskReads) ] ] //---------------------------------------------------------------------------- and SwappedOut(nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil) be //---------------------------------------------------------------------------- IFSError(ecSwappedOut) // IFS Extended Emulator version of overlay package // Based on: Overlays.BCPL - Bcpl overlay package, by P. Deutsch, // last edited May 24, 1977 12:48 PM //---------------------------------------------------------------------------- // and LockPendingCode(stack; numargs na) be //---------------------------------------------------------------------------- // [ // if na eq 0 then // current stack // [ // let od = FirstOD // while od ne EndOD do [ od>>OD.onstack = 0; od = od+lOD ] // stack = (lv stack)!-4 // ] // while @stack ugr stack do // [ // LockPendingPc(stack!1) // stack = @stack // ] // ] //---------------------------------------------------------------------------- // and LockPendingPc(pc) be //---------------------------------------------------------------------------- // [ // if pc uge MinOverlayLoc then // O.S. or overlay // [ // let od = FirstOD // while od ne EndOD do // [ // if od>>OD.core ne 0 & // (pc-od>>OD.core) rshift OverlayDisk>>DSK.lnPageSize ls // (od+lOD)>>OD.firstPn-od>>OD.firstPn then // od>>OD.onstack = 1 // od = od+lOD // ] // ] // ] //---------------------------------------------------------------------------- and FindOverlayFromPn(pn) = valof //---------------------------------------------------------------------------- [ let od = FirstOD while od ne EndOD do [ if pn eq od>>OD.firstPn resultis od od = od+lOD ] IFSError(ecFindOverlayFromPn) ] //---------------------------------------------------------------------------- // and GeneratePresentOverlays(proc) be //---------------------------------------------------------------------------- // [ // let od = FirstOD // while od ne EndOD do // [ if od>>OD.core ne 0 then proc(od); od = od+lOD ] // ] //---------------------------------------------------------------------------- and GenerateOverlays(proc) be //---------------------------------------------------------------------------- [ let od = FirstOD while od ne EndOD do [ proc(od); od = od+lOD ] ] //---------------------------------------------------------------------------- and OverlayFaultProc(ac0, ac1, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil) = valof //---------------------------------------------------------------------------- [ // *** Critical code began at JSR to missing procedure let ove = OverlayEntry // *** End critical code let od = ove - (offset OD.JSR/16 +1) // Compute static location let callerframe = (lv ac0)!-4 let callerpc = callerframe!1-1 let callerNumArgs = callerpc!1 let callins = @callerpc let disp = (callins±)-(callinsÈ) let callerea = callerpc!disp // (extra work if not JSRII) // Handle calls from extended memory if callerpc + 1 eq lv (callerframe!xArgs) & // extended call, od-FirstOEP uge EndOEP-FirstOEP then // and not special? [ callerframe!xPC = callerframe!xPC - 2; // backup xPC let bank = callerframe!xJmp & 3; callins = LoadXM(bank, callerframe!xPC); disp = (callins±)-(callinsÈ); callerea = LoadXM(bank, callerframe!xPC+disp); callerpc = lv callerframe!xJmp; ] let target = selecton (callins𫓸) into [ case #64400: callerea // JSRII case #65000: callerframe!disp // JSRIS case jsrRv: callinsŹ // JSR @ page 0 case #7000: callerframe+disp // JSR @,2 case #77400: lv EndOD // SWAT, ok default: lv FirstOD // no good ] // Find overlay descriptor let special = nil; // remember if special test od-FirstOEP uls EndOEP-FirstOEP ifso // special entry [ if od>>OEP.JSRJMP ne (STA3JSRI + lv OverlaySave) then // already in IFSError(ecOverlayAlreadyPresent) callerpc = od+(offset OEP.JSRJMP/16) // re-execute in OEP target = lv od>>OEP.ODorEP od = @target special = true; ] ifnot [ if od>>OD.core ne 0 then IFSError(ecOverlayAlreadyPresent) special = false; ] // Read in the overlay DeclareOverlayPresent(od, CallProc(ReadOv, od, CtxRunning)) if @target-FirstOD uls EndOD-FirstOD then unless special & @(target-1) ne (STA3JSRI + lv OverlaySave) do IFSError(ecBadOverlayCall) // Re-execute call callerframe!2 = callerpc resultis (table [ // load up ACs and exit #31000 // LDA 2 0,2 #35001 // LDA 3 1 2 // in case OEP, JSR will not be re-executed #3002 // JMP @2,2 ])(ac0, ac1) ] //---------------------------------------------------------------------------- and DeclareOverlayPresent(od, base) be //---------------------------------------------------------------------------- [ // if base uls MinOverlayLoc then MinOverlayLoc = base let p = base+#21+base!1 let plim = p+2*p!-1 while p ne plim do [ let sa, ep = p!0, base+#20+p!1 test @sa-FirstOEP uls EndOEP-FirstOEP ifso [ // OEP (@sa)>>OEP.JSRJMP = #2401 // JMP @.+1 (@sa)>>OEP.ODorEP = ep ] ifnot @sa = ep // non-OEP p = p+2 ] od>>OD.core = base numOverlaysPresent = numOverlaysPresent+1 ] //---------------------------------------------------------------------------- and OverlayFirstPn(od) = od>>OD.firstPn //---------------------------------------------------------------------------- //---------------------------------------------------------------------------- and OverlayNpages(od) = (od+lOD)>>OD.firstPn-od>>OD.firstPn //---------------------------------------------------------------------------- //---------------------------------------------------------------------------- // and OverlayDiskAddr(od) = od>>OD.da //---------------------------------------------------------------------------- //---------------------------------------------------------------------------- // and OverlayCoreAddr(od) = od>>OD.core //---------------------------------------------------------------------------- //---------------------------------------------------------------------------- and ReadOverlay(pn, core, np) be //---------------------------------------------------------------------------- [ let DAs, CAs = np, np Dvec(ReadOverlay, lv DAs, lv CAs) for i = 0 to np-1 do CAs!i = core + i lshift OverlayDisk>>DSK.lnPageSize SetBlock(DAs, fillInDA, np+1) DAs!0 = FindOverlayFromPn(pn)>>OD.da ActOnDiskPages(OverlayDisk, CAs-pn, DAs-pn, OverlayFp, pn, pn+np-1, DCreadD) ] //---------------------------------------------------------------------------- and ReleaseOverlay(od, flag) = valof //---------------------------------------------------------------------------- [ if od>>OD.onstack ne 0 resultis false unless flag resultis true let base = od>>OD.core let p = base+#21+base!1 let plim = p+2*p!-1 while p ne plim do [ let sa = p!0 test @sa-FirstOEP uls EndOEP-FirstOEP // special entry? ifso // yes [ (@sa)>>OEP.JSRJMP=STA3JSRI+lv OverlaySave; (@sa)>>OEP.ODorEP=od; ] ifnot @sa = od // no p = p+2 ] od>>OD.core = 0 numOverlaysPresent = numOverlaysPresent-1 resultis true ]