linux-kernel – Linux内核ARM异常堆栈init
我在飞思卡尔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 您错过的一点是,在此之后所有异常都切换到SVC_MODE,因此使用当前任务堆栈,它也具有thread_info结构.模式切换是ARM系统级汇编器的一个难点概念.以前设定的登记册现在完全不同.注意msr和cps类型指令.事情可以在他们之后完全改变;我已经被这几十次困惑了. spsr用作vector_stub表的索引,该表通常会跳转到__irq_svc或__irq_usr.只需向下滚动即可查看已找到的入口臂底部. 相关:Physical address of ARM-Linux vector table (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |