UBOOT启用中断
一、增加宏定义
用户自己修改。
#define CONFIG_USE_IRQ
#define CONFIG_STACKSIZE_IRQ (4*1024) /* IRQ的栈大小*/
#define CONFIG_STACKSIZE_FIQ (4*1024) /* FIQ的栈大小*/
二、建立中断向量表
arch/arm/lib/vectors.S中的源代码为(不用改)
b reset /*这句话反汇编为 33f00000: ea0000b8 b 33f002e8 <reset>*/
ldr pc, _undefined_instruction
ldr pc, _software_interrupt
ldr pc, _prefetch_abort
ldr pc, _data_abort
ldr pc, _not_used
ldr pc, _irq
ldr pc, _fiq
查看反汇编,可以看到,最开始的启动代码,就是在TEXT_BASE基地址0x33f00000建立中断向量表,
u-boot: file format elf32-littlearm
Disassembly of section .text:
33f00000 <__image_copy_start>:
33f00000: ea0000b8 b 33f002e8 <reset>
33f00004: e59ff014 ldr pc, [pc, #20] ; 33f00020 <_undefined_instruction>
33f00008: e59ff014 ldr pc, [pc, #20] ; 33f00024 <_software_interrupt>
33f0000c: e59ff014 ldr pc, [pc, #20] ; 33f00028 <_prefetch_abort>
33f00010: e59ff014 ldr pc, [pc, #20] ; 33f0002c <_data_abort>
33f00014: e59ff014 ldr pc, [pc, #20] ; 33f00030 <_not_used>
33f00018: e59ff014 ldr pc, [pc, #20] ; 33f00034 <_irq>
33f0001c: e59ff014 ldr pc, [pc, #20] ; 33f00038 <_fiq>
2.1 堆栈初始化
在arch/arm/cpu/arm920t/start.S中:
IRQ_STACK_START的赋值:
在arch/arm/lib/board.c中的board_init_f函数中给gd赋值;
在arch/arm/lib/board.c中的board_init_r函数中:
void board_init_r(gd_t *id, ulong dest_addr)
{
......
/* set up exceptions */
interrupt_init();
/* enable exceptions */
enable_interrupts();
.......
}
其中,在interrupt_init中给IRQ_STACK_START赋值,在enable_interrupts中设置CPSR相关位。这两个函数在interrupts.c (arch\arm\lib) 中实现。
#ifdef CONFIG_USE_IRQ
int interrupt_init (void)
{
IRQ_STACK_START = gd->irq_sp - 4;
IRQ_STACK_START_IN = gd->irq_sp + 8;
FIQ_STACK_START = IRQ_STACK_START - CONFIG_STACKSIZE_IRQ;
//return arch_interrupt_init();
return 0;
}
三、启用MMU
用户自己修改。
四、将物理地址TEXT_BASE与虚拟地址0映射
用户自己修改。
映射后,发生异常和中断,CPU自动跳转到0x00-0x1c地址,那么实际就会跳转到0x33F00000-0x33F0001C地址,根据实际的异常类型,跳到对应的向量,向量又指向可自定义的具体的函数。
五、中断汇编跳转
用户可以修改。
例如IRQ:
arch/arm/lib/vectors.S中的irq
irq:
get_bad_stack
bad_save_user_regs
bl do_irq
也可以屏蔽arch/arm/lib/vectors.S的irq,在我们的start.S中定义irq
irq:
sub lr, lr, #4 @ the return address
ldr sp, IRQ_STACK_START @ the stack for irq
stmdb sp!, { r0-r12,lr } @ save registers
ldr lr, =int_return @ set the return addr
ldr pc, =do_irq @ call the isr
int_return:
ldmia sp!, { r0-r12,pc }^ @ return from interrupt
“sub lr, lr, #4”的原因为ARM的三级流水线:
假设中断在执行0xAA00代码处时发生
0xAA00 执行 //此时pc=0xAA08,在此处跳转到中断,那么中断处理完成后的返回地址应该为0xAA04
0xAA04 译码
0xAA08 取值
中断肯定是在执行代码时发生,假设在0xAA00代码处跳转到中断,那么中断执行完成后就该返回执行0xAA04的代码了。
而lr保存的是PC寄存器的值,PC总是指向"取值"地址,所以在执行0xAA00时,PC=0xAA08,那么sub lr, lr, #4,就是让lr=PC-4=0xAA04了,这样就能跳转到我们期望的 中断返回地址 了。
六、用户自定义中断处理函数
用户自己修改。
随意放置,例如interrupts.c (arch\arm\cpu\arm920t\s3c24x0)中。
void do_irq (struct pt_regs *pt_regs)
{
switch( ... ){
}
//清中断
}
推荐
https://www.cnblogs.com/fah936861121/articles/7259156.html