【详解】中断相关的知识

2025-07-03 20:22:40
Avatar for adminadmin

3.3.1. 向量中断和非向量中断实例解析

以ARM系统为例,物理地址最开始的几个地址,存放的是对应的几个最常见的向量中断,如数据中止异常,软中断,预取指错误异常等,还有一个是其他非向量中断的总入口IRQ。

此部分内容,可以参考Uboot中的ARM的初始化部分start.S中的代码来解释:

其相关代码如下:

_start: b 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

_undefined_instruction: .word undefined_instruction

_software_interrupt: .word software_interrupt

_prefetch_abort: .word prefetch_abort

_data_abort: .word data_abort

_not_used: .word not_used

_irq: .word irq

_fiq: .word fiq

。。。

/*

* exception handlers

*/

.align 5

undefined_instruction:

get_bad_stack

bad_save_user_regs

bl do_undefined_instruction

.align 5

software_interrupt:

get_bad_stack

bad_save_user_regs

bl do_software_interrupt

.align 5

prefetch_abort:

get_bad_stack

bad_save_user_regs

bl do_prefetch_abort

.align 5

data_abort:

get_bad_stack

bad_save_user_regs

bl do_data_abort

.align 5

not_used:

get_bad_stack

bad_save_user_regs

bl do_not_used

。。。

.align 5

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, =IRQ_Handle @ call the isr

int_return:

ldmia sp!, { r0-r12,pc }^ @ return from interrupt

.align 5

fiq:

get_fiq_stack

/* someone ought to write a more effiction fiq_save_user_regs */

irq_save_user_regs

bl do_fiq

irq_restore_user_regs

可看出,物理内存最开始的存放的内容是:

地址0x0: reset整个系统

地址0x04:放了一个指令,该指令是将_undefined_instruction存入PC,即实现PC跳转到_undefined_instruction的地址中去;

地址0x08:同理,PC跳转到_software_interrupt

地址0x0C:同理,PC跳转到_prefetch_abort

地址0x10:同理,PC跳转到_data_abort

地址0x14:同理,PC跳转到_not_used

地址0x18:同理,PC跳转到_irq

地址0x1C:同理,PC跳转到_fiq

其中,对于_undefined_instruction,很明显,就是我们之前所解释的异常,即指令执行出了对应的问题了,PC会直接跳转到此处的0x04的地址,然后该地址中,就是把PC跳转到对应的_undefined_instructio的位置,去执行对应的异常处理。

其他的_software_interrupt和_data_abort等,都是同样道理,不多解释。

而上述这些异常或_software_interrupt,就都是所谓的中断向量,都是由硬件架构决定的,固定好的了地址,作为软件开发人员,只要把对应的指令写好,到时候发生对应的异常,系统自动会跳转到此处的地址,实现对应的PC的跳转,去做对应的处理。

而对于0x18处的_irq,就是我们所说的所有的非向量中断的总的入口地址,即系统发现有中断了,此处发现是普通的中断,那么就会跳转到0x18的地址这里,然后执行的是:

PC跳转到_irq,而_irq地址所对应的内容是:保存对应的当前的环境,即上下文,然后执行“ldr pc, =IRQ_Handle”,即跳转到IRQ_Handle函数中去。

而以TQ2440的S3C2410为例,其代码为:

interrupts.c (opt\embedsky\u-boot-1.1.6\cpu\arm920t\s3c24x0)

void Isr_Init(void)

{

int i = 0;

intregs = S3C24X0_GetBase_INTERRUPT();

for (i = 0; i < sizeof(isr_handle_array) / sizeof(isr_handle_array[0]); i++ )

{

isr_handle_array[i] = Dummy_isr;

}

intregs->INTMOD=0x0; // All=IRQ mode

intregs->INTMSK=BIT_ALLMSK; // All interrupt is masked.

//pISR_URXD0=(unsigned)Uart0_RxInt;

//rINTMSK=~(BIT_URXD0); //enable UART0 RX Default value=0xffffffff

isr_handle_array[ISR_TIMER4_OFT] = IsrTimer4;

isr_handle_array[ISR_WDT_OFT] = IsrWatchdog;

#ifdef CONFIG_USB_DEVICE

isr_handle_array[ISR_USBD_OFT] = IsrUsbd;

isr_handle_array[ISR_DMA2_OFT] = IsrDma2;

ClearPending(BIT_DMA2);

ClearPending(BIT_USBD);

#endif

}

void IRQ_Handle(void)

{

unsigned long oft = intregs->INTOFFSET;

S3C24X0_GPIO * const gpio = S3C24X0_GetBase_GPIO();

// printk("IRQ_Handle: %d\n", oft);

if( oft == 4 ) gpio->EINTPEND = 1<<7;

intregs->SRCPND = 1<

intregs->INTPND = intregs->INTPND;

/* run the isr */

isr_handle_array[oft]();

}

可见,其中IRQ_Handle做的事情,就是去读取对应的寄存器,然后经过计算,找到真正的中断源的偏移量,然后再通过偏移量,在中断函数表中,去获得对应该中断的中断服务程序ISR。

而其中的中断函数表isr_handle_array是在程序最开始初始化时候去调用Isr_Init来初始化好的,已经见每个中断多对应的ISR函数存放了对应的位置了。

向量中断的优点是,反应速度快,有了中断,CPU直接跳转到对应的位置,去执行对应的代码了,属于速度快,但是无法扩展,由硬件设计时候觉得的,固定好了,没法改变。

而非向量中断,由于多了一层调用关系,而且在总的普通中断的入口函数中,要去读取寄存器,再去计算到底是哪个中断,所以,速度上,就相对较慢了,属于速度慢,但是扩展性较好。

简单的说就是:

硬件中断,由硬件提供ISR地址,速度较快;

软件中断,由软件计算出中断源,再去找出对应的ISR,速度相对慢。

Copyright © 2088 沙滩足球世界杯_足球世界杯中国 - pfw18.com All Rights Reserved.
友情链接