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中:
image

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

posted @ 2022-10-17 19:31  solonj  阅读(539)  评论(0编辑  收藏  举报