linux内核初探(一)

在提到linux内核的时候,总觉得很是高大上,自己没有能力去触碰,但是在进行云计算开发,特别是虚拟化的一些 代码阅读方面,如果没有内核的知识很是捉襟见肘,这里作为内核初探,我们先来明确一些在内核中一些比较重要的 概念,我不会去具体分析linux的源代码,实际上我也看不太懂,特别是汇编,所以一个比较简单快速的办法就是去 抓住一些重要的概念来理解。

中断

中断几乎是内核设计中最重要的概念了,在linux启动的时候要设置多次中断向量表,中断关乎两个重要概念:

 * IDT(Interrupt Descriptor Table) 中断描述符表
 * 中断服务程序

很显然IDT中存储了中断服务程序的入口地址,他们都存在于内核的代码区,当内核接收到中断控制器(8259A)发来 的中断信号时,根据中断的类型,在IDT中寻找对应的中断服务程序的入口地址,然后执行中断服务程序。那么内核 是如何找到中断向量表呢,这个得求助于IDTR(IDT基地址寄存器),中断的执行原理就是这么简单。

中断是如此的重要,最常见的场景就是内核操作低速的外设的时候,就需要使用中断。常见的低速外设有块设备(硬盘)、 显示器、键盘、串行口(如鼠标),当对这些设备进行操作的时候都有对应的中断服务程序,这就需要将它们的中断 服务程序和IDT相挂接。

用户进程与内核进行交互的时候,需要使用到system call。它实际上是为了解决用户进程不能访问内核代码而提供 的一套系统服务接口,System Call与int 0x80中断描述符表挂接,是系统调用软中断的总入口。所以system call 是一种软中断,需要通过IDT来找到系统调用入口。

还有一种比较重要的中断是时钟中断,它掌握着进程的轮转调度,倘若没有时钟中断,也就不会有进程因为时间片到期 而退出执行的情景,那么轮转调度也会失去意义。

当然我们也不想什么时候都产生中断,在操作系统还没有做好中断响应的准备的时候,我们可以在8259A中通过中断 屏蔽字关中断。

缓冲区

实际上CPU只能与内存打交道,它本身是不能看见各种外设的,如何内核想与外设打交道就必须使用缓冲区,它在内存 中的位置处于靠近内核区,在主内存区之前的地方。缓冲区被划分成3000(若干)多个缓冲块,要管理这些缓冲块需要 精心设计的数据结构,在缓冲区的开头有一块专门的内存区域来存储缓冲区管理结构,这个数据结构是buffer_head 双向环链表,每个buffer_head关联一个缓冲块。

内核想要知晓缓冲区的信息,在内核的数据区就必须存储缓冲区的相关情况,这个结构就是hash_table。所以linux 内核使用hash_table与buffer_head来管理整个缓冲区。

前面说了缓冲区是cpu与外设交互的媒介,所以内核在读取和写入硬盘等块设备的时候必须申请空闲的缓存区,然后 才能进行后续的工作。

进程

进程是操作系统的核心,用户对CPU的使用都是通过进程来实现的。那么内核是如何实现对进程的管理和调度的呢?

 * task_struct是每个进程所独有的结构,它标识了进程的各项属性,包括剩余时间片、进程执行状态、局部数据描述符表(LDT)和任务状态描述符表(TSS)

 * task[64]存在于内核的数据区中,它存储着各个进程的task_struct,操作系统需要对多个进程加以比较和选择的时候,就可以遍历task[64]结构。

 * GDT(全局描述符表),它是系统中唯一的段描述符的数组,实际上每个进程(包括内核)都有将自己管辖的内存分为不同的段区(如代码区、数据区、堆栈区等),所以每个进程也有自己的LDT(局部描述符表),GDT通过索引项与每一个LDT建立连接,这样内核就可以知道每个进程的内存布局。

内存管理

我们知道内核会占用一部分的内存,一般位于内存的起始位置,然后接下来对内存的划分主要分为三块,分别是缓冲区、 虚拟盘和主内存区,虚拟盘顾名思义是对硬盘的一种映射,它一般都存储着根文件系统,也是为了加快对硬盘访问的 一种方案。

接下来就是主内存区,它是用户进程的内存空间,linux对主内存采取分页管理的方法,当然对于内核和用户进程的 分页管理完全不同,这就导致了内核可以访问全部的物理地址空间,而用户进程只能访问自己的内存区域。



Previous     Next
zhing /
Published under (CC) BY-NC-SA in categories linux  tagged with linux