// OsMain.bcpl -- CallSubsys and utilities // Copyright Xerox Corporation 1979, 1980 // Last modified September 7, 1980 6:06 PM by Boggs get "AltoFileSys.d" get "Streams.d" get "SysDefs.d" get "AltoDefs.d" get "SysInternals.d" get "BcplFiles.d" external [ // outgoing procedures CallSubsys; Junta //public FinishInitOs //private // incoming procedures by junta level // Basic InLd; CallSwat // BFS BFSClose; BFSWriteDiskDescriptor DefaultArgs; SysErr MyFrame; GotoLabel; GotoFrame; CallersFrame StartIO; Usc; SetBlock; MoveBlock; Zero // DiskStreams Gets; Puts; Closes; Endofs; Resets ReadBlock; WriteBlock PositionPage; GetCompleteFa // Dirs OpenFile // Alloc InitializeZone // Keyboard SetKeyboardProc // Display ShowDisplayStream // OsUtils GetFixedInit; SetEndCode; Ws // incoming system-wide statics fpExecutive; fpSysBoot; EnumerateFp keys; dsp; sysFont; sysDisk juntaTable; OsFinishCode; EventVector lvAbortFlag; lvCursorLink sysZone; protectedSysZone; lProtectedSysZone ] manifest [ // error codes ecStaticLocation = 1960 ecCodeLocation = 1961 ecNoExecutive = 1962 ecIllegalJuntaLevelName = 1963 ecAlreadyJuntaed = 1964 ecBLV = 1965 ecNotInstalled = 1966 userBottom = 1000b ] static [ subsys; swat; userParams; sysRoot ] //--------------------------------------------------------------------------- let FinishInitOs() be //--------------------------------------------------------------------------- // This routine is called after all boot initialization is complete. // Here is where we are supposed to come when a "finish" is executed [ @activeInterrupts = OsActiveNormal //Reset interrupt system... //Point intVec slots for idle channels at location zero. //If we somehow get an interrupt we should land in swat. //Note that the truth about whether a channel is in use is whether // the channel bit in ACTIVE is on; testing the intVec slot for // zero is frowned upon. for i = 0 to 14 do if (OsActiveNormal&(1 lshift i)) eq 0 then interruptVector!i = 0 StartIO(3) //Turn off Ethernet SetEndCode(userBottom) //"Finish" only sets temporarily let cjProc = juntaTable>>JT.jReason if OsFinishCode gr 0 & cjProc eq 0 test OsFinishCode eq fcAbort ifso Ws("...aborted...") ifnot SysErr(nil, OsFinishCode) //Type it out! // Remove user's display quickly, because it is probably running in his // stack. The calls below will begin to clobber the stack! ShowDisplayStream(dsp, DSalone) //Make it the only display @lvCursorLink = true //Re-enable cursor. GetFixedInit() //No more free storage. SetKeyboardProc() //Turn off user procedure sysZone = InitializeZone(protectedSysZone, lProtectedSysZone) BFSWriteDiskDescriptor(sysDisk) //Write bit table if changed. @lvAbortFlag = 0 //Enable SWAT aborts if cjProc then //User called CounterJunta() [ juntaTable>>JT.jReason = 0 cjProc() //Call him finish //If he should return! ] // Now decide what to run if anything. let runsys = 0 let ev = EventVector [ let len = ev>>EVM.length if len eq 0 then break //No events to process let md = ev + size EVM/16 let type = ev>>EVM.type if type eq eventCallSubsys then [ test len ne 1 ifso runsys = OpenFile(md, ksTypeReadOnly) ifnot //invoking HiddenFtp.run [ runsys = OpenFile("Sys.Boot", ksTypeReadOnly, 0, 0, fpSysBoot) PositionPage(runsys, 3) ] MoveBlock(ev, ev+len, EventVector+(EventVector!-1)-ev-len) break ] if type eq eventInLd then InLd(md, md) ev = ev+len ] repeat if runsys eq 0 then runsys = OpenFile("Executive.Run.", ksTypeReadOnly, 0, 0, fpExecutive) sysRoot = CallersFrame() //This will obliterate our frame... CallSubsys(runsys) ] //--------------------------------------------------------------------------- and CallSubsys(subsysX, swatX, doReturn, userParamsX; numargs na) be //--------------------------------------------------------------------------- [ DefaultArgs(lv na, 1, false, false, 0) swat = swatX; subsys = subsysX; userParams = userParamsX //Returning from a subsystem call is not yet implemented //if doReturn then [...] GotoLabel(sysRoot, SystemMain) ] //--------------------------------------------------------------------------- and SystemMain() be //--------------------------------------------------------------------------- // Control comes here to run a program subsys. // Pause and userParams are already set up. [ // Typically, userParams is allocated as a vector in the frame of // CallSubsys' caller. CallSubsys has just done a GotoLabel to here, // setting the stack back to sysRoot. So we are a bit exposed, since // that vector is below us, and liable to be clobbered by GetFrame // if we call anyone. Fortunately MoveBlock is an asm procedure which // doesn't get a frame, so copy that vector before calling any BCPL procs! let upVec = vec lUserParams MoveBlock(upVec, userParams, lUserParams) if userParams eq 0 then upVec!0 = 0 //No parameters really let args = vec lBLV ReadBlock(subsys, args, size SV.H/16) let startingAddress = args>>SV.H.startingAddress let nStaticLinks = args>>SV.H.nStaticLinks let npages = args>>SV.H.length ReadBlock(subsys, args, lBLV) //args vector is reused. // skip the first 16b words of the page 0 image ReadBlock(subsys, 16b, 16b) // and then load the rest of it ReadBlock(subsys, 16b, 300b-16b) let currentStack = MyFrame() CheckBounds(userBottom, args>>BLV.startOfStatics, args>>BLV.endOfStatics, currentStack, ecStaticLocation) CheckBounds(userBottom, args>>BLV.startOfCode, args>>BLV.afterLastCodeWord+nStaticLinks, currentStack, ecCodeLocation) ReadBlock(subsys, args>>BLV.startOfStatics, args>>BLV.endOfStatics-args>>BLV.startOfStatics+1) //read in statics let len = args>>BLV.afterLastCodeWord+nStaticLinks-args>>BLV.startOfCode if ReadBlock(subsys, args>>BLV.startOfCode, len) ne len then SysErr(nil, ecBLV) //BLV disagrees with file unless Endofs(subsys) do PositionPage(subsys, npages+1) let cfa = vec lCFA; GetCompleteFa(subsys, cfa) Closes(subsys) SetEndCode(args>>BLV.endCode) SetBlock(0, 77400b, 10b) SetBlock(614b, 52525b, 621b-614b+1) //To help detect parity errors // Now fix up static links. // EnumerateFp is used as the relocation base for the top static region. // CallSubsys is used as the relocation base for the main static region. let p = args>>BLV.afterLastCodeWord-1 for i = 1 to nStaticLinks do [ // 'staticAddr' is the address of a user static needing initialization. // Bldr sets them to contain an index into one of the two system // static regions. High static indicies have the sign bit set. // 'index' is the address of the corresponding system static. let staticAddr = p!i //Left by loader let index = @staticAddr //ID in Sys.Bk file test index ls 0 // look for sign bit ifso index = (index-100000b) + lv EnumerateFp //in top statics ifnot index = index + lv CallSubsys //in main statics @staticAddr = @index //copy system's static value into user's static ] if swat then CallSwat("pause to swat") startingAddress(args, upVec, cfa) //call the subsystem // subsystem returns control here finish ] //--------------------------------------------------------------------------- and CheckBounds(l, i1, i2, u, ecNo) be //--------------------------------------------------------------------------- unless Usc(l, i1) le 0 & Usc(i1, i2) le 0 & Usc(i2, u) le 0 do SysErr(l, ecNo, i1, i2, u) //--------------------------------------------------------------------------- and Junta(levnam, proc) be //--------------------------------------------------------------------------- [ structure DL [ bl1 word 5; version word 1; bl2 word 2 ] if (lv juntaTable>>JT.BootLabel)>>DL.version eq 0 then SysErr(nil, ecNotInstalled) if juntaTable>>JT.jAtLevel ne 0 then SysErr(levnam, ecAlreadyJuntaed) //Stuff here for cleaning out system free storage area Closes(dsp) //Close the system display // In the following table, put cleanup code ABOVE the level name. This // is because the argument to Junta is the last level to KEEP. Thus, // if BFSwrite is kept, it is not necessary to write the bit table; // but if only BFSbase is to be kept, the bit table must be written. switchon levnam into [ case levBasic: case levBuffer: case levFilePointers: case levBcpl: case levStatics: SysErr = CallSwat case levBFSbase: sysDisk = BFSClose(sysDisk) case levBFSwrite: case levAlloc: case levStreams: case levScan: case levDirectory: @displayInterrupt = @displayInterrupt & not kbInterruptBit @activeInterrupts = @activeInterrupts & not kbInterruptBit case levKeyboard: case levDisplay: case levMain: endcase default: SysErr(levnam, ecIllegalJuntaLevelName) ] sysZone = 0 // Will cause a Swat break at 0 or 1 if used now. let p = lv juntaTable>>JT.jTable for i = 1 to juntaTable>>JT.jLevels do [ if p!0 eq levnam then break p = p+2 ] juntaTable>>JT.jAtLevel = p // remember how far back we went let stack = p!1-4 //New stack root @stack = stack //Link to itself GotoLabel(stack, proc) ]