Cedar Remote Debugging: word-level implementation
WVMImpl.mesa
Andrew Birrell August 1, 1983 12:57 pm
Paul Rovner, August 10, 1983 12:05 pm
DIRECTORY
PrincOpsUtils USING[ LongCOPY ],
PrincOps USING[ BytePC, InstWord, op, zBRK ],
VM USING[ PageNumberForAddress, MakeReadOnly, MakeReadWrite, PageNumber, State ],
WorldVM USING[ Address, 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 =
BEGIN
OPEN WorldVM;
local: WorldVM.World = WorldVM.LocalWorld[];
Read:
PUBLIC
PROC[world: World, addr: Address]
RETURNS[ i:
CARDINAL ] =
BEGIN
n: WVMPrivate.PageNumber;
w: [0..WVMPrivate.pageSize);
h: WVMPrivate.PageHandle;
d: REF WVMPrivate.PageData;
IF world = local
THEN RETURN[LOOPHOLE[addr, LONG POINTER TO CARDINAL]^];
[n, w, h, d] ← PageFromAddr[world, addr];
i ← d[w];
WVMPrivate.ReleasePage[h];
END;
Write:
PUBLIC
PROC[world: World, addr: Address, value:
CARDINAL] =
BEGIN
n: WVMPrivate.PageNumber;
w: [0..WVMPrivate.pageSize);
h: WVMPrivate.PageHandle;
d: REF WVMPrivate.PageData;
IF world = local
THEN { LOOPHOLE[addr, LONG POINTER TO CARDINAL]^ ← value; RETURN };
[n, w, h, d] ← PageFromAddr[world, addr];
d[w] ← value;
WVMPrivate.WriteAndReleasePage[h];
END;
LongRead:
PUBLIC
PROC[world: World, addr: Address]
RETURNS[ i:
LONG
CARDINAL ] =
BEGIN
n: WVMPrivate.PageNumber;
w: [0..WVMPrivate.pageSize);
h: WVMPrivate.PageHandle;
d: REF WVMPrivate.PageData;
IF world = local
THEN RETURN[LOOPHOLE[addr, LONG POINTER TO LONG CARDINAL]^];
[n, w, h, d] ← PageFromAddr[world, addr];
IF w = WVMPrivate.pageSize-1
THEN { WVMPrivate.ReleasePage[h]; CopyRead[world,addr,SIZE[LONG CARDINAL],@i] }
ELSE
BEGIN
i ← LOOPHOLE[@d[w],LONG POINTER TO LONG CARDINAL]^;
WVMPrivate.ReleasePage[h];
END;
END;
LongWrite:
PUBLIC
PROC[world: World, addr: Address, value:
LONG
CARDINAL] =
BEGIN
n: WVMPrivate.PageNumber;
w: [0..WVMPrivate.pageSize);
h: WVMPrivate.PageHandle;
d: REF WVMPrivate.PageData;
IF world = local
THEN { LOOPHOLE[addr, LONG POINTER TO LONG CARDINAL]^ ← value; 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
BEGIN
LOOPHOLE[@d[w],LONG POINTER TO LONG CARDINAL]^ ← value;
WVMPrivate.WriteAndReleasePage[h];
END;
END;
CopyRead:
PUBLIC
PROC[world: World, from: Address, nwords:
INT,
to: LONG POINTER] =
BEGIN
n: WVMPrivate.PageNumber;
w: [0..WVMPrivate.pageSize);
h: WVMPrivate.PageHandle;
d: REF WVMPrivate.PageData;
IF world = local
THEN { PrincOpsUtils.LongCOPY[from: LOOPHOLE[from], nwords: nwords, to: to]; 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;
END;
CopyWrite:
PUBLIC
PROC[world: World, from:
LONG
POINTER, nwords:
INT,
to: Address] =
BEGIN
n: WVMPrivate.PageNumber;
w: [0..WVMPrivate.pageSize);
h: WVMPrivate.PageHandle;
d: REF WVMPrivate.PageData;
IF world = local
THEN { PrincOpsUtils.LongCOPY[from: from, nwords: nwords, to: LOOPHOLE[to]]; 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;
END;
PageFromAddr:
PROC[world: WorldVM.World, addr: WorldVM.Address]
RETURNS[n: WVMPrivate.PageNumber, w: [0..WVMPrivate.pageSize),
h: WVMPrivate.PageHandle, d: REF WVMPrivate.PageData] =
BEGIN
n ← addr / WVMPrivate.pageSize;
w ← addr - n * LONG[WVMPrivate.pageSize];
[d, h] ← WVMPrivate.GetPage[world, n];
END;
SetBreak:
PUBLIC
PROC[world: World, addr: Address, offset: PrincOps.BytePC]
RETURNS[ oldByte: PrincOps.op ] =
BEGIN
oldByte ← Patch[world, addr+offset/2, offset MOD 2, PrincOps.zBRK];
IF oldByte = PrincOps.zBRK THEN ERROR IllegalPatch;
END;
ClearBreak:
PUBLIC
PROC[world: World, addr: Address,
offset: PrincOps.BytePC,
oldByte: PrincOps.op] =
BEGIN
brk: PrincOps.op = Patch[world, addr+offset/2, offset MOD 2, oldByte];
IF brk # PrincOps.zBRK THEN ERROR IllegalPatch;
END;
IllegalPatch: PUBLIC ERROR = CODE;
Patch:
PUBLIC
ENTRY
PROC[world: World, addr: Address,
offset: [0..1], byte: PrincOps.op]
RETURNS[oldByte: PrincOps.op] =
BEGIN
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
BEGIN
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]];
END
ELSE
BEGIN
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];
END;
END;
END.