Extract superclass from MemoryBase and start on a Unix implementation
This commit is contained in:
parent
1f8972df4e
commit
db020e499e
|
@ -62,8 +62,11 @@
|
|||
<Compile Include="BizInvoke\BizInvoker.cs" />
|
||||
<Compile Include="BizInvoke\BizInvokeUtilities.cs" />
|
||||
<Compile Include="BizInvoke\CallingConventionAdapter.cs" />
|
||||
<Compile Include="BizInvoke\POSIXLibC.cs" />
|
||||
<Compile Include="BizInvoke\DynamicLibraryImportResolver.cs" />
|
||||
<Compile Include="BizInvoke\MemoryBlock.cs" />
|
||||
<Compile Include="BizInvoke\MemoryBlockBase.cs" />
|
||||
<Compile Include="BizInvoke\MemoryBlockUnix.cs" />
|
||||
<Compile Include="BizInvoke\WaterboxUtils.cs" />
|
||||
<Compile Include="Buffer.cs" />
|
||||
<Compile Include="Colors.cs" />
|
||||
|
|
|
@ -133,14 +133,14 @@ namespace BizHawk.Common.BizInvoke
|
|||
throw new InvalidOperationException();
|
||||
}
|
||||
|
||||
private readonly MemoryBlock _memory;
|
||||
private readonly MemoryBlockBase _memory;
|
||||
private readonly object _sync = new object();
|
||||
private readonly WeakReference[] _refs;
|
||||
|
||||
public SysVHostMsGuest()
|
||||
{
|
||||
int size = 4 * 1024 * 1024;
|
||||
_memory = new MemoryBlock((ulong)size);
|
||||
_memory = MemoryBlockBase.CallPlatformCtor((ulong)size);
|
||||
_memory.Activate();
|
||||
_refs = new WeakReference[size / BlockSize];
|
||||
}
|
||||
|
@ -186,7 +186,7 @@ namespace BizHawk.Common.BizInvoke
|
|||
|
||||
private void WriteThunk(byte[] data, int placeholderIndex, IntPtr p, int index)
|
||||
{
|
||||
_memory.Protect(_memory.Start, _memory.Size, MemoryBlock.Protection.RW);
|
||||
_memory.Protect(_memory.Start, _memory.Size, MemoryBlockBase.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++)
|
||||
|
@ -194,7 +194,7 @@ namespace BizHawk.Common.BizInvoke
|
|||
ss.Position = placeholderIndex;
|
||||
var bw = new BinaryWriter(ss);
|
||||
bw.Write((long)p);
|
||||
_memory.Protect(_memory.Start, _memory.Size, MemoryBlock.Protection.RX);
|
||||
_memory.Protect(_memory.Start, _memory.Size, MemoryBlockBase.Protection.RX);
|
||||
}
|
||||
|
||||
private IntPtr GetThunkAddress(int index)
|
||||
|
|
|
@ -1,105 +1,33 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.IO;
|
||||
|
||||
namespace BizHawk.Common.BizInvoke
|
||||
{
|
||||
public sealed class MemoryBlock : IDisposable
|
||||
public sealed class MemoryBlock : MemoryBlockBase
|
||||
{
|
||||
/// <summary>
|
||||
/// starting address of the memory block
|
||||
/// </summary>
|
||||
public ulong Start { get; private set; }
|
||||
/// <summary>
|
||||
/// total size of the memory block
|
||||
/// </summary>
|
||||
public ulong Size { get; private set; }
|
||||
/// <summary>
|
||||
/// ending address of the memory block; equal to start + size
|
||||
/// </summary>
|
||||
public ulong End { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// handle returned by CreateFileMapping
|
||||
/// </summary>
|
||||
private IntPtr _handle;
|
||||
|
||||
/// <summary>
|
||||
/// true if this is currently swapped in
|
||||
/// </summary>
|
||||
public bool Active { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// stores last set memory protection value for each page
|
||||
/// </summary>
|
||||
private readonly Protection[] _pageData;
|
||||
|
||||
/// <summary>
|
||||
/// snapshot for XOR buffer
|
||||
/// </summary>
|
||||
private byte[] _snapshot;
|
||||
|
||||
public byte[] XorHash { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// get a page index within the block
|
||||
/// </summary>
|
||||
private int GetPage(ulong addr)
|
||||
{
|
||||
if (addr < Start || addr >= End)
|
||||
throw new ArgumentOutOfRangeException();
|
||||
|
||||
return (int)((addr - Start) >> WaterboxUtils.PageShift);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// get a start address for a page index within the block
|
||||
/// </summary>
|
||||
private ulong GetStartAddr(int page)
|
||||
{
|
||||
return ((ulong)page << WaterboxUtils.PageShift) + Start;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// allocate size bytes at any address
|
||||
/// </summary>
|
||||
public MemoryBlock(ulong size)
|
||||
: this(0, size)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// allocate size bytes starting at a particular address
|
||||
/// </summary>
|
||||
public MemoryBlock(ulong start, ulong size)
|
||||
public MemoryBlock(ulong start, ulong size) : base(start, size)
|
||||
{
|
||||
if (OSTailoredCode.CurrentOS != OSTailoredCode.DistinctOS.Windows)
|
||||
throw new InvalidOperationException("MemoryBlock ctor called on Unix");
|
||||
|
||||
if (!WaterboxUtils.Aligned(start))
|
||||
throw new ArgumentOutOfRangeException();
|
||||
if (size == 0)
|
||||
throw new ArgumentOutOfRangeException();
|
||||
size = WaterboxUtils.AlignUp(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");
|
||||
Start = start;
|
||||
End = start + size;
|
||||
Size = size;
|
||||
_pageData = new Protection[GetPage(End - 1) + 1];
|
||||
_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");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// activate the memory block, swapping it in at the specified address
|
||||
/// </summary>
|
||||
public void Activate()
|
||||
public override void Activate()
|
||||
{
|
||||
if (Active)
|
||||
throw new InvalidOperationException("Already active");
|
||||
|
@ -112,10 +40,7 @@ namespace BizHawk.Common.BizInvoke
|
|||
Active = true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// deactivate the memory block, removing it from RAM but leaving it immediately available to swap back in
|
||||
/// </summary>
|
||||
public void Deactivate()
|
||||
public override void Deactivate()
|
||||
{
|
||||
if (!Active)
|
||||
throw new InvalidOperationException("Not active");
|
||||
|
@ -124,47 +49,7 @@ namespace BizHawk.Common.BizInvoke
|
|||
Active = false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Memory protection constant
|
||||
/// </summary>
|
||||
public enum Protection : byte
|
||||
{
|
||||
None, R, RW, RX
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get a stream that can be used to read or write from part of the block. Does not check for or change Protect()!
|
||||
/// </summary>
|
||||
public Stream GetStream(ulong start, ulong length, bool writer)
|
||||
{
|
||||
if (start < Start)
|
||||
throw new ArgumentOutOfRangeException(nameof(start));
|
||||
if (start + length > End)
|
||||
throw new ArgumentOutOfRangeException(nameof(length));
|
||||
|
||||
return new MemoryViewStream(!writer, writer, (long)start, (long)length, this);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 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
|
||||
/// </summary>
|
||||
public Stream GetXorStream(ulong start, ulong length, bool writer)
|
||||
{
|
||||
if (start < Start)
|
||||
throw new ArgumentOutOfRangeException(nameof(start));
|
||||
if (start + length > End)
|
||||
throw new ArgumentOutOfRangeException(nameof(length));
|
||||
if (_snapshot == null)
|
||||
throw new InvalidOperationException("No snapshot taken!");
|
||||
|
||||
return new MemoryViewXorStream(!writer, writer, (long)start, (long)length, this, _snapshot, (long)(start - Start));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// take a snapshot of the entire memory block's contents, for use in GetXorStream
|
||||
/// </summary>
|
||||
public void SaveXorSnapshot()
|
||||
public override void SaveXorSnapshot()
|
||||
{
|
||||
if (_snapshot != null)
|
||||
throw new InvalidOperationException("Snapshot already taken");
|
||||
|
@ -186,10 +71,7 @@ namespace BizHawk.Common.BizInvoke
|
|||
ProtectAll();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// take a hash of the current full contents of the block, including unreadable areas
|
||||
/// </summary>
|
||||
public byte[] FullHash()
|
||||
public override byte[] FullHash()
|
||||
{
|
||||
if (!Active)
|
||||
throw new InvalidOperationException("Not active");
|
||||
|
@ -216,10 +98,7 @@ namespace BizHawk.Common.BizInvoke
|
|||
return p;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// restore all recorded protections
|
||||
/// </summary>
|
||||
private void ProtectAll()
|
||||
protected override void ProtectAll()
|
||||
{
|
||||
int ps = 0;
|
||||
for (int i = 0; i < _pageData.Length; i++)
|
||||
|
@ -237,10 +116,7 @@ namespace BizHawk.Common.BizInvoke
|
|||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// set r/w/x protection on a portion of memory. rounded to encompassing pages
|
||||
/// </summary>
|
||||
public void Protect(ulong start, ulong length, Protection prot)
|
||||
public override void Protect(ulong start, ulong length, Protection prot)
|
||||
{
|
||||
if (length == 0)
|
||||
return;
|
||||
|
@ -264,13 +140,7 @@ namespace BizHawk.Common.BizInvoke
|
|||
}
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
Dispose(true);
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
|
||||
private void Dispose(bool disposing)
|
||||
public override void Dispose(bool disposing)
|
||||
{
|
||||
if (_handle != IntPtr.Zero)
|
||||
{
|
||||
|
@ -286,159 +156,6 @@ namespace BizHawk.Common.BizInvoke
|
|||
Dispose(false);
|
||||
}
|
||||
|
||||
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 void EnsureNotDisposed()
|
||||
{
|
||||
if (_owner.Start == 0)
|
||||
throw new ObjectDisposedException(nameof(MemoryBlock));
|
||||
}
|
||||
|
||||
private MemoryBlock _owner;
|
||||
|
||||
private readonly bool _readable;
|
||||
private readonly bool _writable;
|
||||
|
||||
private long _length;
|
||||
private long _pos;
|
||||
private readonly long _ptr;
|
||||
|
||||
public override bool CanRead => _readable;
|
||||
public override bool CanSeek => true;
|
||||
public override bool CanWrite => _writable;
|
||||
public override void Flush() { }
|
||||
public override long Length => _length;
|
||||
|
||||
public override long Position
|
||||
{
|
||||
get { return _pos; }
|
||||
set
|
||||
{
|
||||
if (value < 0 || value > _length)
|
||||
throw new ArgumentOutOfRangeException();
|
||||
_pos = value;
|
||||
}
|
||||
}
|
||||
|
||||
public override int Read(byte[] buffer, int offset, int count)
|
||||
{
|
||||
if (!_readable)
|
||||
throw new InvalidOperationException();
|
||||
if (count < 0 || count + offset > buffer.Length)
|
||||
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 || count + offset > buffer.Length)
|
||||
throw new ArgumentOutOfRangeException();
|
||||
if (count > _length - _pos)
|
||||
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;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// the initial data to XOR against for both reading and writing
|
||||
/// </summary>
|
||||
private readonly byte[] _initial;
|
||||
/// <summary>
|
||||
/// offset into the XOR data that this stream is representing
|
||||
/// </summary>
|
||||
private readonly int _offset;
|
||||
|
||||
public override int Read(byte[] buffer, int offset, int count)
|
||||
{
|
||||
int 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)
|
||||
{
|
||||
int pos = (int)Position;
|
||||
if (count < 0 || count + offset > buffer.Length)
|
||||
throw new ArgumentOutOfRangeException();
|
||||
if (count > Length - pos)
|
||||
throw new ArgumentOutOfRangeException();
|
||||
// is mutating the buffer passed to Stream.Write kosher?
|
||||
XorTransform(_initial, _offset + pos, buffer, offset, count);
|
||||
base.Write(buffer, offset, count);
|
||||
}
|
||||
|
||||
private static unsafe void XorTransform(byte[] source, int sourceOffset, byte[] dest, int destOffset, int length)
|
||||
{
|
||||
// we don't do any bounds check because MemoryViewStream.Read and MemoryViewXorStream.Write already did it
|
||||
|
||||
// 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++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static class Kernel32
|
||||
{
|
||||
[DllImport("kernel32.dll", SetLastError = true)]
|
||||
|
|
|
@ -0,0 +1,245 @@
|
|||
using System;
|
||||
using System.IO;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace BizHawk.Common.BizInvoke
|
||||
{
|
||||
public abstract class MemoryBlockBase : IDisposable
|
||||
{
|
||||
protected MemoryBlockBase(ulong start, ulong size)
|
||||
{
|
||||
if (!WaterboxUtils.Aligned(start)) throw new ArgumentOutOfRangeException();
|
||||
if (size == 0) throw new ArgumentOutOfRangeException();
|
||||
Start = start;
|
||||
Size = WaterboxUtils.AlignUp(size);
|
||||
End = Start + Size;
|
||||
_pageData = new Protection[GetPage(End - 1) + 1];
|
||||
}
|
||||
|
||||
/// <summary>stores last set memory protection value for each page</summary>
|
||||
protected readonly Protection[] _pageData;
|
||||
|
||||
/// <summary>ending address of the memory block; equal to <see cref="Start"/> + <see cref="Size"/></summary>
|
||||
public readonly ulong End;
|
||||
|
||||
/// <summary>total size of the memory block</summary>
|
||||
public readonly ulong Size;
|
||||
|
||||
/// <summary>starting address of the memory block</summary>
|
||||
public readonly ulong Start;
|
||||
|
||||
/// <summary>snapshot for XOR buffer</summary>
|
||||
protected byte[] _snapshot;
|
||||
|
||||
/// <summary>true if this is currently swapped in</summary>
|
||||
public bool Active { get; protected set; }
|
||||
|
||||
public byte[] XorHash { get; protected set; }
|
||||
|
||||
/// <summary>get a page index within the block</summary>
|
||||
protected int GetPage(ulong addr)
|
||||
{
|
||||
if (addr < Start || End <= addr) throw new ArgumentOutOfRangeException();
|
||||
return (int) ((addr - Start) >> WaterboxUtils.PageShift);
|
||||
}
|
||||
|
||||
/// <summary>get a start address for a page index within the block</summary>
|
||||
protected ulong GetStartAddr(int page) => ((ulong) page << WaterboxUtils.PageShift) + Start;
|
||||
|
||||
/// <summary>Get a stream that can be used to read or write from part of the block. Does not check for or change <see cref="Protect"/>!</summary>
|
||||
public Stream GetStream(ulong start, ulong length, bool writer)
|
||||
{
|
||||
if (start < Start) throw new ArgumentOutOfRangeException(nameof(start));
|
||||
if (End < start + length) throw new ArgumentOutOfRangeException(nameof(length));
|
||||
return new MemoryViewStream(!writer, writer, (long) start, (long) length, this);
|
||||
}
|
||||
|
||||
/// <summary>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</summary>
|
||||
public Stream GetXorStream(ulong start, ulong length, bool writer)
|
||||
{
|
||||
if (start < Start) throw new ArgumentOutOfRangeException(nameof(start));
|
||||
if (End < start + length) throw new ArgumentOutOfRangeException(nameof(length));
|
||||
if (_snapshot == null) throw new InvalidOperationException("No snapshot taken!");
|
||||
return new MemoryViewXorStream(!writer, writer, (long) start, (long) length, this, _snapshot, (long) (start - Start));
|
||||
}
|
||||
|
||||
/// <summary>activate the memory block, swapping it in at the pre-specified address</summary>
|
||||
public abstract void Activate();
|
||||
|
||||
/// <summary>deactivate the memory block, removing it from RAM but leaving it immediately available to swap back in</summary>
|
||||
public abstract void Deactivate();
|
||||
|
||||
/// <summary>take a hash of the current full contents of the block, including unreadable areas</summary>
|
||||
public abstract byte[] FullHash();
|
||||
|
||||
/// <summary>set r/w/x protection on a portion of memory. rounded to encompassing pages</summary>
|
||||
public abstract void Protect(ulong start, ulong length, Protection prot);
|
||||
|
||||
/// <summary>restore all recorded protections</summary>
|
||||
protected abstract void ProtectAll();
|
||||
|
||||
/// <summary>take a snapshot of the entire memory block's contents, for use in <see cref="GetXorStream"/></summary>
|
||||
public abstract void SaveXorSnapshot();
|
||||
|
||||
public abstract void Dispose(bool disposing);
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
Dispose(true);
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
|
||||
~MemoryBlockBase()
|
||||
{
|
||||
Dispose(false);
|
||||
}
|
||||
|
||||
/// <summary>allocate <paramref name="size"/> bytes starting at a particular address <paramref name="start"/></summary>
|
||||
public static MemoryBlockBase CallPlatformCtor(ulong start, ulong size) => OSTailoredCode.CurrentOS == OSTailoredCode.DistinctOS.Windows
|
||||
? (MemoryBlockBase) new MemoryBlock(start, size)
|
||||
: new MemoryBlockUnix(start, size);
|
||||
|
||||
/// <summary>allocate <paramref name="size"/> bytes at any address</summary>
|
||||
public static MemoryBlockBase CallPlatformCtor(ulong size) => CallPlatformCtor(0, size);
|
||||
|
||||
/// <summary>Memory protection constant</summary>
|
||||
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 { return _pos; }
|
||||
set
|
||||
{
|
||||
if (value < 0 || _length < value) throw new ArgumentOutOfRangeException();
|
||||
_pos = value;
|
||||
}
|
||||
}
|
||||
|
||||
private void EnsureNotDisposed()
|
||||
{
|
||||
if (_owner.Start == 0) throw new ObjectDisposedException("MemoryBlockBase");
|
||||
}
|
||||
|
||||
/// <remarks>TODO should this call base.Flush()? --yoshi</remarks>
|
||||
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;
|
||||
}
|
||||
|
||||
/// <summary>the initial data to XOR against for both reading and writing</summary>
|
||||
private readonly byte[] _initial;
|
||||
|
||||
/// <summary>offset into the XOR data that this stream is representing</summary>
|
||||
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);
|
||||
}
|
||||
|
||||
/// <remarks>bounds check already done by calling method i.e. in <see cref="MemoryViewStream.Read">base.Read</see> (for <see cref="Read"/>) or in <see cref="Write"/></remarks>
|
||||
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++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,124 @@
|
|||
using System;
|
||||
using System.IO;
|
||||
|
||||
using static BizHawk.Common.POSIXLibC;
|
||||
|
||||
namespace BizHawk.Common.BizInvoke
|
||||
{
|
||||
public sealed class MemoryBlockUnix : MemoryBlockBase
|
||||
{
|
||||
/// <summary>handle returned by <see cref="memfd_create"/></summary>
|
||||
private int _fd;
|
||||
|
||||
/// <summary>allocate <paramref name="size"/> bytes starting at a particular address <paramref name="start"/></summary>
|
||||
public MemoryBlockUnix(ulong start, ulong size) : base(start, size)
|
||||
{
|
||||
throw new NotImplementedException($"{nameof(MemoryBlockUnix)} ctor");
|
||||
_fd = memfd_create("MemoryBlockUnix", 0);
|
||||
if (_fd == -1) throw new InvalidOperationException($"{nameof(memfd_create)}() returned -1");
|
||||
}
|
||||
|
||||
public override void Activate()
|
||||
{
|
||||
if (Active) throw new InvalidOperationException("Already active");
|
||||
|
||||
var ptr = mmap(Z.US(Start), Z.UU(Size), MemoryProtection.Read | MemoryProtection.Write | MemoryProtection.Execute, 16, _fd, IntPtr.Zero);
|
||||
if (ptr != Z.US(Start)) throw new InvalidOperationException($"{nameof(mmap)}() returned NULL or the wrong pointer");
|
||||
|
||||
ProtectAll();
|
||||
Active = true;
|
||||
}
|
||||
|
||||
public override void Deactivate()
|
||||
{
|
||||
if (!Active) throw new InvalidOperationException("Not active");
|
||||
|
||||
var exitCode = munmap(Z.US(Start), Z.UU(Size));
|
||||
if (exitCode != 0) throw new InvalidOperationException($"{nameof(munmap)}() returned {exitCode}");
|
||||
|
||||
Active = false;
|
||||
}
|
||||
|
||||
public override byte[] FullHash()
|
||||
{
|
||||
if (!Active) throw new InvalidOperationException("Not active");
|
||||
|
||||
// temporarily switch the entire block to `R`
|
||||
var exitCode = mprotect(Z.US(Start), Z.UU(Size), MemoryProtection.Read);
|
||||
if (exitCode != 0) throw new InvalidOperationException($"{nameof(mprotect)}() returned {exitCode}!");
|
||||
|
||||
var ret = WaterboxUtils.Hash(GetStream(Start, Size, false));
|
||||
ProtectAll();
|
||||
return ret;
|
||||
}
|
||||
|
||||
public override void Protect(ulong start, ulong length, Protection prot)
|
||||
{
|
||||
if (length == 0) return;
|
||||
|
||||
var pstart = GetPage(start);
|
||||
var pend = GetPage(start + length - 1);
|
||||
for (var i = pstart; i <= pend; i++) _pageData[i] = prot; // also store the value for later use
|
||||
if (!Active) return; // it's legal to call this method if we're not active; the information is just saved for the next activation
|
||||
|
||||
var computedStart = WaterboxUtils.AlignDown(start);
|
||||
var protEnum = prot.ToMemoryProtection();
|
||||
var exitCode = mprotect(
|
||||
Z.US(computedStart),
|
||||
Z.UU(WaterboxUtils.AlignUp(start + length) - computedStart),
|
||||
protEnum
|
||||
);
|
||||
if (exitCode != 0) throw new InvalidOperationException($"{nameof(mprotect)}() returned {exitCode}!");
|
||||
}
|
||||
|
||||
protected override void ProtectAll()
|
||||
{
|
||||
var ps = 0;
|
||||
for (var i = 0; i < _pageData.Length; i++)
|
||||
{
|
||||
if (i == _pageData.Length - 1 || _pageData[i] != _pageData[i + 1])
|
||||
{
|
||||
var protEnum = _pageData[i].ToMemoryProtection();
|
||||
var zstart = GetStartAddr(ps);
|
||||
var exitCode = mprotect(
|
||||
Z.US(zstart),
|
||||
Z.UU(GetStartAddr(i + 1) - zstart),
|
||||
protEnum
|
||||
);
|
||||
if (exitCode != 0) throw new InvalidOperationException($"{nameof(mprotect)}() returned {exitCode}!");
|
||||
|
||||
ps = i + 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
var exitCode = mprotect(Z.US(Start), Z.UU(Size), MemoryProtection.Read);
|
||||
if (exitCode != 0) throw new InvalidOperationException($"{nameof(mprotect)}() returned {exitCode}!");
|
||||
|
||||
_snapshot = new byte[Size];
|
||||
GetStream(Start, Size, false).CopyTo(new MemoryStream(_snapshot, true));
|
||||
XorHash = WaterboxUtils.Hash(_snapshot);
|
||||
ProtectAll();
|
||||
}
|
||||
|
||||
public override void Dispose(bool disposing)
|
||||
{
|
||||
if (_fd == 0) return;
|
||||
|
||||
if (Active) Deactivate();
|
||||
close(_fd);
|
||||
_fd = -1;
|
||||
}
|
||||
|
||||
~MemoryBlockUnix()
|
||||
{
|
||||
Dispose(false);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,45 @@
|
|||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
using static BizHawk.Common.BizInvoke.MemoryBlockBase;
|
||||
|
||||
namespace BizHawk.Common
|
||||
{
|
||||
public static class POSIXLibC
|
||||
{
|
||||
[DllImport("libc.so.6")]
|
||||
public static extern int close(int fd);
|
||||
|
||||
[DllImport("libc.so.6")]
|
||||
public static extern int memfd_create(string name, uint flags);
|
||||
|
||||
[DllImport("libc.so.6")]
|
||||
private static extern IntPtr mmap(IntPtr addr, UIntPtr length, int prot, int flags, int fd, IntPtr offset);
|
||||
|
||||
public static IntPtr mmap(IntPtr addr, UIntPtr length, MemoryProtection prot, int flags, int fd, IntPtr offset) => mmap(addr, length, (int) prot, flags, fd, offset);
|
||||
|
||||
[DllImport("libc.so.6")]
|
||||
private static extern int mprotect(IntPtr addr, UIntPtr len, int prot);
|
||||
|
||||
public static int mprotect(IntPtr addr, UIntPtr len, MemoryProtection prot) => mprotect(addr, len, (int) prot);
|
||||
|
||||
[DllImport("libc.so.6")]
|
||||
public static extern int munmap(IntPtr addr, UIntPtr length);
|
||||
|
||||
/// <remarks>32-bit signed int</remarks>
|
||||
[Flags]
|
||||
public enum MemoryProtection { None = 0x0, Read = 0x1, Write = 0x2, Execute = 0x4 }
|
||||
|
||||
public static MemoryProtection ToMemoryProtection(this Protection prot)
|
||||
{
|
||||
switch (prot)
|
||||
{
|
||||
case Protection.None: return MemoryProtection.None;
|
||||
case Protection.R: return MemoryProtection.Read;
|
||||
case Protection.RW: return MemoryProtection.Read | MemoryProtection.Write;
|
||||
case Protection.RX: return MemoryProtection.Read | MemoryProtection.Execute;
|
||||
default: throw new ArgumentOutOfRangeException(nameof(prot));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -27,7 +27,7 @@ namespace BizHawk.Emulation.Cores.Waterbox
|
|||
/// <summary>
|
||||
/// executable is loaded here
|
||||
/// </summary>
|
||||
private MemoryBlock _base;
|
||||
private MemoryBlockBase _base;
|
||||
/// <summary>
|
||||
/// standard malloc() heap
|
||||
/// </summary>
|
||||
|
@ -77,14 +77,14 @@ namespace BizHawk.Emulation.Cores.Waterbox
|
|||
long orig_end = loadsegs.Max(s => s.Address + s.Size);
|
||||
if (HasRelocations())
|
||||
{
|
||||
_base = new MemoryBlock((ulong)(orig_end - orig_start));
|
||||
_base = MemoryBlockBase.CallPlatformCtor((ulong)(orig_end - orig_start));
|
||||
_loadoffset = (long)_base.Start - orig_start;
|
||||
Initialize(0);
|
||||
}
|
||||
else
|
||||
{
|
||||
Initialize((ulong)orig_start);
|
||||
_base = new MemoryBlock((ulong)orig_start, (ulong)(orig_end - orig_start));
|
||||
_base = MemoryBlockBase.CallPlatformCtor((ulong)orig_start, (ulong)(orig_end - orig_start));
|
||||
_loadoffset = 0;
|
||||
Enter();
|
||||
}
|
||||
|
@ -94,7 +94,7 @@ namespace BizHawk.Emulation.Cores.Waterbox
|
|||
_disposeList.Add(_base);
|
||||
AddMemoryBlock(_base, "elf");
|
||||
_base.Activate();
|
||||
_base.Protect(_base.Start, _base.Size, MemoryBlock.Protection.RW);
|
||||
_base.Protect(_base.Start, _base.Size, MemoryBlockBase.Protection.RW);
|
||||
|
||||
foreach (var seg in loadsegs)
|
||||
{
|
||||
|
@ -104,14 +104,14 @@ namespace BizHawk.Emulation.Cores.Waterbox
|
|||
RegisterSymbols();
|
||||
ProcessRelocations();
|
||||
|
||||
_base.Protect(_base.Start, _base.Size, MemoryBlock.Protection.R);
|
||||
_base.Protect(_base.Start, _base.Size, MemoryBlockBase.Protection.R);
|
||||
|
||||
foreach (var sec in _elf.Sections.Where(s => (s.Flags & SectionFlags.Allocatable) != 0))
|
||||
{
|
||||
if ((sec.Flags & SectionFlags.Executable) != 0)
|
||||
_base.Protect((ulong)(sec.LoadAddress + _loadoffset), (ulong)sec.Size, MemoryBlock.Protection.RX);
|
||||
_base.Protect((ulong)(sec.LoadAddress + _loadoffset), (ulong)sec.Size, MemoryBlockBase.Protection.RX);
|
||||
else if ((sec.Flags & SectionFlags.Writable) != 0)
|
||||
_base.Protect((ulong)(sec.LoadAddress + _loadoffset), (ulong)sec.Size, MemoryBlock.Protection.RW);
|
||||
_base.Protect((ulong)(sec.LoadAddress + _loadoffset), (ulong)sec.Size, MemoryBlockBase.Protection.RW);
|
||||
}
|
||||
|
||||
ulong end = _base.End;
|
||||
|
|
|
@ -13,7 +13,7 @@ namespace BizHawk.Emulation.Cores.Waterbox
|
|||
/// </summary>
|
||||
internal sealed class Heap : IBinaryStateable, IDisposable
|
||||
{
|
||||
public MemoryBlock Memory { get; private set; }
|
||||
public MemoryBlockBase Memory { get; private set; }
|
||||
/// <summary>
|
||||
/// name, used in identifying errors
|
||||
/// </summary>
|
||||
|
@ -32,7 +32,7 @@ namespace BizHawk.Emulation.Cores.Waterbox
|
|||
|
||||
public Heap(ulong start, ulong size, string name)
|
||||
{
|
||||
Memory = new MemoryBlock(start, size);
|
||||
Memory = MemoryBlockBase.CallPlatformCtor(start, size);
|
||||
Used = 0;
|
||||
Name = name;
|
||||
Console.WriteLine("Created heap `{1}` at {0:x16}:{2:x16}", start, name, start + size);
|
||||
|
@ -64,7 +64,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, MemoryBlock.Protection.RW);
|
||||
Memory.Protect(Memory.Start + Used, newused - Used, MemoryBlockBase.Protection.RW);
|
||||
Used = newused;
|
||||
Console.WriteLine($"Allocated {size} bytes on {Name}, utilization {Used}/{Memory.Size} ({100.0 * Used / Memory.Size:0.#}%)");
|
||||
return ret;
|
||||
|
@ -74,7 +74,7 @@ namespace BizHawk.Emulation.Cores.Waterbox
|
|||
{
|
||||
if (!Sealed)
|
||||
{
|
||||
Memory.Protect(Memory.Start, Used, MemoryBlock.Protection.R);
|
||||
Memory.Protect(Memory.Start, Used, MemoryBlockBase.Protection.R);
|
||||
_hash = WaterboxUtils.Hash(Memory.GetStream(Memory.Start, Used, false));
|
||||
Sealed = true;
|
||||
}
|
||||
|
@ -118,8 +118,8 @@ namespace BizHawk.Emulation.Cores.Waterbox
|
|||
}
|
||||
var usedAligned = WaterboxUtils.AlignUp(used);
|
||||
|
||||
Memory.Protect(Memory.Start, Memory.Size, MemoryBlock.Protection.None);
|
||||
Memory.Protect(Memory.Start, used, MemoryBlock.Protection.RW);
|
||||
Memory.Protect(Memory.Start, Memory.Size, MemoryBlockBase.Protection.None);
|
||||
Memory.Protect(Memory.Start, used, MemoryBlockBase.Protection.RW);
|
||||
var ms = Memory.GetXorStream(Memory.Start, usedAligned, true);
|
||||
WaterboxUtils.CopySome(br.BaseStream, ms, (long)usedAligned);
|
||||
Used = used;
|
||||
|
|
|
@ -15,7 +15,7 @@ namespace BizHawk.Emulation.Cores.Waterbox
|
|||
/// </summary>
|
||||
internal sealed class MapHeap : IBinaryStateable, IDisposable
|
||||
{
|
||||
public MemoryBlock Memory { get; private set; }
|
||||
public MemoryBlockBase Memory { get; private set; }
|
||||
/// <summary>
|
||||
/// name, used in identifying errors
|
||||
/// </summary>
|
||||
|
@ -42,18 +42,18 @@ namespace BizHawk.Emulation.Cores.Waterbox
|
|||
return ((ulong)page << WaterboxUtils.PageShift) + Memory.Start;
|
||||
}
|
||||
|
||||
private const MemoryBlock.Protection FREE = (MemoryBlock.Protection)255;
|
||||
private const MemoryBlockBase.Protection FREE = (MemoryBlockBase.Protection)255;
|
||||
|
||||
private readonly MemoryBlock.Protection[] _pages;
|
||||
private readonly MemoryBlockBase.Protection[] _pages;
|
||||
private readonly byte[] _pagesAsBytes;
|
||||
|
||||
public MapHeap(ulong start, ulong size, string name)
|
||||
{
|
||||
size = WaterboxUtils.AlignUp(size);
|
||||
Memory = new MemoryBlock(start, size);
|
||||
Memory = MemoryBlockBase.CallPlatformCtor(start, size);
|
||||
Name = name;
|
||||
_pagesAsBytes = new byte[size >> WaterboxUtils.PageShift];
|
||||
_pages = (MemoryBlock.Protection[])(object)_pagesAsBytes;
|
||||
_pages = (MemoryBlockBase.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}");
|
||||
|
@ -104,7 +104,7 @@ namespace BizHawk.Emulation.Cores.Waterbox
|
|||
return -1;
|
||||
}
|
||||
|
||||
private void ProtectInternal(int startPage, int numPages, MemoryBlock.Protection prot, bool wasUsed)
|
||||
private void ProtectInternal(int startPage, int numPages, MemoryBlockBase.Protection prot, bool wasUsed)
|
||||
{
|
||||
for (var i = startPage; i < startPage + numPages; i++)
|
||||
_pages[i] = prot;
|
||||
|
@ -113,9 +113,9 @@ namespace BizHawk.Emulation.Cores.Waterbox
|
|||
ulong length = ((ulong)numPages) << WaterboxUtils.PageShift;
|
||||
if (prot == FREE)
|
||||
{
|
||||
Memory.Protect(start, length, MemoryBlock.Protection.RW);
|
||||
Memory.Protect(start, length, MemoryBlockBase.Protection.RW);
|
||||
WaterboxUtils.ZeroMemory(Z.US(start), (long)length);
|
||||
Memory.Protect(start, length, MemoryBlock.Protection.None);
|
||||
Memory.Protect(start, length, MemoryBlockBase.Protection.None);
|
||||
Used -= length;
|
||||
Console.WriteLine($"Freed {length} bytes on {Name}, utilization {Used}/{Memory.Size} ({100.0 * Used / Memory.Size:0.#}%)");
|
||||
}
|
||||
|
@ -144,7 +144,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 ? MemoryBlock.Protection.None : p);
|
||||
Memory.Protect(zstart, zlength, p == FREE ? MemoryBlockBase.Protection.None : p);
|
||||
ps = i + 1;
|
||||
}
|
||||
}
|
||||
|
@ -163,7 +163,7 @@ namespace BizHawk.Emulation.Cores.Waterbox
|
|||
return true;
|
||||
}
|
||||
|
||||
public ulong Map(ulong size, MemoryBlock.Protection prot)
|
||||
public ulong Map(ulong size, MemoryBlockBase.Protection prot)
|
||||
{
|
||||
if (size == 0)
|
||||
return 0;
|
||||
|
@ -218,14 +218,14 @@ namespace BizHawk.Emulation.Cores.Waterbox
|
|||
var copyPageLen = Math.Min(oldNumPages, newNumPages);
|
||||
|
||||
var data = new byte[copyDataLen];
|
||||
Memory.Protect(start, copyDataLen, MemoryBlock.Protection.RW);
|
||||
Memory.Protect(start, copyDataLen, MemoryBlockBase.Protection.RW);
|
||||
Marshal.Copy(Z.US(start), data, 0, (int)copyDataLen);
|
||||
|
||||
var pages = new MemoryBlock.Protection[copyPageLen];
|
||||
var pages = new MemoryBlockBase.Protection[copyPageLen];
|
||||
Array.Copy(_pages, oldStartPage, pages, 0, copyPageLen);
|
||||
|
||||
ProtectInternal(oldStartPage, oldNumPages, FREE, true);
|
||||
ProtectInternal(newStartPage, newNumPages, MemoryBlock.Protection.RW, false);
|
||||
ProtectInternal(newStartPage, newNumPages, MemoryBlockBase.Protection.RW, false);
|
||||
|
||||
var ret = GetStartAddr(newStartPage);
|
||||
Marshal.Copy(data, 0, Z.US(ret), (int)copyDataLen);
|
||||
|
@ -243,7 +243,7 @@ namespace BizHawk.Emulation.Cores.Waterbox
|
|||
return Protect(start, size, FREE);
|
||||
}
|
||||
|
||||
public bool Protect(ulong start, ulong size, MemoryBlock.Protection prot)
|
||||
public bool Protect(ulong start, ulong size, MemoryBlockBase.Protection prot)
|
||||
{
|
||||
if (start < Memory.Start || start + size > Memory.End || size == 0)
|
||||
return false;
|
||||
|
@ -276,7 +276,7 @@ namespace BizHawk.Emulation.Cores.Waterbox
|
|||
bw.Write(Memory.XorHash);
|
||||
bw.Write(_pagesAsBytes);
|
||||
|
||||
Memory.Protect(Memory.Start, Memory.Size, MemoryBlock.Protection.R);
|
||||
Memory.Protect(Memory.Start, Memory.Size, MemoryBlockBase.Protection.R);
|
||||
var srcs = Memory.GetXorStream(Memory.Start, Memory.Size, false);
|
||||
for (int i = 0, addr = 0; i < _pages.Length; i++, addr += WaterboxUtils.PageSize)
|
||||
{
|
||||
|
@ -307,7 +307,7 @@ namespace BizHawk.Emulation.Cores.Waterbox
|
|||
throw new InvalidOperationException("Unexpected error reading!");
|
||||
|
||||
Used = 0;
|
||||
Memory.Protect(Memory.Start, Memory.Size, MemoryBlock.Protection.RW);
|
||||
Memory.Protect(Memory.Start, Memory.Size, MemoryBlockBase.Protection.RW);
|
||||
var dsts = Memory.GetXorStream(Memory.Start, Memory.Size, true);
|
||||
for (int i = 0, addr = 0; i < _pages.Length; i++, addr += WaterboxUtils.PageSize)
|
||||
{
|
||||
|
@ -335,7 +335,7 @@ namespace BizHawk.Emulation.Cores.Waterbox
|
|||
{
|
||||
ulong siz = (ulong)(rnd.Next(256 * 1024) + 384 * 1024);
|
||||
siz = siz / 4096 * 4096;
|
||||
var ptr = mmo.Map(siz, MemoryBlock.Protection.RW);
|
||||
var ptr = mmo.Map(siz, MemoryBlockBase.Protection.RW);
|
||||
allocs.Add(ptr, siz);
|
||||
}
|
||||
|
||||
|
@ -351,7 +351,7 @@ namespace BizHawk.Emulation.Cores.Waterbox
|
|||
{
|
||||
ulong siz = (ulong)(rnd.Next(256 * 1024) + 384 * 1024);
|
||||
siz = siz / 4096 * 4096;
|
||||
var ptr = mmo.Map(siz, MemoryBlock.Protection.RW);
|
||||
var ptr = mmo.Map(siz, MemoryBlockBase.Protection.RW);
|
||||
allocs.Add(ptr, siz);
|
||||
}
|
||||
|
||||
|
|
|
@ -662,18 +662,18 @@ namespace BizHawk.Emulation.Cores.Waterbox
|
|||
{
|
||||
if (address != IntPtr.Zero)
|
||||
return Z.SS(-1);
|
||||
MemoryBlock.Protection mprot;
|
||||
MemoryBlockBase.Protection mprot;
|
||||
switch (prot)
|
||||
{
|
||||
case 0: mprot = MemoryBlock.Protection.None; break;
|
||||
case 0: mprot = MemoryBlockBase.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 = MemoryBlock.Protection.RW; break;
|
||||
case 1: mprot = MemoryBlock.Protection.R; break;
|
||||
case 5: mprot = MemoryBlock.Protection.RX; break;
|
||||
case 3: mprot = MemoryBlockBase.Protection.RW; break;
|
||||
case 1: mprot = MemoryBlockBase.Protection.R; break;
|
||||
case 5: mprot = MemoryBlockBase.Protection.RX; break;
|
||||
}
|
||||
if ((flags & 0x20) == 0)
|
||||
{
|
||||
|
@ -711,18 +711,18 @@ namespace BizHawk.Emulation.Cores.Waterbox
|
|||
[BizExport(CallingConvention.Cdecl, EntryPoint = "n10")]
|
||||
public int MProtect(UIntPtr address, UIntPtr size, int prot)
|
||||
{
|
||||
MemoryBlock.Protection mprot;
|
||||
MemoryBlockBase.Protection mprot;
|
||||
switch (prot)
|
||||
{
|
||||
case 0: mprot = MemoryBlock.Protection.None; break;
|
||||
case 0: mprot = MemoryBlockBase.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 = MemoryBlock.Protection.RW; break;
|
||||
case 1: mprot = MemoryBlock.Protection.R; break;
|
||||
case 5: mprot = MemoryBlock.Protection.RX; break;
|
||||
case 3: mprot = MemoryBlockBase.Protection.RW; break;
|
||||
case 1: mprot = MemoryBlockBase.Protection.R; break;
|
||||
case 5: mprot = MemoryBlockBase.Protection.RX; break;
|
||||
}
|
||||
return _parent._mmapheap.Protect((ulong)address, (ulong)size, mprot) ? 0 : -1;
|
||||
}
|
||||
|
|
|
@ -34,7 +34,7 @@ namespace BizHawk.Emulation.Cores.Waterbox
|
|||
public bool W { get; set; }
|
||||
public bool R { get; set; }
|
||||
public bool X { get; set; }
|
||||
public MemoryBlock.Protection Prot { get; set; }
|
||||
public MemoryBlockBase.Protection Prot { get; set; }
|
||||
public ulong DiskStart { get; set; }
|
||||
public ulong DiskSize { get; set; }
|
||||
}
|
||||
|
@ -55,7 +55,7 @@ namespace BizHawk.Emulation.Cores.Waterbox
|
|||
|
||||
public long LoadOffset { get; private set; }
|
||||
|
||||
public MemoryBlock Memory { get; private set; }
|
||||
public MemoryBlockBase Memory { get; private set; }
|
||||
|
||||
public IntPtr EntryPoint { get; private set; }
|
||||
|
||||
|
@ -135,7 +135,7 @@ namespace BizHawk.Emulation.Cores.Waterbox
|
|||
ulong start = Start + s.VirtualAddress;
|
||||
ulong length = s.VirtualSize;
|
||||
|
||||
MemoryBlock.Protection prot;
|
||||
MemoryBlockBase.Protection prot;
|
||||
var r = (s.Characteristics & (uint)Constants.SectionFlags.IMAGE_SCN_MEM_READ) != 0;
|
||||
var w = (s.Characteristics & (uint)Constants.SectionFlags.IMAGE_SCN_MEM_WRITE) != 0;
|
||||
var x = (s.Characteristics & (uint)Constants.SectionFlags.IMAGE_SCN_MEM_EXECUTE) != 0;
|
||||
|
@ -144,7 +144,7 @@ namespace BizHawk.Emulation.Cores.Waterbox
|
|||
throw new InvalidOperationException("Write and Execute not allowed");
|
||||
}
|
||||
|
||||
prot = x ? MemoryBlock.Protection.RX : w ? MemoryBlock.Protection.RW : MemoryBlock.Protection.R;
|
||||
prot = x ? MemoryBlockBase.Protection.RX : w ? MemoryBlockBase.Protection.RW : MemoryBlockBase.Protection.R;
|
||||
|
||||
var section = new Section
|
||||
{
|
||||
|
@ -172,9 +172,9 @@ namespace BizHawk.Emulation.Cores.Waterbox
|
|||
// OK, NOW MOUNT
|
||||
|
||||
LoadOffset = (long)Start - (long)_pe.ImageNtHeaders.OptionalHeader.ImageBase;
|
||||
Memory = new MemoryBlock(Start, Size);
|
||||
Memory = MemoryBlockBase.CallPlatformCtor(Start, Size);
|
||||
Memory.Activate();
|
||||
Memory.Protect(Start, Size, MemoryBlock.Protection.RW);
|
||||
Memory.Protect(Start, Size, MemoryBlockBase.Protection.RW);
|
||||
|
||||
// copy headers
|
||||
Marshal.Copy(fileData, 0, Z.US(Start), (int)_pe.ImageNtHeaders.OptionalHeader.SizeOfHeaders);
|
||||
|
@ -293,7 +293,7 @@ namespace BizHawk.Emulation.Cores.Waterbox
|
|||
/// </summary>
|
||||
private void ProtectMemory()
|
||||
{
|
||||
Memory.Protect(Memory.Start, Memory.Size, MemoryBlock.Protection.R);
|
||||
Memory.Protect(Memory.Start, Memory.Size, MemoryBlockBase.Protection.R);
|
||||
|
||||
foreach (var s in _sections)
|
||||
{
|
||||
|
@ -314,7 +314,7 @@ namespace BizHawk.Emulation.Cores.Waterbox
|
|||
// when we need to restore a savestate from another run. so imports might or might not be sealed
|
||||
|
||||
if (_everythingSealed && _imports != null)
|
||||
Memory.Protect(_imports.Start, _imports.Size, MemoryBlock.Protection.RW);
|
||||
Memory.Protect(_imports.Start, _imports.Size, MemoryBlockBase.Protection.RW);
|
||||
|
||||
Dictionary<string, IntPtr> imports;
|
||||
if (ImportsByModule.TryGetValue(moduleName, out imports))
|
||||
|
@ -427,7 +427,7 @@ namespace BizHawk.Emulation.Cores.Waterbox
|
|||
// unlikely to get this far if the previous checks pssed
|
||||
throw new InvalidOperationException("Trickys elves moved on you!");
|
||||
|
||||
Memory.Protect(Memory.Start, Memory.Size, MemoryBlock.Protection.RW);
|
||||
Memory.Protect(Memory.Start, Memory.Size, MemoryBlockBase.Protection.RW);
|
||||
|
||||
foreach (var s in _sections)
|
||||
{
|
||||
|
|
|
@ -29,14 +29,14 @@ namespace BizHawk.Emulation.Cores.Waterbox
|
|||
/// <summary>
|
||||
/// everything to swap in for context switches
|
||||
/// </summary>
|
||||
private List<MemoryBlock> _memoryBlocks = new List<MemoryBlock>();
|
||||
private List<MemoryBlockBase> _memoryBlocks = new List<MemoryBlockBase>();
|
||||
|
||||
/// <summary>
|
||||
/// an informative name for each memory block: used for debugging purposes
|
||||
/// </summary>
|
||||
private List<string> _memoryBlockNames = new List<string>();
|
||||
|
||||
protected void AddMemoryBlock(MemoryBlock block, string name)
|
||||
protected void AddMemoryBlock(MemoryBlockBase block, string name)
|
||||
{
|
||||
_memoryBlocks.Add(block);
|
||||
_memoryBlockNames.Add(name);
|
||||
|
|
Loading…
Reference in New Issue