using System.Runtime.InteropServices;
using XFESystem.Core;
namespace XFESystem.NativeRuntime.Application;
internal sealed unsafe class NativeWorkspaceDevice : IWorkspaceBlockDevice
{
[DllImport("xfe_pal", EntryPoint="xfe_usb_storage_info")] internal static extern ulong Info(uint field);
[DllImport("xfe_pal", EntryPoint="xfe_usb_storage_read")] private static extern int ReadNative(ulong lba,uint count,byte* data);
[DllImport("xfe_pal", EntryPoint="xfe_usb_storage_write")] private static extern int WriteNative(ulong lba,uint count,byte* data);
[DllImport("xfe_pal", EntryPoint="xfe_usb_storage_flush")] private static extern int FlushNative();
[DllImport("xfe_pal", EntryPoint="xfe_usb_storage_allow_workspace")] private static extern int AllowNative(ulong lba,uint count);
public ulong SectorCount => Info(3);
public void Read(ulong lba,Span<byte> destination)
{
if(destination.Length%512!=0)throw new IOException("USB read must use whole sectors.");
while(!destination.IsEmpty) { int count=Math.Min(destination.Length,65536); fixed(byte* data=destination)if(ReadNative(lba,(uint)count/512,data)!=1)throw new IOException("USB sector read failed."); lba+=(uint)count/512;destination=destination[count..]; }
}
public void Write(ulong lba,ReadOnlySpan<byte> source)
{
if(source.Length%512!=0)throw new IOException("USB write must use whole sectors.");
while(!source.IsEmpty) { int count=Math.Min(source.Length,65536); fixed(byte* data=source)if(WriteNative(lba,(uint)count/512,data)!=1)throw new IOException("USB workspace write failed; data was not reported saved."); lba+=(uint)count/512;source=source[count..]; }
}
public void Flush() { if(FlushNative()!=1)throw new IOException("USB cache synchronization failed."); }
public void AllowWorkspace(ulong lba,uint sectors) { if(AllowNative(lba,sectors)!=1)throw new IOException("USB workspace write extent was refused."); }
}
internal static class NativeWorkspace
{
public static IWorkspaceBinaryStorage Open()
{
long end=NativePlatform.Milliseconds()+20000;
while(NativeWorkspaceDevice.Info(1)==1&&NativePlatform.Milliseconds()<end)Thread.Sleep(10);
if(NativeWorkspaceDevice.Info(2)!=1)
{
NativePlatform.Write("XFE_WORKSPACE|Mode|RAM|Persistent|0|Reason|NoUniqueBootUsbStorage\n");
return new MemoryWorkspace(false);
}
var device=new NativeWorkspaceDevice();var fat=new ReadOnlyFat32Volume(device,NativeWorkspaceDevice.Info(5),NativeWorkspaceDevice.Info(6));
var extent=fat.ContiguousWorkspace();var journal=new UsbWorkspaceJournal(device,extent.Lba);
var workspace=new PersistentUsbWorkspace(journal,fat);
NativePlatform.Write("XFE_WORKSPACE|Mode|USB|Persistent|1|Generation|"+workspace.Generation+"|Start|"+extent.Lba+"|Sectors|"+extent.Sectors+"\n");
return workspace;
}
}
using System.Runtime.InteropServices;
using XFESystem.Core;
namespace XFESystem.NativeRuntime.Application;
internal sealed unsafe class NativeWorkspaceDevice : IWorkspaceBlockDevice
{
[DllImport("xfe_pal", EntryPoint="xfe_usb_storage_info")] internal static extern ulong Info(uint field);
[DllImport("xfe_pal", EntryPoint="xfe_usb_storage_read")] private static extern int ReadNative(ulong lba,uint count,byte* data);
[DllImport("xfe_pal", EntryPoint="xfe_usb_storage_write")] private static extern int WriteNative(ulong lba,uint count,byte* data);
[DllImport("xfe_pal", EntryPoint="xfe_usb_storage_flush")] private static extern int FlushNative();
[DllImport("xfe_pal", EntryPoint="xfe_usb_storage_allow_workspace")] private static extern int AllowNative(ulong lba,uint count);
public ulong SectorCount => Info(3);
public void Read(ulong lba,Span<byte> destination)
{
if(destination.Length%512!=0)throw new IOException("USB read must use whole sectors.");
while(!destination.IsEmpty) { int count=Math.Min(destination.Length,65536); fixed(byte* data=destination)if(ReadNative(lba,(uint)count/512,data)!=1)throw new IOException("USB sector read failed."); lba+=(uint)count/512;destination=destination[count..]; }
}
public void Write(ulong lba,ReadOnlySpan<byte> source)
{
if(source.Length%512!=0)throw new IOException("USB write must use whole sectors.");
while(!source.IsEmpty) { int count=Math.Min(source.Length,65536); fixed(byte* data=source)if(WriteNative(lba,(uint)count/512,data)!=1)throw new IOException("USB workspace write failed; data was not reported saved."); lba+=(uint)count/512;source=source[count..]; }
}
public void Flush() { if(FlushNative()!=1)throw new IOException("USB cache synchronization failed."); }
public void AllowWorkspace(ulong lba,uint sectors) { if(AllowNative(lba,sectors)!=1)throw new IOException("USB workspace write extent was refused."); }
}
internal static class NativeWorkspace
{
public static IWorkspaceBinaryStorage Open()
{
long end=NativePlatform.Milliseconds()+20000;
while(NativeWorkspaceDevice.Info(1)==1&&NativePlatform.Milliseconds()<end)Thread.Sleep(10);
if(NativeWorkspaceDevice.Info(2)!=1)
{
NativePlatform.Write("XFE_WORKSPACE|Mode|RAM|Persistent|0|Reason|NoUniqueBootUsbStorage\n");
return new MemoryWorkspace(false);
}
var device=new NativeWorkspaceDevice();var fat=new ReadOnlyFat32Volume(device,NativeWorkspaceDevice.Info(5),NativeWorkspaceDevice.Info(6));
var extent=fat.ContiguousWorkspace();var journal=new UsbWorkspaceJournal(device,extent.Lba);
var workspace=new PersistentUsbWorkspace(journal,fat);
NativePlatform.Write("XFE_WORKSPACE|Mode|USB|Persistent|1|Generation|"+workspace.Generation+"|Start|"+extent.Lba+"|Sectors|"+extent.Sectors+"\n");
return workspace;
}
}