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];
};
};
}.