当前课程知识点:Linux 内核分析与应用 >  第5章 中断 >  5.5 动手实践-中断上半部的代码分析及应用 >  Video

返回《Linux 内核分析与应用》慕课在线视频课程列表

Video在线视频

Video

下一节:Video

返回《Linux 内核分析与应用》慕课在线视频列表

Video课程教案、知识点、字幕

大家好 本节视频来给大家演示一下简单的中断程序

中断常见的应用是在设备驱动程序中 例如我们的鼠标键盘

每次我们的点按都会产生一个中断 从而让计算机识别

这个实验是我们自己虚拟出来一个设备

将这个设备注册到系统之中

之后我们使用自己编写的中断服务例程 来使用中断

首先我们来看一下当前系统中的中断

这就是我们系统中当前的中断

第一列是我们的IRQ序号

CPU0和CPU1分别是

当前CPU上发生中断的一个次数

下一个是我们的中断控制器名称 下来是我们的设备名称

由中断的知识我们可以知道 我们要写一个中断程序

那么就需要申请一根中断线

一个中断线又对应一个IRQ号

在这里我们选择使用1号中断线 和i8042共用一条中断线

由中断的知识我们知道 我们要写一个中断程序

就必须要申请一根中断线 我们来看一下我们的程序

在我们的程序中 首先定义了一个IRQ号 也定义了一个设备名称

接下来这两个是用来让我们可以在命令行传入参数

在这里需要注意我们的参数 这里是charp 相当于char *

是字符指针 接下来定义我们的dev_id

这个主要是用在共享IRQ中

我们首先来看模块注册函数

在我们的模块注册函数中 最重要的工作就是

注册中断线 并将我们自己写的中断服务例程注册进去

这个工作是由request_irq函数来完成的

我们在源码中查看一下request_irq

这个函数是在

这个函数是在include-linux下的interrupt.h文件中

首先我们来介绍一下参数

第一个参数IRQ也就是中断号 对应的就是中断控制器上

IRQ的编号 也就是一开始在中断中看到的

第二个参数是handler 也就是我们要注册的中断服务例程

需要我们自己来实现

它有一个特定类型的返回值irqreturn_t

这个类型可以在irqreturn.h文件中找到

也就是这里

下一个参数是flag

它指定了快速中断或者中断共享中中断的处理属性

在这里我们对flag的取值是IRQ_SHARED

也就是允许共享了 好我们来返回函数

接下来的一个参数是name

它是设备名称 也就是我们刚刚中断中使用的

cat interrupt命令来查看的最后一列

最后一个参数是dev_id 主要用于共享中断线

注意这个参数的类型是void

也就是说可以使用强制类型转换为任意类型

可以作为共享中断时中断区别的一个参数

好 我们来进入这个函数

实际上这个函数调用了request_threaded_irq函数

这个函数在kernel/irq/manage.c中 我们进入

这里首先定义了两个非常重要的结构体

一个是irq_action 一个是irq_desc

接下来进行一系列的判断

之后会执行这一行

这一行是根据中断号irq

在irq_desc数组中

返回一个具体的irq_desc

实际上我们的注册

就是将我们传进来的参数生成一个action

再添加到irq_desc上

具体是通过这个函数来进行的

那么既然有注册 我们就有对应的注销函数

我们将注销函数放到了模块的退出函数中

free_irq() 我们来在源码中查看

还是在manage.c文件中 我们来查找

我们也可以看到主要是进行了这一行函数

之后会释放掉我们的action

接下来我们分析一下中断服务例程

在这里我们给自己的中断服务例程起名为myirq_handler

对应的名字我们要和注册中使用的名字是一致的

在我们的irq_handler中实际上也是一个计数

也就是进入中断一次 我们count就加一

之后我们返回的是一个IRQ_HANDLED

前面说到这里返回的值

代表接受到了准确的中断信号并且做了相应的正确的处理

到此为止我们的模块就写完了

那么之后就需要插入模块

只要1号中断线上发生了中断 不管谁发出的

都会执行我们的中断服务例程

接下来我们来编译我们的代码

来插入我们的模块

在这里我们需要给我们程序中irq和devname赋值

我们来查看一下中断情况

这里看到我们已经将我们的设备挂到了

1号中断线上 我们来看一下日志信息

可以看到程序正确的运行了

