BBS水木清华站∶精华区

发信人: lion (我要offer!), 信区: Linux        
标  题: Linux内核源码指南  
发信站: BBS 水木清华站 (Wed Oct 18 16:52:54 2000) 
 
 
找到一些好文,未敢独享,本着Internet精神,翻译出来大家同乐. 
本译文的发布遵守GPL规范. 
原文出处:Kernel Hackers Grouphttp://khg.redhat.com/HyperNews/get/khg.html] 
从零开始 
PC机加电后,80x86的处理器把自己设置为实模式。并跳转到0xFFFF0,开始执行代码, 
正常情况下,那里正是ROM-BIOS的入口地址。PC的BIOS将进行一系列的系统检测并初始 
化从物理地址0开始的中断向量表。然后启动设备的第一个扇区的数据将被装载到0x7C0 
0处,并开始执行。启动设备通常是软驱或者硬盘。这个过程听上去不怎么复杂,确实不 
复杂,这就是我们进一步理解内核初始化工作之前必需的所有知识。 
Linux内核最开始的部分(boot/bootsect.S)是用8086汇编语言编写的,运行的时候,它 
把自己装载到绝对物理地址0x90000处,并继续从启动设备读入2K数据,装载到0x90200 
处,内核剩下的部分装载到0x10000处。在系统进行上述装载工作期间,屏幕会显示"Lo 
ading...".装载完成后,系统把控制权交给另一段用汇编语言编写的程序--boot/Setup 
.S。 
setup阶段将识别一些系统特征和显示卡类型。需要的话,还会提示用户选择控制台的显 
示模式。然后它会把整个系统从0x10000处移动到0x1000处,并进入保护模式,转入0x1 
000执行剩下的代码。 
下一步是内核的解压缩。0x1000处的代码来自zBoot/head.S,它将初始化寄存器并调用 
decompress_kernel()过程,该过程将依次执行zBoot/inflate.c, zBoot/unzip.c 和 z 
Boot/misc.c。解压缩后的数据将从0x100000(1M处)开始存放,这就是为什么Linux不 
可能在小于2M内存的系统上运行的原因。[已经可以在1M内存的系统中使用不压缩内核; 
参见 Memory Savers--ED] 
把内核压缩到一个GZIP文件中的工作,是由Makefile指定zBoot目录中的工具程序完成的 
,都是一些看上去很古怪的文件。 
从1.1.75版内核开始,boot and zBoot目录被下移到了arch/i386/boot。这个改变意味 
着我们可以同时生成多种指令系统的内核。但我们仍只考虑i386的情况。 
解压缩之后的代码将从0x1010000开始运行,所有的32bit相关的设置将在这里完成:装 
载IDT,GDT和LDT,识别处理器和协处理器,设置内存页。然后执行start_kernel程序。 
[Maybe I"ve lost track of physical addresses, here, asI don"t know very well 
 gas source code]以上操作的源代码是boot/head.S。这可能是整个内核代码中最有灵 
感的部分。 
要说明的是,以上的任何一个步骤出现错误,系统都会锁起。操作系统在没有完整启动 
之前无法进行错误处理。 
函数start_kernel()是在init/main.c中定义的,这个函数永远不会返回。从现在开始的 
一切代码就都是C语言编写的了,当然要除去中断管理和enter/leave系统调用。(其实, 
 大多数的宏都嵌入了汇编语言) 
对付完那些狡猾的问题之后,start_kernel()初始化内核的所有部分,特别是:·设置 
内存边界并调用paging_init()·初始化陷阱,IRQ通道和进程调度。 
·解析命令行参数. 
·如果需要,分配一个profiling缓冲。 
·初始化所有的设备驱动程序和磁盘缓冲,以及其他一些次要设备。 
·测量延时循环周期 (计算 CPU的"BogoMips"值)。 
·测试中断16是否分配给协处理器。 
最后,内核做好move_to_user_mode()(转入用户模式--译注)的准备,以便fork出init进 
程(出自同一个源文件)。接着0号进程启动,也就是所谓的摽战虜,一个无限的空循 
环。内核将依次试图执行/etc/init、/bin/init、/sbin/init,以便启动init进程。 
如果三个都没有成功,将执行?bin/sh /etc/rc敚⒃诘谝桓鲋斩松蟜ork一个root she 
ll界面。这部分代码可以上搠至Linux 0.01,那时候的Linux还只是一个单独的内核,没 
有login进程可用。 
从上述标准位置exec()(一个系统函数,用于启动一个子进程并取代父进程--译注)过 
init进程之后,内核对于程序流不再具有直接的控制权,从现在开始,内核的职责是提 
供系统调用以及维护非同步的事件(比如硬件中断)。现在多任务已经设置完毕,从现 
在开始是由init依靠fork()和login进程管理多用户访问。 
鉴于内核提供的服务内容,我们的简介将围绕这些服务进行,也会论及一些总体思想、 
底层的数据结构以及代码组织。. 
  
