Linux 内核栈和用户空间栈

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/12911841/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-06 14:36:58  来源:igfitidea点击:

kernel stack and user space stack

linuxlinux-kernellinux-device-driver

提问by jkv

What's the difference between kernel stack and user stack? Why kernel stack is used? If a local variable is declared in an ISR, where it will be stored? Does each process has its own kernel stack? Then how the process coordinates between both these stacks?

内核堆栈和用户堆栈有什么区别?为什么使用内核堆栈?如果在 ISR 中声明了局部变量,它将存储在哪里?每个进程都有自己的内核堆栈吗?那么这两个堆栈之间的过程如何协调?

采纳答案by FrankH.

  1. What's the difference between kernel stack and user stack ?
  1. 内核堆栈和用户堆栈有什么区别?

In short, nothing - apart from using a different location in memory (and hence a different value for the stackpointer register), and usually different memory access protections. I.e. when executing in user mode, kernel memory (part of which is the kernel stack) will not be accessible even if mapped. Vice versa, without explicitly being requested by the kernel code (in Linux, through functions like copy_from_user()), user memory (including the user stack) is not usually directly accessible.

简而言之,除了使用内存中的不同位置(因此堆栈指针寄存器的值不同)以及通常不同的内存访问保护之外,什么都没有。即在用户模式下执行时,即使已映射,内核内存(其中一部分是内核堆栈)也将无法访问。反之亦然,如果内核代码没有明确请求(在 Linux 中,通过类似 的函数copy_from_user()),用户内存(包括用户堆栈)通常不能直接访问。

  1. Why is [ a separate ] kernel stack used ?
  1. 为什么使用 [单独的] 内核堆栈?

Separation of privileges and security. For one, userspace programs can make their stack(pointer) anything they want, and there is usually no architectural requirement to even have a valid one. The kernel therefore cannot trustthe userspace stackpointer to be valid nor usable, and therefore will require one set under its own control. Different CPU architectures implement this in different ways; x86 CPUs automatically switch stackpointers when privilege mode switches occur, and the values to be used for different privilege levels are configurable - by privileged code (i.e. only the kernel).

权限与安全的分离。一方面,用户空间程序可以根据需要制作任何他们想要的堆栈(指针),并且通常没有架构要求甚至有一个有效的。因此内核不能相信用户空间堆栈指针是有效的或可用的,因此需要在它自己的控制下设置一组。不同的 CPU 架构以不同的方式实现这一点;当权限模式切换发生时,x86 CPU 会自动切换堆栈指针,并且用于不同权限级别的值是可配置的 - 通过特权代码(即仅内核)。

  1. If a local variable is declared in an ISR, where will it be stored ?
  1. 如果在 ISR 中声明了局部变量,它将存储在哪里?

On the kernel stack. The kernel (Linux kernel, that is) does nothook ISRs directly to the x86 architecture's interrupt gatesbut instead delegates the interrupt dispatch to a common kernel interrupt entry/exit mechanism which saves pre-interrupt register state before calling the registered handler(s). The CPU itself when dispatching an interrupt might execute a privilege and/or stack switch, and this is used/set up by the kernel so that the common interrupt entry code can already rely on a kernel stack being present.
That said, interrupts that occur while executing kernel code will simply (continue to) use the kernel stack in place at that point. This can, if interrupt handlers have deeply nested call paths, lead to stack overflows (if a deep kernel call path is interrupted and the handler causes another deep path; in Linux, filesystem / software RAID code being interrupted by network code with iptables active is known to trigger such in untuned older kernels ... solution is to increase kernel stack sizes for such workloads).

在内核堆栈上。内核(即 Linux 内核)不会ISR 直接挂接到 x86 架构的中断门,而是将中断分派委托给通用内核中断进入/退出机制,该机制在调用已注册的处理程序之前保存中断前寄存器状态. CPU 本身在调度中断时可能会执行特权和/或堆栈切换,这是由内核使用/设置的,因此公共中断入口代码已经可以依赖于存在的内核堆栈。
也就是说,在执行内核代码时发生的中断将简单地(继续)使用当时的内核堆栈。如果中断处理程序具有深度嵌套的调用路径,这可能会导致堆栈溢出(如果一个深层内核调用路径被中断并且处理程序导致另一个深层路径;在 Linux 中,文件系统/软件 RAID 代码被具有 iptables 活动的网络代码中断是已知会在未经调整的旧内核中触发此类事件......解决方案是增加此类工作负载的内核堆栈大小)。

  1. Does each process have its own kernel stack ?
  1. 每个进程都有自己的内核堆栈吗?

Not just each process - each threadhas its own kernel stack (and, in fact, its own user stack as well). Remember the only difference between processes and threads (to Linux) is the fact that multiple threads can share an address space (forming a process).

不仅仅是每个进程——每个线程都有自己的内核堆栈(事实上,还有自己的用户堆栈)。请记住,进程和线程(对于 Linux)之间的唯一区别是多个线程可以共享一个地址空间(形成一个进程)。

  1. How does the process coordinate between both these stacks ?
  1. 这两个堆栈之间的过程如何协调?

