控制在什么情况下从用户空间传递到Linux内核空间?

时间:2021-10-03 22:11:01

I'm trying to understand which events can cause a transition from userspace to the linux kernel. If it's relevant, the scope of this question can be limited to the x86/x86_64 architecture.

我试图了解哪些事件可能导致从用户空间到Linux内核的转换。如果相关,则此问题的范围可以限制为x86 / x86_64体系结构。

Here are some sources of transitions that I'm aware of:

以下是我所知道的一些过渡源:

  • System calls (which includes accessing devices) causes a context switch from userspace to kernel space.
  • 系统调用(包括访问设备)导致从用户空间到内核空间的上下文切换。

  • Interrupts will cause a context switch. As far as I know, this also includes scheduler preemptions, since a scheduler usually relies on a timer interrupt to do its work.
  • 中断将导致上下文切换。据我所知,这还包括调度程序抢占,因为调度程序通常依赖于计时器中断来完成其工作。

  • Signals. It seems like at least some signals are implemented using interrupts but I don't know if some are implemented differently so I'm listing them separately.
  • 信号。似乎至少有些信号是使用中断实现的,但我不知道是否有一些是以不同的方式实现的,所以我将它们单独列出。

I'm asking two things here:

我在这里问两件事:

  1. Am I missing any userspace->kernel path?
  2. 我错过了任何用户空间 - >内核路径吗?

  3. What are the various code paths that are involved in these context switches?
  4. 这些上下文切换涉及的各种代码路径是什么?

2 个解决方案

#1


4  

One you are missing: Exceptions

你遗失的一个:例外

(which can be further broken down in faults, traps and aborts)

(可以在故障,陷阱和中止中进一步细分)

For example a page fault, breakpoint, division by zero or floating-point exception. Technically, one can view exceptions as interrupts but not really the way you have defined an interrupt in your question.

例如页面错误,断点,除零或浮点异常。从技术上讲,可以将异常视为中断,但不是您在问题中定义中断的方式。

You can find a list of x86 exceptions at this osdev webpage.

您可以在此osdev网页上找到x86例外列表。

With regard to your second question:

关于你的第二个问题:

What are the various code paths that are involved in these context switches?

这些上下文切换涉及的各种代码路径是什么?

That really depends on the architecture and OS, you will need to be more specific. For x86, when an interrupt occurs you go to the IDT entry and for SYSENTER you get to to address specified in the MSR. What happens after that is completely up to the OS.

这实际上取决于架构和操作系统,您需要更具体。对于x86,当发生中断时,您转到IDT条目,对于SYSENTER,您将转到MSR中指定的地址。之后发生的事情完全取决于操作系统。

#2


1  

No one wrote a complete answer so I will try to incorporate the comments and partial answers into an answer. Feel free to comment or edit the answer to improve it.

没有人写完整的答案,所以我会尝试将评论和部分答案纳入答案。随意评论或编辑答案以改进它。

For the purposes of this question and answer, userspace to kernel transitions mean a change in processor state that allows access to kernel code and memory. In short I will refer to these transistions as context switches.

出于这个问题和答案的目的,用户空间到内核转换意味着处理器状态的变化,允许访问内核代码和内存。简而言之,我将这些转换称为上下文切换。

When discussing events that can trigger userspace to kernel transitions, it is important to separate the OS constructs that we are used to (signals, system calls, scheduling) that require context switches and the way these constructs are implemented, using context switches.

在讨论可以触发用户空间到内核转换的事件时,重要的是使用上下文切换来分离我们习惯的OS构造(信号,系统调用,调度)以及这些构造的实现方式。

In x86, there are two central ways for context switches to occur: interrupts and SYSENTER. Interrupts are a processor feature, which causes a context switch when certain events happen:

