中斷子係統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