《操作系统原理与实践:内核与进程》第2章:内核抽象

本文介绍了操作系统如何通过进程抽象实现程序的独立执行,并利用进程管理块(PCB)跟踪进程状态。进程可以包含多个线程,线程是执行指令的逻辑序列。双模操作使得处理器在用户模式下执行受限指令,而在内核模式下执行特权指令,以保护系统安全。硬件支持特权指令、内存保护和时钟中断,确保内核能控制资源访问并防止恶意行为。操作系统内核与用户级代码分离,遵循最小特权原则,增加系统的可靠性和安全性。
摘要由CSDN通过智能技术生成

1. 进程抽象

在这里插入图片描述
用户编辑、编译和运行用户程序。其他程序也可以存储在物理内存中,包括操作系统本身。

为了运行程序,操作系统将指令和数据从可执行映像拷贝到物理内存中。操作系统留出一个内存区域,即执行栈,用于在过程调用期间保存局部变量的状态。操作系统还为程序可能需要的任何动态分配的数据结构留出一个称为堆的内存区域。当然,要将程序复制到内存中,操作系统本身必须已经加载到内存中,并具有自己的栈和堆。

要运行同一程序的多个副本,操作系统可以在内存中拷贝程序指令、静态数据、堆和栈的多个副本。大多数操作系统会尽可能重用内存:当程序的多个副本同时执行时,它们只存储程序指令的一个副本。即便如此,程序的数据、堆和栈也需要一个单独的副本。简单期间,我们现在假设操作系统为每个进程保留整个程序的单独副本。

因此,进程是程序的实例,与面向对象编程中对象是类的实例的概念大致相同。每个程序可以有零个、一个或多个进程执行它。对于一个程序的每个实例,都有一个进程在内存中有自己的程序副本。

操作系统使用称为进程管理块(PCB)的数据结构跟踪计算机上的各种进程。PCB存储了操作系统需要的关于一个特定进程的所有信息:它存储在内存中的什么位置,它的可执行映像驻留在磁盘上的什么位置,哪个用户让它执行,进程有什么特权,等等。

有些程序由多个并发活动或线程组成。例如,web浏览器可能需要在绘制屏幕或接收网络输入的同时接收用户输入。这些独立的活动中的每一个都有自己的程序计数器和栈,但与其他线程在相同的代码和数据上运行。操作系统在一个进程中运行多个线程,其方式与在物理内存中运行多个进程的方式大致相同。

进程、轻量级进程和线程
“进程”一词,就像计算机科学中的许多术语一样,是随着时间的推移而演变的。词汇的演变有时会绊倒那些粗心的人——不同时期建立的系统会以明显不同的方式使用同一个词。
“进程”最初的意思是现在所说的“线程”——执行操作系统或应用程序代码的逻辑指令序列。进程的概念是为了简化早期操作系统的正确构造而发展起来的,早期操作系统在应用程序之间不提供保护。
将操作系统组织成一组相互协作的进程被证明是非常成功的,很快几乎每一个新的操作系统都是这样构建的,包括那些也能防止恶意或有缺陷的用户程序的系统。当时,几乎所有的用户程序都是简单的单线程程序,只有一个程序计数器和一个栈,因此没有混淆。运行一个程序需要一个进程,也就是说,一个具有保护边界的单一顺序执行流。
然而,随着并行计算机越来越流行,我们再次需要一个词来表示逻辑指令序列。一个多处理器程序可以有多个并行运行的指令序列,每个指令序列都有自己的程序计数器,但都在一个保护边界内协作。有一段时间,这些并行的指令序列被称为“轻量级进程”(每个都是在保护边界内协作的一系列指令),但最终“线程”一词得到了更广泛的应用。
这导致了目前几乎所有现代操作系统都使用的命名约定:进程执行一个程序,该程序由一个或多个在保护边界内运行的线程组成。

2. 双模操作

在这里插入图片描述
CPU的基本操作。操作码是解码得到的要执行的指令,例如分支、内存加载或算术运算。

操作系统内核如何防止进程损害其他进程或操作系统本身?毕竟,当多个程序同时加载到内存中时,是什么阻止一个进程覆盖另一个进程的数据结构,甚至覆盖存储在磁盘上的操作系统映像?

