<> <> <> <> <> <> DIRECTORY BasicTime USING [ToPupTime], BcdDefs USING [Base, BcdBase, FPHandle, MTHandle, SPHandle], BootFile USING [Location], BootStartList USING [BackingLocation, Entry, Header, Index, nullSpaceIndex, nullSwapUnitIndex, SpaceIndex, SpaceType, startIndex, SwapUnitIndex, SwapUnitInfo, SwapUnitState, Base, versionID], MB USING [BHandle, BIndex, BitArray, BitArrayObject, DumpSegs, EnumerateBCDs, EnumerateCode, EnumerateFramePacks, EnumerateGlobalFrames, EnumerateSpaces, Handle, nullIndex, PreScanSegsForOutput, VirtualGlobalFrame], MBVM USING [AllocMDSData, Base, CodeSeg, DataSeg, FileSeg, LongCopyWrite, MDS, Pages, PointerFromSeg, Seg, Segs, SortSegs], PrincOps USING [GlobalFrameHandle, NullControl], PrincOpsUtils USING [AddressForPageNumber, LongCopy, LongZero, PagesForWords, WordsForPages], VM USING [AddressForPageNumber, Allocate, Free, Interval, nullInterval]; MBScript: CEDAR PROGRAM IMPORTS BasicTime, MB, MBVM, PrincOpsUtils, VM EXPORTS MB = BEGIN OPEN BootStartList; PageState: TYPE = RECORD [busy, resident, in, readOnly, mds, first64K: BOOL]; data: MB.Handle _ NIL; segs: MBVM.Segs _ NIL; residentTable, resDescTable, inTable, readOnlyTable: MB.BitArray _ NIL; suIndex: SwapUnitIndex; <> scriptIndex: Index; scriptBase: Base; scriptBuffer: VM.Interval; InitScript: PUBLIC PROC [h: MB.Handle] = { nullLocation: BootFile.Location = [ deviceType: null, deviceOrdinal: 0, vp: any[a: 0, b: 0, c: 0, d: 0, e: 0, f: 0, g: 0, h: 0]]; data _ h; data.header _ NEW[Header _ [ version: versionID, release: [0, 0, 0], buildDate: 0, requiredUCode: [0, 0, 0, 0], controlList: PrincOps.NullControl, initLoadState: nullSwapUnitIndex, mdsBase: 0, pdaPages: 0, stateVectorCounts: ALL[0], stateVectorSize: 0, nProcesses: 0, lastVMPage: 0, lastBootLoadedPage: 0, switches: [0,0,0,0], locDebuggerMicrocode: nullLocation, locDebuggerGerm: nullLocation, locDebugger: nullLocation, locDebuggee: nullLocation ]]; scriptIndex _ startIndex; scriptBase _ NIL; scriptBuffer _ VM.nullInterval; segs _ NIL; }; FinishScript: PUBLIC PROC = { residentTable _ resDescTable _ inTable _ readOnlyTable _ NIL; data.header _ NIL; IF scriptBase ~= NIL THEN { TRUSTED {VM.Free[scriptBuffer]}; scriptBase _ NIL; scriptBuffer _ VM.nullInterval; }; segs _ NIL; data _ NIL; }; InitBitTables: PROC [length: CARDINAL] = { residentTable _ NEW[MB.BitArrayObject[length]]; FOR i: CARDINAL IN [0..length) DO residentTable[i] _ FALSE; ENDLOOP; resDescTable _ NEW[MB.BitArrayObject[length]]; FOR i: CARDINAL IN [0..length) DO resDescTable[i] _ FALSE; ENDLOOP; inTable _ NEW[MB.BitArrayObject[length]]; FOR i: CARDINAL IN [0..length) DO inTable[i] _ FALSE; ENDLOOP; readOnlyTable _ NEW[MB.BitArrayObject[length]]; FOR i: CARDINAL IN [0..length) DO readOnlyTable[i] _ FALSE; ENDLOOP; }; MakeScript: PUBLIC PROC = { header: REF Header = data.header; r: stop Entry _ Entry[stop[]]; nSpaces: CARDINAL _ 0; state: PageState _ [FALSE, FALSE, FALSE, FALSE, FALSE, FALSE]; inMDS, inFirst64K: BOOL; mdsBase: CARDINAL = data.mdsBase; newState: PageState; i, nwords, start: CARDINAL; scriptSeg: MBVM.DataSeg; segs _ MBVM.SortSegs[]; InitBitTables[data.vmMap.length]; <> FOR i IN [0..segs.length) DO AddToBitTables[segs[i]] ENDLOOP; ClassifyPages[]; FOR i IN [0..data.lastVMPage] DO inMDS _ (i IN [mdsBase..mdsBase+255]); inFirst64K _ (i IN [0..255]); newState _ [ busy: data.vmMap[i], resident: residentTable[i], in: inTable[i], readOnly: readOnlyTable[i], mds: inMDS, first64K: inFirst64K ]; IF newState ~= state THEN {state _ newState; nSpaces _ nSpaces + 1}; ENDLOOP; nwords _ 0; FOR i IN [0..segs.length) DO WITH segs[i] SELECT FROM seg: MBVM.DataSeg => nwords _ nwords + SIZE[swapUnit Entry]; seg: MBVM.CodeSeg => TRUSTED { nwords _ nwords + (IF seg.sph ~= NIL THEN seg.sph.length*SIZE[swapUnit Entry] ELSE SIZE[swapUnit Entry]); }; seg: MBVM.FileSeg => IF seg.bIndex = MB.nullIndex THEN nwords _ nwords + SIZE[swapUnit Entry] ELSE { loadee: MB.BHandle = data.inputBCDs.bcds[seg.bIndex]; TRUSTED { IF loadee.bcd.rtPages.pages ~= 0 THEN nwords _ nwords + 2*SIZE[swapUnit Entry] ELSE nwords _ nwords + SIZE[swapUnit Entry]; }; }; ENDCASE; ENDLOOP; nwords _ (nwords + SIZE[Header] + 16 --?? RL-- + nSpaces*SIZE[space Entry]); AddScriptWords[nwords]; <> <> scriptSeg _ MBVM.AllocMDSData[base: MBVM.MDS, pages: scriptBuffer.count]; scriptSeg.bootLoaded _ TRUE; scriptSeg.info _ [readOnly: FALSE, state: swappable]; AddToBitTables[scriptSeg]; TRUSTED { data.scriptBaseInVM _ PrincOpsUtils.AddressForPageNumber[data.mdsBase] + LOOPHOLE[MBVM.PointerFromSeg[scriptSeg], CARDINAL]; }; segs _ MBVM.SortSegs[]; FOR i IN [0..segs.length) DO EnterSegment[segs[i]] ENDLOOP; IF data.debug THEN MB.DumpSegs[segs, "SCRIPT CONSTRUCTION"]; state _ [ busy: data.vmMap[0], resident: residentTable[0], in: inTable[0], readOnly: readOnlyTable[0], mds: mdsBase = 0, first64K: TRUE ]; start _ 0; suIndex _ LOOPHOLE[startIndex]; FOR i IN [1..data.lastVMPage] DO inMDS _ i IN [mdsBase..mdsBase+255]; inFirst64K _ i IN [0..255]; newState _ [ busy: data.vmMap[i], resident: residentTable[i], in: inTable[i], readOnly: readOnlyTable[i], mds: inMDS, first64K: inFirst64K ]; IF newState ~= state THEN {AddSpace[state, start, i-1]; start _ i; state _ newState}; ENDLOOP; AddSpace[state, start, data.lastVMPage]; TRUSTED {AppendBootWords[@r, SIZE[stop Entry]]}; header.buildDate _ BasicTime.ToPupTime[data.buildTime]; header.lastBootLoadedPage _ MB.PreScanSegsForOutput[segs]; header.mdsBase _ data.mdsBase; header.pdaPages _ data.pdaPages; header.initLoadState _ data.lsseg.index; header.lastVMPage _ data.lastVMPage; header.stateVectorCounts _ data.stateVectorCounts; header.stateVectorSize _ data.svSize; header.nProcesses _ data.nProcesses; TRUSTED { scriptBase^ _ header^; MBVM.LongCopyWrite[ from: scriptBase, to: data.scriptBaseInVM, nwords: PrincOpsUtils.WordsForPages[scriptBuffer.count]]; }; segs _ NIL; }; AddToBitTables: PROC [seg: MBVM.Seg] = { resDesc: BOOL = (seg.info.state = residentDescriptor); resident: BOOL = (seg.info.state = resident); FOR i: CARDINAL IN [seg.base..seg.base+seg.pages) DO readOnlyTable[i] _ seg.info.readOnly; inTable[i] _ seg.bootLoaded; resDescTable[i] _ resDesc; residentTable[i] _ resident; ENDLOOP; }; ClassifyPages: PROC = { MB.EnumerateCode[in, BootLoadCode]; MB.EnumerateSpaces[in, BootLoadSpaces]; MB.EnumerateFramePacks[in, BootLoadFramePacks]; MB.EnumerateGlobalFrames[in, BootLoadGlobalFrames]; MB.EnumerateBCDs[in, BootLoadBCDs]; MB.EnumerateCode[resDesc, ResDescCode]; MB.EnumerateSpaces[resDesc, ResDescSpaces]; MB.EnumerateFramePacks[resDesc, ResDescFramePacks]; MB.EnumerateGlobalFrames[resDesc, ResDescGlobalFrames]; MB.EnumerateBCDs[resDesc, ResDescBCDs]; MB.EnumerateCode[resident, ResidentCode]; MB.EnumerateSpaces[resident, ResidentSpaces]; -- resident FramePacks and GlobalFrames were done during loading-- MB.EnumerateBCDs[resident, ResidentBCDs]; }; BootLoadCode: PROC [bh: MB.BHandle, mth: BcdDefs.MTHandle] RETURNS [BOOL] = TRUSTED { cseg: MBVM.CodeSeg = bh.mt[mth.gfi].code; MarkSegPages[cseg, inTable]; RETURN[FALSE] }; BootLoadSpaces: PROC [bh: MB.BHandle, sph: BcdDefs.SPHandle, index: CARDINAL] RETURNS [BOOL] = { MarkSpacePages[sph, index, inTable]; RETURN[FALSE] }; BootLoadFramePacks: PROC [bh: MB.BHandle, fph: BcdDefs.FPHandle] RETURNS [BOOL] = TRUSTED { mtb: BcdDefs.Base = LOOPHOLE[bh.bcd + bh.bcd.mtOffset]; RETURN[BootLoadGlobalFrames[bh, @mtb[fph.modules[0]]]] }; BootLoadGlobalFrames: PROC [bh: MB.BHandle, mth: BcdDefs.MTHandle] RETURNS [BOOL] = TRUSTED { frame: PrincOps.GlobalFrameHandle = bh.mt[mth.gfi].frame; IF ~MB.VirtualGlobalFrame[frame].alloced THEN MarkSegPages[SegForBase[PageFromAddress[frame] + data.mdsBase], inTable]; RETURN[FALSE] }; BootLoadBCDs: PROC [bh: MB.BHandle] RETURNS [BOOL] = { bcdSeg: MBVM.FileSeg = bh.bcdSeg; MarkSegPages[bcdSeg, inTable]; RETURN[FALSE] }; ResDescCode: PROC [bh: MB.BHandle, mth: BcdDefs.MTHandle] RETURNS [BOOL] = TRUSTED { cseg: MBVM.CodeSeg = bh.mt[mth.gfi].code; cseg.info.state _ residentDescriptor; MarkSegPages[cseg, resDescTable]; RETURN[FALSE] }; ResDescSpaces: PROC [bh: MB.BHandle, sph: BcdDefs.SPHandle, index: CARDINAL] RETURNS [BOOL] = TRUSTED { MarkSpacePages[sph, index, resDescTable]; RETURN[FALSE] }; ResDescFramePacks: PROC [bh: MB.BHandle, fph: BcdDefs.FPHandle] RETURNS [BOOL] = TRUSTED { mtb: BcdDefs.Base = LOOPHOLE[bh.bcd + bh.bcd.mtOffset]; RETURN[ResDescGlobalFrames[bh, @mtb[fph.modules[0]]]]}; ResDescGlobalFrames: PROC [bh: MB.BHandle, mth: BcdDefs.MTHandle] RETURNS [BOOL] = TRUSTED { frame: PrincOps.GlobalFrameHandle = bh.mt[mth.gfi].frame; IF ~MB.VirtualGlobalFrame[frame].alloced THEN MarkSegPages[SegForBase[PageFromAddress[frame] + data.mdsBase], resDescTable]; RETURN[FALSE] }; ResDescBCDs: PROC [bh: MB.BHandle] RETURNS [BOOL] = { bcdSeg: MBVM.FileSeg = bh.bcdSeg; bcdSeg.info.state _ residentDescriptor; MarkSegPages[bcdSeg, resDescTable]; RETURN[FALSE] }; ResidentCode: PROC [bh: MB.BHandle, mth: BcdDefs.MTHandle] RETURNS [BOOL] = TRUSTED { cseg: MBVM.CodeSeg = bh.mt[mth.gfi].code; cseg.info.state _ resident; MarkSegPages[cseg, residentTable]; MarkSegPages[cseg, inTable]; RETURN[FALSE] }; ResidentSpaces: PROC [bh: MB.BHandle, sph: BcdDefs.SPHandle, index: CARDINAL] RETURNS [BOOL] = TRUSTED { cseg: MBVM.CodeSeg = SegForSpace[sph]; first: CARDINAL = cseg.base+sph.spaces[index].offset; count: CARDINAL = sph.spaces[index].pages; MarkTablePages[residentTable, first, count]; MarkTablePages[inTable, first, count]; RETURN[FALSE] }; ResidentBCDs: PROC [bh: MB.BHandle] RETURNS [BOOL] = { bcdSeg: MBVM.FileSeg = bh.bcdSeg; bcdSeg.info.state _ resident; MarkSegPages[bcdSeg, residentTable]; MarkSegPages[bcdSeg, inTable]; RETURN[FALSE] }; MarkSegPages: PROC [seg: MBVM.Seg, table: MB.BitArray] = INLINE { MarkTablePages[table, seg.base, seg.pages]}; MarkSpacePages: PROC [ sph: BcdDefs.SPHandle, index: CARDINAL, table: MB.BitArray] = TRUSTED { cseg: MBVM.CodeSeg = SegForSpace[sph]; MarkTablePages[table, cseg.base + sph.spaces[index].offset, sph.spaces[index].pages] }; MarkTablePages: PROC [table: MB.BitArray, first, count: CARDINAL] = { FOR i: CARDINAL IN [first..first+count) DO table[i] _ TRUE; ENDLOOP; }; SegForBase: PROC [base: CARDINAL] RETURNS [seg: MBVM.Seg] = { FOR i: CARDINAL IN [0..segs.length) DO seg _ segs[i]; IF base IN [seg.base..seg.base+seg.pages) THEN EXIT; REPEAT FINISHED => ERROR; ENDLOOP; }; SegForSpace: PROC [sph: BcdDefs.SPHandle] RETURNS [cseg: MBVM.CodeSeg] = { FOR i: CARDINAL IN [0..segs.length) DO WITH segs[i] SELECT FROM s: MBVM.CodeSeg => IF s.sph = sph THEN {cseg _ s; EXIT}; ENDCASE; REPEAT FINISHED => ERROR; ENDLOOP; }; AddScriptWords: PROC [nwords: CARDINAL] = TRUSTED { newPages: CARDINAL = scriptBuffer.count + PrincOpsUtils.PagesForWords[nwords]; newBuffer: VM.Interval = VM.Allocate[newPages]; newBase: LONG POINTER = VM.AddressForPageNumber[newBuffer.page]; IF scriptBase = NIL THEN PrincOpsUtils.LongZero[ where: newBase, nwords: PrincOpsUtils.WordsForPages[newBuffer.count] ] ELSE { PrincOpsUtils.LongCopy[ from: scriptBase, to: newBase, nwords: PrincOpsUtils.WordsForPages[scriptBuffer.count]]; VM.Free[scriptBuffer]; PrincOpsUtils.LongZero[ where: newBase + PrincOpsUtils.WordsForPages[scriptBuffer.count], nwords: PrincOpsUtils.WordsForPages[newBuffer.count - scriptBuffer.count] ]; }; data.scriptBase _ scriptBase _ newBase; scriptBuffer _ newBuffer; }; EnterSegment: PROC [seg: MBVM.Seg] = TRUSTED { WITH s: seg SELECT FROM data => EnterSimpleSegment[seg]; code => IF s.sph = NIL THEN EnterSimpleSegment[seg] ELSE { r: swapUnit Entry; first: BOOL _ TRUE; s.bootLoaded _ FALSE; FOR i: CARDINAL IN [0..s.sph.length) DO base: CARDINAL = s.base+s.sph.spaces[i].offset; state: SwapUnitState = SELECT TRUE FROM residentTable[base] => resident, resDescTable[base] => residentDescriptor, ENDCASE => swappable; IF residentTable[base] OR inTable[base] THEN s.bootLoaded _ TRUE; r _ Entry[swapUnit[info: [s.info.readOnly, state], pages: s.sph.spaces[i].pages, base: s.sph.spaces[i].offset, parent: nullSpaceIndex] ]; IF first THEN {first _ FALSE; s.index _ LOOPHOLE[scriptIndex]}; AppendBootWords[@r, SIZE[swapUnit Entry]]; ENDLOOP; }; file => IF s.bIndex = MB.nullIndex THEN EnterSimpleSegment[seg] ELSE { bcd: BcdDefs.BcdBase = data.inputBCDs.bcds[s.bIndex].bcd; r: swapUnit Entry _ Entry[swapUnit[ info: GetSegmentInfo[seg], pages: seg.pages, base: 0, parent: nullSpaceIndex]]; seg.index _ LOOPHOLE[scriptIndex]; IF r.info.state = resident OR ~(bcd.extended AND bcd.rtPages.pages > 0) THEN AppendBootWords[@r, SIZE[swapUnit Entry]] ELSE { s.nUnits _ 2; r.pages _ bcd.nPages - bcd.rtPages.pages; AppendBootWords[@r, SIZE[swapUnit Entry]]; r.pages _ bcd.rtPages.pages; r.base _ bcd.rtPages.relPageBase; AppendBootWords[@r, SIZE[swapUnit Entry]]; }; }; ENDCASE; }; EnterSimpleSegment: PROC [seg: MBVM.Seg] = { r: swapUnit Entry _ Entry[swapUnit[ info: GetSegmentInfo[seg], pages: seg.pages, base: 0, parent: nullSpaceIndex]]; seg.index _ LOOPHOLE[scriptIndex]; TRUSTED {AppendBootWords[@r, SIZE[swapUnit Entry]]}; }; GetSegmentInfo: PROC [seg: MBVM.Seg] RETURNS [info: SwapUnitInfo] = { state: SwapUnitState = IF seg.info.state = resident THEN resident ELSE SELECT TRUE FROM residentTable[seg.base] => resident, resDescTable[seg.base] => residentDescriptor, ENDCASE => swappable; seg.bootLoaded _ residentTable[seg.base] OR inTable[seg.base]; RETURN[[seg.info.readOnly, state]] }; AppendBootWords: PROC [addr: POINTER, count: CARDINAL] = TRUSTED { IF LOOPHOLE[scriptIndex,CARDINAL]+count > PrincOpsUtils.WordsForPages[scriptBuffer.count] OR count = 0 THEN ERROR; PrincOpsUtils.LongCopy[from: addr, to: @scriptBase[scriptIndex], nwords: count]; scriptIndex _ scriptIndex + count; }; AddSpace: PROC [state: PageState, start, end: CARDINAL] = TRUSTED { r: space Entry; single: BOOL _ TRUE; resident: BOOL _ residentTable[start]; anyResDesc, anyReadOnly: BOOL _ FALSE; allResDesc, allReadOnly: BOOL _ TRUE; offset: CARDINAL; pages: CARDINAL = end-start+1; space: SpaceIndex _ LOOPHOLE[scriptIndex]; IF ~state.busy THEN {AddEmptySpace[start, pages]; RETURN}; r _ Entry[space[ readOnly: state.readOnly, bootLoaded: (state.resident OR state.in), type: , pages: pages, vmPage: start, backingPage: 0, backingStore: null] ]; AppendBootWords[@r, SIZE[space Entry]]; FOR i: CARDINAL IN [start..end] DO anyResDesc _ anyResDesc OR resDescTable[i]; allResDesc _ allResDesc AND resDescTable[i]; anyReadOnly _ anyReadOnly OR readOnlyTable[i]; allReadOnly _ allReadOnly AND readOnlyTable[i]; ENDLOOP; offset _ 0; DO scriptBase[suIndex].parent _ space; scriptBase[suIndex].base _ offset; offset _ scriptBase[suIndex].pages + offset; IF offset >= pages THEN EXIT; suIndex _ suIndex + SIZE[swapUnit Entry]; single _ FALSE; ENDLOOP; scriptBase[space].type _ IF ~single THEN [family[ <> anyResidentChildren: resident, anyResidentDescriptorChildren: anyResDesc, anySwappableChildren: ~resident, <> allResidentChildren: resident, allResidentDescriptorChildren: allResDesc, allSwappableChildren: ~resident]] ELSE [unitary[suIndex]]; suIndex _ suIndex + SIZE[swapUnit Entry]; }; AddEmptySpace: PROC [start, pages: CARDINAL] = TRUSTED { r: space Entry; space: SpaceIndex _ LOOPHOLE[scriptIndex]; r _ Entry[space[bootLoaded: FALSE, backingStore: null, type: [empty[]], readOnly: FALSE, pages: pages, vmPage: start, backingPage: 0] ]; AppendBootWords[@r, SIZE[space Entry]]; }; PageFromAddress: PROC [p: POINTER] RETURNS [CARDINAL] = { RETURN[LOOPHOLE[p, CARDINAL]/256]}; END.