每进入一次中断就会显示一些信息

我们来退出模块

模块已经正确退出了

这个实验只是让我们简单体验了一下中断的程序

实际上我们可以从源代码中来验证

我们在理论课中学到的知识

从中断的发生到真正执行到我们的中断服务例程

中间的过程是怎么样的

这实际上是一个非常复杂的过程

如果要追根溯源的话 可以从内核的

初始化开始 其实这个过程是非常有意思的 我们可以找到我们的

内核中的main函数

从初始化我们的中断到真正执行我们的中断服务例程

那我们在这里就从do_IRQ函数来看起

我们每次进入do_IRQ函数是从汇编的代码中跳入

可以说发生了中断之后

do_IRQ是我们执行的第一个C语言函数

我们就从这里开始分析

这里的代码和体系结构息息相关

我们的do_IRQ函数位于根目录下arch中

x86文件夹下kernel文件夹下

的irq.c文件中

我们来搜索

首先在注释部分 do_IRQ处理所有普通设备的中断

这个函数实际上

最核心的部分是执行handle_irq函数

从这个函数中进入 执行后再返回到

这个函数中来

好 我们来进入handle_irq函数

那在这里我们选择进入irq_64

因为我们的系统是64位系统

这个文件位于arch下x86下kernel下的irq_64.c文件中

实际上我们也可以发现在handle_irq函数中

实际上最后还是执行的这个函数

传入的参数是desc

也就是struct irq_desc类型的参数

我们来进入这个函数

那 这个函数位于include/linux/irqdesc.h

在这里就可以看的比较清晰 实际上最后就是在执行

desc下的handle_irq函数

这里我们需要说明一下

首先我们这里的函数是handle_irq 我们可以看到

实际上handler _irq是在

irq_desc结构中的

这个也是一个回调函数 它负责处理底层细节

比如中断确认 边沿触发以及电平触发的处理

最后再由这个函数调用

我们irqaction中的handler

实际上这里的handler才是我们想要的中断服务例程

那我们这里就以APIC的注册为例

来看一下handle_irq中回调的是哪一个函数

好我们来进入源码

我们进入的目录是arch/x86下

kernel/apic/目录下

/io_apic.c文件

我们在这里可以找到handle_irq的

挂载过程 我们来搜索

好 就是这个函数

我们可以在这个函数的最后两行可以看到它其实在这里进行一个选择

是哪种方式

我们后面将会以这种方式来进行 是边沿触发的方式来进行分析

那实际上执行的还是这个函数

好 我们来进入这个函数

位于kernel/irq/chip.c文件中

那接下来会进入irq_do_set_handler函数 我们来进入

好 这个函数实际上

它比较长 它会有一系列的判断

最关键的一个语句是这句

也就是将我们的handle挂载到了handle_irq上

那我们在这里我们以handle_edge_irq为例来分析

首先也是在这个文件中进行搜索

我们在这个函数中

我们就可以找到

非常重要的一个函数就是handle_irq_event这个函数

好 我们来进入

它是在kernel/irq/handle.c文件中

那实际上这个函数执行的最主要的函数是这句

我们来进入

接下来会进入这个函数

好 我们其实在这个函数中就实现了依次执行我们

这条中断线上所有的中断服务例程

就是通过这一个宏来实现的

首先执行我们的中断服务例程函数的是这句

那对应的返回值是给了res

在后面可以在switch语句中看到

res的两个参数是这个和这个

我们刚刚返回的是IRQ_HANDLED

那我们来看一下这个宏

它是位于kernel/irq/internals.h中

我们可以很清晰的看到

其实这就是一个for循环在进行遍历

就是对desc中的action

这里是action的下一个

我们可以把我们刚刚所说的过程进行一个小结

呢首先呢我们是在

汇编代码中进入到了do_IRQ函数

这个是对应的32位系统 这个对应的是64位系统

那接下来会执行do_IRQ和handle_irq

最后执行这个函数的结果呢

是执行handle_irq 也就对应的是这里的函数

之后这里的函数会回调上一个函数

那我们在这里是以handle_edge_irq为例

那么一层一层调用

调用到最后才执行了我们的中断服务例程中

好 这就是整体的一个过程

好 关于第一个实验我们就分析到这里 谢谢大家

Linux 内核分析与应用课程列表:

第1章 概述

