完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
Linux Version : 2.6.29
1. start_kernel-->setup_arch-->early_trap_init 1: memcpy((void *)vectors, __vectors_start, __vectors_end - __vectors_start); 2: memcpy((void *)vectors + 0x200, __stubs_start, __stubs_end - __stubs_start); 3: memcpy((void *)vectors + 0x1000 - kuser_sz, __kuser_helper_start, kuser_sz); 对于第一行: __vectors_start 和 __vectors_end 定义在 arch/arm/kernel/entry-armv.S , 它们之间保存了中断向量表。 1: .globl __vectors_start 2: __vectors_start: 3: swi SYS_ERROR0 4: b vector_und + stubs_offset 5: ldr pc, .LCvswi + stubs_offset 6: b vector_pabt + stubs_offset 7: b vector_dabt + stubs_offset 8: b vector_addrexcptn + stubs_offset 9: b vector_irq + stubs_offset 10: b vector_fiq + stubs_offset 11: 12: .globl __vectors_end 13: __vectors_end: vectors 的地址为CONFIG_VECTORS_BASE , 在.config中定义为0xffff0000 所以 第1行就是把中断向量表拷贝到0xffff0000 对于第二行: vector_stub是一个带参数的宏,第一个是name,第二个是arm excepiton mode,第三个是为了得到返回地址,lr需要减去的偏移 1: .macro vector_stub, name, mode, correction=0 2: .align 5 3: 4: vector_/name: 5: .if /correction 6: sub lr, lr, #/correction @得到正确的返回地址 7: .endif 8: 9: @ 10: @ Save r0, lr_(parent PC) and spsr_ 11: @ (parent CPSR) 12: @ 13: stmia sp, {r0, lr} @ save r0, lr 14: mrs lr, spsr 15: str lr, [sp, #8] @ save spsr 16: 17: @ 18: @ Prepare for SVC32 mode. IRQs remain disabled. 19: @ 20: mrs r0, cpsr 21: eor r0, r0, #(/mode ^ SVC_MODE) @把cpsr内容与(mode^SVC_mode)异或,即r0里为SVC_MODE 22: msr spsr_cxsf, r0 @把r0的值写入整个spsr寄存器(cxsf表示要往哪个字节写入) 23: 24: @ 25: @ the branch table must immediately follow this code 26: @ 27: and lr, lr, #0x0f @lr为spsr_的值,此语句取到进入异常前的mode 28: mov r0, sp @ 29: ldr lr, [pc, lr, lsl #2] @lr=pc+mode*4,其中pc为紧接着30的指令,即vector_stub后的第一条指令 30: movs pc, lr @ movs会把spsr的值赋给cpsr,所以branch to handler in SVC mode 31: ENDPROC(vector_/name) 32: .endm 再来看下vector 跳转表 1: .long __irq_usr @ 0 (USR_26 / USR_32) 2: .long __irq_invalid @ 1 (FIQ_26 / FIQ_32) 3: .long __irq_invalid @ 2 (IRQ_26 / IRQ_32) 4: .long __irq_svc @ 3 (SVC_26 / SVC_32) 5: .long __irq_invalid @ 4 6: .long __irq_invalid @ 5 7: .long __irq_invalid @ 6 8: .long __irq_invalid @ 7 9: .long __irq_invalid @ 8 10: .long __irq_invalid @ 9 11: .long __irq_invalid @ a 12: .long __irq_invalid @ b 13: .long __irq_invalid @ c 14: .long __irq_invalid @ d 15: .long __irq_invalid @ e 16: .long __irq_invalid @ f 这里只有usr 和svc 有入口,而其他都是invalid ,是因为linux只会从usr(application) 和svc(kernel)两种mode跳转到exception来 __stubs_start 和 __stubs_end 之间的代码简化后为: 1: __stubs_start: 2: vector_irq: @vector_stub irq, IRQ_MODE, 4 3: vector_dabt: @vector_stub dabt, ABT_MODE, 8 4: vector_pabt: @vector_stub pabt, ABT_MODE, 4 5: vector_und: @vector_stub und, UND_MODE 6: vector_fiq: 7: vector_addrexcptn: 8: .LCvswi: 9: __stubs_end: 由此可以知道 __stubs_start 和 __stubs_end 之间定义了各种异常的入口 我们再来看为什么异常入口是“b vector_und + stubs_offset”, 同时为什么stubs_offset 的定义如下 .equ stubs_offset, __vectors_start + 0x200 - __stubs_start arm 的跳转指令b 是跳转到相对于PC的一个偏移地址( offset ),汇编器在编译时会对label 减去PC 得到offset,同时vector 拷贝后是如下排列的 __vectors_start B vector_ __vectors_end +0x200 __stubs_start vector_ __stubs_end 因此,"b vector_" 的label –PC = offset, 而offset 为 b 指令与vector的offset,即 vector_-__stubs_start + ( 0x200 – ( PC_old – __vectors_start ) ) = vector_+ __vectors_start + 0x200 – __stubs_start – PC_old 所以异常入口为“b vector_und + stubs_offset”, 同时stubs_offset= __vectors_start + 0x200 – __stubs_start 我们可以通过objdump反汇编来验证: 00000060 : .globl __stubs_start __stubs_start: /* * Interrupt dispatcher */ vector_stub irq, IRQ_MODE, 4 60 : e24ee004 sub lr, lr, #4 ; 0x4 64: e88d4001 stm sp, {r0, lr} … 1d4: e1a00000 .word 0xe1a00000 1d8: e1a00000 .word 0xe1a00000 1dc: e1a00000 .word 0xe1a00000 000001e0 : /* * Undef instr entry dispatcher * Enter in UND mode, spsr = SVC/USR CPSR, lr = SVC/USR PC */ … __vectors_start: swi SYS_ERROR0 284: ef9f0000 svc 0x009f0000 b vector_und + stubs_offset 288: ea0000dd b 604 ldr pc, .LCvswi + stubs_offset 28c: e59ff410 ldr pc, [pc, #1040] ; 6a4 b vector_pabt + stubs_offset 290: ea0000bb b 584 b vector_dabt + stubs_offset 294: ea00009a b 504 b vector_addrexcptn + stubs_offset 298: ea0000fa b 688 b vector_irq + stubs_offset 29c: ea000078 b 484 b vector_fiq + stubs_offset 2a0: ea0000f7 b 684 0x1e0 – 0x60 + 0x200 – ( 0x288 + 8 ) – 0x284 = 0xdd*4 |
|
|
|
只有小组成员才能发言,加入小组>>
调试STM32H750的FMC总线读写PSRAM遇到的问题求解?
1617 浏览 1 评论
X-NUCLEO-IHM08M1板文档中输出电流为15Arms,15Arms是怎么得出来的呢?
1543 浏览 1 评论
977 浏览 2 评论
STM32F030F4 HSI时钟温度测试过不去是怎么回事?
683 浏览 2 评论
ST25R3916能否对ISO15693的标签芯片进行分区域写密码?
1595 浏览 2 评论
1863浏览 9评论
STM32仿真器是选择ST-LINK还是选择J-LINK?各有什么优势啊?
644浏览 4评论
STM32F0_TIM2输出pwm2后OLED变暗或者系统重启是怎么回事?
515浏览 3评论
531浏览 3评论
stm32cubemx生成mdk-arm v4项目文件无法打开是什么原因导致的?
504浏览 3评论
小黑屋| 手机版| Archiver| 电子发烧友 ( 湘ICP备2023018690号 )
GMT+8, 2024-11-22 07:52 , Processed in 0.816044 second(s), Total 76, Slave 60 queries .
Powered by 电子发烧友网
© 2015 bbs.elecfans.com
关注我们的微信
下载发烧友APP
电子发烧友观察
版权所有 © 湖南华秋数字科技有限公司
电子发烧友 (电路图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191 工商网监 湘ICP备2023018690号