阅读linux内核源码的过程,是一个将计算机学科的所有理论课程与实际的产品紧密联系起来的过程。阅读类UNIX的源码,在国外操作系统课程的教学过程中,曾经伴随了一代计算机人才的培养。遗憾的是,我学了几年计算机专业的课程,直到最近才感觉有了一定的积累,进而阅读了linux内核的源码,切实感受到了作为计算机科学与技术精髓的操作系统的魅力所在。
1.Linux和linux内核
很多linux的用户一直争论和比较各种linux发行版的易用性,但是大家都认同一点:linux,通常是指linux内核,而且尽管软件包管理方式不同、图形界面不同以及上层应用软件也相应不同,但却都具有相同的内核--linux内核。内核是一个操作系统最核心的部分,相当于汽车发动机、PC机处理器在各自系统中的核心地位。
由于我内核的阅读才刚刚起步。所以仅仅针采用x86处理器的PC机器的加电启动直到linux内核程序被成功加载的过程做一点源码阅读级别的阐述。最新的内核是2.6版本的,2.6内核与上一个版本2.4内核的差异还是较大的,这不仅仅表现在源码的组织上,更在于新内核所采用的诸多新的高性能算法上。
2.4内核的资料在网上众多,成为我读懂内核源码的最为重要的参考。试图通过寻找内核开发组织的开发者邮件列表以求了解2.4和2.6差异的过程也是艰辛的。时间所限,我并未采取这一方法,而是采取了阅读2.4资料,对比2.6新版源码的策略。
在搜索并阅读相关资料以求搞清楚linux内核到底是如何运转起来的过程中,我决定借这次课程论文的机会,求同存异,对2.6版本的内核做一点阐述。
linux内核相当复杂。且不说作为操作系统的内核这样的程序,编写源码需要各类技巧,仅仅是所涉及到的知识,分门别类的就有许多许多。可见,内核的阅读是个长期和反复的过程。也正是如此,一方面,linux牵涉到了计算机领域几乎所有的知识及其实际运用的过程,内核的阅读彰显着迷人的魅力;另一方面,linux内核在操作系统领域的应用如此广泛,以至于广大的嵌入式系统开发者都选择了在某种程度上深入学习linux内核。
2. X86 IBM PC机的启动过程
由于准备写这篇文章的时候,最新的稳定版的内核是2.6.35.4,鉴于学习要面向新技术的策略,源码采用了这个最新的版本。
我对linux内核上层软件所运行的intel x86处理器相关的内存管理、中断处理的过程并不太精通,这也限制了我目前对源码的理解。当然,最为重要的是,是因为机器启动和内核启动的过程中,大量的代码都是纯AT&T汇编(.S文件)写成的,尽管汇编都是直来直去,但面向实际运用的汇编程序也确实是一个难关,何况要想深入理解,还需要大量的intel x86处理器的知识。
一般说来,运行linux 内核的PC计算机的启动过程是这样的:
power on -> bios -> bootloader--->kernel boot --->系统初始化(main.c init.c)--->运行应用程序
3. Linux内核启动协议
阅读文档\linux-2.6.35\Documentation\x86\boot.txt
现代支持bzImage的内核的内存布局
程序段地址是由grub的大小来决定的。地址x应该在bootloader所允许的范围内,尽可能的低。
启动过程的内存地址分配情况:
| 保护模式的内核 |
100000 +------------------------+
| I/O memory hole |
0A0000 +------------------------+
| 为 BIOS保留 | Leave as much as possible unused
~ ~
| 命令行 | (Can also be below the X+10000 mark)
X+10000 +------------------------+
| 栈/堆 | 栈/堆空间是给内核实模式代码用的
X+08000 +------------------------+
| Kernel setup | setup代码运行在内核的实模式下
| Kernel boot 扇区 | The kernel legacy boot sector.
X +------------------------+
| Boot loader |
001000 +------------------------+
| Reserved for MBR/BIOS |
000800 +------------------------+
| Typically used by MBR |
000600 +------------------------+
| BIOS use only |
000000 +------------------------+
传统上支持image和zimage的内存布局如下(2.4内核就是这样的布局):
| |
0A0000 +------------------------+
| Reserved for BIOS | Do not use. Reserved for BIOS EBDA.
09A000 +------------------------+
| Command line |
| Stack/heap | For use by the kernel real-mode code.
098000 +------------------------+
| Kernel setup | The kernel real-mode code.
090200 +------------------------+ | Kernel boot sector
| The kernel legacy boot sector.
090000 +------------------------+
| Protected-mode kernel | The bulk of the kernel image.
010000 +------------------------+
| Boot loader | <- Boot sector entry point 0000:7C00
001000 +------------------------+
| Reserved for MBR/BIOS |
000800 +------------------------+
| Typically used by MBR |
000600 +------------------------+
| BIOS use only |
000000 +------------------------+