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

XFESystem

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

公开
关注 0 Fork 0 Star 0
UTF-8
using System.Globalization;
using System.Runtime.InteropServices;
using System.Security.Cryptography;
using System.Text;
using Mono.Cecil;
using Mono.Cecil.Cil;

namespace XfeBootPlatformPatch;

/// <summary>The executing machine has one boot processor; application processors are not started.</summary>
public static class PlatformPatch
{
    public const string PackageVersion = "3.0.94";
    public const string CoreName = "Cosmos.Kernel.Core.X64";
    public const string HalName = "Cosmos.Kernel.HAL.X64";
    public const string CoreOriginalSha256 = "95359dc648a01a2e31ae5fbb513efa3fd796acebd55b69c244c9d4ab988578c0";
    public const string HalOriginalSha256 = "6267612213cbf40a3b20bf56a763652f9075363fb2561d71036d4fe23b164efd";
    public const string PhysicalExport = "XfeRuntimePhysicalCpuCount";
    public const string SchedulerExport = "XfeRuntimeSchedulerCpuCount";
    private const string OriginalTimer = "97693c4fa91997732b61aadc543425be326814a3a7fe5ecbd6fe14316dd70871";
    private const string PatchedTimer = "948a18f6c44247740881c219567b4b1830bfc5dbeb8b133350412bbd70335500";
    private const string OriginalCount = "76314847f293220be85f14b146ed36f9447ebf583898dff04fb0bc21b91600dc";
    private const string PatchedCount = "b9bd48603446583f1db361633209435df227265e38f3883d1a04f2c73bfe01ba";
    private const string OriginalDispatch = "8c41e004b866acbece6ab3a79f1fe856562b7900732a2ba254591233c90f08e5";
    private const string PatchedDispatch = "5e50d316eafcc7d1a4f11aee6dbb0c560a230d25cf1bbbf1decdd517cc844d37";
    private const string PhysicalMethod = "XfePhysicalCpuCountV1";
    private const string SchedulerMethod = "XfeSchedulerCpuCountV1";

    public static void Apply(AssemblyDefinition core, AssemblyDefinition hal)
    {
        Versions(core, hal);
        var timer = Timer(core);
        var count = Count(hal);
        var dispatch = Dispatch(core);
        if (Fingerprint(timer) != OriginalTimer || Fingerprint(count) != OriginalCount || Fingerprint(dispatch) != OriginalDispatch)
            throw new InvalidOperationException("Pinned platform IL changed; refusing to guess a patch location.");
        if (Fingerprint(LatencyPolicyPatch.SchedulerTimer(hal)) != LatencyPolicyPatch.OriginalSchedulerTimer)
            throw new InvalidOperationException("Pinned LAPIC scheduler setup changed.");
        if (hal.MainModule.Types.SelectMany(type => type.Methods).Any(method =>
                method.Name is PhysicalMethod or SchedulerMethod || method.CustomAttributes.Any(attribute =>
                    attribute.AttributeType.FullName == typeof(UnmanagedCallersOnlyAttribute).FullName &&
                    attribute.Fields.Any(field => field.Name == "EntryPoint" && field.Argument.Value is string name &&
                        name is PhysicalExport or SchedulerExport))))
            throw new InvalidOperationException("A platform diagnostic export name is already used.");

        // Retain the exact ACPI getter reference for a read-only physical-topology diagnostic.
        var physical = (MethodReference)count.Body.Instructions[0].Operand;
        count.Body.Instructions.Clear();
        var countIl = count.Body.GetILProcessor();
        countIl.Append(countIl.Create(OpCodes.Ldc_I4_1));
        countIl.Append(countIl.Create(OpCodes.Ret));
        AddExport(hal, PhysicalMethod, PhysicalExport, physical);
        AddExport(hal, SchedulerMethod, SchedulerExport, null);

        var cpu = timer.Body.Instructions.Single(instruction => instruction.Offset == 0x0c);
        cpu.OpCode = OpCodes.Ldc_I4_0;
        cpu.Operand = null;
        var schedulerArguments = timer.Body.Instructions.Single(instruction => instruction.Offset == 0x105);
        var validStack = timer.Body.Instructions.Single(instruction => instruction.Offset == 0x35);
        validStack.Operand = schedulerArguments;
        // Remove the complete normal first-five/every-100-ticks output block, including
        // params object boxing, hexadecimal RSP, and newline. Error diagnostics stay intact.
        var removed = timer.Body.Instructions.Where(instruction => instruction.Offset >= 0x95 && instruction.Offset < 0x105).ToArray();
        foreach (var instruction in removed) timer.Body.Instructions.Remove(instruction);
        // Device-IRQ exit uses the same logical index as the timer. A hardware
        // APIC ID is still used by unchanged routing code, never as this array index.
        var deviceCpu = dispatch.Body.Instructions.Single(instruction => instruction.Offset == 0x73);
        deviceCpu.OpCode = OpCodes.Ldc_I4_0;
        deviceCpu.Operand = null;
        LatencyPolicyPatch.ApplySchedulerTimer(hal);
        Verify(core, hal);
    }

