一、用户态和内核态概述
用户态:
- 不能直接使用系统资源,也不能改变cpu的工作状态,只能访问自己内存空间
内核态:
- 系统中既有用户的代码,又有操作系统的代码,操作系统的代码不能直接被访问,以免出现不安全的的情况,所以要执行操作系统的代码就要从用户态转为内核态
- 内核态能直接访问所有的软硬件资源
二,为什么要有用户态和内核态
- cpu指令集中有一些指令是非常危险的,例如设置时钟,清理内存,如果任何代码都能访问到这些指令,那么我们的电脑就非常容易死机
- 所以就有所谓权限的概念,把不同的指令设置不同的权限,不同的状态可以访问这些不同权限的指令,从而就有了我们的用户态和内核态
三,cpu的指令集
- cpu的指令集就是软件控制硬件的媒介,每一条汇编都对应的有相应的指令,而多条指令就可以组成一个或者多个集合,我们把这些集合叫做指令集
- 假如我们可以随便的访问任何一个指令集,那么用户由于操作不当而引发的错误可能波及整台计算机,进而造成不可挽回的重大失误。
- 指令集是对硬件的操作,而硬件的操作又是极为复杂的,稍有不慎就会出现错误,所以操作系统对用户是不信任的,不允许用户直接对操作系统直接访问
针对上面的行为,硬件的生产厂商对指令集的访问设置了相关的权限,不同权限访问的指令集不同,例如Inter把 C P U 指令集
操作的权限由高到低划为4级:
- ring 0
- ring 1
- ring 2
- ring 3
ring 0是最高权限,ring 3是最低权限,而我们的的Linux操作系统选用的是ring 0和ring 3
- 用户态:ring 3
- 内核态:ring 0
其中 ring 0 权限最高,可以使用所有 C P U 指令集
,ring 3 权限最低,仅能使用常规 C P U 指令集
,不能使用操作硬件资源的 C P U 指令集
,比如 I O
读写、网卡访问、申请内存都不行,Linux系统仅采用ring 0 和 ring 3 这2个权限。
四、用户态与内核态的空间
用32位机器举例,有4G的地址空间,其中0到3G是属于我们的用户态,3到4G是属于我们的内核态
- 用户态:只能操作 0-3G 范围的低位虚拟空间地址
- 内核态:0-4G 范围的虚拟空间地址都可以操作,尤其是对 3-4G 范围的高位虚拟空间地址必须由内核态去操作
- 补充:3G-4G 部分大家是共享的(指所有进程的内核态逻辑地址是共享同一块内存地址),是内核态的地址空间,这里存放在整个内核的代码和所有的内核模块,以及内核所维护的数据
五,进入内核态的几种方法
- 系统调用:用户态进程主动切换到内核态的方式,用户态进程通过系统调用向操作系统申请资源完成工作,例如 fork()就是一个创建新进程的系统调用,系统调用的机制核心使用了操作系统为用户特别开放的一个中断来实现,如Linux 的 int 80h 中断,也可以称为软中断
- 异常:当 C P U 在执行用户态的进程时,发生了一些没有预知的异常,这时当前运行进程会切换到处理此异常的内核相关进程中,也就是切换到了内核态,如缺页异常
-
中断:当 C P U 在执行用户态的进程时,外围设备完成用户请求的操作后,会向 C P U 发出相应的中断信号,这时 C P U 会暂停执行下一条即将要执行的指令,转到与中断信号对应的处理程序去执行,也就是切换到了内核态。如硬盘读写操作完成,系统会切换到硬盘读写的中断处理程序中执行后边的操作等