maxleng
Android爱好者,长期从事嵌入式系统研究,手机软件系统研究。
本博全为原创,转载请注明出处。
展开
-
从零开始理解Linux中断架构(25)中断运行全景实例
前面我们基本理解了软中断处理的基本框架,为了对中断调用有一个全景的直观感受,我们在网卡驱动程序的中断函数dump_stack,观看一下各种情况下的软中断调用call Stack的情况。(1)ksoftirqd处理软中断的情况(2)irq_exit退出时处理软中断的场景,就是那个小尾巴(3)__local_bh_enable_ip执行软中断的场景(4)NAPI模式驱动全貌(网卡驱动)该图中,我们可以看到网卡驱动是如何使用软中断来处理网络数据包的,通过该图对于中断处理也有个全方位的理解。原创 2023-08-12 19:29:25 · 316 阅读 · 0 评论 -
从零开始理解Linux中断架构(24)软中断核心函数__do_softirq
处理软中断期间时还会进入新的硬中断,从而带进新的软中断需要处理,如果同一中断频繁产生,系统会在local_softirq_pending()上的同一未决标志上重复置位,这里会造成软中断丢失。让in_interrupt检查条件为真,进入软中断处理临界区,后面进来的处理请求,需要检查in_interrupt(),从而达到禁止本cpu上的软中断嵌套的目的。__do_softirq可能是要挂在irq_exit小尾巴上跑的,还需要尽快的退出异常处理流程,避免让系统老是回不到应用态执行应用线程。原创 2023-08-04 22:05:12 · 364 阅读 · 0 评论 -
从零开始理解Linux中断架构(23)中断运行临界区和占先调度
只需要判断in_interrupt(),看看这个中断运行临界区是否被占领,如果已经被占领了,说明前一个软中断处理处于被打断状态,后面的就不进去了,就可以保证__do_softirq()不会在同一Core嵌套调用。前面的中断临界区相关的函数:in_interrupt,in_irq等都使用到了preempt_count,这个preempt到底是个什么东西呢?in_interrupt在驱动中使用频率最高的函数了,in_interrupt()就是指示Core是否正在中断处理中,包含了硬中断,软中断运行临界区。原创 2023-07-29 09:46:35 · 914 阅读 · 0 评论 -
从零开始理解Linux中断架构(22)软中断处理框架
内核专门为软中断建立了内核线程(ksoftirqd)来处理软中断事务。在 smpboot.c中,设计一个hotplug thread线程框架,集中管理boot_threads的启动。软中断的内核处理线程ksoftirqd就只依托这个线程框架建立的。软中断处理线程的代码都在kernel/softirq.c,在内核初始化时(kenel_init),spawn_ksoftirqd根据softirq_threads描述,为每个CPU建立ksoftirqd/x软中断线程。原创 2023-07-24 22:53:52 · 173 阅读 · 0 评论 -
从零开始理解Linux中断架构(21)软中断之基本理念
在Linux内核中,软中断是一种在内核空间中执行的中断处理方式,与硬件中断不同,软中断不是由硬件设备触发的,而是由内核软件产生的。在内核中,软中断被用于执行一些高优先级的任务,如网络数据包处理、定时器处理等。原创 2023-07-22 14:34:35 · 90 阅读 · 0 评论 -
从零开始理解Linux中断架构(19)--中断线程化irq_thread
handler主中断处理例程,运行hard_irq 流程上。所谓的中断线程化就是设备注册的主handler也会运行在内核线程上,此时的中断的irqaction->handler指向了irq_default_primary_handler,他不会做任何处理,只是以IRQ_WAKE_THREAD返回,以便后续代码唤醒对应的irq_thread线程。编译时如果定义了CONFIG_IRQ_FORCED_THREADING,参数irqflags不包含IRQF_NO_THREAD中断Action都将强制线程化处理。原创 2023-07-15 10:21:31 · 545 阅读 · 0 评论 -
从零开始理解Linux中断架构(18)--中断流处理
④在全局中段描述符树irq_desc_tree中找的77对应的中断描述符:irq_desc[77]。kernel初始化中断控制器(gic v3)时,调用set_handle_irq(gic_handle_irq),将gic_handle_irq赋予handle_arch_irq,为中断处理进入C语言第一跳建立了跳板。handler代表的是主Handler,运行在硬中断流程上,thread_fn代表的是要创建的中断线程的入口函数,thread_fn如果不为NULL,系统会创建一个内核线程来处理该中断。原创 2023-07-08 16:38:57 · 291 阅读 · 0 评论 -
从零开始理解Linux中断架构(17)--设备中断处理函数
现在达到了最后一步,给中断源安装上设备层级的中断处理函数,这个是每个具体设备驱动需要做的核心工作,每个device probe 时,驱动程序会初始本设备的寄存器和使用@manage.c注册设备自己相关的中断处理函数。设备中断处理函数的运行位置如下图的红色箭头所指的地方,我们就从宏观上的理解到了设备级中断处理函数的运行位置:dev specific handler指示的位置。原创 2023-07-06 21:19:46 · 256 阅读 · 0 评论 -
从零开始理解Linux中断架构(16)--Linux中断映射
linux系统中维护的全局allocated_irqs,从allocated_irqs的低位到高位查询第一个连续N个空闲的位作为软件中断号,每一位代表该位序号对应的软件中断号是否已经分配。系统会调用bitmap_find_next_zero_area() 从allocated_irqs中找到第一个空闲位 start作为软件中断号。of_irq_parse_one会将dts中的中断信息进行解析,并建立如上图的逻辑关系。irq_desc_tree利用irq作为key来存储irq_desc对象,节点动态生成。原创 2023-07-04 21:06:24 · 685 阅读 · 0 评论 -
从零开始理解Linux中断架构(15)--Linux GIC控制初始化
GICv3要求Core处理完中断后,必须通知中断控制器中断处理完成,以便GIC维护中断状态机。GICv3架构将中断的完成分为2个阶段:Priority Drop和Deactivation。(1)原创 2023-07-03 20:46:32 · 319 阅读 · 0 评论 -
从零开始理解Linux中断架构(14)--Linux硬中断管理设计理念
将中断控制硬件控制抽象统一的中断控制器抽象结构,把中断处理系统框架设计成通用框架,让中断处理过程设计成跟体系结构无关,跟中断控制器无关的运行框架,以便系统新添加中断控制器支持时,只需要填写irq_chip.结构这类chip-level specific 的相关工作。不同种类和厂家的中断控制器的访问是不同的,为了隐藏这些差异,Linux内核抽象化了中断控制器操作,定义了统一的中断控制器描述符,每种中断控制器自定义各种操作函数,来隐藏操作细节。中断域还需要管理中断控制器级联时,中断处理链条的传递。原创 2023-07-02 17:29:02 · 290 阅读 · 0 评论 -
从零开始理解Linux中断架构(12)--硬中断之中断控制器(GICV3)
Inactive中断未被触发Pending(待处理)中断已经被硬件触发,GIC回将IAR寄存器中相应的位置1,但cpu还没有应答中断,在这个阶段称为Pending。Active(处理中)CPU已经应答(acknowledge)了该中断请求,并且正在处理中前一个中断已经响应了,同一中断源又触发了中断,后一个中断进入pending状态ICv3中断控制器状态切换过程如下:①中断源没有被触发的时候,处于初始的"原创 2023-06-27 21:17:12 · 524 阅读 · 0 评论 -
从零开始理解Linux中断架构(11)---中断屏蔽与开启
当PE发起AArch64执行状态的一个异常,所有的PSTATE中断自动屏蔽。这意味着此后的中断是禁用的。如果软件是支持嵌套的异常,例如,允许一个更高的优先级中断打断处理一个低优先级的来源,那么需要中断处理程序显式地开启中断。(3)在内核态发生的el1_irq有有占先任务调度的情况,当前任务被调度前打开中断。我们前面的阶段介绍了中断程序的外围工作,外围工作保证在硬中断处理阶段中断是关闭的,“至于中断处理阶段到底打开了中断没有,还的看看具体的设备级中断处理函数个性行为。中断被屏蔽“区只是从外围的角度去看的,原创 2023-06-27 18:12:17 · 234 阅读 · 0 评论 -
从零开始理解Linux中断架构(10)---上下文切换长征路
#10线程需要被调度到#15,pre=#10,next=#15,el0_sync_10执行schedule,将执行流切到了el0_irq_15,此时栈指针SP_EL1指向了#15系统堆栈,el0_irq_15开始执行收尾工作。15#被挂起,中断上下文(pt_regs)存在它的内核栈底部,与他对应的执行流el0_irq_15挂在switch point上,返回信息存储在15#任务的cpu_context上。10#进程为用户态当前运行,SP_EL1指向它的内核栈底部,SP_EL0指向应用程序堆栈。原创 2023-06-26 20:35:55 · 275 阅读 · 0 评论 -
从零开始理解Linux中断架构(9)---异常执行流与调度
线程的管理在内核中有显式的管理实体(task_struct object),但是对于el0_irq,el0_sync,el1_irq,el1_sync这类handler就没有显式的管理,如下图的el1_irq,代码看起来比较好理解,但是深入了解后,会发现在这函数里经历了很多的堆栈切换,但是el1_irq的存续并没有一个专门的内存结构去存储他的状态,被当成了当前线程的延伸段去处理,把上下文存储在了当前任务的cpu_conext,这就会造成理解的困难。如果需要调度,调度器会选择下一个进程,并且进行进程的切换。原创 2023-06-26 19:53:20 · 830 阅读 · 0 评论 -
从零开始理解Linux中断架构(8)---执行上下文之CPU上下文
实际上这里使用了一个隐含的事实:Linux所有的任务切换都是在内核中__switch_to函数中进行的,当前任务通过__switch_to->cpu_switch_to切换到(next)。这个过程相对于__switch_to来讲相当于从cpu_switch_to子函数调用返回,不管调度出去多久,寄存器被修改了多少,从__switch_to层面看就是觉得cpu_switch_to执行的时间变成有点长,只是要求这里只需要cpu_switch_to遵循。跟__switch_to是否进行了任务切换一点关系都没有。原创 2023-06-25 16:24:11 · 352 阅读 · 0 评论 -
从零开始理解Linux中断架构(7)--- Linux执行上下文之中断上下文
当前运行的loop是一条执行流,中断程序运行开启了另外一条执行流,从上一节得知这是三种跳转的第三类,这个是一个大跳转。对中断程序的基本要求就是,除了时间流逝外,原来运行的程序应该毫无感知。具体到Armv8架构,中断上下文要保存就是X0-X30。X30是LR寄存器。Armv8在exception发起后,PE做了一些前提工作:(1) CPU core感知到异常发生,生成一个目标异常等级(2) 把PSTATE寄存器里的值保存到对应目标异常等级的SPSR_ELx寄存器便于恢复时使用。原创 2023-06-24 17:13:29 · 724 阅读 · 0 评论 -
从零开始理解Linux中断架构(13)--Linux中断域
由于计算机系统日益复杂,外设中断数量不断增加,系统可能同时需要多个中断控制器进行级联,中断源需要统一管理,面对这样的状况,Linux对各种中断控制器进行抽象,对如何进行硬件中断号到IRQ number映射关系上进行进一步抽象出通用与设备无关的架构,通用中断处理代码中就有了irq domain的出现。对于每个中断控制器都可以连接若干个外设的中断请求,中断控制器会对连接其上的中断源进行编号,这个编号(1,2,3,...N)仅在中断控制器仅限制在本范围内。原创 2023-06-28 22:43:34 · 239 阅读 · 0 评论 -
从零开始理解Linux中断架构(6)---Linux执行上下文
上面图中上帝视角的PC指针已经不是应用小“我“看到的那样在“小我逻辑连续“下转移,存在着很多大跳转的情况,这些大跳转早已脱离了下一条指令是“我”决定的条件,打破了小我的逻辑连续,跑到了“他“的逻辑地盘上去了,而这个大转移是操作系统这个“大我“的执行逻辑。PC指针被俘获体现出的本地性,让应用程序的执行逻辑产生了“我"(this)的感觉:CPU在忠实的执行我的代码,我决定了PC的下一条指令,各个运算的结果跟我的设计一致,我掌控了这一切。<对应>PC小跳转(顺序执行,无条件转移,条件转移,函数调用,函数返回)原创 2023-06-23 19:13:34 · 290 阅读 · 0 评论 -
从零开始理解Linux中断架构(5)--EL跃迁与Linux用户/内核态
这个就是Linux从内核态进入用户态最为本质的代码,最为底层的逻辑。如果先不考虑内存虚拟空间的切换概念,Linux内核态到用户态的切换,其实就是这么的简单。对比一下 图5-1, 图5-2标注红色的部分,就是这么简单的切换模型,完成了linux内核态到用户态的转换。svc支撑起了整个的系统调用让系统从用户态陷入内核态,eret支撑起了从内核态切入用户态的工作。有了前面的基本概念,我们来看看linux是如何包装使用这个最为简单的模型的,让系统从内核态->用户态的函数叫ret_to_user。原创 2023-06-22 15:22:11 · 668 阅读 · 0 评论 -
从零开始理解Linux中断架构(4)--学习几条ARM汇编指令
因为entry.S是使用汇编指令编写的。我们需要学习几条汇编,以便能够看懂entry.S来消除很多的底层疑惑。这里只需要理解基本的约定和寻址格式和几条常用的指令,达到能够读懂代码的目的就够了。原创 2023-06-18 21:56:15 · 331 阅读 · 0 评论 -
从零开始理解Linux中断架构(3)--Armv8体系架构
首先让我们带着问题进入到armv8架构的学习中。linux中断代码分为两部分entry.S @arch\arm64\kernel\entry.S汇编部分和C代码后续处理。汇编代码中处理最为低级的部分,设置硬件中断向量表,保持当前上下文,切换中断堆栈等任务,这是就如我们嵌入式系统看到那样。@arch\arm64\kernel\entry.S中对于中断向量表(vectors)的定义如下:一开始我也是看不懂这些代表什么,如果要彻底理解这张表,需要知道一点点ARMV8系统架构中的一些基本知识。PE,原创 2023-06-15 22:06:49 · 1650 阅读 · 1 评论 -
从零开始理解Linux中断架构(20)--关于二级中断控制-链式chained Handler
上级中断控制器链接的中断源(irq=17)handler_irq已经被EINT的中断控制器驱动改写成mtk_eint_irq_handler,而不再是原来的handle_fasteio_irq。链式(chained)级联方式里,上级中断控制器链接的中断源handler_irq是由当前的二级中断控制器驱动提供,irq_data.chip任然是上级的中断控制器chip对象,这就表明,中断开关和应答还是通过上级中断控制器进行。这个是典型的N->1的连接方式。他的连接也是一样,分为1->N的模式和1->1的模式。原创 2023-07-16 17:31:25 · 255 阅读 · 0 评论 -
从零开始理解Linux中断架构(2)-朴素的中断管理设计理念
不破除这些迷障,就达不到对系统的深刻理解,中断系统和CPU体系架构息息相关,我们AX3000 WIFI路由器使用的平台是MTK7981,基带是Arm Cortex-a53,系统架构是ArmV8。纯逻辑是跨越系统和应用的,不管对于应用程序员还是系统程序员,逻辑推导是基本的工具,设计原型是基本的出发点。在这个多任务情况下,如果允许抢占(preempt),中断程序执行完毕后,就不一定回到原来的那个任务,这里有一个调度点(schedule),系统会根据任务的优先级和任务等待情况来决定挑选那个任务出来运行。原创 2023-06-14 21:39:57 · 419 阅读 · 0 评论 -
从零开始理解Linux中断架构(1)-前言
前段时间在转行手撸WIFI路由器,搞wifi路由器需要理解网络驱动程序,以太网卡驱动程序,无线WIFI驱动程序,而网卡驱动的关键路径就在中断程序中,需要了解NIC设备驱动程序如何收发数据,为了彻底的知道数据包是如何二层传递上来的,又需要了解一点Linux中断系统。第一次看到这张表是无感的,大概能够看懂的就是那个中断次数,因为不停的cat,这个数值会一直不停的增加。第一列是逻辑中断号,第二三列是中断次数,第四列是中断控制器的名字,第五列是硬件中断号,第六列 中断类型,第七列是 中断源关联设备。原创 2023-06-14 14:45:03 · 739 阅读 · 0 评论