夸克之书

  • 首页
  • 科普
  • 笔记
  • .NET/C#
  • 物联网
  • 算法
  • Linux
  • 树莓派
夸克之内,别有洞天
  1. 首页
  2. 默认
  3. 正文

在代码中判断龙芯新旧世界平台

2025-02-21 569点热度 0人点赞 0条评论

龙芯新旧世界是龙芯基于 LoongArch 架构形成的两套软件生态体系,主要差异体现在 ABI 规范、软件兼容性及开发策略上:

1. 新旧世界的核心区别

  • 旧世界(ABI1.0):早期为快速构建生态,沿用部分 MIPS 遗留设计,指令集未完全脱离 MIPS 兼容模式。其内核由龙芯独立维护(版本多为 4.19、5.4 等),优先支持商业软件(如 QQ、微信),适配发行版包括 Loongnix、麒麟、统信等。旧世界生态闭源程度较高,更新依赖龙芯内部推动。
  • 新世界(ABI2.0):完全遵循开源社区标准重构 LoongArch 指令集,彻底摒弃 MIPS 兼容模式,内核版本更高(≥5.19),由开源社区协作维护。新世界对开源软件兼容性更优(如高版本浏览器、Archlinux 等),并通过 liblol 兼容层支持旧世界商业软件运行。未来旧世界将逐步向新世界迁移,3A6000 及以上 CPU 已实现固件级兼容。

2. 命令行判断方法
通过检测系统原生二进制文件的 ELF 头部标识,可快速区分新旧世界:

hexdump -s 48 -C /usr/bin/sh | head -n 1 | awk '{print $2}'
  • 返回值为 43 表示新世界(ABI2.0)
  • 返回值为 03 表示旧世界(ABI1.0)

此方法通过解析 Shell 解释器的 ELF 头特定字段(e_flags),直接反映 ABI 版本,较内核版本判断更为可靠。若需自动化脚本实现,可将该命令集成至环境检测逻辑中。

3. 在C#中的判断方法

基于上述规则,使用C#判断龙芯新旧世界平台

/// <summary>
/// Helper class for runtime environment information, especially for LoongArch64 architecture.
/// </summary>
internal static class RuntimeInformationHelper
{
    // Pre-compile the regex pattern for kernel version matching
    private static readonly Regex KernelVersionRegex = new(
        @"^(?<major>0|[1-9]\d*)\.(?<minor>0|[1-9]\d*)\.(?<patch>0|[1-9]\d*)(?:-(?<prerelease>(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+(?<buildmetadata>[0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?$",
        RegexOptions.Compiled);
    
    private static readonly Lazy<bool> _isABI1 = new(DetermineIsABI1);
    
    // Version threshold for ABI2
    private static readonly Version Abi2MinVersion = new(5, 19);
    
    // Common executable files to read ELF mark from
    private static readonly string[] ElfExecutables = { "/usr/bin/sh", "/bin/sh", "/usr/bin/bash" };

    /// <summary>
    /// Determines if the current runtime is using ABI1 on LoongArch64 Linux.
    /// </summary>
    /// <returns>True if running on ABI1, false otherwise.</returns>
    public static bool IsABI1() => _isABI1.Value;

    /// <summary>
    /// Determines if the current runtime is LoongArch64 architecture on Linux OS.
    /// </summary>
    /// <returns>True if running on LoongArch64 Linux, false otherwise.</returns>
    public static bool IsLoongArch64Linux() =>
        RuntimeInformation.ProcessArchitecture == Architecture.LoongArch64 &&
        RuntimeInformation.IsOSPlatform(OSPlatform.Linux);

    /// <summary>
    /// Determines if the current LoongArch64 Linux environment is using ABI1.
    /// </summary>
    /// <returns>True if ABI1 is detected, false otherwise.</returns>
    private static bool DetermineIsABI1()
    {
        // Quick check - if not on LoongArch64 Linux, definitely not ABI1
        if (!IsLoongArch64Linux())
        {
            return false;
        }

        // Strategy 1: Check ELF header mark
        string elfMark = ReadELFMark();
        if (elfMark == "03") return true;
        if (elfMark == "43") return false;

        // Strategy 2: Check kernel version
        Version? kernelVersion = DetectKernelVersion();
        if (kernelVersion != null)
        {
            return kernelVersion < Abi2MinVersion;
        }

        // Strategy 3: Check OS description
        return RuntimeInformation.OSDescription.Contains("Loongnix GNU/Linux 20");
    }

    /// <summary>
    /// Detects the kernel version using available methods.
    /// </summary>
    /// <returns>The kernel version or null if detection failed.</returns>
    private static Version? DetectKernelVersion()
    {
        // Try uname syscall first
        string? kernelVersionStr = GetLinuxKernelVersionByUname();
        if (TryMatchKernelVersion(kernelVersionStr, out var version))
        {
            return version;
        }
        
        // Fall back to process execution
        kernelVersionStr = GetLinuxKernelVersionByProcess();
        TryMatchKernelVersion(kernelVersionStr, out version);
        
        return version;
    }

