| |
|
开发:
C++知识库
Java知识库
JavaScript
Python
PHP知识库
人工智能
区块链
大数据
移动开发
嵌入式
开发工具
数据结构与算法
开发测试
游戏开发
网络协议
系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程 数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁 |
-> 系统运维 -> 一起分析Linux系统设计思想——05中断框架剖析(一) -> 正文阅读 |
|
[系统运维]一起分析Linux系统设计思想——05中断框架剖析(一) |
文章目录中断从哪里来,到哪里去?中断号是如何分配的?共享中断是如何实现的? 1 中断框架中断其实是很简单的概念,还能有多复杂呢?就是某一种类型来了,跳到指定的位置去执行对应的处理函数而已。 所以,万变不离其宗,千万不要被内核复杂的代码搞得晕头转向了。在看内核代码前一定要有自己的思路,然后再去看,看的时候和自己的思路对比,看看别人是如何实现的,对应上了就是看懂了,细枝末节不要太纠结,随着使用和工作中遇到的问题会逐渐明白的。 下面就让我们看看内核是如何“将中断这么简单的机制搞得非常复杂的”。 1.1 irq_descirq_desc是内核中断框架中的灵魂人物。irq_desc变量是一个结构体数组,每一个成员(也就是struct irq_desc结构体)对应一个中断号(一定要牢牢记住这一点,内核中好多数据结构都是类似的套路),并负责 管理 这个中断号。 irq_desc变量就定义在kernel/irq/handle.c中,是一个跨文件的全局变量。
struct irq_desc结构体定义在include/linux/irq.h中。 前文提到了 管理 ,那什么又叫管理呢? 管理就是控制中断的 状态 和 行为 。状态对应数据,行为对应函数/方法。所以,结构体定义中必然有对应的成员。
其中的status和name成员都比较好理解,那handle_irq、chip和action有什么用呢? 如果是我自己设计,我可能只会设计一个action函数指针。因为,无非就是中断来了之后我去执行action中指向的函数(该函数由用户提前注册好)去运行。 这种思路完全没有错,而且,我估计早期的内核可能就是这么实现的。但是,在实际使用过程中会遇到内核需要兼容多款芯片的问题,为了通用就必然会出现 分层 。和芯片强相关的操作(比如配置各种寄存器)放到chip中;和用户定义的流程相关的处理放到action中。机制和策略分离 ,机制在下层,策略在上层。 那handle_irq是干什么用的呢?它为什么也被分离出来了?该函数指针会根据不同的触发方式(比如边沿触发和电平触发)调用不同的处理方法。而不论用户定义的处理流程是什么,这个流程的处理是固定的,不变的,也就是公共部分,其实也可以归到机制一类中去。 那爱问问题的同学又问了,既然都是机制,那怎么不和chip放在一起?这个问题问的好。现在要祭出最最根本的思维方法和设计原则——一定要将易变的和稳定的部分分离;将导致变化原因不同的部分分离。我们本着这个原则再来看action、handle_irq和chip的划分就通透多了——action容易跟随业务变化;handle_irq跟随中断触发方式变化;chip跟随芯片类型变化。 考虑到这个层面才是真的通透了,所以,学习内核的目的不是看多少代码,而是要窥探大神们代码背后鬼斧神差般的思维! 1.2 irq_chip如果你理解了irq_desc的设计思想,那么接下来的内容基本都是知识型的了,没有什么难度了,我尽量减少篇幅。 struct irq_chip的定义如下。我们可以看到里面的成员大部分是函数指针(也就是接口),这些接口全部是和芯片打交道的,将内核移植到新的硬件平台需要关注这些接口的实现。 这个结构体的技术含量在于其接口定义的完备性,提取了所有芯片操作中断的共性,一半不是经验老手定义不了这么全。
1.3 handle_irq下面是irq_flow_handler_t的定义。在irq_desc中handle_irq成员一般都指向 handle_level_irq() 和 handle_edge_irq() 函数。
1.4 irqaction距离用户最近的成员就是irqaction了。
2 中断初始化任何一个模块一般都包括三个部分的代码—— 初始化代码 、 流程代码 和 控制代码 。 本小节先来分析中断的初始化。 我们可以猜想,初始化的工作肯定就是填充我们上一节分析的数据结构。 2.1 init_IRQ该函数被start_kernel函数调用,想要了解内核启动流程的同学可以看我之前写的内核启动的系列文章。
2.2 init_arch_irq我们跳到init_arch_irq的定义处,发现其是一个函数指针,这就导致我们的思路被打断了,需要我们再去看这个函数指针指向的到底是哪个函数。
接下来,我们需要找到init_arch_irq是在哪里初始化的。
我们看到init_arch_irq的赋值阶段也是在内核初始化时完成的,它指向的内容是mdesc->init_irq。这其实还是一个函数指针,mdesc结构体和和我们的芯片架构有关系。 对于S3C2440芯片来说,该结构体初始化的情况如下。至于是如何通过机器码定位到该结构体的请参看我之前的文章:03内核启动流程分析(八,uboot命令行参数获取),当然也可以先跳过该细节问题。
最终,我们锁定了S3C2440芯片对应的中断初始化函数为 s3c24xx_init_irq 。 2.3 s3c24xx_init_irq接下来中断初始化的BOSS终于登场了。 我们查看源码发现和我们先前猜想的是一样的,初始化的重点工作就是配置上一节的数据结构。
未完待续。。。
|
|
|
上一篇文章 下一篇文章 查看所有文章 |
|
开发:
C++知识库
Java知识库
JavaScript
Python
PHP知识库
人工智能
区块链
大数据
移动开发
嵌入式
开发工具
数据结构与算法
开发测试
游戏开发
网络协议
系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程 数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁 |
360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年12日历 | -2024/12/28 3:04:45- |
|
网站联系: qq:121756557 email:121756557@qq.com IT数码 |
数据统计 |