-- UtilityStore>UtilitySpaceImpl.mesa (October 26, 1982 10:09 am by Levin) -- This version of SpaceImpl is for UtilityPilot. It simulates the operation of the Virtual Memory Manager only for simple file spaces and for data spaces resident in memory. Minimal checking of arguments is done. At present, some operations are unimplemented. If a client of UtilityPilot has some strong reason for needing them, they may be implemented in the future. -- This module is an edited version of SpaceImpl{A|B}.mesa. Changes to this module should track changes to them. DIRECTORY CachedRegion USING [Apply, Desc, kill, Operation, Outcome, writeProtect], CachedSpace USING [DataOrFile, Desc, Get, Handle, handleNull, handleVM, Level, Update], Environment USING [Long, maxPagesInMDS, PageCount], File USING [GetAttributes, GetSize, PageCount, write], Inline USING [BITAND, LowHalf], PageFault USING [ReportAddressFault], Process USING [SetPriority], ProcessPriorities USING [priorityPageFaultHigh], SimpleSpace USING [Create, defaultCount, ForceOut, Map, Unmap], Space USING [defaultBase, defaultWindow, ErrorType, Handle, PageCount, PageNumber, PageOffset, WindowOrigin, wordsPerPage], SpecialSpace USING [], StoragePrograms USING [HandleFromPage], SwapperException USING [Await], SystemInternal USING [Unimplemented], Transaction USING [Handle], Utilities USING [LongPointerFromPage], VM USING [Interval, PageCount], VMMPrograms USING [], WriteFault USING [AwaitWriteFault, ReportWriteProtectFault]; UtilitySpaceImpl: PROGRAM IMPORTS CachedRegion, CachedSpace, File, Inline, PageFault, Process, SimpleSpace, StoragePrograms, SwapperException, SystemInternal, Transaction, Utilities, WriteFault EXPORTS SpecialSpace, Space, VMMPrograms SHARES File -- to extract permissions -- = BEGIN OPEN Space; Interval: TYPE = VM.Interval; Level: TYPE = CachedSpace.Level; SpaceD: TYPE = CachedSpace.Desc; RegionD: TYPE = CachedRegion.Desc; --~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -- Space data: --~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -- Public Constants Error: PUBLIC ERROR [type: ErrorType] = CODE; InsufficientSpace: PUBLIC ERROR [available: PageCount] = CODE; Handle: PUBLIC TYPE = CachedSpace.Handle; mds: PUBLIC Handle; nullHandle: PUBLIC Handle _ CachedSpace.handleNull; virtualMemory: PUBLIC Handle _ CachedSpace.handleVM; -- Private data: intervalMDS: Interval; maxPagesInCodeBlock: PageCount = Environment.maxPagesInMDS; codeBdyMask: WORD = LOOPHOLE[-(maxPagesInCodeBlock-1)-1, WORD]; -- = BITNOT[maxPagesInCodeBlock-1] Bug: ERROR [type: BugType] = CODE; -- not to be caught by client; BugType: TYPE = {funnyExceptionErrorOperation, funnyExceptionOutcome}; --~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -- Initialization: --~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ --VMMPrograms.--InitializeSpace: PUBLIC PROCEDURE [countVM: VM.PageCount, handleMDS: CachedSpace.Handle] = BEGIN throwAway: PROCESS; -- countVM not used in UtilitySpaceImpl (or we would have a name collision!) mds _ handleMDS; intervalMDS _ [handleMDS.page, Environment.maxPagesInMDS]; -- done differently than in SpaceImpl. -- Since the following processes run forever, there's no profit in Detaching them: Process.SetPriority[ProcessPriorities.priorityPageFaultHigh]; throwAway _ FORK VMHelperProcess[]; throwAway _ FORK WriteFaultProcess[]; END; --~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -- SpecialSpace implementation: --~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ --Currently this is only used by UserTerminal; it is a candidate for flushing CreateForCode: PUBLIC PROCEDURE [size: PageCount, parent: Handle, base: PageOffset] RETURNS [Handle] = -- Try it. If fails, possibly pad, then try again. BEGIN m: PageCount = Environment.maxPagesInMDS; h: Handle _ CreateInternal[size, parent, base]; p: PageNumber _ VMPageNumber[h]; IF size NOT IN (0..m] THEN ERROR Error[invalidParameters]; IF p/m = (p+size-1)/m THEN RETURN[h]; p _ (p+size) MOD m; -- next page to allocate in seg IF (p+size)>m THEN [] _ CreateInternal[m-p, parent, base]; RETURN[CreateInternal[size, parent, base]]; END; MakeResident, MakeSwappable: PUBLIC PROCEDURE [space: Handle] = { -- all code and data is always resident under UtiliyPilot --}; MakeCodeResident, MakeCodeSwappable: PUBLIC PROCEDURE [frame: PROGRAM] = { -- all code and data is always resident under UtiliyPilot -- }; --~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -- Space implementation: --~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Activate, Deactivate: PUBLIC SAFE PROCEDURE [space: Handle] = TRUSTED { }; DeleteSwapUnits: PUBLIC PROCEDURE [space: Handle] = { }; CopyIn, CopyOut: PUBLIC PROCEDURE [space: Handle, window: WindowOrigin, transaction: Transaction.Handle] = { SIGNAL SystemInternal.Unimplemented }; Create: PUBLIC PROCEDURE [size: PageCount, parent: Handle, base: PageOffset] RETURNS [Handle] = { RETURN[CreateInternal[size: size, parent: parent, base: base]] }; CreateInternal: PROCEDURE [size: PageCount, parent: Handle, base: PageOffset] RETURNS [Handle] = -- parent must be virtualMemory or mds (no nested spaces allowed). -- base must be defaultBase. { IF size=0 OR base~=defaultBase OR ~(parent=CachedSpace.handleVM OR parent=mds) THEN ERROR Error[invalidParameters]; RETURN[SimpleSpace.Create[size, IF parent=CachedSpace.handleVM THEN hyperspace ELSE --parent=mds-- mds]] }; -- This is not a perfect simulation since GetAttributes will return wrong data. CreateUniformSwapUnits: PUBLIC PROCEDURE [size: PageCount, parent: Handle] ={ }; Delete: PUBLIC PROCEDURE [space: Handle] = -- recovers real memory. (can't actually delete simpleSpaces.) BEGIN spaceD: SpaceD; CachedSpace.Get[@spaceD, space]; IF spaceD.state=mapped THEN { spaceD.dPinned _ TRUE; -- (Spaces created by StartPilot may not look like SimpleSpaces.) [] _ CachedSpace.Update[@spaceD]; SimpleSpace.Unmap[space] }; END; ForceOut: PUBLIC PROCEDURE [space: Handle] = { SimpleSpace.ForceOut[space] }; GetAttributes: PUBLIC SAFE PROCEDURE [space: Handle] RETURNS [parent, lowestChild, nextSibling: Handle, base: PageOffset, size: PageCount, mapped: BOOLEAN] = TRUSTED { SIGNAL SystemInternal.Unimplemented; }; GetHandle: PUBLIC SAFE PROCEDURE [page: PageNumber] RETURNS [Handle] = TRUSTED { RETURN[StoragePrograms.HandleFromPage[page]] }; GetWindow: PUBLIC SAFE PROCEDURE [space: Handle] RETURNS [WindowOrigin] = TRUSTED BEGIN spaceD: SpaceD; CachedSpace.Get[@spaceD, space]; IF spaceD.state~=mapped THEN ERROR Error[noWindow]; RETURN[IF spaceD.dataOrFile=file THEN spaceD.window ELSE defaultWindow]; END; Kill: PUBLIC PROCEDURE [space: Handle] = { [] _ CachedRegion.Apply[space.page, CachedRegion.kill] }; LongPointer: PUBLIC SAFE PROCEDURE [space: Handle] RETURNS [LONG POINTER] = TRUSTED { RETURN[Utilities.LongPointerFromPage[space.page]] }; LongPointerFromPage: PUBLIC SAFE PROCEDURE [page: PageNumber] RETURNS [LONG POINTER] = TRUSTED { RETURN[Utilities.LongPointerFromPage[page]]; }; MakeReadOnly: PUBLIC PROCEDURE [space: Handle, transaction: Transaction.Handle] = BEGIN spaceD: SpaceD; CachedSpace.Get[@spaceD, space]; spaceD.writeProtected _ TRUE; [] _ CachedSpace.Update[@spaceD]; [] _ CachedRegion.Apply[space.page, CachedRegion.writeProtect]; END; Map: PUBLIC PROCEDURE [space: Handle, window: WindowOrigin, transaction: Transaction.Handle] = BEGIN countMapped: Space.PageCount; spaceD: SpaceD; CachedSpace.Get[@spaceD, space]; IF window.file=defaultWindow.file THEN { countMapped _ spaceD.interval.count } --data space-- ELSE --file space-- { -- The following File.GetSize may raise File.Unknown or Volume.Unknown. Since we are not in a monitor, we just let the signal propagate. countFile: File.PageCount = MAX[File.GetSize[window.file], window.base]-window.base; countMapped _ IF spaceD.interval.count<=countFile THEN spaceD.interval.count ELSE Inline.LowHalf[countFile] }; -- no danger of truncation SimpleSpace.Map[space, window, --andPin:-- TRUE , countMapped ]; IF window.file~=defaultWindow.file AND (File.GetAttributes[window.file].immutable OR Inline.BITAND[window.file.permissions, File.write]=0) THEN { CachedSpace.Get[@spaceD, space]; spaceD.writeProtected _ TRUE; [] _ CachedSpace.Update[@spaceD] }; END; PageFromLongPointer: PUBLIC SAFE PROCEDURE [lp: LONG POINTER] RETURNS [page: PageNumber] = TRUSTED { OPEN LOOPHOLE[lp, num Environment.Long]; IF lp=NIL THEN ERROR Error[invalidParameters] ELSE RETURN[highbits*256+lowbits/256] }; Pointer: PUBLIC SAFE PROCEDURE [space: Handle] RETURNS [POINTER] = TRUSTED BEGIN spaceD: SpaceD; CachedSpace.Get[@spaceD, space]; IF spaceD.state=missing THEN ERROR Error[invalidHandle]; IF space.level<=mds.level OR ~(space.page IN [intervalMDS.page..intervalMDS.page+intervalMDS.count)) THEN ERROR Error[invalidParameters]; RETURN[LOOPHOLE[(space.page-intervalMDS.page)*wordsPerPage]]; END; Remap: PUBLIC PROCEDURE [space: Handle, window: WindowOrigin, transaction: Transaction.Handle] = { SIGNAL SystemInternal.Unimplemented }; Unmap: PUBLIC PROCEDURE [space: Handle] = { SimpleSpace.Unmap[space] }; VMPageNumber: PUBLIC SAFE PROCEDURE [space: Handle] RETURNS [PageNumber] = TRUSTED { RETURN[space.page] }; -- Other VMHelperProcess: PROCEDURE [] = BEGIN DO page: PageNumber; operation: CachedRegion.Operation; outcome: CachedRegion.Outcome; [page, operation, outcome] _ SwapperException.Await[]; WITH outcome SELECT FROM error --[state]-- => IF operation.action=activate THEN PageFault.ReportAddressFault[page] ELSE ERROR Bug[funnyExceptionErrorOperation]; ENDCASE --ok, regionDDirty, regionDMissing, spaceDMissing-- => ERROR Bug[funnyExceptionOutcome]; ENDLOOP; END; WriteFaultProcess: PROCEDURE = BEGIN DO page: PageNumber _ WriteFault.AwaitWriteFault[]; WriteFault.ReportWriteProtectFault[page]; ENDLOOP; END; END. LOG September 12, 1979 10:36 AM Knutsen Created file from SpaceImpl of August 30, 1979. Added InitSpace. October 22, 1979 10:41 AM Knutsen Changed Forgot to SystemInternal. January 28, 1980 11:48 AM Forrest Copied LongPtr<=>Page code in from SpaceImpl; added export of StoragePrograms; Merged in InitVMMgr from UtilityVMMControl (now dead) March 10, 1980 5:05 PM Forrest Made CreateUniformSwapUnits be a no-op April 17, 1980 1:32 PM Knutsen Added InitializeSpace. Changes for non-zero MDS. Add transaction Handle. Implement Delete. April 23, 1980 10:29 AM Knutsen Made Delete be a no-op. April 28, 1980 11:59 AM Forrest/Knutsen FrameOps=>Frame, ControlDefs=>PrincOps, TrapOps=>Trap. Implement Delete. Add updating of Cache in Delete. June 27, 1980 10:31 AM McJones Added transaction handle to MakeReadOnly, Remap; remove interrupt disable in trap handler September 18, 1980 10:28 AM Luniewski Added CopyIn and CopyOut as "SystemInternal.Unimplemented" procedures. January 13, 1981 3:09 PM Knutsen Made Map also pin. January 28, 1981 4:12 PM Knutsen Set process priorities. February 4, 1981 11:35 AM Knutsen Remove LOOPHOLEs used to access fault parameter. August 3, 1982 4:37 pm Levin Correct all occurrences of ~IN. August 26, 1982 3:34 pm Levin Make things SAFE. September 15, 1982 6:32 pm Levin Rework fault handling. October 26, 1982 10:09 am Levin Eliminate forking in fault handlers.