如果我们不考虑性能,一个非常简单、安全、完全假设的方法就是让操作系统内核一步一步地模拟每个用户进程中的每一条指令。软件解释器将依次获取、解码和执行每个用户程序指令,而不是处理器直接执行指令。在执行每个指令之前,解释器可以检查进程是否有权执行所讨论的操作:它引用的是自己内存的一部分,还是别人的?它是在试图转移到其他人的代码中吗?它是直接访问磁盘,还是使用操作系统中的正确例程访问磁盘?解释器可以允许所有合法操作,同时停止任何超出其界限的应用程序。

现在假设我们想加速我们假设的模拟器。大多数指令都是完全安全的,例如将两个寄存器相加,并将结果存储在第三个寄存器中。我们能否以某种方式修改处理器,使安全指令直接在硬件上执行?

为了实现这一点,我们实现了与在假设的解释器中相同的检查,但是是在硬件上而不是软件中。这称为双模操作,由处理器状态寄存器中表示处理器当前模式的单个位表示。在用户模式下,处理器在执行每个指令之前检查它,以验证是否允许该进程执行该指令。在内核模式下,操作系统在保护检查关闭的情况下执行。

内核与操作系统的其他部分
       操作系统内核是操作系统的关键部分,但它只是整个操作系统的一部分。在大多数现代操作系统中,操作系统的一部分作为链接到每个应用程序的库以用户模式运行。例如,管理应用程序菜单按钮的库代码。为了鼓励跨应用程序使用通用的用户界面,大多数操作系统都提供了一个用户界面小部件库。应用程序可以编写自己的用户界面例程,但大多数开发人员选择重用操作系统提供的例程。此代码可以在内核中运行,但不需要这样做。如果应用程序崩溃,应用程序的菜单按钮是否停止工作也无关紧要。库代码(而不是操作系统内核)与应用程序的其余部分有着共同的命运:一个问题的后果与另一个问题的后果相同。
        同样,操作系统的某些部分可以在它们自己的用户级进程中运行。窗口管理器就是一个例子。窗口管理器将发生在窗口内的鼠标操作和键盘输入定向到正确的应用程序,并且窗口管理器还确保每个应用程序只修改该应用程序的屏幕部分,而不修改操作系统的菜单栏或任何其他应用程序的窗口。如果没有此限制,恶意应用程序可能会控制机器。例如,病毒可能会显示与系统登录相同的登录提示,从而可能诱导用户向攻击者披露其密码。
        为什么不在内核中包含整个操作系统——库代码和任何用户级进程?虽然这看起来更符合逻辑,但其中一个原因是调试用户级代码通常比调试内核代码更容易。内核可以使用低级硬件来实现对断点和应用程序代码单步执行的调试支持;要单步执行内核,需要在内核下运行更低级别的调试器。调试操作系统内核的困难是虚拟机开发背后的原始动机。
        更重要的是,内核必须是可信的,因为它可以完全控制硬件。内核中的任何错误都可能损坏磁盘、一些不相关应用程序的内存,或者导致系统崩溃。通过分离出不需要在内核中的代码,操作系统可以变得更加可靠——窗口系统中的一个bug已经够糟糕的了,但是如果它能损坏磁盘,情况会更糟。这说明了最小特权的原则,即如果系统的每个部分都只具有完成其工作所需的特权而不具有更多的特权,那么安全性和可靠性就会得到增强。

在这里插入图片描述
图显示了双模处理器的操作;程序计数器和模式位共同控制处理器的操作。反过来,模式位被一些指令修改,就像程序计数器被一些指令修改一样。

需要什么样的硬件才能让操作系统内核保护应用程序和用户彼此不受影响,同时也让用户代码直接在处理器上运行?硬件至少必须支持三件事:

  • 特权指令:在用户模式下执行时,禁止所有可能不安全的指令
  • 内存保护:在用户模式下执行时,禁止进程有效内存区域之外的所有内存访问
  • 时钟中断:不管进程做什么,内核都必须有一种定期从当前进程恢复控制的方法

此外,硬件还必须提供一种安全地将控制从用户模式转移到内核模式并返回的方法。