    /// <summary>
    /// Reads the ELF header mark from common executable files.
    /// </summary>
    /// <returns>The ELF mark as a hexadecimal string or empty string if reading failed.</returns>
    private static string ReadELFMark()
    {
        foreach (var filePath in ElfExecutables)
        {
            if (!File.Exists(filePath))
            {
                continue;
            }

            try
            {
                using var fs = new FileStream(filePath, FileMode.Open, FileAccess.Read);
                fs.Seek(48, SeekOrigin.Begin);
                int byteValue = fs.ReadByte();
                if (byteValue != -1)
                {
                    string hexValue = byteValue.ToString("X2");
                    if (hexValue is "43" or "03")
                    {
                        return hexValue;
                    }
                }
            }
            catch (Exception)
            {
                // Continue trying with next file
            }
        }

        return string.Empty;
    }

    /// <summary>
    /// Attempts to parse a kernel version string into a Version object.
    /// </summary>
    /// <param name="kernelVersion">The kernel version string.</param>
    /// <param name="version">The parsed Version object.</param>
    /// <returns>True if parsing succeeded, false otherwise.</returns>
    private static bool TryMatchKernelVersion(string? kernelVersion, out Version? version)
    {
        version = null;
        if (string.IsNullOrWhiteSpace(kernelVersion))
        {
            return false;
        }

        Match match = KernelVersionRegex.Match(kernelVersion);
        if (match.Success &&
            match.Groups.TryGetValue("major", out Group? major) && !string.IsNullOrWhiteSpace(major?.Value) &&
            match.Groups.TryGetValue("minor", out Group? minor) && !string.IsNullOrWhiteSpace(minor?.Value) &&
            Version.TryParse($"{major.Value}.{minor.Value}", out Version? parsedVersion))
        {
            version = parsedVersion;
            return true;
        }

        return false;
    }

    /// <summary>
    /// Gets the Linux kernel version by executing the uname command.
    /// </summary>
    /// <returns>The kernel version string or empty string if execution failed.</returns>
    private static string GetLinuxKernelVersionByProcess()
    {
        try
        {
            using var process = new Process
            {
                StartInfo = new ProcessStartInfo
                {
                    FileName = "uname",
                    Arguments = "-r",
                    RedirectStandardOutput = true,
                    UseShellExecute = false,
                    CreateNoWindow = true
                }
            };
            
            process.Start();
            string output = process.StandardOutput.ReadToEnd().Trim();
            process.WaitForExit();
            return output;
        }
        catch (Exception)
        {
            return string.Empty;
        }
    }

    [DllImport("libc", SetLastError = true)]
    private static extern int uname(IntPtr buf);

    /// <summary>
    /// Gets the Linux kernel version using the uname system call.
    /// </summary>
    /// <returns>The kernel version string or empty string if the call failed.</returns>
    private static string? GetLinuxKernelVersionByUname()
    {
        IntPtr buf = IntPtr.Zero;
        try
        {
            buf = Marshal.AllocHGlobal(400);
            if (uname(buf) == 0)
            {
                return Marshal.PtrToStringAnsi(buf + 130);
            }
            return string.Empty;
        }
        catch (Exception)
        {
            return string.Empty;
        }
        finally
        {
            if (buf != IntPtr.Zero)
            {
                Marshal.FreeHGlobal(buf);
            }
        }
    }
}

注:部分旧世界系统可能通过兼容层运行新世界软件,但原生编译的二进制仍遵循上述规则。开发跨生态应用时,建议优先采用新世界工具链以确保长期兼容性。

本作品采用 知识共享署名-非商业性使用 4.0 国际许可协议 进行许可
标签: 暂无
最后更新:2025-03-25

管理员

这个人很懒,什么都没留下

打赏 点赞
< 上一篇

文章评论

您需要 登录 之后才可以评论
放松一下
https://www.quarkbook.com/wp-content/uploads/2021/05/凤凰传奇-海底(Live).flac
分类
  • .NET/C#
  • Linux
  • 树莓派
  • 物联网
  • 科普
  • 笔记
  • 算法
  • 默认
最新 热点 随机
最新 热点 随机
在代码中判断龙芯新旧世界平台 Windows获取固定后缀的IPv6地址 目前为止,你可能找不到第二台支持志强的1L小主机(P350 Tiny+W-1350+ECC+双NVME+PCIE扩展)!!! iKuai(爱快)实现成都移动IPTV IPoE拨号 Linux EXT4分区误删除后数据恢复 C#连接到巴法云
在代码中判断龙芯新旧世界平台
23种常见的设计模式(1):单例模式 ASP MVC设置Cookie EF MySQL未将引用设置到对象的实例 使用淘宝npm以及安装cnpm 树莓派4B(Raspbian)切换64位内核+简单性能测试 JS判断是手机浏览器还是电脑浏览器
最近评论
Eagle 发布于 9 个月前(10月21日) 参考博主教程成功搞定了成都移动IPTV组播转单播,电脑、手机都可以播放了。但目前有个问题,原IPTV...
rundoze 发布于 11 个月前(08月31日) 牛逼
cc21216695 发布于 2 年前(09月27日) 试了一下,加入启动项也无效,压根没有用
afirefish 发布于 3 年前(11月28日) 非常感谢,非常棒!
》随缘《 发布于 3 年前(11月20日) 最新【一键处理】方法: https://github.com/MrXhh/VSTools/rele...
书签
  • 打赏
  • 毒鸡汤
  • 米店
  • 金鱼直播间

COPYRIGHT © 2023 quarkbook.com. ALL RIGHTS RESERVED.

Theme Kratos Made By Seaton Jiang

蜀ICP备15036129号-9

登录
注册|忘记密码?