对Linux内核的总结认识

数据人 2010-08-10

第一次接触Linux是高三那时,后来在大学里舍友T总的影响便开始了对Linux的不断追求与学习。读万卷书不如行万里路,以前在学校里看了那么多书还不如工作中在代码中煅练,当然关键是找到个入门口点,我选择驱动程序开始!下面总结和谈下学习驱动后对其的理解与认识。

1.内核是怎样实现其管理的职能?

以前在学校时一直不能理解内核是怎么做管理?比如内核如何知道在什么时候对各个进程做调度,又在什么时候知道缺页从而执行内存比如内核如何知道在什么时候对各个进程做调度,又在什么时候知道缺页从而执行内存管理的代码,内核为什么在会需要它管理的时候被唤醒,进程在用户态跑的好好的,又是谁唤醒内核转入核心态去check一下?内核管理职能的实现一方面可以是通过中断触发,这些中断包括系统调用,硬件中断;另一方面有一些内核线程长期运行在内核态。因为系统调用往往触发相应驱动程序代码的执行,而驱动程序本身包含大量可以导致进程休眠的代码,例如一个系统调用read把CPU从用户态转到核心态,经过虚拟文件系统VFS传入到设备相关的驱动程序中file_operations的真正实现函数read,这个系统调用可能引发内核中很多管理模块的执行,假如驱动中发现设备没有可用的数据时对于阻塞型的调用,驱动程序会把与其相关联的用户执行线程挂起休眠,从而让出了CPU实现了进程调度器的调度。另外,一般来说CPU定时器会周期性地唤醒内核让其check一下,看一下有没有东西需要它处理的(主要是引发了软中断的产生,进而可能执行一些软中断的任务,稍后解释什么是软中断)。这就是内核的“心跳”,一般PC上会把这个心跳值HZ(每秒定时器中断次数)设置为100~1000,jiffies是开机累计心跳值。同样,CPU外部的器件会产生大量的中断,这样使得内核也知道了它将要干什么。最后,内核线程kernel thread在内核态周期性地执行,例如磁盘高速缓存的刷新,网络连接的维护,页面的换入换出等。

2.代码执行空间及其可见度

以前看一本书操作系统的书搞得好头痛,x86上又是什么GDT,又是什么LDT,MMU的存在搞得内存这块非常的难懂。现在看来在区分用户态和核心态的32位系统上,用户进程所能看到的空间仅仅分配给它的4G虚拟地址空间,用户进程要想通往内核的唯一途径是内核事先定义的有限数目的“系统调用”。系统调用的实质是该进程把数据(包括中断号,系统调用的参数)放进 CPU特定寄存器并向CPU发送一个异常。通往内核并不意味着用户进程就能看到并且干预内核空间,它能且仅能通过系统调用给定的接口参数向内核申请服务,这样内核会接手和代表用户进程并借用该用户进程的上下文继续执行(英文context的翻译,是指程序计数器、栈和一组寄存器等),CPU转入核心态,内核代码就执行该系统调用在内核中的“实现部分”以满足用户进程对数据操作的需要,就执行路线上说,此时的内核执行处于“该用户进程上下文” 中,内核能够看到该用户进程的空间并且该执行路线是与用户进程相关,内核访问用户空间的代码随体系结构不同而有不同的实现,而且需要经过地址转换。待内核处理完系统调用返回后,则转回用户态,用户态进程就在该系统调用返回继续前行。在这种多任务的操作系统中,内核代码存在着多条执行路线,所以内核代码非常讲究代码可重入性设计。在内核中,中断不与任何一个用户进程相关,包括定时器中断或者外围硬件中断和甚至“软中断”,即不是运行在任何一个进程的上下文中而是运行在中断上下文拥有自己的程序计数器、栈和一组寄存器;常常硬件中断的发生并且被响应必定意味着切换CPU上下文。中断上下文不代表用户进程,所以中断执行例程不能访问用户空间的一切内容。

3.驱动程序是什么?及其与内核的关系

驱动程序本身就是内核的一部分,从www.kernel.org下载回来的内核代码,单从代码量来说驱动程序超过占65%,当然因为内核配置和条件编译的关系,并不是所有的驱动都会被选上。内核中除掉驱动程序以外的代码是一个框架,该框架提供一个公有的属性,不随CPU体系架构和具体硬件型号而变化,也是一个高度抽象模块集,更是内核的“基础设施”,这个基础设施向驱动程序提供一些接口和定义一些标准。驱动程序的设计要遵循内核给定给驱动程序的标准并使用内核和接口,这样就把操作具体硬件相关的工作交给了驱动程序,抽象出更一般的模块,提高了操作系统的可移植性,可扩展性,和标准化。就像做填空题那样,驱动程序在内核给定的空格上填好这个固定的空以使整个表达式是正确的。严格来说驱动程序包括:CPU体系架构驱动,各种各样的硬件设施驱动。一般的驱动开发者其实工作的重点是除CPU外的设备的适配。基于CPU体系架构的实现依赖于具体的平台如ARM,X86,SPARC,PPC,MIPS等,所以具体到平台的实现部分有些是用汇编语言写的,这些汇编因不同的体系结构而不同(某种原因是C语言实现不了的操作,某些是基于采用汇编实现效率更高更安全)。比如在关中断开断的实现又或切换进程上下文等操作采用汇编。除CPU外的设备一般C语言就完成了,因为大多数是与操作寄存器和数据读写有关。这里应该指明,现在的嵌入式芯片应该称之为SOC(System On Chip)更适合,而本文的CPU指的是处理器内核比如ARM926EJ-S。设备驱动程序是跟设备操作相关的系统调用的内核实现版本。就是说对设备的操作(比如ioctl(fd,…))其在内核的实现是由驱动完成。所以驱动要做的事情就是实现file_operations结构的函数指针,安排中断例程。当然驱动也有分层的,有些模块纯粹是一种软件抽象。比如USB驱动分层。驱动程序是直接面对硬件,内核通过驱动与硬件交互。对内核的核心来说驱动屏蔽了硬件的实现细节。驱动对硬件的操作集中表现在对寄存器的访问及数据读写。

相关推荐