實驗5――中斷異常系統(tǒng)調(diào)用_第1頁
實驗5――中斷異常系統(tǒng)調(diào)用_第2頁
實驗5――中斷異常系統(tǒng)調(diào)用_第3頁
實驗5――中斷異常系統(tǒng)調(diào)用_第4頁
實驗5――中斷異常系統(tǒng)調(diào)用_第5頁
已閱讀5頁,還剩7頁未讀, 繼續(xù)免費閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進行舉報或認(rèn)領(lǐng)

文檔簡介

1、實驗5:中斷/異常/系統(tǒng)調(diào)用姓名:學(xué)號:要求(對于系統(tǒng)調(diào)用:1、Linux的系統(tǒng)調(diào)用利用了x86的哪種硬件機制?系統(tǒng)調(diào)用是作為一種異常類型實現(xiàn)的。它將執(zhí)行相應(yīng)的機器代碼指令來產(chǎn)生異常信號。產(chǎn)生中斷或異常的重要效果是系統(tǒng)自動將用戶模式切換為內(nèi)核模式來對它進行處理。這就是說,執(zhí)行系統(tǒng)調(diào)用的異常指令時,將自動地將系統(tǒng)切換為內(nèi)核模式,并安排異常處理程序的執(zhí)行。它知道如何處理這一調(diào)用。在LINUX中實現(xiàn)系統(tǒng)調(diào)用異常的實際指令是:int $0x80這一指令使用中斷/異常向量號128(即16進制的80將控制權(quán)轉(zhuǎn)移給內(nèi)核。為達到在系統(tǒng)調(diào)用時不必用機器指令編程,在標(biāo)準(zhǔn)的C語言庫中為每一個系統(tǒng)調(diào)用提供了一段短的子

2、程序,完成機器代碼的編程工作。事實上,機器代碼非常短。它要做的工作只是將送給系統(tǒng)調(diào)用的參數(shù)值加載到CPU寄存器中,接著執(zhí)行int $0x80指令。然后運行系統(tǒng)調(diào)用,系統(tǒng)調(diào)用的返回值將送入CPU的一個寄存器中,標(biāo)準(zhǔn)的庫子程序取得這一返回值,并將它送回給你的程序。為了使系統(tǒng)調(diào)用執(zhí)行成為一項簡單的任務(wù),LINUX中提供了一組預(yù)處理宏指令。它們可以用在程序中。這些宏指令取一定的參數(shù),然后擴展為調(diào)用指定的系統(tǒng)調(diào)用的函數(shù)。2、說明Linux是如何組織系統(tǒng)調(diào)用的?在Linux中,每個系統(tǒng)調(diào)用被賦予一個系統(tǒng)調(diào)用號。這樣,通過這個獨一無二的號就可以關(guān)聯(lián)系統(tǒng)調(diào)用。當(dāng)用戶空間的進程執(zhí)行一個系統(tǒng)調(diào)用的時候,這個系統(tǒng)調(diào)

3、用號就被用來指明到底是要執(zhí)行哪個系統(tǒng)調(diào)用。進程不會提及系統(tǒng)調(diào)用的名稱。系統(tǒng)調(diào)用號相當(dāng)關(guān)鍵,一旦分配就不能再有任何變更,否則編譯好的應(yīng)用程序就會崩潰。Linux有一個“未實現(xiàn)”系統(tǒng)調(diào)用sys_ni_syscall(,它除了返回一ENOSYS外不做任何其他工作,這個錯誤號就是專門針對無效的系統(tǒng)調(diào)用而設(shè)的。因為所有的系統(tǒng)調(diào)用陷入內(nèi)核的方式都一樣,所以僅僅是陷入內(nèi)核空間是不夠的。因此必須把系統(tǒng)調(diào)用號一并傳給內(nèi)核。在x86上,系統(tǒng)調(diào)用號是通過eax寄存器傳遞給內(nèi)核的。在陷人內(nèi)核之前,用戶空間就把相應(yīng)系統(tǒng)調(diào)用所對應(yīng)的號放入eax中了。這樣系統(tǒng)調(diào)用處理程序一旦運行,就可以從eax中得到數(shù)據(jù)。其他體系結(jié)構(gòu)上的

4、實現(xiàn)也都類似。內(nèi)核記錄了系統(tǒng)調(diào)用表中的所有已注冊過的系統(tǒng)調(diào)用的列表,存儲在sys_call_table中。它與體系結(jié)構(gòu)有關(guān),一般在entry.s中定義。這個表中為每一個有效的系統(tǒng)調(diào)用指定了惟一的系統(tǒng)調(diào)用號。sys_call_table是一張由指向?qū)崿F(xiàn)各種系統(tǒng)調(diào)用的內(nèi)核函數(shù)的函數(shù)指針組成的表:ENTRY(sys_call_table.long SYMBOL_NAME(sys_ni_syscall /* 0-old "setup(" system call*/.long SYMBOL_NAME(sys_exit.long SYMBOL_NAME(sys_fork.long SY

5、MBOL_NAME(sys_read.long SYMBOL_NAME(sys_write.long SYMBOL_NAME(sys_open /* 5 */.long SYMBOL_NAME(sys_close.long SYMBOL_NAME(sys_waitpid.long SYMBOL_NAME(sys_capget.long SYMBOL_NAME(sys_capset/* 185 */.long SYMBOL_NAME(sys_sigaltstack.long SYMBOL_NAME(sys_sendfile.long SYMBOL_NAME(sys_ni_syscall /* s

6、treams1 */.long SYMBOL_NAME(sys_ni_syscall /* streams2 */.long SYMBOL_NAME(sys_vfork/* 190 */system_call(函數(shù)通過將給定的系統(tǒng)調(diào)用號與NR_syscalls做比較來檢查其有效性。如果它大于或者等于NR syscalls,該函數(shù)就返回一ENOSYS。否則,就執(zhí)行相應(yīng)的系統(tǒng)調(diào)用。call *sys_ call-table(,%eax, 4由于系統(tǒng)調(diào)用表中的表項是以32位(4字節(jié)類型存放的,所以內(nèi)核需要將給定的系統(tǒng)調(diào)用號乘以4,然后用所得的結(jié)果在該表中查詢其位置3、說明一個用戶態(tài)的程序是如何進入系

7、統(tǒng)調(diào)用中執(zhí)行的?用戶空間的程序無法直接執(zhí)行內(nèi)核代碼。它們不能直接調(diào)用內(nèi)核空間中的函數(shù),因為內(nèi)核駐留在受保護的地址空間上。如果進程可以直接在內(nèi)核的地址空間上讀寫的話,系統(tǒng)安全就會失去控制。所以,應(yīng)用程序應(yīng)該以某種方式通知系統(tǒng),告訴內(nèi)核自己需要執(zhí)行一個系統(tǒng)調(diào)用,希望系統(tǒng)切換到內(nèi)核態(tài),這樣內(nèi)核就可以代表應(yīng)用程序來執(zhí)行該系統(tǒng)調(diào)用了。通知內(nèi)核的機制是靠軟件中斷實現(xiàn)的。首先,用戶程序為系統(tǒng)調(diào)用設(shè)置參數(shù)。其中一個參數(shù)是系統(tǒng)調(diào)用編號。參數(shù)設(shè)置完成后,程序執(zhí)行“系統(tǒng)調(diào)用”指令。x86系統(tǒng)上的軟中斷由int產(chǎn)生。這個指令會導(dǎo)致一個異常:產(chǎn)生一個事件,這個事件會致使處理器切換到內(nèi)核態(tài)并跳轉(zhuǎn)到一個新的地址,并開始執(zhí)行

8、那里的異常處理程序。此時的異常處理程序?qū)嶋H上就是系統(tǒng)調(diào)用處理程序。它與硬件體系結(jié)構(gòu)緊密相關(guān)。新地址的指令會保存程序的狀態(tài),計算出應(yīng)該調(diào)用哪個系統(tǒng)調(diào)用,調(diào)用內(nèi)核中實現(xiàn)那個系統(tǒng)調(diào)用的函數(shù),恢復(fù)用戶程序狀態(tài),然后將控制權(quán)返還給用戶程序。系統(tǒng)調(diào)用是設(shè)備驅(qū)動程序中定義的函數(shù)最終被調(diào)用的一種方式。4、以某個系統(tǒng)調(diào)用為例,從用戶激活系統(tǒng)調(diào)用開始,分析系統(tǒng)調(diào)用在Linux中是如何一步一步執(zhí)行的系統(tǒng)調(diào)用實例分析:sys_exit當(dāng)用戶發(fā)出一個退出系統(tǒng)命令的時候,Linux就調(diào)用系統(tǒng)調(diào)用sys_exit。系統(tǒng)調(diào)用sys_exit 的主要作用是終止當(dāng)前正在運行的所有用戶的應(yīng)用程序,保存當(dāng)前帳號的各種信息,逐步退出支

9、撐Linux操作系統(tǒng)運行的系統(tǒng)子模塊和子系統(tǒng)。這些系統(tǒng)子模塊和子系統(tǒng)是:1.刪除當(dāng)前任務(wù)的實定時器。2. 刪除信號隊列(destroye semaphore arrays,釋放信號撤消結(jié)構(gòu)(free semaphores undo structures3. 清空當(dāng)前任務(wù)的kerneld隊列。4. 退出內(nèi)存管理。5. 關(guān)閉打開的文件。6. 退出文件系統(tǒng)。7. 釋放當(dāng)前任務(wù)的所有信號(signal。8. 退出線程(thread。系統(tǒng)調(diào)用sys_exit的處理函數(shù)定義在文件kernel/exit.c中。sys_exit的函數(shù)體很簡單,只是調(diào)用了函數(shù)do_exit:do_exit(error_code

10、&0xff<<(error_code&0xff<<8的作用就是將error_code的低8位移到高8位中,低8位用0填補,此數(shù)將作為參數(shù)傳給函數(shù)do_exit。下面來看看函數(shù)do_exit是怎樣做的。首先,do_exit判斷表示是否有正在處理的中斷服務(wù)全局變量intr_count是否為1,如果為1,表明當(dāng)前還有中斷正在處理,執(zhí)行intr_count=0,停止處理中斷。接著,do_exit要為關(guān)閉系統(tǒng),逐步退出一些運行操作系統(tǒng)所必須的模塊。1.執(zhí)行函數(shù)acct_process(。(該函數(shù)定義在kernel/sys.c中再該函數(shù)中,保存當(dāng)前帳號的各種狀態(tài)。2

11、. 把當(dāng)前任務(wù)的標(biāo)記記為退出:current->flags |= PF_EXITING;向所有的進程宣布,現(xiàn)在系統(tǒng)要退出了,以便一些調(diào)度處理函數(shù)得知這一消息(通過檢測該標(biāo)記。3. 刪除當(dāng)前的實定時器:del_timer(¤t->real_timer;4. 刪除信號隊列(destroye semaphore arrays,釋放信號撤消結(jié)構(gòu)(free semaphores undo structuresSem_exit(;(定義在ipc/sem.c文件中在該函數(shù)中,增加調(diào)整值(semval給信號,再釋放撤消結(jié)構(gòu)(free undo structures。由于某些信號(sema

12、phore可能已經(jīng)過時或無效了,直到信號數(shù)組(semaphore array被刪除了以后,撤消結(jié)構(gòu)(undo structures才被釋放。具體做法如下:a.如果當(dāng)前進程正在睡眠狀況(需要一信號(semaphore來喚醒,將進程當(dāng)前指向所需信號(semaphore的指針置空。b.在當(dāng)前的信號撤消鏈表(struct sem_undo里查找a中提到的那信號(semaphore,找到以后,調(diào)整該信號(已在信號撤消鏈表中注冊過的的內(nèi)容。c.由于有可能有一個隊列的進程在等該信號,故須更新整個操作系統(tǒng)的數(shù)組。5. 清空當(dāng)前任務(wù)的kerneld隊列:kerneld_exit(;6. 退出內(nèi)存管理系統(tǒng):_ex

13、it_mm(current;(函數(shù)定義在kernel/exit.c文件中具體做法如下:a.將cache,tlb,page里的內(nèi)容全部回寫。b.退出內(nèi)存影射。c.釋放頁表(page table。7. 把當(dāng)前任務(wù)所打開的文件都關(guān)閉,釋放文件指針。_exit_files(current;8. 退出文件系統(tǒng):_exit_fs(current;9. 釋放當(dāng)前任務(wù)的所有信號(signal:_exit_sighand(current;10.釋放當(dāng)前線程數(shù)據(jù):_exit_thread(;11. 向外廣播退出:exit_notify(;先將當(dāng)前任務(wù)的狀態(tài)(state設(shè)為TASK_ZOMBIE,退出碼為code(

14、即傳進來的參數(shù)。再調(diào)用exit_notify(函數(shù)。在exit_notify(中,作為我們執(zhí)行上述過程后,退出系統(tǒng)的結(jié)果,我們的進程組們應(yīng)該變成孤立的了。如果它們已經(jīng)停止工作了,給它們發(fā)"SIGHUP"和"SIGCONT"信號。接著,通知它們的父進程,本進程已經(jīng)被kill了。接下去是一循環(huán),該循環(huán)主要做以下兩件事:使初始進程(init繼承所有子進程。檢查是否有遺漏:還有進程組不是孤立的。若有,處理方法同上。最后,調(diào)用函數(shù)disassciate_ctty(int(定義在drivers/char/tty_io.c中。只有當(dāng)參數(shù)是1時,才是被exit_noti

15、fy(調(diào)用的。在該函數(shù)中,將當(dāng)前tty進程組kill掉,所有進程對應(yīng)的tty成員賦NULL。12.將當(dāng)前任務(wù)的用戶數(shù)目減一:(*current->exec_domain->use_count-;(*current->binfmt->use_count-;13.繼續(xù)調(diào)度:schedule(;在調(diào)用完sys_exit后,先判斷返回值_res是否為非負(fù)數(shù)。若是,則說明該次調(diào)用是成功的,返回_res即可。若_res為負(fù)數(shù),則說明該次調(diào)用過程中存在著一個或一些錯誤,將錯誤值賦給一全局變量errno:errno = -_res;再返回-1,指明有錯誤存在,可以讓專門處理這些錯誤的函

16、數(shù)根據(jù)errno的值知道這次調(diào)用到底出錯在什么地方,是哪種類型的錯,以便進行錯誤處理。5、自己編寫一個系統(tǒng)調(diào)用,并編寫用戶態(tài)程序,從這個用戶態(tài)程序中調(diào)用這個系統(tǒng)調(diào)用如果用戶在Linux中添加新的系統(tǒng)調(diào)用,應(yīng)該遵循幾個步驟才能添加成功,下面幾個步驟詳細說明了添加系統(tǒng)調(diào)用的相關(guān)內(nèi)容。(1添加源代碼第一個任務(wù)是編寫加到內(nèi)核中的源程序,即將要加到一個內(nèi)核文件中去的一個函數(shù),該函數(shù)的名稱應(yīng)該是新的系統(tǒng)調(diào)用名稱前面加上sys_標(biāo)志。假設(shè)新加的系統(tǒng)調(diào)用為mycall(int number,在/usr/src/linux/kernel/sys.c文件中添加源代碼,如下所示:asmlinkage int sys

17、_mycall(int numberreturn number;作為一個最簡單的例子,我們新加的系統(tǒng)調(diào)用僅僅返回一個整型值。(2連接新的系統(tǒng)調(diào)用添加新的系統(tǒng)調(diào)用后,下一個任務(wù)是使Linux內(nèi)核的其余部分知道該程序的存在。為了從已有的內(nèi)核程序中增加到新的函數(shù)的連接,需要編輯兩個文件。第一個要修改的文件是:/usr/src/linux/include/asm-i386/unistd.h該文件中包含了系統(tǒng)調(diào)用清單,用來給每個系統(tǒng)調(diào)用分配一個唯一的號碼。文件中每一行的格式如下:#define _NR_name NNN其中,name用系統(tǒng)調(diào)用名稱代替,而NNN則是該系統(tǒng)調(diào)用對應(yīng)的號碼。應(yīng)該將新的系統(tǒng)調(diào)用

18、名稱加到清單的最后,并給它分配號碼序列中下一個可用的系統(tǒng)調(diào)用號。我們的系統(tǒng)調(diào)用如下:#define _NR_mycall 191系統(tǒng)調(diào)用號為191,之所以系統(tǒng)調(diào)用號是191,是因為Linux-2.2內(nèi)核自身的系統(tǒng)調(diào)用號碼已經(jīng)用到190。第二個要修改的文件是:/usr/src/linux/arch/i386/kernel/entry.S該文件中有類似如下的清單:.long SYMBOL_NAME(該清單用來對sys_call_table數(shù)組進行初始化。該數(shù)組包含指向內(nèi)核中每個系統(tǒng)調(diào)用的指針。這樣就在數(shù)組中增加了新的內(nèi)核函數(shù)的指針。我們在清單最后添加一行: .long SYMBOL_NAME(sy

19、s_mycall(3重建新的Linux內(nèi)核為使新的系統(tǒng)調(diào)用生效,需要重建Linux的內(nèi)核。這需要以超級用戶身份登錄。#pwd/usr/src/linux#超級用戶在當(dāng)前工作目錄(/usr/src/linux下,才可以重建內(nèi)核。#make config#make dep#make clearn#make bzImage編譯完畢后,系統(tǒng)生成一可用于安裝的、壓縮的內(nèi)核映象文件:/usr/src/linux/arch/i386/boot/bzImage(4用新的內(nèi)核啟動系統(tǒng)要使用新的系統(tǒng)調(diào)用,需要用重建的新內(nèi)核重新引導(dǎo)系統(tǒng)。為此,需要修改/etc/lilo.conf 文件,在我們的系統(tǒng)中,該文件內(nèi)容如

20、下:boot=/dev/hdamap=/boot/mapinstall=/boot/boot.bprompttimeout=50image=/boot/vmlinuz-2.2.5-15label=linuxroot=/dev/hdb1read-onlyother=/dev/hda1label=dostable=/dev/had首先編輯該文件,添加新的引導(dǎo)內(nèi)核: image=/boot/bzImage-new label=linux-new root=/dev/hdb1 read-only 添加完畢,該文件內(nèi)容如下所示: boot=/dev/hda map=/boot/map install=/boot/boot.b prompt timeout=50 image=/boot/bzImag

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論