diff --git a/BizHawk.Emulation.Cores/BizHawk.Emulation.Cores.csproj b/BizHawk.Emulation.Cores/BizHawk.Emulation.Cores.csproj index e7df197953..0ff66a8a21 100644 --- a/BizHawk.Emulation.Cores/BizHawk.Emulation.Cores.csproj +++ b/BizHawk.Emulation.Cores/BizHawk.Emulation.Cores.csproj @@ -110,6 +110,9 @@ False ..\References\OpenTK.dll + + ..\References\PeNet.dll + 3.5 @@ -208,7 +211,7 @@ C64.cs - C64.cs + C64.cs C64.cs @@ -220,7 +223,7 @@ - + @@ -1247,7 +1250,7 @@ - + @@ -1269,7 +1272,8 @@ - + + @@ -1281,6 +1285,8 @@ + + @@ -1346,4 +1352,4 @@ --> - + \ No newline at end of file diff --git a/BizHawk.Emulation.Cores/Consoles/Sega/gpgx64/GPGX.cs b/BizHawk.Emulation.Cores/Consoles/Sega/gpgx64/GPGX.cs index c54a7d7892..6707e53448 100644 --- a/BizHawk.Emulation.Cores/Consoles/Sega/gpgx64/GPGX.cs +++ b/BizHawk.Emulation.Cores/Consoles/Sega/gpgx64/GPGX.cs @@ -4,6 +4,7 @@ using System.Runtime.InteropServices; using BizHawk.Common.BizInvoke; using BizHawk.Emulation.Common; +using BizHawk.Emulation.Cores.Waterbox; namespace BizHawk.Emulation.Cores.Consoles.Sega.gpgx64 { diff --git a/BizHawk.Emulation.Cores/ElfRunner.cs b/BizHawk.Emulation.Cores/Waterbox/ElfRunner.cs similarity index 67% rename from BizHawk.Emulation.Cores/ElfRunner.cs rename to BizHawk.Emulation.Cores/Waterbox/ElfRunner.cs index 0f6f1dfaa8..d72ce948fc 100644 --- a/BizHawk.Emulation.Cores/ElfRunner.cs +++ b/BizHawk.Emulation.Cores/Waterbox/ElfRunner.cs @@ -13,9 +13,9 @@ using System.IO; using System.Collections.Concurrent; using System.Threading; -namespace BizHawk.Emulation.Cores +namespace BizHawk.Emulation.Cores.Waterbox { - public sealed class ElfRunner : IImportResolver, IDisposable, IMonitor + public sealed class ElfRunner : Swappable, IImportResolver, IDisposable { // TODO: a lot of things only work with our elves and aren't fully generalized @@ -41,11 +41,6 @@ namespace BizHawk.Emulation.Cores /// private Heap _invisibleheap; - /// - /// _base.Start, or 0 if we were relocated and so don't need to be swapped - /// - private ulong _lockkey; - private long _loadoffset; private Dictionary> _symdict; private List> _symlist; @@ -55,11 +50,6 @@ namespace BizHawk.Emulation.Cores /// private List _disposeList = new List(); - /// - /// everything to swap in for context switches - /// - private List _memoryBlocks = new List(); - private ulong GetHeapStart(ulong prevend) { // if relocatable, we won't have constant pointers, so put the heap anywhere @@ -72,7 +62,7 @@ namespace BizHawk.Emulation.Cores { using (var fs = new FileStream(filename, FileMode.Open, FileAccess.Read)) { - _elfhash = Hash(fs); + _elfhash = WaterboxUtils.Hash(fs); } // todo: hack up this baby to take Streams @@ -87,12 +77,12 @@ namespace BizHawk.Emulation.Cores { _base = new MemoryBlock((ulong)(orig_end - orig_start)); _loadoffset = (long)_base.Start - orig_start; - _lockkey = 0; + Initialize(0); } else { - _lockkey = (ulong)orig_start; - _base = new MemoryBlock(_lockkey, (ulong)(orig_end - orig_start)); + Initialize((ulong)orig_start); + _base = new MemoryBlock((ulong)orig_start, (ulong)(orig_end - orig_start)); _loadoffset = 0; Enter(); } @@ -100,7 +90,7 @@ namespace BizHawk.Emulation.Cores try { _disposeList.Add(_base); - _memoryBlocks.Add(_base); + AddMemoryBlock(_base); _base.Activate(); _base.Protect(_base.Start, _base.Size, MemoryBlock.Protection.RW); @@ -130,7 +120,7 @@ namespace BizHawk.Emulation.Cores _heap.Memory.Activate(); end = _heap.Memory.End; _disposeList.Add(_heap); - _memoryBlocks.Add(_heap.Memory); + AddMemoryBlock(_heap.Memory); } if (sealedheapsize > 0) @@ -139,7 +129,7 @@ namespace BizHawk.Emulation.Cores _sealedheap.Memory.Activate(); end = _sealedheap.Memory.End; _disposeList.Add(_sealedheap); - _memoryBlocks.Add(_sealedheap.Memory); + AddMemoryBlock(_sealedheap.Memory); } if (invisibleheapsize > 0) @@ -148,7 +138,7 @@ namespace BizHawk.Emulation.Cores _invisibleheap.Memory.Activate(); end = _invisibleheap.Memory.End; _disposeList.Add(_invisibleheap); - _memoryBlocks.Add(_invisibleheap.Memory); + AddMemoryBlock(_invisibleheap.Memory); } ConnectAllClibPatches(); @@ -306,7 +296,7 @@ namespace BizHawk.Emulation.Cores foreach (var d in _disposeList) d.Dispose(); _disposeList.Clear(); - _memoryBlocks.Clear(); + PurgeMemoryBlocks(); _base = null; _heap = null; _sealedheap = null; @@ -425,67 +415,6 @@ namespace BizHawk.Emulation.Cores } } - /// - /// true if the IMonitor should be used for native calls - /// - public bool ShouldMonitor { get { return _lockkey != 0; } } - - // any ElfRunner is assumed to conflict with any other ElfRunner at the same base address, - // but not any other starting address. so don't put them too close together! - - private class LockInfo - { - public object Sync; - public ElfRunner Loaded; - } - - private static readonly ConcurrentDictionary LockInfos = new ConcurrentDictionary(); - - static ElfRunner() - { - LockInfos.GetOrAdd(0, new LockInfo()); // any errant attempt to lock when ShouldMonitor == false will result in NRE - } - - /// - /// acquire lock and swap this into memory - /// - public void Enter() - { - var li = LockInfos.GetOrAdd(_lockkey, new LockInfo { Sync = new object() }); - Monitor.Enter(li.Sync); - if (li.Loaded != this) - { - if (li.Loaded != null) - li.Loaded.DeactivateInternal(); - li.Loaded = null; - ActivateInternal(); - li.Loaded = this; - } - } - - /// - /// release lock - /// - public void Exit() - { - var li = LockInfos.GetOrAdd(_lockkey, new LockInfo { Sync = new object() }); - Monitor.Exit(li.Sync); - } - - private void DeactivateInternal() - { - Console.WriteLine("ElfRunner DeactivateInternal {0}", GetHashCode()); - foreach (var m in _memoryBlocks) - m.Deactivate(); - } - - private void ActivateInternal() - { - Console.WriteLine("ElfRunner ActivateInternal {0}", GetHashCode()); - foreach (var m in _memoryBlocks) - m.Activate(); - } - #region state const ulong MAGIC = 0xb00b1e5b00b1e569; @@ -533,7 +462,7 @@ namespace BizHawk.Emulation.Cores if (sec.Size != len) throw new InvalidOperationException("Unexpected section size for " + sec.Name); var ms = _base.GetStream((ulong)(sec.LoadAddress + _loadoffset), (ulong)sec.Size, true); - CopySome(br.BaseStream, ms, len); + WaterboxUtils.CopySome(br.BaseStream, ms, len); } if (_heap != null) _heap.LoadStateBinary(br); @@ -555,33 +484,6 @@ namespace BizHawk.Emulation.Cores #region utils - private static void CopySome(Stream src, Stream dst, long len) - { - var buff = new byte[4096]; - while (len > 0) - { - int r = src.Read(buff, 0, (int)Math.Min(len, 4096)); - dst.Write(buff, 0, r); - len -= r; - } - } - - private static byte[] Hash(byte[] data) - { - using (var h = SHA1.Create()) - { - return h.ComputeHash(data); - } - } - - private static byte[] Hash(Stream s) - { - using (var h = SHA1.Create()) - { - return h.ComputeHash(s); - } - } - private byte[] HashSection(ulong ptr, ulong len) { using (var h = SHA1.Create()) @@ -591,132 +493,6 @@ namespace BizHawk.Emulation.Cores } } - /// - /// a simple grow-only fixed max size heap - /// - private sealed class Heap : IDisposable - { - public MemoryBlock Memory { get; private set; } - /// - /// name, used in identifying errors - /// - public string Name { get; private set; } - /// - /// total number of bytes used - /// - public ulong Used { get; private set; } - - /// - /// true if the heap has been sealed, preventing further changes - /// - public bool Sealed { get; private set; } - - private byte[] _hash; - - public Heap(ulong start, ulong size, string name) - { - Memory = new MemoryBlock(start, size); - Used = 0; - Name = name; - } - - private void EnsureAlignment(int align) - { - if (align > 1) - { - ulong newused = ((Used - 1) | (ulong)(align - 1)) + 1; - if (newused > Memory.Size) - { - throw new InvalidOperationException(string.Format("Failed to meet alignment {0} on heap {1}", align, Name)); - } - Used = newused; - } - } - - public ulong Allocate(ulong size, int align) - { - if (Sealed) - throw new InvalidOperationException(string.Format("Attempt made to allocate from sealed heap {0}", Name)); - - EnsureAlignment(align); - - ulong newused = Used + size; - if (newused > Memory.Size) - { - throw new InvalidOperationException(string.Format("Failed to allocate {0} bytes from heap {1}", size, Name)); - } - ulong ret = Memory.Start + Used; - Memory.Protect(ret, newused - Used, MemoryBlock.Protection.RW); - Used = newused; - Console.WriteLine("Allocated {0} bytes on {1}", size, Name); - return ret; - } - - public void Seal() - { - if (!Sealed) - { - Memory.Protect(Memory.Start, Memory.Size, MemoryBlock.Protection.R); - _hash = Hash(Memory.GetStream(Memory.Start, Used, false)); - Sealed = true; - } - else - { - throw new InvalidOperationException(string.Format("Attempt to reseal heap {0}", Name)); - } - } - - public void SaveStateBinary(BinaryWriter bw) - { - bw.Write(Name); - bw.Write(Used); - if (!Sealed) - { - var ms = Memory.GetStream(Memory.Start, Used, false); - ms.CopyTo(bw.BaseStream); - } - else - { - bw.Write(_hash); - } - } - - public void LoadStateBinary(BinaryReader br) - { - var name = br.ReadString(); - if (name != Name) - throw new InvalidOperationException(string.Format("Name did not match for heap {0}", Name)); - var used = br.ReadUInt64(); - if (used > Memory.Size) - throw new InvalidOperationException(string.Format("Heap {0} used {1} larger than available {2}", Name, used, Memory.Size)); - if (!Sealed) - { - Memory.Protect(Memory.Start, Memory.Size, MemoryBlock.Protection.None); - Memory.Protect(Memory.Start, used, MemoryBlock.Protection.RW); - var ms = Memory.GetStream(Memory.Start, used, true); - CopySome(br.BaseStream, ms, (long)used); - Used = used; - } - else - { - var hash = br.ReadBytes(_hash.Length); - if (!hash.SequenceEqual(_hash)) - { - throw new InvalidOperationException(string.Format("Hash did not match for heap {0}. Is this the same rom?")); - } - } - } - - public void Dispose() - { - if (Memory != null) - { - Memory.Dispose(); - Memory = null; - } - } - } - #endregion } } diff --git a/BizHawk.Emulation.Cores/Waterbox/Heap.cs b/BizHawk.Emulation.Cores/Waterbox/Heap.cs new file mode 100644 index 0000000000..1d83e7618d --- /dev/null +++ b/BizHawk.Emulation.Cores/Waterbox/Heap.cs @@ -0,0 +1,134 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; + +namespace BizHawk.Emulation.Cores.Waterbox +{ + /// + /// a simple grow-only fixed max size heap + /// + internal sealed class Heap : IDisposable + { + public MemoryBlock Memory { get; private set; } + /// + /// name, used in identifying errors + /// + public string Name { get; private set; } + /// + /// total number of bytes used + /// + public ulong Used { get; private set; } + + /// + /// true if the heap has been sealed, preventing further changes + /// + public bool Sealed { get; private set; } + + private byte[] _hash; + + public Heap(ulong start, ulong size, string name) + { + Memory = new MemoryBlock(start, size); + Used = 0; + Name = name; + } + + private void EnsureAlignment(int align) + { + if (align > 1) + { + ulong newused = ((Used - 1) | (ulong)(align - 1)) + 1; + if (newused > Memory.Size) + { + throw new InvalidOperationException(string.Format("Failed to meet alignment {0} on heap {1}", align, Name)); + } + Used = newused; + } + } + + public ulong Allocate(ulong size, int align) + { + if (Sealed) + throw new InvalidOperationException(string.Format("Attempt made to allocate from sealed heap {0}", Name)); + + EnsureAlignment(align); + + ulong newused = Used + size; + if (newused > Memory.Size) + { + throw new InvalidOperationException(string.Format("Failed to allocate {0} bytes from heap {1}", size, Name)); + } + ulong ret = Memory.Start + Used; + Memory.Protect(ret, newused - Used, MemoryBlock.Protection.RW); + Used = newused; + Console.WriteLine("Allocated {0} bytes on {1}", size, Name); + return ret; + } + + public void Seal() + { + if (!Sealed) + { + Memory.Protect(Memory.Start, Memory.Size, MemoryBlock.Protection.R); + _hash = WaterboxUtils.Hash(Memory.GetStream(Memory.Start, Used, false)); + Sealed = true; + } + else + { + throw new InvalidOperationException(string.Format("Attempt to reseal heap {0}", Name)); + } + } + + public void SaveStateBinary(BinaryWriter bw) + { + bw.Write(Name); + bw.Write(Used); + if (!Sealed) + { + var ms = Memory.GetStream(Memory.Start, Used, false); + ms.CopyTo(bw.BaseStream); + } + else + { + bw.Write(_hash); + } + } + + public void LoadStateBinary(BinaryReader br) + { + var name = br.ReadString(); + if (name != Name) + throw new InvalidOperationException(string.Format("Name did not match for heap {0}", Name)); + var used = br.ReadUInt64(); + if (used > Memory.Size) + throw new InvalidOperationException(string.Format("Heap {0} used {1} larger than available {2}", Name, used, Memory.Size)); + if (!Sealed) + { + Memory.Protect(Memory.Start, Memory.Size, MemoryBlock.Protection.None); + Memory.Protect(Memory.Start, used, MemoryBlock.Protection.RW); + var ms = Memory.GetStream(Memory.Start, used, true); + WaterboxUtils.CopySome(br.BaseStream, ms, (long)used); + Used = used; + } + else + { + var hash = br.ReadBytes(_hash.Length); + if (!hash.SequenceEqual(_hash)) + { + throw new InvalidOperationException(string.Format("Hash did not match for heap {0}. Is this the same rom?")); + } + } + } + + public void Dispose() + { + if (Memory != null) + { + Memory.Dispose(); + Memory = null; + } + } + } +} diff --git a/BizHawk.Emulation.Cores/MemoryBlock.cs b/BizHawk.Emulation.Cores/Waterbox/MemoryBlock.cs similarity index 99% rename from BizHawk.Emulation.Cores/MemoryBlock.cs rename to BizHawk.Emulation.Cores/Waterbox/MemoryBlock.cs index 5bdea3a105..beaf8b45ab 100644 --- a/BizHawk.Emulation.Cores/MemoryBlock.cs +++ b/BizHawk.Emulation.Cores/Waterbox/MemoryBlock.cs @@ -5,7 +5,7 @@ using System.Text; using System.Runtime.InteropServices; using System.IO; -namespace BizHawk.Emulation.Cores +namespace BizHawk.Emulation.Cores.Waterbox { public static class Z { diff --git a/BizHawk.Emulation.Cores/Waterbox/Swappable.cs b/BizHawk.Emulation.Cores/Waterbox/Swappable.cs new file mode 100644 index 0000000000..d6046dbb31 --- /dev/null +++ b/BizHawk.Emulation.Cores/Waterbox/Swappable.cs @@ -0,0 +1,104 @@ +using BizHawk.Common; +using System; +using System.Collections.Concurrent; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading; + +namespace BizHawk.Emulation.Cores.Waterbox +{ + /// + /// represents an object that can be swapped in and out of memory to compete with other objects in the same memory + /// not suited for general purpose stuff + /// + public abstract class Swappable : IMonitor + { + /// + /// start address, or 0 if we don't need to be swapped + /// + private ulong _lockkey = 0; + + /// + /// everything to swap in for context switches + /// + private List _memoryBlocks = new List(); + + protected void AddMemoryBlock(MemoryBlock block) + { + _memoryBlocks.Add(block); + } + + protected void PurgeMemoryBlocks() + { + _memoryBlocks = null; + } + + protected void Initialize(ulong lockkey) + { + _lockkey = lockkey; + } + + /// + /// true if the IMonitor should be used for native calls + /// + public bool ShouldMonitor { get { return _lockkey != 0; } } + + // any Swappable is assumed to conflict with any other Swappable at the same base address, + // but not any other starting address. so don't put them too close together! + + private class LockInfo + { + public object Sync; + public Swappable Loaded; + } + + private static readonly ConcurrentDictionary LockInfos = new ConcurrentDictionary(); + + static Swappable() + { + LockInfos.GetOrAdd(0, new LockInfo()); // any errant attempt to lock when ShouldMonitor == false will result in NRE + } + + /// + /// acquire lock and swap this into memory + /// + public void Enter() + { + var li = LockInfos.GetOrAdd(_lockkey, new LockInfo { Sync = new object() }); + Monitor.Enter(li.Sync); + if (li.Loaded != this) + { + if (li.Loaded != null) + li.Loaded.DeactivateInternal(); + li.Loaded = null; + ActivateInternal(); + li.Loaded = this; + } + } + + /// + /// release lock + /// + public void Exit() + { + var li = LockInfos.GetOrAdd(_lockkey, new LockInfo { Sync = new object() }); + Monitor.Exit(li.Sync); + } + + private void DeactivateInternal() + { + Console.WriteLine("Swappable DeactivateInternal {0}", GetHashCode()); + foreach (var m in _memoryBlocks) + m.Deactivate(); + } + + private void ActivateInternal() + { + Console.WriteLine("Swappable ActivateInternal {0}", GetHashCode()); + foreach (var m in _memoryBlocks) + m.Activate(); + } + + } +} diff --git a/BizHawk.Emulation.Cores/Waterbox/WaterboxUtils.cs b/BizHawk.Emulation.Cores/Waterbox/WaterboxUtils.cs new file mode 100644 index 0000000000..74540e47ef --- /dev/null +++ b/BizHawk.Emulation.Cores/Waterbox/WaterboxUtils.cs @@ -0,0 +1,46 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Security.Cryptography; +using System.Text; + +namespace BizHawk.Emulation.Cores.Waterbox +{ + public static class WaterboxUtils + { + /// + /// copy `len` bytes from `src` to `dest` + /// + /// + /// + /// + public static void CopySome(Stream src, Stream dst, long len) + { + var buff = new byte[4096]; + while (len > 0) + { + int r = src.Read(buff, 0, (int)Math.Min(len, 4096)); + dst.Write(buff, 0, r); + len -= r; + } + } + + public static byte[] Hash(byte[] data) + { + using (var h = SHA1.Create()) + { + return h.ComputeHash(data); + } + } + + public static byte[] Hash(Stream s) + { + using (var h = SHA1.Create()) + { + return h.ComputeHash(s); + } + } + + } +} diff --git a/References/PeNet.dll b/References/PeNet.dll new file mode 100644 index 0000000000..f2c887f476 Binary files /dev/null and b/References/PeNet.dll differ