Featured image of post 教程推荐 1000行编写一个操作系统 1

教程推荐 1000行编写一个操作系统 1

推荐一个使用 1000 行以内 C 语言编写基于 RISC-V 操作系统内核的教程。

大家好,今天和大家分享一个我之前看过的很好的一个教程,关于计算机系统的。

如果你是计算机相关专业,那么你一定不可避免的学过操作系统这门课,我在考研的时候也囫囵吞枣式的学习过这门课程,不过学得也很浅,背了几个算法,背了几个知识点就过去了,只是大概了解计算机如何分配内存和资源,如何操控磁盘和io;操作系统的课本不会告诉你怎么去真正的写一个操作系统,我相信很多对计算机感兴趣的人并不只想知道理论知识,还想要自己真正的去实现一个操作系统,不需要有太多功能,也不需要能做到什么,只要能写出来就行了。

由nuta所编写的OS in 1000 Lines是一个很棒的教程,教程的链接是1000os.seiya.me,有官方中文,项目的地址为os-in-1000-lines。这个教程讲述了如何使用1000行以内的C语言编写一个基于riscv的操作系统内核,这个教程很精简,门槛不高,不过在大家阅读之前,我还是补充一点内容给对C语言了解的不太多的朋友比较好。

新手须知

很多朋友学C语言的时候都是在Windows系统上,Windows系统上常用的开发工具是Visual Studio C++,有很多人在学得时候甚至是用VC++或者DevC++学习的,虽然他们也能写出很多程序,但是对于这个教程来说不行。在正式学习之前,你可以通过在网上搜集资料,或者问ai,来学习如何使用WSL或者如何安装一个Linux的虚拟机(我推荐fedora workstation,这个系统开箱即用,不需要关心太多);

在准备好环境之后,还有一些基础的知识需要和新手说;

编译器

首先要说的是编译器,编辑器什么的,很多朋友在学习C语言的时候都是在一个编辑界面,按一下编译并运行就弹出一个黑框显示结果,所以他们可能确实不了解这些相关内容,简单来说,你写的代码只是一个文本文件,电脑看不懂这个文本文件,也无法运行他,所以需要一个叫做编译器的工具将代码翻译成电脑能看懂的可执行文件;常见的编译器有gcc,clang,msvc,他们都各有优劣,这个教程将使用clang作为编译器;编辑器就是写代码的软件,你可以任选一个,对于不了解linux的朋友来说,nano是一个大部分系统自带,用起来很简单的编辑器,或者也可以用系统自带的文本编辑器来写。又或者你可以去问ai或者自己搜集如何使用vscode,zed等编辑器;

代码流水线

为什么选择clang

既然编译器有三个,为什么选择clang,因为clang好用;这里来说一下编译器是如何把代码翻译成可执行文件的:当你的代码文件喂给clang时,首先clang会进行处理,把一些宏定义展开,执行一些#开头的预处理命令(了解就行),再生成完整的代码之后,会把代码翻译成中间语言,到这一步代码依旧不能直接运行;我们额外的再来看一个知识:计算机怎么跑程序?计算机的CPU只会按照它预设的指令集来对一个固定长度的数字进行执行,也就是给CPU一个数字,CPU就会按照预设的方式把这个数字拆成指令,而这个指令集就决定了如何拆这个数字;比如在指令集A中,当收到0001时就在显示屏输出hello,而指令集B里,收到0001时输出world,同样的代码在A指令集的CPU和B指令集的CPU运行结果不一样。

指令集差异

不一样指令集的CPU不能执行同一个程序,所以编译器要根据当前的CPU指令集来输出不同的可执行文件,这也是为什么编译器要把代码翻译成中间语言,如果直接翻译成指令,换一个指令集的CPU就得重新写一个编译器了;翻译成中间语言后,再根据指令集翻译成对应的汇编语言,汇编语言是CPU执行的那一串数据的给人看的版本,把抽象的指令改成了助记词;汇编语言通过简单的变换就成为了真正的指令数据,理论上CPU直接执行这一堆数据就能执行程序了,然而还不能,因为操作系统还不能直接运行这一堆数据,所以还要把这一堆数据按照操作系统想要的方式打包,这个过程称为链接,最后操作系统读取这个格式确认是可执行文件之后再执行;

翻译

为什么讲这么多呢,因为等会不可避免的需要知道这些,所以提前打一个预防针;clang的一个很大的优势就是带了一个可以转换成很多个架构的后端llvm和很多工具,不需要你去额外的安装什么;如前文所说,这个操作系统是基于riscv的,riscv是一个指令集,它的指令数量很少,适合学习,而我们平常使用的是x86指令集,用clang可以很轻松的把代码在x86的设备上编译成riscv指令;

需要安装什么?

在教程中有写,需要安装clang llvm lld qemu-system-riscv32这几个软件,在linux上,这不是什么难题,基本上一个指令就能覆盖了。这里介绍一下qemu,这是一个虚拟机软件,system指系统模式,只需要知道它可以直接模拟硬件设备就行,riscv32则是指明了其模拟的指令集;lld是clang和llvm用来链接的工具;除了这些工具,还要一个 很重要的东西,就是opensbi的固件代码,在原文里有具体下载地址,这个固件的作用相当于BIOS,用来启动硬件和系统的;

clang怎么用?

首先你需要打开一个控制台,然后输入 clang [选项] <文件> 就行了,比如 clang -o main.out main.c,意思就是使用clang这个软件,提供了一个-o main.out的选项,意思是输出到叫main.out的文件,main.c就是提供给clang 的代码文件,当然你可以提供很多个;

现在打开一个终端,输入:

1
clang -print-targets | grep riscv32

如果显示

1
riscv32     - 32-bit RISC-V

就说明clang可以编译为riscv32指令集的指令

虚拟机启动

现在把opensbi的文件放在一个文件夹里,打开这个文件夹,在这个文件夹打开终端,执行:

1
qemu-system-riscv32 -machine virt -bios default -nographic -serial mon:stdio --no-reboot

就会启动虚拟机,具体这些参数的作用原文有写 启动后会显示opensbi的标志,说明成功了。

opensbi

最后一块学前拼图

现在还剩下一个拼图,链接;前文说了链接是为了把代码打包成系统能用的样子,然而这次我们要写的就是一个系统,所以我们不能使用默认的链接方式。要决定链接方式,就需要通过编写链接脚本,为什么换个打包方式就能写操作系统呢,因为当我们加载了opensbi和我们写的系统时,qemu会把他们加载到不同的内存地址,opensbi由于是bios,会放在启动地址,执行完一些指令后又会在另一个地址启动系统;我们在链接脚本中指定操作系统的入口地址,qemu会把这个入口放在对应的内存地址,只要这个内存地址是opensbi会启动的,那么我们的系统就会开始运行了;

现在开始探索吧

别忘了本文只是一个推荐,具体的内容还要自己去看;这是我根据教程写的项目,有一些更改,不过大体还是直接抄的教程的;

comments powered by Disqus