<> <> <> <> <> <> <> DIRECTORY Basics USING [BITSHIFT, DoubleShiftLeft, DoubleShiftRight, LongNumber], PrincOps USING [bytesPerPage, logBytesPerPage, logWordsPerPage, PageCount, PageNumber, wordsPerPage]; <> <> <<>> VM: CEDAR DEFINITIONS IMPORTS Basics = BEGIN <> PageNumber: TYPE = PrincOps.PageNumber; -- INT[0..2^24) PageCount: TYPE = PrincOps.PageCount; -- INT[0..2^24] <> <> <<>> Interval: TYPE = RECORD [page: PageNumber, count: PageCount]; nullInterval: Interval = [page: 0, count: 0]; <> <> PageState: TYPE = RECORD [ dataState: DataState, -- state of the contents of the page (see below) readOnly: BOOL, -- altered only by MakeReadOnly and MakeReadWrite hasRealMemory: BOOL, -- altered only by SwapIn and MakeUndefined needsCleaning: BOOL, -- a hint for clients of "Clean" pinCount: INT -- altered only by Pin and Unpin ]; <> <> DataState: TYPE = { none, -- page is unallocated; it has no associated backing storage undefined, -- page is allocated, but content is undefined unchanged, -- page content has not changed since MakeUnchanged was last called changed -- page content has changed }; <> <> State: PROC [page: PageNumber] RETURNS [state: PageState]; <<... returns the current PageState of the indicated page.>> <> <<... sets the dataState of all pages in the indicated interval.>> <> <<>> <> <<>> <> VMPartition: TYPE = {lowCore, pda, mds, normalVM}; <> <<>> LogPageCount: TYPE = NAT[0..23--LogBase2[PageCount.LAST]-1--]; Allocate: PROC [count: PageCount, partition: VMPartition _ normalVM, subRange: Interval _ nullInterval, start: PageNumber _ 0, alignment: LogPageCount _ 0, in64K: BOOL _ FALSE] RETURNS [interval: Interval]; <> <<(1) for each page in "interval", State[page].dataState = none,>> <<(2) interval.count = count,>> <<(3) if subRange.count >= count, then "interval" is contained in "subRange",>> <<(4) interval.page MOD 2alignment is zero, and>> <<(5) if start is non-zero, then interval.page-start is minimal, and>> <<(6) if in64K is TRUE, then the interval does not cross a 64K word boundary.>> <> <> <> <<(1) for each page in "bestInterval", State[page].dataState = none,>> <<(2) bestInterval.count < count with count-bestInterval.count minimal, and>> <<(3) if subRange.count >= count, then "bestInterval" is contained in "subRange",>> <> SimpleAllocate: PROC [count: PageCount] RETURNS [interval: Interval]; <<... equivalent to Allocate[count: count], defaulting all other parameters.>> <<>> CantAllocate: ERROR [bestInterval: Interval]; <<... raised by Allocate; bestInterval is the largest available interval within the requested one.>> <<>> Free: UNSAFE PROC [interval: Interval]; <<... performs SetDataState[interval, none].>> <> <> <<>> <> <> <> SwapIn: UNSAFE PROC [interval: Interval, kill: BOOL _ FALSE, pin: BOOL _ FALSE, nextPage: PageNumber _ 0]; <> <> <> <> <> <> <> <> <> <> <> Kill, MakeUndefined: UNSAFE PROC [interval: Interval]; <<... performs SetDataState[interval, undefined].>> <> <> Touch: PROC [interval: Interval]; <<... performs SwapIn[interval: interval].>> <> <> <> <<>> <> Pin: PROC [interval: Interval]; <<... performs SwapIn[interval: interval, pin: TRUE].>> <> <> <> <> Unpin: PROC [interval: Interval]; <> <> <> <<>> <> <> <<>> MakeReadOnly: PROC [interval: Interval]; <> <> <> <<>> MakeReadWrite: PROC [interval: Interval]; <> <> <<>> <<>> <> <<>> MakeUnchanged: PROC [interval: Interval]; <<... performs SetDataState[interval, unchanged].>> <> <> <> <<>> MakeChanged: PROC [interval: Interval]; <<... performs SetDataState[interval, changed].>> <> <> <<>> <> <> <<>> Clean: PROC [interval: Interval]; <<... ensures that the backing storage for each page in the interval contains the same information as the associated real memory (if any).>> <> <<>> Age: PROC [interval: Interval]; <<... increases the likelihood that the backing storage associated with pages in the interval will be selected for replacement. However, this procedure does not initiate any I/O operations.>> <> <<>> ForceCleaning: PROC; <<... forces the VM laundry process to clean some memory.>> <<>> <> AddressFault: ERROR [address: LONG POINTER]; WriteProtectFault: ERROR [address: LONG POINTER]; <> <<>> IOErrorType: TYPE = {software, hardware}; CantDoIO: ERROR [reason: IOErrorType, page: PageNumber]; <> <<>> LaundryError: TYPE = RECORD [ errorType: IOErrorType, -- error classification page: PageNumber -- page that gave trouble ]; <<>> LastLaundryError: PROC RETURNS [LaundryError]; <> <> <> <<>> wordsPerPage: NAT = PrincOps.wordsPerPage; logWordsPerPage: NAT = PrincOps.logWordsPerPage; bytesPerPage: NAT = PrincOps.bytesPerPage; logBytesPerPage: NAT = PrincOps.logBytesPerPage; PagesForWords: PROC [words: INT] RETURNS [pages: PageCount] = INLINE { RETURN[Basics.DoubleShiftRight[[li[words+(wordsPerPage-1)]], logWordsPerPage].li] }; WordsForPages: PROC [pages: PageCount] RETURNS [words: INT] = INLINE { RETURN[Basics.DoubleShiftLeft[[li[li: pages]], logWordsPerPage].li] }; PagesForBytes: PROC [bytes: INT] RETURNS [pages: PageCount] = INLINE { RETURN[Basics.DoubleShiftRight[[li[li: bytes+(bytesPerPage-1)]], logBytesPerPage].li] }; BytesForPages: PROC [pages: PageCount] RETURNS [bytes: INT] = INLINE { RETURN[Basics.DoubleShiftLeft[[li[li: pages]], logBytesPerPage].li] }; <<>> AddressForPageNumber: PROC [page: PageNumber] RETURNS [address: LONG POINTER] = INLINE { RETURN[Basics.DoubleShiftLeft[[li[li: page]], logWordsPerPage].lp] }; PageNumberForAddress: PROC [address: LONG POINTER] RETURNS [page: PageNumber] = INLINE { RETURN[Basics.DoubleShiftRight[ [lp[address]], logWordsPerPage].li] }; <> <> lowCore: UNCOUNTED ZONE; END. <<>> <> <> <> <<>> <> <> <<>> <> <> <>