内核堆栈和用户空间堆栈

时间:2012-10-16 09:46:49

标签: linux linux-kernel linux-device-driver

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

3 个答案:

答案 0 :(得分:161)

  
      
  1. 内核堆栈和用户堆栈有什么区别?
  2.   

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

  
      
  1. 为什么使用[单独的]内核堆栈?
  2.   

分离权限和安全性。例如,用户空间程序可以使它们的堆栈(指针)成为他们想要的任何东西,并且通常没有架构要求甚至没有架构要求。因此,内核不能信任用户空间栈指针有效也不可用,因此需要一组在其自己的控制之下。不同的CPU架构以不同的方式实现这一点;当特权模式切换发生时,x86 CPU会自动切换堆栈指针,并且可以配置用于不同权限级别的值 - 通过特权代码(即只有内核)。

  
      
  1. 如果在ISR中声明了局部变量,它将存储在哪里?
  2.   

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

  
      
  1. 每个进程都有自己的内核堆栈吗?
  2.   

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

  
      
  1. 这两个堆栈之间的流程如何协调?
  2.   

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

答案 1 :(得分:15)

我的回答是从我的其他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的答案看起来很棒。

答案 2 :(得分:3)

  
      
  1. 内核堆栈和用户堆栈有什么区别
  2.   

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

  

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

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