Linux内核(一)
内核,是一个操作系统的核心,它负责管理系统的进程、内存、设备驱动程序、文件和网络系统,决定着系统的性能和稳定性。是一个提供硬件抽象层、磁盘及文件系统控制、多任务等功能的系统软件,一个内核不是一套完整的操作系统。Linux的核心,通常在根目录下,一个叫vmlinuz的文件。我们用这个文件来控制我们的整台PC,包括周边设备和软硬磁盘机、CD-ROM、声卡等。简单地说,核心就是操作系统本身。
从程序员的角度来讲,操作系统的内核提供了一个与计算机硬件等价的扩展或虚拟的计算平台。它抽象了许多硬件细节,程序可以以某种统一的方式进行数据处理,而程序员则可以避开许多硬件细节。从另一个角度讲,普通用户则把操作系统看成是一个资源管理者,在它的帮助下,用户可以以某种易于理解的方式组织自己的数据,完成自己的工作并和其他人共享资源。
Linux以统一的方式支持多任务,而这种方式对用户进程是透明的,每一个进程运行起来就好象只有它一个进程在计算机上运行一样,独占内存和其它的硬件资源,而实际上,内核在并发地运行几个进程,并且能够让几个进程公平合理地使用硬件资源,也能使各进程之间互不干扰安全地运行。
Linux操作系统由四个部分组成:
1.用户进程—用户应用程序是运行在Linux操作系统最高层的一个庞大的软件集合, 当一个用户程序在操作系统之上运行时,它成为操作系统中的一个进程。
2. 系统调用接口— 在应用程序中,可通过系统调用来调用操作系统内核中特定的过程,以实现特定的服务。例如,在程序中安排一条创建进程的系统调用,则操作系统内核便会为之创建一个新进程。
系统调用本身也是由若干条指令构成的过程。但它与一般的过程不同,主要区别是:系统调用是运行在内核态(或叫系统态),而一般过程是运行在用户态。在Linux中,系统调用是内核代码的一部分。
3. Linux内核— 内核是操作系统的灵魂,它负责管理磁盘上的文件、内存,负责启动并运行程序,负责从网络上接收和发送数据包等等。简言之,内核实际是抽象的资源操作到具体硬件操作细节之间的接口。
4. 硬件—这个子系统包括了Linux安装时需要的所有可能的物理设备。例如,CPU、 内存、硬盘、网络硬件等等。
上面的这种划分把整个Linux操作系统分为四个层次。把用户进程也纳入操作系统的范围内是因为用户进程的运行和操作系统密切相关,而系统调用接口可以说是操作系统内核的扩充,硬件则是操作系统内核赖以生存的物质条件。这四个层次的依赖关系表现为:上层依赖下层。
嵌入式linux系统有三个部分:bootloader,zImage,文件系统。从操作系统的角度来看,bootloader的最终目标是引导加载内核镜像,分为stage1,stage2,stage1完成基本硬件初始化、为stage2准备内存空间、复制stage2到内存空间、设置堆栈指针、跳转到stage2;在stage2中完成初始化本阶段用到的硬件设备、检测系统的内存映射、加载内核映像和根文件系统、设置内核启动参数、调用内核。
linux由用户空间和内核空间组成,最上面是用户(或应用程序)空间。这是用户应用程序执行的地方。用户空间之下是内核空间,Linux 内核正是位于这里。
GNU C Library (glibc)也在这里。它提供了连接内核的系统调用接口,还提供了在用户空间应用程序和内核之间进行转换的机制。这点非常重要,因为内核和用户空间的应用程序使用的是不同的保护地址空间。每个用户空间的进程都使用自己的虚拟地址空间,而内核则占用单独的地址空间。
Linux 内核可以进一步划分成 3 层。最上面是系统调用接口,它实现了一些基本的功能,例如 read
和 write
。系统调用接口之下是内核代码,可以更精确地定义为独立于体系结构的内核代码。这些代码是 Linux 所支持的所有处理器体系结构所通用的。在这些代码之下是依赖于体系结构的代码,构成了通常称为 BSP(Board Support Package)的部分。这些代码用作给定体系结构的处理器和特定于平台的代码。
Linux 内核实现了很多重要的体系结构属性。在或高或低的层次上,内核被划分为多个子系统。Linux 也可以看作是一个整体,因为它会将所有这些基本服务都集成到内核中。这与微内核的体系结构不同,后者会提供一些基本的服务,例如通信、I/O、内存和进程管理,更具体的服务都是插入到微内核层中的。
通常内核空间和用户空间是程序执行的两种不同状态。arm实现了7种工作模式,在不同模式下运行,享有不同的权限,即访问的寄存器也是不同的。划分用户空间与内核空间有助于对内核的保护,在用户空间错误的运行一些应用程序或者应用程序出错的时候而不至于修改内核空间,如果修改了内核空间很可能对系统造成破坏。
通过系统调用与硬件中断实现从内核空间到用户空间的转移。linux内核框架由7个部分组成,分别为:系统调用接口、虚拟文件系统、进程管理、内存管理、设备驱动、体系结构、网络协议栈。
系统调用接口
SCI 层提供了某些机制执行从用户空间到内核的函数调用。这个接口依赖于体系结构,SCI 实际上是一个非常有用的函数调用多路复用和多路分解服务。
进程管理
进程管理的重点是进程的执行。在内核中,这些进程称为线程,代表了单独的处理器虚拟化(线程代码、数据、堆栈和 CPU 寄存器)。在用户空间,通常使用进程 这个术语,不过 Linux 实现并没有区分进程和线程。内核通过 SCI 提供了一个应用程序编程接口(API)来创建一个新进程(fork、exec 或 Portable Operating System Interface [POSIX] 函数),停止进程(kill、exit),并在它们之间进行通信和同步(signal 或者 POSIX 机制)。
进程管理还包括处理活动进程之间共享 CPU 的需求。内核实现了一种新型的调度算法,不管有多少个线程在竞争 CPU,这种算法都可以在固定时间内进行操作。这种算法就称为 O(1) 调度程序,这个名字就表示它调度多个线程所使用的时间和调度一个线程所使用的时间是相同的。 O(1) 调度程序也可以支持多处理器(称为对称多处理器或 SMP)。
内存管理
内核所管理的另外一个重要资源是内存。为了提高效率,如果由硬件管理虚拟内存,内存是按照所谓的内存页 方式进行管理的(对于大部分体系结构来说都是 4KB)。Linux 包括了管理可用内存的方式,以及物理和虚拟映射所使用的硬件机制。
Linux 提供了对 4KB 缓冲区的抽象,例如 slab 分配器。这种内存管理模式使用 4KB 缓冲区为基数,然后从中分配结构,并跟踪内存页使用情况,比如哪些内存页是满的,哪些页面没有完全使用,哪些页面为空。这样就允许该模式根据系统需要来动态调整内存使用。
为了支持多个用户使用内存,有时会出现可用内存被消耗光的情况。由于这个原因,页面可以移出内存并放入磁盘中。这个过程称为交换,因为页面会被从内存交换到硬盘上。
虚拟文件系统
虚拟文件系统(VFS)是 Linux 内核中非常有用的一个方面,因为它为文件系统提供了一个通用的接口抽象。VFS 在 SCI 和内核所支持的文件系统之间提供了一个交换层。在 VFS 上面,是对诸如 open、close、read 和 write 之类的函数的一个通用 API 抽象。在 VFS 下面是文件系统抽象,它定义了上层函数的实现方式。文件系统层之下是缓冲区缓存,它为文件系统层提供了一个通用函数集(与具体文件系统无关)。这个缓存层通过将数据保留一段时间(或者随即预先读取数据以便在需要是就可用)优化了对物理设备的访问。缓冲区缓存之下是设备驱动程序,它实现了特定物理设备的接口。
网络堆栈
网络堆栈在设计上遵循模拟协议本身的分层体系结构。Internet Protocol (IP) 是传输协议(通常称为传输控制协议或 TCP)下面的核心网络层协议。TCP 上面是 socket 层,它是通过 SCI 进行调用的。
socket 层是网络子系统的标准 API,它为各种网络协议提供了一个用户接口。从原始帧访问到 IP 协议数据单元(PDU),再到 TCP 和 User Datagram Protocol (UDP),socket 层提供了一种标准化的方法来管理连接,并在各个终点之间移动数据。
设备驱动程序
Linux 内核中有大量代码都在设备驱动程序中,它们能够运转特定的硬件设备。Linux 源码树提供了一个驱动程序子目录,这个目录又进一步划分为各种支持设备,例如 Bluetooth、I2C、serial 等。
依赖体系结构的代码
尽管Linux 很大程度上独立于所运行的体系结构,但是有些元素则必须考虑体系结构才能正常操作并实现更高效率。内核源代码中依赖于体系结构的部分,包含了各种特定于体系结构的子目录(共同组成了 BSP)。对于一个典型的桌面系统来说,使用的是 i386 目录。每个体系结构子目录都包含了很多其他子目录,每个子目录都关注内核中的一个特定方面,例如引导、内核、内存管理等。
内核中的所有子系统要依赖于一些共同的资源。这些资源包括所有子系统都用到的过程。例如:分配和释放内存空间的过程,打印警告或错误信息的过程,还有系统的调试例程等等。
系统数据结构
task_struct
Linux内核利用一个数据结构(task_struct)代表一个进程,代表进程的数据结构指针形成了一个task数组(Linux中,任务和进程是相同的术语),这种指针数组有时也称为指针向量。这个数组的大小由NR_TASKS决定,表明Linux系统中最多能同时运行的进程数目。当建立新进程的时候,Linux为新进程分配一个task_struct结构,然后将指针保存在task数组中。调度程序一直维护着一个current指针,他指向当前正在运行的进程。
mm_struct
每个进程的虚拟内存由一个mm_struct结构来代表,该结构实际上包含了当前执行映像的有关信息,并且包含了一组指向vm_area_struct结构的指针,vm_area_struct结构描述了虚拟内存的一个区域。
inode
虚拟文件系统(VFS)中的文件、目录等均由对应的索引节点(inode)代表。每个VFS索引节点中的内容由文件系统专属的例程提供。VFS索引节点只存在于内核内存中,实际保存于VFS的索引节点高速缓存中。如果两个进程用相同的进程打开,则可以共享inode的数据结构,这种共享是通过两个进程中数据块指向相同的inode完成。
Linux 内核源代码的结构
Linux内核源代码位于/usr/src/linux目录下。
/arch:目录包括了所有和体系结构相关的核心代码。它下面的每一个子目录都代表一种Linux支持的体系结构,例如i386就是Intel CPU及与之相兼容体系结构的子目录。PC机一般都基于此目录。
/block:块设备驱动程序I/O调度。
/crypto:常用加密和散列算法(如AES,SHA等),还有一些压缩和CRC校验算法。
/drivers:目录中是系统中所有的设备驱动程序。它又进一步划分成几类设备驱动,每一种有对应的子目录,如声卡的驱动对应于/drivers/sound。
/documentation目录下是一些文档,是对每个目录作用的具体说明。
/fs:目录存放Linux支持的文件系统代码和各种类型的文件操作代码。每一个子目录支持一个文件系统,如ext3文件系统对应的就是ext3子目录
/include:目录包括编译核心所需要的大部分头文件,例如与平台相关的头文件在/include/linux子目录下,与intel cpu相关的头文件在/include/asm-i386子目录下,而/include/scsi目录则是有关scsi设备的头文件目录。
/init:目录包含核心的初始化代码(不是系统的引导代码),有main.c和Version.c两个文件。
/ipc:目录包含了核心进程间的通信代码。
/Kernel:内核管理的核心代码,此目录下的文件实现了大多数linux系统的内核函数,其中最重要的文件当属sched.c;同时与处理器结构相关代码都放在/arch/*/kernel目录下。
/lib:目录包含了核心的库代码,不过与处理器结构相关的库代码被放在/arch/*/lib/目录下。
/mm:目录包含了所有独立于 cpu 体系结构的内存管理代码,如页式存储管理内存的分配和释放等。与具体硬件体系结构相关的内存管理代码位于/arch/*/mm目录下,例如/arch/i386/mm/Fault.c 。
/modules:目录存放了已建好的、可动态加载的模块。
/net:目录里是核心的网络部分代码,实现了各种常见的网络协议,其每个子目录对应于网络的一个方面。
/scripts:目录包含用于配置核心的脚本文件等。
/security:主要包含SELinux模块。
/sound:ALSA,OSS音频设备的驱动核心代码和常用设备驱动。
/usr:实现了用于打包和压缩的cpio等。