WVMImpl.mesa: word-level implementation
Copyright © 1985 by Xerox Corporation. All rights reserved.
Andrew Birrell August 1, 1983 12:57 pm
Paul Rovner, August 10, 1983 12:05 pm
Russ Atkinson (RRA) May 14, 1985 10:41:38 am PDT
DIRECTORY
PrincOpsUtils USING [ LongCopy ],
PrincOps USING [ BytePC, InstWord, op, zBRK ],
VM USING [AddressFault, MakeReadOnly, MakeReadWrite, PageNumber, PageNumberForAddress, State],
WorldVM USING [ Address, AddressFault, LocalWorld, World ],
WVMPrivate USING [ GetPage, PageData, PageHandle, PageNumber, pageSize, ReleasePage, WriteAndReleasePage ];
WVMImpl: MONITOR-- mutual exclusion on making code pages writable(!) --
IMPORTS PrincOpsUtils, VM, WorldVM, WVMPrivate
EXPORTS WorldVM, WVMPrivate
= { OPEN WorldVM;
local: WorldVM.World = WorldVM.LocalWorld[];
LocalCopy: PROC [from: LONG POINTER, to: LONG POINTER, words: INT] = {
This procedure handles LONG copies, and also provides a procedure call to allow translation of VM.AddressFault to WorldVM.AddressFault.
inner: PROC = {
WHILE words > 1024 DO
PrincOpsUtils.LongCopy[from: from, nwords: 1024, to: to];
from ← from + 1024;
to ← to + 1024;
words ← words - 1024;
ENDLOOP;
IF words > 0 THEN
PrincOpsUtils.LongCopy[from: from, nwords: words, to: to];
};
faultAddr: Address;
{
inner[ ! VM.AddressFault => {faultAddr ← LOOPHOLE[address]; GO TO fault}];
RETURN;
EXITS fault => ERROR WorldVM.AddressFault[faultAddr];
};
};
Read: PUBLIC PROC [world: World, addr: Address] RETURNS [ i: CARDINAL ← 0 ] = {
n: WVMPrivate.PageNumber;
w: [0..WVMPrivate.pageSize);
h: WVMPrivate.PageHandle;
d: REF WVMPrivate.PageData;
IF world = local THEN {
LocalCopy[LOOPHOLE[addr], @i, SIZE[CARDINAL] ];
RETURN;
};
[n, w, h, d] ← PageFromAddr[world, addr];
i ← d[w];
WVMPrivate.ReleasePage[h];
};
Write: PUBLIC PROC [world: World, addr: Address, value: CARDINAL] = {
n: WVMPrivate.PageNumber;
w: [0..WVMPrivate.pageSize);
h: WVMPrivate.PageHandle;
d: REF WVMPrivate.PageData;
IF world = local THEN {
LocalCopy[@value, LOOPHOLE[addr], SIZE[CARDINAL] ];
RETURN;
};
[n, w, h, d] ← PageFromAddr[world, addr];
d[w] ← value;
WVMPrivate.WriteAndReleasePage[h];
};
LongRead: PUBLIC PROC [world: World, addr: Address] RETURNS [ i: LONG CARDINAL ] = {
n: WVMPrivate.PageNumber;
w: [0..WVMPrivate.pageSize);
h: WVMPrivate.PageHandle;
d: REF WVMPrivate.PageData;
IF world = local THEN {
LocalCopy[LOOPHOLE[addr], @i, SIZE[LONG CARDINAL]];
RETURN;
};
[n, w, h, d] ← PageFromAddr[world, addr];
IF w = WVMPrivate.pageSize-1
THEN { WVMPrivate.ReleasePage[h]; CopyRead[world,addr,SIZE[LONG CARDINAL],@i] }
ELSE {
i ← LOOPHOLE[@d[w],LONG POINTER TO LONG CARDINAL]^;
WVMPrivate.ReleasePage[h];
};
};
LongWrite: PUBLIC PROC [world: World, addr: Address, value: LONG CARDINAL] = {
n: WVMPrivate.PageNumber;
w: [0..WVMPrivate.pageSize);
h: WVMPrivate.PageHandle;
d: REF WVMPrivate.PageData;
IF world = local THEN {
LocalCopy[@value, LOOPHOLE[addr], SIZE[LONG CARDINAL] ];
RETURN;
};
[n, w, h, d] ← PageFromAddr[world, addr];
IF w = WVMPrivate.pageSize-1
THEN {
WVMPrivate.ReleasePage[h];
CopyWrite[world,@value,SIZE[LONG CARDINAL],addr] }
ELSE {
LOOPHOLE[@d[w],LONG POINTER TO LONG CARDINAL]^ ← value;
WVMPrivate.WriteAndReleasePage[h];
};
};
CopyRead: PUBLIC PROC [world: World, from: Address, nwords: INT, to: LONG POINTER] = {
n: WVMPrivate.PageNumber;
w: [0..WVMPrivate.pageSize);
h: WVMPrivate.PageHandle;
d: REF WVMPrivate.PageData;
IF world = local THEN {
LocalCopy[LOOPHOLE[from], to, nwords ];
RETURN;
};
WHILE nwords > 0 DO
amount: (0..WVMPrivate.pageSize];
[n, w, h, d] ← PageFromAddr[world, from];
amount ← MIN[nwords,WVMPrivate.pageSize-w];
PrincOpsUtils.LongCopy[from: @d[w], to: to, nwords: amount];
nwords ← nwords - amount;
from ← from + amount;
to ← to + amount;
WVMPrivate.ReleasePage[h];
ENDLOOP;
};
CopyWrite: PUBLIC PROC [world: World, from: LONG POINTER, nwords: INT, to: Address] = {
n: WVMPrivate.PageNumber;
w: [0..WVMPrivate.pageSize);
h: WVMPrivate.PageHandle;
d: REF WVMPrivate.PageData;
IF world = local THEN {
LocalCopy[from, LOOPHOLE[to], nwords ];
RETURN;
};
WHILE nwords > 0 DO
amount: [0..WVMPrivate.pageSize);
[n, w, h, d] ← PageFromAddr[world, to];
amount ← MIN[nwords,WVMPrivate.pageSize-w];
PrincOpsUtils.LongCopy[from: from, to: @d[w], nwords: amount];
nwords ← nwords - amount;
from ← from + amount;
to ← to + amount;
WVMPrivate.WriteAndReleasePage[h];
ENDLOOP;
};
PageFromAddr: PROC [world: WorldVM.World, addr: WorldVM.Address] RETURNS [n: WVMPrivate.PageNumber, w: [0..WVMPrivate.pageSize), h: WVMPrivate.PageHandle, d: REF WVMPrivate.PageData] = {
n ← addr / WVMPrivate.pageSize;
w ← addr - n * LONG[WVMPrivate.pageSize];
[d, h] ← WVMPrivate.GetPage[world, n];
};
SetBreak: PUBLIC PROC [world: World, addr: Address, offset: PrincOps.BytePC] RETURNS [ oldByte: PrincOps.op ] = {
oldByte ← Patch[world, addr+offset/2, offset MOD 2, PrincOps.zBRK];
IF oldByte = PrincOps.zBRK THEN ERROR IllegalPatch;
};
ClearBreak: PUBLIC PROC [world: World, addr: Address, offset: PrincOps.BytePC, oldByte: PrincOps.op] = {
brk: PrincOps.op = Patch[world, addr+offset/2, offset MOD 2, oldByte];
IF brk # PrincOps.zBRK THEN ERROR IllegalPatch;
};
IllegalPatch: PUBLIC ERROR = CODE;
Patch: PUBLIC ENTRY PROC [world: World, addr: Address, offset: [0..1], byte: PrincOps.op] RETURNS [oldByte: PrincOps.op] = {
ENABLE UNWIND => NULL;
value: PrincOps.InstWord ← LOOPHOLE[Read[world, addr]]; -- new memory word contents --
oldByte ← IF offset=0 THEN value.evenbyte ELSE value.oddbyte;
IF offset=0 THEN value.evenbyte ← byte ELSE value.oddbyte ← byte;
IF world = local
THEN {
ptr: LONG POINTER = LOOPHOLE[addr];
page: VM.PageNumber = VM.PageNumberForAddress[ptr];
readOnly: BOOL = VM.State[page].readOnly;
IF readOnly THEN VM.MakeReadWrite[[page: page, count: 1]];
ptr^ ← value;
IF readOnly THEN VM.MakeReadOnly[[page: page, count: 1]];
}
ELSE {
n: WVMPrivate.PageNumber;
w: [0..WVMPrivate.pageSize);
h: WVMPrivate.PageHandle;
d: REF WVMPrivate.PageData;
[n, w, h, d] ← PageFromAddr[world, addr];
d[w] ← LOOPHOLE[value];
WVMPrivate.WriteAndReleasePage[h];
};
};
}.