在x86中,有两种*方式可以进行上下文切换:中断和SYSENTER。中断是处理器功能,在某些事件发生时会导致上下文切换:

  • Hardware devices may request an interrupt, for example, a timer/clock can cause an interrupt when a certain amount of time has elapsed. A keyboard can interrupt when keys are pressed. It's also called a hardware interrupt.
  • 硬件设备可能请求中断,例如,定时器/时钟可能在经过一定时间后导致中断。按下键时键盘可能会中断。它也被称为硬件中断。

  • Userspace can initiate an interrupt. For example, the old way to perform a system call in Linux on x86 was to execute INT 0x80 with arguments passed through the registers. Debugging breakpoints are also implemented using interrupts, with the debugger replacing an instruction with INT 0x3. This type of an interrupt is called a software interrupt.
  • 用户空间可以启动中断。例如,在x86上的Linux中执行系统调用的旧方法是使用通过寄存器传递的参数执行INT 0x80。调试断点也是使用中断实现的,调试器用INT 0x3替换指令。这种类型的中断称为软件中断。

  • The CPU itself generates interrupts in certain situations, like when memory is accessed without permissions, when a user divides by zero, or when one core must notify another core that it needs to do something. This type of interrupt is called an exception, and you can read more about them in @esm 's answer.
  • CPU本身在某些情况下会产生中断,例如在没有权限的情况下访问内存时,当用户除以零时,或者当一个内核必须通知另一个内核需要执行某些操作时。这种类型的中断被称为异常,您可以在@esm的答案中阅读更多关于它们的内容。

  • For a broader discussion of interrupts see here: http://wiki.osdev.org/Interrupt
  • 有关中断的更广泛讨论,请参见此处:http://wiki.osdev.org/Interrupt

SYSENTER is an instruction that provides the modern path to cause a context switch for the particular case of performing a system call.

SYSENTER是一条指令,它提供现代路径,以便在执行系统调用的特定情况下进行上下文切换。

The code that handles the context switching due to interrupts or SYSENTER in Linux can be found in arch/x86/kernel/entry_{32|64}.S.

可以在arch / x86 / kernel / entry_ {32 | 64} .S中找到处理由于Linux中的中断或SYSENTER而导致的上下文切换的代码。

There are many situations in which a higher-level Linux construct might cause a context switch. Here are a few examples:

在许多情况下,更高级别的Linux构造可能会导致上下文切换。这里有一些例子:

  • If a system call got to int 0x80 or sysenter instruction, a context switch occurs. Some system call routines can use userspace information to get the information the system call was meant to get. In this case, no context switch will occur.
  • 如果系统调用到达int 0x80或sysenter指令,则发生上下文切换。某些系统调用例程可以使用用户空间信息来获取系统调用要获取的信息。在这种情况下,不会发生上下文切换。

  • Many times scheduling doesn't require an interrupt: a thread will perform a system call, and the return from the syscall is delayed until it is scheduled again. For processses that are in a section where syscalls aren't performed, Linux relies on timer interrupts to gain control.
  • 很多时候,调度不需要中断:线程将执行系统调用,并且系统调用的返回将被延迟,直到再次调度为止。对于未执行系统调用的部分中的进程,Linux依赖于计时器中断来获得控制权。

  • Virtual memory access to a memory location that was paged out will cause a segmentation fault, and therefore a context switch.
  • 对已分页的内存位置的虚拟内存访问将导致分段错误,从而导致上下文切换。

  • Signals are usually delivered when a process is already "switched out" (see comments by @caf on the question), but sometimes an inter-processor interrupt is used to deliver the signal between two running processes.
  • 信号通常在进程已经“切换”时发送(请参阅@caf对问题的评论),但有时会使用处理器间中断在两个正在运行的进程之间传递信号。

#1


4  

One you are missing: Exceptions

你遗失的一个:例外

(which can be further broken down in faults, traps and aborts)

(可以在故障,陷阱和中止中进一步细分)

For example a page fault, breakpoint, division by zero or floating-point exception. Technically, one can view exceptions as interrupts but not really the way you have defined an interrupt in your question.

例如页面错误,断点,除零或浮点异常。从技术上讲,可以将异常视为中断,但不是您在问题中定义中断的方式。

You can find a list of x86 exceptions at this osdev webpage.

您可以在此osdev网页上找到x86例外列表。

With regard to your second question:

关于你的第二个问题:

What are the various code paths that are involved in these context switches?

这些上下文切换涉及的各种代码路径是什么?

That really depends on the architecture and OS, you will need to be more specific. For x86, when an interrupt occurs you go to the IDT entry and for SYSENTER you get to to address specified in the MSR. What happens after that is completely up to the OS.

这实际上取决于架构和操作系统,您需要更具体。对于x86,当发生中断时,您转到IDT条目,对于SYSENTER,您将转到MSR中指定的地址。之后发生的事情完全取决于操作系统。

#2


1  

No one wrote a complete answer so I will try to incorporate the comments and partial answers into an answer. Feel free to comment or edit the answer to improve it.

没有人写完整的答案,所以我会尝试将评论和部分答案纳入答案。随意评论或编辑答案以改进它。

For the purposes of this question and answer, userspace to kernel transitions mean a change in processor state that allows access to kernel code and memory. In short I will refer to these transistions as context switches.

