waterbox - expose read-only information about the guest memory page table
This commit is contained in:
parent
e778e5248d
commit
1c606c1eb6
Binary file not shown.
Binary file not shown.
|
@ -437,5 +437,10 @@ namespace BizHawk.Emulation.Cores.Nintendo.SNES
|
||||||
_exe.LoadStateBinary(reader);
|
_exe.LoadStateBinary(reader);
|
||||||
_core.PostLoadState();
|
_core.PostLoadState();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public MemoryDomain GetPagesDomain()
|
||||||
|
{
|
||||||
|
return _exe.GetPagesDomain();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -73,7 +73,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.SNES
|
||||||
MakeMemoryDomain("SGB CARTRAM", LibsnesApi.SNES_MEMORY.SGB_CARTRAM, MemoryDomain.Endian.Little);
|
MakeMemoryDomain("SGB CARTRAM", LibsnesApi.SNES_MEMORY.SGB_CARTRAM, MemoryDomain.Endian.Little);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_memoryDomainList.Add(Api.GetPagesDomain());
|
||||||
|
|
||||||
_memoryDomains = new MemoryDomainList(_memoryDomainList);
|
_memoryDomains = new MemoryDomainList(_memoryDomainList);
|
||||||
((BasicServiceProvider) ServiceProvider).Register(_memoryDomains);
|
((BasicServiceProvider) ServiceProvider).Register(_memoryDomains);
|
||||||
|
|
|
@ -94,6 +94,7 @@ namespace BizHawk.Emulation.Cores.Consoles.Sega.gpgx
|
||||||
|
|
||||||
mm.Add(s68Bus);
|
mm.Add(s68Bus);
|
||||||
}
|
}
|
||||||
|
mm.Add(_elf.GetPagesDomain());
|
||||||
|
|
||||||
_memoryDomains = new MemoryDomainList(mm) { SystemBus = m68Bus };
|
_memoryDomains = new MemoryDomainList(mm) { SystemBus = m68Bus };
|
||||||
((BasicServiceProvider) ServiceProvider).Register(_memoryDomains);
|
((BasicServiceProvider) ServiceProvider).Register(_memoryDomains);
|
||||||
|
|
|
@ -73,8 +73,12 @@ namespace BizHawk.Emulation.Cores.Waterbox
|
||||||
var primaryDomain = memoryDomains
|
var primaryDomain = memoryDomains
|
||||||
.Where(md => md.Definition.Flags.HasFlag(LibWaterboxCore.MemoryDomainFlags.Primary))
|
.Where(md => md.Definition.Flags.HasFlag(LibWaterboxCore.MemoryDomainFlags.Primary))
|
||||||
.Single();
|
.Single();
|
||||||
|
|
||||||
var mdl = new MemoryDomainList(memoryDomains.Cast<MemoryDomain>().ToList());
|
var mdl = new MemoryDomainList(
|
||||||
|
memoryDomains.Cast<MemoryDomain>()
|
||||||
|
.Concat(new[] { _exe.GetPagesDomain() })
|
||||||
|
.ToList()
|
||||||
|
);
|
||||||
mdl.MainMemory = primaryDomain;
|
mdl.MainMemory = primaryDomain;
|
||||||
_serviceProvider.Register<IMemoryDomains>(mdl);
|
_serviceProvider.Register<IMemoryDomains>(mdl);
|
||||||
|
|
||||||
|
|
|
@ -218,11 +218,12 @@ namespace BizHawk.Emulation.Cores.Waterbox
|
||||||
return ms.ToArray();
|
return ms.ToArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
// public class MissingFileResult
|
#if false
|
||||||
// {
|
public class MissingFileResult
|
||||||
// public byte[] data;
|
{
|
||||||
// public bool writable;
|
public byte[] data;
|
||||||
// }
|
public bool writable;
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Can be set by the frontend and will be called if the core attempts to open a missing file.
|
/// Can be set by the frontend and will be called if the core attempts to open a missing file.
|
||||||
|
@ -233,29 +234,65 @@ namespace BizHawk.Emulation.Cores.Waterbox
|
||||||
/// if it was for firmware only.
|
/// if it was for firmware only.
|
||||||
/// writable == false is equivalent to AddReadonlyFile, writable == true is equivalent to AddTransientFile
|
/// writable == false is equivalent to AddReadonlyFile, writable == true is equivalent to AddTransientFile
|
||||||
/// </summary>
|
/// </summary>
|
||||||
// public Func<string, MissingFileResult> MissingFileCallback
|
public Func<string, MissingFileResult> MissingFileCallback
|
||||||
// {
|
{
|
||||||
// set
|
set
|
||||||
// {
|
{
|
||||||
// // TODO
|
// TODO
|
||||||
// using (this.EnterExit())
|
using (this.EnterExit())
|
||||||
// {
|
{
|
||||||
// var mfc_o = value == null ? null : new WaterboxHostNative.MissingFileCallback
|
var mfc_o = value == null ? null : new WaterboxHostNative.MissingFileCallback
|
||||||
// {
|
{
|
||||||
// callback = (_unused, name) =>
|
callback = (_unused, name) =>
|
||||||
// {
|
{
|
||||||
// var res = value(name);
|
var res = value(name);
|
||||||
// }
|
}
|
||||||
// };
|
};
|
||||||
|
|
||||||
// NativeImpl.wbx_set_missing_file_callback(_activatedNativeHost, value == null
|
NativeImpl.wbx_set_missing_file_callback(_activatedNativeHost, value == null
|
||||||
// ? null
|
? null
|
||||||
// : )
|
: )
|
||||||
// }
|
}
|
||||||
// }
|
}
|
||||||
// get => _syscalls.MissingFileCallback;
|
get => _syscalls.MissingFileCallback;
|
||||||
// set => _syscalls.MissingFileCallback = value;
|
set => _syscalls.MissingFileCallback = value;
|
||||||
// }
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
public MemoryDomain GetPagesDomain()
|
||||||
|
{
|
||||||
|
return new WaterboxPagesDomain(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
private class WaterboxPagesDomain : MemoryDomain
|
||||||
|
{
|
||||||
|
protected readonly WaterboxHost _host;
|
||||||
|
public WaterboxPagesDomain(WaterboxHost host)
|
||||||
|
{
|
||||||
|
_host = host;
|
||||||
|
|
||||||
|
var retobj = new ReturnData();
|
||||||
|
NativeImpl.wbx_get_page_len(_host._nativeHost, retobj);
|
||||||
|
|
||||||
|
Name = "Waterbox PageData";
|
||||||
|
Size = (long)retobj.GetDataOrThrow();
|
||||||
|
WordSize = 1;
|
||||||
|
EndianType = Endian.Unknown;
|
||||||
|
Writable = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override byte PeekByte(long addr)
|
||||||
|
{
|
||||||
|
var retobj = new ReturnData();
|
||||||
|
NativeImpl.wbx_get_page_data(_host._nativeHost, Z.SU(addr), retobj);
|
||||||
|
return (byte)retobj.GetDataOrThrow();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void PokeByte(long addr, byte val)
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public void SaveStateBinary(BinaryWriter bw)
|
public void SaveStateBinary(BinaryWriter bw)
|
||||||
{
|
{
|
||||||
|
|
|
@ -235,5 +235,24 @@ namespace BizHawk.Emulation.Cores.Waterbox
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[BizImport(CallingConvention.Cdecl)]
|
[BizImport(CallingConvention.Cdecl)]
|
||||||
public abstract void wbx_set_always_evict_blocks(bool val);
|
public abstract void wbx_set_always_evict_blocks(bool val);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Retrieve the number of pages of guest memory that this host is tracking
|
||||||
|
/// </summary>
|
||||||
|
[BizImport(CallingConvention.Cdecl)]
|
||||||
|
public abstract void wbx_get_page_len(IntPtr /*WaterboxHost*/ obj, ReturnData /*UIntPtr*/ ret);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Retrieve basic information for a tracked guest page. Index should be in 0..wbx_get_page_len().
|
||||||
|
/// 1 - readable, implies allocated
|
||||||
|
/// 2 - writable
|
||||||
|
/// 4 - executable
|
||||||
|
/// 0x10 - stack
|
||||||
|
/// 0x20 - allocated but not readable (guest-generated "guard")
|
||||||
|
/// 0x40 - invisible
|
||||||
|
/// 0x80 - dirty
|
||||||
|
/// </summary>
|
||||||
|
[BizImport(CallingConvention.Cdecl)]
|
||||||
|
public abstract void wbx_get_page_data(IntPtr /*WaterboxHost*/ obj, UIntPtr index, ReturnData /*byte*/ ret);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -354,3 +354,26 @@ pub extern fn wbx_set_always_evict_blocks(_val: bool) {
|
||||||
unsafe { ALWAYS_EVICT_BLOCKS = _val; }
|
unsafe { ALWAYS_EVICT_BLOCKS = _val; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Retrieve the number of pages of guest memory that this host is tracking
|
||||||
|
#[no_mangle]
|
||||||
|
pub extern fn wbx_get_page_len(obj: &mut WaterboxHost, ret: &mut Return<usize>) {
|
||||||
|
ret.put(Ok(obj.page_len()))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Retrieve basic information for a tracked guest page. Index should be in 0..wbx_get_page_len().
|
||||||
|
/// 1 - readable, implies allocated
|
||||||
|
/// 2 - writable
|
||||||
|
/// 4 - executable
|
||||||
|
/// 0x10 - stack
|
||||||
|
/// 0x20 - allocated but not readable (guest-generated "guard")
|
||||||
|
/// 0x40 - invisible
|
||||||
|
/// 0x80 - dirty
|
||||||
|
#[no_mangle]
|
||||||
|
pub extern fn wbx_get_page_data(obj: &mut WaterboxHost, index: usize, ret: &mut Return<u8>) {
|
||||||
|
if index >= obj.page_len() {
|
||||||
|
ret.put(Err(anyhow!("Index out of range")))
|
||||||
|
} else {
|
||||||
|
ret.put(Ok(obj.page_info(index)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -154,6 +154,14 @@ impl WaterboxHost {
|
||||||
pub fn run_guest_simple(&mut self, entry_point: usize) {
|
pub fn run_guest_simple(&mut self, entry_point: usize) {
|
||||||
context::call_guest_simple(entry_point, &mut self.context);
|
context::call_guest_simple(entry_point, &mut self.context);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn page_len(&self) -> usize {
|
||||||
|
self.memory_block.page_len()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn page_info(&self, index: usize) -> u8 {
|
||||||
|
self.memory_block.page_info(index)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const SAVE_START_MAGIC: &str = "ActivatedWaterboxHost_v1";
|
const SAVE_START_MAGIC: &str = "ActivatedWaterboxHost_v1";
|
||||||
|
|
|
@ -492,6 +492,32 @@ impl MemoryBlock {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn page_len(&self) -> usize {
|
||||||
|
self.pages.len()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn page_info(&self, index: usize) -> u8 {
|
||||||
|
let p = &self.pages[index];
|
||||||
|
let mut res = match p.status {
|
||||||
|
PageAllocation::Free => 0,
|
||||||
|
PageAllocation::Allocated(prot) => match prot {
|
||||||
|
Protection::None => 0x20,
|
||||||
|
Protection::R => 1,
|
||||||
|
Protection::RW => 3,
|
||||||
|
Protection::RX => 5,
|
||||||
|
Protection::RWX => 7,
|
||||||
|
Protection::RWStack => 0x13,
|
||||||
|
}
|
||||||
|
};
|
||||||
|
if p.dirty {
|
||||||
|
res |= 0x80;
|
||||||
|
}
|
||||||
|
if p.invisible {
|
||||||
|
res |= 0x40;
|
||||||
|
}
|
||||||
|
res
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Drop for MemoryBlock {
|
impl Drop for MemoryBlock {
|
||||||
|
|
Loading…
Reference in New Issue