内核怎样看待进程 
  
从内核的角度看,一个进程只是进程表的一个条目而已。 
而进程表,是系统中最重要的一个数据结构,另外的重要数据结构还有内存管理表和缓 
冲存储器。进程表中的单位是一个叫task_struct 的庞大结构,在include/linux/sche 
d.h中定义。task_struct中既包括底层信息,又包括高层信息--广泛地汇集了从硬件寄 
存器的拷贝,到进程工作目录的inode号等等重要信息。 
进程表既是个数组又是个双向链表,还是一个树。它的物理实现是一个由指针组成的静 
态数组,指针的长度等于一个叫做NR_TASKS的常量,这个常量在include/linux/tasks. 
h中给与了定义,数组元素所指向的每个structure都位于一个为之保留的内存页中。链 
表结构由next_task和prev_task两个指针完成,但树的结构实现相当复杂,这里就不叙 
述了。如果你想改变NR_TASKS的值(该值缺省为128),你一定要确认已经修正了所有相 
关的从属文件,并重新编译。 
系统引导完成之后,内核总是面向一个进程的全局变量状态和该task_struct的指针等能 
够记录进程运行状态的方面进行工作。全局变量状态只能由scheduler(进程调度程序- 
-译注)改变,参看源码kernel/sched.c。无论如何,所有的进程在任何时候都应该被内 
核看到,由一个叫for_each_task的宏来实现。在系统轻载时,它要比顺序扫描数组更快 
。 
一个进程,永远是要么运行于"用户态模式",要么运行于"内核态模式"。以一个用户程 
序为例,它的主体运行于用户态,而系统调用运行于内核态。堆栈的使用在两种不同的 
模式下是不同的,常规的栈段供进程在用户态使用,而一个固定深度的栈(内核栈,长 
一页,由进程专有)供进程在内核态使用。内核栈所在的页永远不会被换出,因为它必 
须随时准备在进入系统调用是被使用。 
内核中的系统调用以C语言函数的形式存在,他们的"官方"名称要在函数名称前加上"sy 
s_"前缀。比如:调用burnout系统调用时,要写作"sys_burnout()"。 
[更多信息]系统调用的机制将在本指南的第三章阐述。看一看include/linux/sched.h  
中for_each_task 和 SET_LINKS的定义有助于理解关于进程表中的链表和树。 
  
创建和毁灭进程 
  
UNIX系统通过fork()系统调用创建进程,进程的终结通过调用exit()或者通过收到相应 
信号来完成。Linux对它们的实现是在kernel/fork.c和kernel/exit.c中。 
fork()比较简单,frok.c很简短而且很容易懂。它的主要任务是为新进程填写进程表的 
数据结构。Relevant steps, apartfrom filling fields, are: 
Getting a free page to hold the task_struct Finding an 
empty process slot (find_empty_process()) getting 
another free page for the kernel_stack_page copying the 
father"s LDT to the child duplicating mmap information of the father 
申请一个空闲页用来保存task_struct。找到一个空的进程槽(find_empty_process()) 
并再申请一个空闲页作为内核栈,把父进程的LDT拷贝给子进程。为父进程制作mmap的副 
本。sys_fork() 也会管理文件描述和inode. 
[新消息]1.0的内核提供某些简化的线程支持,而且fork()系统调用作出了有关的暗示。 
内核线程支持的开发正在主流内核开发之外进行。 
从进程中退出需要点技巧,因为子进程退出的话,父进程必须被告知。此外,一个进程 
可以被其他进程kill()掉(这些是UNIX的特点)。因此,文件exit.c是sys_kill()的所 
在,and thevarious flavours of sys_wait(), in addition to sys_exit(). 
exit.c中的代码我们不在这里阐述-那可不是件有趣的事情。它处理很多保证系统处于稳 
定状态的细节问题。POSIX标准非常强调的信号也是必须要处理的内容。 
 
-- 
 
※ 来源:·BBS 水木清华站 smth.org·[FROM: 211.69.205.152] 

BBS水木清华站∶精华区