Linux内核ARM异常栈init [英] Linux kernel ARM exception stack init

查看:27
本文介绍了Linux内核ARM异常栈init的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在 Freescale i.MX6 (ARM Cortex-A9) 上使用 Linux 内核 3.0.35.在遇到内核 OOPS 后,我试图了解异常堆栈初始化.以下是我目前所发现的.

I am using Linux kernel 3.0.35 on Freescale i.MX6 (ARM Cortex-A9). After running into a kernel OOPS I tried to understand the exception stack initialization. Here is what I have uncovered so far.

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

In cpu_init() in arch/arm/kernel/setup.c, I see the exception stack getting initialized:

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");

我看到每个堆栈只有三个字的空间.这就是 arch/arm/kernel/entry-armv.S 中的宏 vector_stub 使用它的方式.它将R0、LR(父PC)和SPSR(父CPSR)保存在这三个词中.然后它跳转到 __irq_svc.从一个宏 svc_entry 开始,它创建了一个堆栈帧

I see that each stack has room for only three words. That is how the macro vector_stub in arch/arm/kernel/entry-armv.S uses it. It saves R0, LR (parent PC) and SPSR (parent CPSR) into those three words. Then it jumps to __irq_svc. That starts with a macro svc_entry which creates a stack frame

    .macro  svc_entry, stack_hole=0
 UNWIND(.fnstart        )
 UNWIND(.save {r0 - pc}     )
    sub sp, sp, #(S_FRAME_SIZE + \stack_hole - 4)

这也是我从 KGDB 中看到的反汇编代码的方式:

That is also how I see the disassembled code from 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.

在例外情况下,SP 是存入的 R13.如果我正确地跟随,则该堆栈上的此框架没有空间.这意味着我一定错过了一些东西.是否有其他地方初始化异常堆栈?

During an exception, SP is the banked R13. If I am following correctly, there is no room for this frame on that stack. That means I must have missed something. Is there some other place where the exception stacks are initialized?

推荐答案

tl;dr - 我们将模式切换为主管并使用该堆栈.

tl;dr - We switch modes to supervisor and use that stack.

您错过了通过向量表切换模式将控制权交给 CPU 的关键点.参见:entry-armv.S 和 __vectors_start.vector stubs 是在主要的 b 牧场之后最初发送控制的代码矢量表.vector_stub 宏保存三项;异常模式的更正 lrr0spsr(如您所见).

You are missing the key point of where control is handed to the CPU via the vector table and the mode is switched. See: entry-armv.S and __vectors_start. The vector stubs is the code where control is initially sent after the branch in the main vector table. The vector_stub macro saves three items; a corrected lr, r0 and the spsr of the excepted mode (as you noted).

你错过的一点是,在此之后所有异常都切换到 SVC_MODE 并因此使用 current 任务堆栈,它也有 thread_info 结构.模式切换在 ARM 系统级汇编器中是一个很难理解的概念.以前设置的寄存器现在完全不同.注意msrcps 类型说明.在他们之后,事情可能会完全改变;我已经被这个困惑了几十次了.

The point you miss is, after this all exceptions switch to SVC_MODE and as such use the current tasks stack, which also has the thread_info structure. mode switching is a tough concept to get in ARM system level assembler. Registers that were previously set are now completely different. Pay attention to msr and cps type instructions. Things can change completely after them; I have been confused by this dozens of times.

spsr 用作vector_stub 表的索引,该表通常跳转到__irq_svc__irq_usr.只需向下滚动即可查看您已找到的 entry-arm.S 底部.

The spsr is used as an index into a vector_stub table, which will normally jump to either __irq_svc or __irq_usr. Just scroll down to look at the bottom of the entry-arm.S which you already found.

相关:ARM的物理地址-Linux向量表

这篇关于Linux内核ARM异常栈init的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