【linux】中断基础知识

中断基础知识

中断与中断函数

在linux中,中断处理程序就是普普通通的c函数,只不过这些函数必须按照特定的类型声明,以便内核能够以标准的方式传递处理程序的信息,在其他方面它们与一般的函数没有什么不同,中断处理程序与其他内核函数的真正区别在于中断处理程序是被内核调用来响应中断的。中断机制是硬件在需要的时候向cpu发出信号,cpu暂时停止正在运行的工作,来处理硬件请求的一种机制。

/proc/interrupts这个文件包含有哪些中断正在使用和每个处理器各被中断多少次的信息
在这里插入图片描述

举例16号

16: 0 198540 0 0 IO-APIC 16-fasteoi vmwgfx, snd_ens1371

中断号16的中断口,在cpu1上响应了198540个中断,其他三个cpu上响应了0次,链接在这个端口的中断链表上设备接口是IO-APIC-fasteoi

这个中断号是设备名为 vmwgfx, snd_ens1371的几个设备共享的。

IRQ与中断信号

每个能够发出中断请求的硬件设备控制器都有一条名为IRQ的输出线,所有现有的IRQ线都与一个名为可编程中断控制器的硬件电路的输入引脚相连,可编程中断控制器执行下列动作:

  1. 监视IRQ线,检查产生的信号,如果有两条或两条以上的IRQ线上产生了信号,就选择引脚编号比较小的IRQ线。
  2. 如果一个引发信号出现在IRQ线上:
  • a. 把接收到的引发信号转换成对应的向量。
  • b. 把这个向量存放在中断控制器的一个I/O端口,从而允许CPU通过数据总线读此向量。
  • c. 把引发向量发送到处理器的INTER引脚,即产生一个中断。
  • d. 等待,直到CPU通过把这个中断信号写进可编程中断控制器的一个I/O端口来确认它;当这种情况发生时,清INTER线。
  1. 返回到第一步。

中断向量描述符

中断向量是指中断发生以后,程序会按照中断类型执行不同的中断服务程序,这个中断向量就是这些中断处理函数的入口地址的变量。
具体为什么叫向量,我认为,中断是有优先级的,程序会按照优先级从高到低依次查询,突出一个方向性,所以叫向量。

CPU是根据中断号获取中断向量值,即对应中断服务程序的入口地址值。因此为了让CPU由中断号查找到对应的中断向量,就需要在内存中建立一张查询表,即中断向量表(在32位保护模式下该表称为中断描述符表)。80x86微机支持256个中断,对应每个中断需要安排一个中断服务程序。在80x86实模式运行方式下,每个中断向量由4字节组成。这4字节指明了一个中断服务程序的段值和段内偏移值。

中断描述表(IDT)是一个系统表,它与每一个中断或异常向量相联系,每一个向量在表中有相应的中断或异常处理程序的入口地址。IDT表可以驻留在线性地址空间的任何地方,处理器使用IDTR寄存器来定位IDT表的位置,这个寄存器中含有IDT表32位的基地址和16位的长度(限长)值,IDT表基地址应该对其在8字节边界上以提高处理器的访问效率,限长值是以字节为单位的IDT表的长度。其中每一个表项叫做门描述符,“门”的含义是当中断发生时必须先通过这些门,然后才能进入相应的处理程序。

在这里插入图片描述

中断号查询简要步骤

计算机内存的前1024个字节(偏移量00000H到003FFH)保存着256个中断向量,每个中断向量占4个字节,前两个字节保存着中断服务程序的入口地址偏移量,后两个字节保存着中断程序的入口段地址,使用时,只要将它们分别调入寄存器IP及CS中,就可以转入中断服务程序实现中断调用。每当中断发生时,CPU将中断号乘以4,在中断向量表中得到该中断向量地址,进而获得IP及CS值,从而转到中断服务程序的入口地址,调用中断。这就是中断服务程序通过中断号调用的基本过程。在计算机启动的时候,BIOS将基本的中断填入中断向量表,当DOS得到系统控制权后,它又要将一些中断向量填入表中,还要修改一部分BIOS的中断向量。有一部分中断向量是系统为用户保留的,如60H到67H号中断,用户可以将自己的中断服务程序写入这些中断向量中。不仅如此,用户还可以自己更改和完善系统已有的中断向量。

中断类型

中断一般分为异步中断(通常由硬件引起)和同步中断(一般由处理器本身引起)。