Not at all - it doesn't need to. Scheduling (how / when different threads are being run, how their state is saved and restored) is the operating system's task and processes don't need to concern themselves with this. As threads are created (and each process must have at least one thread), the kernel creates kernel stacks for them, while userspace stacks are either explicitly created/provided by whichever mechanism is used to create a thread (functions like makecontext()or pthread_create()allow the caller to specify a memory region to be used for the "child" thread's stack), or inherited (by on-access memory cloning, usually called "copy on write" / COW, when creating a new process).
That said, the process caninfluence scheduling of its threads and/or influence the context(state, amongst that is the thread's stackpointer). There are multiple ways for this: UNIX signals, setcontext(), pthread_yield()/ pthread_cancel(), ... - but this is disgressing a bit from the original question.

完全没有 - 它不需要。调度(如何/何时运行不同的线程,如何保存和恢复它们的状态)是操作系统的任务,进程不需要关心这个。随着线程的创建(并且每个进程必须至少有一个线程),内核为它们创建内核堆栈,而用户空间堆栈要么由用于创建线程的任何机制显式创建/提供(类似于makecontext()pthread_create()允许调用者的功能)指定要用于“子”线程堆栈的内存区域)或继承(通过访问内存克隆,通常称为“写入时复制”/ COW,在创建新进程时)。
那说,(状态,其中包括线程的堆栈指针)。有多种方法可以解决这个问题:UNIX 信号,setcontext(), pthread_yield()/ pthread_cancel(), ... - 但这与原始问题有点偏离。

回答by Jeyaram

My answer is collected from other SO questions with my stuffs.

我的答案是从其他 SO 问题和我的东西中收集的。

What's the difference between kernel stack and user stack?

As a kernel programmer, you know that the kernel should be restricted from erroneous user programs. Suppose you keep same stack for both kernel & user space, then simple segfault in user application crashes kernel and needs restart.

作为内核程序员,您知道内核应该限制错误的用户程序。假设您为内核和用户空间保留相同的堆栈,然后用户应用程序中的简单段错误会使内核崩溃并需要重新启动。

There is one "kernel stack" per CPU like ISR Stack and one "kernel stack" per Process. There is one "user stack" for each process, though each thread has its own stack, including both user and kernel threads.

每个 CPU 有一个“内核堆栈”,如 ISR 堆栈,每个进程有一个“内核堆栈”。每个进程都有一个“用户堆栈”,尽管每个线程都有自己的堆栈,包括用户线程和内核线程。

http://linux.derkeiler.com/Mailing-Lists/Kernel/2004-10/3194.html

http://linux.derkeiler.com/Mailing-Lists/Kernel/2004-10/3194.html

Why kernel stack is used?

So when we are in kernel mode, stack kind of mechanism is necessary for dealing with function calls, local variables similar to user space.

所以当我们处于内核态时,栈类的机制对于处理函数调用、类似于用户空间的局部变量是必要的。

http://www.kernel.org/doc/Documentation/x86/kernel-stacks

http://www.kernel.org/doc/Documentation/x86/kernel-stacks

If a local variable is declared in an ISR, where it will be stored?

It will be stored in ISR stack(IRQSTACKSIZE). The ISR runs on a separate interrupt stack only if the hardware supports it. Otherwise, the ISR stack frames are pushed onto the stack of the interrupted thread.

它将存储在 ISR 堆栈(IRQSTACKSIZE)中。仅当硬件支持时,ISR 才会在单独的中断堆栈上运行。否则,ISR 堆栈帧将被推送到被中断线程的堆栈中。

The user space does not know and frankly does not care about whether the interrupt is served in current process's kernel stack or a separate ISR stack. As interrupts comes per cpu, therefore ISR stack has to be per cpu.

用户空间不知道,坦率地说也不关心中断是在当前进程的内核堆栈中还是在单独的 ISR 堆栈中提供服务。由于中断来自每个 cpu,因此 ISR 堆栈必须每个 cpu。

 Does each process has its own kernel stack ?

Yes. Each process has its own kernel stack.

是的。每个进程都有自己的内核堆栈。

 Then how the process coordinates between both these stacks?

@FrankH's answer looks great to me.

@FrankH 的回答对我来说很棒。

回答by arenard

  1. What's the difference between kernel stack and user stack
  1. 内核堆栈和用户堆栈有什么区别

Taking reference from Robert Love's Linux Kernel Development, the main difference is the size:

参考 Robert Love 的 Linux Kernel Development,主要区别在于大小:

User-space can get away with statically allocating many variables on the stack, including huge structures and thousand-element arrays.
This behavior is legal because user-space has a large stack that can dynamically grow.
The kernel stack is neither large nor dynamic; it is small and fixed in size.
The exact size of the kernel's stack varies by architecture.
On x86, the stack size is configurable at compile-time and can be either 4KB or 8KB.
Historically, the kernel stack is two pages, which generally implies that it is 8KB on 32-bit architectures and 16KB on 64-bit architectures—this size is fixed and absolute.
Each process receives its own stack.

用户空间可以避免在堆栈上静态分配许多变量,包括巨大的结构和千元素数组。
这种行为是合法的,因为用户空间有一个可以动态增长的大堆栈。
内核堆栈既不大也不动态;它体积小,尺寸固定。
内核堆栈的确切大小因架构而异。
在 x86 上,堆栈大小可在编译时配置,可以是 4KB 或 8KB。
历史上,内核堆栈是两页,这通常意味着它在 32 位架构上是 8KB,在 64 位架构上是 16KB——这个大小是固定的和绝对的。
每个进程接收自己的堆栈。

Also the kernel stack contains a pointer to the thread_info struct holding information about the thread.

此外,内核堆栈包含一个指向 thread_info 结构的指针,该结构保存有关线程的信息。