|
EDA365欢迎您登录!
您需要 登录 才可以下载或查看,没有帐号?注册
x
本帖最后由 pulbieup 于 2020-11-12 15:45 编辑 " T% B! Z; t6 P B) w1 v9 M
- L1 m* E0 h* T2 W中断处理一般不是纯软件来实现的,需要硬件的支持。通过对中断的学习有助于更深入的了解系统的一些底层原理,特别是驱动程序的开发。
( A) ]7 j' }2 \% C1 Y9 Y# J0 K L; P4 L7 f- y: ~0 h. o0 @ M
主要内容:, C0 D* m" m$ _% I7 v% L0 m
' h" G3 B6 h! O, X$ K
什么是中断, F2 @, E; q) B' _
中断类型
! v2 I( t" a/ Y9 P* |中断相关函数: E7 `: f: n" v3 F1 p7 R) c. {
中断处理机制
: A+ q9 c3 J a0 d$ @5 [5 Q1 ]5 n1 G中断控制方法! g, n% r) b' x" T% R
总结, Q9 T4 Q- S h$ I
% w% X7 {3 R$ N8 b8 \6 w' `: ?: O7 j/ k! p2 F3 v
1. 什么是中断
$ T1 F. g# k; c为了提高CPU和外围硬件(硬盘,键盘,鼠标等等)之间协同工作的性能,引入了中断的机制。
9 [3 i* x# B! z* X
" z2 v t9 h; Z1 d( z没有中断的话,CPU和外围设备之间协同工作可能只有轮询这个方法:CPU定期检查硬件状态,需要处理时就处理,否则就跳过。
p1 V1 l7 ]% A! j1 H. u+ ?. ?& W) d* m9 \! J
当硬件忙碌的时候,CPU很可能会做许多无用功(每次轮询都是跳过不处理)。7 J4 z' O) W1 Q7 Z- V4 ]1 d
/ e* ^5 c* ?. _9 L1 S# k/ Q
% c1 P& V; T3 _: L7 j5 W' q9 C
0 d2 y6 j3 q) N5 \" f中断机制是硬件在需要的时候向CPU发出信号,CPU暂时停止正在进行的工作,来处理硬件请求的一种机制。
$ C9 W" ]! X% d2 Y [1 \$ c- u' u1 n* d1 Y% \3 {" D
5 D$ h5 y) D% j' D7 p4 T' w& z0 b" Z Y8 |: s
2. 中断类型
1 M" x" I7 A* M3 M4 C中断一般分为异步中断(一般由硬件引起)和同步中断(一般由处理器本身引起)。
m, }2 A: S$ d$ ]( Q2 X! |1 ?3 J* o1 [3 N" u1 _
异步中断:CPU处理中断的时间过长,所以先将硬件复位,使硬件可以继续自己的工作,然后在适当时候处理中断请求中耗时的部分。$ a) @4 W5 }- J/ Q+ g6 h; Y9 J; g
) p: |6 Q5 C( i: n7 U: \
举个例子:网卡的工作原理
1 F, e( i/ v, o: O, S! d
* F- Q$ N, v0 }, K 网卡收到数据包后,向CPU发出中断信号,请求处理接收到的数据包
; i7 F- i2 p% }+ P* e6 N0 `' C CPU将收到的数据包拷贝到内存后,即通知网卡继续工作/ ?/ X5 ~; h" w1 ]
至于数据包拷贝至内存后的处理会在适当的时候进行
$ Z, ?5 P5 @6 F# ~8 L) j
/ {% z- S h" w I0 r9 u N9 D$ X" `3 \- M$ k/ }3 n2 F
这样做避免了处理数据包时间过长导致网卡接收数据包速度变慢。
3 m( ?# J0 t+ Q/ a& n* t. g
* F( {6 R' i5 H : [9 n- r% |3 v& ]& S. U9 {' N
# m7 R% b7 g# o9 o- a/ {
同步中断:CPU处理完中断请求的所有工作后才反馈硬件
5 x6 O7 b: k% O
0 U" ?$ P. { @) Z5 S, l8 p# f; u举个例子:系统异常处理(比如运算中的除0操作)
. B7 k4 m* v0 Q- o
! W, D/ a) S( Y7 o8 } 应用程序出现异常后,需要内核来处理
) i( s! p7 W( L0 |8 h 内核调用相应的异常处理函数来处理异常: G: V# }1 s5 }
处理完后终了应用程序或者给出message% Q% y9 x$ Z; [! a5 U( u( f& ]
1 p6 ] v8 P/ O7 k1 Q6 {
4 `6 f$ \5 k8 ~( h+ w( @' c: n同步中断应该处理能很快完成的一种中断。5 [5 m8 j1 B9 _ v
@& _% M- x& P2 S1 F
5 W+ @$ K& v) n; s+ d- f; X7 b: W
. | W0 H" R' q- e- I g+ H3. 中断相关函数
6 C0 ^" S1 `/ x) J, V实现一个中断,主要需要知道3个函数:
y) Y; J t2 k& E( i3 {! v9 Z, X* l# R, x$ ]. B. t' Q4 C" b: A
注册中断的函数
% Z) [+ A* X @$ \7 s0 `3 X释放中断的函数+ {8 e' g4 h; Z) b
中断处理程序的声明
H7 w+ ]2 y( E, [3 I4 N% \' f! \: \$ Z
# Q! y- A0 ?# q1 E: c( u) \8 m$ c1 y% T: D
3.1 注册中断的函数
3 c& [' z0 t. P: Z 位置:<linux/interrupt.h> include/linux/interrupt.h
?* A4 v7 n' D! z) C, h' \4 P; m j. g1 _% M, w" S
! l8 c- C6 y& E' C. @" X3 E& |
4 X; G2 v7 n: m0 ^# O1 a
定义如下:
' s9 r0 [2 P8 Z; D% `4 y
5 N |7 a g/ F$ A复制代码) Q! l1 c# Z' b. n# [! R( k, ]
/*
" a3 {8 O9 S; C2 v * irg - 表示要分配的中断号9 P W* y \9 W9 c v- q6 C
* handler - 实际的中断处理程序0 l8 P2 M8 v0 r) r
* flags - 标志位,表示此中断的具有特性
) c5 b A4 Q' f4 ` * name - 中断设备名称的ASCII 表示,这些会被/proc/irq和/proc/interrupts文件使用' ~1 K% Z/ k5 I* z5 x8 J
* dev - 用于共享中断线,多个中断程序共享一个中断线时(共用一个中断号),依靠dev来区别各个中断程序0 Y$ r1 T5 ?5 X D
* 返回值:9 Z2 j* L# B, {+ R1 p" s
* 执行成功:0
1 D4 _: w/ J5 a% A% t5 l8 y8 s! E% T * 执行失败:非0% o6 l2 X( p+ p/ u- S* N8 @
*/ b+ [7 ~- g9 M. K
int request_irq(unsigned int irq,
( U+ P6 A0 X8 x: e irq_handler_t handler, r3 Y: ^8 m9 o
unsigned long flags,
9 ^( M# f- _. _9 A0 l8 A const char* name,6 ]5 e7 G9 l7 f
void *dev)
8 N( q& {+ w1 S! e8 e; v% D2 A复制代码
$ C- u8 \- m# M$ W& ~2 h; u& D
* l' q+ |/ |) u9 I' c
: p5 H0 \$ O2 ^/ M- v8 s3.2 释放中断的函数
. ^5 ^, ?, }4 E5 u定义比较简单:
. e! f- R" ~0 e% o! `2 N; T
# D+ M; h7 r( W2 Pvoid free_irq(unsigned int irq, void *dev)8 U9 A5 [: H2 `+ g
如果不是共享中断线,则直接删除irq对应的中断线。: T, s" e1 w# T& `; M
# a) R7 D/ G( y& W- R8 f2 ]8 j
如果是共享中断线,则判断此中断处理程序是否中断线上的最后一个中断处理程序,6 ^! p/ j) W3 `, `, q }
+ {4 ` C; K; s9 C% f 是最后一个中断处理程序 -> 删除中断线和中断处理程序
4 b3 s: ]+ V4 i0 U
N# V5 ~; ?$ O9 D! ` 不是最后一个中断处理程序 -> 删除中断处理程序' `2 b+ c) H- W( k2 d* s$ E
# {; A( Q! m/ h. T
' o9 `% A: C! \7 g& _. @. \, R; v/ R4 K- v8 o6 F) g0 f& A
3.3 中断处理程序的声明& u+ C, B& c; ]4 T
声明格式如下: G6 v$ i$ z: ~ H/ f+ y: K
9 f' l9 D, |6 q1 [5 b' O
复制代码: Y3 {; c; ^; d+ c
/*
7 I+ J) J5 Z) a M% G& b# ]+ G% b * 中断处理程序的声明
2 |4 d+ y% H+ k `7 c3 q- S * @irp - 中断处理程序(即request_irq()中handler)关联的中断号
2 T" b0 J; | j * @dev - 与 request_irq()中的dev一样,表示一个设备的结构体
9 Y m5 j" l$ E7 {0 e/ w * 返回值:+ i, u" S9 [- ?) v; S
* irqreturn_t - 执行成功:IRQ_HANDLED 执行失败:IRQ_NONE
# w' U, c# F( [, H */$ v4 D; ~8 r B* \5 w# A
static irqreturn_t intr_handler(int, irq, void *dev)
7 V0 m4 i* W, i复制代码( C$ z1 P' l; V% H
1 ]. g0 T5 m3 i5 k
8 B3 h: s- w( Y
4. 中断处理机制/ h5 P3 f6 D! J+ I8 m3 Q
中断处理的过程主要涉及3函数:
# Q4 f* H: q7 H o; l5 t: _$ d$ k9 a# C! v. N
do_IRQ 与体系结构有关,对所接收的中断进行应答
/ l, e C2 I# s. M/ ?handle_IRQ_event 调用中断线上所有中断处理
1 `- ^6 H. G4 K4 ]0 V; dret_from_intr 恢复寄存器,将内核恢复到中断前的状态
' G0 {& D, K) Y' B5 g9 t 8 p+ F! i$ q! N' f. k0 E8 s
! |, k4 N$ o1 y+ S( ?* i/ k处理流程可以参见书中的图,如下:
8 H5 T+ J, r* y7 y( B, B: n' A7 o
% v! N b5 a: d8 m/ V; j& L
9 f/ K5 J9 _! o+ K
a" u3 r$ p, b) C |; b 6 ~0 k, \# Q0 ^( A7 d, s
! A3 ^3 ~5 F/ g) @! T# X$ C5. 中断控制方法
6 n S' Z/ {) E7 O: S: U! t5 ^常用的中断控制方法见下表:( f; l, Z' u" I, o8 G
函数 | 说明 | local_irq_disable() | 禁止本地中断传递 | local_irq_enable() | 激活本地中断传递 | local_irq_save() | 保存本地中断传递的当前状态,然后禁止本地中断传递 | local_irq_restore() | 恢复本地中断传递到给定的状态 | disable_irq() | 禁止给定中断线,并确保该函数返回之前在该中断线上没有处理程序在运行 | disable_irq_nosync() | 禁止给定中断线 | enable_irq() | 激活给定中断线 | irqs_disabled() | 如果本地中断传递被禁止,则返回非0;否则返回0 | in_interrupt() | 如果在中断上下文中,则返回非0;如果在进程上下文中,则返回0 | in_irq() | 如果当前正在执行中断处理程序,则返回非0;否则返回0 |
# i2 k0 Q3 r. t2 S总结
/ U. j& \1 S _ x" w5 G% d* f3 i8 C% ?$ |* D' y u
0 F0 C8 Y ]& {+ k$ }; \) w
中断处理对处理时间的要求很高,如果一个中断要花费较长时间,那么中断处理一般分为2部分。0 U6 q2 D4 r8 l6 x0 |
4 |- ]+ p, n+ `
上半部只做一些必要的工作后,立即通知硬件继续自己的工作。3 q3 T) @" @" ?$ c3 k
+ J! W% V) G0 `0 n( B9 S" r
中断处理中耗时的部分,也就是下半部的工作,CPU会在适当的时候去完成。
0 d2 B- F* ^# |9 o |
|