您可以在 上找到内核代码。当您进入到那后,您将发现内核的源代码按内核版本(v2.2、v2.3 等),被组织到多个不同的目录中。在每个目录中,您将发现文件被冠以"linux-x.y.z.tar.gz"和"linux-x.y.z.tar.bz2"。这些就是 Linux 内核的源代码。您也将看到冠以 "patch-x.y.z.gz" 和 "patch-x.y.z.bz2" 的文件。这些是用来更新前面完整的内核源代码的补丁包。如果您希望编译一个新的内核版本,您将需要下载这些"linux"文件其中之一。
内核解包
如果您已从 kernel.org 下载一个新的内核,现在是要将其解包时候了。首先,cd /usr/src。如果这里有一个存在的"linux"目录,将其改名为"linux.old" ("mv linux linux.old",以 root 权限)。
现在,可以解开新的内核包了。仍然在 /usr/src 目录下,输入 tar xzvf /path/to/my/kernel-x.y.z.tar.gz 或者 cat /path/to/my/kernel-x.y.z.tar.bz2 | bzip2 -d | tar xvf -,根据您下载的源代码是用 gzip 或 bzip2 压缩的。在输入完此命令后,您下载的内核源代码会被释放到一个新的"linux"目录下。注意 -- 全套内核源代码通常将在硬盘上占用超过 50 兆空间!
讨论配置问题
在您编译内核前,您需要配置它,配置是您精确控制在新内核中启用(禁止)哪些内核功能的机会。您也将控制哪些会被编译到内核的二进制映像(在启动时被载入)而哪些被编译到需要时载入的内核模块文件。
老式配置内核的方法是极为痛苦的过程,并涉及到进入 /usr/src/linux 目录并输入 make config 命令。请放弃这种配置内核的方式 -- 除非您想在命令行上回答几百个(对!几百个)“yes/no”的问题。
配置的新途径
我们是现代人类,我们不在输入 make config,而是输入 make menuconfig 或者 make xconfig。如果您想要配置您的内核,使用上述选择之一。如果您输入 make menuconfig,您将使用一个漂亮的基于文本的彩色菜单系统来配置内核。如果您输入 make xconfig,您将使用一个更漂亮的基于 X-Window 的 GUI 界面来配置内核的各种选项。这里有一个使用 "make menuconfig" 的屏幕截图:
当使用 "make menuconfig" 时,在左面出现一个 "< >" 的选项能被编译成为一个模块。当选项被选中,按下空格键来循环选择选项是被选中或未选中, ("<*>")表示将被编译成内核映像而("<M>")表示将被编译成模块。
配置技巧
在这里有极其多的内核选项,而且我们无法在此一一解释 -- 所以请利用内核内置的帮助功能。基本上每个选项都至少有一些描述,而且每个通常都有一行"如果您不知道这个选项的含义,输入 Y。(或者 N)"。这些提示在您不知道一个特定选项的含义时能帮助您。要使用帮助,选中您有疑问的选项然后按 "?" 键。
编译和安装内核
make dep make clean
一旦您的内核配置完毕,就可开始编译它了。在我们能编译它前,我们需要生成依赖(dependency)信息并清除任何老的"编译结果"。这可以通过在 /usr/src/linux 下输入 make dep make clean 完成。
make bzImage
现在是编译真正的二进制内核映像时候了。输入 make bzImage。过几分钟后,编译会结束而且您在 /usr/src/linux/arch/i386/boot(x86 PC 内核)目录下找到 bzImage 文件。我们将待会告诉您如何安装这个新内核,但是现在我们要看看模块编译了。
编译模块
现在我们有了 bzImage,下面要编译模块了。即使您在配置内核时没有使用任何模块,也不要跳过此步骤 -- 在编译完 bzImage 后立刻编译模块是个好习惯。而且,如果您真的没有模块需要编译,这个步骤也非常快就结束了。输入 make modules make modules_install。这将导致模块被编译而且被安装到 /usr/lib/<内核版本号> 目录下。
祝贺您!您的内核已经被编译完成了,您的内核模块也编译完成并被安装。现在是要重新配置 LILO,这样您能使用新的内核。
启动配置
LILO 入门
现在是最后来重新配置 LILO 的时候了,它将负责载入新的内核。LILO 是最流行的 Linux 引导工具,而且为所有的主流 Linux 发行商所采用。您要作的第一件事是察看您的 /etc/lilo.conf 文件。它将包含一行看似 "image=/vmlinuz" 的语句。该语句告诉 LILO 到何处找到内核。
启动配置, 第二部分
要配置 LILO 来使用新的内核,您有两种选择。第一个是覆盖您现有的内核 -- 除非您手头上有一些紧急启动措施如还有此内核的引导盘,这很危险的方法。
更为安全的选择是配置 LILO 是得它能从新的或旧的内核引导。LILO 可配置成从新内核缺省启动,但仍提供一种方法让您遇上问题时能选择旧的内核来启动。这是推荐的作法,也是我们将随后介绍的方法。
启动配置, 第三部分
您的 lilo.conf 文件有可能看起来如下:
boot=/dev/hda
delay=20
vga=normal
root=/dev/hda1
read-only
image=/vmlinuz
label=linux
要在您的 lilo.conf 文件中增添新的项目,参见下列步骤。首先,拷贝 /usr/src/linux/arch/i386/boot/bzImage 到您的根(root)分区上的一个文件,例如 /vmlinuz2。一旦拷贝完毕,复制您 lilo.conf 文件的最后三行并将它们添加到该文件的最后... 我们即将结束整个步骤了...
启动配置, 第四部分
现在,您的 lilo.conf 文件应该看起来如下:
boot=/dev/hda
delay=20
vga=normal
root=/dev/hda1
read-only
image=/vmlinuz
label=linux
image=/vmlinuz
label=linux
首先,将第一个 "image=" 行改为 "image=/vmlinuz2"。其次,将第二个 "label=" 行改为 "label=oldlinux"。然后,确定在文件的开始有一行 "delay=20" -- 如果没有,增添一行。如果它已经存在,将数字至少设为 20。
启动配置, 第五部分
您最后的 lilo.conf 文件将看起来如下:
boot=/dev/hda
delay=20
vga=normal
root=/dev/hda1
read-only
image=/vmlinuz2
label=linux
image=/vmlinuz
label=oldlinux
作完这些修改后,您将需要以 root 身份运行 "lilo"。这非常重要!如果您不执行此步,启动的过程无法继续。运行 "lilo" 将给 lilo 一个机会来更新它的启动映射。
启动配置, 详解
现在我们详细地解释一下我们所作的改动。这个 lilo.conf 文件可以用来允许您启动两个不同的内核。它允许您启动您原来的内核,位于 /vmlinuz 目录下。它也允许您启动新的内核,位于 /vmlinuz2 目录下。在缺省情况下,它将尝试启动您的新内核(指向新内核的 image/label 行首先出现在配置文件中)。
如果,出于某种原因,您需要启动旧内核,只需在重新启动计算机时按住 Shift 键。LILO 将会监测到此 *** 作,然后允许您输入要启动的映像标签名。要启动旧内核,您需要输入 "oldlinux",然后按回车键。要看到有哪些选择,您可按 TAB 键。
实模式,并开始执行位于地址0xFFFF0处的代码,也就是ROM-BIOS起始位置的代码。BIOS先进行一系列的系统自检,然后初始化位
于地址0的中断向量表。最后BIOS将启动盘的第一个扇区装入到0x7C00,并开始执行此处
的代码。这就是对内核初始化过程的一个最简单的描述。
最初,linux核心的最开始部分是用8086汇编语言编写的。当开始运行时,核心将自
己装入到绝对地址0x90000,再将其后的2k字节装入到地址0x90200处,最后将核心的其余
部分装入到0x10000。
当系统装入时,会显示Loading...信息。装入完成后,控制转向另一个实模式下的汇
编语言代码boot/Setup.S。Setup部分首先设置一些系统的硬件设备,然后将核心从
0x10000处移至0x1000处。这时系统转入保护模式,开始执行位于0x1000处的代码。
接下来是内核的解压缩。0x1000处的代码来自于文件Boot/head.S,它用来初始化寄
存器和调用decompress_kernel( )程序。decompress_kernel( )程序由Boot/inflate.c,
Boot/unzip.c和Boot../misc.c组成。解压缩后的数据被装入到了0x100000处,这也是
linux不能在内存小于2M的环境下运行的主要原因。
解压后的代码在0x1010000处开始执行,紧接着所有的32位的设置都将完成: IDT、
GDT和LDT将被装入,处理器初始化完毕,设置好内存页面,最终调用start_kernel过程。
这大概是整个内核中最为复杂的部分。
[系统开始运行]
linux kernel 最早的C代码从汇编标记startup_32开始执行
startup_32:
start_kernel
lock_kernel
trap_init
init_IRQ
sched_init
softirq_init
time_init
console_init
#ifdef CONFIG_MODULES
init_modules
#endif
kmem_cache_init
sti
calibrate_delay
mem_init
kmem_cache_sizes_init
pgtable_cache_init
fork_init
proc_caches_init
vfs_caches_init
buffer_init
page_cache_init
signals_init
#ifdef CONFIG_PROC_FS
proc_root_init
#endif
#if defined(CONFIG_SYSVIPC)
ipc_init
#endif
check_bugs
smp_init
rest_init
kernel_thread
unlock_kernel
cpu_idle
・startup_32 [arch/i386/kernel/head.S]
・start_kernel [init/main.c]
・lock_kernel [include/asm/smplock.h]
・trap_init [arch/i386/kernel/traps.c]
・init_IRQ [arch/i386/kernel/i8259.c]
・sched_init [kernel/sched.c]
・softirq_init [kernel/softirq.c]
・time_init [arch/i386/kernel/time.c]
・console_init [drivers/char/tty_io.c]
・init_modules [kernel/module.c]
・kmem_cache_init [mm/slab.c]
・sti [include/asm/system.h]
・calibrate_delay [init/main.c]
・mem_init [arch/i386/mm/init.c]
・kmem_cache_sizes_init [mm/slab.c]
・pgtable_cache_init [arch/i386/mm/init.c]
・fork_init [kernel/fork.c]
・proc_caches_init
・vfs_caches_init [fs/dcache.c]
・buffer_init [fs/buffer.c]
・page_cache_init [mm/filemap.c]
・signals_init [kernel/signal.c]
・proc_root_init [fs/proc/root.c]
・ipc_init [ipc/util.c]
・check_bugs [include/asm/bugs.h]
・smp_init [init/main.c]
・rest_init
・kernel_thread [arch/i386/kernel/process.c]
・unlock_kernel [include/asm/smplock.h]
・cpu_idle [arch/i386/kernel/process.c]
start_kernel( )程序用于初始化系统内核的各个部分,包括:
*设置内存边界,调用paging_init( )初始化内存页面。
*初始化陷阱,中断通道和调度。
*对命令行进行语法分析。
*初始化设备驱动程序和磁盘缓冲区。
*校对延迟循环。
最后的function'rest_init' 作了以下工作:
・开辟内核线程'init'
・调用unlock_kernel
・建立内核运行的cpu_idle环, 如果没有调度,就一直死循环
实际上start_kernel永远不能终止.它会无穷地循环执行cpu_idle.
最后,系统核心转向move_to_user_mode( ),以便创建初始化进程(init)。此后,进程0开始进入无限循环。
初始化进程开始执行/etc/init、/bin/init 或/sbin /init中的一个之后,系统内核就不再对程序进行直接控制了。之后系统内核的作用主要是给进程提供系统调用,以及提供异步中断事件的处理。多任务机制已经建立起来,并开始处理多个用户的登录和fork( )创建的进程。
[init]
init是第一个进程,或者说内核线程
init
lock_kernel
do_basic_setup
mtrr_init
sysctl_init
pci_init
sock_init
start_context_thread
do_init_calls
(*call())->kswapd_init
prepare_namespace
free_initmem
unlock_kernel
execve
[目录]
--------------------------------------------------------------------------------
启动步骤
系统引导:
涉及的文件
./arch/$ARCH/boot/bootsect.s
./arch/$ARCH/boot/setup.s
bootsect.S
这个程序是linux kernel的第一个程序,包括了linux自己的bootstrap程序,
但是在说明这个程序前,必须先说明一般IBM PC开机时的动作(此处的开机是指
"打开PC的电源"):
一般PC在电源一开时,是由内存中地址FFFF:0000开始执行(这个地址一定
在ROM BIOS中,ROM BIOS一般是在FEOOOh到FFFFFh中),而此处的内容则是一个
jump指令,jump到另一个位於ROM BIOS中的位置,开始执行一系列的动作,包
括了检查RAM,keyboard,显示器,软硬磁盘等等,这些动作是由系统测试代码
(system test code)来执行的,随着制作BIOS厂商的不同而会有些许差异,但都
是大同小异,读者可自行观察自家机器开机时,萤幕上所显示的检查讯息。
紧接着系统测试码之后,控制权会转移给ROM中的启动程序
(ROM bootstrap routine),这个程序会将磁盘上的第零轨第零扇区读入
内存中(这就是一般所谓的boot sector,如果你曾接触过电脑病
毒,就大概听过它的大名),至於被读到内存的哪里呢? --绝对
位置07C0:0000(即07C00h处),这是IBM系列PC的特性。而位在linux开机
磁盘的boot sector上的正是linux的bootsect程序,也就是说,bootsect是
第一个被读入内存中并执行的程序。现在,我们可以开始来
看看到底bootsect做了什么。
第一步
首先,bootsect将它"自己"从被ROM BIOS载入的绝对地址0x7C00处搬到
0x90000处,然后利用一个jmpi(jump indirectly)的指令,跳到新位置的
jmpi的下一行去执行,
第二步
接着,将其他segment registers包括DS,ES,SS都指向0x9000这个位置,
与CS看齐。另外将SP及DX指向一任意位移地址( offset ),这个地址等一下
会用来存放磁盘参数表(disk para- meter table )
第三步
接着利用BIOS中断服务int 13h的第0号功能,重置磁盘控制器,使得刚才
的设定发挥功能。
第四步
完成重置磁盘控制器之后,bootsect就从磁盘上读入紧邻着bootsect的setup
程序,也就是setup.S,此读入动作是利用BIOS中断服务int 13h的第2号功能。
setup的image将会读入至程序所指定的内存绝对地址0x90200处,也就是在内存
中紧邻着bootsect 所在的位置。待setup的image读入内存后,利用BIOS中断服
务int 13h的第8号功能读取目前磁盘的参数。
第五步
再来,就要读入真正linux的kernel了,也就是你可以在linux的根目录下看
到的"vmlinuz" 。在读入前,将会先呼叫BIOS中断服务int 10h 的第3号功能,
读取游标位置,之后再呼叫BIOS 中断服务int 10h的第13h号功能,在萤幕上输
出字串"Loading",这个字串在boot linux时都会首先被看到,相信大家应该觉
得很眼熟吧。
第六步
接下来做的事是检查root device,之后就仿照一开始的方法,利用indirect
jump 跳至刚刚已读入的setup部份
第七步
setup.S完成在实模式下版本检查,并将硬盘,鼠标,内存参数写入到 INITSEG
中,并负责进入保护模式。
第八步
*** 作系统的初始化。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)