予焦啦!目录、快速上手与前言

目录

快速上手

予焦啦!欢迎各位读者点进这个系列文!

第一天,我们不罗唆直接去拉取 Hoddarla 专案吧!

笔者建议读者跟随快速上手章节的部份就好,应该可以直接跑出一个具备计时器中断(timer interrupt)功能的小型展示。这个展示包含的内容大约涵盖到第 20 天的内容,後续还在赶工中。现在的这个名为 debut 的分支,将目前为止的 Hoddarla 开发进度压成了一整个 patch。之後随着每一天的推进,笔者会依序揭露试误与开发的过程。

git clone [email protected]:NonerKao/Hoddarla.git && cd Hoddarla
make env
. .hdlarc
make

理论上,应该可以看到

...
i = 16
i = 15
i = 14
i = 13
i = 12
i = 11
i = 10
i = 9
i = 8
i = 7
i = 6
i = 5
i = 4
i = 3
i = 2
i = 1
i = 16
i = 15
i = 14
i = 13
i = 12
i = 11

的一连串倒数。是的,这就是罗!

建置开发环境的步骤展开

以下是 make env 较细部的拆解,但实务上应该是没有必要的,只是参照用。

模拟器使用 QEMU

考量到 RISC-V 硬体还不是很好取得,开发者总还是必须要有一个可运行系统的平台才行,所以通常就使用功能最齐全的模拟器 QEMU。

笔者使用 QEMU 6.1.0 的版本。以下将几个套件取消掉并非绝对,只是现阶段还不需要那些功能罢了。--target-list 则是必要的,因为 QEMU 能够支援多种平台与架构,这里指定的 riscv64-softmmu 通常用以运行 Linux。prefix 虽非必要但仍然强烈建议,因为如此一来,就可以很方便的管理安装目录了。

./configure \
    --target-list=riscv64-softmmu \
    --disable-sdl \
    --disable-vnc \
    --disable-gtk \
    --prefix=$HOME/qemu
    # 可自行调整想安装的目录位址,建议将 $HOME/qemu/bin 也加入 PATH 环境变数

如果成功的话,会显示一整排的组态,以及它们是否被启动或取消。这之後就可以

make && make install

GNU C 工具链

目前 Hoddarla 还是需要仰赖 GNU 的 C 工具链。自己编的话需要花一点时间,如果可以使用发行版就有的软件包,也是可以考虑的选项。

自行建置

最简单的方法就是先拉取一份 riscv-gnu-toolchain 到自己的开发环境,然後开始建置

git clone https://github.com/riscv/riscv-gnu-toolchain
cd riscv-gnu-toolchain
git submodule update --init riscv-gcc
git submodule update --init riscv-newlib
git submodule update --init riscv-binutils
git submodule update --init riscv-gdb
mkdir build && cd build && ../configure --prefix=$HOME/toolchain
make

结束之後就会产生预设 64-bit 的 newlib 工具链。

预先建置/发行版打包版本

笔者没有使用过这些版本。若要使用这类型的工具链於 Hoddarla 实验或开发的话可能会因此需要一些调整。

  • Bootlin:这是一个提供开源服务的公司,点选之後在 Select arch 选择 riscv64,glibc 和 musl 应该都可以使用。
  • Arch Linux 的 community/riscv64-elf-binutilscommunity/riscv64-elf-gdb:可以直接使用 pacman -S 安装

前言

笔者在 2016年底首次参加ITHOME的铁人赛。

该次系列文是非常浅碟的学习笔记,内容也没有什麽特殊之处,是关於使用者空间与Linux作业系统核心之间的系统呼叫介面。那次的经验让我明显感受到,铁人赛本质上是一场犹如马拉松的盛会;参赛者们位在其中,各自由意志力驱使自我成长,同时也有机会学习他人或供他人学习,整个活动空间於是成为多面向且多维度的集体学习场域。

撰写系列文是很有趣,介绍性质或是学习性质的文章也可以帮助初学者,但是要更加提升的话,必定要往更深处走去吧。

於是在後来的两年,2018第 11 届 2020,笔者决定锁定更具体的范围、订出明确的目标。前者是以 binutils 这样伟大的专案为目标去试图实作一部分子集合,後者则是追踪 Golang 内建的各种机制。以结果来说,两篇系列文最後还是流於通泛了,但它们确实标注了笔者过去几年以来一直都很感兴趣的的技术主轴:RISC-V 以及 Golang 。

开发之经纬

这一次,笔者决定开始一个以 Golang 与 RISC-V 两个主题为双轴线的作业系统专案,并将之命名为 Hoddarla。当然,要是说我打算在这 30 天内一天累积一点点的速度,完成一个作业系统,那未免也太瞧不起数十年来累积的作业系统原理与技术了。

事实上,在第十一届(上上届)铁人赛结束之後,笔者就已经着手进行 Hoddarla 专案:使用 Golang 打造一个 RISC-V 的作业系统。到今年(写作的此时,是 2021)初期累积了非常微小的一点点成果,远远不及当初的恢宏梦想,但还是以这次铁人赛为契机纪录一下;题目也相对应的修改成符合事实的描述:Hoddarla 专案起步:使用 Golang 撰写 RISC-V 作业系统的初步探索

以下数个小节,就解析这个题目的若干名词对笔者的意义之所在。希望在今天这一篇开宗明义的文章当中能够指引各位读者,通往後续几篇技术文章的道路或许会更有趣一些。

到底为什麽是 RISC-V 与 Golang?

这两个大项目纯粹是笔者的兴趣,也因此想要做的题目形式上会成为两者的交集点,事实上两者没有什麽关联。RISC-V 是众所瞩目的第五代简化指令集架构,官方单位(RISC-V 国际基金会)以电脑系统的巴别塔为己任,以模组化的弹性为最大的卖点,技术社群与规格社群也相当蓬勃地发展当中。Golang 则是一个高阶的静态编译程序语言,语法简洁却功能强大,由颇负盛名的Ken Thompson(Unix之父、C语言之父)、Rob Pike(UTF-8编码设计者)以及Robert Griesemer开发。

若真的要定位出两者的相同点,也不是没有:

  • 从研究走向实用:RISC-V 起源自柏克莱大学的研究室,而 Golang 原先是为了解决软件工程开发的基本问题的 Google 研究专案。
  • 由领域大师发起:Unix/C 语言之父与计算机组织经典教科书算盘本的教授 David Patterson 是专案的发起人。
  • 极简主义:两者同样倡导「少即是多」的极简哲学。Golang 三人小组在第一次召开会议之时,最先确立的共识就仅有「C++ 的复杂令人厌恶」的一点;而 RISC-V 则在白皮书中大量比较 x86 的复杂本质连带影响软件工具设计,以及 ARM,虽号称是 RISC 却仍然包含许多根本用不到的复杂指令。

或许还可以再补上一则笔者的个人主观意见,那就是两者都还没有得到应有的地位。试想一个内建扩充性的计算机指令集架构(ISA),如果能够让全世界共享其中的基础部分,能够相消弭多少的额外负担?又,一个语法极简却提供垃圾回收、轻量程序与内建并行机制的语言,可以为多少软件工程师节省认知负荷?然而世界并非如此运作,这两者能够在历史之中挺立多久,都尚属未知。

至於两者真正的交集,也就是 Golang 内的 RISC-V 架构支援,目前只有 Linux 作业系统堪称较完整,但其实也还非常初阶。仅有 64-bit 的支援不说,能够大幅节省编译产物空间的压缩指令集(C extension)也还没有支援。

若是各位读者对於 Golang 与 RISC-V 之间的真正的交集有兴趣,笔者曾提交两个功能实作,都已经进入到 Golang 的历史之中。相关主题会在最後倒数几日时的附录主题与各位分享。

无论如何,由於我完全认同这两者背後的哲学,但又没有非常充裕的时间能够彻底研究这两者,所以才会继前两组铁人系列文之後,再於今年度的铁人赛延续这个双轴线。

工具链比较:C vs. Golang

我们可以从不同角度检视一个程序语言:语法、语意如何处理、执行时环境(runtime)与行为,都有各自的学问与钻研的趣味。

在这里我特别想比较的是工具链(toolchain)的部份。C 语言工具链的编译牵涉到多个软件元件、多个专案的偕同工作才有办法达成。若要简单的描述 GNU C 工具链的编译流程的话,那麽得先将链结器、组译器之类的工具编译出来,再以这些工具先编译出一个功能有限的 C 编译器;然後再用这个编译器去编译 C 函式库,这时候才能让 gcc 专案使用到 C 函式库的功能并编译成一个整体。Golang 的话,若非特殊情况,相依性管理完全不是问题,因为它自己为自己实作了编译器,也就是所谓的自主(Self-Hosting)。

工具链本身编好之後,若要执行测试来检验它是否功能正常,C 语言需要外部的测试专案;但是,go 语言已将单元测试当作是语言的基本功能,也能够在编译好工具链之後自动执行所有标准函式库的测试。

执行时间则是另外一个两者相差悬殊的项目,我在同一台电脑上面实测的结果,C 语言工具链的下载与编译时间都大概是 Golang 的 9 倍左右。

