以下口水描述,不代表正确,仅个人理解。
最原始的需求是安全,保证内核不被怀有恶意或者无意的代码攻击,以至丧失自己的 “权利”。
操作系统的能力是建立在硬件芯片能力之上的,在 intel 芯片上,就规定了 Ring0-3 的 4 个特权级,分别记录在内存寻址的二进制某个确定的位中(RPL、CPL、DPL)。
Linux 只用了 Ring0 和 Ring3 这 2 个特权级,1 和 2 被用在了虚拟机上以避免特权级混淆。0、3 分别代表内核特权级和用户特权级,并基于 intel 提供的特权级校验规则:比如低特权级不能直接访问高特权级的数据段、代码段等,高特权级为低特权级提供了非一致性代码以便调用,还有提供了低特权级调用高特权级的门逻辑 (call gate)等,芯片级的核心是在可控授权的情况下,提供低特权级执行高特权级指令能力。
所有操作硬件的能力、敏感操作,都不能在用户态直接操作,所以普遍的需要由用户态向内核态申请执行。具象到 Linux 中就是我们熟悉的 0x80 中断的系统调用,中断够写一篇了,不赘述。
那么内核态和用户态的进程是同一个的嘛?
答案不是肯定也不是否定。人话就是:所有进程的内存空间使用都是一套虚拟内存空间,每个内存在自己视角看到的都是自己独占了整个内存。内核态,是内核那边内存区的代码片段在执行的一个描述,跟具体某个进程只有联系,但不是必然是一个进程。
这就很有意思了,内核的内存空间只有一个,但是都被 “映射” 到各个进程之中了,每个进程都看得到,有点像 “只读共享”,全局看,所有进程共享了相同的内核空间。
所以,有时候 A 进程通过内核调用陷入到内核态是它自己,如果是同步操作,执行完出来就完了。如果是 IO 的异步操作,申请一个读磁盘文件操作后,就去 sleep 以让出 CPU 让其他进程执行,相关申请事件挂在内核某个队列中,其他陷入内核的 “倒霉蛋” 碰到了就由它来处理,处理完执行回调唤起等待的 A 进程,A 就拿到了结果。
所以,实质情况应该是,CPU 不管你指令来自哪里,它只管执行,内核态只不过是特权级不同的内存空间上的代码片段在执行而已。所有进程都有内核的代码映射,所有进程就都具备陷入内核态的能力,谁进入了内核态,能执行内核的任务,它碰到了内心态的某些任务,就它来执行,执行完交出去,如果任务不是自己的,就告诉其他进程。这又涉及到进程调度,就很复杂了,就说不清楚了。
最后一句话:内核态和用户态是进程的两种状态,由于所有进程共享内核空间,内核空间发生的事,每个进程都有责任去处理,对应其他进程异步的,谁碰到了谁就得去处理。