<> <> <> <> 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.