    public static void Verify(AssemblyDefinition core, AssemblyDefinition hal)
    {
        Versions(core, hal);
        var timer = Timer(core);
        var count = Count(hal);
        var dispatch = Dispatch(core);
        if (Fingerprint(timer) != PatchedTimer || Fingerprint(count) != PatchedCount || Fingerprint(dispatch) != PatchedDispatch)
            throw new InvalidOperationException("The installed platform patch differs from its fixed IL contract.");
        if (Fingerprint(LatencyPolicyPatch.SchedulerTimer(hal)) != LatencyPolicyPatch.PatchedSchedulerTimer)
            throw new InvalidOperationException("The installed LAPIC scheduler is not the exact 1 ms contract.");
        var instructions = timer.Body.Instructions;
        if (instructions.Count(instruction => instruction.Operand is MethodReference method && method.Name == "OnTimerInterrupt" &&
                method.DeclaringType.FullName == "Cosmos.Kernel.Core.Scheduler.SchedulerManager") != 1 ||
            instructions.Any(instruction => instruction.Operand is string text && text == "[LAPIC] Timer tick ") ||
            instructions.Any(instruction => instruction.Operand is MethodReference method && method.Name is "GetId" or "SendEOI") ||
            instructions.Count(instruction => instruction.Operand is string text && text == "[LAPIC] ERROR: Invalid RSP at tick ") != 1)
            throw new InvalidOperationException("The timer's tick, error, logical-CPU or EOI contract changed.");
        if (dispatch.Body.Instructions.Count(instruction => instruction.Operand is MethodReference method && method.Name == "ReschedulePendingFromIrq" &&
                method.DeclaringType.FullName == "Cosmos.Kernel.Core.Scheduler.SchedulerManager") != 1 ||
            dispatch.Body.Instructions.Count(instruction => instruction.Operand is MethodReference method && method.Name == "SendEOI") != 2 ||
            dispatch.Body.Instructions.Any(instruction => instruction.Operand is MethodReference method && method.Name == "GetId"))
            throw new InvalidOperationException("The device-IRQ scheduler index or original EOI paths changed.");
        VerifyExport(hal, PhysicalMethod, PhysicalExport, true);
        VerifyExport(hal, SchedulerMethod, SchedulerExport, false);
    }

    public static string Fingerprint(MethodDefinition method)
    {
        string Operand(object? operand) => operand switch
        {
            Instruction branch => "#" + method.Body.Instructions.IndexOf(branch),
            VariableDefinition local => "$" + local.Index,
            MemberReference member => member.FullName,
            null => "",
            IFormattable value => value.ToString(null, CultureInfo.InvariantCulture),
            _ => operand.ToString()!
        };
        var value = string.Join("|", method.IsStatic, method.ReturnType.FullName,
            string.Join(";", method.Parameters.Select(parameter => parameter.ParameterType.FullName)),
            method.Body.InitLocals, method.Body.ExceptionHandlers.Count,
            string.Join(";", method.Body.Variables.Select(local => local.VariableType.FullName)),
            string.Join("\n", method.Body.Instructions.Select(instruction => instruction.OpCode.Code + ":" + Operand(instruction.Operand))));
        return Hash(Encoding.UTF8.GetBytes(value));
    }

