?? 2.html
字號(hào):
|SAVE_ALL ---<br> |do_IRQ | wrapper routines<br> |handle_IRQ_event ---<br> |handler() -> timer_interrupt // registered IRQ 0 handler<br> |do_timer_interrupt<br> |do_timer<br> |jiffies++;<br> |update_process_times<br> |if (--counter <= 0) { // if time slice ended then<br> |counter = 0; // reset counter<br> |need_resched = 1; // prepare to reschedule<br> |}<br> |do_softirq<br> |while (need_resched) { // if necessary<br> |schedule // reschedule<br> |handle_softirq<br> |}<br> |RESTORE_ALL<p>·IRQ0x00_interrupt, SAVE_ALL [include/asm/hw_irq.h]<br>·do_IRQ, handle_IRQ_event [arch/i386/kernel/irq.c]<br>·timer_interrupt, do_timer_interrupt [arch/i386/kernel/time.c]<br>·do_timer, update_process_times [kernel/timer.c]<br>·do_softirq [kernel/soft_irq.c]<br>·RESTORE_ALL, while loop [arch/i386/kernel/entry.S]<p> 系統(tǒng)啟動(dòng)核心時(shí),調(diào)用start_kernal()繼續(xù)各方面的初始化,在這之前,各種中斷都被禁止,只有在完成必要的初始化后,直到執(zhí)行完Kmalloc_init()后,才允許中斷(init\main.c)。與時(shí)鐘中斷有關(guān)的部分初始化如下:<p> 調(diào)用trap_init()設(shè)置各種trap入口,如system_call、GDT entry、LDT entry、call gate等。其中0~17為各種錯(cuò)誤入口,18~47保留。<p> 調(diào)用init_IRQ()函數(shù)設(shè)置核心系統(tǒng)的時(shí)鐘周期為10ms,即100HZ,它是以后按照輪轉(zhuǎn)法進(jìn)行CPU調(diào)度時(shí)所依照的基準(zhǔn)時(shí)鐘周期。每10ms產(chǎn)生的時(shí)鐘中斷信號(hào)直接輸入到第一塊8259A的INT 0(即irq0)。初始化中斷矢量表中從0x20起的17個(gè)中斷矢量,用bad_IRQ#_interrupt函數(shù)的地址(#為中斷號(hào))填寫(xiě)。<p> 調(diào)用sched_init()函數(shù),設(shè)置啟動(dòng)第一個(gè)進(jìn)程init_task。設(shè)置用于管理bottom_half機(jī)制的數(shù)據(jù)結(jié)構(gòu)bh_base[],規(guī)定三類事件的中斷處理函數(shù),即時(shí)鐘TIMER_BH、設(shè)備TQUEUE_BH和IMMEDIATE_BH。<p> 調(diào)用time_init()函數(shù),首先讀取當(dāng)時(shí)的CMOS時(shí)間,最后調(diào)用setup_x86_irq(0,&irq0)函數(shù),把irq0掛到irq_action[0]隊(duì)列的后面,并把中斷矢量表中第0x20項(xiàng),即timer中斷對(duì)應(yīng)的中斷矢量改為IRQ0_interrupt函數(shù)的地址,在irq0中,指定時(shí)間中斷服務(wù)程序是timer_interrupt,<br> static struct irqaction irq0 = { timer_interrupt, 0, 0, "timer", NULL, NULL}<br> 結(jié)構(gòu)irqaction的定義如下:<br> struct irqaction {<br> void (*handler)(int, void *, struct pt_regs *); /* 中斷服務(wù)函數(shù)入口 */<br> unsigned long flags; /* 服務(wù)允中與否標(biāo)記 */<br> unsigned long mask;<br> const char *name;<br> void *dev_id;<br> struct irqaction *next;<br> };<br> 其中,若flag==SA_INTERRUPT,則中斷矢量改為fast_IRQ#_interrupt,在執(zhí)行中斷服務(wù)的過(guò)程中不允許出現(xiàn)中斷,若為其它標(biāo)記,則中斷矢量為IRQ#_interrupt,在執(zhí)行中斷服務(wù)的過(guò)程中,允許出現(xiàn)中斷。<br>Irq_action的定義與初始化如下:<br> static void (*interrupt[17])(void) = {IRQ#_interrupt};<br> static void (*fast_interrupt[16])(void) = {fast_IRQ#_interrupt};<br> static void (*bad_interrupt[16])(void) = {bad_IRQ#_interrupt};(以上#為中斷號(hào))<br> static struct irqaction *irq_action[16] = {<br> NULL, NULL, NULL, NULL,<br> NULL, NULL, NULL, NULL,<br> NULL, NULL, NULL, NULL,<br> NULL, NULL, NULL, NULL<br> };<p> irq_action是一個(gè)全局?jǐn)?shù)組,每個(gè)元素指向一個(gè)irq隊(duì)列,共16個(gè)irq隊(duì)列,時(shí)鐘中斷請(qǐng)求隊(duì)列在第一個(gè)隊(duì)列,即irq_action[0]。當(dāng)每個(gè)中斷請(qǐng)求到來(lái)時(shí),都調(diào)用setup_x86_irq把該請(qǐng)求掛到相應(yīng)的隊(duì)列的后面。<p> 以后,系統(tǒng)每10ms產(chǎn)生一次時(shí)鐘中斷信號(hào),該信號(hào)直接輸入到第一塊8259A的INT 0(即irq0)。CPU根據(jù)中斷矢量表和中斷源,找到中斷矢量函數(shù)入口IRQ0_interrupt(程序運(yùn)行過(guò)程中允許中斷)或者fast_IRQ0_interrupt(程序運(yùn)行過(guò)程中不允許中斷)或者bad_IRQ0_interrupt(不執(zhí)行任何動(dòng)作,直接返回),這些函數(shù)由宏BUILD_TIMER_IRQ(chip, nr, mask)展開(kāi)定義。<br>宏BUILD_TIMER_IRQ(chip, nr, mask)的定義如下:<br>#define BUILD_TIMER_IRQ(chip,nr,mask) \<br>asmlinkage void IRQ_NAME(nr); \<br>asmlinkage void FAST_IRQ_NAME(nr); \<br>asmlinkage void BAD_IRQ_NAME(nr); \<br>__asm__( \<br>"\n"__ALIGN_STR"\n" \<br>SYMBOL_NAME_STR(fast_IRQ) #nr "_interrupt:\n\t" \<br>SYMBOL_NAME_STR(bad_IRQ) #nr "_interrupt:\n\t" \<br>SYMBOL_NAME_STR(IRQ) #nr "_interrupt:\n\t" \<br> "pushl $-"#nr"-2\n\t" \<br> SAVE_ALL \<br> ENTER_KERNEL \<br> ACK_##chip(mask,(nr&7)) \<br> "incl "SYMBOL_NAME_STR(intr_count)"\n\t"\ /* intr_count為進(jìn)入臨界區(qū)的同步信號(hào)量 */<br> "movl %esp,%ebx\n\t" \<br> "pushl %ebx\n\t" \<br> "pushl $" #nr "\n\t" \ /* 把do_irq函數(shù)參數(shù)壓進(jìn)堆棧 */<br> "call "SYMBOL_NAME_STR(do_IRQ)"\n\t" \<br> "addl $8,%esp\n\t" \<br> "cli\n\t" \<br> UNBLK_##chip(mask) \<br> "decl "SYMBOL_NAME_STR(intr_count)"\n\t" \<br> "incl "SYMBOL_NAME_STR(syscall_count)"\n\t" \<br> "jmp ret_from_sys_call\n");<p> 其中nr為中斷請(qǐng)求類型,取值0~15。在irq.c中通過(guò)語(yǔ)句BUILD_TIMER_IRQ(first, 0, 0x01)調(diào)用該宏,在執(zhí)行宏的過(guò)程中處理時(shí)鐘中斷響應(yīng)程序do_irq()。<p> 函數(shù)do_irq()的第一個(gè)參數(shù)是中斷請(qǐng)求隊(duì)列序號(hào),時(shí)鐘中斷請(qǐng)求傳進(jìn)來(lái)的該參數(shù)是0。于是程序根據(jù)參數(shù)0找到請(qǐng)求隊(duì)列irq_action[0],逐個(gè)處理該隊(duì)列上handler所指的時(shí)鐘中斷請(qǐng)求的服務(wù)函數(shù)。由于已經(jīng)指定時(shí)鐘中斷請(qǐng)求的服務(wù)函數(shù)是timer_interrupt,在函數(shù)timer_interrupt中,立即調(diào)用do_timer()函數(shù)。<p> 函數(shù)do_timer()把jiffies和lost_ticks加1,接著就執(zhí)行mark_bh(TIMER_BH)函數(shù),把bottom_half中時(shí)鐘隊(duì)列對(duì)應(yīng)的位置位,表示該隊(duì)列處于激活狀態(tài)。在做完這些動(dòng)作后,程序從函數(shù)do_irq()中返回,繼續(xù)執(zhí)行以后的匯編代碼。于是,程序在執(zhí)行語(yǔ)句jmp ret_from_sys_call后,跳到指定的位置處繼續(xù)執(zhí)行。<p>代碼段jmp ret_from_sys_call及其相關(guān)的代碼段如下:<br> ALIGN<br> .globl ret_from_sys_call<br>ret_from_sys_call:<br> cmpl $0,SYMBOL_NAME(intr_count)<br> jne 2f<br>9: movl SYMBOL_NAME(bh_mask),%eax<br> andl SYMBOL_NAME(bh_active),%eax<br> jne handle_bottom_half<br>#ifdef __SMP__<br> cmpb $(NO_PROC_ID), SYMBOL_NAME(saved_active_kernel_processor)<br> jne 2f<br>#endif<br> movl EFLAGS(%esp),%eax # check VM86 flag: CS/SS are<br> testl $(VM_MASK),%eax # different then<br> jne 1f<br> cmpw $(KERNEL_CS),CS(%esp) # was old code segment supervisor ?<br> je 2f<br>1: sti<br> orl $(IF_MASK),%eax # these just try to make sure<br> andl $~NT_MASK,%eax # the program doesn't do anything<br> movl %eax,EFLAGS(%esp) # stupid<br> cmpl $0,SYMBOL_NAME(need_resched)<br> jne reschedule<br>#ifdef __SMP__<br> GET_PROCESSOR_OFFSET(%eax)<br> movl SYMBOL_NAME(current_set)(,%eax), %eax<br>#else<br> movl SYMBOL_NAME(current_set),%eax<br>#endif<br> cmpl SYMBOL_NAME(task),%eax # task[0] cannot have signals<br> je 2f<br> movl blocked(%eax),%ecx<br> movl %ecx,%ebx # save blocked in %ebx for signal handling<br> notl %ecx<br> andl signal(%eax),%ecx<br> jne signal_return<br>2: RESTORE_ALL<p>ALIGN<br>signal_return:<br> movl %esp,%ecx<br> pushl %ecx<br> testl $(VM_MASK),EFLAGS(%ecx)<br> jne v86_signal_return<br> pushl %ebx<br> call SYMBOL_NAME(do_signal)<br> popl %ebx<br> popl %ebx<br> RESTORE_ALL<p>ALIGN<br>v86_signal_return:<br> call SYMBOL_NAME(save_v86_state)<br> movl %eax,%esp<br> pushl %eax<br> pushl %ebx<br> call SYMBOL_NAME(do_signal)<br> popl %ebx<br> popl %ebx<br> RESTORE_ALL<p> handle_bottom_half:<br>incl SYMBOL_NAME(intr_count)<br>call SYMBOL_NAME(do_bottom_half)<br>decl SYMBOL_NAME(intr_count)<br>
?? 快捷鍵說(shuō)明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號(hào)
Ctrl + =
減小字號(hào)
Ctrl + -