diff --git a/src/BizHawk.BizInvoke/CallingConventionAdapter.cs b/src/BizHawk.BizInvoke/CallingConventionAdapter.cs index e85363effb..da08373914 100644 --- a/src/BizHawk.BizInvoke/CallingConventionAdapter.cs +++ b/src/BizHawk.BizInvoke/CallingConventionAdapter.cs @@ -132,14 +132,14 @@ namespace BizHawk.BizInvoke throw new InvalidOperationException(); } - private readonly MemoryBlockBase _memory; + private readonly MemoryBlock _memory; private readonly object _sync = new object(); private readonly WeakReference[] _refs; public SysVHostMsGuest() { int size = 4 * 1024 * 1024; - _memory = MemoryBlockBase.CallPlatformCtor((ulong)size); + _memory = MemoryBlock.Create((ulong)size); _memory.Activate(); _refs = new WeakReference[size / BlockSize]; } @@ -185,7 +185,7 @@ namespace BizHawk.BizInvoke private void WriteThunk(byte[] data, int placeholderIndex, IntPtr p, int index) { - _memory.Protect(_memory.Start, _memory.Size, MemoryBlockBase.Protection.RW); + _memory.Protect(_memory.Start, _memory.Size, MemoryBlock.Protection.RW); var ss = _memory.GetStream(_memory.Start + (ulong)index * BlockSize, BlockSize, true); ss.Write(data, 0, data.Length); for (int i = data.Length; i < BlockSize; i++) @@ -193,7 +193,7 @@ namespace BizHawk.BizInvoke ss.Position = placeholderIndex; var bw = new BinaryWriter(ss); bw.Write((long)p); - _memory.Protect(_memory.Start, _memory.Size, MemoryBlockBase.Protection.RX); + _memory.Protect(_memory.Start, _memory.Size, MemoryBlock.Protection.RX); } private IntPtr GetThunkAddress(int index) diff --git a/src/BizHawk.BizInvoke/MemoryBlock.cs b/src/BizHawk.BizInvoke/MemoryBlock.cs index e146127c06..28d6ab8eea 100644 --- a/src/BizHawk.BizInvoke/MemoryBlock.cs +++ b/src/BizHawk.BizInvoke/MemoryBlock.cs @@ -1,238 +1,255 @@ -using System; -using System.Runtime.InteropServices; -using System.IO; - -namespace BizHawk.BizInvoke -{ - public sealed class MemoryBlock : MemoryBlockBase - { - /// - /// handle returned by CreateFileMapping - /// - private IntPtr _handle; - - /// - /// failed to create file mapping - public MemoryBlock(ulong start, ulong size) : base(start, size) - { - _handle = Kernel32.CreateFileMapping( - Kernel32.INVALID_HANDLE_VALUE, - IntPtr.Zero, - Kernel32.FileMapProtection.PageExecuteReadWrite | Kernel32.FileMapProtection.SectionCommit, - (uint)(Size >> 32), - (uint)Size, - null - ); - if (_handle == IntPtr.Zero) throw new InvalidOperationException($"{nameof(Kernel32.CreateFileMapping)}() returned NULL"); - } - - /// is or failed to map file view - public override void Activate() - { - if (Active) - throw new InvalidOperationException("Already active"); - if (Kernel32.MapViewOfFileEx( - _handle, - Kernel32.FileMapAccessType.Read | Kernel32.FileMapAccessType.Write | Kernel32.FileMapAccessType.Execute, - 0, - 0, - Z.UU(Size), - Z.US(Start) - ) != Z.US(Start)) - { - throw new InvalidOperationException($"{nameof(Kernel32.MapViewOfFileEx)}() returned NULL"); - } - ProtectAll(); - Active = true; - } - - /// is or failed to unmap file view - public override void Deactivate() - { - if (!Active) - throw new InvalidOperationException("Not active"); - if (!Kernel32.UnmapViewOfFile(Z.US(Start))) - throw new InvalidOperationException($"{nameof(Kernel32.UnmapViewOfFile)}() returned NULL"); - Active = false; - } - - /// snapshot already taken, is , or failed to make memory read-only - public override void SaveXorSnapshot() - { - if (_snapshot != null) - throw new InvalidOperationException("Snapshot already taken"); - if (!Active) - throw new InvalidOperationException("Not active"); - - // temporarily switch the entire block to `R`: in case some areas are unreadable, we don't want - // that to complicate things - Kernel32.MemoryProtection old; - if (!Kernel32.VirtualProtect(Z.UU(Start), Z.UU(Size), Kernel32.MemoryProtection.READONLY, out old)) - throw new InvalidOperationException($"{nameof(Kernel32.VirtualProtect)}() returned FALSE!"); - - _snapshot = new byte[Size]; - var ds = new MemoryStream(_snapshot, true); - var ss = GetStream(Start, Size, false); - ss.CopyTo(ds); - XorHash = WaterboxUtils.Hash(_snapshot); - - ProtectAll(); - } - - /// is or failed to make memory read-only - public override byte[] FullHash() - { - if (!Active) - throw new InvalidOperationException("Not active"); - // temporarily switch the entire block to `R` - Kernel32.MemoryProtection old; - if (!Kernel32.VirtualProtect(Z.UU(Start), Z.UU(Size), Kernel32.MemoryProtection.READONLY, out old)) - throw new InvalidOperationException($"{nameof(Kernel32.VirtualProtect)}() returned FALSE!"); - var ret = WaterboxUtils.Hash(GetStream(Start, Size, false)); - ProtectAll(); - return ret; - } - - private static Kernel32.MemoryProtection GetKernelMemoryProtectionValue(Protection prot) - { - Kernel32.MemoryProtection p; - switch (prot) - { - case Protection.None: p = Kernel32.MemoryProtection.NOACCESS; break; - case Protection.R: p = Kernel32.MemoryProtection.READONLY; break; - case Protection.RW: p = Kernel32.MemoryProtection.READWRITE; break; - case Protection.RX: p = Kernel32.MemoryProtection.EXECUTE_READ; break; - default: throw new ArgumentOutOfRangeException(nameof(prot)); - } - return p; - } - - protected override void ProtectAll() - { - int ps = 0; - for (int i = 0; i < _pageData.Length; i++) - { - if (i == _pageData.Length - 1 || _pageData[i] != _pageData[i + 1]) - { - var p = GetKernelMemoryProtectionValue(_pageData[i]); - ulong zstart = GetStartAddr(ps); - ulong zend = GetStartAddr(i + 1); - Kernel32.MemoryProtection old; - if (!Kernel32.VirtualProtect(Z.UU(zstart), Z.UU(zend - zstart), p, out old)) - throw new InvalidOperationException($"{nameof(Kernel32.VirtualProtect)}() returned FALSE!"); - ps = i + 1; - } - } - } - - /// failed to protect memory - public override void Protect(ulong start, ulong length, Protection prot) - { - if (length == 0) - return; - int pstart = GetPage(start); - int pend = GetPage(start + length - 1); - - var p = GetKernelMemoryProtectionValue(prot); - for (int i = pstart; i <= pend; i++) - _pageData[i] = prot; // also store the value for later use - - if (Active) // it's legal to Protect() if we're not active; the information is just saved for the next activation - { - var computedStart = WaterboxUtils.AlignDown(start); - var computedEnd = WaterboxUtils.AlignUp(start + length); - var computedLength = computedEnd - computedStart; - - Kernel32.MemoryProtection old; - if (!Kernel32.VirtualProtect(Z.UU(computedStart), - Z.UU(computedLength), p, out old)) - throw new InvalidOperationException($"{nameof(Kernel32.VirtualProtect)}() returned FALSE!"); - } - } - - public override void Dispose(bool disposing) - { - if (_handle != IntPtr.Zero) - { - if (Active) - Deactivate(); - Kernel32.CloseHandle(_handle); - _handle = IntPtr.Zero; - } - } - - ~MemoryBlock() - { - Dispose(false); - } - - private static class Kernel32 - { - [DllImport("kernel32.dll", SetLastError = true)] - public static extern bool VirtualProtect(UIntPtr lpAddress, UIntPtr dwSize, - MemoryProtection flNewProtect, out MemoryProtection lpflOldProtect); - - [Flags] - public enum MemoryProtection : uint - { - EXECUTE = 0x10, - EXECUTE_READ = 0x20, - EXECUTE_READWRITE = 0x40, - EXECUTE_WRITECOPY = 0x80, - NOACCESS = 0x01, - READONLY = 0x02, - READWRITE = 0x04, - WRITECOPY = 0x08, - GUARD_Modifierflag = 0x100, - NOCACHE_Modifierflag = 0x200, - WRITECOMBINE_Modifierflag = 0x400 - } - - [DllImport("kernel32.dll", SetLastError = true)] - public static extern IntPtr CreateFileMapping( - IntPtr hFile, - IntPtr lpFileMappingAttributes, - FileMapProtection flProtect, - uint dwMaximumSizeHigh, - uint dwMaximumSizeLow, - string lpName); - - [Flags] - public enum FileMapProtection : uint - { - PageReadonly = 0x02, - PageReadWrite = 0x04, - PageWriteCopy = 0x08, - PageExecuteRead = 0x20, - PageExecuteReadWrite = 0x40, - SectionCommit = 0x8000000, - SectionImage = 0x1000000, - SectionNoCache = 0x10000000, - SectionReserve = 0x4000000, - } - - [DllImport("kernel32.dll", SetLastError = true)] - public static extern bool CloseHandle(IntPtr hObject); - - [DllImport("kernel32.dll", SetLastError = true)] - public static extern bool UnmapViewOfFile(IntPtr lpBaseAddress); - - [DllImport("kernel32.dll")] - public static extern IntPtr MapViewOfFileEx(IntPtr hFileMappingObject, - FileMapAccessType dwDesiredAccess, uint dwFileOffsetHigh, uint dwFileOffsetLow, - UIntPtr dwNumberOfBytesToMap, IntPtr lpBaseAddress); - - [Flags] - public enum FileMapAccessType : uint - { - Copy = 0x01, - Write = 0x02, - Read = 0x04, - AllAccess = 0x08, - Execute = 0x20, - } - - public static readonly IntPtr INVALID_HANDLE_VALUE = Z.US(0xffffffffffffffff); - } - } -} +using System; +using System.IO; +using System.Runtime.InteropServices; +using BizHawk.Common; + +namespace BizHawk.BizInvoke +{ + public abstract class MemoryBlock : IDisposable + { + /// allocate bytes starting at a particular address + /// is not aligned or is 0 + protected MemoryBlock(ulong start, ulong size) + { + if (!WaterboxUtils.Aligned(start)) + throw new ArgumentOutOfRangeException(nameof(start), start, "start address must be aligned"); + if (size == 0) + throw new ArgumentOutOfRangeException(nameof(size), size, "cannot create 0-length block"); + Start = start; + Size = WaterboxUtils.AlignUp(size); + EndExclusive = Start + Size; + _pageData = new Protection[GetPage(EndExclusive - 1) + 1]; + } + + /// stores last set memory protection value for each page + protected readonly Protection[] _pageData; + + /// end address of the memory block (not part of the block; class invariant: equal to + ) + public readonly ulong EndExclusive; + + /// total size of the memory block + public readonly ulong Size; + + /// starting address of the memory block + public readonly ulong Start; + + /// snapshot for XOR buffer + protected byte[] _snapshot; + + /// true if this is currently swapped in + public bool Active { get; protected set; } + + public byte[] XorHash { get; protected set; } + + /// get a page index within the block + protected int GetPage(ulong addr) + { + if (addr < Start || EndExclusive <= addr) throw new ArgumentOutOfRangeException(nameof(addr), addr, "invalid address"); + return (int) ((addr - Start) >> WaterboxUtils.PageShift); + } + + /// get a start address for a page index within the block + protected ulong GetStartAddr(int page) => ((ulong) page << WaterboxUtils.PageShift) + Start; + + /// Get a stream that can be used to read or write from part of the block. Does not check for or change ! + /// or end (= + - 1) are outside [, ), the range of the block + public Stream GetStream(ulong start, ulong length, bool writer) + { + if (start < Start) + throw new ArgumentOutOfRangeException(nameof(start), start, "invalid address"); + if (EndExclusive < start + length) + throw new ArgumentOutOfRangeException(nameof(length), length, "requested length implies invalid end address"); + return new MemoryViewStream(!writer, writer, (long) start, (long) length, this); + } + + /// get a stream that can be used to read or write from part of the block. both reads and writes will be XORed against an earlier recorded snapshot + /// or end (= + - 1) are outside [, ), the range of the block + /// no snapshot taken (haven't called ) + public Stream GetXorStream(ulong start, ulong length, bool writer) + { + if (start < Start) throw new ArgumentOutOfRangeException(nameof(start), start, "invalid address"); + if (EndExclusive < start + length) throw new ArgumentOutOfRangeException(nameof(length), length, "requested length implies invalid end address"); + if (_snapshot == null) throw new InvalidOperationException("No snapshot taken!"); + return new MemoryViewXorStream(!writer, writer, (long) start, (long) length, this, _snapshot, (long) (start - Start)); + } + + /// activate the memory block, swapping it in at the pre-specified address + public abstract void Activate(); + + /// deactivate the memory block, removing it from RAM but leaving it immediately available to swap back in + public abstract void Deactivate(); + + /// take a hash of the current full contents of the block, including unreadable areas + public abstract byte[] FullHash(); + + /// set r/w/x protection on a portion of memory. rounded to encompassing pages + public abstract void Protect(ulong start, ulong length, Protection prot); + + /// restore all recorded protections + protected abstract void ProtectAll(); + + /// take a snapshot of the entire memory block's contents, for use in + public abstract void SaveXorSnapshot(); + + public abstract void Dispose(bool disposing); + + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + + ~MemoryBlock() + { + Dispose(false); + } + + /// allocate bytes starting at a particular address + public static MemoryBlock Create(ulong start, ulong size) => OSTailoredCode.IsUnixHost + ? (MemoryBlock) new MemoryBlockUnix(start, size) + : new MemoryBlockWindows(start, size); + + /// allocate bytes at any address + public static MemoryBlock Create(ulong size) => Create(0, size); + + /// Memory protection constant + public enum Protection : byte { None, R, RW, RX } + + private class MemoryViewStream : Stream + { + public MemoryViewStream(bool readable, bool writable, long ptr, long length, MemoryBlock owner) + { + _readable = readable; + _writable = writable; + _ptr = ptr; + _length = length; + _owner = owner; + _pos = 0; + } + + private readonly long _length; + private readonly MemoryBlock _owner; + private readonly long _ptr; + private readonly bool _readable; + private readonly bool _writable; + + private long _pos; + + public override bool CanRead => _readable; + public override bool CanSeek => true; + public override bool CanWrite => _writable; + public override long Length => _length; + public override long Position + { + get => _pos; + set + { + if (value < 0 || _length < value) throw new ArgumentOutOfRangeException(); + _pos = value; + } + } + + private void EnsureNotDisposed() + { + if (_owner.Start == 0) + throw new ObjectDisposedException(nameof(MemoryBlock)); + } + + public override void Flush() {} + + public override int Read(byte[] buffer, int offset, int count) + { + if (!_readable) throw new InvalidOperationException(); + if (count < 0 || buffer.Length < count + offset) throw new ArgumentOutOfRangeException(); + EnsureNotDisposed(); + + count = (int) Math.Min(count, _length - _pos); + Marshal.Copy(Z.SS(_ptr + _pos), buffer, offset, count); + _pos += count; + return count; + } + + public override long Seek(long offset, SeekOrigin origin) + { + long newpos; + switch (origin) + { + default: + case SeekOrigin.Begin: + newpos = offset; + break; + case SeekOrigin.Current: + newpos = _pos + offset; + break; + case SeekOrigin.End: + newpos = _length + offset; + break; + } + Position = newpos; + return newpos; + } + + public override void SetLength(long value) + { + throw new InvalidOperationException(); + } + + public override void Write(byte[] buffer, int offset, int count) + { + if (!_writable) throw new InvalidOperationException(); + if (count < 0 || _length - _pos < count || buffer.Length < count + offset) throw new ArgumentOutOfRangeException(); + EnsureNotDisposed(); + + Marshal.Copy(buffer, offset, Z.SS(_ptr + _pos), count); + _pos += count; + } + } + + private class MemoryViewXorStream : MemoryViewStream + { + public MemoryViewXorStream(bool readable, bool writable, long ptr, long length, MemoryBlock owner, byte[] initial, long offset) + : base(readable, writable, ptr, length, owner) + { + _initial = initial; + _offset = (int) offset; + } + + /// the initial data to XOR against for both reading and writing + private readonly byte[] _initial; + + /// offset into the XOR data that this stream is representing + private readonly int _offset; + + public override int Read(byte[] buffer, int offset, int count) + { + var pos = (int) Position; + count = base.Read(buffer, offset, count); + XorTransform(_initial, _offset + pos, buffer, offset, count); + return count; + } + + public override void Write(byte[] buffer, int offset, int count) + { + var pos = (int) Position; + if (count < 0 || Length - pos < count || buffer.Length < count + offset) throw new ArgumentOutOfRangeException(); + + // is mutating the buffer passed to Stream.Write kosher? + XorTransform(_initial, _offset + pos, buffer, offset, count); + base.Write(buffer, offset, count); + } + + /// bounds check already done by calling method i.e. in base.Read (for ) or in + private static unsafe void XorTransform(byte[] source, int sourceOffset, byte[] dest, int destOffset, int length) + { + // TODO: C compilers can make this pretty snappy, but can the C# jitter? Or do we need intrinsics + fixed (byte* _s = source, _d = dest) + { + byte* s = _s + sourceOffset; + byte* d = _d + destOffset; + byte* sEnd = s + length; + while (s < sEnd) *d++ ^= *s++; + } + } + } + } +} diff --git a/src/BizHawk.BizInvoke/MemoryBlockBase.cs b/src/BizHawk.BizInvoke/MemoryBlockBase.cs deleted file mode 100644 index 1219c9b4d2..0000000000 --- a/src/BizHawk.BizInvoke/MemoryBlockBase.cs +++ /dev/null @@ -1,255 +0,0 @@ -using System; -using System.IO; -using System.Runtime.InteropServices; -using BizHawk.Common; - -namespace BizHawk.BizInvoke -{ - public abstract class MemoryBlockBase : IDisposable - { - /// allocate bytes starting at a particular address - /// is not aligned or is 0 - protected MemoryBlockBase(ulong start, ulong size) - { - if (!WaterboxUtils.Aligned(start)) - throw new ArgumentOutOfRangeException(nameof(start), start, "start address must be aligned"); - if (size == 0) - throw new ArgumentOutOfRangeException(nameof(size), size, "cannot create 0-length block"); - Start = start; - Size = WaterboxUtils.AlignUp(size); - EndExclusive = Start + Size; - _pageData = new Protection[GetPage(EndExclusive - 1) + 1]; - } - - /// stores last set memory protection value for each page - protected readonly Protection[] _pageData; - - /// end address of the memory block (not part of the block; class invariant: equal to + ) - public readonly ulong EndExclusive; - - /// total size of the memory block - public readonly ulong Size; - - /// starting address of the memory block - public readonly ulong Start; - - /// snapshot for XOR buffer - protected byte[] _snapshot; - - /// true if this is currently swapped in - public bool Active { get; protected set; } - - public byte[] XorHash { get; protected set; } - - /// get a page index within the block - protected int GetPage(ulong addr) - { - if (addr < Start || EndExclusive <= addr) throw new ArgumentOutOfRangeException(nameof(addr), addr, "invalid address"); - return (int) ((addr - Start) >> WaterboxUtils.PageShift); - } - - /// get a start address for a page index within the block - protected ulong GetStartAddr(int page) => ((ulong) page << WaterboxUtils.PageShift) + Start; - - /// Get a stream that can be used to read or write from part of the block. Does not check for or change ! - /// or end (= + - 1) are outside [, ), the range of the block - public Stream GetStream(ulong start, ulong length, bool writer) - { - if (start < Start) - throw new ArgumentOutOfRangeException(nameof(start), start, "invalid address"); - if (EndExclusive < start + length) - throw new ArgumentOutOfRangeException(nameof(length), length, "requested length implies invalid end address"); - return new MemoryViewStream(!writer, writer, (long) start, (long) length, this); - } - - /// get a stream that can be used to read or write from part of the block. both reads and writes will be XORed against an earlier recorded snapshot - /// or end (= + - 1) are outside [, ), the range of the block - /// no snapshot taken (haven't called ) - public Stream GetXorStream(ulong start, ulong length, bool writer) - { - if (start < Start) throw new ArgumentOutOfRangeException(nameof(start), start, "invalid address"); - if (EndExclusive < start + length) throw new ArgumentOutOfRangeException(nameof(length), length, "requested length implies invalid end address"); - if (_snapshot == null) throw new InvalidOperationException("No snapshot taken!"); - return new MemoryViewXorStream(!writer, writer, (long) start, (long) length, this, _snapshot, (long) (start - Start)); - } - - /// activate the memory block, swapping it in at the pre-specified address - public abstract void Activate(); - - /// deactivate the memory block, removing it from RAM but leaving it immediately available to swap back in - public abstract void Deactivate(); - - /// take a hash of the current full contents of the block, including unreadable areas - public abstract byte[] FullHash(); - - /// set r/w/x protection on a portion of memory. rounded to encompassing pages - public abstract void Protect(ulong start, ulong length, Protection prot); - - /// restore all recorded protections - protected abstract void ProtectAll(); - - /// take a snapshot of the entire memory block's contents, for use in - public abstract void SaveXorSnapshot(); - - public abstract void Dispose(bool disposing); - - public void Dispose() - { - Dispose(true); - GC.SuppressFinalize(this); - } - - ~MemoryBlockBase() - { - Dispose(false); - } - - /// allocate bytes starting at a particular address - public static MemoryBlockBase CallPlatformCtor(ulong start, ulong size) => OSTailoredCode.IsUnixHost - ? (MemoryBlockBase) new MemoryBlockUnix(start, size) - : new MemoryBlock(start, size); - - /// allocate bytes at any address - public static MemoryBlockBase CallPlatformCtor(ulong size) => CallPlatformCtor(0, size); - - /// Memory protection constant - public enum Protection : byte { None, R, RW, RX } - - private class MemoryViewStream : Stream - { - public MemoryViewStream(bool readable, bool writable, long ptr, long length, MemoryBlockBase owner) - { - _readable = readable; - _writable = writable; - _ptr = ptr; - _length = length; - _owner = owner; - _pos = 0; - } - - private readonly long _length; - private readonly MemoryBlockBase _owner; - private readonly long _ptr; - private readonly bool _readable; - private readonly bool _writable; - - private long _pos; - - public override bool CanRead => _readable; - public override bool CanSeek => true; - public override bool CanWrite => _writable; - public override long Length => _length; - public override long Position - { - get => _pos; - set - { - if (value < 0 || _length < value) throw new ArgumentOutOfRangeException(); - _pos = value; - } - } - - private void EnsureNotDisposed() - { - if (_owner.Start == 0) - throw new ObjectDisposedException(nameof(MemoryBlockBase)); - } - - public override void Flush() {} - - public override int Read(byte[] buffer, int offset, int count) - { - if (!_readable) throw new InvalidOperationException(); - if (count < 0 || buffer.Length < count + offset) throw new ArgumentOutOfRangeException(); - EnsureNotDisposed(); - - count = (int) Math.Min(count, _length - _pos); - Marshal.Copy(Z.SS(_ptr + _pos), buffer, offset, count); - _pos += count; - return count; - } - - public override long Seek(long offset, SeekOrigin origin) - { - long newpos; - switch (origin) - { - default: - case SeekOrigin.Begin: - newpos = offset; - break; - case SeekOrigin.Current: - newpos = _pos + offset; - break; - case SeekOrigin.End: - newpos = _length + offset; - break; - } - Position = newpos; - return newpos; - } - - public override void SetLength(long value) - { - throw new InvalidOperationException(); - } - - public override void Write(byte[] buffer, int offset, int count) - { - if (!_writable) throw new InvalidOperationException(); - if (count < 0 || _length - _pos < count || buffer.Length < count + offset) throw new ArgumentOutOfRangeException(); - EnsureNotDisposed(); - - Marshal.Copy(buffer, offset, Z.SS(_ptr + _pos), count); - _pos += count; - } - } - - private class MemoryViewXorStream : MemoryViewStream - { - public MemoryViewXorStream(bool readable, bool writable, long ptr, long length, MemoryBlockBase owner, byte[] initial, long offset) - : base(readable, writable, ptr, length, owner) - { - _initial = initial; - _offset = (int) offset; - } - - /// the initial data to XOR against for both reading and writing - private readonly byte[] _initial; - - /// offset into the XOR data that this stream is representing - private readonly int _offset; - - public override int Read(byte[] buffer, int offset, int count) - { - var pos = (int) Position; - count = base.Read(buffer, offset, count); - XorTransform(_initial, _offset + pos, buffer, offset, count); - return count; - } - - public override void Write(byte[] buffer, int offset, int count) - { - var pos = (int) Position; - if (count < 0 || Length - pos < count || buffer.Length < count + offset) throw new ArgumentOutOfRangeException(); - - // is mutating the buffer passed to Stream.Write kosher? - XorTransform(_initial, _offset + pos, buffer, offset, count); - base.Write(buffer, offset, count); - } - - /// bounds check already done by calling method i.e. in base.Read (for ) or in - private static unsafe void XorTransform(byte[] source, int sourceOffset, byte[] dest, int destOffset, int length) - { - // TODO: C compilers can make this pretty snappy, but can the C# jitter? Or do we need intrinsics - fixed (byte* _s = source, _d = dest) - { - byte* s = _s + sourceOffset; - byte* d = _d + destOffset; - byte* sEnd = s + length; - while (s < sEnd) *d++ ^= *s++; - } - } - } - } -} diff --git a/src/BizHawk.BizInvoke/MemoryBlockUnix.cs b/src/BizHawk.BizInvoke/MemoryBlockUnix.cs index b3914cd7de..36ad113680 100644 --- a/src/BizHawk.BizInvoke/MemoryBlockUnix.cs +++ b/src/BizHawk.BizInvoke/MemoryBlockUnix.cs @@ -5,12 +5,12 @@ using static BizHawk.BizInvoke.POSIXLibC; namespace BizHawk.BizInvoke { - public sealed class MemoryBlockUnix : MemoryBlockBase + public sealed class MemoryBlockUnix : MemoryBlock { /// handle returned by private int _fd; - /// + /// /// failed to get file descriptor (never thrown as is thrown first) /// always public MemoryBlockUnix(ulong start, ulong size) : base(start, size) @@ -22,7 +22,7 @@ namespace BizHawk.BizInvoke #endif } - /// is or failed to map memory + /// is or failed to map memory public override void Activate() { if (Active) throw new InvalidOperationException("Already active"); @@ -34,7 +34,7 @@ namespace BizHawk.BizInvoke Active = true; } - /// is or failed to unmap memory + /// is or failed to unmap memory public override void Deactivate() { if (!Active) throw new InvalidOperationException("Not active"); @@ -45,7 +45,7 @@ namespace BizHawk.BizInvoke Active = false; } - /// is or failed to make memory read-only + /// is or failed to make memory read-only public override byte[] FullHash() { if (!Active) throw new InvalidOperationException("Not active"); @@ -100,7 +100,7 @@ namespace BizHawk.BizInvoke } } - /// snapshot already taken, is , or failed to make memory read-only + /// snapshot already taken, is , or failed to make memory read-only public override void SaveXorSnapshot() { if (_snapshot != null) throw new InvalidOperationException("Snapshot already taken"); diff --git a/src/BizHawk.BizInvoke/MemoryBlockWindows.cs b/src/BizHawk.BizInvoke/MemoryBlockWindows.cs new file mode 100644 index 0000000000..ba2f6a3591 --- /dev/null +++ b/src/BizHawk.BizInvoke/MemoryBlockWindows.cs @@ -0,0 +1,238 @@ +using System; +using System.Runtime.InteropServices; +using System.IO; + +namespace BizHawk.BizInvoke +{ + public sealed class MemoryBlockWindows : MemoryBlock + { + /// + /// handle returned by CreateFileMapping + /// + private IntPtr _handle; + + /// + /// failed to create file mapping + public MemoryBlockWindows(ulong start, ulong size) : base(start, size) + { + _handle = Kernel32.CreateFileMapping( + Kernel32.INVALID_HANDLE_VALUE, + IntPtr.Zero, + Kernel32.FileMapProtection.PageExecuteReadWrite | Kernel32.FileMapProtection.SectionCommit, + (uint)(Size >> 32), + (uint)Size, + null + ); + if (_handle == IntPtr.Zero) throw new InvalidOperationException($"{nameof(Kernel32.CreateFileMapping)}() returned NULL"); + } + + /// is or failed to map file view + public override void Activate() + { + if (Active) + throw new InvalidOperationException("Already active"); + if (Kernel32.MapViewOfFileEx( + _handle, + Kernel32.FileMapAccessType.Read | Kernel32.FileMapAccessType.Write | Kernel32.FileMapAccessType.Execute, + 0, + 0, + Z.UU(Size), + Z.US(Start) + ) != Z.US(Start)) + { + throw new InvalidOperationException($"{nameof(Kernel32.MapViewOfFileEx)}() returned NULL"); + } + ProtectAll(); + Active = true; + } + + /// is or failed to unmap file view + public override void Deactivate() + { + if (!Active) + throw new InvalidOperationException("Not active"); + if (!Kernel32.UnmapViewOfFile(Z.US(Start))) + throw new InvalidOperationException($"{nameof(Kernel32.UnmapViewOfFile)}() returned NULL"); + Active = false; + } + + /// snapshot already taken, is , or failed to make memory read-only + public override void SaveXorSnapshot() + { + if (_snapshot != null) + throw new InvalidOperationException("Snapshot already taken"); + if (!Active) + throw new InvalidOperationException("Not active"); + + // temporarily switch the entire block to `R`: in case some areas are unreadable, we don't want + // that to complicate things + Kernel32.MemoryProtection old; + if (!Kernel32.VirtualProtect(Z.UU(Start), Z.UU(Size), Kernel32.MemoryProtection.READONLY, out old)) + throw new InvalidOperationException($"{nameof(Kernel32.VirtualProtect)}() returned FALSE!"); + + _snapshot = new byte[Size]; + var ds = new MemoryStream(_snapshot, true); + var ss = GetStream(Start, Size, false); + ss.CopyTo(ds); + XorHash = WaterboxUtils.Hash(_snapshot); + + ProtectAll(); + } + + /// is or failed to make memory read-only + public override byte[] FullHash() + { + if (!Active) + throw new InvalidOperationException("Not active"); + // temporarily switch the entire block to `R` + Kernel32.MemoryProtection old; + if (!Kernel32.VirtualProtect(Z.UU(Start), Z.UU(Size), Kernel32.MemoryProtection.READONLY, out old)) + throw new InvalidOperationException($"{nameof(Kernel32.VirtualProtect)}() returned FALSE!"); + var ret = WaterboxUtils.Hash(GetStream(Start, Size, false)); + ProtectAll(); + return ret; + } + + private static Kernel32.MemoryProtection GetKernelMemoryProtectionValue(Protection prot) + { + Kernel32.MemoryProtection p; + switch (prot) + { + case Protection.None: p = Kernel32.MemoryProtection.NOACCESS; break; + case Protection.R: p = Kernel32.MemoryProtection.READONLY; break; + case Protection.RW: p = Kernel32.MemoryProtection.READWRITE; break; + case Protection.RX: p = Kernel32.MemoryProtection.EXECUTE_READ; break; + default: throw new ArgumentOutOfRangeException(nameof(prot)); + } + return p; + } + + protected override void ProtectAll() + { + int ps = 0; + for (int i = 0; i < _pageData.Length; i++) + { + if (i == _pageData.Length - 1 || _pageData[i] != _pageData[i + 1]) + { + var p = GetKernelMemoryProtectionValue(_pageData[i]); + ulong zstart = GetStartAddr(ps); + ulong zend = GetStartAddr(i + 1); + Kernel32.MemoryProtection old; + if (!Kernel32.VirtualProtect(Z.UU(zstart), Z.UU(zend - zstart), p, out old)) + throw new InvalidOperationException($"{nameof(Kernel32.VirtualProtect)}() returned FALSE!"); + ps = i + 1; + } + } + } + + /// failed to protect memory + public override void Protect(ulong start, ulong length, Protection prot) + { + if (length == 0) + return; + int pstart = GetPage(start); + int pend = GetPage(start + length - 1); + + var p = GetKernelMemoryProtectionValue(prot); + for (int i = pstart; i <= pend; i++) + _pageData[i] = prot; // also store the value for later use + + if (Active) // it's legal to Protect() if we're not active; the information is just saved for the next activation + { + var computedStart = WaterboxUtils.AlignDown(start); + var computedEnd = WaterboxUtils.AlignUp(start + length); + var computedLength = computedEnd - computedStart; + + Kernel32.MemoryProtection old; + if (!Kernel32.VirtualProtect(Z.UU(computedStart), + Z.UU(computedLength), p, out old)) + throw new InvalidOperationException($"{nameof(Kernel32.VirtualProtect)}() returned FALSE!"); + } + } + + public override void Dispose(bool disposing) + { + if (_handle != IntPtr.Zero) + { + if (Active) + Deactivate(); + Kernel32.CloseHandle(_handle); + _handle = IntPtr.Zero; + } + } + + ~MemoryBlockWindows() + { + Dispose(false); + } + + private static class Kernel32 + { + [DllImport("kernel32.dll", SetLastError = true)] + public static extern bool VirtualProtect(UIntPtr lpAddress, UIntPtr dwSize, + MemoryProtection flNewProtect, out MemoryProtection lpflOldProtect); + + [Flags] + public enum MemoryProtection : uint + { + EXECUTE = 0x10, + EXECUTE_READ = 0x20, + EXECUTE_READWRITE = 0x40, + EXECUTE_WRITECOPY = 0x80, + NOACCESS = 0x01, + READONLY = 0x02, + READWRITE = 0x04, + WRITECOPY = 0x08, + GUARD_Modifierflag = 0x100, + NOCACHE_Modifierflag = 0x200, + WRITECOMBINE_Modifierflag = 0x400 + } + + [DllImport("kernel32.dll", SetLastError = true)] + public static extern IntPtr CreateFileMapping( + IntPtr hFile, + IntPtr lpFileMappingAttributes, + FileMapProtection flProtect, + uint dwMaximumSizeHigh, + uint dwMaximumSizeLow, + string lpName); + + [Flags] + public enum FileMapProtection : uint + { + PageReadonly = 0x02, + PageReadWrite = 0x04, + PageWriteCopy = 0x08, + PageExecuteRead = 0x20, + PageExecuteReadWrite = 0x40, + SectionCommit = 0x8000000, + SectionImage = 0x1000000, + SectionNoCache = 0x10000000, + SectionReserve = 0x4000000, + } + + [DllImport("kernel32.dll", SetLastError = true)] + public static extern bool CloseHandle(IntPtr hObject); + + [DllImport("kernel32.dll", SetLastError = true)] + public static extern bool UnmapViewOfFile(IntPtr lpBaseAddress); + + [DllImport("kernel32.dll")] + public static extern IntPtr MapViewOfFileEx(IntPtr hFileMappingObject, + FileMapAccessType dwDesiredAccess, uint dwFileOffsetHigh, uint dwFileOffsetLow, + UIntPtr dwNumberOfBytesToMap, IntPtr lpBaseAddress); + + [Flags] + public enum FileMapAccessType : uint + { + Copy = 0x01, + Write = 0x02, + Read = 0x04, + AllAccess = 0x08, + Execute = 0x20, + } + + public static readonly IntPtr INVALID_HANDLE_VALUE = Z.US(0xffffffffffffffff); + } + } +} diff --git a/src/BizHawk.BizInvoke/POSIXLibC.cs b/src/BizHawk.BizInvoke/POSIXLibC.cs index 6d61c32b8f..db3e7a956a 100644 --- a/src/BizHawk.BizInvoke/POSIXLibC.cs +++ b/src/BizHawk.BizInvoke/POSIXLibC.cs @@ -1,7 +1,7 @@ using System; using System.Runtime.InteropServices; -using static BizHawk.BizInvoke.MemoryBlockBase; +using static BizHawk.BizInvoke.MemoryBlock; namespace BizHawk.BizInvoke { diff --git a/src/BizHawk.Emulation.Cores/Waterbox/ElfLoader.cs b/src/BizHawk.Emulation.Cores/Waterbox/ElfLoader.cs index 140b169ec5..c454f2d4cc 100644 --- a/src/BizHawk.Emulation.Cores/Waterbox/ElfLoader.cs +++ b/src/BizHawk.Emulation.Cores/Waterbox/ElfLoader.cs @@ -33,7 +33,7 @@ namespace BizHawk.Emulation.Cores.Waterbox private bool _everythingSealed; - public MemoryBlockBase Memory { get; private set; } + public MemoryBlock Memory { get; private set; } public string ModuleName { get; } @@ -94,9 +94,9 @@ namespace BizHawk.Emulation.Cores.Waterbox .ToList(); - Memory = MemoryBlock.CallPlatformCtor(start, size); + Memory = MemoryBlock.Create(start, size); Memory.Activate(); - Memory.Protect(Memory.Start, Memory.Size, MemoryBlockBase.Protection.RW); + Memory.Protect(Memory.Start, Memory.Size, MemoryBlock.Protection.RW); foreach (var seg in loadsegs) { @@ -170,23 +170,23 @@ namespace BizHawk.Emulation.Cores.Waterbox /// private void Protect() { - Memory.Protect(Memory.Start, Memory.Size, MemoryBlockBase.Protection.R); + Memory.Protect(Memory.Start, Memory.Size, MemoryBlock.Protection.R); foreach (var sec in _elf.Sections.Where(s => (s.Flags & SectionFlags.Allocatable) != 0)) { if (_everythingSealed && IsSpecialReadonlySection(sec)) continue; if ((sec.Flags & SectionFlags.Executable) != 0) - Memory.Protect(sec.LoadAddress, sec.Size, MemoryBlockBase.Protection.RX); + Memory.Protect(sec.LoadAddress, sec.Size, MemoryBlock.Protection.RX); else if ((sec.Flags & SectionFlags.Writable) != 0) - Memory.Protect(sec.LoadAddress, sec.Size, MemoryBlockBase.Protection.RW); + Memory.Protect(sec.LoadAddress, sec.Size, MemoryBlock.Protection.RW); } } // connect all of the .wbxsyscall stuff public void ConnectSyscalls(IImportResolver syscalls) { - Memory.Protect(Memory.Start, Memory.Size, MemoryBlockBase.Protection.RW); + Memory.Protect(Memory.Start, Memory.Size, MemoryBlock.Protection.RW); var tmp = new IntPtr[1]; var ptrSize = (ulong)IntPtr.Size; @@ -343,7 +343,7 @@ namespace BizHawk.Emulation.Cores.Waterbox throw new InvalidOperationException("Memory consistency check failed. Is this savestate from different SyncSettings?"); } - Memory.Protect(Memory.Start, Memory.Size, MemoryBlockBase.Protection.RW); + Memory.Protect(Memory.Start, Memory.Size, MemoryBlock.Protection.RW); foreach (var s in _savedSections) { diff --git a/src/BizHawk.Emulation.Cores/Waterbox/Heap.cs b/src/BizHawk.Emulation.Cores/Waterbox/Heap.cs index 24d0629dec..9ac0916276 100644 --- a/src/BizHawk.Emulation.Cores/Waterbox/Heap.cs +++ b/src/BizHawk.Emulation.Cores/Waterbox/Heap.cs @@ -11,7 +11,7 @@ namespace BizHawk.Emulation.Cores.Waterbox /// internal sealed class Heap : IBinaryStateable, IDisposable { - public MemoryBlockBase Memory { get; private set; } + public MemoryBlock Memory { get; private set; } /// /// name, used in identifying errors /// @@ -30,7 +30,7 @@ namespace BizHawk.Emulation.Cores.Waterbox public Heap(ulong start, ulong size, string name) { - Memory = MemoryBlockBase.CallPlatformCtor(start, size); + Memory = MemoryBlock.Create(start, size); Used = 0; Name = name; Console.WriteLine("Created heap `{1}` at {0:x16}:{2:x16}", start, name, start + size); @@ -62,7 +62,7 @@ namespace BizHawk.Emulation.Cores.Waterbox throw new InvalidOperationException($"Failed to allocate {size} bytes from heap {Name}"); } ulong ret = Memory.Start + allocstart; - Memory.Protect(Memory.Start + Used, newused - Used, MemoryBlockBase.Protection.RW); + Memory.Protect(Memory.Start + Used, newused - Used, MemoryBlock.Protection.RW); Used = newused; Console.WriteLine($"Allocated {size} bytes on {Name}, utilization {Used}/{Memory.Size} ({100.0 * Used / Memory.Size:0.#}%)"); return ret; @@ -72,7 +72,7 @@ namespace BizHawk.Emulation.Cores.Waterbox { if (!Sealed) { - Memory.Protect(Memory.Start, Used, MemoryBlockBase.Protection.R); + Memory.Protect(Memory.Start, Used, MemoryBlock.Protection.R); _hash = WaterboxUtils.Hash(Memory.GetStream(Memory.Start, Used, false)); Sealed = true; } @@ -116,8 +116,8 @@ namespace BizHawk.Emulation.Cores.Waterbox } var usedAligned = WaterboxUtils.AlignUp(used); - Memory.Protect(Memory.Start, Memory.Size, MemoryBlockBase.Protection.None); - Memory.Protect(Memory.Start, used, MemoryBlockBase.Protection.RW); + Memory.Protect(Memory.Start, Memory.Size, MemoryBlock.Protection.None); + Memory.Protect(Memory.Start, used, MemoryBlock.Protection.RW); var ms = Memory.GetXorStream(Memory.Start, usedAligned, true); WaterboxUtils.CopySome(br.BaseStream, ms, (long)usedAligned); Used = used; diff --git a/src/BizHawk.Emulation.Cores/Waterbox/MapHeap.cs b/src/BizHawk.Emulation.Cores/Waterbox/MapHeap.cs index 8b34a4aff3..f6cac6282d 100644 --- a/src/BizHawk.Emulation.Cores/Waterbox/MapHeap.cs +++ b/src/BizHawk.Emulation.Cores/Waterbox/MapHeap.cs @@ -13,7 +13,7 @@ namespace BizHawk.Emulation.Cores.Waterbox /// internal sealed class MapHeap : IBinaryStateable, IDisposable { - public MemoryBlockBase Memory { get; private set; } + public MemoryBlock Memory { get; private set; } /// /// name, used in identifying errors /// @@ -40,18 +40,18 @@ namespace BizHawk.Emulation.Cores.Waterbox return ((ulong)page << WaterboxUtils.PageShift) + Memory.Start; } - private const MemoryBlockBase.Protection FREE = (MemoryBlockBase.Protection)255; + private const MemoryBlock.Protection FREE = (MemoryBlock.Protection)255; - private readonly MemoryBlockBase.Protection[] _pages; + private readonly MemoryBlock.Protection[] _pages; private readonly byte[] _pagesAsBytes; public MapHeap(ulong start, ulong size, string name) { size = WaterboxUtils.AlignUp(size); - Memory = MemoryBlockBase.CallPlatformCtor(start, size); + Memory = MemoryBlock.Create(start, size); Name = name; _pagesAsBytes = new byte[size >> WaterboxUtils.PageShift]; - _pages = (MemoryBlockBase.Protection[])(object)_pagesAsBytes; + _pages = (MemoryBlock.Protection[])(object)_pagesAsBytes; for (var i = 0; i < _pages.Length; i++) _pages[i] = FREE; Console.WriteLine($"Created {nameof(MapHeap)} `{name}` at {start:x16}:{start + size:x16}"); @@ -102,7 +102,7 @@ namespace BizHawk.Emulation.Cores.Waterbox return -1; } - private void ProtectInternal(int startPage, int numPages, MemoryBlockBase.Protection prot, bool wasUsed) + private void ProtectInternal(int startPage, int numPages, MemoryBlock.Protection prot, bool wasUsed) { for (var i = startPage; i < startPage + numPages; i++) _pages[i] = prot; @@ -111,9 +111,9 @@ namespace BizHawk.Emulation.Cores.Waterbox ulong length = ((ulong)numPages) << WaterboxUtils.PageShift; if (prot == FREE) { - Memory.Protect(start, length, MemoryBlockBase.Protection.RW); + Memory.Protect(start, length, MemoryBlock.Protection.RW); WaterboxUtils.ZeroMemory(Z.US(start), (long)length); - Memory.Protect(start, length, MemoryBlockBase.Protection.None); + Memory.Protect(start, length, MemoryBlock.Protection.None); Used -= length; Console.WriteLine($"Freed {length} bytes on {Name}, utilization {Used}/{Memory.Size} ({100.0 * Used / Memory.Size:0.#}%)"); } @@ -142,7 +142,7 @@ namespace BizHawk.Emulation.Cores.Waterbox var p = _pages[i]; ulong zstart = GetStartAddr(ps); ulong zlength = (ulong)(i - ps + 1) << WaterboxUtils.PageShift; - Memory.Protect(zstart, zlength, p == FREE ? MemoryBlockBase.Protection.None : p); + Memory.Protect(zstart, zlength, p == FREE ? MemoryBlock.Protection.None : p); ps = i + 1; } } @@ -161,7 +161,7 @@ namespace BizHawk.Emulation.Cores.Waterbox return true; } - public ulong Map(ulong size, MemoryBlockBase.Protection prot) + public ulong Map(ulong size, MemoryBlock.Protection prot) { if (size == 0) return 0; @@ -216,14 +216,14 @@ namespace BizHawk.Emulation.Cores.Waterbox var copyPageLen = Math.Min(oldNumPages, newNumPages); var data = new byte[copyDataLen]; - Memory.Protect(start, copyDataLen, MemoryBlockBase.Protection.RW); + Memory.Protect(start, copyDataLen, MemoryBlock.Protection.RW); Marshal.Copy(Z.US(start), data, 0, (int)copyDataLen); - var pages = new MemoryBlockBase.Protection[copyPageLen]; + var pages = new MemoryBlock.Protection[copyPageLen]; Array.Copy(_pages, oldStartPage, pages, 0, copyPageLen); ProtectInternal(oldStartPage, oldNumPages, FREE, true); - ProtectInternal(newStartPage, newNumPages, MemoryBlockBase.Protection.RW, false); + ProtectInternal(newStartPage, newNumPages, MemoryBlock.Protection.RW, false); var ret = GetStartAddr(newStartPage); Marshal.Copy(data, 0, Z.US(ret), (int)copyDataLen); @@ -241,7 +241,7 @@ namespace BizHawk.Emulation.Cores.Waterbox return Protect(start, size, FREE); } - public bool Protect(ulong start, ulong size, MemoryBlockBase.Protection prot) + public bool Protect(ulong start, ulong size, MemoryBlock.Protection prot) { if (start < Memory.Start || start + size > Memory.EndExclusive || size == 0) return false; @@ -274,7 +274,7 @@ namespace BizHawk.Emulation.Cores.Waterbox bw.Write(Memory.XorHash); bw.Write(_pagesAsBytes); - Memory.Protect(Memory.Start, Memory.Size, MemoryBlockBase.Protection.R); + Memory.Protect(Memory.Start, Memory.Size, MemoryBlock.Protection.R); var srcs = Memory.GetXorStream(Memory.Start, Memory.Size, false); for (int i = 0, addr = 0; i < _pages.Length; i++, addr += WaterboxUtils.PageSize) { @@ -305,7 +305,7 @@ namespace BizHawk.Emulation.Cores.Waterbox throw new InvalidOperationException("Unexpected error reading!"); Used = 0; - Memory.Protect(Memory.Start, Memory.Size, MemoryBlockBase.Protection.RW); + Memory.Protect(Memory.Start, Memory.Size, MemoryBlock.Protection.RW); var dsts = Memory.GetXorStream(Memory.Start, Memory.Size, true); for (int i = 0, addr = 0; i < _pages.Length; i++, addr += WaterboxUtils.PageSize) { @@ -333,7 +333,7 @@ namespace BizHawk.Emulation.Cores.Waterbox { ulong siz = (ulong)(rnd.Next(256 * 1024) + 384 * 1024); siz = siz / 4096 * 4096; - var ptr = mmo.Map(siz, MemoryBlockBase.Protection.RW); + var ptr = mmo.Map(siz, MemoryBlock.Protection.RW); allocs.Add(ptr, siz); } @@ -349,7 +349,7 @@ namespace BizHawk.Emulation.Cores.Waterbox { ulong siz = (ulong)(rnd.Next(256 * 1024) + 384 * 1024); siz = siz / 4096 * 4096; - var ptr = mmo.Map(siz, MemoryBlockBase.Protection.RW); + var ptr = mmo.Map(siz, MemoryBlock.Protection.RW); allocs.Add(ptr, siz); } diff --git a/src/BizHawk.Emulation.Cores/Waterbox/Swappable.cs b/src/BizHawk.Emulation.Cores/Waterbox/Swappable.cs index a84431ffb7..64c9aa9a4e 100644 --- a/src/BizHawk.Emulation.Cores/Waterbox/Swappable.cs +++ b/src/BizHawk.Emulation.Cores/Waterbox/Swappable.cs @@ -28,14 +28,14 @@ namespace BizHawk.Emulation.Cores.Waterbox /// /// everything to swap in for context switches /// - private List _memoryBlocks = new List(); + private List _memoryBlocks = new List(); /// /// an informative name for each memory block: used for debugging purposes /// private List _memoryBlockNames = new List(); - protected void AddMemoryBlock(MemoryBlockBase block, string name) + protected void AddMemoryBlock(MemoryBlock block, string name) { _memoryBlocks.Add(block); _memoryBlockNames.Add(name); diff --git a/src/BizHawk.Emulation.Cores/Waterbox/Syscalls.cs b/src/BizHawk.Emulation.Cores/Waterbox/Syscalls.cs index e36c31d767..fd8428a0ca 100644 --- a/src/BizHawk.Emulation.Cores/Waterbox/Syscalls.cs +++ b/src/BizHawk.Emulation.Cores/Waterbox/Syscalls.cs @@ -399,18 +399,18 @@ namespace BizHawk.Emulation.Cores.Waterbox { if (address != IntPtr.Zero) return Z.SS(-1); - MemoryBlockBase.Protection mprot; + MemoryBlock.Protection mprot; switch (prot) { - case 0: mprot = MemoryBlockBase.Protection.None; break; + case 0: mprot = MemoryBlock.Protection.None; break; default: case 6: // W^X case 7: // W^X case 4: // exec only???? case 2: return Z.SS(-1); // write only???? - case 3: mprot = MemoryBlockBase.Protection.RW; break; - case 1: mprot = MemoryBlockBase.Protection.R; break; - case 5: mprot = MemoryBlockBase.Protection.RX; break; + case 3: mprot = MemoryBlock.Protection.RW; break; + case 1: mprot = MemoryBlock.Protection.R; break; + case 5: mprot = MemoryBlock.Protection.RX; break; } if ((flags & 0x20) == 0) { @@ -448,18 +448,18 @@ namespace BizHawk.Emulation.Cores.Waterbox [BizExport(CallingConvention.Cdecl, EntryPoint = "__wsyscalltab[10]")] public int MProtect(UIntPtr address, UIntPtr size, int prot) { - MemoryBlockBase.Protection mprot; + MemoryBlock.Protection mprot; switch (prot) { - case 0: mprot = MemoryBlockBase.Protection.None; break; + case 0: mprot = MemoryBlock.Protection.None; break; default: case 6: // W^X case 7: // W^X case 4: // exec only???? case 2: return -1; // write only???? - case 3: mprot = MemoryBlockBase.Protection.RW; break; - case 1: mprot = MemoryBlockBase.Protection.R; break; - case 5: mprot = MemoryBlockBase.Protection.RX; break; + case 3: mprot = MemoryBlock.Protection.RW; break; + case 1: mprot = MemoryBlock.Protection.R; break; + case 5: mprot = MemoryBlock.Protection.RX; break; } return _parent._mmapheap.Protect((ulong)address, (ulong)size, mprot) ? 0 : -1; }