加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 综合聚焦 > 服务器 > Linux > 正文

linux-kernel – Linux内核ARM异常堆栈init

发布时间:2020-12-13 23:10:41 所属栏目:Linux 来源:网络整理
导读:我在飞思卡尔i.MX6(ARM Cortex-A9)上使用 Linux内核3.0.35.在运行内核OOPS后,我试图理解异常堆栈初始化.这是我到目前为止所发现的. 在arch / arm / kernel / setup.c中的cpu_init()中,我看到异常堆栈被初始化: struct stack { u32 irq[3]; u32 abt[3]; u32
我在飞思卡尔i.MX6(ARM Cortex-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,%1nt"
    "add    r14,%0,%2nt"
    "mov    sp,r14nt"
    "msr    cpsr_c,%3nt"
    "add    r14,%4nt"
    "mov    sp,%5nt"
    "add    r14,%6nt"
    "mov    sp,%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),abt[0])),PLC (PSR_F_BIT | PSR_I_BIT | UND_MODE),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,它创建一个堆栈帧

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

这也是我如何看到KGDB的反汇编代码:

Dump of assembler code for function __irq_svc:
   0xc01402c0 <+0>:  44 d0 4d e2    sub sp,#68 ; 0x44
   0xc01402c4 <+4>:  04 00 1d e3    tst sp,#4
   0xc01402c8 <+8>:  04 d0 4d 02    subeq   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,r3}
   0xc01402d4 <+20>:     30 50 8d e2    add r5,#48 ; 0x30
   0xc01402d8 <+24>:     00 40 e0 e3    mvn r4,#0
   0xc01402dc <+28>:     44 00 8d e2    add r0,#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,r4}
   0xc01402f0 <+48>:     ad 96 a0 e1    lsr r9,#13
   0xc01402f4 <+52>:     89 96 a0 e1    lsl r9,#13
   0xc01402f8 <+56>:     04 80 99 e5    ldr r8,[r9,#4]
   0xc01402fc <+60>:     01 70 88 e2    add r7,#1
   0xc0140300 <+64>:     04 70 89 e5    str r7,#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,#76]   ; 0xc0140364
   0xc0140314 <+84>:     07 0b c6 e3    bic r0,#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,#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,#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,r12,lr,pc}^
End of assembler dump.

在例外情况下,SP是存储的R13.如果我正确地关注,那个堆栈上没有空间.这意味着我一定错过了什么.是否有其他地方初始化异常堆栈?

解决方法

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

您缺少通过向量表将控制权交给CPU并切换模式的关键点.请参阅:entry-armv.S and __vectors_start.vector stubs是最初在主向量表中的分支之后发送控制的代码. vector_stub宏保存了三个项目;修正后的lr,r0和例外模式的spsr(正如你所说).

您错过的一点是,在此之后所有异常都切换到SVC_MODE,因此使用当前任务堆栈,它也具有thread_info结构.模式切换是ARM系统级汇编器的一个难点概念.以前设定的登记册现在完全不同.注意msr和cps类型指令.事情可以在他们之后完全改变;我已经被这几十次困惑了.

spsr用作vector_stub表的索引,该表通常会跳转到__irq_svc或__irq_usr.只需向下滚动即可查看已找到的入口臂底部.

相关:Physical address of ARM-Linux vector table

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读