要搞清楚什么是内核态,当然首先得明白:什么是「内核」
内核:OS的核心
内核负责提供基础性、结构性的功能,比如内存管理,文件系统等等。
很多初学者会误认为「内核 = 操作系统」,这是不对的。这种误区往往来源于Linux的命名,Linux本身只是一个内核,但我们也用Linux指代操作系统,实际上另一种不容易造成误会的名称为:「GNU/Linux」。
而学Linux,一般就是学Linux内核的实现,内核也是我们深入研究的核心。
但不要惧怕内核,内核本质也是程序,可能是C语言编写或者汇编语言编写的代码段,只是它们具有最高的权限等级,可以直接操作硬件。 当然内核是非常庞大雄伟的,代码量往往极大,但仍然是大量的C与少量的汇编,仅此而已。
内核空间
在OS中,对内存进行了划分,分成两个部分:用户空间和内核空间。
所有内核代码运行在内核空间,所有用户代码运行在用户空间。
内核的分类
内核有很多分类,比如宏内核,微内核,混合内核等等,Linux采用宏内核。
宏内核
那什么是宏内核呢?
内核要实现很多功能,比如实现TCP/IP网络通信,实现进程管理,内存管理,IO设备管理等等功能,我们可以根据这些功能划分成很多个模块,分开实现。
而宏内核就是将这些功能模块都集成在一起,即内核的全部代码,包括所有子系统(如内存管理、文件系统、设备驱动程序)都打包到一个文件中,在内核进程中运行。优点是性能高,缺点是耦合度高。
Linux采用宏内核。
微内核
与宏内核相对的是微内核。
微内核只提供最核心的功能,比如任务调度,中断处理等,其它模块如进程管理被移出内核,成为了服务进程,是一种特殊的用户进程。
在宏内核中,不同模块需要交互直接发起一个普通的函数调用即可,而在微内核中,由于不属于同一个进程,需要一种进程间通信的机制,这种通信依赖于微内核,因此运行速度会更慢一些。
当然还有混合内核,平衡两种方案的优缺点,在这就不细说了
下图对比宏内核与微内核,转自:微内核和宏内核
用户态 and 内核态
了解了内核,再来了解「内核态」就会比较轻松了。
「用户态」和「内核态」都是用来描述进程的「权限等级」的。
- 「内核态」是执行操作系统的代码的状态,有最高的权限等级,具有对所有硬件的完全访问权
- 「用户态」是执行用户代码的状态,比如我们下载的QQ、微信,浏览器访问网页,都属于「用户态」,而用户程序可以通过发起系统调用执行操作系统代码,这当然会切换到「内核态」
另一种理解是:因为我们知道内存分为「内核空间」和「用户空间」,因此「内核态」可以访问整个内存,包括「内核空间」和「用户空间」,而「用户态」只能访问「用户空间」。
操作系统一个很重要的功能就是向程序员提供优美的抽象,这种类似用户态的「所谓状态」就是一个优雅的抽象,但这也容易让人摸不着头脑。更具体地说,「用户/内核态」是两个比特位,00表示内核态,11表示用户态。
我们说过内核具有最高的权限等级,可以直接操作硬件。但是内核代码有部分也是C语言代码啊,我们自己也可以编写C语言代码,CPU该如何区分代码段来自内核还是来自用户呢?
CPU在程序状态寄存器设计了两位标志位,用于感知程序的「权限等级」,叫做ring。但是呢,大多数操作系统只用了两种,即0和3,两种「权限等级」,也就成了用户态和内核态。
CPU在保护模式下CS段寄存器的前两个bit保存着特权级的信息:00就是内核态,11就是特权最低的用户态。
因此,可以发现「内核态」的概念和CPU是紧耦合的。虽然「内核态」的概念是来自操作系统,但「内核态」本质是CPU的一种工作状态,是CPU的一种特权模式。
用户态切换内核态的时机
1、中断
发生硬件中断,比如键盘鼠标,DMA中断磁盘IO完成等等
2、系统调用
系统调用,是用户态主动的,需要依靠操作系统的支持完成对硬件的操作
3、异常
发生缺页异常等,缺页异常会在内存管理章节详述
具体如何切换
首先,Linux中,每个进程都有两个栈,分别是「用户栈」和「内核栈」,对应用户态和内核态使用。
具体可以分为三步:
- 首先拿到进程的内核栈地址空间(OS负责维护一个TSS字段存储内核栈的栈顶指针),切换到内核栈,将CPU上下文,即PC,寄存器等信息,压入到内核栈里。
- 无论是上述哪种方式触发的切换到内核态都是要执行内核方法的,将CPU的字段改为内核态,将内核程序装入相应寄存器(PC)中并开始执行内核程序
- 将内核栈的信息重新装入对应的寄存器中,将CPU的字段改回用户态,切换回用户栈,并继续执行用户程序。
可以看到,主要就是切换了两次栈地址,发生了两次CPU上下文切换(PC和所有寄存器) ,这就是用户态切换内核态带来的开销。当然上述流程包括了从内核态切换回用户态的过程。