内核栈和用户栈有什么区别?为什么要使用内核栈?如果在ISR中声明了一个本地变量,它将存储在哪里?每个进程都有自己的内核栈吗?那么进程如何在这两个栈之间协调?
内核栈和用户栈有什么区别?为什么要使用内核栈?如果在ISR中声明了一个本地变量,它将存储在哪里?每个进程都有自己的内核栈吗?那么进程如何在这两个栈之间协调?
- 内核栈和用户栈有什么区别?
简而言之,除了使用不同的内存位置(因此堆栈指针寄存器的值不同)以及通常具有不同的内存访问保护之外,它们没有任何区别。也就是说,在用户模式下执行时,即使映射了内核内存(其中部分为内核栈),也将无法访问内核内存。反之亦然,没有通过内核代码明确请求(在Linux中,通过像copy_from_user()
这样的函数),通常无法直接访问用户内存(包括用户堆栈)。
- 为什么要使用[单独的]内核栈?
特权和安全的分离。首先,用户空间程序可以使它们的堆栈(指针)成为任何它们想要的东西,通常没有必要甚至具有一个有效的堆栈指针的结构要求。因此,内核不能信任用户空间堆栈指针为有效或可用,因此需要一个由自己控制的堆栈。不同的CPU架构以不同的方式实现这一点。x86 CPU 在特权模式切换发生时自动切换堆栈指针,并且要使用不同的特权级别的值是可配置的,只有特权代码(即内核)才能够更改。
- 如果在ISR中声明了一个局部变量,它将存储在哪里?
在内核栈上。内核(即Linux内核)不会直接挂钩ISR到x86架构的中断门,而是将中断分派委托给通用内核中断入口/出口机制,在调用注册的处理程序之前保存预中断寄存器状态。当CPU分派中断时,可能会执行权限和/或堆栈切换,这由内核使用/设置,以便通用中断入口代码可以依赖于已经存在的内核栈。
话虽如此,当内核代码执行时发生中断时,将继续使用该点处的内核堆栈。如果中断处理程序具有深层嵌套的调用路径,则可能会导致堆栈溢出(如果中断了深度内核调用路径并且处理程序引起另一个深度路径;在Linux中,文件系统/软件RAID代码被具有iptables活动的网络代码中断已知会触发此类问题,对于这些工作负载的解决方案是增加内核堆栈大小)。
我的回答是从其他SO问题中收集的并加入了我的东西。
What's the difference between kernel stack and user stack?
作为内核程序员,您知道内核应该受到错误用户程序的限制。假设您为内核和用户空间保留相同的堆栈,那么用户应用程序中的简单段错误会导致内核崩溃并需要重新启动。
每个CPU都有一个“内核堆栈”,就像ISR堆栈一样,每个进程也有一个“内核堆栈”。虽然每个线程都有自己的堆栈,包括用户和内核线程,但每个进程只有一个“用户堆栈”。
http://linux.derkeiler.com/Mailing-Lists/Kernel/2004-10/3194.html
Why kernel stack is used?
所以当我们在内核模式下时,需要一种类似于用户空间的堆栈机制来处理函数调用和局部变量。
http://www.kernel.org/doc/Documentation/x86/kernel-stacks
If a local variable is declared in an ISR, where it will be stored?
它将存储在ISR堆栈(IRQSTACKSIZE)中。如果硬件支持,ISR将在单独的中断堆栈上运行。否则,ISR堆栈框架将被推入中断线程的堆栈上。
用户空间并不知道,并且实际上也不关心中断是在当前进程的内核堆栈还是单独的ISR堆栈中服务的。由于中断发生在每个CPU上,因此ISR堆栈必须为每个CPU设置。
Does each process has its own kernel stack ?
是的,每个进程都有自己的内核栈。
Then how the process coordinates between both these stacks?
我认为@FrankH的回答很棒。
sleep
系统调用期间修改该内存,例如,将内核返回地址替换为跳转到某些内核代码的地址,该代码将为该进程设置UID=0。 - Peter Cordes
syscall
指令具有以下属性:SYSCALL指令不保存堆栈指针(RSP)。如果操作系统系统调用处理程序将更改堆栈指针,则由软件负责保存堆栈指针的先前值。 - Some Name