版權說明:本文檔由用戶提供并上傳,收益歸屬內容提供方,若內容存在侵權,請進行舉報或認領
文檔簡介
1、盡管linux絕對是最流行的開源操作系統(tǒng),但是相對于其他操作系統(tǒng)的漫 長丿力史來說,linux的丿力史非常短暫。在計算機出現(xiàn)早期,程序員是使用硬件語 言在裸硬件上進行開發(fā)的。缺少操作系統(tǒng)就意味著在某個吋間只有一個應用程序 (和一個用戶)可以使用這些龐大而又昂貴的設備。早期的操作系統(tǒng)是在20世 紀50年代開發(fā)的,用來提供簡單的開發(fā)體驗。包括為ibm 701開發(fā)的 general motors operating system (gmos)和 north american aviation 為 ibm 709 開發(fā)的 fortran monitor system (fms)。在 20 世紀 60
2、年代,mit (massachusetts institute of technology)和一些公 司為 ge-645 開發(fā)了一個名為 multics (multiplexed information and computing service)的實驗性的操作系統(tǒng)。這個操作系統(tǒng)的開發(fā)者z at&t 后來退出了 multics,并在1970年開發(fā)了自己的名為unics的操作系統(tǒng)。與 這個操作系統(tǒng)一同誕生的是c語言,c語言就是為此而開發(fā)的,然后它們使用 c語言對操作系統(tǒng)進行了重寫,使操作系統(tǒng)開發(fā)具有可移植性。二十年后,andrewtanenbaum創(chuàng)建了一個微內核版本的unix®
3、;,名為minix (代表minimal unix),它可以在小型的個人計算機上運行。這個開源操作系 統(tǒng)在20世紀90年代激發(fā)了 linus torvalds開發(fā)linux的靈感(請參看圖 1所示)。linux快速從一個個人項目進化成為一個全球數(shù)千人參與的開發(fā)項目。對于 linux來說,最為重要的決策之一是采用gpl (gnu general public license) 在gpl保護z下,linux內核可以防止商業(yè)使用,并且它還從gnu項口(richard stallman開發(fā),其源代碼要比linux內核大得多)的用戶空間開發(fā) 受益。這允許使用一些非常有用的應用程序,例如gcc (gnu
4、compiler collection)和各種 shell 支持。nux的最大的好處z就是它的源碼公開。同時,公開的核心源碼也吸引著無數(shù)的 電腦愛好者和程序員;他們把解讀和分析linux的核心源碼作為自己的最大興趣,把修 改linux源碼和改造linux系統(tǒng)作為口己對計算機技術追求的最大目標。linux內核源碼是很具吸引力的,特別是當你弄懂了一個分析了好久都沒搞懂的問 題;或者是被你修改過了的內核,順利通過編譯,一切運行止常的時候。那種成就感真 是油然而生!而且,對內核的分析,除了出自對技術的狂熱追求z外,這種令人生畏的 勞動所帶來的回報也是非常令人著迷的,這也正是它擁有眾多追隨者的主要原因:
5、首先,你可以從中學到很多的計算機的底層知識,如后而將講到的系統(tǒng)的引導 和硬件提供的中斷機制等;其它,象虛擬存儲的實現(xiàn)機制,多任務機制,系統(tǒng) 保護機制等等,這些都是非都源碼不能體會的。同時,你還將從操作系統(tǒng)的整體結構中,體會整體設計在軟件設計中的份量和 作用,以及一些宏觀設計的方法和技巧:linux的內核為上層應用提供一個與具 體硬件不相關的平臺;同時在內核內部,它又把代碼分為與體系結構和碩件相 關的部分,和可移植的部分;再例如,linux雖然不是微內核的,但他把人部分的設備駁動處理成相對獨立的內核模塊,這樣減小了內核運行的開銷,增強了 內核代碼的模塊獨立性。而r你還能從對內核源碼的分析中,體會
6、到它在解決某個具體細節(jié)問題時,方 法的巧妙:如后面將分析到了的linux通過botoom_half機制來加快系統(tǒng)對屮 斷的處理。最璽要的是:在源碼的分析過程中,你將會被一點一點地、潛移默化地專業(yè)化。 一個專業(yè)的程序員,總是把代碼的清晰性,兼容性,可移植性放在很重要的位 置。他們總是通過定義人量的宏,來增強代碼的清晰度和可讀性,而乂不增加 編譯后的代碼長度和代碼的運行效率;他們總是在編碼的同時,就考慮到了以 后的代碼維護和升級。甚至,只要分析百分之一的代碼后,你就會深刻地體會 到,什么樣的代碼才是一個專業(yè)的程序員寫的,什么樣的代碼是一個業(yè)余愛好 者寫的。而這一點是任何沒有真正分析過標準代碼的人都
7、無法體會到的。然而,由于內核代碼的冗長,和內核體系結構的龐雜,所以分析內核也是一個很艱 難,很需耍毅力的事;在缺乏指導和交流的悄況下,尤其如此。只有方法正確,才能事 半功倍。止是基丁這種考慮,作者希望通過此文能給人家一些借鑒和啟迪。由于本人所進行的分析都是基于2.2.5版本的內核;所以,如果沒有特別說明,以 下分析都是基于i386單處理器的2.2.5版本的linux內核。所有源文件均是相對于目錄 /usr/src/linux 的。方法之一:從何入手要分析linux內核源碼,首先必須找到各個模塊的位置,也即要弄懂源碼的文件組 織形式。雖然對于有經(jīng)驗的高手而言,這個不是很難;但對于很多初級的lin
8、ux愛好者, 和那些對源碼分析很有興趣但接觸不多的人來說,這還是很冇必要的。1> linux核心源程序通常都安裝在/usr/src/linux卜,而且它有一個非常簡單的編號 約定:任何偶數(shù)的核心(的二個數(shù)為偶數(shù),例如2.0.30)都是一個穩(wěn)定地發(fā)行的核心, 而任何奇數(shù)的核心(例如2.1.42)都是一個開發(fā)中的核心。2、核心源程序的文件按樹形結構進行組織,在源程序樹的最上層,即目錄 /usr/src/linux卜有這樣一些目錄和文件: copying: gpl版權中明。對具有gpl版權的源代碼改動而形成的程序,或使用 gpl工具產(chǎn)生的程序,具有使用gpl發(fā)表的義務,如公開源代碼; cred
9、its:光榮榜。對linux做出過很大貢獻的一些人的信息; maintainers:維護人員列表,對當前版本的內核各部分都有誰負責; makefile:第一個makefile文件。用來組織內核的各模塊,記錄了個模塊間的相互這 間的聯(lián)系和依托關系,編譯時使用;仔細閱讀各子目錄卜的makefile文件對弄清各個文 件這間的聯(lián)系和依托關系很有幫助; readme:核心及其編譯配置方法簡單介紹; rules.make:各種makefilemake所使用的一些共同規(guī)則; reportingbugs:有關報告bug的一些內容; arch/ : arch子目錄包括了所有和體系結構相關的核心代碼。它的每一個子
10、目錄都代 表一種支持的體系結構,例如i386就是關于intel cpu及與z相兼容體系結構的子口錄。pc機一般都基于此目錄; include/: include t目錄包括編譯核心所需要的大部分頭文件。與平臺無關的頭文件 在include/linux子目錄下,與intel cpu相關的頭文件在include/asm-i386子目錄下, 而include/scsi目錄則是有關scsi設備的頭文件口錄; ini”:這個目錄包含核心的初始化代碼(注:不是系統(tǒng)的引導代碼),包含兩個文件 main.c和version.c,這是研究核心如何工作的好的起點之一。 mm/:這個目錄包括所有獨立于cpu體系結構
11、的內存管理代碼,如頁式存儲管理內 存的分配和釋放等;而和體系結構相關的內存管理代碼則位于arch/*/mm/,例如 arch/i386/mm/fault.c; kernel/:主要的核心代碼,此目錄下的文件實現(xiàn)了大多數(shù)linux系統(tǒng)的內核函數(shù),其 中最巫要的文件當屬sched.c;同樣,和體系結構相關的代碼在arch/*/kernel中; drivers/:放置系統(tǒng)所有的設備驅動程序;每種驅動程序又各占用一個子h錄:如, /block下為塊設備驅動程序,比如ide (ide.c)。如果你希望查看所有可能包含文件系 統(tǒng)的設備是如何初始化的,你可以看drivers/block/genhd.c屮的d
12、evice_setup()o它不 僅初始化碩盤,也初始化網(wǎng)絡,因為安裝nfs文件系統(tǒng)的時候需要網(wǎng)絡 documentation/:文檔目錄,沒有內核代碼,只是一套有用的文檔,可惜都是english 的,看看應該有用的哦; fs/:所有的文件系統(tǒng)代碼和各種類型的文件操作代碼,它的每一個了目錄支持一個文 件系統(tǒng),例如fat和ext2; ipc/:這個口錄包含核心的進程間通訊的代碼; lib/:放置核心的庫代碼; net/:核心與網(wǎng)絡相關的代碼; modules/:模塊文件日錄,是個空日錄,用于存放編譯時產(chǎn)牛的模塊日標文件; scripts/:描述文件,腳本,用于對核心的配置;一般,在每個子目錄卞,
13、都有一個makefile和一個readme文件,仔細閱讀這兩 個文件,對內核源碼的理解很有用。對linux內核源碼的分析,有兒個很好的入口點:一個就是系統(tǒng)的引導和初始化, 即從機器加電到系統(tǒng)核心的運行;另外一個就是系統(tǒng)調用,系統(tǒng)調用是用戶程序或操作 調用核心所提供的功能的接口。対于那些対硬件比較熟悉的愛好者,從系統(tǒng)的引導入手 進行分析,可能來的容易一些;而從系統(tǒng)調用下口,則可能更合適于那些在dos或uinx、 linux下有過c編程經(jīng)驗的高手。這兩點,在后面述將介紹到。方法之二:以程序流程為線索,一線串珠從表面上看,linux的源碼就象一團扎亂無章的亂麻,其實它是一個組織得冇條冇 理的蛛網(wǎng)。耍
14、把整個結構分析清楚,除了找岀線頭,還得理順各個部分之間的關系,有 條不紊的一點一點的分析。所謂以程序流程為線索、一線串珠,就是指根據(jù)程序的執(zhí)行流程,把程序執(zhí)行過程 所涉及到的代碼分析清楚。這種方法最典型的應用有兩個:一是系統(tǒng)的初始化過程;二 是應用程序的執(zhí)行流程:從程序的裝載,到運行,一直到程序的退出。為了簡便起見,遵從循序漸進的原理,現(xiàn)就系統(tǒng)的初始化過程來具體的介紹這種方 法。系統(tǒng)的初始化流程包括:系統(tǒng)引導,實模式下的初始化,保護模式下的初始化共三 個部分。下面將介紹。inux系統(tǒng)的常見引導方式有兩種:lilo引導和loadin引導;同時linux內核也自帶 了一個bootsectloade
15、r。由于它只能實現(xiàn)linux的引導,不像前兩個那樣具有很大的靈 活性(lilo可實現(xiàn)多重引導、loadin可在dos卞引導linux),所以在普通應用場合實際上 很少使用bootsect-loaderc當然,bootsect-loader也具有它自己的優(yōu)點:短小沒有多 余的代碼、附帶在內核源碼中、是內核源碼的有機組成部分,等等。bootsect-loader在內和源碼中對應的程序是/arch/i386/boot/bootsect.s。下面將 主要是針對此文件進行的分析。1. 幾個相關文件:<1> /arch/i386/boot/bootsect.s <2> /in cl
16、ude/li nux/con fig.h<3> /in clude/asm/boot.h<4> /in clude/li nu x/autoconf.h2. 引導過程分析:對于intel x86 pc,開啟電源后,機器就會開始執(zhí)行rom bios的一系列系統(tǒng) 測試動作,包括檢查ram, keyboard,顯示器,軟硬磁盤等等。執(zhí)行完bios 的系統(tǒng)測試z后,緊接著控制權會傳移給rom屮的啟動程序(rom bootstrap routine);這個程序會將磁盤上的笫0軌笫0扇區(qū)(叫boot sector或mbr ,系 統(tǒng)的引導程序就放在此處)讀入內存中,并放到自0x070
17、0:0x0000 始的512 個字節(jié)處;然后處理機將跳到此處開始執(zhí)行這一引導程序;也即裝入mbr屮的 引導程序后,cs:ip = 0x0700:0x0000。加電后處理機運行在與8086相兼容 的實模式下。如果耍用bootsect-loader進行系統(tǒng)引導,則必須把bootsect.s編譯連接斤對應 的二進制代碼置于mbr;當rom bios把bootsect.s編譯連接后對應的二進 制代碼裝入內存斤 機器的控制權就完全轉交給bootsect;也就是說,bootsect 將是第一個被讀入內存中并執(zhí)行的程序。bootsect接管機器控制權后,將依次進行以下一些動作:1. 首先,bootsect將
18、它泊己”(自位置0x07c0:0x0000 始的512個字節(jié))從被 rom bios載入的地址0x0700:0x0000處搬到0x9000:0000處 這一任務山 bootsect.s的前十條指令完成;第十一條指令“jmpi go,initseg”則把機器跳轉 到“新”的 bootsect 的“jmpi go,initseg”后的那條指令“go: mov di,#0x4000-12n; 之后,繼續(xù)執(zhí)行bootsect的剩卜的代碼;在bootsect.s屮定義了幾個常量:bootseg = 0x07c0 bios載入mbr的約定位置的段址;initseg = 0x9000 bootsect.s的
19、前i 條指令將自己搬到此處(段址)setupseg =0x9020 裝入 setup.s 的段址sysseg =0x1000系統(tǒng)區(qū)段址對于這些常量可參m/include/asm/boot.h中的定義;這些常量在下面的分析屮將 會經(jīng)常用到;2. 以0x9000:0x4000-12為棧底,建立自己的棧區(qū);其中0x9000:0x4000-12 到0x9000:0x4000的一十二個字節(jié)預留作磁盤參數(shù)表區(qū);3. 在0x9000:0x4000-12到0x9000:0x4000的一二個預留字節(jié)中建立新的磁 盤參數(shù)表,之所以叫“新”的磁盤參數(shù)表,是相對于bios建立的磁盤參數(shù)表而言 的。由于設計者考慮到有些
20、老的bios不能準確地識別磁盤“每個磁道的扇區(qū)數(shù)”, 從而導致bios建立的磁盤參數(shù)表妨礙磁盤的最高性能發(fā)揮,所以,設計者就在 bios建立的磁盤參數(shù)表的棊礎上通過枚舉法測試,試圖建立準確的“新”的磁盤參 數(shù)表(這是在后繼步驟中完成的);并把參數(shù)表的位置由原來的0x0000:0x0078 搬到0x9000:0x4000-12;且修改老的磁盤參數(shù)表區(qū)使之指向新的磁盤參數(shù)表;4. 接下來就到了 load_setup子過程;它調用0x13中斷的第2號服務;把第0 道第2扇區(qū)開始的連續(xù)的setup_sects (為常量4)個扇區(qū)讀到緊鄰bootsect的內 存區(qū);,即0x9000:0x0200開始的2
21、048個字節(jié);而這四個扇區(qū)的內容即是 /arch/i386/boot/setup.s編譯連接后對應的二進制代碼;也就是說,如果耍用 bootsect-loader進行系統(tǒng)引導,不僅必須把bootsect.s編譯連接后對應的二進 制代碼置于mbr,而且還得把setup.s編譯連接后對應的二進制代碼置于緊跟 mbr后的連續(xù)的四個扇區(qū)屮;當然,由于setup.s對應的可執(zhí)行碼是山bootsect 裝載的,所以,在我們的這個項口中可以通過修改bootsect來根據(jù)需要隨意地 放置setup.s對應的可執(zhí)行碼;5. ioad_setup子過程的唯一出口是probejoop子過程;該過程通過枚舉法測 試磁
22、盤“每個磁道的扇區(qū)數(shù)”;6. 接下來兒個子過程比較清晰易懂:打印我們熟悉的“l(fā)oading”;讀入系統(tǒng)到 0x1000:0x0000;關掉軟駁馬達;根據(jù)的5步測岀的“每個磁道的扇區(qū)數(shù)”確定磁 盤類型;最后跳轉到0x9000:0x0200,即setup.s對應的m執(zhí)行碼的入口,將機 器控制權轉交setup.s;整個bootsect代碼運行完畢;3. 引導過程執(zhí)行完后的內存印象圖:出于簡便考慮,在此分析屮,我忽略了對大內核的處理的分析,因為對大內核的處 理,只是此引導過程屮的一個很小的部分,并不影響對整體的把握。完成了系統(tǒng)的引導 后,系統(tǒng)將進入到初始化處理階段。系統(tǒng)的初始化分為實模式和保護模式兩部
23、分。 ii、實模式下的初始化實模式下的初始化,主要是指從內核引導成功后,到進入保護模式之前系統(tǒng)所做的 一些處理。在內核源碼中對應的程序是/arch/i386/boovsetup.s;以下部分主要是針對 此文件進行的分析。這部分的分析主要是耍奔懂它的處理流程和initseg(9000:0000) 段參數(shù)表的建立,此參數(shù)表包含了很多碩件參數(shù),這些都是以后進行保護模式卜初始化, 以及核心建立的基礎。1.幾個其它相關文件:<1> /arch/i386/boot/bootsect.s<2> /in clude/linux/config.h<3> /include/as
24、m/boot.h<4> /in elude/ asm/segme nt.h <5> /include/li nu x/version.h<6> /include/li nu x/compile.h2.實模式下的初始化過程分析:開始復位硬盤系統(tǒng)確禍整系統(tǒng)內核段地址到正確位苴"彩尹和沐3汕僮于setup. s 的束氐衛(wèi)確,則setup區(qū)全出 裝在 9qjq; q2jq 和 5000:9004. 何;歪則,余m和系統(tǒng)內絃一進 裝在 1000: 0000 之qaa55 -和 5a5a澤來的糸覘內建段范址 a 1000芒執(zhí)的段址還 必須加二setjp余部占
25、用詢空間.將 hdo 和 hdal 的參瓠 從 0000:4*0x41 的32個字節(jié)搬到0x0x9000:0x0080linuz實模式下的初始儷程圖二將 hdal 的參數(shù)(a 0x000:0x0090 起 的10個寧節(jié))涪零檢杳m3 a bjs,將其參數(shù)貫于0x9000: oxooao檢杳ps/2鼠標器,存在則置0x9000: 0x0iff為oxaa,否則苴其為0檢查apmbios,將其夢皺直于0x000:0x00645'j ohpooo: oko082 m三十二個字節(jié)關申斷:并禁止nmi謹求以sysseg與in:tseg間的4kb作為緩沖取, 每設4k,將系統(tǒng)搬到0z0100:000
26、0處檢查自己杲否位于setup seg j(t,不存.則探至此處1 idt為空,設呻段址咖心,共256個入口,并設了一個系統(tǒng)數(shù)據(jù)和一個代解段in;el把d-51號申斷向 量用來處理異常李件,而 t8m則把碩申晰設住 dx)8-d:<df防以必須審 新編程,把硬中騎設到 dx2d-d:<2f使a20線有瓶對中斷控制器8259a-l,9259a-2重新編程t孕保護模對initseg(9000:0000)段參數(shù)表:(參見 include/linux/tty.h)參數(shù)名偏移量(段址均為 0x9000)長度byte參考文件param_cursor_pos0x00002arch/i386/bo
27、ot/video.sextended mem size0x00022arch/i386/boot/setup.sparam_video_page0x00042arch/i386/boot/video.sparam_video_mode0x00061arch/i386/boot/video.sparam_video_cols0x00071arch/i386/boot/video.s沒用0x00082include/linux/tty.hparam_video_ega_bx0x000a2arch/i386/boot/video.s沒用0x000c2include/linux/tty.hparam_
28、video_linesoxoooe1arch/i386/boot/video.sparam_have_vgaoxooof1arch/i386/boot/video.sparam_font_points0x00102arch/i386/boot/video.sparam_lfb_width0x00122arch/i386/boot/video.sparam_lfb_height0x00142arch/i386/boot/video.sparam_lfb_depth0x00162arch/i386/boot/video.sparam_lfb_base0x00184arch/i386/boot/vi
29、deo.sparam_lfb_size0x001c4arch/i386/boot/video.s暫未用0x00204include/linux/tty.hparam_lfb_linelength0x00242arch/i386/boot/video.sparam_lfb_colors0x00266arch/i386/boot/video.s暫未用0x002c2arch/i386/boot/video.sparam_vesapm_seg0x002e2arch/i386/boot/video.sparam_vesapm_off0x00302arch/i386/boot/video.sparam_l
30、fb_pages0x00322arch/i386/boot/video.s保留0x0034-0x003finclude/linux/tty.hapm bios version0x00402arch/i386/boot/setu p.sbios code segment0x00422arch/i386/boot/setup.sbios entry offset0x00444arch/i386/boot/setup.sbios 16 bit code seg0x00482arch/i386/boot/setup.sbios data segment0x004a2arch/i386/boot/set
31、up.s支持32位標志0x004c2arch/i386/boot/setu p.sbios code seg length0x004e4arch/i386/boot/setup.sbios data seg length0x00522arch/i386/boot/setup.shdo參數(shù)0x008016arch/i386/boot/setu p. shdo參數(shù)0x009016arch/i386/boot/setup.sps/2 device 標志0x0 iff1arch/i386/boot/setup.s* 注: include/linux/tty.h : cl_magic and cl_of
32、fset here1. include/linux/tty.h :unsigned char rsvd_size; /* 0x2c */ unsigned char rsvd_pos; /* 0x2d */ 0表示沒有apm bios 0x0002置位表示支持32位模式 0表示沒有,oxoaa表示有鼠標器川、保護模式下的初始化保護模式下的初始化,是指處理機進入保護模式后到運行系統(tǒng)笫一個內核程序過程 中系統(tǒng)所做的一些處理。保護模式卜的初始化在內核源碼中對應的程序是 /arch/i386/boovcompressed/head.s 和 /arch/i386/kernel/head.s ;以下部分主
33、要 是針對這兩個文件進行的分析。1. 幾個相關文件:<1 .> /arch/i386/boot/compressed/head.s<2 > /arch/i386/kernel/head.s<3.> /arch/i386/boot/compressed/misc.c<4.> /arch/i386/boot/setup.s<5.> /inelude/ asm/segment.h<6.> /arch/i386/kernel/traps.c<7> /include/i386/desc.h<8.> /incl
34、ude/asm-i386/processor.h2. 保護模式下的初始化過程分析:一、/arch/i386/kernel/head.s 流程:逹意,從此均 為俁護虛擬 方式尋址/arch/i386/kernel/head-sgs開始 + 用 kernel ds 初始化 ds, es, fs, gs此時頁目錄只定義了 2個頁表項: 第0項和第768項,此兩項都對 應同一個頁表0x00102 »同時, head.s 也0x00102000 處定義了 一個頁表民0,餞頁表對應物理地 址的0-4m/即在0-4m/物理 地址與邏輯地址是一致的;當然 通過頁目錄的第7住項,也可訪 問此段空間即3
35、g3gb-mm段 也段應此段bssji setup. s 的代碼段? k同時參見:/ ar ch/ i386/kernel/1 raps. c和include/i386/ desc. hinitseg段的參數(shù)參見 “實模式下的初始化j emp后 2k將作為命令緩沖區(qū) empty_zero_page 位 于 0x105000 | 大小 4ki務 cl_base_addr;cl_offset 開始的 2k 個字節(jié)拷貝到empty zero page的后2k此時皿已經(jīng)初始化了,只需裝載到i dtr即可正常情況下,不會返 回 > 若返回,則不正 常,所以死循環(huán)的£h/i巒何則l/it仝
36、號程圖二有關cpu的信息被放在一個 命名b oot,_cpu_data的結構 cpuinfo_x86 中丿參見 in.cludle/asm-i386/processor.h|檢查cpu類型,保存cpu信息;并根據(jù)不同類型的cpu來重新初始化cro檢查協(xié)處理器是否有救,無效則em 5位、否則復 位,同時對保存cpu信息的相應單元迸行標示,在進入保護模式前,已初貽化 了一個只含兩個有效采統(tǒng)段 的gdt ;此處重新建立gdt, 新的gdt位于0x106000,共 12+2*1ir_tasks 個 項毎頂 8byte?設置了兩個系紜段和 兩個用戶段,都是從0并始的 4g大小還設了 4個apm段二、/a
37、rch/i386/boot/compressed/head.s 流程:|/arch/i386/boot/cc>iip:r巳 ss巳d/h巳adl s 流程圖 |1. 從流程圖中可以看到,保護模式下的初始化主耍干了這樣兒件事:1. 解壓內核到0x100000處、2. 建立頁h錄和pgo頁表并啟動分頁功能(即虛存管理功能)、3. 保存實模式下測到的硬件信息到empty_zero_page初始化命令 緩存區(qū)、4. 檢測cpu類型、檢查協(xié)處理器、5. 重新建立gdt全局描述符表、和屮斷描述附表idt;2. 從頁h錄和pgo頁表可以看出,0�; 4m物理內存被用作系統(tǒng)區(qū),它被映射 到系
38、統(tǒng)段線性空間的0�; 4m和3g�; 3g+4m;即系統(tǒng)可以通過訪問這兩 個段來訪問實際的0�; 4m物理內存,也就是系統(tǒng)所在的區(qū)域;3. 木來在實模式下初始化時已經(jīng)建立了全局描述符表gdt,而此處重新建立全局描 述符表gdt則主要是出于兩個原因:一個就是若內核是大內核bzimag,則以前 建立的gdt,可能已經(jīng)在解壓時被覆蓋掉了所以,在這個源碼文件中均只采用相 對轉移指令jxxnf或jxxnb;二是以前建立的gdt是建立在實地址方式下的,而 現(xiàn)在則是在啟用保護虛擬地址方式之后建立的,也即現(xiàn)在的gdt是建立在邏輯地 址(即線性地址)上的;4. 每次建立新的g
39、dt后和啟用保護虛擬地址方式后都必須巫新裝載系統(tǒng)棧和巫新 初始化各段寄存器:cs,ds,es,fs,gs;5. 從實模式下的初始化和保護模式下的初始化過程可以看ill, linux系統(tǒng)由實模式 進入到保護模式的過程大致如下:實模式到386保護模式毓程圖|第一歩第二步第三步6. 由于分頁機制只能在保護模式下啟動,不能在實模式下啟動,所以第一步是必要的; 又因為在386保護模式下gdt和idt是建立在邏輯地址(線性地址)上的,所以第三步也 是必要的;7. 經(jīng)過實模式和保護模式下的初始后,主要系統(tǒng)數(shù)據(jù)分布如下:初始后屯要系統(tǒng)數(shù)據(jù)分布表位置系統(tǒng)數(shù)據(jù)大小0x101000頁目錄 swapper_pg_di
40、r4k0x102000頁表pgo4k0x103000empty_bad_page4k0x104000e m pty_bad_pa g e_ta b i e4k0x105000empty_zero_page4k0x105000系統(tǒng)硬件參數(shù)2k0x105800命令緩沖區(qū)2k0x106000全局描述附表gdtjable4192b從上面對linux系統(tǒng)的初始化過程的分析可以看出,以程序執(zhí)行流程為線索、一線 出珠,就是按照程序的執(zhí)行先后順序,弄懂程序執(zhí)行的各個階段所進行的處理,及其各 階段之間的相互聯(lián)系。而流程圖應該是這種分析方法最合適的表達工具。事實上,以程序執(zhí)行流程為線索,是分析任何源代碼都首選的方
41、法。山于操作系統(tǒng) 的特殊性,光用這種方法是遠遠不夠的。當然用這種方法來分析系統(tǒng)的初始化過程或用 戶進程的執(zhí)行流程應該說是很有效的。方法之三:以數(shù)據(jù)結構為基點,觸類旁通結構化程序設計思想認為:程序=數(shù)據(jù)結構+算法。數(shù)據(jù)結構體現(xiàn)了整個系統(tǒng) 的構架,所以數(shù)據(jù)結構通常都是代碼分析的很好的著手點,對linux內核分析尤其如此。 比如,把進程控制塊結構分析清楚了,就對進程有了基本的把握;再比如,把頁目錄結 構和頁表結構弄懂了,兩級虛存映射和內存管理也就掌握得差不多了。為了體現(xiàn)循序漸 進的思想,在這我就以linux對屮斷機制的處理來介紹這種方法。首先,必須指出的是:在此處,中斷指廣義的中斷概義,它指所有通過
42、idt進行的 控制轉移的機制和處理;它覆蓋以f兒個常用的概義:中斷、異常、可屏蔽中斷、不可 屏蔽中斷、換中斷、軟中斷 i、硬件提供的中斷機制和約定'尋址:彼件提供可供256個服務程序中斷進入的入口,即中斷向量;中斷向量在保護模式下的實現(xiàn)機制是中斷描述符表idt, idt的位置由idtr確定,idtr 是個48位的寄存器,高32位是idt的基址,低16位為idt的界限(通常為2k=256*8);idt中包含256個中斷描述符,對應256個中斷向量;每個中斷描述符8位,其結 構如圖一:0-1offset (15-0)2-3selector15 >14 l3fl28,t4-5p |dp
43、l | oxoe| 0x006-7offset (3116)oj注.e. 刪磁 ?=o磁 使用則«賢異常dpu 00-11.對應ih個特6嗽(00量高)中斷進入過程如圖二所示。當中斷是由低特權級轉到高特權級(即當前特權級cpl>dpl)時,將進行堆棧的轉 移;內層堆棧的選擇曲當前tss的相應字段確定,而r內層堆棧將依次被壓入如下數(shù)據(jù): 外層ss,外層esp,eflags,外層cs,外層eip;中斷返回過程為一逆過程;圖二7中靳進入京尋圖idt selector特性字 bffsg - 基址特性字w- pdt 或 ldt |服務程序入口二異常處理機制:intel公司保留031號中斷
44、向量用來處理異常事件:當產(chǎn)生一個異常時,處理機就會自動把控制轉移到相應的處理程序的入口,異常的處理程序由操作系統(tǒng)提供,中斷向量和異常事件對應如表一:表一、中斷向量和異常事件對應表中斷向量號異常事件linux的處理程序0除法錯誤divide_error1調試異常debug2nmi中斷nmi3單字節(jié),int3int34溢出overflow5邊界監(jiān)測中斷bounds6無效操作碼lnvalid_op7設備不可用device_ no t_available8雙垂故障double_fault9協(xié)處理器段溢出coprocessor_segment_overrun10無效tssin calid_tss11缺段
45、中斷nsegme nt_not_prese nt12堆棧異常stack_segme nt13一般保護異常general_protection14頁異常page_fault15spurious_interrupt_bug16協(xié)處理器出錯coprocessor_error仃對齊檢查中斷alignmen t_check三可編程中斷控制器8259a :為更好的處理外部設備,x86微機提供了兩片可編程屮斷控制器,用來輔助cpu接 受外部的中斷信號;對丁中斷,cpu只提供兩個外接引線:nmi和intr;nmi只能通過端口操作來屏蔽,它通常用于:電源掉電和物理存儲器奇偶驗錯;intr可通過直接設置屮斷屏蔽位
46、來屏蔽,它可用來接受外部中斷信號,但只有一 個引線,不夠用;所以它通過外接兩片級鏈了的8259a,以接受更多的外部中斷信號。 8259a主要完成這樣一些任務:a. 中斷優(yōu)先級排隊管理,b. 接受外部中斷請求c. 向cpu提供小斷類型號外部設備產(chǎn)生的屮斷信號在irq (中斷請求)管腳上首先由中斷控制器處理。屮斷 控制器可以響應多個屮斷輸入,它的輸岀連接到cpu的int管腳,信號可通過int 管腳,通知處理器產(chǎn)生了中斷。如果cpu這時可以處理中斷,cpu會通過inta (中 斷確認)管腳上的信號通知屮斷控制器已接受屮斷,這時,屮斷控制器可將一個8位 數(shù)據(jù)放置在數(shù)據(jù)總線上,這一 8位數(shù)據(jù)也稱為中斷向
47、量號,cpu依據(jù)中斷向量號和中 斷描述符表(idt)中的信息自動調用相應的中斷服務程序。圖三屮,兩個屮斷控制器 級聯(lián)了起來,從屬中斷控制器的輸出連接到了主中斷控制器的第3個中斷信號輸入, 這樣,該系統(tǒng)可處理的外部中斷數(shù)量最多可達15個,圖的右邊是i386 pc中各中斷 輸入管腳的一般分配??赏ㄟ^對8259a的初始化,使這15個外接引腳對應256個屮斷 向量的任何15個連續(xù)的向量;由于intel公司保留031號中斷向量用來處理異常事件(而 默認情況下,ibm bios把碩中斷設在0x08-0x0f),所以,硬屮斷必須設在31以后,linux 則在實模式下初始化時把其設在0x200x2f,対此下而
48、還將具體說明。圖三、i386 pc可編程中斷控制器8259a級鏈示意圖irq0 (時鐘)irq 1(鍵盤)irq 3(tty2)irq 4( ttyl)irq5(xtwinchester)irq 6 (軟駝)irq 7 (打印機)irq 8 (實時時鐘)irq 9 (重定向的irq2)irq 10irq 11irq 12irq 13( fpu 異常)irq 14( at winchester)irq 15碩件中斷機制提供了 256個入口,即idt中包含的256個中斷描述符(對應256個 中斷向量)。ifu 0-31號中斷向量被intel公司保留用來處理異常事件,不能另作它用。對這031 號中斷
49、向量,操作系統(tǒng)只需提供界常的處理程序,當產(chǎn)生一個異常時,處理機就會口動 把控制轉移到相應的處理程序的入口,運行相應的處理程序;而事實上,對于這32個 處理異常的中斷向量,此版本(225)的linux只提供了 017號中斷向量的處理程序, 其對應處理程序參見表一、中斷向量和異常事件對應表;也就是說,17-31號中斷向量 是空著未用的。既然031號中斷向量已被保留,那么,就是« k 32-255共224個屮斷向量可用。 這224個中斷向量又是怎么分配的呢?在此版本(2.2.5)的linux中,除了 0x80 (syscall_vector)用作系統(tǒng)調用總入口之外,其他都用在外部硬件中斷源
50、上,其中 包括可編程中斷控制器8259a的15個irq:事實上,當沒有定義config_x86_io_apic 時,其他223(除0x80外)個中斷向量,只利用了從32號開始的15個,其它208個空 著未用。這些中斷服務程序入口的設置將在下而有詳細說明。相關數(shù)據(jù)結構a. 中斷描述符表idt:也就是中斷向量表,相當如一個數(shù)組,保存著各中斷服務 例程的入口。(詳細描述參見圖一、中斷描述符格式)b. 與硬中斷相關數(shù)據(jù)結構:與硬中斷相關數(shù)據(jù)結構主要有三個:一:定義在/arch/i386/kernel/irq.h 中的struct hw_interrupt_type const char * type
51、name;void (*startup)(unsigned int irq);void (*shutdown)(unsigned int irq);void (*handle)(unsigned int irq, struct pt_regs * regs);void (*enable)(unsigned int irq);void (*disable)(unsigned int irq);二:定義在/arch/i386/kernel/irq.h 中的typedef struct unsigned int status; /* irq status - irqjnprogress, irq_d
52、isabled */ struct hw_interrupt_type *handler; /* handle/enable/disable functions */ struct irqaction *action; /* irq action list */unsigned int depth; /* disable depth for nested irq disables */ irq_desc_t;三:定義在泊clude/linux/ interrupt.h 屮的struct irqaction void (*handler)(int, void *, struct pt_regs
53、*);unsigned long flags;unsigned long mask;const char *name;void *dev_id;struct irqaction *next;;三者關系如下:圖四、與駛中斷相關的幾個數(shù)據(jù)結構各關系各結構成員詳述如下:a. struct irqaction結構,它包含了內核接收到特定 irq之后應該采取的操作,其成員如下: handler:是一指向某個隊 1數(shù)的指針。該函數(shù)就是所在結構對相應中斷的處理函 數(shù)。 flags:取值只有 sa_interrupt (中斷可嵌套),sa_sample_random(這個中斷是源于物理隨機性的),和sa_sh
54、irq (這個irq和英它struct irqaction 共享)。 mask:在x86或者體系結構無關的代碼屮不會使用(除非將其設置為0);只 有在sparc64的移植版本中耍跟蹤有關軟盤的信息時才會使用它。 name:產(chǎn)生屮斷的硬件設備的名字。因為不止一個硬件可以共享一個irq。 devjd:標識碩件類型的一個唯一的id。linux支持的所有硬件設備的每一種 類型,都有一個由制造廠商定義的在此成員中記錄的設備ido next:如果irq是共享的,那么這就是指向隊列屮下一個struct irqaction結 構的指針。通常情況下,irq不是共享的,因此這個成員就為空。a. struct hw
55、_interrupt_type 結構,它是一個抽象 的中斷控渝器。這包含一系列的指向函數(shù)的指針, 這些函數(shù)處理控制器特有的操作: typename:控制器的名字。 startup:允許從給定的控制器的irq所產(chǎn)生的事件。 shutdown:禁止從給定的控制器的irq所產(chǎn)牛的事件。 handle:根據(jù)提供給該函數(shù)的irq,處理唯一的中斷。 enable和disable:這兩個函數(shù)基本上和startup和shutdown相同;a.另外一個數(shù)據(jù)結構是irq_desc_t,它具有如下成 員: status: 一個整數(shù)。代表irq的狀態(tài):irq是否被禁止了,有關irq的設備當 前是否正被自動檢測,等等。
56、 handler:扌n|nj hw_interrupt_type 的指針。 action:指向irqaction結構組成的隊列的頭。止常悄況下每個irq只有一個操 作,因此鏈接列表的止常長度是1 (或者0)。但是,如果irq被兩個或者多個 設備所共享,那么這個隊列中就有多個操作。 depth: irq_desc_t的當前用戶的個數(shù)。主要是用來保證在中斷處理過程中irq 不會被禁止。 irq_desc是irq_desc_t類型的數(shù)組。對于每一個irq都有一個數(shù)組入口,即 數(shù)組把每一個irq映射到和它相關的處理程序和irq_desc_t中的其它信息。a.與bottom_half相關的數(shù)據(jù)結構:圖五、底半處理數(shù)據(jù)結構示意圖底半處理程序 bh_mask_count:計數(shù)器。對每個enable/disable請求嵌套對進彳亍計數(shù)。這 些請求通過調用enable_bh和disable_bh實現(xiàn)。每個禁止請求都增加計數(shù)器;每個使能請求都減小計竅器。當計數(shù)器払到0時,所有未完成的禁止語句都已 經(jīng)被使能語句所匹配了,因此下半部分最終被重新使能。(定義在kernel/softirq.c 中) bh_
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內容里面會有圖紙預覽,若沒有圖紙預覽就沒有圖紙。
- 4. 未經(jīng)權益所有人同意不得將文件中的內容挪作商業(yè)或盈利用途。
- 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內容本身不做任何修改或編輯,并不能對任何下載內容負責。
- 6. 下載文件中如有侵權或不適當內容,請與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 遼寧工業(yè)大學《測量學2》2023-2024學年第一學期期末試卷
- 浙江省金華市2024年中考數(shù)學模擬考試試卷含答案
- 喀什大學《幼兒園教師職業(yè)道德》2023-2024學年第一學期期末試卷
- 江蘇警官學院《電子商務數(shù)據(jù)分析與應用》2023-2024學年第一學期期末試卷
- 吉安幼兒師范高等??茖W?!督ㄖz影初步》2023-2024學年第一學期期末試卷
- 湖南理工學院《線天線與面天線》2023-2024學年第一學期期末試卷
- 高考物理模擬測試題(有答案)
- 重慶外語外事學院《軟件測試與質量保證》2023-2024學年第一學期期末試卷
- 重慶電子工程職業(yè)學院《地理研究方法與寫作》2023-2024學年第一學期期末試卷
- 浙江建設職業(yè)技術學院《鄉(xiāng)土文化與鄉(xiāng)村教育》2023-2024學年第一學期期末試卷
- 自來水維修員年度工作總結
- 國際海上避碰規(guī)則(中英版)課件
- 導電銅漿及其制備方法、應用與流程
- 批量訂購車輛合同范本
- 鋼鐵生產(chǎn)企業(yè)溫室氣體核算與報告案例
- 農業(yè)合作社全套報表(已設公式)-資產(chǎn)負債表-盈余及盈余分配表-成員權益變動表-現(xiàn)金流量表
- 貝利嬰幼兒發(fā)展量表BSID
- 人教部編版八年級歷史下冊第7課 偉大的歷史轉折課件(共25張PPT)
- SB/T 10863-2012家用電冰箱維修服務技術規(guī)范
- 偏癱患者的臨床護理及康復評估課件
- 檢驗科危急值項目范圍考核試題與答案
評論
0/150
提交評論