美团二面:什么叫进入内核态?

作者:灵剑
链接:https://www.zhihu.com/question/306127044/answer/555327651
对操作系统有过了解的童鞋都知道内核态,而且大家或多或少都听过进入内核态,这到底是是啥意思呢?这篇文章就详细给大家科普下 。
建议首先先集中力量在计算机组成原理上,不过的确单看计算机组成原理也比较枯燥,可以结合起来稍微讲一下 。
太长不看的提前总结:

  1. 内核态,或者说 CPU 的特权模式,是 CPU 的一种工作状态,它影响 CPU 对不同指令的执行结果 。操作系统通过跟 CPU 配合,设置特权模式和用户模式,来防止应用程序进行越权的操作 。
  2. 防止应用程序越权访问内存时使用了虚拟地址空间映射的技术,这是操作系统软件配合硬件的结果 MMU 共同实现的 。在用户模式下,应用程序访问的内存地址是虚拟内存地址,会映射到操作系统指定的物理地址上 。这个虚拟内存地址空间就是你说的用户空间 。
  3. 内核态是个操作系统概念,虽然对应到 CPU 的特权模式,但一般如果没有操作系统,就不说内核态了,直接说运行在 CPU 特权模式应该没毛病 。
  4. 应用程序无法自由进入内核状态,只能通过操作系统提供的接口调用进入,或者在硬件中断到来时被动进入 。
  5. 应用程序通过操作系统的功能来使用硬件 。
首先从问题最关键的地方开始:归根到底为什么需要保护模式?
从计算机组成原理的最基础的理论开始讲起 。说到计算机,从冯诺依曼体系讲起,最重要的就是五部分:运算器、控制器、存储器、输入设备、输出设备 。
其中,运算器是无状态的;控制器配合一部分寄存器,但是寄存器数量很少,而且通常都很容易被修改;输入设备、输出设备只有接受指令的时候才能动作 。归根结底来说,整个计算机的运行状态几乎完全由存储器和少数几个寄存器控制 。
也就是说,如果一段程序能够完全控制物理内存,那么它就能做到任意改变计算机的状态,包括干掉整个操作系统然后把自己变成操作系统;把自己变成操作系统的一部分等等 。通常来说操作系统肯定是不乐意的了 。
早期的 DOS 这样的操作系统,运行在实际模式上,就遇到的是这样的情况:它其实将要执行的应用程序加载变成了操作系统的一部分,然后混合起来运行,哪一段是用户程序、哪一段是操作系统并没有很明确的界限:用户程序退出就回到操作系统;用户程序触发软件中断就到操作系统,返回又回到用户程序;用户程序自己可以访问大部分的硬件设备;用户程序甚至可以随意修改属于操作系统的数据 。于是,当时的许多病毒也毫不客气地把自己直接连接到了操作系统的程序里面,一旦执行就永远驻留成为操作系统的一部分 。当时在 DOS 上流行的病毒可谓多种多样、五花八门 。
单任务的情况下已经有不少问题了,到了多任务模式下,问题就更严重了:
  1. 因为多个应用程序要独立加载,如果两个应用程序执意要使用同一个内存地址,那就会发生严重的问题,操作系统必须防止这种事情发生
  2. 外部设备一般来说都是很傻的,它并不知道多任务的存在,不管谁操作外部设备它都是一样响应 。这样如果多个应用程序自己直接去操纵硬件设备,就会出现相互冲突,有可能一个程序的数据被发送到了另一个程序等等
  3. 操作系统必须自己响应硬件中断,通过硬件中断来切换任务上下文,让合适的任务在合适的时机继续执行 。如果应用程序自己把中断响应的程序改掉了,整个操作系统都会崩溃
  4. 操作系统必须有能力在单个应用程序崩溃的情况下清理这个应用程序使用的资源,保证不影响其他应用程序;这就要求它必须清楚知道每个应用程序使用了哪些资源
这还只是考虑到应用程序都是善良的情况下,要对付恶意程序就需要更强的手段 。
可我们前面说了,物理内存就是整个计算机状态的全部,如果程序有办法读写所有的物理内存和寄存器,那任何保护手段都无济于事 。所以要限制应用程序的行为,必须在应用程序和操作系统执行时有不同的状态,核心问题在于保护关键寄存器和重要的物理内存 。
这个目标显然是必须要硬件配合的,否则 CPU 如何区分当前究竟是执行操作系统(开放所有能力)还是应用程序(限制危险功能)呢?那么我们如果不考虑实际结果,只从需求上面分析如何解决这个问题,应该可以得到以下结论:


推荐阅读