出于这个问题和答案的目的,用户空间到内核转换意味着处理器状态的变化,允许访问内核代码和内存。简而言之,我将这些转换称为上下文切换。

When discussing events that can trigger userspace to kernel transitions, it is important to separate the OS constructs that we are used to (signals, system calls, scheduling) that require context switches and the way these constructs are implemented, using context switches.

在讨论可以触发用户空间到内核转换的事件时,重要的是使用上下文切换来分离我们习惯的OS构造(信号,系统调用,调度)以及这些构造的实现方式。

In x86, there are two central ways for context switches to occur: interrupts and SYSENTER. Interrupts are a processor feature, which causes a context switch when certain events happen:

在x86中,有两种*方式可以进行上下文切换:中断和SYSENTER。中断是处理器功能,在某些事件发生时会导致上下文切换:

  • Hardware devices may request an interrupt, for example, a timer/clock can cause an interrupt when a certain amount of time has elapsed. A keyboard can interrupt when keys are pressed. It's also called a hardware interrupt.
  • 硬件设备可能请求中断,例如,定时器/时钟可能在经过一定时间后导致中断。按下键时键盘可能会中断。它也被称为硬件中断。

  • Userspace can initiate an interrupt. For example, the old way to perform a system call in Linux on x86 was to execute INT 0x80 with arguments passed through the registers. Debugging breakpoints are also implemented using interrupts, with the debugger replacing an instruction with INT 0x3. This type of an interrupt is called a software interrupt.
  • 用户空间可以启动中断。例如,在x86上的Linux中执行系统调用的旧方法是使用通过寄存器传递的参数执行INT 0x80。调试断点也是使用中断实现的,调试器用INT 0x3替换指令。这种类型的中断称为软件中断。

  • The CPU itself generates interrupts in certain situations, like when memory is accessed without permissions, when a user divides by zero, or when one core must notify another core that it needs to do something. This type of interrupt is called an exception, and you can read more about them in @esm 's answer.
  • CPU本身在某些情况下会产生中断,例如在没有权限的情况下访问内存时,当用户除以零时,或者当一个内核必须通知另一个内核需要执行某些操作时。这种类型的中断被称为异常,您可以在@esm的答案中阅读更多关于它们的内容。

  • For a broader discussion of interrupts see here: http://wiki.osdev.org/Interrupt
  • 有关中断的更广泛讨论,请参见此处:http://wiki.osdev.org/Interrupt

SYSENTER is an instruction that provides the modern path to cause a context switch for the particular case of performing a system call.

SYSENTER是一条指令,它提供现代路径,以便在执行系统调用的特定情况下进行上下文切换。

The code that handles the context switching due to interrupts or SYSENTER in Linux can be found in arch/x86/kernel/entry_{32|64}.S.

可以在arch / x86 / kernel / entry_ {32 | 64} .S中找到处理由于Linux中的中断或SYSENTER而导致的上下文切换的代码。

There are many situations in which a higher-level Linux construct might cause a context switch. Here are a few examples:

在许多情况下,更高级别的Linux构造可能会导致上下文切换。这里有一些例子:

  • If a system call got to int 0x80 or sysenter instruction, a context switch occurs. Some system call routines can use userspace information to get the information the system call was meant to get. In this case, no context switch will occur.
  • 如果系统调用到达int 0x80或sysenter指令,则发生上下文切换。某些系统调用例程可以使用用户空间信息来获取系统调用要获取的信息。在这种情况下,不会发生上下文切换。

  • Many times scheduling doesn't require an interrupt: a thread will perform a system call, and the return from the syscall is delayed until it is scheduled again. For processses that are in a section where syscalls aren't performed, Linux relies on timer interrupts to gain control.
  • 很多时候,调度不需要中断:线程将执行系统调用,并且系统调用的返回将被延迟,直到再次调度为止。对于未执行系统调用的部分中的进程,Linux依赖于计时器中断来获得控制权。

  • Virtual memory access to a memory location that was paged out will cause a segmentation fault, and therefore a context switch.
  • 对已分页的内存位置的虚拟内存访问将导致分段错误,从而导致上下文切换。

  • Signals are usually delivered when a process is already "switched out" (see comments by @caf on the question), but sometimes an inter-processor interrupt is used to deliver the signal between two running processes.
  • 信号通常在进程已经“切换”时发送(请参阅@caf对问题的评论),但有时会使用处理器间中断在两个正在运行的进程之间传递信号。