XFE Git
XFE Studio Git
Git 首页 全局搜索
XFE 主站 文档 NuGet

XFESystem

【Rust】XFE系统,基于Rust和汇编

公开
关注 0 Fork 0 Star 0
UTF-8
using System.Runtime.InteropServices;

namespace XFESystem.NativeKernel;

public unsafe struct UsbMassDevice
{
    public UsbDevice* Device;
    public UsbRing InputRing, OutputRing;
    public ulong Packet, Data, Completed, Blocks, PartitionStart, PartitionEnd, AllowedStart, AllowedCount;
    public uint InputDci, OutputDci, CompletionCode, Remaining, Active, Tag, BootMatch;
}

// USB-IF Bulk-Only Transport, SCSI transparent command set, LUN 0, 512-byte sectors.
// No native buffer passed here belongs to the managed GC. Only the USB worker
// owns rings/DMA; callers exchange bounded copies through a kernel mailbox.
public static unsafe partial class UsbXhci
{
    static UsbMassDevice* _mass, _bootMass;
    static uint _massCount, _bootMatches, _requestState, _requestKind, _requestCount, _requestDevice;
    static ulong _requestLba, _mailbox, _writeStart, _writeCount, _storageReads, _storageWrites, _storageFlushes;
    static uint Crc(byte* p,uint count)
    { uint crc=0xffffffff;for(uint i=0;i<count;i++){crc^=p[i];for(uint j=0;j<8;j++)crc=crc>>1^((crc&1)!=0?0xedb88320u:0);}return ~crc; }
    static uint Be32(byte* p) => (uint)p[0]<<24|(uint)p[1]<<16|(uint)p[2]<<8|p[3];
    static void SetBe32(byte* p,uint n){p[0]=(byte)(n>>24);p[1]=(byte)(n>>16);p[2]=(byte)(n>>8);p[3]=(byte)n;}
    static void AddStorage(UsbDevice* d,byte* descriptors,uint bytes)
    {
        uint iface=0,valid=0,input=0,output=0,inPacket=0,outPacket=0;
        for(uint at=0;at+2<=bytes;)
        {
            uint size=descriptors[at],type=descriptors[at+1];if(size<2||size>bytes-at)break;
            if(type==4&&size>=9)
            {
                if(valid!=0&&input!=0&&output!=0)break;
                iface=descriptors[at+2];input=output=0;
                valid=descriptors[at+3]==0&&descriptors[at+5]==8&&descriptors[at+6]==6&&descriptors[at+7]==80?1u:0;
            }
            else if(type==5&&size>=7&&valid!=0&&(descriptors[at+3]&3)==2)
            {
                uint address=descriptors[at+2],packet=(uint)(descriptors[at+4]|descriptors[at+5]<<8)&2047;
                if((address&15)!=0&&packet!=0&&packet<=1024)
                {if((address&128)!=0){input=address;inPacket=packet;}else{output=address;outPacket=packet;}}
            }
            at+=size;
        }
        if(valid==0||input==0||output==0||_massCount>=8)return;
        if(_mass==null)_mass=(UsbMassDevice*)At(Allocate(2));
        if(_mass==null)return;
        UsbMassDevice* m=&_mass[_massCount++];m->Device=d;m->InputDci=(input&15)*2+1;m->OutputDci=(output&15)*2;
        m->Packet=Allocate();ulong storage=Allocate(32);m->Data=(storage+65535)&~65535UL;
        if(m->Packet==0||storage==0||!NewRing(&m->InputRing)||!NewRing(&m->OutputRing))return;
        uint* ic=Context(d,0);ic[0]=0;ic[1]=1u|(1u<<(int)m->InputDci)|(1u<<(int)m->OutputDci);CopyContext(d,1);
        uint last=m->InputDci>m->OutputDci?m->InputDci:m->OutputDci;
        uint* sc=Context(d,1);if((sc[0]>>27)<last)sc[0]=(sc[0]&0x7ffffff)|last<<27;
        uint* ei=Context(d,m->InputDci+1),eo=Context(d,m->OutputDci+1);
        ei[1]=3u<<1|6u<<3|inPacket<<16;((ulong*)(ei+2))[0]=m->InputRing.Physical|1;ei[4]=inPacket;
        eo[1]=3u<<1|2u<<3|outPacket<<16;((ulong*)(eo+2))[0]=m->OutputRing.Physical|1;eo[4]=outPacket;
        uint slot;if(!Command(d->Controller,12,d->Input,d->Slot<<24,out slot)){DeviceLog(d,"STORAGE_ENDPOINT_FAILED");return;}
        m->Active=1;
        byte* cdb=stackalloc byte[16];for(uint i=0;i<16;i++)cdb[i]=0;
        bool ready=false;
        for(uint attempt=0;attempt<8;attempt++)
        {
            cdb[0]=0;if(Scsi(m,cdb,6,0,true)){ready=true;break;}
            cdb[0]=3;cdb[4]=18;Scsi(m,cdb,6,18,true);cdb[4]=0;Sleep(100);
        }
        if(!ready){m->Active=0;DeviceLog(d,"STORAGE_NOT_READY");return;}
        cdb[0]=0x25;if(!Scsi(m,cdb,10,8,true)){m->Active=0;return;}
        byte* capacity=At(m->Data);uint lastBlock=Be32(capacity),sectorBytes=Be32(capacity+4);
        if(lastBlock==0xffffffff||sectorBytes!=512){m->Active=0;DeviceLog(d,"STORAGE_SECTOR_SIZE_OR_CAPACITY_UNSUPPORTED");return;}
        m->Blocks=(ulong)lastBlock+1;
        if(_mailbox==0)_mailbox=Allocate(16);
        if(_mailbox==0){m->Active=0;return;}
        if(!MatchBootVolume(m)){DeviceLog(d,"STORAGE_NOT_BOOT_VOLUME_READ_ONLY");return;}
        m->BootMatch=1;_bootMatches++;_bootMass=m;
        // One short cold-start record, before the boot workspace is available.
        // Runtime/disk worker preemption must not splice fields into this ABI
        // acknowledgement. UART polling remains bounded; no per-I/O or frame
        // logging is added to the interrupt-excluded region.
        ulong readyLogFlags=Native.IrqSave();
        Serial.Write("XFE_USB_STORAGE_READY|Matches|");Serial.Number(_bootMatches);Serial.Write("|Blocks|");Serial.Number(m->Blocks);Serial.Line("|SectorBytes|512|Transport|BOT");
        Native.IrqRestore(readyLogFlags);
    }
    static bool CompleteStorage(UsbDevice* d,uint endpoint,ulong pointer,uint code,uint remaining)
    {
        for(uint i=0;i<_massCount;i++)
        {
            UsbMassDevice* m=&_mass[i];if(m->Device!=d||(endpoint!=m->InputDci&&endpoint!=m->OutputDci))continue;
            m->Completed=pointer;m->CompletionCode=code;m->Remaining=remaining;return true;
        }
        return false;
    }
    static bool Bulk(UsbMassDevice* m,bool input,ulong address,uint bytes)
    {
        if(m->Active==0||m->Device->Connected==0||bytes==0||bytes>65536||(address&65535)+bytes>65536)return false;
        UsbRing* ring=input?&m->InputRing:&m->OutputRing;
        ulong pending=Put(ring,address,bytes,(1u<<10)|32|4);m->Completed=0;
        Write(m->Device->Controller->Doorbell+m->Device->Slot*4,input?m->InputDci:m->OutputDci);
        ulong end=Now()+2000;
        do
        {
            Events(m->Device->Controller);
            if(m->Completed==pending)
            {
                if((m->CompletionCode==1||m->CompletionCode==13)&&m->Remaining==0)return true;
                break;
            }
            Sleep(1);
        }while(Now()<end);
        m->Active=0;Failures++;DeviceLog(m->Device,"STORAGE_TRANSFER_FAILED_QUARANTINED");return false;
    }
    static bool Scsi(UsbMassDevice* m,byte* command,uint commandBytes,uint bytes,bool input)
    {
        if(commandBytes==0||commandBytes>16||bytes>65536||m->Active==0)return false;
        byte* packet=At(m->Packet);for(uint i=0;i<31;i++)packet[i]=0;
        *(uint*)packet=0x43425355;*(uint*)(packet+4)=++m->Tag;*(uint*)(packet+8)=bytes;
        packet[12]=input?(byte)128:(byte)0;packet[14]=(byte)commandBytes;
        for(uint i=0;i<commandBytes;i++)packet[15+i]=command[i];
        if(!Bulk(m,false,m->Packet,31)||bytes!=0&&!Bulk(m,input,m->Data,bytes)||!Bulk(m,true,m->Packet,13))return false;
        if(*(uint*)packet!=0x53425355||*(uint*)(packet+4)!=m->Tag||*(uint*)(packet+8)!=0||packet[12]>1)
        {m->Active=0;Failures++;return false;}
        return packet[12]==0;
    }
    static bool Sectors(UsbMassDevice* m,ulong lba,uint count,bool write)
    {
        if(m==null||count==0||count>128||lba>=m->Blocks||count>m->Blocks-lba||lba>0xffffffff)return false;
        if(write)
        {
            ulong start=m==_bootMass?_writeStart:m->AllowedStart,size=m==_bootMass?_writeCount:m->AllowedCount;
            if(m==_bootMass?_bootMatches!=1:m->BootMatch!=0)return false;
            if(size==0||lba<start||lba-start>=size||count>size-(lba-start))return false;
        }
        byte* command=stackalloc byte[16];for(uint i=0;i<16;i++)command[i]=0;
        command[0]=write?(byte)0x2a:(byte)0x28;SetBe32(command+2,(uint)lba);command[7]=(byte)(count>>8);command[8]=(byte)count;
        bool ok=Scsi(m,command,10,count*512,!write);
        if(ok){if(write)_storageWrites+=count;else _storageReads+=count;}return ok;
    }
    static bool MatchBootVolume(UsbMassDevice* m)
    {
        NativeBootInfo* boot=Kernel.Boot;
        if((boot->BootDiskIdLow|boot->BootDiskIdHigh)==0||(boot->BootPartitionIdLow|boot->BootPartitionIdHigh)==0||!Sectors(m,1,1,false))return false;
        byte* header=At(m->Data);
        if(*(ulong*)header!=0x5452415020494645UL||*(uint*)(header+12)!=92||((ulong*)(header+56))[0]!=boot->BootDiskIdLow||((ulong*)(header+56))[1]!=boot->BootDiskIdHigh)return false;
        byte* copy=stackalloc byte[92];for(uint i=0;i<92;i++)copy[i]=header[i];*(uint*)(copy+16)=0;
        if(Crc(copy,92)!=*(uint*)(header+16)||*(uint*)(header+80)!=128||*(uint*)(header+84)!=128)return false;
        ulong entries=*(ulong*)(header+72);uint crc=*(uint*)(header+88);
        if(!Sectors(m,entries,32,false)||Crc(At(m->Data),16384)!=crc)return false;
        byte* table=At(m->Data);
        for(uint i=0;i<128;i++)
        {
            byte* entry=table+i*128;
            if(((ulong*)(entry+16))[0]!=boot->BootPartitionIdLow||((ulong*)(entry+16))[1]!=boot->BootPartitionIdHigh)continue;
            m->PartitionStart=*(ulong*)(entry+32);m->PartitionEnd=*(ulong*)(entry+40);
            return m->PartitionStart>=34&&m->PartitionEnd>=m->PartitionStart&&m->PartitionEnd<m->Blocks;
        }
        return false;
    }
    static void DisconnectStorage(UsbDevice* d)
    {
        for(uint i=0;i<_massCount;i++)if(_mass[i].Device==d){_mass[i].Active=0;if(_mass[i].BootMatch!=0){_mass[i].BootMatch=0;if(_bootMatches!=0)_bootMatches--;}}
        if(_bootMass!=null&&_bootMass->Device==d){_writeCount=0;_bootMass=null;}
    }
    static void ProcessStorageRequest()
    {
        Native.MemoryBarrier();if(_requestState!=1)return;_requestState=2;
        bool ok=false;UsbMassDevice* m=_requestDevice==0xffffffffu?_bootMass:_requestDevice<_massCount?&_mass[_requestDevice]:null;
        if(m!=null&&m->Active!=0&&m->Device->Connected!=0&&(_requestDevice==0xffffffffu?_bootMatches==1:m->BootMatch==0))
        {
            if(_requestKind==3)
            {
                byte* command=stackalloc byte[16];for(uint i=0;i<16;i++)command[i]=0;command[0]=0x35;
                ok=Scsi(m,command,10,0,true);if(ok)_storageFlushes++;
            }
            else
            {
                if(_requestKind==2)for(uint i=0;i<_requestCount*512;i++)At(m->Data)[i]=At(_mailbox)[i];
                ok=Sectors(m,_requestLba,_requestCount,_requestKind==2);
                if(ok&&_requestKind==1)for(uint i=0;i<_requestCount*512;i++)At(_mailbox)[i]=At(m->Data)[i];
            }
        }
        Native.MemoryBarrier();_requestState=_requestState==6?0u:ok?3u:4u;
    }
    static int Request(uint kind,ulong lba,uint count,byte* buffer,uint device=0xffffffffu)
    {
        UsbMassDevice* m=device==0xffffffffu?_bootMass:device<_massCount?&_mass[device]:null;
        if(m==null||m->Active==0||m->Device->Connected==0||(device==0xffffffffu?_bootMatches!=1:m->BootMatch!=0)||_mailbox==0||kind!=3&&(buffer==null||count==0||count>128))return 0;
        ulong irq=Native.IrqSave();if(_requestState!=0){Native.IrqRestore(irq);return 0;}
        if(kind==2)for(uint i=0;i<count*512;i++)At(_mailbox)[i]=buffer[i];
        _requestDevice=device;_requestKind=kind;_requestLba=lba;_requestCount=count;_requestState=1;Native.MemoryBarrier();Native.IrqRestore(irq);
        ulong end=Now()+10000;
        for(;;)
        {
            Native.MemoryBarrier();uint state=_requestState;
            if(state==3||state==4)
            {
                if(state==3&&kind==1)for(uint i=0;i<count*512;i++)buffer[i]=At(_mailbox)[i];
                _requestState=0;Native.MemoryBarrier();return state==3?1:0;
            }
            if(Now()>=end)
            {irq=Native.IrqSave();uint current=_requestState;if(current==1)_requestState=0;else if(current==2)_requestState=6;Native.IrqRestore(irq);if(current==3||current==4)continue;return 0;}
            Sleep(1);
        }
    }
    [UnmanagedCallersOnly(EntryPoint="xfe_usb_storage_info")]
    public static ulong StorageInfo(uint field)
    {
        Native.MemoryBarrier();UsbMassDevice* m=_bootMatches==1?_bootMass:null;
        return field switch {0=>1,1=>State,2=>m!=null&&m->Active!=0?1UL:0,3=>m==null?0:m->Blocks,4=>512,
            5=>m==null?0:m->PartitionStart,6=>m==null?0:m->PartitionEnd,7=>_storageReads,8=>_storageWrites,9=>_storageFlushes,
            10=>_writeStart,11=>_writeCount,12=>Kernel.Boot->BootDiskIdLow,13=>Kernel.Boot->BootDiskIdHigh,
            14=>Kernel.Boot->BootPartitionIdLow,15=>Kernel.Boot->BootPartitionIdHigh,_=>0};
    }
    [UnmanagedCallersOnly(EntryPoint="xfe_usb_storage_read")]
    public static int StorageRead(ulong lba,uint count,byte* buffer)=>Request(1,lba,count,buffer);
    [UnmanagedCallersOnly(EntryPoint="xfe_usb_storage_write")]
    public static int StorageWrite(ulong lba,uint count,byte* buffer)=>Request(2,lba,count,buffer);
    [UnmanagedCallersOnly(EntryPoint="xfe_usb_storage_flush")]
    public static int StorageFlush()=>Request(3,0,0,null);
    [UnmanagedCallersOnly(EntryPoint="xfe_usb_storage_allow_workspace")]
    public static int AllowWorkspace(ulong lba,uint count)
    {
        if(_bootMatches!=1||_bootMass==null||_writeCount!=0||count!=131072||lba<_bootMass->PartitionStart||lba>_bootMass->PartitionEnd||count>_bootMass->PartitionEnd-lba+1)return 0;
        byte* descriptor=stackalloc byte[512];if(Request(1,lba,1,descriptor)!=1)return 0;
        if(*(ulong*)descriptor!=0x5357425355454658UL||*(uint*)(descriptor+8)!=1||*(uint*)(descriptor+12)!=count||
            *(uint*)(descriptor+16)!=65535||*(uint*)(descriptor+20)!=Crc(descriptor,20))return 0;
        _writeStart=lba+1;_writeCount=131070;Native.MemoryBarrier();return 1;
    }
    [UnmanagedCallersOnly(EntryPoint="xfe_usb_other_info")]
    public static ulong OtherInfo(uint index,uint field)
    {
        Native.MemoryBarrier();if(field==0)return State;if(field==1)return _massCount;if(index>=_massCount)return 0;
        UsbMassDevice* m=&_mass[index];return field switch {2=>m->Active!=0&&m->Device->Connected!=0&&m->BootMatch==0?1UL:0,3=>m->Blocks,_=>0};
    }
    [UnmanagedCallersOnly(EntryPoint="xfe_usb_other_read")]
    public static int OtherRead(uint index,ulong lba,uint count,byte* buffer)=>Request(1,lba,count,buffer,index);
    [UnmanagedCallersOnly(EntryPoint="xfe_usb_other_write")]
    public static int OtherWrite(uint index,ulong lba,uint count,byte* buffer)=>Request(2,lba,count,buffer,index);
    [UnmanagedCallersOnly(EntryPoint="xfe_usb_other_flush")]
    public static int OtherFlush(uint index)=>Request(3,0,0,null,index);
    [UnmanagedCallersOnly(EntryPoint="xfe_usb_other_allow_partition")]
    public static int OtherAllow(uint index,ulong start,ulong count)
    {
        if(index>=_massCount||_mass[index].Active==0||_mass[index].BootMatch!=0||start==0||count==0||start>=_mass[index].Blocks||count>_mass[index].Blocks-start)return 0;
        ulong irq=Native.IrqSave();if(_requestState!=0){Native.IrqRestore(irq);return 0;}
        _mass[index].AllowedStart=start;_mass[index].AllowedCount=count;Native.MemoryBarrier();Native.IrqRestore(irq);return 1;
    }
}