简单介绍 LoongArch 和在 LoongArch 上开发的注意事项。

LoongArch 简介

LoongArch 是一种精简指令集计算机风格的指令架构,由龙芯中科技术股份有限公司在 2021 年正式推出。 从字面来看,“LoongArch” 是 “Loongson”(龙芯的英文名)和 “Architecture”(体系结构的英文) 混合而成,指“龙芯架构”。

不难看出 LoongArch 吸取了很多 MIPS 和 RISC-V 的经验教训,个人认为最显著的是它取消了延迟槽,采用了和 RISC-V 相似的 psABI,相关内容可以参考 LoongArch 汇编

新世界和旧世界

现在很多社区都提到了 LoongArch 的“新世界”和“旧世界”,这是没法回避的。 简单地说,就是把产品版系统称为“旧世界”,把社区开源软件构建的系统称为“新世界”。

到底什么是新什么是旧,其实没有明确的界限,这个要从新旧世界的来源说起。 刚迁移到 LoongArch 时,这是一个崭新的架构,第一件事当然是在这个架构上把系统跑起来。 那怎么才能最快得把系统跑起来呢,因为龙芯公司以前主要做 MIPS,对 MIPS 系统软件非常熟悉,所以自然是把 MIPS 的代码稍作更改,转换成 LoongArch 的做法。 进一步,早期的商业发行版也就这么做出来了。 确实这样的系统已经能够使用了,但不能止步如此,LoongArch 要力争上游。

要把 LoongArch 的软件推向上游,并不是一件容易的事,因为上游对代码风格有较为严格的要求。 显然,MIPS 改版的代码让内核上游非常不满,被老外写文章批判,这也被国内自媒体抓住机会,立马发文说 LoongArch 就是 MIPS(老外原文只是表示对代码的强烈不满,但并没否认 LoongArch 不是 MIPS 这一基本事实),来赚取流量,链接我就不贴了,有兴趣可以在网上查到。 既然确定了这样走不通,那就要重视社区的意见,让代码更加规范、更加“独立”。 如果只是普通的代码风格,那还好说,但很多关键的 API,也需要按照上游要求进行更改,来更加“现代化”。 不止是内核,编译器、C 库等基础系统软件都需要更改,这些更改基本上重构了 LoongArch 架构的代码,但也带来了不兼容。 毕竟用户相关的 API 都更改了,那在旧系统上能运行的软件,放在新系统上,完全无法正常工作,反之亦然。 更要命的是,这些更改是根据上游意见,循序渐进的,而每次小更改,都会导致整个系统层面的不兼容,需要重新构建整个系统。 这样代价过于大,显然不可接受。

于是到了拍板的时候了,已经推出的发行版不能这样大改,要尽可能保留原本的风格、保证兼容。 而需要推到社区的代码,参照社区的意见,彻底放弃与旧发行版兼容,走自己的路线。 这是没办法的妥协,但也能被大部分人接受,就这样,新旧世界的概念被真正抛上了台面。 新世界完全在进入上游前,自然是不停变化的,随时都可能修改,所以我们在讨论新世界时,永远是指最新的那个;但旧世界真的是最初的那个旧世界吗,这要打个问号了。

从发展的角度看,新世界必然会取代旧世界,只是时间问题,而旧世界的商业发行版通常是闭源的,普通开发者也参与不了,所以后续都以在新世界(这里特指 Linux 平台)上开发为前提。

如何上手

要开发的软件涉及两大类:

  • 应用软件
  • 系统软件

理论上在基础设施很完善时,在 LoongArch 上开发应用软件和在其他架构上开发是差别不大的。 这种情况下,不需要开发者懂得不同架构的区别,甚至不需要开发者刻意去学习新的知识。 比如对于 Python 程序员,Python 如果已经在 LoongArch 上被很好地支持,他完全可以像在 x86 Linux 上开发一样,不需要额外学习任何知识。 当然,这个大前提很难满足,满足的时候就说明 LoongArch 生态真的建立好了。

而系统软件则对开发者有较高的要求,我觉得可以分为很多阶段(可能跳过第 2 和第 4 阶段):

  1. 从理论开始,这里的理论要求不高,懂一些计算机基础知识,具体来说懂得 C 语言的基本语法和了解开发过程,就可以了。
  2. 实际在 Windows 上开发一些控制台的小程序(因为大部分人平时使用的系统是 x86 Windows),而不是停留在理论层面。
  3. 开始接触 Linux 平台了,最基本的,安装一个 Linux 发行版,并尝试在这上面进行一些简单的开发,这时候大部分人的电脑依然是 x86 架构的,要在这上面能用命令行编译、运行自己写的小程序。
  4. 有需求的开发人员会开始接触其他架构(如 MIPS、ARM64、RISC-V 等),开始了解不同架构的区别,以及照着教程交叉编译、移植一些简单的软件。
  5. 在听到 LoongArch 推出后,查看官方文档,利用已有知识、经验,在 LoongArch 上进行开发。

即使是开发系统软件,也未必需要用到汇编,当然懂汇编在一定程度上能帮上不少忙,也能更好地理解指令集直接的差异。

迁移到 LoongArch

那么通常意义上,怎么把一个软件从其他架构移植到 LoongArch 呢? (因为是通常意义,所以通篇废话,逃

先考虑两个极端:

  • 这个软件足够底层,需要大量的相关知识,比如编译器、内核,这类软件基本已经移植完成了,而且有能力能移植这类软件的开发者应该不屑于也不需要看这篇文章……
  • 这个软件是比较上层的,本身就是架构无关的,比如一些 Python 包、简单的 C 程序(“Hello, world!")等,这类软件不需要移植,直接就能正常使用,或者最多需要编译一下就行了。

抛开上面两个极端,大部分软件的移植工作并没想象中的那么难。 从社区的角度出发,我们为一个软件(或者库)添加 LoongArch 支持的流程大体如下:

  1. 发现某个软件不支持 LoongArch,而且没人移植。
  2. 找到这个软件的上游仓库,通常是使用 git 管理的(也有用 svn 的),大概率存放在 Github 上(或者类似的代码托管平台)。
  3. 阅读项目里的开发文档以及许可证,进行本地开发。
  4. 把我们本地开发的内容按社区规则来提交,给上游审查,比如通过 Github PR 的形式(有些可能使用邮件交流)。
  5. 听取社区的意见并修改,这个过程可能持续很久,直到被认可,之后上游会合并我们的工作,以后这个软件就支持 LoongArch 了。

整个过程可能需要英文交流,但即使英文不行,现在翻译引擎这么强大,大家都能看懂的,还会有热心老外帮忙修改。

那么现在的重点就是怎么本地开发了:

  • 如果这个软件有多架构支持,那么就简单多了,直接“抄”其他架构的,然后改成 LoongArch 版本的代码,甚至好多软件加几个 #ifdef 之类的宏,或者修改几个编译参数,就能正常编译、使用。
  • 如果这个软件本身不支持其它架构,或者“抄”其他架构的后还是不能正常使用,那稍微麻烦一点,通常会根据编译、运行时的错误来定位问题,添加或修改代码。

相关链接