<> <> <> <> <> <> DIRECTORY BootStartList USING [EntryPointer, Enumerate, h, IndexToEntryPointer, IndexToSpaceEntryPointer, Proc, SpaceEntryPointer], GermSwap USING [mdsiGerm], PrincOps USING [flagsVacant, PDA, shortPointerSpan], ProcessorFace USING [GetNextAvailableVM, firstSpecialRealPage, specialRealPages, useLongMapOps], VM USING [AddressForPageNumber, MakeReadOnly, PageNumberForAddress, Pin, PagesForWords], VMInternal USING [AddToFreeList, AllocCount, allocCounts, Crash, DataState, freePages, GetVMMap, InOut, Interval, IsVacant, lastRealPage, PageCount, PageNumber, PageStateFromFlags, partitions, RealPageNumber, rmMap, RMMapEntry, SetVMMap, VMMapEntry, VMPartition], VMSideDoor USING []; VMInitImpl: PROGRAM IMPORTS BootStartList, ProcessorFace, VM, VMInternal EXPORTS VMInternal, VMSideDoor SHARES VMInternal = BEGIN OPEN VMInternal; <<>> <> <<>> vmPages: PUBLIC PageCount; <> rmPages: PUBLIC INT; <> <<>> <> <<>> useLong: PUBLIC BOOL _ ProcessorFace.useLongMapOps; lastVMPage: PUBLIC PageNumber; InitializeTables: PUBLIC PROC = { rmTable: Interval; AllocateRMMap: PROC RETURNS [rmTable: Interval] = { AssignVMForRMTable: PROC RETURNS [Interval] = { pagesForRMMap: PageCount = VM.PagesForWords[(lastRealPage.LONG+1)*SIZE[RMMapEntry]]; page: PageNumber _ BootStartList.h.lastVMPage + 1; DO count: PageCount; [firstPage: page, count: count] _ ProcessorFace.GetNextAvailableVM[page]; SELECT count FROM 0 => Crash[]; < pagesForRMMap => page _ page + count; ENDCASE => EXIT; ENDLOOP; RETURN[[page, pagesForRMMap]] }; AssignRealMemoryToInterval: PROC [interval: Interval] = { endInterval: PageNumber = interval.page + interval.count - 1; nextUnmapped: PageNumber _ AdvanceToNextUnmapped[interval.page]; AdvanceToNextUnmapped: PROC [vmPage: PageNumber] RETURNS [PageNumber] = { UNTIL VMInternal.IsVacant[vmPage] DO vmPage _ vmPage.SUCC; ENDLOOP; RETURN[vmPage] }; RealMemoryStealable: PROC [vmPage: PageNumber] RETURNS [BOOL] = { IF VMInternal.IsVacant[vmPage] THEN RETURN [FALSE]; RETURN[ProcessorFace.GetNextAvailableVM[vmPage].firstPage = vmPage] }; SwapVMEntries: PROC [vm1, vm2: PageNumber] = { vmE1: VMMapEntry = GetVMMap[vm1]; vmE2: VMMapEntry = GetVMMap[vm2]; SetVMMap[vm1, vmE2]; SetVMMap[vm2, vmE1]; }; FindRealMemoryForInterval: BootStartList.Proc = { WITH e: BootStartList.IndexToEntryPointer[index] SELECT FROM space => { IF ~e.bootLoaded THEN FOR vmPage: PageNumber IN [e.vmPage..e.vmPage+e.pages) DO <> <> IF RealMemoryStealable[vmPage] THEN SwapVMEntries[vmPage, nextUnmapped]; IF (nextUnmapped _ AdvanceToNextUnmapped[nextUnmapped]) > endInterval THEN RETURN[TRUE]; ENDLOOP; }; swapUnit => NULL; ENDCASE => Crash[]; }; IF nextUnmapped <= endInterval THEN BootStartList.Enumerate[FindRealMemoryForInterval]; FOR vmPage: PageNumber IN [BootStartList.h.lastBootLoadedPage+1..vmPages) DO IF vmPage IN [interval.page..interval.page+interval.count) THEN LOOP; IF RealMemoryStealable[vmPage] THEN { SwapVMEntries[vmPage, nextUnmapped]; IF (nextUnmapped _ AdvanceToNextUnmapped[nextUnmapped]) > endInterval THEN EXIT; }; ENDLOOP; }; <> AssignRealMemoryToInterval[rmTable _ AssignVMForRMTable[]]; }; PartitionForPage: PROC [page: PageNumber] RETURNS [partition: VMPartition] = { FOR partition IN VMPartition DO interval: Interval = partitions[partition]; IF page IN [interval.page..interval.page+interval.count) THEN EXIT; ENDLOOP; }; ProcessSpaces: BootStartList.Proc = { OPEN BootStartList; entry: EntryPointer = IndexToEntryPointer[index]; WITH e: entry SELECT FROM space => { <> --*stats*-- partition: VMPartition = PartitionForPage[e.vmPage]; IF e.bootLoaded THEN { <> FOR vmPage: PageNumber IN [e.vmPage..e.vmPage+e.pages) DO vmEntry: VMMapEntry _ GetVMMap[vmPage]; WITH vmE: vmEntry SELECT InOut[vmEntry] FROM in => { <> rmMap[vmE.real] _ [ dataState: unchanged, needsBackingStoreWrite: TRUE, body: reclaimable[virtual: vmPage] ]; <> vmE.state.flags.referenced _ FALSE; <> vmE.state.flags.readonly _ FALSE; SetVMMap[vmPage, vmE]; }; out => Crash[]; ENDCASE; ENDLOOP; --*stats*-- allocCounts[partition].pagesAllocated _ allocCounts[partition].pagesAllocated + e.pages; } ELSE { <> EnsureUnmapped[ [e.vmPage, e.pages], IF e.type.class = empty THEN none ELSE undefined]; --*stats*-- IF e.type.class ~= empty THEN allocCounts[partition].pagesAllocated _ allocCounts[partition].pagesAllocated + e.pages; }; }; swapUnit => NULL; -- Pinning, where necessary, will be done later. ENDCASE => Crash[]; }; ProcessSwapUnits: BootStartList.Proc = { OPEN BootStartList; entry: EntryPointer = IndexToEntryPointer[index]; WITH e: entry SELECT FROM space => NULL; swapUnit => { parent: SpaceEntryPointer = IndexToSpaceEntryPointer[e.parent]; IF parent.bootLoaded THEN { <> interval: Interval = [parent.vmPage+e.base, e.pages]; IF e.info.state = resident THEN { VM.Pin[interval]}; IF e.info.readOnly THEN { VM.MakeReadOnly[interval]}; }; }; ENDCASE => {Crash[]}; }; ReserveSpecialVM: PROC [interval: Interval] = { <> FOR vmPage: PageNumber IN [interval.page..interval.page+interval.count) DO --*stats*-- partition: VMPartition = PartitionForPage[vmPage]; vmEntry: VMMapEntry _ GetVMMap[vmPage]; WITH vmE: vmEntry SELECT InOut[vmEntry] FROM in => <> IF vmE.real <= lastRealPage THEN rmMap[vmE.real] _ [ dataState: changed, needsBackingStoreWrite: TRUE, body: pinned[pinReason: permanentlyPinned, pinCount: 1] ]; out => { vmE.dataState _ none; vmE.checkedOut _ TRUE; SetVMMap[vmPage, vmEntry]; }; ENDCASE; --*stats*-- allocCounts[partition].pagesAllocated _ allocCounts[partition].pagesAllocated.SUCC; ENDLOOP; }; EnsureUnmapped: PROC [interval: Interval, dataState: DataState] = { AlreadyAllocated: PROC [real: RealPageNumber] RETURNS [inUse: BOOL] = INLINE { WITH rmE: rmMap[real] SELECT FROM free => Crash[]; reclaimable => RETURN[TRUE]; pinned => RETURN[rmE.pinReason ~= noSuchRealPage]; ENDCASE; }; FOR vmPage: PageNumber IN [interval.page..interval.page+interval.count) DO vmEntry: VMMapEntry _ GetVMMap[vmPage]; WITH vmE: vmEntry SELECT InOut[vmEntry] FROM in => IF AlreadyAllocated[vmE.real] THEN LOOP ELSE AddToFreeList[vmE.real]; out => NULL; ENDCASE; SetVMMap[vmPage, [state: VMInternal.PageStateFromFlags[PrincOps.flagsVacant], body: out[checkedOut: FALSE, readOnly: FALSE, dataState: dataState]]]; ENDLOOP; }; ReserveUnavailableVM: PROC [] = -- INLINE -- { vmPage: PageNumber _ ProcessorFace.GetNextAvailableVM[0].firstPage; ReserveSpecialVM[[0, vmPage]]; DO <> nextAvailable: PageNumber; count: PageCount _ ProcessorFace.GetNextAvailableVM[vmPage].count; [nextAvailable, count] _ ProcessorFace.GetNextAvailableVM[vmPage + count]; IF count = 0 THEN EXIT; ReserveSpecialVM[[vmPage + count, nextAvailable - (vmPage + count)]]; vmPage _ nextAvailable; ENDLOOP; }; <> firstSpecialReal: RealPageNumber = ProcessorFace.firstSpecialRealPage; countSpecialReal: PageCount = ProcessorFace.specialRealPages; lastRealPage _ RealPageNumber.FIRST; rmPages _ 0; vmPages _ 0; DO page: PageNumber; count: PageCount; [firstPage: page, count: count] _ ProcessorFace.GetNextAvailableVM[vmPages]; IF count = 0 THEN EXIT; vmPages _ page + count; lastVMPage _ vmPages.PRED; THROUGH [0..count) DO vmEntry: VMMapEntry = GetVMMap[page]; WITH vmE: vmEntry SELECT InOut[vmE] FROM in => {lastRealPage _ MAX[lastRealPage, vmE.real]; rmPages _ rmPages.SUCC}; out => NULL; ENDCASE; page _ page.SUCC; ENDLOOP; ENDLOOP; IF countSpecialReal > 0 THEN lastRealPage _ MAX[lastRealPage, RealPageNumber[firstSpecialReal+countSpecialReal-1]]; InitializePartitions[]; rmTable _ AllocateRMMap[]; rmMap _ VM.AddressForPageNumber[rmTable.page]; FOR realPage: RealPageNumber IN [RealPageNumber.FIRST..lastRealPage] DO rmMap[realPage].body _ pinned[pinReason: noSuchRealPage, pinCount: 1]; ENDLOOP; IF countSpecialReal > 0 THEN FOR realPage: RealPageNumber IN [firstSpecialReal..RealPageNumber[firstSpecialReal+countSpecialReal-1]] DO rmMap[realPage].body _ pinned[pinReason: specialRealPageAvailable, pinCount: 0]; ENDLOOP; BootStartList.Enumerate[ProcessSpaces]; BootStartList.Enumerate[ProcessSwapUnits]; <> <> ReserveSpecialVM[rmTable]; ReserveSpecialVM[ [GermSwap.mdsiGerm*PrincOps.shortPointerSpan, PrincOps.shortPointerSpan]]; ReserveSpecialVM[[VM.PageNumberForAddress[LONG[NIL]], 1]]; ReserveSpecialVM[[VM.PageNumberForAddress[LONG[LOOPHOLE[1, POINTER]]], 1]]; ReserveUnavailableVM[]; <> EnsureUnmapped[ [BootStartList.h.lastVMPage+1, vmPages - (BootStartList.h.lastVMPage+1)], none]; <> vmPages _ MIN[(rmTable.page + rmTable.count - 1) + freePages, 16000]; <> partitions[normalVM].count _ vmPages - partitions[normalVM].page; }; InitializePartitions: PROC = { lowCoreBase: PageNumber = 0; pdaBase: PageNumber = VM.PageNumberForAddress[PrincOps.PDA]; mdsBase: PageNumber = VM.PageNumberForAddress[LONG[LOOPHOLE[1, POINTER]]]; vmBase: PageNumber = mdsBase + PrincOps.shortPointerSpan; partitions _ [ --lowCore-- [lowCoreBase, PrincOps.shortPointerSpan], --pda-- [pdaBase, PrincOps.shortPointerSpan], --mds-- [mdsBase, PrincOps.shortPointerSpan], --normalVM-- [vmBase, vmPages - vmBase] ]; }; END.