您的位置:首页 > 运维架构 > Linux

《Linux内核设计与实现》——中断和中断处理

2014-11-11 15:09 176 查看
一、中断

1、中断本质上是一种特殊的电信号,由硬件设备发向处理器。处理器接收到中断后,会马上向操作系统反应此信号的到来,然后就由操作系统负责处理这些新到来的数据。

2、不同的设备对应的中断不同,而每个中断都通过一个唯一的数字标志。这些中断值通常被称为中断请求(IRQ)线,每个IRQ线都会被关联一个数值量。

二、中断处理程序

1、再响应一个特定中断的时候,内核会执行一个函数,该函数叫做中断处理程序或中断服务例程(ISR)。

1)、产生中断的每个设备都有一个相应的中断处理程序。

2)、一个设备的中断处理程序是它设备驱动程序的一部分——设备驱动程序是用于对设备进行管理的内核代码。

2、中断处理程序与其他内核函数的真正区别在于:中断处理程序是被内核调用来响应中断的,而他们运行在中断上下文中,中断上下文也称原子上下文。

三、上半部和下半部的对比

1、中断处理切为两个部分

1)、中断处理程序是上半部——接收到一个中断,它就立即开始执行,但***严格限时的工作。

2)、能够被允许稍后完成的工作会推迟到下半部去。此后,在合适的时机,下半部会被开中断执行。

四、注册中断处理程序

1、驱动程序可以通过requeset_irq()函数注册一个中断处理程序,并激活给定的中断线:

int requeset_irq(unsigned int irq, irq_handler_t handler,

unsigned long flags, const char *name, void *dev);

I、参数irq表示要分配的中断号。

II、参数handler是一个指针,指向处理这个中断的实际中断处理程序。

2、中断处理程序标志

1)、参数flags可以为0,也可以是一个或多个标志的位掩码。

I、IRQF_DISABLED——该标志被设置后,意味着内核在处理程序本身期间,要禁止所有的其他中断。

II、IRQF_SAMPLE_RANDOM——此标志表明这个设备产生的中断对内核熵池有贡献。

III、IRQF_TIMER——此标志是特别位系统定时器的中断处理而准备的。

IV、IRQF_SHARED——此标志表明可以在多个终端处理程序之间共享中断线。

2)、参数name是与中断有关的的设备的ASCII文本表示。

3)、参数dev用于共享中断线。

3、一个中断例子

4、释放中断处理程序

1)、卸载驱动程序时,需要注销相应的中断处理程序,并释放中断线:

void free_irq(unsigned int irq, void *dev);

I、如果指定的中断线不是共享的,那么,该函数删除处理程序的同时将禁用这条中断线。

II、如果中断线是共享的,则仅删除dev所对应的处理程序,而这条中断线本省只有在删除了最后一个处理程序时才会被禁用。

五、编写中断处理程序

1、一个中断处理程序声明:

static irqreturn_t intr_hanler(int irq, void *dev);

I、此函数的类型与request_irq()参数中的healer所要求的参数类型匹配。

II、第一个参数irq就是处理程序要响应的中断的中断号。

III、第二个参数dev是一个用用指针,它与中断处理程序注册时传递给request_irq()的参数dev必须一致。

IV、中断处理程序的返回值类型是irqreturn_t。中断处理程序可能返回两个特殊值:IRQ_NONE和IRQ_HANDLED。

2、共享的中断处理程序

1)、共享的处理程序与非共享的处理程序在注册和运行方式上比较相似,但差异主要有一下三处:

I、request_irq()的参数flags必须设置IRQF_SHARED标志。

II、对于每个注册的中断处理程序来说,dev参数必须唯一。

III、中断处理程序必须能够区分它的设备是否产生了中断。

2)、指定IRQF_SHARED标志以调用request_irq()时,只有在以下两种情况才能够成功:

I、中断线当前未被注册。

II、在该线上的所有已注册处理程序都指定了IRQF_SHARED。

3、中断处理程序实例

六、中断上下文

1、当执行一个中断处理程序时,内核处于中断上下文中。

