Start working on a primitive mmap implementation. It's good enough for VirtualBoyee to boot, but undoubtedly has many bugs.
This commit is contained in:
parent
7d84946daa
commit
855ff7deca
|
@ -96,6 +96,9 @@ namespace BizHawk.Client.ApiHawk
|
|||
case "WSWAN":
|
||||
return CoreSystem.WonderSwan;
|
||||
|
||||
case "VB":
|
||||
return 0; // like I give a shit
|
||||
|
||||
default:
|
||||
throw new IndexOutOfRangeException(string.Format("{0} is missing in convert list", value));
|
||||
}
|
||||
|
|
|
@ -331,6 +331,10 @@ namespace BizHawk.Emulation.Common
|
|||
case ".DO":
|
||||
game.System = "AppleII";
|
||||
break;
|
||||
|
||||
case ".VB":
|
||||
game.System = "VB";
|
||||
break;
|
||||
}
|
||||
|
||||
game.Name = Path.GetFileNameWithoutExtension(fileName)?.Replace('_', ' ');
|
||||
|
|
|
@ -1279,6 +1279,7 @@
|
|||
<Compile Include="Libretro\LibretroCore_Description.cs" />
|
||||
<Compile Include="Libretro\LibretroCore_InputCallbacks.cs" />
|
||||
<Compile Include="Waterbox\Heap.cs" />
|
||||
<Compile Include="Waterbox\MapHeap.cs" />
|
||||
<Compile Include="Waterbox\MemoryBlock.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
<Compile Include="Sound\CDAudio.cs" />
|
||||
|
|
|
@ -25,10 +25,11 @@ namespace BizHawk.Emulation.Cores.Consoles.Nintendo.VB
|
|||
{
|
||||
Path = comm.CoreFileProvider.DllPath(),
|
||||
Filename = "vb.wbx",
|
||||
NormalHeapSizeKB = 1024,
|
||||
NormalHeapSizeKB = 4 * 1024,
|
||||
SealedHeapSizeKB = 12 * 1024,
|
||||
InvisibleHeapSizeKB = 6 * 1024,
|
||||
SpecialHeapSizeKB = 64
|
||||
SpecialHeapSizeKB = 64,
|
||||
MmapHeapSizeKB = 16 * 1024
|
||||
});
|
||||
|
||||
_boyee = BizInvoker.GetInvoker<LibVirtualBoyee>(_exe, _exe);
|
||||
|
@ -112,22 +113,22 @@ namespace BizHawk.Emulation.Cores.Consoles.Nintendo.VB
|
|||
|
||||
#region IVideoProvider
|
||||
|
||||
private int[] _videoBuffer = new int[0];
|
||||
private int[] _videoBuffer = new int[256 * 192];
|
||||
|
||||
public int[] GetVideoBuffer()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
return _videoBuffer;
|
||||
}
|
||||
|
||||
public int VirtualWidth { get; private set; }
|
||||
public int VirtualHeight { get; private set; }
|
||||
public int VirtualWidth { get; private set; } = 256;
|
||||
public int VirtualHeight { get; private set; } = 192;
|
||||
|
||||
public int BufferWidth { get; private set; }
|
||||
public int BufferHeight { get; private set; }
|
||||
public int BufferWidth { get; private set; } = 256;
|
||||
public int BufferHeight { get; private set; } = 192;
|
||||
|
||||
public int VsyncNumerator { get; private set; }
|
||||
public int VsyncNumerator { get; private set; } = 60;
|
||||
|
||||
public int VsyncDenominator { get; private set; }
|
||||
public int VsyncDenominator { get; private set; } = 1;
|
||||
|
||||
public int BackgroundColor => unchecked((int)0xff000000);
|
||||
|
||||
|
|
|
@ -0,0 +1,303 @@
|
|||
using BizHawk.Emulation.Common;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.IO;
|
||||
|
||||
namespace BizHawk.Emulation.Cores.Waterbox
|
||||
{
|
||||
/// <summary>
|
||||
/// a heap that supports basic alloc, free, and realloc calls
|
||||
/// </summary>
|
||||
internal sealed class MapHeap : IBinaryStateable, IDisposable
|
||||
{
|
||||
public MemoryBlock Memory { get; private set; }
|
||||
/// <summary>
|
||||
/// name, used in identifying errors
|
||||
/// </summary>
|
||||
public string Name { get; private set; }
|
||||
|
||||
public byte[] XorHash { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// get a page index within the block
|
||||
/// </summary>
|
||||
private int GetPage(ulong addr)
|
||||
{
|
||||
return (int)((addr - Memory.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) + Memory.Start;
|
||||
}
|
||||
|
||||
private class Bin
|
||||
{
|
||||
public int StartPage;
|
||||
public int PageCount;
|
||||
public MemoryBlock.Protection Protection;
|
||||
public bool Free
|
||||
{
|
||||
get
|
||||
{
|
||||
return (byte)Protection == 255;
|
||||
}
|
||||
set
|
||||
{
|
||||
Protection = value ? (MemoryBlock.Protection)255 : MemoryBlock.Protection.None;
|
||||
}
|
||||
}
|
||||
|
||||
public Bin Next;
|
||||
|
||||
/// <summary>
|
||||
/// split this bin, keeping only numPages pages
|
||||
/// </summary>
|
||||
public bool Cleave(int numPages)
|
||||
{
|
||||
int nextPages = PageCount - numPages;
|
||||
if (nextPages > 0)
|
||||
{
|
||||
Next = new Bin
|
||||
{
|
||||
StartPage = StartPage + numPages,
|
||||
PageCount = nextPages,
|
||||
Next = Next
|
||||
};
|
||||
PageCount = numPages;
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private Bin _root;
|
||||
|
||||
public MapHeap(ulong start, ulong size, string name)
|
||||
{
|
||||
size = WaterboxUtils.AlignUp(size);
|
||||
Memory = new MemoryBlock(start, size);
|
||||
Name = name;
|
||||
Console.WriteLine("Created mapheap `{1}` at {0:x16}:{2:x16}", start, name, start + size);
|
||||
|
||||
_root = new Bin
|
||||
{
|
||||
StartPage = 0,
|
||||
PageCount = (int)(size >> WaterboxUtils.PageShift),
|
||||
Free = true
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// gets the bin that contains a page
|
||||
/// </summary>
|
||||
private Bin GetBinForStartPage(int page)
|
||||
{
|
||||
Bin curr = _root;
|
||||
while (curr.StartPage + curr.PageCount <= page)
|
||||
curr = curr.Next;
|
||||
return curr;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// gets the bin that contains the page before the passed page, returning null if
|
||||
/// any bin along the way is Free
|
||||
/// </summary>
|
||||
private Bin GetBinForEndPageEnsureAllocated(int page, Bin start)
|
||||
{
|
||||
Bin curr = start;
|
||||
while (curr != null && curr.StartPage + curr.PageCount < page)
|
||||
{
|
||||
if (curr.Free)
|
||||
return null;
|
||||
curr = curr.Next;
|
||||
}
|
||||
return curr;
|
||||
}
|
||||
|
||||
public ulong Map(ulong size, MemoryBlock.Protection prot)
|
||||
{
|
||||
int numPages = WaterboxUtils.PagesNeeded(size);
|
||||
Bin best = null;
|
||||
Bin curr = _root;
|
||||
|
||||
// find smallest potential bin
|
||||
do
|
||||
{
|
||||
if (curr.Free && curr.PageCount >= numPages)
|
||||
{
|
||||
if (best == null || curr.PageCount < best.PageCount)
|
||||
{
|
||||
best = curr;
|
||||
if (curr.PageCount == numPages)
|
||||
break;
|
||||
}
|
||||
}
|
||||
curr = curr.Next;
|
||||
} while (curr != null);
|
||||
|
||||
if (best == null)
|
||||
return 0;
|
||||
|
||||
if (best.Cleave(numPages))
|
||||
best.Next.Free = true;
|
||||
best.Protection = prot;
|
||||
|
||||
var ret = GetStartAddr(best.StartPage);
|
||||
Memory.Protect(ret, ((ulong)numPages) << WaterboxUtils.PageShift, prot);
|
||||
return ret;
|
||||
}
|
||||
|
||||
public ulong Remap(ulong start, ulong oldSize, ulong newSize, bool canMove)
|
||||
{
|
||||
if (start < Memory.Start || start + oldSize > Memory.End)
|
||||
return 0;
|
||||
|
||||
var oldStartPage = GetPage(start);
|
||||
var oldStartBin = GetBinForStartPage(oldStartPage);
|
||||
if (oldSize == 0 && canMove)
|
||||
return Map(newSize, oldStartBin.Protection);
|
||||
|
||||
var oldNumPages = WaterboxUtils.PagesNeeded(oldSize);
|
||||
var oldEndPage = oldStartPage + oldNumPages;
|
||||
// first, check if the requested area is actually mapped
|
||||
var oldEndBin = GetBinForEndPageEnsureAllocated(oldEndPage, oldStartBin);
|
||||
if (oldEndBin == null)
|
||||
return 0;
|
||||
|
||||
var newNumPages = WaterboxUtils.PagesNeeded(newSize);
|
||||
var newEndPage = oldStartPage + newNumPages;
|
||||
if (newEndPage > oldEndPage)
|
||||
{
|
||||
// increase size
|
||||
// the only way this will work in place is if all of the remaining space is free
|
||||
Bin nextBin;
|
||||
if (oldEndBin.StartPage + oldEndBin.PageCount == oldEndPage // if end bin is too bag, space after that is used by something else
|
||||
&& (nextBin = oldEndBin.Next) != null // can't go off the edge
|
||||
&& nextBin.Free
|
||||
&& nextBin.StartPage + nextBin.PageCount >= newEndPage)
|
||||
{
|
||||
nextBin.Protection = oldStartBin.Protection;
|
||||
if (nextBin.Cleave(newEndPage - nextBin.StartPage))
|
||||
nextBin.Next.Free = true;
|
||||
return start;
|
||||
}
|
||||
// could not increase in place, so move
|
||||
if (!canMove)
|
||||
return 0;
|
||||
|
||||
// if there's some free space right before `start`, and some right after, but not enough
|
||||
// to extend in place, it's possible that a realloc would succeed reusing the same space,
|
||||
// but would fail anywhere else due to heavy memory pressure.
|
||||
|
||||
// that would be a much more complicated algorithm; we'd need to compute a new allocation
|
||||
// as if this one had been freed, but still be able to preserve this if that allocation
|
||||
// still failed. instead, we ignore this case.
|
||||
var ret = Map(newSize, oldStartBin.Protection);
|
||||
if (ret != 0)
|
||||
{
|
||||
// move data
|
||||
// NB: oldSize > 0
|
||||
Memory.Protect(start, oldSize, MemoryBlock.Protection.R);
|
||||
var ss = Memory.GetStream(start, oldSize, false);
|
||||
Memory.Protect(ret, oldSize, MemoryBlock.Protection.RW);
|
||||
var ds = Memory.GetStream(ret, oldSize, true);
|
||||
ss.CopyTo(ds);
|
||||
Memory.Protect(ret, oldSize, oldStartBin.Protection);
|
||||
UnmapPagesInternal(oldStartPage, oldNumPages, oldStartBin);
|
||||
return ret;
|
||||
}
|
||||
else
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
else if (newEndPage < oldEndPage)
|
||||
{
|
||||
// shrink in place
|
||||
var s = GetBinForStartPage(newEndPage);
|
||||
UnmapPagesInternal(newEndPage, oldEndPage - newEndPage, s);
|
||||
return start;
|
||||
}
|
||||
else
|
||||
{
|
||||
// no change
|
||||
return start;
|
||||
}
|
||||
}
|
||||
|
||||
public bool Unmap(ulong start, ulong size)
|
||||
{
|
||||
if (start < Memory.Start || start + size > Memory.End)
|
||||
return false;
|
||||
if (size == 0)
|
||||
return true;
|
||||
|
||||
var startPage = GetPage(start);
|
||||
var numPages = WaterboxUtils.PagesNeeded(size);
|
||||
var endPage = startPage + numPages;
|
||||
// check to see if the requested area is actually mapped
|
||||
var startBin = GetBinForStartPage(startPage);
|
||||
if (GetBinForEndPageEnsureAllocated(endPage, startBin) == null)
|
||||
return false;
|
||||
|
||||
UnmapPagesInternal(startPage, numPages, startBin);
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// frees some pages. assumes they are all allocated
|
||||
/// </summary>
|
||||
private void UnmapPagesInternal(int startPage, int numPages, Bin startBin)
|
||||
{
|
||||
// from the various paths we took to get here, we must be unmapping at least one page
|
||||
|
||||
var endPage = startPage + numPages;
|
||||
Bin freeBin = startBin;
|
||||
if (!freeBin.Free && freeBin.StartPage != startPage)
|
||||
{
|
||||
freeBin.Cleave(startPage - freeBin.StartPage);
|
||||
freeBin = freeBin.Next;
|
||||
freeBin.Free = true;
|
||||
}
|
||||
MemoryBlock.Protection lastEaten = MemoryBlock.Protection.None;
|
||||
while (freeBin.StartPage + freeBin.PageCount < endPage)
|
||||
{
|
||||
freeBin.PageCount += freeBin.Next.PageCount;
|
||||
lastEaten = freeBin.Next.Protection;
|
||||
freeBin.Next = freeBin.Next.Next;
|
||||
}
|
||||
if (freeBin.Cleave(freeBin.StartPage + freeBin.PageCount - endPage))
|
||||
{
|
||||
freeBin.Next.Protection = lastEaten;
|
||||
}
|
||||
Memory.Protect(GetStartAddr(startPage), ((ulong)numPages) << WaterboxUtils.PageShift, MemoryBlock.Protection.None);
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
if (Memory != null)
|
||||
{
|
||||
Memory.Dispose();
|
||||
Memory = null;
|
||||
}
|
||||
}
|
||||
|
||||
public void SaveStateBinary(BinaryWriter writer)
|
||||
{
|
||||
}
|
||||
|
||||
public void LoadStateBinary(BinaryReader reader)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
|
@ -7,96 +7,8 @@ using System.IO;
|
|||
|
||||
namespace BizHawk.Emulation.Cores.Waterbox
|
||||
{
|
||||
// C# is annoying: arithmetic operators for native ints are not exposed.
|
||||
// So we store them as long/ulong instead in many places, and use these helpers
|
||||
// to convert to IntPtr when needed
|
||||
|
||||
public static class Z
|
||||
{
|
||||
public static IntPtr US(ulong l)
|
||||
{
|
||||
if (IntPtr.Size == 8)
|
||||
return (IntPtr)(long)l;
|
||||
else
|
||||
return (IntPtr)(int)l;
|
||||
}
|
||||
|
||||
public static UIntPtr UU(ulong l)
|
||||
{
|
||||
if (UIntPtr.Size == 8)
|
||||
return (UIntPtr)l;
|
||||
else
|
||||
return (UIntPtr)(uint)l;
|
||||
}
|
||||
|
||||
public static IntPtr SS(long l)
|
||||
{
|
||||
if (IntPtr.Size == 8)
|
||||
return (IntPtr)l;
|
||||
else
|
||||
return (IntPtr)(int)l;
|
||||
}
|
||||
|
||||
public static UIntPtr SU(long l)
|
||||
{
|
||||
if (UIntPtr.Size == 8)
|
||||
return (UIntPtr)(ulong)l;
|
||||
else
|
||||
return (UIntPtr)(uint)l;
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class MemoryBlock : IDisposable
|
||||
{
|
||||
/// <summary>
|
||||
/// system page size
|
||||
/// </summary>
|
||||
public static int PageSize { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// bitshift corresponding to PageSize
|
||||
/// </summary>
|
||||
private static readonly int PageShift;
|
||||
/// <summary>
|
||||
/// bitmask corresponding to PageSize
|
||||
/// </summary>
|
||||
private static readonly ulong PageMask;
|
||||
|
||||
static MemoryBlock()
|
||||
{
|
||||
int p = PageSize = Environment.SystemPageSize;
|
||||
while (p != 1)
|
||||
{
|
||||
p >>= 1;
|
||||
PageShift++;
|
||||
}
|
||||
PageMask = (ulong)(PageSize - 1);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// true if addr is aligned
|
||||
/// </summary>
|
||||
private static bool Aligned(ulong addr)
|
||||
{
|
||||
return (addr & PageMask) == 0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// align address down to previous page boundary
|
||||
/// </summary>
|
||||
private static ulong AlignDown(ulong addr)
|
||||
{
|
||||
return addr & ~PageMask;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// align address up to next page boundary
|
||||
/// </summary>
|
||||
private static ulong AlignUp(ulong addr)
|
||||
{
|
||||
return ((addr - 1) | PageMask) + 1;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// starting address of the memory block
|
||||
/// </summary>
|
||||
|
@ -140,7 +52,7 @@ namespace BizHawk.Emulation.Cores.Waterbox
|
|||
if (addr < Start || addr >= End)
|
||||
throw new ArgumentOutOfRangeException();
|
||||
|
||||
return (int)((addr - Start) >> PageShift);
|
||||
return (int)((addr - Start) >> WaterboxUtils.PageShift);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -148,7 +60,7 @@ namespace BizHawk.Emulation.Cores.Waterbox
|
|||
/// </summary>
|
||||
private ulong GetStartAddr(int page)
|
||||
{
|
||||
return ((ulong)page << PageShift) + Start;
|
||||
return ((ulong)page << WaterboxUtils.PageShift) + Start;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -167,11 +79,11 @@ namespace BizHawk.Emulation.Cores.Waterbox
|
|||
/// <param name="size"></param>
|
||||
public MemoryBlock(ulong start, ulong size)
|
||||
{
|
||||
if (!Aligned(start))
|
||||
if (!WaterboxUtils.Aligned(start))
|
||||
throw new ArgumentOutOfRangeException();
|
||||
if (size == 0)
|
||||
throw new ArgumentOutOfRangeException();
|
||||
size = AlignUp(size);
|
||||
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);
|
||||
|
@ -325,10 +237,13 @@ namespace BizHawk.Emulation.Cores.Waterbox
|
|||
|
||||
if (Active) // it's legal to Protect() if we're not active; the information is just saved for the next activation
|
||||
{
|
||||
// TODO: if using another OS's memory protection calls, they must give the same non-aligned behavior
|
||||
// as VirtualProtect, or this must be changed
|
||||
var computedStart = WaterboxUtils.AlignDown(start);
|
||||
var computedEnd = WaterboxUtils.AlignUp(start + length);
|
||||
var computedLength = computedEnd - computedStart;
|
||||
|
||||
Kernel32.MemoryProtection old;
|
||||
if (!Kernel32.VirtualProtect(Z.UU(start), Z.UU(length), p, out old))
|
||||
if (!Kernel32.VirtualProtect(Z.UU(computedStart),
|
||||
Z.UU(computedLength), p, out old))
|
||||
throw new InvalidOperationException("VirtualProtect() returned FALSE!");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -26,23 +26,33 @@ namespace BizHawk.Emulation.Cores.Waterbox
|
|||
|
||||
/// <summary>
|
||||
/// how large the normal heap should be. it services sbrk calls
|
||||
/// can be 0, but sbrk calls will crash.
|
||||
/// </summary>
|
||||
public uint NormalHeapSizeKB { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// how large the sealed heap should be. it services special allocations that become readonly after init
|
||||
/// Must be > 0 and at least large enough to store argv and envp
|
||||
/// </summary>
|
||||
public uint SealedHeapSizeKB { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// how large the invisible heap should be. it services special allocations which are not savestated
|
||||
/// Must be > 0 and at least large enough for the internal vtables
|
||||
/// </summary>
|
||||
public uint InvisibleHeapSizeKB { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// how large the special heap should be. it is savestated, and contains ??
|
||||
/// Must be > 0 and at least large enough for the internal pthread structure
|
||||
/// </summary>
|
||||
public uint SpecialHeapSizeKB { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// how large the mmap heap should be. it is savestated.
|
||||
/// can be 0, but mmap calls will crash.
|
||||
/// </summary>
|
||||
public uint MmapHeapSizeKB { get; set; }
|
||||
}
|
||||
|
||||
|
||||
|
@ -385,6 +395,57 @@ namespace BizHawk.Emulation.Cores.Waterbox
|
|||
time.NanoSeconds = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
[BizExport(CallingConvention.Cdecl, EntryPoint = "n9")]
|
||||
public IntPtr MMap(IntPtr address, UIntPtr size, int prot, int flags, int fd, IntPtr offs)
|
||||
{
|
||||
if (address != IntPtr.Zero)
|
||||
return Z.SS(-1);
|
||||
MemoryBlock.Protection mprot;
|
||||
switch (prot)
|
||||
{
|
||||
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 = MemoryBlock.Protection.RW; break;
|
||||
case 1: mprot = MemoryBlock.Protection.R; break;
|
||||
case 5: mprot = MemoryBlock.Protection.RX; break;
|
||||
}
|
||||
if ((flags & 0x20) == 0)
|
||||
{
|
||||
// MAP_ANONYMOUS is required
|
||||
return Z.SS(-1);
|
||||
}
|
||||
if ((flags & 0xf00) != 0)
|
||||
{
|
||||
// various unsupported flags
|
||||
return Z.SS(-1);
|
||||
}
|
||||
|
||||
var ret = _parent._mmapheap.Map((ulong)size, mprot);
|
||||
return ret == 0 ? Z.SS(-1) : Z.US(ret);
|
||||
}
|
||||
[BizExport(CallingConvention.Cdecl, EntryPoint = "n25")]
|
||||
public IntPtr MRemap(UIntPtr oldAddress, UIntPtr oldSize,
|
||||
UIntPtr newSize, int flags)
|
||||
{
|
||||
if ((flags & 2) != 0)
|
||||
{
|
||||
// don't support MREMAP_FIXED
|
||||
return Z.SS(-1);
|
||||
}
|
||||
var ret = _parent._mmapheap.Remap((ulong)oldAddress, (ulong)oldSize, (ulong)newSize,
|
||||
(flags & 1) != 0);
|
||||
return ret == 0 ? Z.SS(-1) : Z.US(ret);
|
||||
}
|
||||
[BizExport(CallingConvention.Cdecl, EntryPoint = "n11")]
|
||||
public int MUnmap(UIntPtr address, UIntPtr size)
|
||||
{
|
||||
return _parent._mmapheap.Unmap((ulong)address, (ulong)size) ? 0 : -1;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -511,6 +572,11 @@ namespace BizHawk.Emulation.Cores.Waterbox
|
|||
/// </summary>
|
||||
private Heap _specheap;
|
||||
|
||||
/// <summary>
|
||||
/// memory map emulation
|
||||
/// </summary>
|
||||
private MapHeap _mmapheap;
|
||||
|
||||
/// <summary>
|
||||
/// all loaded PE files
|
||||
/// </summary>
|
||||
|
@ -548,15 +614,22 @@ namespace BizHawk.Emulation.Cores.Waterbox
|
|||
|
||||
private Heap CreateHeapHelper(uint sizeKB, string name, bool saveStated)
|
||||
{
|
||||
var heap = new Heap(_nextStart, sizeKB * 1024, name);
|
||||
heap.Memory.Activate();
|
||||
ComputeNextStart(sizeKB * 1024);
|
||||
AddMemoryBlock(heap.Memory);
|
||||
if (saveStated)
|
||||
_savestateComponents.Add(heap);
|
||||
_disposeList.Add(heap);
|
||||
_heaps.Add(heap);
|
||||
return heap;
|
||||
if (sizeKB != 0)
|
||||
{
|
||||
var heap = new Heap(_nextStart, sizeKB * 1024, name);
|
||||
heap.Memory.Activate();
|
||||
ComputeNextStart(sizeKB * 1024);
|
||||
AddMemoryBlock(heap.Memory);
|
||||
if (saveStated)
|
||||
_savestateComponents.Add(heap);
|
||||
_disposeList.Add(heap);
|
||||
_heaps.Add(heap);
|
||||
return heap;
|
||||
}
|
||||
else
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||
|
@ -566,7 +639,7 @@ namespace BizHawk.Emulation.Cores.Waterbox
|
|||
{
|
||||
Initialize(_nextStart);
|
||||
using (this.EnterExit())
|
||||
{
|
||||
{
|
||||
// load any predefined exports
|
||||
_psx = new Psx(this);
|
||||
_exports.Add("libpsxscl.so", BizExvoker.GetExvoker(_psx));
|
||||
|
@ -610,6 +683,16 @@ namespace BizHawk.Emulation.Cores.Waterbox
|
|||
_invisibleheap = CreateHeapHelper(opt.InvisibleHeapSizeKB, "invisible-heap", false);
|
||||
_specheap = CreateHeapHelper(opt.SpecialHeapSizeKB, "special-heap", true);
|
||||
|
||||
if (opt.MmapHeapSizeKB != 0)
|
||||
{
|
||||
_mmapheap = new MapHeap(_nextStart, opt.MmapHeapSizeKB * 1024, "mmap-heap");
|
||||
_mmapheap.Memory.Activate();
|
||||
ComputeNextStart(opt.MmapHeapSizeKB * 1024);
|
||||
AddMemoryBlock(_mmapheap.Memory);
|
||||
_savestateComponents.Add(_mmapheap);
|
||||
_disposeList.Add(_mmapheap);
|
||||
}
|
||||
|
||||
_syscalls.Init();
|
||||
|
||||
//System.Diagnostics.Debugger.Break();
|
||||
|
@ -729,6 +812,7 @@ namespace BizHawk.Emulation.Cores.Waterbox
|
|||
_sealedheap = null;
|
||||
_invisibleheap = null;
|
||||
_specheap = null;
|
||||
_mmapheap = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -294,11 +294,12 @@ namespace BizHawk.Emulation.Cores.Waterbox
|
|||
s.Size);
|
||||
}
|
||||
Console.WriteLine("GDB Symbol Load:");
|
||||
Console.WriteLine("add-sym {0} {1} -s .data {2} -s .bss {3}",
|
||||
ModuleName,
|
||||
_sectionsByName[".text"].Start,
|
||||
_sectionsByName[".data"].Start,
|
||||
_sectionsByName[".bss"].Start);
|
||||
var symload = $"add-sym {ModuleName} {_sectionsByName[".text"].Start}";
|
||||
if (_sectionsByName.ContainsKey(".data"))
|
||||
symload += $" -s .data {_sectionsByName[".data"].Start}";
|
||||
if (_sectionsByName.ContainsKey(".bss"))
|
||||
symload += $" -s .bss {_sectionsByName[".bss"].Start}";
|
||||
Console.WriteLine(symload);
|
||||
}
|
||||
|
||||
public IntPtr Resolve(string entryPoint)
|
||||
|
|
|
@ -56,5 +56,101 @@ namespace BizHawk.Emulation.Cores.Waterbox
|
|||
{
|
||||
return DateTime.UtcNow.Ticks;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// system page size
|
||||
/// </summary>
|
||||
public static int PageSize { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// bitshift corresponding to PageSize
|
||||
/// </summary>
|
||||
public static int PageShift { get; private set; }
|
||||
/// <summary>
|
||||
/// bitmask corresponding to PageSize
|
||||
/// </summary>
|
||||
public static ulong PageMask { get; private set; }
|
||||
|
||||
static WaterboxUtils()
|
||||
{
|
||||
int p = PageSize = Environment.SystemPageSize;
|
||||
while (p != 1)
|
||||
{
|
||||
p >>= 1;
|
||||
PageShift++;
|
||||
}
|
||||
PageMask = (ulong)(PageSize - 1);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// true if addr is aligned
|
||||
/// </summary>
|
||||
public static bool Aligned(ulong addr)
|
||||
{
|
||||
return (addr & PageMask) == 0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// align address down to previous page boundary
|
||||
/// </summary>
|
||||
public static ulong AlignDown(ulong addr)
|
||||
{
|
||||
return addr & ~PageMask;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// align address up to next page boundary
|
||||
/// </summary>
|
||||
public static ulong AlignUp(ulong addr)
|
||||
{
|
||||
return ((addr - 1) | PageMask) + 1;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// return the minimum number of pages needed to hold size
|
||||
/// </summary>
|
||||
public static int PagesNeeded(ulong size)
|
||||
{
|
||||
return (int)((size + PageMask) >> PageShift);
|
||||
}
|
||||
}
|
||||
|
||||
// C# is annoying: arithmetic operators for native ints are not exposed.
|
||||
// So we store them as long/ulong instead in many places, and use these helpers
|
||||
// to convert to IntPtr when needed
|
||||
|
||||
public static class Z
|
||||
{
|
||||
public static IntPtr US(ulong l)
|
||||
{
|
||||
if (IntPtr.Size == 8)
|
||||
return (IntPtr)(long)l;
|
||||
else
|
||||
return (IntPtr)(int)l;
|
||||
}
|
||||
|
||||
public static UIntPtr UU(ulong l)
|
||||
{
|
||||
if (UIntPtr.Size == 8)
|
||||
return (UIntPtr)l;
|
||||
else
|
||||
return (UIntPtr)(uint)l;
|
||||
}
|
||||
|
||||
public static IntPtr SS(long l)
|
||||
{
|
||||
if (IntPtr.Size == 8)
|
||||
return (IntPtr)l;
|
||||
else
|
||||
return (IntPtr)(int)l;
|
||||
}
|
||||
|
||||
public static UIntPtr SU(long l)
|
||||
{
|
||||
if (UIntPtr.Size == 8)
|
||||
return (UIntPtr)(ulong)l;
|
||||
else
|
||||
return (UIntPtr)(uint)l;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,7 +4,7 @@ CCFLAGS:= -I. -I../emulibc \
|
|||
-Wall -Werror=pointer-to-int-cast -Werror=int-to-pointer-cast -Werror=implicit-function-declaration \
|
||||
-std=c++0x -fomit-frame-pointer -fvisibility=hidden -fno-exceptions -fno-rtti \
|
||||
-DLSB_FIRST \
|
||||
-O0
|
||||
-O0 -g
|
||||
|
||||
TARGET = vb.wbx
|
||||
|
||||
|
@ -29,7 +29,8 @@ $(TARGET).in: $(OBJS)
|
|||
@$(CC) -o $@ $(LDFLAGS) $(CCFLAGS) $(OBJS) ../emulibc/libemuhost.so
|
||||
|
||||
$(TARGET): $(TARGET).in
|
||||
strip $< -o $@ -R /4 -R /14 -R /29 -R /41 -R /55 -R /67 -R /78 -R /89 -R /104
|
||||
# strip $< -o $@ -R /4 -R /14 -R /29 -R /41 -R /55 -R /67 -R /78 -R /89 -R /104
|
||||
cp $< $@
|
||||
|
||||
clean:
|
||||
rm -rf $(OBJ_DIR)
|
||||
|
|
Binary file not shown.
Binary file not shown.
Loading…
Reference in New Issue