日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 运维知识 > linux >内容正文

linux

linux kernel中的中断处理流程

發(fā)布時(shí)間:2025/3/21 linux 35 豆豆
生活随笔 收集整理的這篇文章主要介紹了 linux kernel中的中断处理流程 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

目錄

        • 1、linux kernel arm32的中斷函數(shù)處理流程
          • (1)、irq_handler宏
          • (2)、arch_irq_handler_default 宏
          • (3)、調(diào)用了asm_do_IRQ
        • 2、linux kernel arm64的中斷函數(shù)處理流程
          • (1)、irq_handler宏 調(diào)用handle_arch_irq
          • (2)、handle_arch_irq
          • (3)、gic_handle_irq()
          • (4)、handle_domain_irq()---->__handle_domain_irq()---->generic_handle_irq()---->generic_handle_irq_desc()


★★★ 友情鏈接 : 個(gè)人博客導(dǎo)讀首頁—點(diǎn)擊此處 ★★★

1、linux kernel arm32的中斷函數(shù)處理流程

我們從irq_handler宏函數(shù)看起

(1)、irq_handler宏

注意CONFIG_MULTI_IRQ_HANDLER宏表示"允許每臺(tái)機(jī)器在運(yùn)行時(shí)指定它自己的IRQ處理程序",當(dāng)前默認(rèn)是不開啟的.
所以走else的arch_irq_handler_default邏輯

(arch/arm/kernel/entry-armV.S) /** Interrupt handling.*/.macro irq_handler #ifdef CONFIG_MULTI_IRQ_HANDLERldr r1, =handle_arch_irqmov r0, spbadr lr, 9997fldr pc, [r1] #elsearch_irq_handler_default #endif 9997:.endm
(2)、arch_irq_handler_default 宏

arch_irq_handler_default 宏 調(diào)用了asm_do_IRQ或do_IPI

(arch/arm/include/asr/entry-macro-multi.S) /** Interrupt handling. Preserves r7, r8, r9*/.macro arch_irq_handler_defaultget_irqnr_preamble r6, lr 1: get_irqnr_and_base r0, r2, r6, lrmovne r1, sp@@ routine called with r0 = irq number, r1 = struct pt_regs *@badrne lr, 1bbne asm_do_IRQ#ifdef CONFIG_SMP/** XXX** this macro assumes that irqstat (r2) and base (r6) are* preserved from get_irqnr_and_base above*/ALT_SMP(test_for_ipi r0, r2, r6, lr)ALT_UP_B(9997f)movne r1, spbadrne lr, 1bbne do_IPI #endif 9997:.endm
(3)、調(diào)用了asm_do_IRQ

asm_do_IRQ()—>handle_IRQ()—>__handle_domain_irq()—>generic_handle_irq()—>調(diào)用用戶request_irq注冊(cè)的中斷處理函數(shù)

