閱讀753 返回首頁    go 阿裏雲 go 技術社區[雲棲]


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

  上一篇:go JSP翻頁代碼
  下一篇:go JSP網頁分頁顯示數據庫的內容