精华区 [关闭][返回]

当前位置:网易精华区>>讨论区精华>>电脑技术>>● FreeBSD>>网络书籍>>FreeBSD 启动代码学习笔记

主题:FreeBSD 启动代码学习笔记
发信人: zenz.hu(真)
整理人: sungang(2003-04-02 20:13:45), 站内信件
Yale Huang 
mailto: [email protected] 

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 后找到答案。 



----

OpenBSD版看看吧!   

[关闭][返回]