void handle_IRQ(unsigned int irq, struct pt_regs *regs) {__handle_domain_irq(NULL, irq, false, regs); } /** asm_do_IRQ is the interface to be used from assembly code.*/ asmlinkage void __exception_irq_entry asm_do_IRQ(unsigned int irq, struct pt_regs *regs) {handle_IRQ(irq, regs); } int __handle_domain_irq(struct irq_domain *domain, unsigned int hwirq,bool lookup, struct pt_regs *regs) {struct pt_regs *old_regs = set_irq_regs(regs);unsigned int irq = hwirq;int ret = 0;irq_enter();#ifdef CONFIG_IRQ_DOMAINif (lookup)irq = irq_find_mapping(domain, hwirq); #endif/** Some hardware gives randomly wrong interrupts. Rather* than crashing, do something sensible.*/if (unlikely(!irq || irq >= nr_irqs)) {ack_bad_irq(irq);ret = -EINVAL;} else {generic_handle_irq(irq);}irq_exit();set_irq_regs(old_regs);return ret; } (kernel/irq/irqdesc.c) int generic_handle_irq(unsigned int irq) {struct irq_desc *desc = irq_to_desc(irq);if (!desc)return -EINVAL;generic_handle_irq_desc(desc);return 0; } EXPORT_SYMBOL_GPL(generic_handle_irq); (kernel/include/linux/irqdesc.h) static inline void generic_handle_irq_desc(struct irq_desc *desc) {desc->handle_irq(desc); // 這里真正調(diào)用到,用戶request_irq注冊(cè)的中斷處理函數(shù) }

2、linux kernel arm64的中斷函數(shù)處理流程

我們依然從irq_handler宏函數(shù)看起

(1)、irq_handler宏 調(diào)用handle_arch_irq
(arch/arm/kernel/entry.S) /** Interrupt handling.*/.macro irq_handlerldr_l x1, handle_arch_irqmov x0, spirq_stack_entryblr x1irq_stack_exit.endm
(2)、handle_arch_irq

handle_arch_irq是在set_handle_irq()設(shè)置的handle地址

void __init set_handle_irq(void (*handle_irq)(struct pt_regs *)) {if (handle_arch_irq)return;handle_arch_irq = handle_irq; }
(3)、gic_handle_irq()

在gic_of_init初始化的時(shí)候,將gic_handle_irq()地址賦給了handle_arch_irq

static int __init gic_of_init(struct device_node *node, struct device_node *parent) { ......set_handle_irq(gic_handle_irq); ...... }

進(jìn)入gic中的gic_handle_irq處理函數(shù)
在這里會(huì)調(diào)用handle_domain_irq函數(shù)或者h(yuǎn)andle_IPI函數(shù)

static asmlinkage void __exception_irq_entry gic_handle_irq(struct pt_regs *regs) {u32 irqnr;do {irqnr = gic_read_iar();if (likely(irqnr > 15 && irqnr < 1020) || irqnr >= 8192) {int err;if (static_key_true(&supports_deactivate))gic_write_eoir(irqnr);err = handle_domain_irq(gic_data.domain, irqnr, regs);if (err) {WARN_ONCE(true, "Unexpected interrupt received!\n");if (static_key_true(&supports_deactivate)) {if (irqnr < 8192)gic_write_dir(irqnr);} else {gic_write_eoir(irqnr);}}continue;}if (irqnr < 16) {gic_write_eoir(irqnr);if (static_key_true(&supports_deactivate))gic_write_dir(irqnr); #ifdef CONFIG_SMP/** Unlike GICv2, we don't need an smp_rmb() here.* The control dependency from gic_read_iar to* the ISB in gic_write_eoir is enough to ensure* that any shared data read by handle_IPI will* be read after the ACK.*/handle_IPI(irqnr, regs); #elseWARN_ONCE(true, "Unexpected SGI received!\n"); #endifcontinue;}} while (irqnr != ICC_IAR1_EL1_SPURIOUS); }
(4)、handle_domain_irq()---->__handle_domain_irq()---->generic_handle_irq()---->generic_handle_irq_desc()
int __handle_domain_irq(struct irq_domain *domain, unsigned int hwirq,bool lookup, struct pt_regs *regs) {struct pt_regs *old_regs = set_irq_regs(regs);unsigned int irq = hwirq;int ret = 0;irq_enter();#ifdef CONFIG_IRQ_DOMAINif (lookup)irq = irq_find_mapping(domain, hwirq); #endif/** Some hardware gives randomly wrong interrupts. Rather* than crashing, do something sensible.*/if (unlikely(!irq || irq >= nr_irqs)) {ack_bad_irq(irq);ret = -EINVAL;} else {generic_handle_irq(irq);}irq_exit();set_irq_regs(old_regs);return ret; } int generic_handle_irq(unsigned int irq) {struct irq_desc *desc = irq_to_desc(irq);if (!desc)return -EINVAL;generic_handle_irq_desc(desc);return 0; } EXPORT_SYMBOL_GPL(generic_handle_irq);static inline void generic_handle_irq_desc(struct irq_desc *desc) {desc->handle_irq(desc); }

總結(jié)

以上是生活随笔為你收集整理的linux kernel中的中断处理流程的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。