**异步中断:**CPU处理中断的时间过长,所以先将硬件复位,使硬件可以继续自己的工作,然后再使得当时候处理中断请求中耗时的部分。

网卡的工作原理(异步中断)

  1. 网卡收到数据包后,向CPU发出中断信号,请求处理接收的的数据包。
  2. CPU将收到的数据包拷贝到内存后,即通知网卡继续工作。
  3. 至于数据包拷贝到内存后的处理会在适当的时候进行。

**同步中断:**CPU处理完中断请求的所有工作后才反馈硬件

系统异常处理(比如运算中的除0操作)

  1. 应用程序出现异常后,需要内核来处理
  2. 内核调用相应的异常处理函数来处理异常
  3. 处理完后终止应用程序或给出message

中断相关函数

实现一个中断,主要需要知道3个函数:

  • 注册中断的函数
  • 释放中断的函数
  • 中断处理程序的声明

注册中断的函数,在内核<linux/interrupt.h>

/*
irg        -表示要分配的中断号
handler    -实际的中断处理程序
flags      -标志位,表示此中断的具有特性
name       -中断设备名称的ASCII表示,会被/proc/irg和/proc/interruputs文件使用
dev        -用于共享中断线,多个中断程序共享一个中断线时(共用一个中断信号),依靠dev来区别各个中断程序
*/
request_irq(unsigned int irq, irq_handler_t handler, unsigned long flags,
	    const char *name, void *dev);

中断处理机制,主要涉及3个函数

do_IRQ与体系结构有关,对所接收的中断进行应答

handle_IRQ_event调用中断线上所有中断处理

ret_from_intr恢复寄存器,将内核恢复到中断前的状态

处理流程如下:
在这里插入图片描述

在内核中,中断开始于预定于入口点,这类似于系统调用通过预定于的异常句柄进入内核,对于每条中断线,处理器都会跳到对应的一个唯一的位置,这样内核就可知道所接收到的IRQ号了,初始入口点只是在栈中保存这个号,并存放当前寄存器的值,然后内核调用函数do_IRQ()。

do_IRQ()声明如下:

unsigned int do_IRQ(struct pt_regs regs)

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

接下来,do_IRQ()需要确保在这条中断线上有一个有效的处理程序,而且这个程序已经启动,但是当前并没有执行,如果存在该已启动且尚未执行的处理程序,do_IRQ()就调用handle_IRQ_event()来运行这条中断线上所安装的中断处理程序。kernel/irq/handle.c

irqreturn_t handle_IRQ_event(unsigned int irq, struct irqaction *action)
{
	irqreturn_t ret, retval = IRQ_NONE;
	unsigned int status = 0;

	if (!(action->flags & IRQF_DISABLED))
		local_irq_enable_in_hardirq();

	do {
		trace_irq_handler_entry(irq, action);
		ret = action->handler(irq, action->dev_id);
		trace_irq_handler_exit(irq, action, ret);

		switch (ret) {
		case IRQ_WAKE_THREAD:
			/*
			 * 把返回值设置为已处理,以便可疑的检查不再触发
			 */
			ret = IRQ_HANDLED;

			/*
			 * 捕获返回值为WAKE_THREAD的驱动程序,但是并不创建一个线程函数
			 */
			if (unlikely(!action->thread_fn)) {
				warn_no_thread(irq, action);
				break;
			}

			/*
			 * 为这次中断唤醒处理线程,万一线程崩溃且杀死,我们仅仅假装已经处理了该中断,上述的硬件中断处理程序已经禁止设备中断,因此杜绝irq的产生。
			 * storm is lurking.
			 */
			if (likely(!test_bit(IRQTF_DIED,
					     &action->thread_flags))) {
				set_bit(IRQTF_RUNTHREAD, &action->thread_flags);
				wake_up_process(action->thread);
			}

			/* Fall through to add to randomness */
		case IRQ_HANDLED:
			status |= action->flags;
			break;

		default:
			break;
		}

		retval |= ret;
		action = action->next;
	} while (action);

	if (status & IRQF_SAMPLE_RANDOM)
		add_interrupt_randomness(irq);
	local_irq_disable();

	return retval;
}

#ifndef CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ

#ifdef CONFIG_ENABLE_WARN_DEPRECATED
# warning __do_IRQ is deprecated. Please convert to proper flow handlers
#endif

中断上下文

