【问题标题】:How does the Linux kernel enter supervisor mode in x86?Linux 内核如何在 x86 中进入超级用户模式?
【发布时间】:2021-03-05 00:33:19
【问题描述】:

我试图探测模式切换发生时的事件(用户->内核模式),结果我需要找到转换发生时会触发哪个函数。

似乎SBI 是 RISC-V 的过渡位置。我想知道为 x86 处理这个的代码在哪里?

【问题讨论】:

  • 在 x86 上,通常用户空间使用 syscall。 64 位内核入口点在arch/x86/entry/entry_64.Sarch/x86/entry/entry_64_compat.S 中定义。有关这些系统调用入口点如何工作的一些信息,请参阅What happens if you use the 32-bit int 0x80 Linux ABI in 64-bit code?。 (至少在最近通过 C 进行重新设计之前。)
  • 没有单一的方法。访问内存可能会触发内核模式(通常用于更新访问页数,用于缓存管理)。任何错误也可能触发内核。调试说明或陷阱。跳远(取决于描述符)。中断(硬件,例如调度程序的定时器,或来自设备的软件中断),系统调用......

标签: linux-kernel x86


【解决方案1】:

事情没那么简单。在 x86 中,有 4 种不同的权限级别:0(操作系统内核)、1、2 和 3(应用程序)。 Linux 中不使用特权级别 1 和 2:内核以特权级别 0 运行,而用户空间代码以特权级别 3 运行。当前特权级别 (CPL) 存储在 CS(代码段)的位 0 和 1 中注册。

从用户到内核的转换可以通过多种方式发生:

  • 通过硬件中断:页面错误、一般保护错误、设备、硬件计时器等。
  • 通过软件中断:int 指令引发软件中断。 Linux中最常见的是int 0x80,配置为用于从用户空间到内核空间的系统调用。
  • 通过sysentersyscall 等专用指令。

在任何情况下,都没有实际的代码进行转换:它是由处理器自己完成的,它从一个特权级别切换到另一个,并根据内核在启动后立即设置的信息。

在中断的情况下,使用Interrupt Descriptor Table (IDT) 的条目。请参阅this useful documentation page 关于 Linux 中的中断,其中解释了有关 IDT 的更多信息。如果您想了解详细信息,请查看Intel 64 and IA-32 architectures software developer's manual, Volume 3 的第 5 章。

简而言之,每个 IDT 条目都指定了一个描述符特权级别 (DPL) 以及一个新的代码段和偏移量。在软件中断的情况下,处理器会进行一些特权级别检查(其中之一是 CPL int 0x80 系统调用的方式。

对于像 sysentersyscall 这样的专用指令,细节不同,但概念相似:CPU 检查权限,然后从专用的 Model Specific Registers (MSR) 中检索信息,该信息由之前设置启动后的内核。

对于系统调用,结果总是相同的:用户代码切换到特权级别 0 并开始执行内核代码,最终在内核定义的不同系统调用入口点之一的开头结束。

可能的系统调用入口点是:

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-05-16
    • 2020-08-09
    • 2018-05-06
    • 1970-01-01
    • 2017-09-19
    相关资源
    最近更新 更多