-1.1 Linux操作系统概述

--1.1 Linux 操作系统概述

-1.2 Linux内核结构以及内核模块编程

--Video

-1.3 Linux内核源码中的双链表结构

--Video

-1.4 源码分析-内核中的哈希表

--Video

-1.5 动手实践-Linux内核模块的插入和删除

--Video

-第1章 概述--章节测验

-第1章导学--引领你进入Linux内核的大门

第2章 内存寻址

-2.1 内存管理之内存寻址

--Video

-2.2 段机制

--Video

-2.3分页机制

--Video

-2.4 动手实践-把虚拟地址转换成物理地址

--Video

-第2章 内存寻址--章节测验

-第二章导学-从零打造自己的操作系统

第3章 进程管理

-3.1 进程概述

--Video

-3.2 Linux进程创建

--Video

-3.3 Linux进程调度

--Video

-3.4 动手实践-打印进程描述符task_struct中的字段

--Video

-3.5工程实践-基于内核模块的负载监控

--Video

-第3章 进程管理--章节测验

-第三章导学-进程背后琳琅满目的宝贝到哪里挖?

第4章 内存管理

-4.1 Linux内存管理机制

--Video

-4.2 进程用户空间管理机制

--Video

-4.3 物理内存分配与回收机制(上)

--Video

-4.4 物理内存分配与回收机制(下)

--Video

-4.5 动手实践-Linux内存映射基础(上)

--Video

-4.6 动手实践-Linux内存映射实现(中)

--Video

-4.7 动手实践-Linux内存映射测试(下)

--Video

-4.8 初学者对内存管理的常见疑惑

--初学者对内存管理的常见疑惑(一)

--初学者对内存管理的常见疑惑(二)

--初学者对内存管理的常见疑惑(三)

-第4章 内存管理--章节测验

第5章 中断

-5.1 中断机制概述

--Video

-5.2 中断处理机制

--Video

-5.3 中断下半部处理机制

--Video

-5.4 时钟中断机制

--Video

-5.5 动手实践-中断上半部的代码分析及应用

--Video

-5.6 动手实践-中断下半部的代码分析及应用

--Video

-第5章 中断--章节测验

第6章 系统调用

-6.1 Linux中的各种API

--Video

-6.2 系统调用机制

--Video

-6.3 动手实践-添加系统调用(系统调用日志收集系统)

--Video

-第6章 系统调用--章节测验

第7章 内核同步

-7.1 内核同步概述

--Video

-7.2 内核同步机制

--Video

-7.3 动手实践-内核多任务并发实例(上)

--Video

-7.4 动手实践-内核多任务并发实例(下)

--Video

-第7章 内核同步--章节测验

第8章 文件系统

-8.1 虚拟文件系统的引入

--Video

-8.2 虚拟文件系统的主要数据结构

--Video

-8.3 文件系统中的各种缓存

--Video

-8.4 页高速缓存机制以及读写

--Video

-8.5 动手实践-编写一个文件系统(上)

--Video

-8.6 动手实践-编写一个文件系统(中)

--Video

-8.7 动手实践-编写一个文件系统(下)

--Video

-第8章 文件系统--章节测验

第9章 设备驱动

-9.1 设备驱动概述

--Video

-9.2 I/O空间管理

--Video

-9.3 设备驱动模型

--Video

-9.4 字符设备驱动程序简介

--Video

-9.5 块设备驱动程序简介

--Video

-9.6 动手实践-编写字符设备驱动程序

--Video

-9.7工程实践-编写块设备驱动的基础(上)

--Video

-9.8 工程实践-块设备驱动程序分析(中)

--Video

-9.9 工程实践-块设备驱动程序实现(下)

--Video

-第9章 设备驱动--章节测验

致谢与说明

-致谢与说明

--Video

直播视频:从Linux内核学习到自主操作系统研发

-从Linux内核学习到自主操作系统研发

附录:实验代码、课件以及相关素材

-各章实验代码

-《Linux内核分析与应用》课件

-《Linux操作系统原理与应用》教材课堂视频

Video笔记与讨论

也许你还感兴趣的课程:

© 柠檬大学-慕课导航 课程版权归原始院校所有,
本网站仅通过互联网进行慕课课程索引,不提供在线课程学习和视频,请同学们点击报名到课程提供网站进行学习。