为什么“读取”必须是在“内核模式”下运行的系统调用?

时间:2014-01-07 14:52:37

标签: c linux file unix operating-system

据我所知,UNIX函数read()将导致中断(TRAP)并调用系统调用read。我还记得在调用系统调用read之前它必须切换到“内核模式”并且切换很昂贵。

我想知道为什么read操作必须在“内核模式”下委托给系统调用,而不是完全在“用户模式”下完成。

例如,如果在“用户模式”中有一个管理文件访问权限的服务,read操作可以只请求此服务,而不是干扰内核..

对于磁盘驱动程序,在link中说

  

设备驱动程序可以在用户模式或内核模式下运行

有没有人有这方面的想法?为什么read必须处于内核模式?

2 个答案:

答案 0 :(得分:6)

操作系统的设计方式不同。操作系统的定义是处理计算机的硬件并为用户提供资源。操作系统也具有用户模式和内核模式的概念(正如您所说)。

通过拥有这些概念,操作系统可以定义用户可能做什么和不做什么的特定行。让他们管理硬件绝对是操作系统不希望用户做的事情。

read通常涉及硬件访问。访问硬件很麻烦且容易出错,并且可能使计算机处于不可用状态。操作系统使用驱动程序来控制计算机的硬件。

发出read(假设硬盘IO)通常会让驱动程序向磁盘控制器发送一组命令,读取它的输出,将其传递给主存等等。这是危险的操作,不应该不信任用户模式。

如果在用户模式下有服务来处理此问题。仍然需要完成上下文切换,因为该服务将作为另一个进程运行。

当然可以通过允许此操作的操作系统来完成。但现代操作系统并不是为了实现这种行为而设计的。

还有其他方法可以构建依赖于微内核的操作系统。微内核只需最少的工作就可以启动电脑并将其他所有模块留给其他模块。这意味着如果模块崩溃,系统仍然会启动。这是特定驱动程序,文件系统等的情况。我不知道微内核是否允许它们在用户空间中运行。

希望这有帮助!

答案 1 :(得分:3)

首先:调用内核非常昂贵,这已经不再适用了。过去曾经导致异常/陷阱/故障/中断是在x86系统中从用户模式切换到内核模式的唯一方法,但所有这些都随着systenter / sysexit的添加而改变机器代码指令,执行更轻量级的转换。

即使它是昂贵的,就消耗的时间而言,处理字符和块设备驱动程序的系统调用应该在内核模式下运行,因为处理硬件设备涉及读取和写入硬件寄存器,这可能是内存映射或通过I / O端口访问。

必须保护这些寄存器不受用户空间进程的任何访问。不这样做可能导致任何过程不使用已建立的API来读取文件,并直接使用硬件寄存器来读取和写入设备。对于带有文件的磁盘,这将允许用户进程完全绕过文件系统,从而绕过所有安全和权限系统。

因此,如果我们需要保护这些硬件寄存器,以便用户进程无法使用它们,那么使用它们的代码就无法在与任何其他用户进程相同的特权级别上运行。因此,它们以另一种(更特权)模式运行,这就是所谓的“内核模式”。

考虑如果配置Linux系统会发生什么,/dev/sda(通常是根文件系统所在的主硬盘)对任何人和每个人都可读/写:

# chmod 666 /dev/sda

完成此操作或多或少相当于将硬盘设备暴露给任何用户进程。您可以有效地编写可以打开,读取和写入存储在此设备中的文件的程序,但同时,您可以编写一个程序,在分区内打开,读取和写入任何文件,无论哪个权限文件都有。

也就是说,有些情况下系统只运行受信任的应用程序。这种系统不需要通用系统中存在的保护级别,因此它可以受益于不依赖于API层以将过程与硬件隔离而提高的速度。最广为人知的例子是视频会议系统。我记得Windows CE曾经以同样的权限运行它的所有程序和设备驱动程序。