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