<> <> <> <> DIRECTORY BcdDefs USING [Base], BcdOps USING [BcdBase, FPHandle, MTHandle, SPHandle], BootFile USING [MemorySizeToFileSize], Environment USING [bitsPerWord, wordsPerPage], Inline USING [LongCOPY], MB USING [ BHandle, BIndex, BitArray, DumpSegs, EnumerateBCDs, EnumerateCode, EnumerateFramePacks, EnumerateGlobalFrames, EnumerateSpaces, Handle, nullIndex, VirtualGlobalFrame, Zero], MBStorage USING [FreeMDSPages, FreePages, FreeWords, MDSPages, PagesForWords, Words], MBVM USING [ AllocMDSData, Base, CodeSeg, CopyWrite, DataSeg, FileSeg, MDS, Pages, PointerFromSeg, Seg, SortSegs], PrincOps USING [GlobalFrameHandle], StartList USING [ BackingLocation, Entry, Header, Index, NullSpaceIndex, NullSwapUnitIndex, SpaceIndex, SpaceType, StartIndex, SwapUnitIndex, SwapUnitInfo, SwapUnitState, Base, VersionID]; MBScript: PROGRAM IMPORTS BootFile, Inline, MB, MBStorage, MBVM EXPORTS MB = BEGIN OPEN StartList; PageSize: CARDINAL = Environment.wordsPerPage; PageState: TYPE = RECORD [busy, resident, in, readOnly, mds, first64K: BOOL]; data: MB.Handle _ NIL; segs: LONG DESCRIPTOR FOR ARRAY OF MBVM.Seg; residentTable, resDescTable, inTable, readOnlyTable: MB.BitArray _ NIL; suIndex: SwapUnitIndex; <> scriptIndex: Index; tablePages: CARDINAL; scriptBase: StartList.Base; header: LONG POINTER TO Header; InitScript: PUBLIC PROC [h: MB.Handle] = { data _ h; header _ data.zone.NEW[Header]; MB.Zero[header, SIZE[Header]]; data.header _ header; header.version _ VersionID; scriptIndex _ StartList.StartIndex; tablePages _ 0; scriptBase _ NIL; }; FinishScript: PUBLIC PROC = { OPEN MBStorage; IF residentTable ~= NIL THEN {FreeWords[BASE[residentTable]]; residentTable _ NIL}; IF resDescTable ~= NIL THEN {FreeWords[BASE[resDescTable]]; resDescTable _ NIL}; IF inTable ~= NIL THEN {FreeWords[BASE[inTable]]; inTable _ NIL}; IF readOnlyTable ~= NIL THEN {FreeWords[BASE[readOnlyTable]]; readOnlyTable _ NIL}; IF header ~= NIL THEN data.zone.FREE[@header]; IF scriptBase ~= NIL THEN {FreeMDSPages[scriptBase]; scriptBase _ NIL}; data _ NIL; }; InitBitTables: PROC [length: CARDINAL] = { OPEN MBStorage; wordsForTable: CARDINAL = (length+Environment.bitsPerWord-1)/Environment.bitsPerWord; residentTable _ DESCRIPTOR[Words[wordsForTable], length]; MB.Zero[BASE[residentTable], wordsForTable]; resDescTable _ DESCRIPTOR[Words[wordsForTable], length]; MB.Zero[BASE[resDescTable], wordsForTable]; inTable _ DESCRIPTOR[Words[wordsForTable], length]; MB.Zero[BASE[inTable], wordsForTable]; readOnlyTable _ DESCRIPTOR[Words[wordsForTable], length]; MB.Zero[BASE[readOnlyTable], wordsForTable]; }; MakeScript: PUBLIC PROC = { 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; tableSeg: MBVM.DataSeg; segs _ MBVM.SortSegs[]; InitBitTables[LENGTH[data.vmMap]]; <> FOR i IN [0..LENGTH[segs]) 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..LENGTH[segs]) DO WITH seg: segs[i] SELECT FROM data => nwords _ nwords + SIZE[swapUnit Entry]; code => nwords _ nwords + (IF seg.sph # NIL THEN seg.sph.length*SIZE[swapUnit Entry] ELSE SIZE[swapUnit Entry]); file => IF seg.bIndex = MB.nullIndex THEN nwords _ nwords + SIZE[swapUnit Entry] ELSE { loadee: MB.BHandle = data.inputBCDs.bcds[seg.bIndex]; 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 + nSpaces*SIZE[space Entry]); AddScriptWords[nwords]; <> <> tableSeg _ MBVM.AllocMDSData[base: MBVM.MDS, pages: tablePages]; -- this won't expand vmMap tableSeg.bootLoaded _ TRUE; tableSeg.info _ [readOnly: FALSE, state: swappable]; AddToBitTables[tableSeg]; header.table _ MBVM.PointerFromSeg[tableSeg]; MBStorage.FreePages[BASE[segs]]; segs _ MBVM.SortSegs[]; FOR i IN [0..LENGTH[segs]) DO EnterSegment[segs[i]] ENDLOOP; IF data.debug THEN MB.DumpSegs[segs, "SCRIPT CONSTRUCTION"L]; 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]; AppendBootWords[@r, SIZE[stop Entry]]; [lastBootedPage: header.lastBootLoadedPage, nBootPages: data.nBootPages, nFilePages: data.nFilePages] _ PreScanSegs[segs]; MBStorage.FreePages[BASE[segs]]; header.mdsBase _ data.mdsBase; header.pdaPages _ data.pdaPages; header.loadState _ NullSwapUnitIndex; header.initLoadState _ data.lsseg.index; header.lastVMPage _ data.lastVMPage; header.stateVectorCounts _ data.stateVectorCounts; header.stateVectorSize _ data.svSize; header.nProcesses _ data.nProcesses; scriptBase^ _ header^; MBVM.CopyWrite[from: scriptBase, to: header.table, nwords: PageSize*tablePages]; }; 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: BcdOps.MTHandle] RETURNS [BOOL] = { cseg: MBVM.CodeSeg = bh.mt[mth.gfi].code; MarkSegPages[cseg, @inTable]; RETURN[FALSE] }; BootLoadSpaces: PROC [bh: MB.BHandle, sph: BcdOps.SPHandle, index: CARDINAL] RETURNS [BOOL] = { MarkSpacePages[sph, index, @inTable]; RETURN[FALSE] }; BootLoadFramePacks: PROC [bh: MB.BHandle, fph: BcdOps.FPHandle] RETURNS [BOOL] = { mtb: BcdDefs.Base = LOOPHOLE[bh.bcd + bh.bcd.mtOffset]; RETURN[BootLoadGlobalFrames[bh, @mtb[fph.modules[0]]]] }; BootLoadGlobalFrames: PROC [bh: MB.BHandle, mth: BcdOps.MTHandle] RETURNS [BOOL] = { 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: BcdOps.MTHandle] RETURNS [BOOL] = { cseg: MBVM.CodeSeg = bh.mt[mth.gfi].code; cseg.info.state _ residentDescriptor; MarkSegPages[cseg, @resDescTable]; RETURN[FALSE] }; ResDescSpaces: PROC [bh: MB.BHandle, sph: BcdOps.SPHandle, index: CARDINAL] RETURNS [BOOL] = { MarkSpacePages[sph, index, @resDescTable]; RETURN[FALSE] }; ResDescFramePacks: PROC [bh: MB.BHandle, fph: BcdOps.FPHandle] RETURNS [BOOL] = { mtb: BcdDefs.Base = LOOPHOLE[bh.bcd + bh.bcd.mtOffset]; RETURN[ResDescGlobalFrames[bh, @mtb[fph.modules[0]]]]}; ResDescGlobalFrames: PROC [bh: MB.BHandle, mth: BcdOps.MTHandle] RETURNS [BOOL] = { 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: BcdOps.MTHandle] RETURNS [BOOL] = { 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: BcdOps.SPHandle, index: CARDINAL] RETURNS [BOOL] = { 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: POINTER TO MB.BitArray] = INLINE { MarkTablePages[table, seg.base, seg.pages]}; MarkSpacePages: PROC [ sph: BcdOps.SPHandle, index: CARDINAL, table: POINTER TO MB.BitArray] = { cseg: MBVM.CodeSeg = SegForSpace[sph]; MarkTablePages[table, cseg.base + sph.spaces[index].offset, sph.spaces[index].pages] }; MarkTablePages: PROC [table: POINTER TO 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..LENGTH[segs]) DO seg _ segs[i]; IF base IN [seg.base..seg.base+seg.pages) THEN EXIT; REPEAT FINISHED => ERROR; ENDLOOP; }; SegForSpace: PROC [sph: BcdOps.SPHandle] RETURNS [cseg: MBVM.CodeSeg] = { FOR i: CARDINAL IN [0..LENGTH[segs]) DO WITH s: segs[i] SELECT FROM code => IF s.sph = sph THEN {cseg _ @s; EXIT}; ENDCASE; REPEAT FINISHED => ERROR; ENDLOOP; }; AddScriptWords: PROC [nwords: CARDINAL] = { newPages: CARDINAL _ (tablePages + MBStorage.PagesForWords[nwords]); newbase: POINTER _ MBStorage.MDSPages[newPages]; IF scriptBase # NIL THEN { Inline.LongCOPY[from: scriptBase, to: newbase, nwords: tablePages*PageSize]; MBStorage.FreeMDSPages[scriptBase]; }; tablePages _ newPages; data.scriptBase _ scriptBase _ newbase; }; EnterSegment: PROC [seg: MBVM.Seg] = { 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: BcdOps.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.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]; 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] = { IF LOOPHOLE[scriptIndex,CARDINAL]+count > tablePages*PageSize OR count = 0 THEN ERROR; Inline.LongCOPY[from: addr, to: @scriptBase[scriptIndex], nwords: count]; scriptIndex _ scriptIndex + count; }; AddSpace: PROC [state: PageState, start, end: CARDINAL] = { 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), handle:, type:, pages: pages, vmpage: start, backingPage: 0, backingStore: (IF state.resident THEN null ELSE self)] ]; 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] = { r: space Entry; space: SpaceIndex _ LOOPHOLE[scriptIndex]; r _ Entry[space[bootLoaded: FALSE, backingStore: null, type: [empty[]], readOnly: FALSE, pages: pages, vmpage: start, handle:, backingPage: 0] ]; AppendBootWords[@r, SIZE[space Entry]]; }; PageFromAddress: PROC [p: POINTER] RETURNS [CARDINAL] = { RETURN[LOOPHOLE[p, CARDINAL]/256]}; PreScanSegs: PROC [ segs: LONG DESCRIPTOR FOR ARRAY OF MBVM.Seg] RETURNS [lastBootedPage, nBootPages, nFilePages: CARDINAL] = { i: CARDINAL; seg: MBVM.Seg; nBootPages _ 0; FOR i IN [0..LENGTH[segs]) DO seg _ segs[i]; IF ~seg.bootLoaded THEN LOOP; WITH s: seg SELECT FROM data => IF seg.base # 376B THEN { lastBootedPage _ s.base + s.pages - 1; nBootPages _ nBootPages + s.pages; }; code => [lastBootedPage, nBootPages] _ ScanBootedCodeSeg[@s, nBootPages]; file => { lastBootedPage _ s.base + s.pages - 1; nBootPages _ nBootPages + s.pages; }; ENDCASE; ENDLOOP; nFilePages _ BootFile.MemorySizeToFileSize[nBootPages]; FOR i IN [0..LENGTH[segs]) DO info: StartList.SwapUnitInfo; seg _ segs[i]; info _ scriptBase[seg.index].info; WITH s: seg SELECT FROM data => IF info.state # resident THEN { IF scriptBase[scriptBase[seg.index].parent].backingPage = 0 THEN scriptBase[scriptBase[seg.index].parent].backingPage _ nFilePages; nFilePages _ nFilePages + s.pages; }; code => nFilePages _ ScanCodeSeg[@s, nFilePages]; file => IF info.state # resident THEN { IF scriptBase[scriptBase[seg.index].parent].backingPage = 0 THEN scriptBase[scriptBase[seg.index].parent].backingPage _ nFilePages; nFilePages _ nFilePages + s.pages; }; ENDCASE; ENDLOOP; }; ScanBootedCodeSeg: PROC [seg: MBVM.CodeSeg, nBootPages: CARDINAL] RETURNS [lastPage, pages: CARDINAL] = { i, page: CARDINAL; nUnits: CARDINAL _ IF seg.sph = NIL THEN 1 ELSE seg.sph.length; index: SwapUnitIndex _ seg.index; page _ seg.base; pages _ 0; FOR i IN [0..nUnits) DO IF scriptBase[scriptBase[index].parent].bootLoaded THEN { lastPage _ page + scriptBase[index].pages - 1; pages _ pages + scriptBase[index].pages; }; page _ page + scriptBase[index].pages; index _ index + SIZE[swapUnit Entry]; ENDLOOP; RETURN[lastPage, nBootPages + pages] }; ScanCodeSeg: PROC [seg: MBVM.CodeSeg, nFilePages: CARDINAL] RETURNS [CARDINAL] = { nUnits: CARDINAL _ IF seg.sph = NIL THEN 1 ELSE seg.sph.length; index: SwapUnitIndex _ seg.index; su: POINTER TO swapUnit Entry; FOR i: CARDINAL IN [0..nUnits) DO su _ @scriptBase[index]; IF scriptBase[su.parent].backingPage = 0 THEN scriptBase[su.parent].backingPage _ nFilePages; IF su.info.state # resident THEN nFilePages _ nFilePages + su.pages; index _ index + SIZE[swapUnit Entry]; ENDLOOP; RETURN[nFilePages] }; END.