中断上文:硬件通过中断触发信号,导致内核调用中断处理程序,进入内核空间中,硬件的一些变量和参数也要传递给内核,内核通过这些参数进行中断处理,中断上文可以看着就是硬件传递过来的这些参数和内核需要保存的一些其他环境。

中断下文:执行在内核空间的中断服务程序。

中断上下文具有较为严格的时间限制,因为它打断了其他代码。中断上下文中的代码应当迅速、简洁,尽量不使用循环去处理繁重的工作。尽量把工作从中断处理程序中分离出来,放在下半部来执行,因为下半部可以在更合适的时间运行。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
### 回答1: 在开发 Linux 驱动程序时,您应该掌握以下基础知识: 1. Linux 内核架构:了解 Linux 内核的整体架构,包括内核的启动流程、内存管理、进程管理、文件系统等。 2. C 语言编程:Linux 驱动程序通常使用 C 语言编写,因此应该熟练掌握 C 语言的语法和基本编程技巧。 3. Linux 内核编程:了解 Linux 内核提供的 API 和数据结构,以及如何使用这些 API 和数据结构开发驱动程序。 4. 硬件知识:开发驱动程序时,您需要了解所支持的硬件的工作原理和数据通信协议。 5. 调试技巧:在开发驱动程序时,经常需要使用调试工具来查找问题,因此应该掌握常用的调试技巧。 ### 回答2: 要设计和编写Linux驱动程序,需要掌握以下基础知识: 1. Linux操作系统内核知识:要理解驱动程序的设计和工作原理,需要对Linux操作系统内核有一定的了解。这包括进程管理、内存管理、文件系统、设备驱动框架等。 2. C编程语言:驱动程序是用C语言编写的,所以需要熟悉C语言的语法和特性。同时,还需要了解内存管理、指针操作、结构体、位运算等与驱动程序相关的C语言知识。 3. 设备驱动的概念和原理:了解设备驱动程序的基本概念和工作原理,包括设备文件、设备文件操作方法、设备注册和注销、设备的初始化和资源分配等。 4. 硬件和总线知识:驱动设计需要了解设备硬件的工作原理和配置,以及相应的总线架构和协议。这有助于驱动程序与硬件之间的交互和通信。 5. 中断和时钟:驱动程序常常要处理设备的中断信号和时钟信号,因此需要了解中断处理程序的编写方法,以及如何使用时钟来进行计时和同步。 6. 调试和故障排除:设计和开发驱动程序时,经常会遇到问题和错误。掌握调试和故障排除的技巧,如使用调试工具、分析日志等,有助于解决问题并改进驱动程序的性能和稳定性。 总而言之,Linux驱动设计需要对Linux操作系统内核知识、C编程语言、设备驱动概念和原理、硬件和总线知识、中断和时钟等有一定的基础知识。这些知识将帮助工程师设计、实现和调试高效、稳定的Linux驱动程序。 ### 回答3: Linux驱动设计需要掌握以下基础知识: 1. 操作系统基础知识:了解操作系统的概念、架构以及对驱动程序的要求。熟悉Linux内核的工作原理、进程管理、内存管理和设备管理等基础知识。 2. C语言编程:熟练掌握C语言,因为Linux内核主要是由C语言编写的。掌握指针操作、数据结构、内存管理和函数调用等基本概念。 3. 设备驱动原理:了解设备驱动程序的基本原理,包括设备的访问方式、中断处理和数据传输等。理解驱动程序和硬件设备之间的交互过程。 4. 文件系统:了解Linux文件系统的基本概念和结构,掌握文件读写操作、文件系统和设备驱动之间的关系。熟悉虚拟文件系统(VFS)接口。 5. 网络编程:如果需要设计网络设备驱动,需要了解网络编程的基本概念,包括网络协议、套接字编程等。熟悉网络设备的配置和管理。 6. 调试技能:掌握调试工具和技术,如GDB调试器和内核调试器。能够使用这些工具定位和解决驱动程序中的问题。 7. 内核编程:了解Linux内核编程的基本原理和技巧,熟悉内核模块的编写和加载,能够编写和修改内核代码。 8. 设备文档:掌握设备的技术文档和规范,包括设备寄存器的配置和控制。正确理解设备文档对驱动程序的要求和限制。 总之,Linux驱动设计需要对操作系统、编程语言、设备原理、文件系统和网络编程等多个方面有深入的了解和掌握。同时,良好的调试技能和对设备文档的正确理解也是非常重要的。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

董lucky

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值