处理器状态寄存器和特权级别
        从概念上讲,内核/用户模式是单比特位的寄存器。当设置为1时,处理器处于内核模式,可以执行任何操作。当设置为0时,处理器处于用户模式并且受到限制。在大多数处理器上,内核/用户模式存储在处理器状态寄存器中。此寄存器包含控制处理器操作的标志,通常应用程序代码无法直接访问。相反,标志在执行指令后被设置或重置。例如,当中断发生时,硬件会自动将状态寄存器保存到内存中,否则中断处理程序代码会无意中覆盖其内容。
        内核/用户模式位是处理器状态寄存器中的一个标志,每当进入内核时设置,每当内核切换回用户模式时重置。其他标志包括条件码,在执行算术运算后设置,以允许对条件分支指令进行更紧凑的编码。还有其他标志可以指定处理器是使用16位、32位还是64位地址执行。处理器状态寄存器的具体内容取决于处理器体系结构。
        某些处理器体系结构(包括Intel x86)在处理器状态寄存器中支持两个以上的权限级别(x86支持四个权限级别)。这样做的最初原因是允许将操作系统内核分为两层:(i)对机器具有无限访问权限的内核,和(ii)受某些操作限制的外层,但比完全没有权限的应用程序代码具有更大的功能。这样,操作系统内核某个部分的bug可能不会使整个系统崩溃。然而,据我们所知,无论是MacOS、Windows还是Linux都没有使用这个特性。
        未来多个权限级别的潜在用途是简化操作系统作为应用程序或虚拟机在另一个操作系统之上的运行。运行在虚拟机操作系统之上的应用程序将在用户级别运行;虚拟机将在某个中间级别运行;而真正的内核将在内核模式下运行。当然,由于只有四个级别,这对于在两层虚拟机上运行的虚拟机不起作用。在我们的讨论中,我们假设两级硬件保护的情况更简单、更普遍。

1. 特权指令

只有在有办法限制在用户模式下运行的程序直接更改其特权级别时,才可能实现进程隔离。进程可以通过执行一个特殊的指令(称为系统调用)来间接地改变它们的特权级别,从而将控制权转移到操作系统定义的固定位置的内核中。除了在这些固定位置将控制权转移到操作系统内核(即实际上成为内核)之外,应用程序进程不能更改其特权级别。

其他指令也仅限于内核代码使用。不能允许应用程序更改它可以访问的内存位置;我们将在后面讨论,将应用程序限制为只访问自己的内存,对于防止它有意或无意地损坏或误用来自其他应用程序或操作系统的数据或代码至关重要。此外,应用程序不能禁用处理器中断。

在内核模式下可用但在用户模式下不可用的指令称为特权指令。操作系统内核必须能够执行这些指令来完成其工作——它需要更改权限级别、调整内存访问以及禁用和启用中断。如果应用程序可以使用这些指令,那么恶意应用程序实际上就具有操作系统内核的能力。

因此,虽然应用程序只能使用完整指令集的一部分,但操作系统在内核模式下执行可以使用硬件的全部能力。

如果应用程序试图访问受限内存或试图更改其权限级别,会发生什么情况?这样的操作会导致处理器异常。与在语言运行时和用户代码处理异常的编程语言中获取异常不同,处理器异常会导致处理器将控制权转移到操作系统内核中的异常处理程序。通常情况下,内核只是在权限冲突后停止进程。

例子:如果允许应用程序以内核模式跳转到内核的任何位置,会发生什么?

回答:尽管看起来最坏的情况可能是操作系统崩溃,这也可能允许恶意应用程序访问特权数据或可能控制计算机。操作系统内核代表应用程序实现一组特权服务。通常,内核例程的第一步是验证用户是否具有执行操作的权限;例如,文件系统在返回数据之前检查用户是否具有读取文件的权限。如果一个应用程序可以跳过权限检查,它就有可能规避内核的安全限制。

2. 内存保护

要运行应用程序进程,操作系统和应用程序必须同时驻留在内存中。应用程序必须在内存中才能执行,而操作系统必须在内存中启动程序并处理程序运行时发生的任何中断、处理器异常或系统调用。此外,其他应用程序进程也可以存储在内存中;例如,您可以同时阅读电子邮件、下载歌曲、Skype、即时消息和浏览web。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值