using System.Runtime.InteropServices;
using XFESystem.Core;
using XFESystem.Storage;
namespace XFESystem.NativeRuntime.Application;
internal sealed unsafe class NativePhysicalDisk : IPhysicalDisk
{
[DllImport("xfe_pal",EntryPoint="xfe_disk_info")] internal static extern ulong Info(uint index,uint field);
[DllImport("xfe_pal",EntryPoint="xfe_disk_read")] static extern int ReadNative(uint index,ulong lba,uint count,byte* bytes);
[DllImport("xfe_pal",EntryPoint="xfe_disk_write")] static extern int WriteNative(uint index,ulong lba,uint count,byte* bytes);
[DllImport("xfe_pal",EntryPoint="xfe_disk_flush")] static extern int FlushNative(uint index);
[DllImport("xfe_pal",EntryPoint="xfe_disk_allow_partition")] static extern int AllowNative(uint index,ulong start,ulong count);
[DllImport("xfe_pal",EntryPoint="xfe_usb_other_info")] internal static extern ulong UsbInfo(uint index,uint field);
[DllImport("xfe_pal",EntryPoint="xfe_usb_other_read")] static extern int UsbRead(uint index,ulong lba,uint count,byte* bytes);
[DllImport("xfe_pal",EntryPoint="xfe_usb_other_write")] static extern int UsbWrite(uint index,ulong lba,uint count,byte* bytes);
[DllImport("xfe_pal",EntryPoint="xfe_usb_other_flush")] static extern int UsbFlush(uint index);
[DllImport("xfe_pal",EntryPoint="xfe_usb_other_allow_partition")] static extern int UsbAllow(uint index,ulong start,ulong count);
readonly uint index;
readonly bool usb;
public string Name {get;}
public ulong SectorCount {get;}
public int LogicalSectorBytes {get;}
public bool CanWrite {get;}
readonly int batch;
public NativePhysicalDisk(uint index,bool usb)
{
this.index=index;this.usb=usb;
Name=(usb?"USB":Info(index,4)==2?"NVMe":"SATA")+index;
SectorCount=usb?UsbInfo(index,3):Info(index,3);CanWrite=usb||Info(index,6)==1;
LogicalSectorBytes=usb?512:1<<(int)Info(index,5);
batch=usb?32768:(int)Math.Min(32768,Info(index,10));if(batch<512)throw new IOException("Disk transfer limit is unavailable.");
}
void Bounds(ulong lba,int bytes)
{if(bytes%512!=0||lba>=SectorCount||(ulong)bytes/512>SectorCount-lba)throw new IOException("Disk I/O leaves its media.");}
public void Read(ulong lba,Span<byte> bytes)
{
Bounds(lba,bytes.Length);
while(!bytes.IsEmpty)
{
int length=Math.Min(bytes.Length,batch);fixed(byte* p=bytes)
{if((usb?UsbRead(index,lba,(uint)length/512,p):ReadNative(index,lba,(uint)length/512,p))!=1)throw new IOException(Name+" read failed.");}
lba+=(uint)length/512;bytes=bytes[length..];
}
}
public void Write(ulong lba,ReadOnlySpan<byte> bytes)
{
Bounds(lba,bytes.Length);
while(!bytes.IsEmpty)
{
int length=Math.Min(bytes.Length,batch);fixed(byte* p=bytes)
{if((usb?UsbWrite(index,lba,(uint)length/512,p):WriteNative(index,lba,(uint)length/512,p))!=1)throw new IOException(Name+" write failed; file was not reported saved.");}
lba+=(uint)length/512;bytes=bytes[length..];
}
}
public void Flush(){if((usb?UsbFlush(index):FlushNative(index))!=1)throw new IOException(Name+" cache synchronization failed.");}
public void AuthorizePartition(ulong start,ulong count)
{if((usb?UsbAllow(index,start,count):AllowNative(index,start,count))!=1)throw new IOException(Name+" partition write extent was refused.");}
}
internal static class NativeOtherDisks
{
public static IWorkspaceBinaryStorage Open(IWorkspaceBinaryStorage workspace)
{
long end=NativePlatform.Milliseconds()+20000;
while((NativePhysicalDisk.Info(0,0)==1||NativePhysicalDisk.UsbInfo(0,0)==1)&&NativePlatform.Milliseconds()<end)Thread.Sleep(10);
var disks=new List<IPhysicalDisk>();
for(uint index=0;index<Math.Min(NativePhysicalDisk.Info(0,1),32);index++)if(NativePhysicalDisk.Info(index,2)==1)disks.Add(new NativePhysicalDisk(index,false));
for(uint index=0;index<Math.Min(NativePhysicalDisk.UsbInfo(0,1),8);index++)if(NativePhysicalDisk.UsbInfo(index,2)==1)disks.Add(new NativePhysicalDisk(index,true));
return new MountedWorkspace(workspace,disks,message=>NativePlatform.PostDiagnostic(message+"\n"));
}
}
using System.Runtime.InteropServices;
using XFESystem.Core;
using XFESystem.Storage;
namespace XFESystem.NativeRuntime.Application;
internal sealed unsafe class NativePhysicalDisk : IPhysicalDisk
{
[DllImport("xfe_pal",EntryPoint="xfe_disk_info")] internal static extern ulong Info(uint index,uint field);
[DllImport("xfe_pal",EntryPoint="xfe_disk_read")] static extern int ReadNative(uint index,ulong lba,uint count,byte* bytes);
[DllImport("xfe_pal",EntryPoint="xfe_disk_write")] static extern int WriteNative(uint index,ulong lba,uint count,byte* bytes);
[DllImport("xfe_pal",EntryPoint="xfe_disk_flush")] static extern int FlushNative(uint index);
[DllImport("xfe_pal",EntryPoint="xfe_disk_allow_partition")] static extern int AllowNative(uint index,ulong start,ulong count);
[DllImport("xfe_pal",EntryPoint="xfe_usb_other_info")] internal static extern ulong UsbInfo(uint index,uint field);
[DllImport("xfe_pal",EntryPoint="xfe_usb_other_read")] static extern int UsbRead(uint index,ulong lba,uint count,byte* bytes);
[DllImport("xfe_pal",EntryPoint="xfe_usb_other_write")] static extern int UsbWrite(uint index,ulong lba,uint count,byte* bytes);
[DllImport("xfe_pal",EntryPoint="xfe_usb_other_flush")] static extern int UsbFlush(uint index);
[DllImport("xfe_pal",EntryPoint="xfe_usb_other_allow_partition")] static extern int UsbAllow(uint index,ulong start,ulong count);
readonly uint index;
readonly bool usb;
public string Name {get;}
public ulong SectorCount {get;}
public int LogicalSectorBytes {get;}
public bool CanWrite {get;}
readonly int batch;
public NativePhysicalDisk(uint index,bool usb)
{
this.index=index;this.usb=usb;
Name=(usb?"USB":Info(index,4)==2?"NVMe":"SATA")+index;
SectorCount=usb?UsbInfo(index,3):Info(index,3);CanWrite=usb||Info(index,6)==1;
LogicalSectorBytes=usb?512:1<<(int)Info(index,5);
batch=usb?32768:(int)Math.Min(32768,Info(index,10));if(batch<512)throw new IOException("Disk transfer limit is unavailable.");
}
void Bounds(ulong lba,int bytes)
{if(bytes%512!=0||lba>=SectorCount||(ulong)bytes/512>SectorCount-lba)throw new IOException("Disk I/O leaves its media.");}
public void Read(ulong lba,Span<byte> bytes)
{
Bounds(lba,bytes.Length);
while(!bytes.IsEmpty)
{
int length=Math.Min(bytes.Length,batch);fixed(byte* p=bytes)
{if((usb?UsbRead(index,lba,(uint)length/512,p):ReadNative(index,lba,(uint)length/512,p))!=1)throw new IOException(Name+" read failed.");}
lba+=(uint)length/512;bytes=bytes[length..];
}
}
public void Write(ulong lba,ReadOnlySpan<byte> bytes)
{
Bounds(lba,bytes.Length);
while(!bytes.IsEmpty)
{
int length=Math.Min(bytes.Length,batch);fixed(byte* p=bytes)
{if((usb?UsbWrite(index,lba,(uint)length/512,p):WriteNative(index,lba,(uint)length/512,p))!=1)throw new IOException(Name+" write failed; file was not reported saved.");}
lba+=(uint)length/512;bytes=bytes[length..];
}
}
public void Flush(){if((usb?UsbFlush(index):FlushNative(index))!=1)throw new IOException(Name+" cache synchronization failed.");}
public void AuthorizePartition(ulong start,ulong count)
{if((usb?UsbAllow(index,start,count):AllowNative(index,start,count))!=1)throw new IOException(Name+" partition write extent was refused.");}
}
internal static class NativeOtherDisks
{
public static IWorkspaceBinaryStorage Open(IWorkspaceBinaryStorage workspace)
{
long end=NativePlatform.Milliseconds()+20000;
while((NativePhysicalDisk.Info(0,0)==1||NativePhysicalDisk.UsbInfo(0,0)==1)&&NativePlatform.Milliseconds()<end)Thread.Sleep(10);
var disks=new List<IPhysicalDisk>();
for(uint index=0;index<Math.Min(NativePhysicalDisk.Info(0,1),32);index++)if(NativePhysicalDisk.Info(index,2)==1)disks.Add(new NativePhysicalDisk(index,false));
for(uint index=0;index<Math.Min(NativePhysicalDisk.UsbInfo(0,1),8);index++)if(NativePhysicalDisk.UsbInfo(index,2)==1)disks.Add(new NativePhysicalDisk(index,true));
return new MountedWorkspace(workspace,disks,message=>NativePlatform.PostDiagnostic(message+"\n"));
}
}