まず、割り込み処理
1、割り込みが発生します
割り込みが発生すると、CPUは対応する割り込み処理、例外処理ベクタテーブルにジャンプします
で例外処理ベクタテーブルをarch\arm\kernel\entry-armv.S
定義ファイルの内部
.globl __vectors_start
__vectors_start:
swi SYS_ERROR0
b vector_und + stubs_offset
ldr pc, .LCvswi + stubs_offset
b vector_pabt + stubs_offset
b vector_dabt + stubs_offset
b vector_addrexcptn + stubs_offset
/* 中断入口地址。发生中断时会跳到这里,执行这句跳转语句,
*+ stubs_offset 是因为异常向量表使用高地址0xffff0000,异常向量copy0xffff0000处 */
b vector_irq + stubs_offset
b vector_fiq + stubs_offset
.globl __vectors_end
__vectors_end:
IRQ割り込みが発生した場合、それが実行され
b vector_irq + stubs_offset
、それは、次のコードブロックにジャンプします、この言語を
するvector_stub
には、マクロアーキテクチャのLinuxを例外処理の簡単な紹介があります
/* vector_stub 是汇编下定义的一个宏, 里面是一块代码块,主要用于计算返回地址,计算下一步要跳转的入口地址
* irq这个宏的名字,
* #define IRQ_MODE 0x00000012
* 4 这个是用于计算返回地址的
*/
vector_stub irq, IRQ_MODE, 4
/* 下面要跳转到那个入口,是在 vector_stub 宏里面计算并且跳转的*/
.long __irq_usr @ 0 (USR_26 / USR_32) /* 用户模式下发生irq异常 */
.long __irq_invalid @ 1 (FIQ_26 / FIQ_32)
.long __irq_invalid @ 2 (IRQ_26 / IRQ_32)
.long __irq_svc @ 3 (SVC_26 / SVC_32) /* 管理模式下发生irq异常 */
.long __irq_invalid @ 4
.long __irq_invalid @ 5
.long __irq_invalid @ 6
.long __irq_invalid @ 7
.long __irq_invalid @ 8
.long __irq_invalid @ 9
.long __irq_invalid @ a
.long __irq_invalid @ b
.long __irq_invalid @ c
.long __irq_invalid @ d
.long __irq_invalid @ e
.long __irq_invalid @ f
前に例外処理アーキテクチャのLinuxそれはユーザーモードの割り込みで発生した、または割り込みが管理モードの下で発生するかどうか、に導入、割り込みサービスルーチンは、(ちょうど必要性の前で)同じです。
その後に上の__irq_usr
分析。
__irq_usr:
/* usr_entry 也是一个宏,里面的代码块作用是保存 r0、r1 等一些寄存器 */
usr_entry
#ifdef CONFIG_TRACE_IRQFLAGS
bl trace_hardirqs_off
#endif
get_thread_info tsk
#ifdef CONFIG_PREEMPT
ldr r8, [tsk, #TI_PREEMPT] @ get preempt count
add r7, r8, #1 @ increment it
str r7, [tsk, #TI_PREEMPT]
#endif
irq_handler /* irq_handler 是一个宏,这个宏也是一个代码块,中断服务函数,也是在这个宏的代码块里面调用 */
#ifdef CONFIG_PREEMPT
ldr r0, [tsk, #TI_PREEMPT]
str r8, [tsk, #TI_PREEMPT]
teq r0, r7
strne r0, [r0, -r0]
#endif
#ifdef CONFIG_TRACE_IRQFLAGS
bl trace_hardirqs_on
#endif
mov why, #0
b ret_to_user
irq_handler
このマクロは、で定義されているarch\arm\kernel\entry-armv.S
ファイルの内部
.macro irq_handler
get_irqnr_preamble r5, lr /*get_irqnr_preamble 是一个宏,里面什么都没做 */
1: get_irqnr_and_base r0, r6, r5, lr /* get_irqnr_and_base 也是一个宏,在里面会计算当前的中断号(中断号通过 INTOFFSET 寄存器的某一位来确定)、中断状态等,和struct pt_regs 结构体压栈。*/
movne r1, sp /* 通过堆栈将struct pt_regs* 传给 asm_do_IRQ 函数 */
@
@ routine called with r0 = irq number, r1 = struct pt_regs *
@
adrne lr, 1b
bne asm_do_IRQ /* 到这里就是跳转过去执行中断服务函数了 */
2、割り込み処理
asm_do_IRQ()
この関数は、すべての割り込みサービスの関数です。arch\arm\kernel\Irq.c
次のようにコードブロックを定義文書:
asmlinkage void __exception asm_do_IRQ(unsigned int irq, struct pt_regs *regs)
{
struct pt_regs *old_regs = set_irq_regs(regs);
/* 通过中断号获取 irq_desc 数组项*/
struct irq_desc *desc = irq_desc + irq;
/*
* Some hardware gives randomly wrong interrupts. Rather
* than crashing, do something sensible.
*/
if (irq >= NR_IRQS)
desc = &bad_irq_desc;
irq_enter();
/* 这里处理中断了 */
desc_handle_irq(irq, desc);
/* AT91 specific workaround */
irq_finish(irq);
irq_exit();
set_irq_regs(old_regs);
}
ハンドラ割り込み登録ユーザを呼び出すことですdesc_handle_irq機能。
desc_handle_irq
関数でinclude\asm-arm\mach\Irq.h
定義ファイルの内部。コードブロック、次の
static inline void desc_handle_irq(unsigned int irq, struct irq_desc *desc)
{
desc->handle_irq(irq, desc);
}
*追加情報:
asm_do_IRQ
範囲パラメータIRQ関数値があるIRQ_EINT0 ~ 31
だけで32個の値。asm_do_IRQ
関数のirq
パラメータは、割り込みがチップS3C2440によって決定される割込み番号の組であってもよく、実際の割り込み番号であってもよい。後に割り込みが発生するINTPND
ビットレジスタは1にセットされ、INTOFFSET
レジスタの値が決定されirq
たパラメータを。すべての実際の中断は、irq_desc
そのうちの数よりも多く、それに対応する配列を、持っています。場合asm_do_IRQ
関数は、IRQ割り込み「のセット」表現され、irq_desc[irq].handle_irq
メンバ関数は、最初の(割り込み数であると仮定すると割り込みこのグループの割り込みを区別する必要があるirqno
)、次いでコールirq_desc[irqno].handle_irq
さらなる処理のために。
外部割り込みEINT8〜EINT23例:
(1)割込みがトリガされ、
INTOFFSET
レジスタの値は、5であるasm_do_IRQ
関数IRQ値のパラメータ(IRQ_EINT0+5)
、すなわち、IRQ_EINT8t23
。その後、呼び出すirq_desc[IRQ_EINT8t23].handle_irq
プロセスに機能を
(2)irq_desc[IRQ_EINT8t23].handle_irq
初期化時に、それがに初期化されるs3c_irq_demux_extint8
(3)s3c_irq_demux_extint8
関数arch\arm\plat-s3c24xx\Irq.c
定義ファイルの内部。これは、最初の読み取りEINTPEND 和 EINTMASK
割り込みが発生したかを決定するために、レジスタの値を、次に、割り込み番号を再計算し、次に呼び出しirq_desc
で配列項目をhandle_irq
メンバ関数。
s3c_irq_demux_extint8
次のように機能コードは次のようになります。
static void
s3c_irq_demux_extint8(unsigned int irq, struct irq_desc *desc)
{
/* 读取 EINTPEND 寄存器的值,EINT8 ~ EINT23 发生时相应的位被置1 */
unsigned long eintpnd = __raw_readl(S3C24XX_EINTPEND);
/* 读取屏蔽寄存器的值 */
unsigned long eintmsk = __raw_readl(S3C24XX_EINTMASK);
/* 清除被屏蔽位 */
eintpnd &= ~eintmsk;
/* 清除低8位,EINT8对应位8 ... */
eintpnd &= ~0xff; /* ignore lower irqs */
/* we may as well handle all the pending IRQs here */
/* 循环处理所有的子中断 */
while (eintpnd) {
/* 确定 eintpnd 中为1的最高位 */
irq = __ffs(eintpnd);
/* 将该位清零 */
eintpnd &= ~(1<<irq);
/* 重新计算中断号:前面计算出,如果 irq = __ffs(eintpnd) 算出的是8,则中断号为8 */
irq += (IRQ_EINT4 - 4);
/* 调用这个中断真正的处理函数(handle_edge_irq函数) */
desc_handle_irq(irq, irq_desc + irq);
}
}
(4)
IRQ_EINT8 ~ IRQ_EINT23
におけるこれらの実際の割り込みハンドラの入り口、init_IRQ
初期化関数の時間は、割り込み初期化handle_edge_irq
(エッジトリガ)機能。
handle_edge_irq
機能kernel\irq\Chip.c
次のように、定義したファイル:
void fastcall handle_edge_irq(unsigned int irq, struct irq_desc *desc)
{
...
/* 统计中断发生的次数 */
kstat_cpu(cpu).irqs[irq]++;
/* Start handling the irq */
/* 调用 chip 底层的操作函数 清除中断 */
desc->chip->ack(irq);
/* Mark the IRQ currently in progress.*/
desc->status |= IRQ_INPROGRESS;
do {
/* 依次调用 action 链表里面的处理函数(用户注册的函数都是挂在action链表里面的) */
action_ret = handle_IRQ_event(irq, action);
} while ((desc->status & (IRQ_PENDING | IRQ_DISABLED)) == IRQ_PENDING);
}
handle_IRQ_event
順次呼び出しaction
ハンドラ内のリストを、この機能kernel\irq\Handle.c
ブロック以下、定義ファイル
irqreturn_t handle_IRQ_event(unsigned int irq, struct irqaction *action)
{
...
/* 依次调用 action 链表的成员函数*/
do {
ret = action->handler(irq, action->dev_id);
if (ret == IRQ_HANDLED)
status |= action->flags;
retval |= ret;
action = action->next;
} while (action);
...
return retval;
}
注:上記の分析は、エッジトリガ呼び出しのためのプロセスは、エッジトリガー割り込みである
handle_edge_irq()
レベルトリガ、呼処理の関数であるhandle_level_irq
プロセスは類似している方法の機能だけでなく、レベルトリガ割り込みこのシールドまた、割り込みを処理した後に開きます。
要約:
(1)割り込み、割り込みベクタコール
asm_do_IRQ
、着信割り込み番号irq
。(2)
asm_do_IRQ
割り込み数に応じて機能をirq
呼び出しますirq_desc[irq].handle_irq
。彼は、割り込みハンドラの入り口です。レベルトリガするためにこの関数は、通常、入口でhandle_level_irq
通常エントリエッジトリガ機能のためhandle_edge_irq
。(3)クリア割り込み関数の最初のエントリは、エントリ関数である
handle_level_irq
にも割り込みをマスクします。(4)利用者ごとのコールに登録
irq_desc[irq].action
割り込みハンドラに登録リスト(5)エントリ関数である
handle_level_irq
時間が、また、処理後に割り込みをオープンしました。