知識
不管是網(wǎng)站,軟件還是小程序,都要直接或間接能為您產(chǎn)生價(jià)值,我們在追求其視覺表現(xiàn)的同時(shí),更側(cè)重于功能的便捷,營銷的便利,運(yùn)營的高效,讓網(wǎng)站成為營銷工具,讓軟件能切實(shí)提升企業(yè)內(nèi)部管理水平和效率。優(yōu)秀的程序?yàn)楹笃谏壧峁┍憬莸闹С郑?
linux的中斷子系統(tǒng)簡介(匯編和hardirq部分)_ARM平臺(S
發(fā)表時(shí)間:2020-10-19
發(fā)布人:葵宇科技
瀏覽次數(shù):45
2011年9月份時(shí)刻做的標(biāo)記, 當(dāng)時(shí)瀏覽中斷子體系的代碼后做的一個(gè)PPT, 內(nèi)核版本不記得了, 硬件平臺是samsung 的S5PV210.
這部分主如果針對匯編和hard irq的部分, 在hard irq處理后的softirq的處理, 以及下半部的處理(tasklet/workqueue)都沒有涉及.
Agenda
?Interrupts in ARM
?Important structs
?External interrupt resources in S5PV210
?Code flow
?Kernel API
?Interrupts in ARM
ARM CPU CORE 中只有兩根中斷引腳, 分別是IRQ和FIQ.
?IRQ
–Why chip can handle so many IRQS? ===> VIC
?FIQ
?Important structs
struct irq_desc <strong>irq_desc</strong>[NR_IRQS] __cacheline_aligned_in_smp = { [0 ... NR_IRQS-1] = { .status = IRQ_DISABLED, .chip = &no_irq_chip, .handle_irq = handle_bad_irq, .depth = 1, .lock = __RAW_SPIN_LOCK_UNLOCKED(irq_desc->lock), } }; //NR_IRQS = 393 in R70
irq_desc is a global struct describing all the interrupt lines in the system.
struct irq_desc { <span style="color:#FF0000;"> unsigned int irq;</span> struct timer_rand_state *timer_rand_state; unsigned int *kstat_irqs; #ifdef CONFIG_INTR_REMAP struct irq_2_iommu *irq_2_iommu; #endif <span style="color:#FF0000;"> irq_flow_handler_t handle_irq; //high level irq-events handle struct irq_chip *chip;</span> struct msi_desc *msi_desc; void *handler_data; void *chip_data; <span style="color:#FF0000;"> struct irqaction *action; /* IRQ action list */</span> unsigned int status; /* IRQ status */ unsigned int depth; /* nested irq disables */ unsigned int wake_depth; /* nested wake enables */ unsigned int irq_count; /* For detecting broken IRQs */ unsigned long last_unhandled; /* Aging timer for unhandled count */ unsigned int irqs_unhandled; raw_spinlock_t lock; #ifdef CONFIG_SMP cpumask_var_t affinity; const struct cpumask *affinity_hint; unsigned int node; #ifdef CONFIG_GENERIC_PENDING_IRQ cpumask_var_t pending_mask; #endif #endif atomic_t threads_active; wait_queue_head_t wait_for_threads; #ifdef CONFIG_PROC_FS struct proc_dir_entry *dir; #endif const char *name; } ____cacheline_internodealigned_in_smp;
struct <strong>irq_chip</strong> { const char *name; unsigned int (*startup)(unsigned int irq); void (*shutdown)(unsigned int irq); void (*enable)(unsigned int irq); void (*disable)(unsigned int irq); void (*ack)(unsigned int irq); void (*mask)(unsigned int irq); void (*mask_ack)(unsigned int irq); void (*unmask)(unsigned int irq); void (*eoi)(unsigned int irq); void (*end)(unsigned int irq); int (*set_affinity)(unsigned int irq, const struct cpumask *dest); int (*retrigger)(unsigned int irq); int (*set_type)(unsigned int irq, unsigned int flow_type); int (*set_wake)(unsigned int irq, unsigned int on); void (*bus_lock)(unsigned int irq); void (*bus_sync_unlock)(unsigned int irq); /* Currently used only by UML, might disappear one day.*/ #ifdef CONFIG_IRQ_RELEASE_METHOD void (*release)(unsigned int irq, void *dev_id); #endif /* * For compatibility, ->typename is copied into ->name. * Will disappear. */ const char *typename; };
struct <strong>irqaction</strong> { <span style="color:#FF0000;"> irq_handler_t handler; // handler assigned by request_irq</span> unsigned long flags; const char *name; void *dev_id; struct irqaction *next; int irq; struct proc_dir_entry *dir; irq_handler_t thread_fn; struct task_struct *thread; unsigned long thread_flags; };之間的關(guān)系圖:
[img]http://img.blog.csdn.net/20150104101704954?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvamFja2pvbmVzXzAwOA==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center
?External interrupt resources in S5PV210
[img]http://img.blog.csdn.net/20150104101748946?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvamFja2pvbmVzXzAwOA==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center
?Code flow
起首可以查看體系中有哪些有效的中斷以及相干的信息.
# cat /proc/interrupts //只顯示有響應(yīng)的action的IRQ的信息 CPU0 IRQ_NR count desc->chip->name action->name 16: 43 s3c-uart s5pv210-uart 18: 59 s3c-uart s5pv210-uart 33: 1 s5p_vic_eint mmc1 36: 0 s5p_vic_eint a700_ts 37: 1 s5p_vic_eint aic3254 headset irq 38: 0 s5p_vic_eint keypad 39: 0 s5p_vic_eint keypad 40: 0 s5p_vic_eint keypad 41: 0 s5p_vic_eint keypad 42: 0 s5p_vic_eint keypad 43: 0 s5p_vic_eint keypad 45: 1 s5p_vic_eint hpd 46: 1 s5p_vic_eint USB wak up 50: 0 VIC s3c-pl330.0 51: 0 VIC s3c-pl330.1 52: 0 VIC s3c-pl330.2 58: 0 VIC System timer 59: 0 VIC s3c2410-wdt 61: 14772 VIC rtc-tick 78: 220 VIC s3c2440-i2c.0 83: 27985 VIC s3c2440-i2c.2 88: 1 VIC s3c-udc 90: 52662 VIC mmc0 92: 268 VIC mmc1 93: 0 VIC s3c-csis 97: 2582 VIC s3cfb, s3cfb 102: 0 VIC s3c-fimc1 103: 0 VIC s3c-fimc2 105: 0 VIC s3c-g2d 106: 747 VIC pvrsrvkm 107: 0 VIC s5p-tvout 108: 0 VIC s5p-tvout 109: 0 VIC s3c2440-i2c.1 110: 0 VIC s3c-mfc 111: 0 VIC s5p-tvout 130: 13 VIC mmc2 170: 0 s5p-eint Bq27520_INT Err: 0
起首是初始化的過程, IRQ init sequence:
start_kernel setup_arch early_trap_init early_irq_init //沒做什么事 init_IRQ s5pv210_init_irq s5p_init_irq vic_init(irq_nr直接是大年夜32開端的, 前面的今朝看起來至少留給了timer和UART) s3c_init_vic_timer_irq s3c_init_uart_irqs個(gè)中的early_trap_init, 根本的思路就是, 對于有MMU的體系, 異常向量的虛擬地址被映射到0xFFFF0000, 所以, 真正的7個(gè)異常向量(__vectors_start~__vectors_end)是被拷貝到這個(gè)0xFFFF0000開端的處所了. 接著, 異常處理代碼塊(__stubs_start~__stubs_end)被拷貝到0xFFFF0200處.
void __init early_trap_init(void) { unsigned long vectors = CONFIG_VECTORS_BASE; //0xFFFF0000 extern char __stubs_start[], __stubs_end[]; extern char __vectors_start[], __vectors_end[]; extern char __kuser_helper_start[], __kuser_helper_end[]; int kuser_sz = __kuser_helper_end - __kuser_helper_start; /* * Copy the vectors, stubs and kuser helpers (in entry-armv.S) * into the vector page, mapped at 0xffff0000, and ensure these * are visible to the instruction stream. */ <span style="color:#FF0000;"> memcpy((void *)vectors, __vectors_start, __vectors_end - __vectors_start); memcpy((void *)vectors + 0x200, __stubs_start, __stubs_end - __stubs_start); memcpy((void *)vectors + 0x1000 - kuser_sz, __kuser_helper_start, kuser_sz);</span> /* * Copy signal return handlers into the vector page, and * set sigreturn to be a pointer to these. */ memcpy((void *)KERN_SIGRETURN_CODE, sigreturn_codes, sizeof(sigreturn_codes)); memcpy((void *)KERN_RESTART_CODE, syscall_restart_code, sizeof(syscall_restart_code)); flush_icache_range(vectors, vectors + PAGE_SIZE); modify_domain(DOMAIN_USER, DOMAIN_CLIENT); }
接下來, 中斷產(chǎn)生后, 起首我們看到的是前面注冊的那些vectors. 異常向量表的寫法重要應(yīng)用跳轉(zhuǎn)指令B來進(jìn)行. 因?yàn)楫惓O蛄勘砗彤惓L幚泶a塊之間沒有跨越B指令請求的2^24=32MB, 僅僅相差0x200. 然則因?yàn)関ertor_swi不是在這個(gè)文件中定義的, 所以, 只能用LDR指令來進(jìn)行處理了.
__vectors_start: ARM( swi SYS_ERROR0 ) THUMB( svc #0 ) THUMB( nop ) W(b) vector_und + stubs_offset W(ldr) pc, .LCvswi + stubs_offset W(b) vector_pabt + stubs_offset // prefetch abort W(b) vector_dabt + stubs_offset // data abort W(b) vector_addrexcptn + stubs_offset // W(b) vector_irq + stubs_offset //IRQ人口 W(b) vector_fiq + stubs_offset //FIQ .globl __vectors_end __vectors_end:
@@@ 中斷處理法度榜樣的 stub vector_irq: @ 調(diào)劑 LR_irq sub lr, lr, #4 @ 保存 R0, LR_irq(中斷之前的 PC, 斷點(diǎn)), SPSR_irq(中斷之前的 CPSR) 到 irq模式的┞坊中 stmia sp, {r0, lr} @ save r0, lr mrs lr, spsr str lr, [sp, #8] @ save spsr @ SPSR 設(shè)置為 SVC模式 mrs r0, cpsr eor r0, r0, #(\mode ^ SVC_MODE) msr spsr_cxsf, r0 @ 根據(jù)中斷前的模式跳轉(zhuǎn)到響應(yīng)的處理法度榜樣 @ lr是中斷剛開端時(shí)的 SPSR,即被中斷代碼的 CPSR,其低 4位表示中斷之前的模式 and lr, lr, #0x0f mov r0, sp ldr lr, [pc, lr, lsl #2] @ 跳轉(zhuǎn)到響應(yīng)模式的處理法度榜樣,模式變?yōu)?SVC(SPSR 拷貝到 CPSR ) movs pc, lr @ 跳轉(zhuǎn)表,必須緊跟 ldr lr,[pc,lr,lsl #2]和 movs pc,lr 兩條指令(ARM 流水線機(jī)制??) .long __irq_usr @ 0 (USR) .long __irq_invalid @ 1 (FIQ) .long __irq_invalid @ 2 (IRQ) .long __irq_svc @ 3 (SVC) .long __irq_invalid @ 4 .long __irq_invalid @ 5 .long __irq_invalid @ 6 (ABT) .long __irq_invalid @ 7 .long __irq_invalid @ 8 .long __irq_invalid @ 9 .long __irq_invalid @ a .long __irq_invalid @ b (UND) .long __irq_invalid @ c .long __irq_invalid @ d .long __irq_invalid @ e .long __irq_invalid @ f (SYS)
user mode的處理
@@@ USR模式中斷人口 __irq_usr: @ 在內(nèi)核棧中產(chǎn)生 include/asm-arm/ptrace.h中 pt_regs 定義的┞坊幀構(gòu)造 sub sp, sp, #S_FRAME_SIZE stmib sp, {r1 - r12} ldmia r0, {r1 - r3} add r0, sp, #S_PC @ here for interlock avoidance mov r4, #-1 @ "" "" "" "" str r1, [sp] @ save the "real" r0 copied @ from the exception stack @ We are now ready to fill in the remaining blanks on the stack: @ r2 - lr_<exception>, already fixed up for correct return/restart @ r3 - spsr_<exception> @ r4 - orig_r0 (see pt_regs definition in ptrace.h) @ Also, separately save sp_usr and lr_usr stmia r0, {r2 - r4} stmdb r0, {sp, lr}^ @ Clear FP to mark the first stack frame zero_fp @ 把被中斷義務(wù)的 preempt_count 增長 1 get_thread_info tsk #ifdef CONFIG_PREEMPT ldr r8, [tsk, #TI_PREEMPT] @ get preempt count add r7, r8, #1 @ increment it str r7, [tsk, #TI_PREEMPT] #endif ?@ 輪回調(diào)用 asm_do_IRQ() ?1: get_irqnr_and_base r0, r6, r5, lr ? movne r1, sp ?@ routine called with r0 = irq number, r1 = struct pt_regs * / ? adrne lr, 1b ? bne <span style="color:#FF0000;">asm_do_IRQ</span> ? ?#ifdef CONFIG_PREEMPT ? ldr r0, [tsk, #TI_PREEMPT] ? str r8, [tsk, #TI_PREEMPT] ? teq r0, r7 ? strne r0, [r0, -r0] ?#endif ?@ 返回到 user 模式 ? mov why, #0 ? <span style="color:#FF0000;">b ret_to_user</span>
svc mode的處理
@@@ SVC模式中斷人口 __irq_svc: @ 在內(nèi)核棧中產(chǎn)生 include/asm-arm/ptrace.h中 pt_regs 定義的┞坊幀構(gòu)造 sub sp, sp, #S_FRAME_SIZE tst sp, #4 bicne sp, sp, #4 stmib sp, {r1 - r12} ldmia r0, {r1 - r3} add r5, sp, #S_SP @ here for interlock avoidance mov r4, #-1 @ "" "" "" "" add r0, sp, #S_FRAME_SIZE @ "" "" "" "" addne r0, r0, #4 str r1, [sp] @ save the "real" r0 copied from the exception stack mov r1, lr @ We are now ready to fill in the remaining blanks on the stack: @ r0 - sp_svc @ r1 - lr_svc @ r2 - lr_<exception>, already fixed up for correct return/restart @ r3 - spsr_<exception> @ r4 - orig_r0 (see pt_regs definition in ptrace.h) stmia r5, {r0 - r4} @ 把被中斷義務(wù)的 preempt_count 增長 1 #ifdef CONFIG_PREEMPT get_thread_info tsk ldr r8, [tsk, #TI_PREEMPT] @ get preempt count add r7, r8, #1 @ increment it str r7, [tsk, #TI_PREEMPT] #endif @ 輪回調(diào)用 asm-do_IRQ() 1: get_irqnr_and_base r0, r6, r5, lr movne r1, sp @ routine called with r0 = irq number, r1 = struct pt_regs * adrne lr, 1b bne asm_do_IRQ @ 如不雅須要調(diào)劑,調(diào)用 svc_preempt進(jìn)行內(nèi)核搶占 #ifdef CONFIG_PREEMPT ldr r0, [tsk, #TI_FLAGS] @ get flags tst r0, #_TIF_NEED_RESCHED blne svc_preempt preempt_return: ldr r0, [tsk, #TI_PREEMPT] @ read preempt value str r8, [tsk, #TI_PREEMPT] @ restore preempt count teq r0, r7 strne r0, [r0, -r0] @ bug() #endif @ 返回到內(nèi)核空間 ldr r0, [sp, #S_PSR] @ irqs are already disabled msr spsr_cxsf, r0 ldmia sp, {r0 - pc}^ @ load r0 - pc, cpsr
可以看到, 都調(diào)用了 asm_do_IRQ
asmlinkage void __exception asm_do_IRQ(unsigned int irq, struct pt_regs *regs) { struct pt_regs *old_regs = set_irq_regs(regs); <span style="color:#FF0000;">irq_enter();</span> /* * Some hardware gives randomly wrong interrupts. Rather * than crashing, do something sensible. */ if (unlikely(irq >= NR_IRQS)) { if (printk_ratelimit()) printk(KERN_WARNING "Bad IRQ%u\n", irq); ack_bad_irq(irq); } else { <span style="color:#FF0000;">generic_handle_irq(irq);</span> } /* AT91 specific workaround */ irq_finish(irq); irq_exit(); set_irq_regs(old_regs); }
static inline void generic_handle_irq(unsigned int irq) { generic_handle_irq_desc(irq, irq_to_desc(irq)); } static inline void generic_handle_irq_desc(unsigned int irq, struct irq_desc *desc) { #ifdef CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ <span style="color:#FF0000;">desc->handle_irq(irq, desc); // high level handle, take handle_level_irq for example</span> #else if (likely(desc->handle_irq)) desc->handle_irq(irq, desc); else __do_IRQ(irq); #endif }
然落后入 handle_level_irq
Void handle_level_irq(unsigned int irq, struct irq_desc *desc) { struct irqaction *action; irqreturn_t action_ret; raw_spin_lock(&desc->lock); mask_ack_irq(desc, irq); if (unlikely(desc->status & IRQ_INPROGRESS)) goto out_unlock; desc->status &= ~(IRQ_REPLAY | IRQ_WAITING); kstat_incr_irqs_this_cpu(irq, desc); action = desc->action; if (unlikely(!action || (desc->status & IRQ_DISABLED))) goto out_unlock; desc->status |= IRQ_INPROGRESS; raw_spin_unlock(&desc->lock); action_ret = <span style="color:#FF0000;">handle_IRQ_event(irq, action);</span> if (!noirqdebug) note_interrupt(irq, desc, action_ret); raw_spin_lock(&desc->lock); desc->status &= ~IRQ_INPROGRESS; if (!(desc->status & (IRQ_DISABLED | IRQ_ONESHOT))) unmask_irq(desc, irq); out_unlock: raw_spin_unlock(&desc->lock); }然后是handle_IRQ_event, 這邊調(diào)用了request_irq時(shí)刻注冊的那個(gè)handle.
irqreturn_t handle_IRQ_event(unsigned int irq, struct irqaction *action) { irqreturn_t ret, retval = IRQ_NONE; unsigned int status = 0; do { trace_irq_handler_entry(irq, action); ret = <span style="color:#FF0000;">action->handler(irq, action->dev_id); // handle registered by request_irq</span> trace_irq_handler_exit(irq, action, ret); switch (ret) { case IRQ_WAKE_THREAD: … /* Fall through to add to randomness */ case IRQ_HANDLED: status |= action->flags; break; default: break; } retval |= ret; action = action->next; } while (action); if (status & IRQF_SAMPLE_RANDOM) add_interrupt_randomness(irq); local_irq_disable(); return retval; }以圖表示的話, 就是:
[img]http://img.blog.csdn.net/20150104110240871?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvamFja2pvbmVzXzAwOA==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center
?Kernel API
int request_irq(unsigned int irq, irq_handler_t handler, unsigned long irqflags, const char *devname, void *dev_id) 參數(shù): irq---中斷通道號,取值范圍為 0~NR_IRQS – 1 handler---中斷處理法度榜樣,原型為 irq_return_t isr_func(int irq, void *dev_id) irq_flags---標(biāo)記位 dev_name---名稱,將會(huì)顯示在/proc/interrupts中 dev_id---區(qū)分共享同一個(gè)中斷通道的不合的處理法度榜樣 void free_irq(unsigned int irq, void *dev_id) 參數(shù): irq---中斷通道號,取值范圍為 0~NR_IRQS – 1 dev_id---區(qū)分共享同一個(gè)中斷通道的不合的處理法度榜樣時(shí)才須要用到.
int set_irq_chip(unsigned int irq, struct irq_chip *chip) 設(shè)置 chip int set_irq_chip_data(unsigned int irq, void *data) 設(shè)置 chip_data int set_irq_handle(unsigned int irq, irq_flow_handler_t handle) 設(shè)置 handle_irq int set_irq_data(unsigned int irq, void *data) 設(shè)置 handler_data int set_irq_type(unsigned int irq, unsigned int type) 設(shè)置指定通道的觸發(fā)類型
Ryan: PPT完成于2011.9.15, blog完成于2015.1.4
相關(guān)案例查看更多
相關(guān)閱讀
- 云南軟件公司
- Web開發(fā)框架
- 云南網(wǎng)站建設(shè)招商
- 昆明小程序設(shè)計(jì)
- 云南網(wǎng)站建設(shè)首頁
- 云南小程序被騙蔣軍
- 紅河小程序開發(fā)
- 昆明小程序開發(fā)聯(lián)系方式
- 網(wǎng)站排名優(yōu)化
- 區(qū)塊鏈
- 網(wǎng)絡(luò)公司電話
- 貴州小程序開發(fā)
- uniapp開發(fā)小程序
- 網(wǎng)站搭建
- 小程序開發(fā)公司
- .net網(wǎng)站
- 退款
- 小程序被攻擊
- 模版消息
- 高端網(wǎng)站建設(shè)公司
- 云南小程序開發(fā)費(fèi)用
- 云南網(wǎng)站建設(shè)一條龍
- 小程序開發(fā)費(fèi)用
- 汽車報(bào)廢
- 網(wǎng)站建設(shè)服務(wù)公司
- 網(wǎng)站建設(shè)公司哪家好
- 昆明做網(wǎng)站建設(shè)的公司排名
- 云南網(wǎng)站建設(shè)公司排名
- 二叉樹
- 昆明網(wǎng)站設(shè)計(jì)