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.Boot;

// XFESystem-owned, pointer-free firmware resource snapshot. It does not transfer
// a compute context, firmware session, mappings or an acceleration claim.
[StructLayout(LayoutKind.Sequential)]
public struct FirmwareGpuBar
{
    public uint Index, Flags;
    public ulong Address, Bytes;
}

[StructLayout(LayoutKind.Sequential)]
public unsafe struct FirmwareGpuDevice
{
    public uint Segment, Bus, Device, Function, VendorId, DeviceId, ClassCode, Command;
    public fixed byte Bars[6 * 24];
}

[StructLayout(LayoutKind.Sequential)]
public unsafe struct FirmwareGpuHandoff
{
    public const ulong Signature = 0x3130555047454658; // XFEGPU01
    public const ulong GuidLow = 0x4d2858ad448d9951, GuidHigh = 0x91b4025496e031ba;
    public const uint MaximumDevices = 8, DeviceBytes = 176, TotalBytes = 32 + 8 * DeviceBytes;
    public ulong Magic;
    public uint Version, Bytes, Count, Flags, Checksum, Reserved;
    public fixed byte Devices[8 * 176];
}

public static unsafe class FirmwareGpuResources
{
    public const uint Valid = 1, Memory = 2, Io = 4, Width64 = 8, Prefetch = 16;
    public static uint Checksum(byte* bytes, uint length)
    {
        uint crc = 0xffffffff;
        for (uint i = 0; i < length; i++)
        {
            // The checksum field itself is zero during CRC computation.
            crc ^= i >= 24 && i < 28 ? (byte)0 : bytes[i];
            for (uint bit = 0; bit < 8; bit++) crc = (crc >> 1) ^ ((crc & 1) != 0 ? 0xedb88320u : 0);
        }
        return ~crc;
    }

    public static bool Validate(FirmwareGpuHandoff* report, uint availableBytes)
    {
        return report != null && availableBytes >= FirmwareGpuHandoff.TotalBytes &&
            report->Magic == FirmwareGpuHandoff.Signature && report->Version == 1 &&
            report->Bytes == FirmwareGpuHandoff.TotalBytes && report->Count <= FirmwareGpuHandoff.MaximumDevices &&
            report->Reserved == 0 && report->Checksum == Checksum((byte*)report, report->Bytes);
    }

    static ulong Read64(byte* bytes)
    {
        ulong result = 0;
        for (uint i = 0; i < 8; i++) result |= (ulong)bytes[i] << (int)(i * 8);
        return result;
    }

    // EFI_PCI_IO.GetBarAttributes returns an ACPI QWORD resource descriptor.
    // Accept the x86 identity-translation case only; do not guess host/bus
    // translation, BAR lengths or an aperture from a vendor/device ID.
    public static bool DecodeBarDescriptor(byte* descriptor, uint bytes, uint index, uint barLow,
        uint barHigh, FirmwareGpuBar* result)
    {
        if (result == null) return false;
        *result = default;
        if (descriptor == null || bytes < 48 || index >= 6 || descriptor[0] != 0x8a ||
            descriptor[1] != 43 || descriptor[2] != 0 || descriptor[46] != 0x79) return false;
        bool io = (barLow & 1) != 0;
        uint type = (barLow >> 1) & 3;
        if ((!io && type != 0 && type != 2) || (!io && type == 2 && index == 5) ||
            descriptor[3] != (io ? 1 : 0)) return false;
        ulong address = io ? barLow & 0xfffffffcu : barLow & 0xfffffff0u;
        if (!io && type == 2) address |= (ulong)barHigh << 32;
        ulong granularity = Read64(descriptor + 6);
        ulong minimum = Read64(descriptor + 14), alignment = Read64(descriptor + 22);
        ulong translation = Read64(descriptor + 30), length = Read64(descriptor + 38);
        if (translation != 0 || minimum != address || address == 0 || length == 0 ||
            (length & (length - 1)) != 0 || address > ~0UL - (length - 1) ||
            // GetBarAttributes uses AddrRangeMax for the BAR alignment mask,
            // not an inclusive ending address (EDK II PciIoGetBarAttributes).
            alignment != length - 1 || (address & (length - 1)) != 0 ||
            (!io && granularity != (type == 2 ? 64UL : 32UL)) ||
            (!io && type == 0 && length - 1 > 0xffffffffUL - address) ||
            (io && (address > 65535 || length - 1 > 65535 - address))) return false;
        result->Index = index;
        result->Flags = Valid | (io ? Io : Memory) | (!io && type == 2 ? Width64 : 0) |
            (!io && (barLow & 8) != 0 ? Prefetch : 0);
        result->Address = address; result->Bytes = length;
        return true;
    }
}