    public static string Hash(byte[] bytes) => Convert.ToHexStringLower(SHA256.HashData(bytes));
    private static TypeDefinition Initializer(AssemblyDefinition hal) => hal.MainModule.Types.Single(type => type.FullName == "Cosmos.Kernel.HAL.X64.X64PlatformInitializer");
    public static MethodDefinition Count(AssemblyDefinition hal) => Initializer(hal).Methods.Single(method => method.Name == "GetCpuCount");
    public static MethodDefinition Timer(AssemblyDefinition core) => core.MainModule.Types.Single(type => type.FullName == "Cosmos.Kernel.Core.X64.Cpu.LocalApic").Methods.Single(method => method.Name == "HandleTimerInterrupt");
    public static MethodDefinition Dispatch(AssemblyDefinition core) => core.MainModule.Types.Single(type => type.FullName == "Cosmos.Kernel.Core.X64.Cpu.X64InterruptController").Methods.Single(method => method.Name == "Dispatch");
    private static void Versions(AssemblyDefinition core, AssemblyDefinition hal)
    {
        if (core.Name.Name != CoreName || hal.Name.Name != HalName || core.Name.Version != new Version(3, 0, 94, 0) || hal.Name.Version != new Version(3, 0, 94, 0))
            throw new InvalidOperationException("Only the pinned Cosmos x64 platform 3.0.94 is supported.");
        if (!Timer(core).HasBody || !Count(hal).HasBody || !Dispatch(core).HasBody || Timer(core).Parameters.Count != 1 ||
            Count(hal).Parameters.Count != 0 || Dispatch(core).Parameters.Count != 1)
            throw new InvalidOperationException("Pinned platform method signatures changed.");
    }

    private static void AddExport(AssemblyDefinition hal, string name, string entry, MethodReference? physical)
    {
        var module = hal.MainModule;
        var method = new MethodDefinition(name, MethodAttributes.Assembly | MethodAttributes.Static | MethodAttributes.HideBySig, module.TypeSystem.UInt32);
        var attribute = new CustomAttribute(module.ImportReference(typeof(UnmanagedCallersOnlyAttribute).GetConstructor(Type.EmptyTypes)!));
        attribute.Fields.Add(new("EntryPoint", new CustomAttributeArgument(module.TypeSystem.String, entry)));
        method.CustomAttributes.Add(attribute);
        Initializer(hal).Methods.Add(method);
        var il = method.Body.GetILProcessor();
        il.Append(physical is null ? il.Create(OpCodes.Ldc_I4_1) : il.Create(OpCodes.Call, physical));
        il.Append(il.Create(OpCodes.Ret));
        method.Body.MaxStackSize = 1;
    }

    private static void VerifyExport(AssemblyDefinition hal, string name, string entry, bool physical)
    {
        var method = Initializer(hal).Methods.Single(candidate => candidate.Name == name);
        if (!method.IsAssembly || !method.IsStatic || method.ReturnType.MetadataType != MetadataType.UInt32 || method.Parameters.Count != 0 ||
            !method.HasBody || method.Body.InitLocals || method.Body.Variables.Count != 0 || method.Body.ExceptionHandlers.Count != 0 ||
            method.Body.Instructions.Count != 2 || method.Body.Instructions[1].OpCode != OpCodes.Ret ||
            method.CustomAttributes.Count != 1 || method.CustomAttributes[0].AttributeType.FullName != typeof(UnmanagedCallersOnlyAttribute).FullName ||
            method.CustomAttributes[0].Fields.Count != 1 || method.CustomAttributes[0].Fields[0].Name != "EntryPoint" ||
            !Equals(method.CustomAttributes[0].Fields[0].Argument.Value, entry))
            throw new InvalidOperationException("The platform diagnostic export signature changed.");
        var first = method.Body.Instructions[0];
        if (physical ? first.OpCode != OpCodes.Call || first.Operand is not MethodReference getter ||
                getter.FullName != "System.UInt32 Cosmos.Kernel.Core.X64.AcpiMadt::get_CpuCount()" : first.OpCode != OpCodes.Ldc_I4_1)
            throw new InvalidOperationException("The platform diagnostic is not its expected read-only leaf.");
    }
}