精华内容
下载资源
问答
  • ---------------------------------------------------Linux 中的各种栈:进程栈 线程栈 内核栈 中断栈
  • 9.11 中断(中):进程栈与中断栈 进程上下文 进程上下文 pc 指针指向 task函数体 sp 指针指向 任务栈 栈是C语言运行的基础 函数调用:局部变量、函数参数、返回地址、寄存器 现场保护:状态寄存器 、寄存器、返回地址...

    9.11 中断(中):进程栈与中断栈

    进程上下文

    进程上下文

    pc 指针指向 task函数体
    sp 指针指向 任务栈

    栈是C语言运行的基础

    函数调用:局部变量、函数参数、返回地址、寄存器
    现场保护:状态寄存器 、寄存器、返回地址

    SP指到哪,我就可以在哪里执行

    函数栈帧符号访问:SP/FP + 相对偏移
    SP指针的切换
    饭店与小摊儿

    进程栈

    task3执行完之后
    状态寄存器、堆栈指针、中断地址重新弹到cpu
    ![[Pasted image 20201003182707.png]]

    Linux进程的内核栈

    ![[Pasted image 20201003183300.png]]

    什么是中断栈

    中断函数调用
    中断嵌套现场保护
    ![[Pasted image 20201003183334.png]]

    Linux中断栈

    跟内核栈共享内存空间
    独立中断栈:硬中断栈、软中断栈

    栈空间大小

    任务函数体局部变量、参数
    函数调用层次
    中断嵌套层次

    展开全文
  • nuttx 中断栈配置

    2018-02-28 17:00:57
    1、某块stm32单板跑nuttx系统,出现异常挂起,分析发现中断栈已经用完,需要调整中断栈大小up_hardfault: PANIC!!! Hard fault: 40000000up_assert: Assertion failed at file:armv7-m/up_hardfault.c line: 171 ...

    1、某块stm32单板跑nuttx系统,出现异常挂起,分析发现中断栈已经用完,需要调整中断栈大小

    up_hardfault: PANIC!!! Hard fault: 40000000
    up_assert: Assertion failed at file:armv7-m/up_hardfault.c line: 171 task: hpwork
    up_dumpstate: sp:     240074c8
    up_dumpstate: IRQ stack:
    up_dumpstate:   base: 240074e8
    up_dumpstate:   size: 000002ec
    up_dumpstate:   used: 000002ec
    up_stackdump: 240074c0: 00000003 080ddec7 080ddea5 080e7119 00000010 2400742c 000000ff 00000000
    up_stackdump: 240074e0: 0000002f 080dde2b deadbeef 30000010 00000001 00000000 00000000 0000ffff
    up_dumpstate: sp:     080ea1c9
    up_dumpstate: User stack:
    up_dumpstate:   base: 30001ee8
    up_dumpstate:   size: 00000fec
    up_dumpstate:   used: 00000358
    up_registerdump: R0: 0811b2d8 00000358 000000ab 300008fc 2400747c 0811b3b7 240041e8 24005264
    up_registerdump: R8: 00000358 300007b0 30001e48 00000000 300008fc 00000000 2400747c 0811b3b7
    up_registerdump: xPSR: 2400747c BASEPRI: 00000000 CONTROL: 00000000
    up_registerdump: EXC_RETURN: 080e4253
    up_taskdump: Idle Task: PID=0 Stack Used=0 of 0
    up_taskdump: hpwork: PID=1 Stack Used=856 of 4076
    up_taskdump: lpwork: PID=2 Stack Used=632 of 4076
    up_taskdump: init: PID=3 Stack Used=2088 of 2484
    up_taskdump: mc_att_control: PID=197 Stack Used=1272 of 1676
    up_taskdump: mc_pos_control: PID=199 Stack Used=656 of 1876
    up_taskdump: gps: PID=106 Stack Used=888 of 1372
    up_taskdump: navigator: PID=203 Stack Used=888 of 1572
    up_taskdump: mavlink_if0: PID=140 Stack Used=1648 of 2420
    up_taskdump: mavlink_rcv_if0: PID=141 Stack Used=944 of 2100
    up_taskdump: commander_low_prio: PID=209 Stack Used=584 of 2996
    up_taskdump: sensors: PID=120 Stack Used=1624 of 1980
    up_taskdump: commander: PID=122 Stack Used=2832 of 3548
    up_taskdump: mavlink_if1: PID=157 Stack Used=1624 of 2388
    up_taskdump: mavlink_rcv_if1: PID=158 Stack Used=944 of 2100

    up_taskdump: ekf2: PID=191 Stack Used=4968 of 5780

    2、单板的nuttx配置文件与中断栈相关的配置,需要调整CONFIG_ARCH_INTERRUPTSTACK配置项的大小

    #
    # Interrupt options
    #
    CONFIG_ARCH_HAVE_INTERRUPTSTACK=y
    CONFIG_ARCH_INTERRUPTSTACK=750
    CONFIG_ARCH_HAVE_HIPRI_INTERRUPT=y

    CONFIG_ARCH_HIPRI_INTERRUPT=y


    3、nuttx\arch\arm\src\armv7-m\gnu\up_exception.S文件里面分配了中断栈

    /************************************************************************************
     *  Name: g_intstackalloc/g_intstackbase
     *
     * Description:
     *   Shouldn't happen
     *
     ************************************************************************************/
    #if CONFIG_ARCH_INTERRUPTSTACK > 7
    .bss
    .global g_intstackalloc
    .global g_intstackbase
    .align 8
    g_intstackalloc:
    .skip (CONFIG_ARCH_INTERRUPTSTACK & ~7)
    g_intstackbase:
    .size g_intstackalloc, .-g_intstackalloc
    #endif
          .end








    展开全文
  • Linux内核栈与中断栈补充说明

    千次阅读 2016-04-25 12:53:59
     中断栈与内核栈的话题更多地属于内核的范畴,所以在《深入Linux设备驱动程序内核机制》第5章“中断处理”当中,基本上没怎么涉及到上述内容,只是在5.4节有些许的文字讨论中断栈在中断嵌套情形下可能的溢出问题。...

    转自:http://blog.chinaunix.net/uid-20543672-id-3164573.html


     中断栈与内核栈的话题更多地属于内核的范畴,所以在《深入Linux设备驱动程序内核机制》第5章“中断处理”当中,基本上没怎么涉及到上述内容,只是在5.4节有些许的文字讨论中断栈在中断嵌套情形下可能的溢出问题。

          本贴在这个基础上对内核栈与中断栈的话题做些补充,讨论基于x86 32位系统,因为64位系统下Linux内核关于栈的支持原理上是相同的,不过也有些特性属于64位特有的,比如IST(Interrupt Stack Table),如果可能将来会在processor版块发个帖子专门讨论。

    1. x86下内核栈与中断栈是否共享的问题

    我们知道Linux系统下每个用户进程都有个task_struct对象来表示,同时在处理器层面还对应一个TSS(Task State Segment),当中断发生时,用户进程或者处于用户态(特权级3)或者处于内核态(特权级0),如果是在用户态,那么会发生栈的切换问题,也就是会切换到内核态的栈,如果是在内核态,那么就没有栈切换的问题。但是x86处理器在特权级0上只有一个ESP,这意味着中断发生后,只能使用一个栈,这个栈就是内核栈(kernel stack)。处理器的硬件逻辑会将被中断进程的下条指令(CS,EIP)以及EFLAG压入栈,当然如果发生用户态栈向内核态栈的切换,处理器还会把用户态的(SS, ESP)也压入栈,此时使用的就是内核栈。这个行为属于处理器的硬件逻辑范畴,不是系统软件的行为。

    至于x86下内核栈与中断栈是否共享的问题,其实是个内核设计的问题,换言之,中断栈可与内核栈共享,也可重新分配一个独立的中断栈。2.4的内核版本似乎采用中断栈与内核栈共享的设计,因为这种设计的好处是代码相对简单,如前所述,直接使用ESP0就可以了,但是负面因素是中断栈如果发生嵌套,可能破坏内核栈的一些数据,因为毕竟共享,所以栈空间有时候难免会捉襟见肘。所以在2.5内核版本开发中,来自IBM的一位大侠曾提交过一个补丁,试图在中断发生时,从内核栈switch到一个独立的中断栈中,后来也不知道被内核社区采纳了没有,总之我现在在3.2的内核源码中没有看到那位仁兄的补丁代码了,当然也可能是那个补丁已经长成现在的代码样子了。

    现在的Linux内核中采用的是内核栈与中断栈分离的设计,下面我们从源码层面来看一看这种分离是如何完成的。

    内核栈与中断栈分离的核心代码发生在do_IRQ() --> handle_irq() --> execute_on_irq_stack()
    最后一个函数字面上的意思大约是在中断栈中执行中断处理例程,也就是说中断的处理函数会在独立于被中断进程的上下文中执行。execute_on_irq_stack的函数实现为:

    点击(此处)折叠或打开

    1. static inline int
    2. execute_on_irq_stack(int overflow, struct irq_desc *desc, int irq)
    3. {
    4.         union irq_ctx *curctx, *irqctx;
    5.         u32 *isp, arg1, arg2;

    6.         curctx = (union irq_ctx *) current_thread_info();
    7.         irqctx = __this_cpu_read(hardirq_ctx);

    8.         /*
    9.          * this is where we switch to the IRQ stack. However, if we are
    10.          * already using the IRQ stack (because we interrupted a hardirq
    11.          * handler) we can'do that and just have to keep using the
    12.          * current stack (which is the irq stack already after all)
    13.          */
    14.         if (unlikely(curctx == irqctx))
    15.                 return 0;

    16.         /* build the stack frame on the IRQ stack */
    17.         isp = (u32 *) ((char *)irqctx + sizeof(*irqctx));
    18.         irqctx->tinfo.task = curctx->tinfo.task;
    19.         irqctx->tinfo.previous_esp = current_stack_pointer;

    20.         /*
    21.          * Copy the softirq bits in preempt_count so that the
    22.          * softirq checks work in the hardirq context.
    23.          */
    24.         irqctx->tinfo.preempt_count =
    25.                 (irqctx->tinfo.preempt_count & ~SOFTIRQ_MASK) |
    26.                 (curctx->tinfo.preempt_count & SOFTIRQ_MASK);

    27.         if (unlikely(overflow))
    28.                 call_on_stack(print_stack_overflow, isp);

    29.         asm volatile("xchgl %%ebx,%%esp \n"
    30.                      "call *%%edi \n"
    31.                      "movl %%ebx,%%esp \n"
    32.                      : "=a" (arg1), "=d" (arg2), "=b" (isp)
    33.                      : "0" (irq), "1" (desc), "2" (isp),
    34.                         "D" (desc->handle_irq)
    35.                      : "memory", "cc", "ecx");
    36.         return 1;
    37. }
    代码中的curctx=(union irq_ctx *) current_thread_info()用来获得当前被中断进程的上下文,irqctx = __this_cpu_read(hardirq_ctx)用来获得hardirq的上下文,其实就是获得独立的中断栈起始地址。中断栈的大小与layout与内核栈是完全一样的。接下来isp指向中断栈栈顶,最后的堆栈切换发生在那段汇编代码中:当前进程的内核栈ESP指针保存在EBX中,而中断栈的isp则赋值给了ESP,这样接下来的代码就将使用中断栈了。call语句负责调用desc->handle_irq()函数,这里会进行中断处理,设备驱动程序注册的中断处理函数会被调用到。当中断处理例程结束返回时,ESP将重新指向被中断进程的内核栈。(此处我们应该注意到内核栈中还保留着中断发生时处理器硬件逻辑所压入的CS, EIP等寄存器,所以在内核栈中做中断返回是完全正确的)。


    2. 中断栈的分配

    独立的中断栈所在内存空间的分配发生在arch/x86/kernel/irq_32.c的irq_ctx_init函数中(如果是多处理器系统,那么每个处理器都会有一个独立的中断栈),函数使用__alloc_pages在低端内存区分配2个物理页面(2的THREAD_ORDER次方),也就是8KB大小的空间。有趣的是,这个函数还会为softirq分配一个同样大小的独立堆栈,如此说来,softirq将不会在hardirq的中断栈上执行,而是在自己的上下文中执行。

    总结一下,系统中每个进程都会拥有属于自己的内核栈,而系统中每个CPU都将为中断处理准备了两个独立的中断栈,分别是hardirq栈和softirq栈。草图如下:


    关于在中断处理函数中涉及到的阻塞问题,我个人的观点是:现实中绝对不要这么干,其中的原因就不多说了。从内核理论实现的角度,调度其他进程是可行的。

    展开全文
  • 说一下上文中最开始提到的“某个问题”:如果一台主机网卡比较多,然后每个网卡分队列又比较多,总之结果...一旦中断栈溢出,那么将会导致怎样的结果,这曾在之前的文章里隐含的提到过,这里再重新整理一遍。在继...

    说一下上文中最开始提到的“某个问题”:如果一台主机网卡比较多,然后每个网卡分队列又比较多,总之结果就是系统里的网卡设备的中断号比较多(关于超过256个中断数的情况,请见参考1,2,3),一旦所有这些中断都绑定到同一个CPU,那么如果网卡收到数据包进而触发中断,而众多硬中断一嵌套就非常容易出现中断栈溢出。一旦中断栈溢出,那么将会导致怎样的结果,这曾在之前的文章里隐含的提到过,这里再重新整理一遍。

    在继续下面的描述之前,先看两个知识点:

    1,Linux 2.4.x的中断栈:

    a),由硬中断/软中断共同使用同一个中断栈

    b),中断栈与内核栈共享一个栈

    c),中断执行的时候使用的栈就是当前进程的内核栈

    2,Linux 2.6.x的中断栈:

    a),硬中断与软中断分离使用不同的中断栈

    b),中断栈与内核栈分离

    c),X86_64 double fault、NMI还可以有额外的栈(64bit特性:IST(Interrupt Stack Table))

    可以看到,对于Linux 2.4.x内核而言,因为中断处理函数使用内核栈作为中断栈,所以导致更加容易发生内核栈溢出(因内核函数本身用栈过多导致溢出,或内核函数本身还未导致内核栈溢出,但此时来了一个中断,因中断函数使用栈而导致溢出,即中断函数成了压死骆驼的最后一根稻草),而内核栈溢出的直接结果就是踩坏task结构体,从而无法正常执行对应的task进程而出现oops宕机。

    由于“中断执行的时候使用的栈就是当前进程的内核栈”,所以如果是执行到中断函数后才溢出,那么导致oops里提示的进程信息可能每次都不一样,因此如果出现这种情况,需要考虑是中断函数导致内核栈溢出,否则需怀疑普通的内核函数导致栈溢出即可。

    对于Linux 2.6.x内核而言,因为其中断/内核栈分离、软/硬中断栈分离,即每个CPU私有两个栈(见下面注释)分别处理软中断和硬中断,因此出现内核栈溢出,特别是中断栈溢出的概率大大降低。

    注释:这个说法来之书本《Understanding.the.Linux.Kernel.3rd.Edition》4.6.1.4. Multiple Kernel Mode stacks,而这本书针对的内核版本是2.6.11,且主要是指32位架构,所以与现在的新版内核源码有些许出入(比如现在情况的栈大小可能是占用2页),但这些细微改变与本文的具体问题相关不大(无非是溢出的难易程度问题),这里不再深入研究,具体情况请参考源代码自行斟酌。

    The hard IRQ stack is used when handling interrupts. There is one hard IRQ stack for each CPU in the system, and each stack is contained in a single page frame.The soft IRQ stack is used when handling deferrable functions (softirqs or tasklets; see the later section “Softirqs and Tasklets”). There is one soft IRQ stack for each CPU in the system, and each stack is contained in a single page frame.

    回到本文的主题,在之前的文章里提到过,即如果中断/异常处理函数本身在处理的过程中出现异常,那么就有可能发生double fault,比如中断栈溢出。中断栈溢出导致的最终结果有两种情况,这由所使用的具体Linux内核版本来决定,更具体点说是由double fault异常的栈是否单独来决定(见参考1)。

    1,double fault的栈被单独出来

    这意味着double fault的处理函数还能正常执行,因此打印oops,宕机。

    2,double fault的栈没有被单独出来

    这意味着double fault的处理函数也无法正常执行,进而触发triple fault,机器直接重启。

    对于86-64架构下的Linux 2.6.x内核,因为IST(Interrupt Stack Table)的帮助,所以中断栈溢出导致的最终结果就是打印oops,宕机。

    下面来看内核源码文档kernel-stacks,

    1,每一个活动线程都有一个内核栈,大小为2页。

    2,每一个cpu有一些专门的栈,只有当cpu执行在内核态时,这些栈才有用;一旦cpu回退到用户态,这些特定栈就不再包含任何有用数据。

    3,主要的特定栈有:

    a,中断栈:外部硬件中断的处理函数使用,单独的栈可以提供给中断处理函数更多的栈空间。

    这里还提到,在2.6.x-i386下,如果设置内核栈只有4K,即CONFIG_4KSTACKS,那么中断栈也是单独开的。备注:这个已有修改,2010-06-29 x86: Always use irq stacks,即不管设置的内核栈是否只有4K,中断栈都是独立的了。

    另外,这里有个说法与前面的引用有点出入:

    The interrupt stack is also used when processing a softirq.

    即软中断和硬中断一样,也是使用这个中断栈。

    b,x86_64所特有的(也就是i386没有,即同时2.6.30.8内核,32位的Linux就不具备下面所说的这个特性),为double fault或NMI单独准备的栈,这个特性被称为Interrupt Stack Table(IST)。每个cpu最多支持7个IST。关于IST的具体原理与实现暂且不说,直接来看当前已经分配的IST独立栈:

    STACKFAULT_STACK. EXCEPTION_STKSZ (PAGE_SIZE)

    12号中断Stack Fault Exception (#SS)使用

    DOUBLEFAULT_STACK. EXCEPTION_STKSZ (PAGE_SIZE)

    8号中断Double Fault Exception (#DF)使用

    NMI_STACK. EXCEPTION_STKSZ (PAGE_SIZE)

    2号中断non-maskable interrupts (NMI)使用

    DEBUG_STACK. DEBUG_STKSZ

    1号中断硬件调试和3号中断软件调试使用

    MCE_STACK. EXCEPTION_STKSZ (PAGE_SIZE)

    18号中断Machine Check Exception (#MC)使用

    正因为double fault异常处理函数所使用的栈被单独了出来,所以在出现中断栈溢出时,double fault异常的处理函数还能正常执行,顺利打印出oops信息。

    最后的最后,有补丁移除IST功能(貌似是因为如果没有IST功能,那么kvm可以得到更好的优化,具体请见参考5),但通过对比补丁修改与实际源码(2.6.30.8以及3.6.11)来看,这个补丁并没有合入mainline主线。

    参考资料:

    6,Interrupt Descriptor Table

    http://wiki.osdev.org/IDT

    展开全文
  • Linux内核中的中断栈与内核栈的补充说明 (2012-02-20 20:17) 标签: Linux内核栈 中断栈 Linux中断处理 设备驱动  分类: Linux系统内核 中断栈与内核栈的话题更多地属于内核的范畴,所以在《深入...
  • 原文地址:Linux内核中的...中断栈与内核栈的话题更多地属于内核的范畴,所以在《深入Linux设备驱动程序内核机制》第5章“中断处理”当中,基本上没怎么涉及到上述内容,只是在5.4节有些许的文字讨论中断栈在中断...
  • 中断栈与内核栈的话题更多地属于内核的范畴,所以在《深入Linux设备驱动程序内核机制》第5章“中断处理”当中,基本上没怎么涉及到上述内容,只是在5.4节有些许的文字讨论中断栈在中断嵌套情形下可能的溢出问题。...
  • Linux内核栈和中断栈

    千次阅读 2019-08-09 11:47:21
    内核 #define MIN_THREAD_SHIFT (14 + KASAN_THREAD_SHIFT) #define THREAD_SIZE (UL(1) << THREAD_SHIFT) union thread_union { #ifndef CONFIG_THREAD_INFO_IN_TASK struct thread_info ...
  • 问题1:不同线程/进程拥有着不同的,那系统所有的中断用的是同一个吗,那意味着不支持中断嵌套,如果中断可以被打断,那么不同中断必须使用不同,否则如何管控,怎么理解这个问题? M3的双堆栈(PSP/MSP), ...
  • 是什么?有什么作用?首先, (stack) 是一种串列形式的 数据结构。这种数据结构的特点是 后入先出 (LIFO, Last In First Out),数据只能在串列的一端 (称为:栈顶 top) 进行 推入 (push) 和 弹出 (pop) 操作。...
  • 一、是什么?有什么作用? 首先, (stack) 是一种串列形式的 数据结构。这种数据结构的特点是 后入先出 (LIFO, Last In First Out),数据只能在串列的一端 (称为:栈顶 top) 进行 推入 (push) 和 弹出 (pop) ...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 2,393
精华内容 957
关键字:

中断栈