前言
数年前,出于对于操作系统内核的好奇和兴趣,看了一些自制内核资料和教程,断断续续地也写了一个简单的的玩具内核。
在学习的过程中,往往第一步遇到的问题就是内核的加载和系统的引导,发现不少教程都使用grub等现成的工具直接完成这一步骤,这样能快速的完成读取硬盘、加载内核文件、探测内存等这些dirty work,让初学者快速进入到内核开发的学习中,但是却使得这些过程对我们始终蒙上了一层神秘的面纱。
想必做出自己写系统内核这个决定的人都对于系统底层的运行原理有着浓厚兴趣,对于bootlader的原理,一样也会想进行了解,因此尝试不使用grub等工具,从零开始开发了一个简易的bootloader,学习相关原理的同时,也整理下开发流程中遇到的问题,做一个记录。
项目地址:https://github.com/basic60/ARCUS ,由于项目中的内核部分代码使用了hurlex内核的代码和linux内核的代码,因此项目代码将同样以GPL-2.0协议发布。
开发环境配置
Linux下构建交叉编译器
在正式开始开发之前,首先要做的就是先配置好开发环境,开发本项目内核所需要的工具只有编译器和用于运行内核的虚拟机而已。本内核采用汇编和C、C++编写,因此我们需要一个汇编器和C++的交叉编译器。
为什么我们需要一个交叉编译器?交叉编译器是在某个系统平台下可以产生另一个系统平台的可执行文件的编译器。我们的开发的内核当然是“另外”一个平台,因此需要交叉编译器来编译我们的代码。构建的内容包含了GCC和Binutils,GCC中有我们要使用的编译器,Binutils中有ar,ld,objdump,readelf等工具。
Linux下安装如下工具:
- GCC (existing release you wish to replace), or another system C compiler
- G++ (if building a version of GCC >= 4.8.0), or another system C++ compiler
- Make
- Bison
- Flex
- GMP
- MPFR
- MPC
- Texinfo
- GCC和Binutils的源代码
下载GCC和Binutils的源代码。可以从GCC的官方镜像和Binutils的官方镜像下载。不过国内访问比较慢,推荐从中科大镜像下载。准备完成后执行以下命令:
export PREFIX="$HOME/opt/cross"
export TARGET=x86_64-elf
export PATH="$PREFIX/bin:$PATH"
其中TARGET描述了交叉编译器的目标三元组(Target Triplet),target triple是一个交叉编译器的术语,用于描述交叉编译的目标代码所运行的平台。格式为 <arch><sub>-<vendor>-<sys>-<abi>:
- arch = x86_64, i386, arm, thumb, mips, etc.
- sub = for ex. on ARM: v5, v6m, v7a, v7m, etc.
- vendor = pc, apple, nvidia, ibm, etc.
- sys = none, linux, win32, darwin, cuda, etc.
- abi = eabi, gnu, android, macho, elf, etc.
本项目使用的Traget Triple为“x86_64-elf”,vender和sys都进行了忽略,构建系统会自动将缺失的参数推到为unkown或none,我们的目标是开发一个64位的内核,x86_64指明平台和elf指明abi就足够了。
构建Binutils
在home目录下建立一个src文件夹(当然也可以在其他的目录下),然后把binutils的代码解压到src目录中,执行以下命令:
cd $HOME/src
mkdir build-binutils
cd build-binutils
../binutils-x.y.z/configure --target=$TARGET --prefix="$PREFIX" --with-sysroot --disable-nls --disable-werror
make
make install
构建GCC
把GCC的代码同样解压到src目录中,执行以下命令:
cd $HOME/src
# The $PREFIX/bin dir _must_ be in the PATH. We did that above.
which -- $TARGET-as || echo $TARGET-as is not in the PATH
mkdir build-gcc
cd build-gcc
../gcc-x.y.z/configure --target=$TARGET --prefix="$PREFIX" --disable-nls --enable-languages=c,c++ --without-headers
make all-gcc
make all-target-libgcc
make install-gcc
make install-target-libgcc
macos下安装交叉编译器
macos下可以选择和linux下一样自己下载源码编译,或者直接brew安装即可,非常方便
brew install x86_64-elf-gcc
brew install x86_64-elf-binutils
使用交叉编译器
直接使用交叉编译器的绝对路径。
$HOME/opt/cross/bin/$TARGET-gcc --version
当然你也可以自己把交叉编译器的路径加到环境变量里,这里不做赘述。
安装虚拟机
这里选择了qemu,下载安装最新版即可。