又一篇旧作,差不多也是2001年底写的。
FreeBSD 启动代码学习笔记 1
1. FreeBSD 启动流程 3
2. 分析 3
2.1. MBR 3
2.1.1. mbr/mbr.s 3
2.1.2. boot0/boot0.s 4
2.2. boot2/boot1.s 4
2.3. btx/btx/btx.s 5
2.4. boot2/boot2.c 5
3. 小结 5
感谢所有为 Linux、FreeBSD、GNU 等 Freeware 事业做出贡献的人们。
这 两天学习了一下 FreeBSD 的启动代码 (boot code),又看了一下《Linux操作系统内核分 析》第五章“Linux 启动系统”。这儿简单的写一下我自己的认识,诸多偏颇之处,敬请指正,关于 Linux 启动的 部分,参照了《Linux操作系统内核分析》一书。
本文介绍以 FreeBSD 4.2 的 boot code,因为lxr.linux.no (一个出色的 source cross reference 项目)上的 FreeBSD source 是这个版本。如果是其他版本,会有些不同,我 在家里读的就是 4.3 的,本文中有些地方也会提到这一版本中的一些内容。如果能够在线阅读,可以直接访问http://lxr.linux.no/freebsd/source/。
Lxr 上FreeBSD 4.2 for i386的启动代码都在 src/ boot/i386/ 中,在我家里的机器上 4.3 的文件目录是 src/sys/boot/i386/。
1. FreeBSD 启动流程
最典型的硬盘启动流程如下:
1) MBR (其中任意一个或者都不用,我通常都不用)
a. mbr/mbr.s 最简单的 mbr
b. boot0/boot0.s 一个简单的 Boot Manager
2) boot2/boot1.s 真正的FreeBSD 启动扇区
3) btx/btx/btx.s 初始化系统,进入保护模式
4) boot2/boot2.c 输入 kernel 文件名并调用 kernel
如 果是软盘启动,应该会省掉第一 1 两步。在src/ boot/i386/ 下还有 cdldr、 kgzldr、liloldr 几个目录提供其它方式的启动;在 4.3 中,则是 /usr/src/sys/i386/boot 下有 biosboot、cdbootboot、netboot、dosboot、 kzipboot和rawboot几个目录,提供从不同的介质启动。本文主要讨论从硬盘和软盘启动,重点在 2、3、4 几步, mbr 和 Boot Manager 都是常见的做法,没什么特别的。
2. 分析
2.1. MBR
2.1.1. mbr/mbr.s
MBR,不会有什么特别的,无非是找 Active 的分区,读入并 Jump 过去。
2.1.2. boot0/boot0.s
一个 Load Manager ,和 LILO 类似。显示一个主分区的菜单,读取用户的选择,装入扇区并 Jump 过去。整个程序很清晰,不过其中有一段非常精彩:
290 #
291 # Display routines
292 #
293
294 putkey: movb $'F',%al # Display
295 callw putchr # 'F'
296 movb $'1',%al # Prepare
297 addb %dl,%al # digit
298 jmp putstr.1 # Display the rest
299
300 #
301 # Display the option and note that it is a valid option.
302 # That last point is a bit tricky..
303 #
304 putx: btsw %dx,_MNUOPT(%bp) # Enable menu option
305 movw $item,%si # Display
306 callw putkey # key
307 movw %di,%si # Display the rest
308
309 puts: callw putstr # Display string
310
311 putn: movw $crlf,%si # To next line
312
313 putstr: lodsb # Get byte
314 testb $0x80,%al # End of string?
315 jnz putstr.2 # Yes
316 putstr.1: callw putchr # Display char
317 jmp putstr # Continue
318 putstr.2: andb $~0x80,%al # Clear MSB
319
320 putchr: pushw %bx # Save
321 movw $0x7,%bx # Page:attribute
322 movb $0xe,%ah # BIOS: Display
323 int $0x10 # character
324 popw %bx # Restore
325 retw # To caller
算上注释,35 行代码,实现六种功能(putstr.1 和 putstr.2 不是)。
2.2. boot2/boot1.s
读 入 Boot2 (disklabel+BTX+boot2.bin) 并 JUMP 至 BTX 。如果你有 4.3 的 source ,读到这儿,我建议你去看一下 /usr/src/sys/i386/boot/biosboot/README.386BSD ,这篇文档对 boot1、BTX 和 boot2 的动作有不少介绍,说明了几处重点。
2.3. btx/btx/btx.s
当当当当!重头戏上演啦!(当然,和 kernel 比这还不算重头。不过 boot 中这段是最重要的。)
老 实说,到现在我也不知道 BTX 是什么的缩写,Google 搜不到,www.FreeBSD.org 也没 有。哪位同仁若是知道,望不吝赐教。其实 btx 部分不仅是 btx.s 一个文件, btx/lib 下的 btxcsu.s、btxsys.s 和btxv86.s 也包含几个简单的函数。还有 一个 btx/btxldr 目录,不过 btx/btxldr/btxldr.s 说这只是 btx.s 的原型,我就没有多看了。
btx.s 主要做了以下工作:创建和设置保护模式环境,如 IDT、 GDT、TTS,如果设置了 PAGING 宏,还会创建一个页表(page table。我不知道这个页表是否有用,btx 在进入 boot2.c 前会把 PG 设成 0,我觉得 kernel 里应该会另外创建一个页 表,不过我还没有读到 kernel 呢);btx 也定义了0x00 - 0x10 (异常)、0x20-0x2f(硬件中断)、0x30(系统调用)和0x31-0x32(V86调用)的中断,这些中断应该会被kernel 换掉,不过在载入 kenerl 前,许多工作都要靠这些中断来做;最后,btx.s 切换到用户模式,开始执行 boot2/boot2.c。
0x31 中断(V86调用)很重要,它从用户模式切换到 V86 模式,执行V86的系统调用,然后再返回用户模式。boot2.c 中的 I/O 全靠 0x31 中断实现。
2.4. boot2/boot2.c
如 前所述,btx 在进 boot2.c 前已经进入了保护模式下的用户模式(关闭 PG 分页)。 boot2.c 就是一个在用户模式下执行的程序了。当然,boot2.c 和普通程序还是不同的:直接做成 BIN 和 boot1及 btx 绑在一起(README.386BSD 提到 boot1 在连接时和 btx 及 boot2.bin 是在一起的,然后才分开,这样 boot1 就可以确切的知道 btx 的地址了);没有函数库和完整的系统调用,只能依靠 btx 提供的系统调用。
不过 boot2.c 的工作不算多,就是显示提示、接收用户输入,最后载入指定 kernel 文件并调用 btx 的 0x30 中断(exec)执行kernel。
和 Linux 的 main.c 相比,btx + boot2.c 的结构是较简单的,我 到现在还不太清楚,Linux 中的printk 在内核载入前是否有用。在 boot 到 main.c 前,我没找到哪儿调用了printk.c 中的 register_console。如果确实没有,那么 main.c 中的输出是不是就看不到了呢?
3. 小结
FreeBSD 的 boot code 还是比较清晰的,遗留的一些问题我希望能在进一步学习 kernel 后找到答案。
FreeBSD 启动代码学习笔记 1
1. FreeBSD 启动流程 3
2. 分析 3
2.1. MBR 3
2.1.1. mbr/mbr.s 3
2.1.2. boot0/boot0.s 4
2.2. boot2/boot1.s 4
2.3. btx/btx/btx.s 5
2.4. boot2/boot2.c 5
3. 小结 5
感谢所有为 Linux、FreeBSD、GNU 等 Freeware 事业做出贡献的人们。
这 两天学习了一下 FreeBSD 的启动代码 (boot code),又看了一下《Linux操作系统内核分 析》第五章“Linux 启动系统”。这儿简单的写一下我自己的认识,诸多偏颇之处,敬请指正,关于 Linux 启动的 部分,参照了《Linux操作系统内核分析》一书。
本文介绍以 FreeBSD 4.2 的 boot code,因为lxr.linux.no (一个出色的 source cross reference 项目)上的 FreeBSD source 是这个版本。如果是其他版本,会有些不同,我 在家里读的就是 4.3 的,本文中有些地方也会提到这一版本中的一些内容。如果能够在线阅读,可以直接访问http://lxr.linux.no/freebsd/source/。
Lxr 上FreeBSD 4.2 for i386的启动代码都在 src/ boot/i386/ 中,在我家里的机器上 4.3 的文件目录是 src/sys/boot/i386/。
1. FreeBSD 启动流程
最典型的硬盘启动流程如下:
1) MBR (其中任意一个或者都不用,我通常都不用)
a. mbr/mbr.s 最简单的 mbr
b. boot0/boot0.s 一个简单的 Boot Manager
2) boot2/boot1.s 真正的FreeBSD 启动扇区
3) btx/btx/btx.s 初始化系统,进入保护模式
4) boot2/boot2.c 输入 kernel 文件名并调用 kernel
如 果是软盘启动,应该会省掉第一 1 两步。在src/ boot/i386/ 下还有 cdldr、 kgzldr、liloldr 几个目录提供其它方式的启动;在 4.3 中,则是 /usr/src/sys/i386/boot 下有 biosboot、cdbootboot、netboot、dosboot、 kzipboot和rawboot几个目录,提供从不同的介质启动。本文主要讨论从硬盘和软盘启动,重点在 2、3、4 几步, mbr 和 Boot Manager 都是常见的做法,没什么特别的。
2. 分析
2.1. MBR
2.1.1. mbr/mbr.s
MBR,不会有什么特别的,无非是找 Active 的分区,读入并 Jump 过去。
2.1.2. boot0/boot0.s
一个 Load Manager ,和 LILO 类似。显示一个主分区的菜单,读取用户的选择,装入扇区并 Jump 过去。整个程序很清晰,不过其中有一段非常精彩:
290 #
291 # Display routines
292 #
293
294 putkey: movb $'F',%al # Display
295 callw putchr # 'F'
296 movb $'1',%al # Prepare
297 addb %dl,%al # digit
298 jmp putstr.1 # Display the rest
299
300 #
301 # Display the option and note that it is a valid option.
302 # That last point is a bit tricky..
303 #
304 putx: btsw %dx,_MNUOPT(%bp) # Enable menu option
305 movw $item,%si # Display
306 callw putkey # key
307 movw %di,%si # Display the rest
308
309 puts: callw putstr # Display string
310
311 putn: movw $crlf,%si # To next line
312
313 putstr: lodsb # Get byte
314 testb $0x80,%al # End of string?
315 jnz putstr.2 # Yes
316 putstr.1: callw putchr # Display char
317 jmp putstr # Continue
318 putstr.2: andb $~0x80,%al # Clear MSB
319
320 putchr: pushw %bx # Save
321 movw $0x7,%bx # Page:attribute
322 movb $0xe,%ah # BIOS: Display
323 int $0x10 # character
324 popw %bx # Restore
325 retw # To caller
算上注释,35 行代码,实现六种功能(putstr.1 和 putstr.2 不是)。
2.2. boot2/boot1.s
读 入 Boot2 (disklabel+BTX+boot2.bin) 并 JUMP 至 BTX 。如果你有 4.3 的 source ,读到这儿,我建议你去看一下 /usr/src/sys/i386/boot/biosboot/README.386BSD ,这篇文档对 boot1、BTX 和 boot2 的动作有不少介绍,说明了几处重点。
2.3. btx/btx/btx.s
当当当当!重头戏上演啦!(当然,和 kernel 比这还不算重头。不过 boot 中这段是最重要的。)
老 实说,到现在我也不知道 BTX 是什么的缩写,Google 搜不到,www.FreeBSD.org 也没 有。哪位同仁若是知道,望不吝赐教。其实 btx 部分不仅是 btx.s 一个文件, btx/lib 下的 btxcsu.s、btxsys.s 和btxv86.s 也包含几个简单的函数。还有 一个 btx/btxldr 目录,不过 btx/btxldr/btxldr.s 说这只是 btx.s 的原型,我就没有多看了。
btx.s 主要做了以下工作:创建和设置保护模式环境,如 IDT、 GDT、TTS,如果设置了 PAGING 宏,还会创建一个页表(page table。我不知道这个页表是否有用,btx 在进入 boot2.c 前会把 PG 设成 0,我觉得 kernel 里应该会另外创建一个页 表,不过我还没有读到 kernel 呢);btx 也定义了0x00 - 0x10 (异常)、0x20-0x2f(硬件中断)、0x30(系统调用)和0x31-0x32(V86调用)的中断,这些中断应该会被kernel 换掉,不过在载入 kenerl 前,许多工作都要靠这些中断来做;最后,btx.s 切换到用户模式,开始执行 boot2/boot2.c。
0x31 中断(V86调用)很重要,它从用户模式切换到 V86 模式,执行V86的系统调用,然后再返回用户模式。boot2.c 中的 I/O 全靠 0x31 中断实现。
2.4. boot2/boot2.c
如 前所述,btx 在进 boot2.c 前已经进入了保护模式下的用户模式(关闭 PG 分页)。 boot2.c 就是一个在用户模式下执行的程序了。当然,boot2.c 和普通程序还是不同的:直接做成 BIN 和 boot1及 btx 绑在一起(README.386BSD 提到 boot1 在连接时和 btx 及 boot2.bin 是在一起的,然后才分开,这样 boot1 就可以确切的知道 btx 的地址了);没有函数库和完整的系统调用,只能依靠 btx 提供的系统调用。
不过 boot2.c 的工作不算多,就是显示提示、接收用户输入,最后载入指定 kernel 文件并调用 btx 的 0x30 中断(exec)执行kernel。
和 Linux 的 main.c 相比,btx + boot2.c 的结构是较简单的,我 到现在还不太清楚,Linux 中的printk 在内核载入前是否有用。在 boot 到 main.c 前,我没找到哪儿调用了printk.c 中的 register_console。如果确实没有,那么 main.c 中的输出是不是就看不到了呢?
3. 小结
FreeBSD 的 boot code 还是比较清晰的,遗留的一些问题我希望能在进一步学习 kernel 后找到答案。
No comments:
Post a Comment