2、中断上下文具有较为严格的时间限制,因为它打断了其他的代码。中断上下文中的代码应当迅速、简洁、尽量不要使用循环去处理繁重的工作。

3、中断处理程序栈是一个配置选项。

七、中断处理机制的实现

1、中断处理系统在Linux中的实现非常依赖于体系结构,实现依赖于处理器、所使用的中断控制器的类型、体系结构的设计及及机器本身。

2、中断从硬件到内核的路由(P100 图7-1)

1)、在内核中,中断开始于预定义的入口点。对于每条中断线,处理器都会跳到对应的一个惟一的位置。

2)、初始入口点只是在栈中保存这个号,并存放当前寄存器的值;然后,内核调用函数do_IRQ()。

unsigend int do_IRQ(struct pt_regs regs)

3)、pt_regs结构包含原始寄存器的值。中断的值也会得以保存,所以,do_IRQ()可以将它提取出来。

4)、计算出中断号之后,do_IRQ()对所接收的中断进行应答,禁止这条线上的中断。

5)、接下来,do_IRQ()需要确保在这条中断线上有一个有效的处理程序,而且这个程序已经启动,但是当前并没有执行。如是如此,do_IRQ()就调用handle_IRQ_event()来

运行为这条中断线安装的中断处理程序。

八、/proc/interrupts

1、procfs是一个虚拟文件系统,它只存在内核内存中,一般安装于/proc目录。在procfs中读写文件都要调用内核函数,这些函数模拟从真实文件中读写。

九、中断控制

1、禁止和激活中断

1)、用于禁止当前处理器上的本地中断,随后又激活它们的语句为:

local_irq_disable();

local_irq_enable();

I、在X86中,local_irq_disable()仅仅是cli指令,local_irq_enable()仅仅是sti指令。cli和sti分别是对clear和set允许中断标志的会变调用。

II、如果在调用local_irq_disable()例程之前已经禁止了中断,那么该例程往往会带来潜在的危险;同样相应的local_irq_enable()例程也存在潜在危险。

2)、在禁止中断之前保存中断系统的状态会更加安全一些。相反,在准备激活中断时,只需要把中断恢复到他们原来的状态:

unisgend long flags;

local_irq_save(flags);

/* . . . */

local_irq_restore(flags);

2、禁止指定中断

1)、对中断状态操作之前禁止设备中断的传递。LInux提供了四个接口:

void disable_irq(unsigned int irq);

void disable_irq_nosync(unsigned int irq);

void enable_irq(unsigned int irq);

void synchronize_irq(unsigned int irq);

I、disable_irq和disable_irq_nosync禁止中断控制器上指定的中断线,即禁止给定中断向系统所有处理器的传递。此外函数只有在当前正在执行的所有处理器程序完成

后,disable_irq才会返回。disable_irq_nosync不会等待当前中断处理程序执行完毕。

II、函数synchronize_irq等待一个特定的中断处理程序的退出。如果该处理程序正在执行,那么该函数必须退出之后才能返回。

III、这些函数可以嵌套。但是记住在一条指定的中断线上,对disable_irq和disable_irq_nosync的每次调用,都需要相应的调用一次enable_irq。

IV、以上函数可以从中断或进程上下文中调用,而且不会休眠。但是从中断上下文中调用必须注意。

2)、禁止多个中断处理程序共享的中断时不合适的。禁止中断线也就禁止了这条线上所有设备的中断传递。

3、中断系统的状态

1)、irqs_disable()定义在<asm/aystem.h>中。如果本地处理器上的中断系统被禁止,则它返回非0,否则返回0。

2)、在<linux/hardirq.h>中定义的两个宏提供一个用来检查内核的当前上下文的接口:

in_interrupt()

in_irq()

I、in_interrupt:如果内核处于任何类型的中断处理中,它返回非0,说明内核此刻正在执行中断处理程序或正在执行下半部处理程序。

II、in_irq:只有在内核确实正在执行中断处理程序时才会返回非0。

3)、中断控制方法列表(P106 表7-2)。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: