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

XFESystem

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

公开
关注 0 Fork 0 Star 0
UTF-8
using Mono.Cecil;
using Mono.Cecil.Cil;

/// <summary>Serial diagnostics must never prevent a machine without COM1 from booting.</summary>
internal static class SerialRuntimePatch
{
    public const string HelperName = "XfeBoundedComWriteV1";
    // An iteration bound deliberately works before any clock, scheduler or IRQ exists.
    // A failed UART is disabled for this boot, so later diagnostics do not repeat it.
    public const int PollLimit = 4096;
    private const string Prefix = "XfeSerialV1_";
    private static readonly string[] CounterNames = ["Absent", "Timeout", "Dropped", "Written"];

    public static bool Apply(AssemblyDefinition assembly)
    {
        if (assembly.Name.Name != "Cosmos.Kernel.Core" || assembly.Name.Version != new Version(3, 0, 94, 0))
            throw new InvalidOperationException("Bounded serial output supports only pinned Cosmos.Kernel.Core 3.0.94.");
        var module = assembly.MainModule;
        var serial = module.Types.Single(type => type.FullName == "Cosmos.Kernel.Core.IO.Serial");
        var write = serial.Methods.Single(method => method.Name == "ComWrite" && method.IsStatic && method.HasBody &&
            method.ReturnType.MetadataType == MetadataType.Void && method.Parameters.Count == 1 && method.Parameters[0].ParameterType.MetadataType == MetadataType.Byte);
        var uart = module.Types.Single(type => type.FullName == "Cosmos.Kernel.Core.CosmosFeatures").Methods.Single(method => method.Name == "get_UARTEnabled");
        var io = module.Types.Single(type => type.FullName == "Cosmos.Kernel.Core.Native").NestedTypes.Single(type => type.Name == "IO");
        var read = io.Methods.Single(method => method.Name == "Read8");
        var output = io.Methods.Single(method => method.Name == "Write8");
        var existing = serial.Methods.SingleOrDefault(method => method.Name == HelperName);
        if (existing is not null)
        {
            Verify(serial, write, uart, read, output);
            return true;
        }
        if (serial.Fields.Any(field => field.Name.StartsWith(Prefix, StringComparison.Ordinal)) ||
            serial.Methods.Any(method => method.Name.StartsWith("XfeSerial", StringComparison.Ordinal)))
            throw new InvalidOperationException("Incomplete or unknown bounded serial patch exists.");
        // Exact pinned x64 body, including branch destinations, constants and native calls.
        if (!OriginalReleaseShape(write, uart, read, output))
            throw new InvalidOperationException("Pinned x64 ComWrite IL changed; refusing to patch an unknown UART implementation.");
        var disabled = new FieldDefinition(Prefix + "Disabled", FieldAttributes.Private | FieldAttributes.Static, module.TypeSystem.Boolean);
        serial.Fields.Add(disabled);
        var counters = CounterNames.ToDictionary(name => name, name => new FieldDefinition(Prefix + name, FieldAttributes.Private | FieldAttributes.Static, module.TypeSystem.UInt64));
        foreach (var counter in counters.Values) serial.Fields.Add(counter);
        var helper = new MethodDefinition(HelperName, MethodAttributes.Private | MethodAttributes.Static | MethodAttributes.HideBySig, module.TypeSystem.Void);
        helper.Parameters.Add(new("value", ParameterAttributes.None, module.TypeSystem.Byte)); serial.Methods.Add(helper);
        EmitHelper(helper, disabled, counters, read, output);
        EmitWrapper(write, uart, helper);
        foreach (var name in CounterNames)
        {
            var getter = new MethodDefinition("XfeSerial" + name + "CountV1", MethodAttributes.Assembly | MethodAttributes.Static | MethodAttributes.HideBySig, module.TypeSystem.UInt64);
            var attribute = new CustomAttribute(module.ImportReference(typeof(System.Runtime.InteropServices.UnmanagedCallersOnlyAttribute).GetConstructor(Type.EmptyTypes)!));
            attribute.Fields.Add(new("EntryPoint", new CustomAttributeArgument(module.TypeSystem.String, "XfeRuntimeSerial" + name + "Count")));
            getter.CustomAttributes.Add(attribute); serial.Methods.Add(getter);
            var il = getter.Body.GetILProcessor(); il.Append(il.Create(OpCodes.Ldsfld, counters[name])); il.Append(il.Create(OpCodes.Ret)); getter.Body.MaxStackSize = 1;
        }
        Verify(serial, write, uart, read, output);
        return false;
    }

    private static bool OriginalReleaseShape(MethodDefinition write, MethodReference uart, MethodReference read, MethodReference output)
    {
        var i = write.Body.Instructions;
        return write.Body.CodeSize == 34 && write.Body.Variables.Count == 0 && write.Body.ExceptionHandlers.Count == 0 && i.Count == 11 &&
            Calls(i[0], uart) && i[1].OpCode == OpCodes.Brfalse_S && ReferenceEquals(i[1].Operand, i[10]) &&
            i[2].OpCode == OpCodes.Ldc_I4 && Equals(i[2].Operand, 0x3fd) && Calls(i[3], read) &&
            i[4].OpCode == OpCodes.Ldc_I4_S && Equals(i[4].Operand, (sbyte)0x20) && i[5].OpCode == OpCodes.And &&
            i[6].OpCode == OpCodes.Brfalse_S && ReferenceEquals(i[6].Operand, i[2]) &&
            i[7].OpCode == OpCodes.Ldc_I4 && Equals(i[7].Operand, 0x3f8) && i[8].OpCode == OpCodes.Ldarg_0 &&
            Calls(i[9], output) && i[10].OpCode == OpCodes.Ret;
    }

    private static void EmitWrapper(MethodDefinition write, MethodReference uart, MethodReference helper)
    {
        write.Body = new MethodBody(write); var il = write.Body.GetILProcessor(); var end = il.Create(OpCodes.Ret);
        il.Append(il.Create(OpCodes.Call, uart)); il.Append(il.Create(OpCodes.Brfalse, end));
        il.Append(il.Create(OpCodes.Ldarg_0)); il.Append(il.Create(OpCodes.Call, helper)); il.Append(end); write.Body.MaxStackSize = 1;
    }

    private static void EmitHelper(MethodDefinition helper, FieldReference disabled, IReadOnlyDictionary<string, FieldDefinition> counters, MethodReference read, MethodReference output)
    {
        helper.Body = new MethodBody(helper) { InitLocals = true, MaxStackSize = 3 };
        var count = new VariableDefinition(helper.Module.TypeSystem.Int32); var status = new VariableDefinition(helper.Module.TypeSystem.Byte);
        helper.Body.Variables.Add(count); helper.Body.Variables.Add(status);
        var il = helper.Body.GetILProcessor();
        var dropped = il.Create(OpCodes.Ldsfld, counters["Dropped"]); var absent = il.Create(OpCodes.Ldsfld, counters["Absent"]);
        var timeout = il.Create(OpCodes.Ldsfld, counters["Timeout"]); var disable = il.Create(OpCodes.Ldc_I4_1);
        var next = il.Create(OpCodes.Ldloc, count); var poll = il.Create(OpCodes.Ldc_I4, 0x3fd);
        il.Append(il.Create(OpCodes.Ldsfld, disabled)); il.Append(il.Create(OpCodes.Brtrue, dropped));
        il.Append(il.Create(OpCodes.Ldc_I4_0)); il.Append(il.Create(OpCodes.Stloc, count));
        il.Append(poll); il.Append(il.Create(OpCodes.Call, read)); il.Append(il.Create(OpCodes.Stloc, status));
        il.Append(il.Create(OpCodes.Ldloc, status)); il.Append(il.Create(OpCodes.Ldc_I4, 0xff)); il.Append(il.Create(OpCodes.Beq, absent));
        il.Append(il.Create(OpCodes.Ldloc, status)); il.Append(il.Create(OpCodes.Ldc_I4, 0x20)); il.Append(il.Create(OpCodes.And)); il.Append(il.Create(OpCodes.Brfalse, next));
        il.Append(il.Create(OpCodes.Ldc_I4, 0x3f8)); il.Append(il.Create(OpCodes.Ldarg_0)); il.Append(il.Create(OpCodes.Call, output));
        Increment("Written"); il.Append(il.Create(OpCodes.Ret));
        il.Append(next); il.Append(il.Create(OpCodes.Ldc_I4_1)); il.Append(il.Create(OpCodes.Add)); il.Append(il.Create(OpCodes.Stloc, count));
        il.Append(il.Create(OpCodes.Ldloc, count)); il.Append(il.Create(OpCodes.Ldc_I4, PollLimit)); il.Append(il.Create(OpCodes.Blt, poll));
        il.Append(timeout); IncrementTail("Timeout"); il.Append(il.Create(OpCodes.Br, disable));
        il.Append(absent); IncrementTail("Absent");
        il.Append(disable); il.Append(il.Create(OpCodes.Stsfld, disabled));
        il.Append(dropped); IncrementTail("Dropped"); il.Append(il.Create(OpCodes.Ret));
        void Increment(string name) { il.Append(il.Create(OpCodes.Ldsfld, counters[name])); IncrementTail(name); }
        void IncrementTail(string name) { il.Append(il.Create(OpCodes.Ldc_I4_1)); il.Append(il.Create(OpCodes.Conv_U8)); il.Append(il.Create(OpCodes.Add)); il.Append(il.Create(OpCodes.Stsfld, counters[name])); }
    }

