中斷子係統7_中斷出口處理
// 中斷公共入口 1.1 common_interrupt: //所有可屏蔽中斷函數的公共入口 SAVE_ALL //寄存器入棧 movl %esp,%eax // eax保存棧頂指針 call do_IRQ //中斷處理函數 jmp ret_from_intr //從中斷返回 // 從中斷返回 // 函數主要任務: // 1.確定中斷發生前的運行模式 // 1.1 恢複內核執行路徑 // 1.1.1 檢查是否內核搶占,執行內核搶占 // 1.1.2 恢複硬件上下文 // 1.1.3.iret // 1.2 恢複用戶執行路徑 // 1.2.1 處理信號 // 1.2.2 恢複硬件上下文 // 1.2.3 iret 2.1 ret_from_intr: GET_THREAD_INFO(%ebp) //當前進程threadinfo的指針存入寄存器EBX中 movl EFLAGS(%esp), %eax movb CS(%esp), %al testl $(VM_MASK | 3), %eax //cs,eflags確定中斷發生前的運行模式:1.VM86,用戶空間,2.內核空間 jz resume_kernel ENTRY(resume_userspace) //恢複用戶空間 cli //關本cpu中斷,防止中斷退出時被打斷 movl TI_flags(%ebp), %ecx //threadinfo->flags andl $_TIF_WORK_MASK, %ecx //處理掛起的信號 jne work_pending jmp restore_all //恢複硬件上下文 ENTRY(resume_kernel) //恢複內核空間 cli //關本cpu中斷,防止中斷退出時被打斷 cmpl $0,TI_preempt_count(%ebp) //內核搶占計數器 jnz restore_all //內核搶占計數!=0,不可以發生內核搶占,恢複之前的內核執行路徑 need_resched: //否則,檢查當前進程是否設置need_resched標誌 movl TI_flags(%ebp), %ecx testb $_TIF_NEED_RESCHED, %cl //沒有設置TIF_NEED_RESCHED標誌 jz restore_all //恢複程序執行 testl $IF_MASK,EFLAGS(%esp) jz restore_all call preempt_schedule_irq //內核搶占 jmp need_resched //重調度 // 恢複中斷發生前程序狀態 // 注:iret中斷服務程序的最後一條指令。IRET指令將推入堆棧的段地址和偏移地址彈出, // 使程序返回到原來發生中斷的地方。其作用是從中斷中恢複中斷前的狀態,具體作用有如下三點: // 1.恢複IP(instruction pointer):(IP)←((SP)+1:(SP)),(SP)←(SP)+2 // 2.恢複CS(code segment):(CS)←((SP))+1:(SP)),(SP)←(SP)+2 // 3.恢複中斷前的PSW(program status word),即恢複中斷前的標誌寄存器的狀態。 // (FR)←((SP)+1:(SP)),(SP)←(SP)+2 2.2 #define RESTORE_ALL \ RESTORE_REGS \ addl $4, %esp; \ 1: iret;
//ret_from_intr 流程:

// 內核搶占入口 // 函數主要任務: // 1.設置preempt_active,表示當前進程正在發生內核搶占 // 1.1 防止遞歸調用preempt_schedule_irq // 2.開中斷 // 3.調度 // 4.進程再次恢複執行,關中斷,清除preempt_active,表示內核搶占完成 // 5.檢查是否再次需要內核搶占 2.3 asmlinkage void __sched preempt_schedule_irq(void) { struct thread_info *ti = current_thread_info(); need_resched: //設置preempt_active,表示正在發生內核搶占 add_preempt_count(PREEMPT_ACTIVE); //在進入preempt_schedule_irq之前中斷被關閉,此處開中斷 local_irq_enable(); //調度 schedule(); //此進程恢複執行,關閉中斷 local_irq_disable(); //清除preempt_active,表示內核搶占完成 sub_preempt_count(PREEMPT_ACTIVE); //檢查是否需要內核搶占 barrier(); if (unlikely(test_thread_flag(TIF_NEED_RESCHED))) goto need_resched; } // 處理掛起的信號 // 函數主要任務: // 1.檢查是否需要重調度 // 1.1 調度 // 1.2 恢複執行後,檢查信號是否已經被處理 // 1.2.1 如果已經被處理,恢複進程路徑 // 1.2.2 重複路徑1 // 2.執行信號處理函數 // 3.恢複硬件上下文 2.4 work_pending: testb $_TIF_NEED_RESCHED, %cl //檢查是否需要重調度 jz work_notifysig // 先執行進程調度 work_resched: call schedule cli //關中斷 movl TI_flags(%ebp), %ecx andl $_TIF_WORK_MASK, %ecx //恢複進程執行後,檢查信號是否已經被處理 jz restore_all //如果信號已經被處理,則直接恢複進程硬件上下文 testb $_TIF_NEED_RESCHED, %cl //檢查是否需進程調度 jnz work_resched work_notifysig: //處理掛起的信號 testl $VM_MASK, EFLAGS(%esp) movl %esp, %eax //檢查是否在vm86模式 jne work_notifysig_v86 xorl %edx, %edx call do_notify_resume //執行信號處理函數 jmp restore_all
//中斷嵌套

// 參考 深入理解linux內核
// 關於x86平台下中斷嵌套的討論 // https://blog.focus-linux.net/?p=50
最後更新:2017-04-03 14:54:20