-- MMMemory.Mesa Edited by Sandman on February 13, 1980 3:00 PM -- Edited by Forrest on July 15, 1980 6:13 PM DIRECTORY AllocDefs USING [AllocInfo], AltoDefs USING [MaxVMPage, PageCount, PageNumber, PageSize], FrameOps USING [FlushLargeFrames], InlineDefs USING [BITAND], MMInit, ProcessDefs USING [DisableInterrupts, EnableInterrupts], SegmentDefs USING [ DataSegmentHandle, DefaultBase, NewDataSegment, PagePointer], SwapperOps, SystemDefs USING [PagesForWords]; MMMemory: PROGRAM IMPORTS FrameOps, InlineDefs, ProcessDefs, SegmentDefs, SystemDefs EXPORTS AllocDefs, MMInit, SegmentDefs, SwapperOps, SystemDefs SHARES SegmentDefs = BEGIN OPEN AltoDefs, SegmentDefs; Object: TYPE = MACHINE DEPENDENT RECORD [ base: [0..--MaxVMPage--256), pages: [0..--MaxVMPage--256)]; Handle: TYPE = POINTER TO Object; -- Data Segments DefaultBase: PageNumber = SegmentDefs.DefaultBase; MakeDataSegment: PUBLIC PROC [ base: PageNumber, pages: PageCount, info: AllocDefs.AllocInfo] RETURNS [seg: DataSegmentHandle] = BEGIN s: Handle; IF pages ~IN (0..MaxVMPage+1] THEN ERROR InvalidSegmentSize[pages]; s _ AllocateObject[]; base _ AllocVM[base, pages ! UNWIND => LiberateObject[s]]; s^ _ [base: base, pages: pages]; RETURN[LOOPHOLE[s]] END; BootDataSegment: PUBLIC PROC [base:PageNumber, pages:PageCount] RETURNS [seg:DataSegmentHandle] = BEGIN s: Handle; FOR i: PageNumber IN [base..base+pages) DO IF pageMap[i]#inuse THEN ERROR; ENDLOOP; s _ AllocateObject[]; s^ _ [base: base, pages: pages]; RETURN[LOOPHOLE[s]] END; DeleteDataSegment: PUBLIC PROC [seg:DataSegmentHandle] = BEGIN base: PageNumber; pages: PageCount; s: Handle _ LOOPHOLE[seg]; [base: base, pages: pages] _ s^; UpdateVM[base, pages, free]; LiberateObject[LOOPHOLE[seg]]; RETURN END; DataSegmentAddress: PUBLIC PROC [seg:DataSegmentHandle] RETURNS [POINTER] = { RETURN[InlineDefs.BITAND[LOOPHOLE[seg, Handle]^, 177400B]] }; -- Memory Allocator PageState: TYPE = MMInit.PageState; pageMap: PUBLIC PACKED ARRAY [0..256) OF PageState _ ALL[inuse]; ffvmp, lfvmp: PUBLIC AltoDefs.PageNumber; InvalidSegmentSize: PUBLIC SIGNAL [pages: PageCount] = CODE; InsufficientVM: PUBLIC SIGNAL [needed: PageCount] = CODE; VMnotFree: PUBLIC SIGNAL [base: PageNumber, pages: PageCount] = CODE; AllocVM: PROC [base: PageNumber, pages: PageCount] RETURNS [PageNumber] = BEGIN FrameOps.FlushLargeFrames[]; IF base # DefaultBase THEN DO -- repeat if requested VM not free ProcessDefs.DisableInterrupts[]; FOR vm: PageNumber IN [base..base+pages) DO IF pageMap[vm] = inuse THEN EXIT; REPEAT FINISHED => GOTO found; ENDLOOP; ProcessDefs.EnableInterrupts[]; SIGNAL VMnotFree[base, pages]; REPEAT found => NULL ENDLOOP ELSE DO -- repeat if insufficient VM n: CARDINAL _ 0; -- count of contiguous free pages ProcessDefs.DisableInterrupts[]; base _ lfvmp; WHILE base IN [ffvmp..lfvmp] DO IF pageMap[base] = inuse THEN n _ 0 ELSE IF (n _ n+1) = pages THEN GOTO foundHole; base _ base-1 ENDLOOP; ProcessDefs.EnableInterrupts[]; SIGNAL InsufficientVM[pages]; REPEAT foundHole => NULL; ENDLOOP; UpdateVM[base, pages, inuse]; ProcessDefs.EnableInterrupts[]; RETURN[base] END; UpdateVM: PROC [base: PageNumber, pages: PageCount, status: PageState] = BEGIN IF status = free THEN BEGIN ProcessDefs.DisableInterrupts[]; ffvmp _ MIN[ffvmp, base]; lfvmp _ MAX[lfvmp, base+pages-1]; ProcessDefs.EnableInterrupts[]; END; ProcessDefs.DisableInterrupts[]; FOR base IN [base..base+pages) DO pageMap[base] _ status ENDLOOP; ProcessDefs.EnableInterrupts[]; RETURN END; -- Primative Object Allocation MaxObjects: CARDINAL = 128; ObjectIndex: TYPE = CARDINAL[0..MaxObjects); objectTable: ARRAY ObjectIndex OF Object _ ALL[FreeObject]; FreeObject: Object = Object[base: 0, pages: 0]; InvalidObject: PUBLIC SIGNAL [object: POINTER] = CODE; AllocateObject: PROC RETURNS [Handle] = BEGIN FOR i: ObjectIndex IN ObjectIndex DO IF objectTable[i].pages = 0 THEN RETURN [@objectTable[i]]; ENDLOOP; ERROR InsufficientVM[1]; END; LiberateObject: PROC [object: Handle] = { object.pages _ 0 }; ValidateObject: PROC [object:Handle] = BEGIN o: CARDINAL _ LOOPHOLE[object]; base: CARDINAL _ LOOPHOLE[@objectTable]; IF o NOT IN [base..base+SIZE[Object]*MaxObjects) THEN ERROR InvalidObject[object]; RETURN END; EnumerateObjects: PROC [ proc: PROC [Handle] RETURNS [BOOLEAN]] RETURNS [object: Handle] = BEGIN i: ObjectIndex; FOR i IN ObjectIndex DO object _ @objectTable[i]; IF object.pages # 0 AND proc[object] THEN RETURN[object]; ENDLOOP; RETURN[NIL] END; VMtoDataSegment: PUBLIC PROC [a: POINTER] RETURNS [DataSegmentHandle] = BEGIN CheckObject: PROC [h: Handle] RETURNS [BOOLEAN] = { RETURN[DataSegmentAddress[LOOPHOLE[h]] = PagePointer[a]] }; RETURN[LOOPHOLE[EnumerateObjects[CheckObject]]]; END; -- Simplified Data Segments AllocatePages, AllocateResidentPages: PUBLIC PROC [ npages:CARDINAL] RETURNS [POINTER] = { RETURN[DataSegmentAddress[NewDataSegment[DefaultBase,npages]]] }; AllocateSegment, AllocateResidentSegment: PUBLIC PROC [ nwords:CARDINAL] RETURNS [POINTER] = { RETURN[AllocatePages[SystemDefs.PagesForWords[nwords]]] }; SegmentSize: PUBLIC PROC [base:POINTER] RETURNS [CARDINAL] = BEGIN h: Handle = LOOPHOLE[VMtoDataSegment[base]]; RETURN[IF h = NIL THEN 0 ELSE h.pages*AltoDefs.PageSize] END; FreeSegment, FreePages: PUBLIC PROC [base:POINTER] = BEGIN seg: DataSegmentHandle = VMtoDataSegment[base]; IF seg # NIL THEN DeleteDataSegment[seg]; RETURN END; END.....