Linux kernel Linux内核ARM异常堆栈初始化

Linux kernel Linux内核ARM异常堆栈初始化,linux-kernel,stack,arm,interrupt,irq,Linux Kernel,Stack,Arm,Interrupt,Irq,我正在飞思卡尔I.MX6(ARMCortex-A9)上使用Linux内核3.0.35。在运行内核OOPS之后,我试图理解异常堆栈初始化。以下是我迄今为止发现的情况 在arch/arm/kernel/setup.c中的cpu_init()中,我看到异常堆栈正在初始化: struct stack { u32 irq[3]; u32 abt[3]; u32 und[3]; } ____cacheline_aligned; static struct stack stacks[

我正在飞思卡尔I.MX6(ARMCortex-A9)上使用Linux内核3.0.35。在运行内核OOPS之后,我试图理解异常堆栈初始化。以下是我迄今为止发现的情况

在arch/arm/kernel/setup.c中的cpu_init()中,我看到异常堆栈正在初始化:

struct stack {
    u32 irq[3];
    u32 abt[3];
    u32 und[3];
} ____cacheline_aligned;

static struct stack stacks[NR_CPUS];

void cpu_init(void)
{
    struct stack *stk = &stacks[cpu];

    ...<snip>

    /*
     * setup stacks for re-entrant exception handlers
     */
    __asm__ (
     "msr   cpsr_c, %1\n\t"
    "add    r14, %0, %2\n\t"
    "mov    sp, r14\n\t"
    "msr    cpsr_c, %3\n\t"
    "add    r14, %0, %4\n\t"
    "mov    sp, r14\n\t"
    "msr    cpsr_c, %5\n\t"
    "add    r14, %0, %6\n\t"
    "mov    sp, r14\n\t"
    "msr    cpsr_c, %7"
        :
        : "r" (stk),
          PLC (PSR_F_BIT | PSR_I_BIT | IRQ_MODE),
          "I" (offsetof(struct stack, irq[0])),
          PLC (PSR_F_BIT | PSR_I_BIT | ABT_MODE),
          "I" (offsetof(struct stack, abt[0])),
          PLC (PSR_F_BIT | PSR_I_BIT | UND_MODE),
          "I" (offsetof(struct stack, und[0])),
          PLC (PSR_F_BIT | PSR_I_BIT | SVC_MODE)
        : "r14");
这也是我从KGDB中看到反汇编代码的方式:

Dump of assembler code for function __irq_svc:
   0xc01402c0 <+0>:  44 d0 4d e2    sub sp, sp, #68 ; 0x44
   0xc01402c4 <+4>:  04 00 1d e3    tst sp, #4
   0xc01402c8 <+8>:  04 d0 4d 02    subeq   sp, sp, #4
   0xc01402cc <+12>:     fe 1f 8d e8    stm sp, {r1, r2, r3, r4, r5, r6, r7, r8, r9, r10, r11, r12}
   0xc01402d0 <+16>:     0e 00 90 e8    ldm r0, {r1, r2, r3}
   0xc01402d4 <+20>:     30 50 8d e2    add r5, sp, #48 ; 0x30
   0xc01402d8 <+24>:     00 40 e0 e3    mvn r4, #0
   0xc01402dc <+28>:     44 00 8d e2    add r0, sp, #68 ; 0x44
   0xc01402e0 <+32>:     04 00 80 02    addeq   r0, r0, #4
   0xc01402e4 <+36>:     04 10 2d e5    push    {r1}        ; (str r1, [sp, #-4]!)
   0xc01402e8 <+40>:     0e 10 a0 e1    mov r1, lr
   0xc01402ec <+44>:     1f 00 85 e8    stm r5, {r0, r1, r2, r3, r4}
   0xc01402f0 <+48>:     ad 96 a0 e1    lsr r9, sp, #13
   0xc01402f4 <+52>:     89 96 a0 e1    lsl r9, r9, #13
   0xc01402f8 <+56>:     04 80 99 e5    ldr r8, [r9, #4]
   0xc01402fc <+60>:     01 70 88 e2    add r7, r8, #1
   0xc0140300 <+64>:     04 70 89 e5    str r7, [r9, #4]
   0xc0140304 <+68>:     54 50 9f e5    ldr r5, [pc, #84]   ; 0xc0140360
   0xc0140308 <+72>:     00 50 95 e5    ldr r5, [r5]
   0xc014030c <+76>:     0c 60 95 e5    ldr r6, [r5, #12]
   0xc0140310 <+80>:     4c e0 9f e5    ldr lr, [pc, #76]   ; 0xc0140364
   0xc0140314 <+84>:     07 0b c6 e3    bic r0, r6, #7168   ; 0x1c00
   0xc0140318 <+88>:     1d 00 50 e3    cmp r0, #29
   0xc014031c <+92>:     00 00 50 31    cmpcc   r0, r0
   0xc0140320 <+96>:     0e 00 50 11    cmpne   r0, lr
   0xc0140324 <+100>:    00 00 50 21    cmpcs   r0, r0
   0xc0140328 <+104>:    0d 10 a0 11    movne   r1, sp
   0xc014032c <+108>:    28 e0 4f 12    subne   lr, pc, #40 ; 0x28
   0xc0140330 <+112>:    32 eb ff 1a    bne 0xc013b000 <asm_do_IRQ>
   0xc0140334 <+116>:    04 80 89 e5    str r8, [r9, #4]
   0xc0140338 <+120>:    00 00 99 e5    ldr r0, [r9]
   0xc014033c <+124>:    00 00 38 e3    teq r8, #0
   0xc0140340 <+128>:    00 00 a0 13    movne   r0, #0
   0xc0140344 <+132>:    02 00 10 e3    tst r0, #2
   0xc0140348 <+136>:    06 00 00 1b    blne    0xc0140368 <svc_preempt>
   0xc014034c <+140>:    40 40 9d e5    ldr r4, [sp, #64]   ; 0x40
   0xc0140350 <+144>:    04 f0 6f e1    msr SPSR_fsxc, r4
   0xc0140354 <+148>:    1f f0 7f f5    clrex
   0xc0140358 <+152>:    ff ff dd e8    ldm sp, {r0, r1, r2, r3, r4, r5, r6, r7, r8, r9, r10, r11, r12, sp, lr, pc}^
End of assembler dump.
函数irq svc的汇编程序代码转储: 0xc01402c0:44 d0 4d e2子sp,sp,#68;0x44 0xc01402c4:04 00 1d e3 tst sp#4 0xc01402c8:04 d0 4d 02子均衡器sp,sp,#4 0xc01402cc:fe 1f 8d e8 stm sp,{r1,r2,r3,r4,r5,r6,r7,r8,r9,r10,r11,r12} 0xc01402d0:0e 00 90 e8 ldm r0,{r1,r2,r3} 0xc01402d4:30 50 8d e2添加r5,sp,#48;0x30 0xc01402d8:00 40 e0 e3 mvn r4,#0 0xc01402dc:44 00 8d e2添加r0,sp,#68;0x44 0xc01402e0:04 00 80 02加法器r0,r0,#4 0xc01402e4:04 10 2d e5推送{r1};(str r1,[sp,#-4]!) 0xc01402e8:0e 10 a0 e1 mov r1,lr 0xc01402ec:1f 00 85 e8 stm r5,{r0,r1,r2,r3,r4} 0xc01402f0:ad 96 a0 e1 lsr r9,sp,#13 0xc01402f4:89 96 a0 e1 lsl r9,r9,#13 0xc01402f8:04 80 99 e5 ldr r8[r9,#4] 0xc01402fc:01 70 88 e2添加r7、r8、#1 0xc0140300:047089E5STRR7[r9,#4] 0xc0140304:54 50 9f e5 ldr r5[pc,#84];0xc0140360 0xc0140308:00 50 95 e5 ldr r5[r5] 0xc014030c:0c 60 95 e5 ldr r6[r5,#12] 0xc0140310:4c e0 9f e5 ldr lr,[pc,#76];0xc0140364 0xc0140314:07 0b c6 e3 bic r0,r6,#7168;0x1c00 0xc0140318:1d 00 50 e3 cmp r0,#29 0xc014031c:00 00 50 31 cmpcc r0,r0 0xc0140320:0e 00 50 11 cmpne r0,左后 0xc0140324:00 00 50 21 cmpcs r0,r0 0xc0140328:0d 10 a0 11移动r1,sp 0xc014032c:28 e0 4f 12子网lr,pc,#40;0x28 0xc0140330:32 eb ff 1a bne 0xc013b000 0xc0140334:04 80 89 e5 str r8[r9,#4] 0xc0140338:00 00 99 e5 ldr r0,[r9] 0xc014033c:00 00 38 e3 teq r8,#0 0xc0140340:00 00 a0 13移动r0,#0 0xc0140344:02 00 10 e3 tst r0,#2 0xc0140348:06 00 00 1b blne 0xc0140368 0xc014034c:40 9d e5 ldr r4[sp,#64];0x40 0xc0140350:04 f0 6f e1 msr SPSR_fsxc,r4 0xc0140354:1f f0 7f f5 clrex 0xc0140358:ff ff dd e8 ldm sp,{r0、r1、r2、r3、r4、r5、r6、r7、r8、r9、r10、r11、r12、sp、lr、pc}^ 汇编程序转储结束。
在异常情况下,SP是存储的R13。如果我跟随正确,则该堆栈上没有空间容纳此帧。那意味着我一定错过了什么。是否存在初始化异常堆栈的其他位置?

tl;dr-我们将模式切换到supervisor并使用该堆栈

您缺少一个关键点,即通过向量表将控制权交给CPU,并且切换模式。请参阅:。是在主向量表中的
b
ranch之后最初发送控制的代码。
vector_stub
宏保存三项;已纠正的异常模式的
lr
r0
spsr
(如您所述)

您忽略的一点是,在此之后,所有异常都切换到
SVC\u模式
,因此使用
current
tasks堆栈,该堆栈也具有
thread\u info
结构。在ARM系统级汇编程序中,模式切换是一个很难实现的概念。以前设置的寄存器现在完全不同了。注意
msr
cps
类型说明。事情可以在它们之后完全改变;这让我困惑了几十次

spsr
用作
vector\u stub
表的索引,该表通常会跳到
\uuuirq\u svc
\uirq\u usr
。只需向下滚动查看已找到的入口臂的底部


相关:

在此版本中,
mov r0,sp
是在
movs pc,lr
之前完成的。第一个命令为
\uuu irq\u svc
提供一个指向已保存三个单词的指针。第二种改变模式。宏
svc\u条目
使用
r0
重新加载值。由于中断被禁用,这个静态存储只使用一次。啊,以防有人不知道。对于每种模式,ARM具有不同的堆栈。因此
sp_irq
sp_abt
sp_und
sp_svc
都是指向不同堆栈的不同寄存器。Linux只使用
sp_svc
,除了这个问题所涉及的短时间之外。
Dump of assembler code for function __irq_svc:
   0xc01402c0 <+0>:  44 d0 4d e2    sub sp, sp, #68 ; 0x44
   0xc01402c4 <+4>:  04 00 1d e3    tst sp, #4
   0xc01402c8 <+8>:  04 d0 4d 02    subeq   sp, sp, #4
   0xc01402cc <+12>:     fe 1f 8d e8    stm sp, {r1, r2, r3, r4, r5, r6, r7, r8, r9, r10, r11, r12}
   0xc01402d0 <+16>:     0e 00 90 e8    ldm r0, {r1, r2, r3}
   0xc01402d4 <+20>:     30 50 8d e2    add r5, sp, #48 ; 0x30
   0xc01402d8 <+24>:     00 40 e0 e3    mvn r4, #0
   0xc01402dc <+28>:     44 00 8d e2    add r0, sp, #68 ; 0x44
   0xc01402e0 <+32>:     04 00 80 02    addeq   r0, r0, #4
   0xc01402e4 <+36>:     04 10 2d e5    push    {r1}        ; (str r1, [sp, #-4]!)
   0xc01402e8 <+40>:     0e 10 a0 e1    mov r1, lr
   0xc01402ec <+44>:     1f 00 85 e8    stm r5, {r0, r1, r2, r3, r4}
   0xc01402f0 <+48>:     ad 96 a0 e1    lsr r9, sp, #13
   0xc01402f4 <+52>:     89 96 a0 e1    lsl r9, r9, #13
   0xc01402f8 <+56>:     04 80 99 e5    ldr r8, [r9, #4]
   0xc01402fc <+60>:     01 70 88 e2    add r7, r8, #1
   0xc0140300 <+64>:     04 70 89 e5    str r7, [r9, #4]
   0xc0140304 <+68>:     54 50 9f e5    ldr r5, [pc, #84]   ; 0xc0140360
   0xc0140308 <+72>:     00 50 95 e5    ldr r5, [r5]
   0xc014030c <+76>:     0c 60 95 e5    ldr r6, [r5, #12]
   0xc0140310 <+80>:     4c e0 9f e5    ldr lr, [pc, #76]   ; 0xc0140364
   0xc0140314 <+84>:     07 0b c6 e3    bic r0, r6, #7168   ; 0x1c00
   0xc0140318 <+88>:     1d 00 50 e3    cmp r0, #29
   0xc014031c <+92>:     00 00 50 31    cmpcc   r0, r0
   0xc0140320 <+96>:     0e 00 50 11    cmpne   r0, lr
   0xc0140324 <+100>:    00 00 50 21    cmpcs   r0, r0
   0xc0140328 <+104>:    0d 10 a0 11    movne   r1, sp
   0xc014032c <+108>:    28 e0 4f 12    subne   lr, pc, #40 ; 0x28
   0xc0140330 <+112>:    32 eb ff 1a    bne 0xc013b000 <asm_do_IRQ>
   0xc0140334 <+116>:    04 80 89 e5    str r8, [r9, #4]
   0xc0140338 <+120>:    00 00 99 e5    ldr r0, [r9]
   0xc014033c <+124>:    00 00 38 e3    teq r8, #0
   0xc0140340 <+128>:    00 00 a0 13    movne   r0, #0
   0xc0140344 <+132>:    02 00 10 e3    tst r0, #2
   0xc0140348 <+136>:    06 00 00 1b    blne    0xc0140368 <svc_preempt>
   0xc014034c <+140>:    40 40 9d e5    ldr r4, [sp, #64]   ; 0x40
   0xc0140350 <+144>:    04 f0 6f e1    msr SPSR_fsxc, r4
   0xc0140354 <+148>:    1f f0 7f f5    clrex
   0xc0140358 <+152>:    ff ff dd e8    ldm sp, {r0, r1, r2, r3, r4, r5, r6, r7, r8, r9, r10, r11, r12, sp, lr, pc}^
End of assembler dump.