Hello FreeBSD! 捣鼓 FreeBSD SYSINIT
Table of contents
FreeBSD sysinit 简单介绍
FreeBSD 中 machine-independent initialization 是从 mi_startup() 函数开始的。mi_startup 函数会将 initset 进行排序,然后顺序执行初始化。每个 sysinit object 都是通过 SYSINIT 宏来将自己加入到 initset 中,SYSINIT 使用了一种叫 linker set 的方法,简单来说是在链接阶段将分散在多处的数据合并成一个连续的数据块,后续代码可以直接遍历处理。
SYSINIT 有四个参数:
#define SYSINIT(uniquifier, subsystem, order, func, ident) uniquifier 是唯一 ID,subsystem 子系统 ID,定义在 sysinit_sub_id 中,是个 enum 值,指定子系统之间的顺序。order 同样是个 enum,用于子系统内部排序。mi_startup 会根据这两个 enum 值来顺序执行初始化。func 为要执行的初始函数,ident 会作为参数传递给 func。
///参见: Kernel Initialization SYSINIT Operation (有简单介绍 linker set)
添加一个简单的系统初始对象
根据上面对 sysinit 的简单介绍,可以发现要添加一个 sysinit object 十分简单,首先定义初始化函数,然后用 SYSINIT 注册就行了:
/* src/sys/kern/init_main.c */
static void
hello_bsd(const void *udata __unused)
{
printf("%s\n", "\033[46m\033[031mHello FreeBSD!\033[0m\033[0m");
}
SYSINIT(hellobsd, SI_SUB_COPYRIGHT, SI_ORDER_THIRD + 3, hello_bsd, NULL);指定 hello_bsd 函数子系统为 SI_SUB_COPYRIGHT,顺序为 SI_ORDER_THIRD + 3,SI_SUB_COPYRIGHT 为打印 COPYRIGHT 信息的 sysinit object,此时console 已经可用,所以我们在这里可以使用 printf 函数进行打印了。SI_ORDER_THIRD + 3 这里的 3 只是在源文件中找到的最低顺序 SI_ORDER_THIRD + 2 上再降低了 1,即会在 SI_SUB_COPYRIGHT 子系统初始化的最后执行。
编译安装 kernel
有关编译 kernel 的流程 FreeBSD handbook 中有详细介绍,首先准备 config 文件,这里可以客制化一些模块,我们按照文档中使用默认的 GENERIC 模版:
cd /usr/src/sys/amd64/conf
cp GENERIC EXPBSD可以修改一下 EXPBSD 文件中的 ident,编译出来的新内核标识(例如执行 uname -a 命令时)会变成这里指定的值。
因为我们这里并没有修改任何模块,可以在 /etc/make.conf 中指定一下,重新编译所有模块需要很长的时间。
MODULES_OVERRIDE =与 MODULES_OVERRIDE 相反的是 WITHOUT_MODULES,从名字可以看出来一个是仅编译指定的模块,一个是略过指定的模块。
编译,根据自己的处理器个数指定 -j 参数来加快编译:
make buildkernel KERNCONF=EXPBSD -j4在已经完整编译过一次 kernel 后可以使用 -DKERNFAST 进一步加快编译过程。
编译完成后安装:
make installkernel KERNCONF=EXPBSD成功后 reboot,默认会使用我们刚编译的新内核,正常的话,可以看到我们新加的打印出现在开机过程中(但是并没有颜色显示出来….):

如果出问题无法启动可以参考文档切换为旧内核开启。
///