从使用者的角度来看的话,我觉得最大的一个差异在於交叉编译(cross-compilation)的支援。C 语言部分,以 GNU 工具链为例的话,交叉编译往往仰赖建置工具 autotool 系列所提供的功能;诚然,相关资讯在网路上都非常容易取得,也容易理解。但有些 C 语言为主的专案,它预设使用的建置系统并无 GNU 建置工具整合,那麽要交叉编译就有可能要费一番手脚;又,就算有整合 GNU 建置工具,若是要支援新平台,专案本身和 GNU 建置工具里面的部分设定档可能都需要更新,这需要不特定且无法轻易估算的额外工夫。

各位读者知道什麽叫做 Cannadian Build 吗?这是在描述一种很有趣的交叉编译需求。你最强力的运算机器是架构 A,但你预期会用到交叉编译工具链的机器是架构 B,而这只交叉编译工具所能够处理与生成的产物是属於架构 C。我实测在 x86_64 上为 ARM64 编译 RISC-V 需要的工具链,结果是寸步难行:最一开始,GNU 工具会提示你,这个编译工作会需要 x86_64 到 ARM64 的交叉工具链,这就算了;就算你备有了,他接下来还会跟你要 ARM64 上面所需要的各种过程中的相依函式库。

反观 Golang,交叉编译功能是内建的。Golang 专案需要的建置指令只是 go build,所以如果想要为 ARM 64 位元处理器上的 FreeBSD 系统建置这个专案,只需要多给两个环境变数

GOOS=freebsd GOARCH=arm64 go build

旋即搞定。笔者甚至没有办法花更多篇幅来说明它,这个抽象层切得妙到颠毫,所有无须深入理解的细节全部都被隐藏。

由此,我们不难发现,Golang 作为一个语言,的确解决了一些困扰着前人的问题,而它解决那些问题的解法也确实的成为这个语言本身提供的工具。

本节举这个工具链交叉编译的例子,对於 Hoddarla 专案本身不是太具意义,因为我们已经限定 RISC-V 64-bit 了。也许围绕在 Golang 上面更合适介绍的主题是 go mod 导入的内建相依性管理,但就留待日後有机会再行研究。

作业系统

Jserv 在八卦版的一篇文 曾引述王佑中博士的一句话:「写一个作业系统是多麽美好的事,在有限的生命中千万不要遗漏了它。」无独有偶,这次铁人赛也由另外一位参赛铁人 EN 也引用了这句话在他打算要打造的 RISC-V 作业系统的系列文介绍当中。

若以人类的文明活动作为类比,作业系统负责的项目应该可以类比於政府体系、官僚制度或者是任何非现代政府形式的调解手段。原因是,作业系统负责管控资源,能够监控它们的状态且有最终决定权,然後接收使用者的需求并将这些资源分配给他们。这麽说来,将写一个作业系统视作美好之事,大概略可以类比於那些想要设计社会制度的思想家,或是有才干能够在有限规则中将政府的运作调理得宜的政治家吧。

然而在电脑系统中,写一个专案就意味着作者有着至高权限,比之皇帝或是史上任何的独裁者都还具有更多的发挥空间,简直就是神一般的存在。这麽一想,的确是令人向往的事情。

但如果只是不论结果的撰写而已,感觉又略嫌缺乏。虽然人们常说意义在过程不在结果,但通常那要嘛是安慰人的话语,要嘛是结果不重要或是难以估量。笔者谦卑的希望 Hoddarla 能够至少在过程的意义之外还能够具备一些其他的意义,但也如同前述的那样,今年能够完成的部份实在是顶多只有初期的一部分,就算要高谈阔论些精神层面的事情,也不是现在吧。

开发思路

Hoddarla 背後的想法很单纯。笔者最一开始烦恼了很久,到底该将这个专案命名为什麽才能够彰显那种无须多言的简单感觉,幸好传统语言的智慧自然在对的时刻浮现脑海。

Golang 的执行期环境(runtime)提供了非常丰富的功能,包含排程、Goroutine(Golang 的 coroutine)、还有垃圾回收机制。单这样描述,就已经很像是作业系统核心的部份内容了,不是吗?当然,一个现代的作业系统核心包含了很多很多很多其他的功能,但从无到有不就是这麽回事吗?那我们何不试试用 Golang 来写作业系统呢?

需要特别注意的是,这里面有个应当厘清的误区。上一段的联想实际上代表着,也许 Golang 的执行期环境能够代替某些作业系统核心的功能,但这和用 Golang 写作业系统的意义不尽相同,值得细分。

