曰本美女∴一区二区特级A级黄色大片, 国产亚洲精品美女久久久久久2025, 页岩实心砖-高密市宏伟建材有限公司, 午夜小视频在线观看欧美日韩手机在线,国产人妻奶水一区二区,国产玉足,妺妺窝人体色WWW网站孕妇,色综合天天综合网中文伊,成人在线麻豆网观看

您好,歡迎來(lái)電子發(fā)燒友網(wǎng)! ,新用戶?[免費(fèi)注冊(cè)]

您的位置:電子發(fā)燒友網(wǎng)>源碼下載>Linux/uClinux/Unix編程>

Linux內(nèi)核源代碼漫游

大?。?/span>92 人氣: 2010-02-09 需要積分:0
{$username}的空間

用戶級(jí)別:注冊(cè)會(huì)員

貢獻(xiàn)文章:

貢獻(xiàn)資料:

Linux內(nèi)核源代碼漫游

本章試圖以順序的方式來(lái)解釋Linux源代碼,以幫助讀者對(duì)源代碼的體系結(jié)構(gòu)以及很多相關(guān)的unix特性的實(shí)現(xiàn)有一個(gè)很好的理解。目標(biāo)是幫助對(duì)Linux不甚了解的有經(jīng)驗(yàn)的C程序員對(duì)整個(gè)Linux的設(shè)計(jì)有所了解。這也就是為什么內(nèi)核漫游的入點(diǎn)選擇為內(nèi)核本身的啟始點(diǎn):系統(tǒng)引導(dǎo)(啟動(dòng))。
這份材料需要對(duì)C語(yǔ)言以及對(duì)Unix的概念和PC機(jī)的結(jié)構(gòu)有很好的了解,然而本章中并沒(méi)有出現(xiàn)任何的C代碼,而是直接參考(指向)實(shí)際的代碼的。有關(guān)內(nèi)核設(shè)計(jì)的最佳篇幅是在本手冊(cè)的其它章節(jié)中,而本章仍趨向于是一個(gè)非正式的概述。
本章中所參閱的任何文件的路徑名都是指主源代碼目錄樹(shù),通常是/usr/src/linux。
?這里所給出的大多數(shù)信息都是取之于Linux發(fā)行版1.0的源代碼。雖然如此,有時(shí)也會(huì)提供對(duì)后期版本的參考。這篇漫游中開(kāi)頭有? 圖標(biāo)的任何小節(jié)都是強(qiáng)調(diào)1.0版本后對(duì)內(nèi)核的新的改動(dòng)。如果沒(méi)有這樣的小節(jié)存在,則表示直到版本1.0.9-1.1.76,沒(méi)有作過(guò)改動(dòng)。
?有時(shí)候本章中會(huì)有象這樣的小節(jié),這是指向正確的代碼以對(duì)剛討論過(guò)的主題取得更多信息的指示符。當(dāng)然,這里是指源代碼。
引導(dǎo)(啟動(dòng))系統(tǒng)
當(dāng)PC的電源打開(kāi)后,80x86結(jié)構(gòu)的CPU將自動(dòng)進(jìn)入實(shí)模式,并從地址0xFFFF0開(kāi)始自動(dòng)執(zhí)行程序代碼,這個(gè)地址通常是ROM-BIOS中的地址。PC機(jī)的BIOS將執(zhí)行某些系統(tǒng)的檢測(cè),在物理地址0處開(kāi)始初始化中斷向量。此后,它將可啟動(dòng)設(shè)備的第一個(gè)扇區(qū)讀入內(nèi)存地址0x7C00處,并跳轉(zhuǎn)到這個(gè)地方。啟動(dòng)設(shè)備通常是軟驅(qū)或是硬盤(pán)。這里的敘述是非常簡(jiǎn)單的,但這已經(jīng)足夠理解內(nèi)核初始化的工作過(guò)程了。
Linux的最最前面部分是用8086匯編語(yǔ)言編寫(xiě)的(boot/bootsect.S),它將由BIOS讀入到內(nèi)存0x7C00處,當(dāng)它被執(zhí)行時(shí)就會(huì)把自己移到絕對(duì)地址0x90000處,并將啟動(dòng)設(shè)備(boot/setup.S)的下2kB字節(jié)的代碼讀入內(nèi)存0x90200處,而內(nèi)核的其它部分則被讀入到地址0x10000處。在系統(tǒng)加載期間將顯示信息"Loading..."。然后控制權(quán)將傳遞給boot/Setup.S中的代碼,這是另一個(gè)實(shí)模式匯編語(yǔ)言程序。
啟動(dòng)部分識(shí)別主機(jī)的某些特性以及vga卡的類型。如果需要,它會(huì)要求用戶為控制臺(tái)選擇顯示模式。然后將整個(gè)系統(tǒng)從地址0x10000移至0x1000處,進(jìn)入保護(hù)模式并跳轉(zhuǎn)至系統(tǒng)的余下部分(在0x1000處)。
下一步是內(nèi)核的解壓縮。0x1000處的代碼來(lái)自于zBoot/head.S,它初始化寄存器并調(diào)用decompress_kernel(),它們依次是由zBoot/inflate.c、zBoot/unzip.c和zBoot/misc.c組成。被解壓的數(shù)據(jù)存放到了地址0x10000處(1兆),這也是為什么Linux不能運(yùn)行于少于2兆內(nèi)存的主要原因。[在1兆內(nèi)存中解壓內(nèi)核的工作已經(jīng)完成,見(jiàn) Memory Savers--ED]
?將內(nèi)核封裝在一個(gè)gzip文件中的工作是由zBoot目錄中的Makefile以及工具完成的。它們是值得一看的有趣的文件。
?內(nèi)核發(fā)行版1.1.75將boot和zBoot目錄下移到了arch/i386/boot中了,這個(gè)改動(dòng)意味著對(duì)不同的體系結(jié)構(gòu)允許真正的內(nèi)核建造,不過(guò)我將仍然只講解有關(guān)i386的信息。
解壓過(guò)的代碼是從地址0x10100處開(kāi)始執(zhí)行的[這里我可能忘記了具體的物理地址了,因?yàn)槲覍?duì)相應(yīng)的代碼不是很熟],在那里,所有32比特的設(shè)置啟動(dòng)被完成: IDT、GDT以及LDT被加載,處理器和協(xié)處理器也已確認(rèn),分頁(yè)工作也設(shè)置好了;最終調(diào)用start_kernel子程序。上述操作的源代碼是在boot/head.S中的,這可能是整個(gè)內(nèi)核中最有訣竅的代碼了。
注意如果在前述任何一步中出了錯(cuò),計(jì)算機(jī)就會(huì)死鎖。在操作系統(tǒng)還沒(méi)有完全運(yùn)轉(zhuǎn)之前是處理不了出錯(cuò)的。
start_kernel()是位于init/main.c中的,并且沒(méi)有任何返回結(jié)果。從現(xiàn)在起的任何代碼都是用C語(yǔ)言編制的,除了中斷管理和系統(tǒng)調(diào)用的入/出代碼(當(dāng)然,還有大多數(shù)的宏都嵌入了匯編代碼)。
讓輪子轉(zhuǎn)動(dòng)起來(lái)
在處理了所有錯(cuò)綜復(fù)雜的問(wèn)題之后,start_kernel()初始化了內(nèi)核的所有部分,尤其是:
??設(shè)置內(nèi)存邊界和調(diào)用paging_init();
??初始化中斷、IRQ通道和調(diào)度;
??分析(解析)命令行;
??如果需要,就分配一個(gè)數(shù)據(jù)緩沖區(qū)(profiling buffer)以及其它一些小部分;
??校正延遲循環(huán)(計(jì)算“BogoMips”數(shù));
??檢查中斷16是否能與協(xié)處理器工作。
最后,為了生成初始進(jìn)程,內(nèi)核準(zhǔn)備好了移至move_to_user_mode(),它的代碼也是在同一個(gè)源代碼文件中的。然后,所謂的空閑任務(wù),進(jìn)程號(hào)0就進(jìn)入無(wú)限的空閑循環(huán)中運(yùn)行。
接著初始進(jìn)程(init process)嘗試著運(yùn)行/etc/init、/bin/init或者/sbin/init。
如果它們沒(méi)有一個(gè)運(yùn)行成功的,就會(huì)去執(zhí)行代碼“/bin/sh /etc/rc”并且在第一個(gè)終端上生成一個(gè)根命令解釋程序(root shell)。這段代碼回溯至Linux 0.01,當(dāng)時(shí)操作系統(tǒng)只有一個(gè)內(nèi)核,并且沒(méi)有登錄進(jìn)程。
在從一個(gè)標(biāo)準(zhǔn)的地方(讓我們假定我們有)用exec()執(zhí)行了init初始化程序之后,內(nèi)核就對(duì)程序的執(zhí)行沒(méi)有了直接的控制。從現(xiàn)在起它的規(guī)則是提供對(duì)系統(tǒng)調(diào)用的處理,以及為異步事件服務(wù)(比如硬件中斷等)。多任務(wù)的環(huán)境已經(jīng)建立,從現(xiàn)在起是init程序通過(guò)fork()派生出的系統(tǒng)進(jìn)程和登錄進(jìn)程來(lái)管理多用戶的訪問(wèn)了。
由于內(nèi)核是負(fù)責(zé)提供服務(wù)的,這個(gè)漫游文章將通過(guò)觀察這些服務(wù)(“系統(tǒng)調(diào)用”)以及通過(guò)提供基本數(shù)據(jù)結(jié)構(gòu)的原理和代碼的組織結(jié)構(gòu)繼續(xù)討論下去。
內(nèi)核是如何看見(jiàn)一個(gè)進(jìn)程的
從內(nèi)核的觀點(diǎn)來(lái)看,一個(gè)進(jìn)程只是進(jìn)程表中的一個(gè)條目而已。
而進(jìn)程表以及各個(gè)內(nèi)存管理表和緩沖存儲(chǔ)器則是系統(tǒng)中最為重要的數(shù)據(jù)結(jié)構(gòu)。進(jìn)程表中的各個(gè)單項(xiàng)是task_struct結(jié)構(gòu),是定義在include/linux/sched.h中的非常大的數(shù)據(jù)結(jié)構(gòu)。在task_struct中保留著從低層到高層的信息,范圍從某些硬件寄存器的拷貝到進(jìn)程工作目錄的inode信息。
進(jìn)程表既是一個(gè)數(shù)組和雙鏈表,也是一個(gè)樹(shù)結(jié)構(gòu)。它的物理實(shí)現(xiàn)是一個(gè)靜態(tài)的指針數(shù)組,它的長(zhǎng)度是定義在include/linux/tasks.h中的常量NR_TASKS,并且每個(gè)結(jié)構(gòu)都位于一個(gè)保留內(nèi)存頁(yè)中。這個(gè)列表結(jié)構(gòu)是通過(guò)指針next_task和pre_task構(gòu)成的,而樹(shù)結(jié)構(gòu)則是非常復(fù)雜的并且我們?cè)诖藢⒉患右杂懻?。你可能希望改?dòng)NR_TASKS的默認(rèn)值128,但你要保證所有源文件中相關(guān)的適當(dāng)文件都要被重新編譯過(guò)。
在啟動(dòng)引導(dǎo)過(guò)程結(jié)束后,內(nèi)核將總是代表某個(gè)進(jìn)程而工作,并且全局變量current --- 一個(gè)指向某個(gè)task_struct條目的指針 --- 被用于記錄正在運(yùn)行的進(jìn)程。current僅能通過(guò)在kernel/sched.c中的調(diào)度程序來(lái)改變。然而,由于所有的進(jìn)程都必須訪問(wèn)它,所以使用了宏for_each_task。當(dāng)系統(tǒng)負(fù)荷很輕時(shí),它要比數(shù)組的順序掃描快得多。
進(jìn)程總是運(yùn)行于“用戶模式”或“內(nèi)核模式”。用戶程序的主體是運(yùn)行于用戶模式而其中的系統(tǒng)調(diào)用則運(yùn)行于內(nèi)核模式中。在這兩種執(zhí)行模式中進(jìn)程所用的堆棧是不一樣的 -- 常規(guī)的堆棧段用于用戶模式,而一個(gè)固定大小的堆棧(一頁(yè),由該進(jìn)程所有)則用于內(nèi)核模式。內(nèi)核堆棧頁(yè)是從不交換出去的,因?yàn)槊慨?dāng)一個(gè)系統(tǒng)調(diào)用進(jìn)入時(shí)它就必須存在著。
內(nèi)核中的系統(tǒng)調(diào)用(system calls)是作為C語(yǔ)言函數(shù)存在的,它們的‘正規(guī)’名稱是以‘sys_’開(kāi)頭的。例如一個(gè)名為burnout的系統(tǒng)調(diào)用將調(diào)用內(nèi)核函數(shù)sys_burnout()。
?系統(tǒng)調(diào)用機(jī)制在本手冊(cè)的第三章中進(jìn)行了討論。觀看在include/linux/sched.h中的for_each_task和SET_LINKS能夠幫助理解進(jìn)程表中的列表和樹(shù)結(jié)構(gòu)。
創(chuàng)建和結(jié)束進(jìn)程
unix系統(tǒng)是通過(guò)fork()系統(tǒng)調(diào)用創(chuàng)建一個(gè)進(jìn)程的,而進(jìn)程的終止是通過(guò)exit()或收到一個(gè)信號(hào)來(lái)完成的。它們的Linux實(shí)現(xiàn)位于kernel/fork.c和kernel/exit.c中。 派生出一個(gè)進(jìn)程是很容易的,所以fork.c程序很短并易于理解。它的主要任務(wù)是為新的進(jìn)程填寫(xiě)數(shù)據(jù)結(jié)構(gòu)。除了填寫(xiě)各個(gè)字段以外,相關(guān)的步驟有:
??取得一個(gè)空閑內(nèi)存頁(yè)面來(lái)保存task_struct
??找到一個(gè)空閑的進(jìn)程槽(find_empty_process())
??為內(nèi)存堆棧頁(yè)kernel_stack_page取得另一個(gè)空閑的內(nèi)存頁(yè)面
??將父輩的LDT拷貝到子進(jìn)程
??復(fù)制父進(jìn)程的mmap信息
sys_fork() 同樣也管理文件描述符和inode。
?1.0的內(nèi)核也對(duì)線程提供某些不夠完善的支持,所以fork()系統(tǒng)調(diào)用對(duì)此也給出了某些示意。內(nèi)核的線程是主流內(nèi)核以外的過(guò)程產(chǎn)品。
從一個(gè)進(jìn)程中退出是比較有竅門(mén)的,因?yàn)楦高M(jìn)程必須被通告有關(guān)任何子進(jìn)程的退出。而且,一個(gè)進(jìn)程可以由另外一個(gè)進(jìn)程使用kill()而退出(這些是Unix的特性),所以除了sys_exit()之外,sys_kill()以及sys_wait()的各種特性也存在于exit.c之中了。
這里不對(duì)exit.c的代碼加以討論---因?yàn)樗稽c(diǎn)也不令人感興趣。為了以一致的狀態(tài)退出系統(tǒng),它涉及到許多細(xì)節(jié)。而POSIX標(biāo)準(zhǔn)對(duì)于信號(hào)則是要求相當(dāng)嚴(yán)格的,所以這里必須對(duì)其加以敘述。
執(zhí)行程序
在調(diào)用了fork()之后,就有同一個(gè)程序的兩個(gè)拷貝在運(yùn)行了,通常一個(gè)程序使用exec()執(zhí)行另一個(gè)程序。exec()系統(tǒng)調(diào)用必須定位該執(zhí)行文件的二進(jìn)制映像,加載并執(zhí)行它。詞語(yǔ)‘加載’并不一定意味著“將二進(jìn)制映像拷貝進(jìn)內(nèi)存”,因?yàn)長(zhǎng)inux支持按需加載。 exec()的Linux實(shí)現(xiàn)支持不同的二進(jìn)制格式。這是通過(guò)linux_binfmt結(jié)構(gòu)來(lái)達(dá)到的,其中內(nèi)嵌了兩個(gè)指向函數(shù)的指針--一個(gè)是用于加載可執(zhí)行文件的,另一個(gè)用于加載庫(kù)函數(shù),每種二進(jìn)制格式都實(shí)現(xiàn)有這兩個(gè)函數(shù)。共享庫(kù)的加載是在exec()同一個(gè)源程序中實(shí)現(xiàn)的,但我們只討論exec()本身。 Unix系統(tǒng)提供了六種exec()函數(shù)。除了一個(gè)以外,所有都是以庫(kù)函數(shù)的形式實(shí)現(xiàn)的,并且,Linux內(nèi)核是單獨(dú)實(shí)現(xiàn)sys_execve()調(diào)用的。它執(zhí)行一個(gè)非常簡(jiǎn)單的任務(wù):加載可執(zhí)行文件的頭部,并試著去執(zhí)行它。如果頭兩個(gè)字節(jié)是“#!”,那么就會(huì)解析該可執(zhí)行文件的第一行并調(diào)用一個(gè)解釋器來(lái)執(zhí)行它,否則的話,就會(huì)順序地試用各個(gè)注冊(cè)過(guò)的二進(jìn)制格式。 Linux本身的格式是由fs/exec.c直接支持的,并且相關(guān)的函數(shù)是load_aout_binary和load_aout_library。對(duì)于二進(jìn)制,函數(shù)將加載一個(gè)“a.out”可執(zhí)行文件并以使用mmap()加載磁盤(pán)文件或調(diào)用read_exec()而結(jié)束。前一種方法使用了Linux的按需加載機(jī)理,在程序被訪問(wèn)時(shí)使用出錯(cuò)加載方式(fault-in)加載程序頁(yè)面,而后一種方式是在主機(jī)文件系統(tǒng)不支持內(nèi)存映像時(shí)(例如“msdos”文件系統(tǒng))使用的。
?新近的1.1內(nèi)核內(nèi)嵌了一個(gè)修訂的msdos文件系統(tǒng),它支持mmap()。而且linux_binfmt結(jié)構(gòu)已是一個(gè)鏈表而不是一個(gè)數(shù)組了,以允許以一個(gè)內(nèi)核模塊的方式加載一個(gè)新的二進(jìn)制格式。最后,結(jié)構(gòu)的本身也已經(jīng)被擴(kuò)展成能夠訪問(wèn)與格式相關(guān)的核心轉(zhuǎn)儲(chǔ)程序了。

非常好我支持^.^

(5) 100%

不好我反對(duì)

(0) 0%

      發(fā)表評(píng)論

      用戶評(píng)論
      評(píng)價(jià):好評(píng)中評(píng)差評(píng)

      發(fā)表評(píng)論,獲取積分! 請(qǐng)遵守相關(guān)規(guī)定!

      ?