如何从用户模式切换到内核模式?

17

我正在学习Linux内核,但是我不太明白如何在Linux中从用户模式切换到内核模式。这是如何工作的?您能给我一些建议或提供一些参考链接或关于此的书籍吗?


你的问题背景是什么?你是在询问特定 CPU 上的具体机制还是一般性的?你是在尝试解决某个问题吗? - Alexey Frunze
3个回答

21
用户空间应用程序在正常操作期间唯一可以显式触发切换到内核模式的方式是通过进行系统调用,例如 openreadwrite 等。每当用户应用程序使用适当的参数调用这些系统调用API时,就会触发软件中断/异常(SWI)。由于这个软中断,代码的控制权从用户应用程序跳转到操作系统提供的中断向量表[IVT]中预定义的位置。
该IVT包含了一个SWI异常处理程序例程的地址,该程序执行所有必要的步骤,以将用户应用程序切换到内核模式,并代表用户进程开始执行内核指令。

2
不完全正确。在x86架构中,任何在用户模式下发生的异常都会转移控制权到操作系统内核模式下的适当异常处理程序。 - Alexey Frunze
是的。我发完回答后就想编辑一下,说明这种情况是当用户应用程序想要显式切换到内核模式时才会出现。但是,由于网络问题,我很难这样做。现在已经编辑好了以反映这一点。 - Amarnath Revanna
@AmarnathRevanna 当服务于SWI时,操作系统如何知道它已经切换到内核模式?是否有一个特定的硬件寄存器/位来跟踪被设置为监管者(环0)/用户(环3)的模式,并在SWI上更新?基本上是什么在硬件级别上断言了从用户到内核模式的切换。 - Shyam

8

要从用户模式切换到内核模式,您需要执行系统调用。

如果您只是想了解底层发生的事情,请访问TLDP is your new friend并查看代码(它有很好的文档,不需要额外的知识来理解汇编代码)。

您对以下内容感兴趣:

  movl    $len,%edx           # third argument: message length
  movl    $msg,%ecx           # second argument: pointer to message to write
  movl    $1,%ebx             # first argument: file handle (stdout)
  movl    $4,%eax             # system call number (sys_write)
  int     $0x80               # call kernel

正如您所看到的,系统调用只是包装在汇编代码周围的一个包装器,执行中断(0x80),因此将调用此系统调用的处理程序。

让我们作弊一下,在这里使用C预处理器构建可执行文件(foo.S是一个文件,您可以在下面的链接中放置代码):

gcc -o foo -nostdlib foo.S

通过strace运行它,以确保我们会得到我们所写的内容:

$ strace -t ./foo 
09:38:28 execve("./foo", ["./foo"], 0x7ffeb5b771d8 /* 57 vars */) = 0
09:38:28 stat(NULL, Hello, world!
 NULL)               = 14
09:38:28 write(0, NULL, 14)      

5

我刚刚阅读了这篇文章,它是一个非常好的资源。它解释了用户模式和内核模式,为什么会发生更改,以及它们的代价,并提供了一些有趣的相关阅读材料。

https://blog.codinghorror.com/understanding-user-and-kernel-mode

以下是一个简短的摘录:

内核模式

在内核模式下,执行的代码对底层硬件拥有完全无限制的访问权限。它可以执行任何CPU指令并引用任何内存地址。内核模式通常保留给操作系统最低级别、最可信赖的功能。内核模式的崩溃是灾难性的;它们将停止整个计算机。

用户模式

在用户模式下,执行的代码没有直接访问硬件或引用内存的能力。在用户模式下运行的代码必须委派给系统API来访问硬件或内存。由于这种隔离所提供的保护,用户模式中的崩溃始终是可恢复的。大部分运行在您计算机上的代码都将在用户模式中执行。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接