以 C 语言为例,用 C 语言写 Linux 没有什麽难以想像的,毕竟是已届 30 年的实践。然而,Linux 并不使用 C 语言的执行期环境。Linux 需要 bootloader 帮它处理载入时的核心参数,而不是像一般 C 语言专案那样,由 C 语言的执行期处理参数,再以 int main(int argc, char *argv[]) 的方便形式传递。所以从 C 的例子就能够明确看出两者的差异。

那麽,Hoddarla 专案所冀求的又是哪一种呢?笔者认为在这个阶段(这次铁人赛所包含的范围内),是只能涵盖前者的一部分。至於用 Golang 写作业系统,在附录的部份会有一些文献回顾,介绍前人的尝试,并较深入一点地研究目前最完整的一个使用 Golang 撰写的作业系统核心;关键字是 biscuit

因此,现阶段 Hoddarla 的绝大部分程序码都依附在 Golang 专案之中;甚至我们可以说,Hoddarla 目前还只是 Golang 的 RISC-V 执行期的一个小 patchset 而已。笔者在里面发展现有 RISC-V 工具链不足之处,增补执行期所需,然後在执行期环境的启动过程中一个一个加入作业系统应有的功能。

作为 patchset,笔者的例行公事就是每隔一段时间就要将既有的部份 rebase 到上游的 Golang 上面。Hoddarla 启动至今已经这样操作十数次,大部份是执行期环境的 API 改动,偶尔涉及到物件处理的部份而需要重新编译工具链。繁琐的细节在附录中也将补述。

各路英雄,切磋於铁人赛

晶心壮士团体第一次上台领奖时,记得主办单位提供了队长发表感言的时段。当时笔者秉持着感动与感谢,将这场盛会与马拉松做联想,以强调其中的耐力成份。现在铁人赛规模更显壮大了,除了自我的耐力考验之外,如果还独学而无友,显然白白糟蹋了一场祭典。所以笔者这里也列出相关主题,以示重点关注:

  • 微自干的作业系统轻旅行:虽然说打造作业系统的目标相近,且目标架构也都一样是 RISC-V,但这一系列的实践手段看起来应该会与 Hoddarla 有很大的区隔。虽然只是推测,但我预期想要学习作业系统核心原理的读者能够从这个系列获得较多,笔者的 Hoddarla 系列文已经趋於邪道了。
  • 从C到JS的同步非同步探索:这个系列探讨非同步相关的主题,目前为止资讯相当深厚,且又旁徵博引。
  • [机派X] 无人机与树莓派的相遇 Linux不只是过客:以 Linux 为关键字搜索,这篇系列看起来会更深入嵌入式系统的运用。
  • arm 还是 x86? 我该怎麽选呢:对於 RISC-V 来讲,ARM 和 x86 这两位老大哥都是迟早要赶过的目标。作者在介绍中提及会有效能的比较,让人额外感兴趣。

当然最後也一定要介绍一下敝组晶心壮士中的另外两位铁人。他们都是是笔者在晶心科技的同事。他们带来的两个系列将分别是

  • 阅读 Linux Kernel 文件:将 Linux 核心源码当中的文件打捞出来阅读,并分享从中获得的知识。这系列应该会相当适合在 Linux 核心开发稍有基础的读者。
  • Port Alpine Linux to open source RISC-V platform:将 Alpine 这个 Linux 发行版移植到开源的 RISC-V 32-bit 硬体平台上面。这系列显然更能够迎合中级甚至进阶的嵌入式系统玩家。读者将能够从使用者以外的视角一探发行版内部的奥秘,并了解移植的实务如何进行。

小结

予焦啦!感谢各位读者愿意在这里见证 Hoddarla 专案的起步。我们明天再会!


<<:  2021-Day5. 铁人赛团体组,Line 群组每日催稿讯息实作教学(一):Notify

>>:  好的会前准备,是效率的第一步

ISO 27001 资讯安全管理系统 【解析】(一)

本篇解析断断续续写了将近一年的时间,一直没有下定决心到底要写成甚麽样子,在一些外在因素影响下,终於努...

Day20 CSS Banner与搜寻框

上一篇我们做完了导览列,今天我们就要建立导览列下面会有的一张大图片,以及搜寻框,一步一步完成我们的网...

【在 iOS 开发路上的大小事-Day06】透过 Delegate 来传值

前情提要 一般我们在做传值动作的时候,会有好几种方式可以做,像是用 Segue、Closure、De...

企划实现(22)

使用firebase简易资料库 在使用前要将专案连结至firebase 第一步:在firebase创...

Day 24 - 资料结构入门理解

前言 今天要来讨论一些更进阶的程序写法,比较偏向效能方面的优化,怎麽写可以让效能变好、扩充容易,而不...