-- 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.....