    private static void Verify(TypeDefinition serial, MethodDefinition write, MethodReference uart, MethodReference read, MethodReference output)
    {
        var helper = serial.Methods.Single(method => method.Name == HelperName);
        var disabled = serial.Fields.Single(field => field.Name == Prefix + "Disabled");
        var counters = CounterNames.ToDictionary(name => name, name => serial.Fields.Single(field => field.Name == Prefix + name));
        if (!disabled.IsPrivate || !disabled.IsStatic || disabled.FieldType.MetadataType != MetadataType.Boolean ||
            counters.Values.Any(field => !field.IsPrivate || !field.IsStatic || field.FieldType.MetadataType != MetadataType.UInt64) ||
            helper.ReturnType.MetadataType != MetadataType.Void || helper.Parameters.Count != 1 || helper.Parameters[0].ParameterType.MetadataType != MetadataType.Byte)
            throw new InvalidOperationException("Unexpected bounded serial state or signature.");
        var expected = new MethodDefinition("Expected", MethodAttributes.Static, serial.Module.TypeSystem.Void);
        expected.Parameters.Add(new("value", ParameterAttributes.None, serial.Module.TypeSystem.Byte)); serial.Methods.Add(expected);
        try
        {
            EmitHelper(expected, disabled, counters, read, output);
            if (Canonical(helper) != Canonical(expected)) throw new InvalidOperationException("Bounded serial helper differs from its fixed polling contract.");
            EmitWrapper(expected, uart, helper);
            if (Canonical(write) != Canonical(expected)) throw new InvalidOperationException("Bounded serial wrapper changed its feature gate.");
        }
        finally { serial.Methods.Remove(expected); }
        foreach (string name in CounterNames)
        {
            var getter = serial.Methods.Single(method => method.Name == "XfeSerial" + name + "CountV1");
            if (getter.Body.Instructions.Count != 2 || getter.Body.Instructions[0].OpCode != OpCodes.Ldsfld ||
                getter.Body.Instructions[0].Operand is not FieldReference field || field.FullName != counters[name].FullName ||
                getter.Body.Instructions[1].OpCode != OpCodes.Ret || !getter.CustomAttributes.Any(attribute => attribute.AttributeType.Name == "UnmanagedCallersOnlyAttribute" &&
                    attribute.Fields.Any(argument => argument.Name == "EntryPoint" && Equals(argument.Argument.Value, "XfeRuntimeSerial" + name + "Count"))))
                throw new InvalidOperationException("Serial diagnostic counter is not a read-only leaf export.");
        }
    }

    private static bool Calls(Instruction i, MethodReference method) => i.OpCode == OpCodes.Call && i.Operand is MethodReference call && call.FullName == method.FullName;
    private static string Canonical(MethodDefinition method) =>
        string.Join(";", method.Body.Variables.Select(variable => variable.VariableType.FullName)) + "|" + method.Body.InitLocals + "|" + method.Body.ExceptionHandlers.Count + "|" +
        string.Join("\n", method.Body.Instructions.Select(instruction => instruction.OpCode.Code + ":" + (instruction.Operand switch
        {
            Instruction branch => "#" + method.Body.Instructions.IndexOf(branch), VariableDefinition local => "$" + local.Index,
            MemberReference member => member.FullName, null => "", var operand => operand.ToString()
        })));
}