当一个任务(进程)执行系统调用而陷入内核代码中执行时,我们就称进程处于内核运行态(或简称为内核态)。此时处理器处于特权级最高的(0级) 内核代码中执行。当进程处于内核态时,执行的内核代码会使用当前进程的内核栈。每个进程都有自己的内核栈。当进程在执行用户自己的代码时,则称其处于用户运行态(用户态)。即此时处理器在特权级最低的(3级)用户代码中运行。
在内核态下CPU可执行任何指令,在用户态下CPU只能执行非特权指令。当CPU处于内核态,可以随意进入用户态;而当CPU处于用户态时,用户从用户态切换到内核态只有在系统调用和中断两种情况下发生,一般程序一开始都是运行于用户态,当程序需要使用系统资源时,就必须通过调用软中断进入内核态。
Linux使用了Ring3级别运行用户态,Ring0作为内核态,没有使用Ring1和Ring2。Ring3状态不能访问Ring0的地址空间,包括代码和数据。Linux进程的4GB地址空间,3G-4G部分大家是共享的,是内核态的地址空间,这里存放在整个内核的代码和所有的内核模块,以及内核所维护的数据。用户运行一个程序,该程序所创建的进程开始是运行在用户态的,如果要执行文件 *** 作,网络数据发送等 *** 作,必须通过 write,send等系统调用,这些系统调用会调用内核中的代码来完成 *** 作,这时,必须切换到Ring0,然后进入3GB-4GB中的内核地址空间去执行这些代码完成 *** 作,完成后,切换回Ring3,回到用户态。这样,用户态的程序就不能随意 *** 作内核地址空间,具有一定的安全保护作用。
处理器模式从Ring3向Ring0的切换发生在控制权转移时,有以下两种情况:访问调用门的长转移指令CALL,访问中断门或陷阱门的INT指令。具体的转移细节由于涉及复杂的保护检查和堆栈切换,不再赘述,请参阅相关资料。现代的 *** 作系统通常使用中断门来提供系统服务,通过执行一条陷入指令来完成模式切换,在INTEL X86上这条指令是INT,如在WIN9X下是INT30(保护模式回调),在LINUX下是INT80,在WINNT/2000下是INT2E。用户模式的服务程序(如系统DLL)通过执行一个INTXX来请求系统服务,然后处理器模式将切换到核心态,工作于核心态的相应的系统代码将服务于此次请求并将结果传给用户程序。
一,中断处理过程
硬件中断:来自时钟,外设
可编程中断:programmed interrupt,执行引起软件中断的指令。
例外中断:如页面错。
都由系统负责处理。当发生一个中断时,如果CPU正在比该中断级低的处理机运行级上运行,它就在解码下条指令之前,接受该中断,并提高处理机运行级。内核处理中断的 *** 作顺序如下:
1,对于正在进行的进程,保存其当前寄存器上下文,并创建压入一个新的上下文层。
2,确定中断源,识别中断类型。如是时钟或磁盘的。
3,查找中断向量。当系统接受一个中断时,它从机器中得到一个数,系统把这个作为查表的偏移量。这个表通常成为中断向量(interrupt vector)。中断向量的内容包括各种中断源的中断处理程序的地址,以及中断处理程序取得参数的方式。
4,内核调用中断处理程序。
5,中断处理程序执行那个返回,恢复(d出)前一上下文层。
二,软中断
软中断通知进程发生了异步事件。
系统有个进程表,每个进程在进程表中有有个进程表项,每个进程表项有个软中断信号字段,纪录发向一个进程的所有未处理的软中断信号。
当一个进程即将从核心态返回到用户态时,或它要进入或离开一个适当的低调度优先级时,内核要检查它是否收到了一个软中断信号。
内核仅当一个进程从核心态返回到用户态时才处理软中断信号。
三,系统调用
我们在C程序中调用系统调用好像是个一般的函数调用,当实际上调用系统调用会引起用户态到核心态的状态变化,这是怎么做到的呢?
原来,C编译程序采用一个预定义的函数库(C之程序库),其中的函数具有系统调用的名字,从而解决了在用户程序中请求系统调用的问题。这些库函数一般都执行一条指令,该指令将进程的运行方式变为核心态,然后,使内核开始为系统调用执行代码。我们称这个指令为 *** 作系统陷入(operating system trap)。
系统调用的接口是一个中断处理程序的特例。
在处理 *** 作系统陷入时,
1,内核根据系统调用号查系统调用入口表,找到相应的内核子程序的地址。
2,内核还要确定该系统调用所要求的参数个数。
3,从用户地址空间拷贝参数到U区(Unix V)。
4,保存当前上下文,执行系统调用代码。
核心态:当CPU正在运行内核代码时(内核代码是共享的)。
用户态:当CPU正在运行用户代码时。
用户模式:不可以访问内核空间(>=0x80000000)
内核模式:可以访问任何有效虚拟地址,包括内核空间。一个线程可以访问其他任何线程地址空间。
已安装内核的新版本(例如,实现 SMP 支持),那不需要下载任何代码 -- 跳过此部分继续下一屏。您可以在 上找到内核代码。当您进入到那后,您将发现内核的源代码按内核版本(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 键。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)