【问题标题】:kernel stack and user space stack内核栈和用户空间栈
【发布时间】:2012-10-06 09:13:17
【问题描述】:

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

【问题讨论】:

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


    【解决方案1】:
    1. 内核栈和用户栈有什么区别?

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

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

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

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

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

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

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

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

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

    【讨论】:

    • 优秀的答案 FrankH.谢谢。
    • @FrankH 很好的答案.. 但我有一些小问题,但在 ARM 架构中.. 这个内核堆栈与不同的处理器模式有什么关系?
    • @Rahul:“SO 评论的边距太小,无法包含这样的答案”。堆栈/堆栈指针寄存器如何在不同的 ARM CPU 模式下工作(哪些模式实现了存储的 SP)是一个很好的问题,但需要比评论更多的空间来回答。这同样适用于 x86 任务门或 IST 之类的东西——没有“单一”内核堆栈指针之类的东西(就像没有“单一”用户堆栈指针一样),以及有什么硬件支持/授权不同操作模式下的单独堆栈指针...非常依赖硬件。
    • @FrankH。我为同样的问题创建了新问题...stackoverflow.com/q/22601165/769260我希望现在你可以帮助我而不用关心空间:)
    • @FrankH。您能否提供一个图表来显示内核堆栈在进程的内存布局中属于哪个位置?
    【解决方案2】:
    1. 内核栈和用户栈有什么区别

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

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

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

    【讨论】:

      【解决方案3】:

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

      【讨论】:

        猜你喜欢
        • 2018-06-10
        • 1970-01-01
        • 2012-04-29
        • 1970-01-01
        • 2017-09-19
        • 1970-01-01
        • 1970-01-01
        • 2014-05-13
        相关资源
        最近更新 更多