为树莓派4编写裸机操作系统--part1
本文最后更新于:2022年3月14日 晚上
本文档所有内容均翻译自 https://github.com/isometimes/rpi4-osdev,作为自己学习树莓派及操作系统的记录。由于本人英文水平有限,如果出现翻译错误请指出,本人会及时改正。如果出现无法理解的内容,请参考原文学习。
为树莓派 4 编写裸机操作系统 1 - 引导
我们如何编码
我们通过编写代码告诉树莓派 4 如何工作。你可能知道代码最终将以一系列二进制的 0 和 1 进行表示。但是,你会很高兴的知道,我们不需要编写二进制代码。否则,我们会很容易忘记我们的目的。事实上,将人类可读的编程语言转化为0和1是编译器的工作之一。
在开始之前,我们需要了解两种编程语言:汇编语言和 C 语言。虽然大多数现代程序员认识 C 语言,但汇编语言却很少被人使用。它是一种低级语言,与 CPU “思考”的方式最相似,因此它赋予了我们更多控制权。而 C 语言将我们带入一个更高层次,人类可读的世界。虽然我们对编译器失去了一点控制,但出于我们的目的,我认为我们可以信任它。
我们需要从汇编语言开始,但在我们使用 C 语言之前,我们并不会编写太多汇编代码。
关于本教程的说明
本教程的目的不是教你如何使用汇编语言或 C 语言编写代码。关于这些主题有很多更好的资源,我也不是这方面的专家或权威。因此我将在此过程中假设你有一些基础知识。如果需要,请继续阅读我介绍的主题。
引导
RPi4 将运行的第一行代码需要使用汇编语言编写。它进行一些检查和设置并将启动到我们的第一个 C 程序-内核。
- Arm Cortex-A72 有四个核心。我们只希望我们的代码运行在主核心上,因此,我们检查处理器 ID并在主核心上运行我们的代码并在其他副核心上执行死循环挂起。
- 我们需要告诉我们的操作系统如何访问栈空间。我认为栈是当前执行代码(如 scratchpad)使用的临时存储空间。我们需要为它留出内存并保存指向它的指针。
- 我们还需要初始化 BSS 段。这是内存中存储未初始化变量的区域。在这里将所有内容初始化为零要比在我们的内核中显式初始化更有效。
- 最终,我们可以跳转到 C 语言的 main() 函数中。
阅读并理解下面的代码并将其保存为 boot.S。我建议使用 Arm Programmer’s Guide 作为参考。
1 |
|
现在开始 C 语言代码
你可能会注意到 main() 函数尚未定义。我们可以使用C语言编写 main() 函数(另存为 kernel.c),并暂时将它实现为一个简单的死循环。
1 |
|
将代码链接在一起
我们使用两种不同的语言编写代码。因此需要以某种方式将它们组合在一起,来确保创建的系统镜像能以我们期望的方式执行。我们使用链接脚本,并在链接脚本中定义与 BBS 段相关的标签(也许你已经想知道它们在哪里定义了?)。建议你将以下内容保存为link.ld。
1 |
|
编写链接脚本指的我们研究。但是对于我们的目标,你只需要知道,引用汇编代码中的 .text.boot 符号并使用 KEEP() 确保 .text 段在汇编代码的开始处。这意味着操作系统程序的第一条指令从 0x80000 开始,这正是 RPi4 启动时开始查找执行指令的位置。我们的代码将从这里开始运行。
现在,你已经准备好编译并启动你的操作系统了!