学习Linux系统中的子系统的一些思考 【gic driver 篇】
最近“兴趣来潮”,哈哈,就想来拆一下Linux 内核中断子系统的黑盒子。些有摸索,也算曲折;但收获颇丰。等你找到答案的时候,就像我一样,原来在这里。
蓦然回首,那人却在灯火阑珊处。
好废话不多讲,进入主题,要梳理清楚中断子系统有哪些模块,怎样关联起来。首先,你得有硬件吧,这是基础,其次有硬件,你应该就有驱动吧,有了驱动就会有应用接口吧。这些部分怎么一步步过来,听我马上道来。
我这里选的是GIC V3 + ARM64 【kernel5.10】的平台,具体的板级随便,大体的框架都是一样的。这里也提一下,刚开始的时候,你一定要掌握架构,点到为止,一旦入坑,可能难以回头,更甚找不到自己想要的答案。因为你会发现,所需背景知识太多太多,作为过来人的忠告。
我喜欢从底层硬件往上来看,那就先看CPU相关的文件,找到启动文件,找到中断向量入口,别问我为什么是这样,问就是这是定律。无论你是单片机,RTOS嵌入式系统,Linux系统都是一样的,记住就行。
//linux-5.10.223\arch\arm64\kernel entry.S
#找到这几个关键字
.macro el1_interrupt_handler, handler:req
/*
* EL1 mode handlers.
*/
.align 6
SYM_CODE_START_LOCAL_NOALIGN(el1_sync)
kernel_entry 1
mov x0, sp
bl el1_sync_handler
kernel_exit 1
SYM_CODE_END(el1_sync)
.align 6
SYM_CODE_START_LOCAL_NOALIGN(el1_irq)
kernel_entry 1
el1_interrupt_handler handle_arch_irq
kernel_exit 1
SYM_CODE_END(el1_irq)
好,到这里,汇编代码到此为止,前期你千万别先沉迷于此文件中。重点是el1_irq 的处理函数,
handle_arch_irq,这个函数在哪里了?那就需要看irq-gic-v3.c 文件了,路径是linux-5.10.223\drivers\irqchip。
找到handle_arch_irq 就好说了,它是一个函数指针(地址),它是怎么获取的了,如下图,
IRQCHIP_DECLARE(gic_v3, "arm,gic-v3", gic_of_init);
->gic_of_init(struct device_node *node, struct device_node *parent)
->gic_enable_of_quirks(node, gic_quirks, &gic_data);
->gic_init_bases
->init gic_data
->set_handle_irq(gic_handle_irq)
->handle_arch_irq =gic_handle_irq;
->gic_update_rdist_properties
->gic_dist_init
->gic_cpu_init
->gic_smp_init
->gic_cpu_pm_init
->gic_populate_ppi_partitions
上图是这段代码的一个调用关系图。从这里可以得到handle_arch_irq 函数指针的来源。
也就是以后有外设中断来,第一入口就是这里,下面再来看看handle_arch_irq 所指向的真正函数gic_handle_irq,它有哪些动作了,先上code,
gic_handle_irq
->irqnr = do_read_iar
->gic_pmr_mask_irqs
->gic_arch_enable_irqs
->isb
->handle_domain_irq(gic_data.domain, irqnr, regs)
->__handle_domain_irq(domain, hwirq, true, regs)
->old_regs = set_irq_regs(regs)
->irq_enter
->irq_find_mapping
->generic_handle_irq
->irq_exit
->set_irq_regs(old_regs)
generic_handle_irq //EXPORT_SYMBOL_GPL(generic_handle_irq)
->struct irq_desc *desc = irq_to_desc(irq)
->data = irq_desc_get_irq_data(desc)
->generic_handle_irq_desc(desc)
->desc->handle_irq(desc)
再上调用关系图,
详细的自行阅读代码,推荐大家一个好网址,在线看linux 源码。https://elixir.bootlin.com/linux/v6.10.3/source
至于基础的知识,比如GIC V3 spec, ARMV8 arch spec,我都有发文档在CSDN文库中。
GIC 的组件,Distributor,CPU interface,Redistributorb,我这里不做过多介绍,就贴出它们在spec的原文解释。
至于ARMv8的E0,E1,E2这些等级,也不做过多介绍,感兴趣同学可以自行了解。好了,今天就到此为止。