 理解Linux內(nèi)核最好預(yù)備的知識(shí)點(diǎn):
懂C語(yǔ)言 懂一點(diǎn)操作系統(tǒng)的知識(shí) 熟悉少量相關(guān)算法 懂計(jì)算機(jī)體系結(jié)構(gòu)
Linux內(nèi)核的特點(diǎn):
結(jié)合了unix操作系統(tǒng)的一些基礎(chǔ)概念
  Linux內(nèi)核的任務(wù):
1.從技術(shù)層面講,內(nèi)核是硬件與軟件之間的一個(gè)中間層。作用是將應(yīng)用層序的請(qǐng)求傳遞給硬件,并充當(dāng)?shù)讓域?qū)動(dòng)程序,對(duì)系統(tǒng)中的各種設(shè)備和組件進(jìn)行尋址。
2.從應(yīng)用程序的層面講,應(yīng)用程序與硬件沒(méi)有聯(lián)系,只與內(nèi)核有聯(lián)系,內(nèi)核是應(yīng)用程序知道的層次中的最底層。在實(shí)際工作中內(nèi)核抽象了相關(guān)細(xì)節(jié)。
3.內(nèi)核是一個(gè)資源管理程序。負(fù)責(zé)將可用的共享資源(CPU時(shí)間、磁盤空間、網(wǎng)絡(luò)連接等)分配得到各個(gè)系統(tǒng)進(jìn)程。
4.內(nèi)核就像一個(gè)庫(kù),提供了一組面向系統(tǒng)的命令。系統(tǒng)調(diào)用對(duì)于應(yīng)用程序來(lái)說(shuō),就像調(diào)用普通函數(shù)一樣。
內(nèi)核實(shí)現(xiàn)策略:
1.微內(nèi)核。最基本的功能由中央內(nèi)核(微內(nèi)核)實(shí)現(xiàn)。所有其他的功能都委托給一些獨(dú)立進(jìn)程,這些進(jìn)程通過(guò)明確定義的通信接口與中心內(nèi)核通信。
2.宏內(nèi)核。內(nèi)核的所有代碼,包括子系統(tǒng)(如內(nèi)存管理、文件管理、設(shè)備驅(qū)動(dòng)程序)都打包到一個(gè)文件中。內(nèi)核中的每一個(gè)函數(shù)都可以訪問(wèn)到內(nèi)核中所有其他部分。目前支持模塊的動(dòng)態(tài)裝卸(裁剪)。Linux內(nèi)核就是基于這個(gè)策略實(shí)現(xiàn)的。
哪些地方用到了內(nèi)核機(jī)制?
1.進(jìn)程(在cpu的虛擬內(nèi)存中分配地址空間,各個(gè)進(jìn)程的地址空間完全獨(dú)立;同時(shí)執(zhí)行的進(jìn)程數(shù)最多不超過(guò)cpu數(shù)目)之間進(jìn)行通 信,需要使用特定的內(nèi)核機(jī)制。
2.進(jìn)程間切換(同時(shí)執(zhí)行的進(jìn)程數(shù)最多不超過(guò)cpu數(shù)目),也需要用到內(nèi)核機(jī)制。
進(jìn)程切換也需要像FreeRTOS任務(wù)切換一樣保存狀態(tài),并將進(jìn)程置于閑置狀態(tài)/恢復(fù)狀態(tài)。
3.進(jìn)程的調(diào)度。確認(rèn)哪個(gè)進(jìn)程運(yùn)行多長(zhǎng)的時(shí)間。
Linux進(jìn)程
1.采用層次結(jié)構(gòu),每個(gè)進(jìn)程都依賴于一個(gè)父進(jìn)程。內(nèi)核啟動(dòng)init程序作為第一個(gè)進(jìn)程。該進(jìn)程負(fù)責(zé)進(jìn)一步的系統(tǒng)初始化操作。init進(jìn)程是進(jìn)程樹(shù)的根,所有的進(jìn)程都直接或者間接起源于該進(jìn)程。
2.通過(guò)pstree命令查詢。實(shí)際上得系統(tǒng)第一個(gè)進(jìn)程是systemd,而不是init(這也是疑問(wèn)點(diǎn))
3.系統(tǒng)中每一個(gè)進(jìn)程都有一個(gè)唯一標(biāo)識(shí)符(ID),用戶(或其他進(jìn)程)可以使用ID來(lái)訪問(wèn)進(jìn)程。
Linux內(nèi)核源代碼的目錄結(jié)構(gòu)Linux內(nèi)核源代碼包括三個(gè)主要部分:1. 內(nèi)核核心代碼,包括第3章所描述的各個(gè)子系統(tǒng)和子模塊,以及其它的支撐子系統(tǒng),例如電源管理、Linux初始化等2. 其它非核心代碼,例如庫(kù)文件(因?yàn)長(zhǎng)inux內(nèi)核是一個(gè)自包含的內(nèi)核,即內(nèi)核不依賴其它的任何軟件,自己就可以編譯通過(guò))、固件集合、KVM(虛擬機(jī)技術(shù))等3. 編譯腳本、配置文件、幫助文檔、版權(quán)說(shuō)明等輔助性文件使用ls命令看到的內(nèi)核源代碼的頂層目錄結(jié)構(gòu),具體描述如下。include/ ---- 內(nèi)核頭文件,需要提供給外部模塊(例如用戶空間代碼)使用。kernel/ ---- Linux內(nèi)核的核心代碼,包含了3.2小節(jié)所描述的進(jìn)程調(diào)度子系統(tǒng),以及和進(jìn)程調(diào)度相關(guān)的模塊。mm/ ---- 內(nèi)存管理子系統(tǒng)(3.3小節(jié))。fs/ ---- VFS子系統(tǒng)(3.4小節(jié))。net/ ---- 不包括網(wǎng)絡(luò)設(shè)備驅(qū)動(dòng)的網(wǎng)絡(luò)子系統(tǒng)(3.5小節(jié))。ipc/ ---- IPC(進(jìn)程間通信)子系統(tǒng)。arch// ---- 體系結(jié)構(gòu)相關(guān)的代碼,例如arm, x86等等。 arch//mach- ---- 具體的machine/board相關(guān)的代碼。 arch//include/asm ---- 體系結(jié)構(gòu)相關(guān)的頭文件。 arch//boot/dts ---- 設(shè)備樹(shù)(Device Tree)文件。init/ ---- Linux系統(tǒng)啟動(dòng)初始化相關(guān)的代碼。 block/ ---- 提供塊設(shè)備的層次。 sound/ ---- 音頻相關(guān)的驅(qū)動(dòng)及子系統(tǒng),可以看作“音頻子系統(tǒng)”。 drivers/ ---- 設(shè)備驅(qū)動(dòng)(在Linux kernel 3.10中,設(shè)備驅(qū)動(dòng)占了49.4的代碼量)。lib/ ---- 實(shí)現(xiàn)需要在內(nèi)核中使用的庫(kù)函數(shù),例如CRC、FIFO、list、MD5等。 crypto/ ----- 加密、解密相關(guān)的庫(kù)函數(shù)。 security/ ---- 提供安全特性(SELinux)。 virt/ ---- 提供虛擬機(jī)技術(shù)(KVM等)的支持。 usr/ ---- 用于生成initramfs的代碼。 firmware/ ---- 保存用于驅(qū)動(dòng)第三方設(shè)備的固件。samples/ ---- 一些示例代碼。 tools/ ---- 一些常用工具,如性能剖析、自測(cè)試等。Kconfig, Kbuild, Makefile, scripts/ ---- 用于內(nèi)核編譯的配置文件、腳本等。COPYING ---- 版權(quán)聲明。 MAINTAINERS ----維護(hù)者名單。 CREDITS ---- Linux主要的貢獻(xiàn)者名單。 REPORTING-BUGS ---- Bug上報(bào)的指南。Documentation, README ---- 幫助、說(shuō)明文檔。Linux內(nèi)核體系結(jié)構(gòu)簡(jiǎn)析簡(jiǎn)析
 圖1 Linux系統(tǒng)層次結(jié)構(gòu) 最上面是用戶(或應(yīng)用程序)空間。這是用戶應(yīng)用程序執(zhí)行的地方。用戶空間之下是內(nèi)核空間,Linux 內(nèi)核正是位于這里。GNU C Library (glibc)也在這里。它提供了連接內(nèi)核的系統(tǒng)調(diào)用接口,還提供了在用戶空間應(yīng)用程序和內(nèi)核之間進(jìn)行轉(zhuǎn)換的機(jī)制。這點(diǎn)非常重要,因?yàn)閮?nèi)核和用戶空間的應(yīng)用程序使用的是不同的保護(hù)地址空間。每個(gè)用戶空間的進(jìn)程都使用自己的虛擬地址空間,而內(nèi)核則占用單獨(dú)的地址空間。 Linux 內(nèi)核可以進(jìn)一步劃分成 3 層。最上面是系統(tǒng)調(diào)用接口,它實(shí)現(xiàn)了一些基本的功能,例如 read 和 write。系統(tǒng)調(diào)用接口之下是內(nèi)核代碼,可以更精確地定義為獨(dú)立于體系結(jié)構(gòu)的內(nèi)核代碼。這些代碼是 Linux 所支持的所有處理器體系結(jié)構(gòu)所通用的。在這些代碼之下是依賴于體系結(jié)構(gòu)的代碼,構(gòu)成了通常稱為 BSP(Board Support Package)的部分。這些代碼用作給定體系結(jié)構(gòu)的處理器和特定于平臺(tái)的代碼。 Linux 內(nèi)核實(shí)現(xiàn)了很多重要的體系結(jié)構(gòu)屬性。在或高或低的層次上,內(nèi)核被劃分為多個(gè)子系統(tǒng)。Linux 也可以看作是一個(gè)整體,因?yàn)樗鼤?huì)將所有這些基本服務(wù)都集成到內(nèi)核中。這與微內(nèi)核的體系結(jié)構(gòu)不同,后者會(huì)提供一些基本的服務(wù),例如通信、I/O、內(nèi)存和進(jìn)程管理,更具體的服務(wù)都是插入到微內(nèi)核層中的。每種內(nèi)核都有自己的優(yōu)點(diǎn),不過(guò)這里并不對(duì)此進(jìn)行討論。 隨著時(shí)間的流逝,Linux 內(nèi)核在內(nèi)存和 CPU 使用方面具有較高的效率,并且非常穩(wěn)定。但是對(duì)于 Linux 來(lái)說(shuō),最為有趣的是在這種大小和復(fù)雜性的前提下,依然具有良好的可移植性。Linux 編譯后可在大量處理器和具有不同體系結(jié)構(gòu)約束和需求的平臺(tái)上運(yùn)行。一個(gè)例子是 Linux 可以在一個(gè)具有內(nèi)存管理單元(MMU)的處理器上運(yùn)行,也可以在那些不提供 MMU 的處理器上運(yùn)行。Linux 內(nèi)核的 uClinux 移植提供了對(duì)非 MMU 的支持。 圖2是Linux內(nèi)核的體系結(jié)構(gòu)
 圖2 Linux內(nèi)核體系結(jié)構(gòu)Linux內(nèi)核的主要組件有:系統(tǒng)調(diào)用接口、進(jìn)程管理、內(nèi)存管理、虛擬文件系統(tǒng)、網(wǎng)絡(luò)堆棧、設(shè)備驅(qū)動(dòng)程序、硬件架構(gòu)的相關(guān)代碼。
SCI 層提供了某些機(jī)制執(zhí)行從用戶空間到內(nèi)核的函數(shù)調(diào)用。正如前面討論的一樣,這個(gè)接口依賴于體系結(jié)構(gòu),甚至在相同的處理器家族內(nèi)也是如此。SCI 實(shí)際上是一個(gè)非常有用的函數(shù)調(diào)用多路復(fù)用和多路分解服務(wù)。在 ./linux/kernel 中您可以找到 SCI 的實(shí)現(xiàn),并在 ./linux/arch 中找到依賴于體系結(jié)構(gòu)的部分。
進(jìn)程管理的重點(diǎn)是進(jìn)程的執(zhí)行。在內(nèi)核中,這些進(jìn)程稱為線程,代表了單獨(dú)的處理器虛擬化(線程代碼、數(shù)據(jù)、堆棧和 CPU 寄存器)。在用戶空間,通常使用進(jìn)程 這個(gè)術(shù)語(yǔ),不過(guò) Linux 實(shí)現(xiàn)并沒(méi)有區(qū)分這兩個(gè)概念(進(jìn)程和線程)。內(nèi)核通過(guò) SCI 提供了一個(gè)應(yīng)用程序編程接口(API)來(lái)創(chuàng)建一個(gè)新進(jìn)程(fork、exec 或 Portable Operating System Interface [POSIX] 函數(shù)),停止進(jìn)程(kill、exit),并在它們之間進(jìn)行通信和同步(signal 或者 POSIX 機(jī)制)。 進(jìn)程管理還包括處理活動(dòng)進(jìn)程之間共享 CPU 的需求。內(nèi)核實(shí)現(xiàn)了一種新型的調(diào)度算法,不管有多少個(gè)線程在競(jìng)爭(zhēng) CPU,這種算法都可以在固定時(shí)間內(nèi)進(jìn)行操作。這種算法就稱為 O(1) 調(diào)度程序,這個(gè)名字就表示它調(diào)度多個(gè)線程所使用的時(shí)間和調(diào)度一個(gè)線程所使用的時(shí)間是相同的。O(1) 調(diào)度程序也可以支持多處理器(稱為對(duì)稱多處理器或 SMP)。您可以在 ./linux/kernel 中找到進(jìn)程管理的源代碼,在 ./linux/arch 中可以找到依賴于體系結(jié)構(gòu)的源代碼。 內(nèi)核所管理的另外一個(gè)重要資源是內(nèi)存。為了提高效率,如果由硬件管理虛擬內(nèi)存,內(nèi)存是按照所謂的內(nèi)存頁(yè) 方式進(jìn)行管理的(對(duì)于大部分體系結(jié)構(gòu)來(lái)說(shuō)都是 4KB)。Linux 包括了管理可用內(nèi)存的方式,以及物理和虛擬映射所使用的硬件機(jī)制。不過(guò)內(nèi)存管理要管理的可不止 4KB 緩沖區(qū)。Linux 提供了對(duì) 4KB 緩沖區(qū)的抽象,例如 slab 分配器。這種內(nèi)存管理模式使用 4KB 緩沖區(qū)為基數(shù),然后從中分配結(jié)構(gòu),并跟蹤內(nèi)存頁(yè)使用情況,比如哪些內(nèi)存頁(yè)是滿的,哪些頁(yè)面沒(méi)有完全使用,哪些頁(yè)面為空。這樣就允許該模式根據(jù)系統(tǒng)需要來(lái)動(dòng)態(tài)調(diào)整內(nèi)存使用。為了支持多個(gè)用戶使用內(nèi)存,有時(shí)會(huì)出現(xiàn)可用內(nèi)存被消耗光的情況。由于這個(gè)原因,頁(yè)面可以移出內(nèi)存并放入磁盤中。這個(gè)過(guò)程稱為交換,因?yàn)轫?yè)面會(huì)被從內(nèi)存交換到硬盤上。內(nèi)存管理的源代碼可以在 ./linux/mm 中找到。
虛擬文件系統(tǒng)(VFS)是 Linux 內(nèi)核中非常有用的一個(gè)方面,因?yàn)樗鼮槲募到y(tǒng)提供了一個(gè)通用的接口抽象。VFS 在 SCI 和內(nèi)核所支持的文件系統(tǒng)之間提供了一個(gè)交換層(請(qǐng)參看圖4)。 圖3 Linux文件系統(tǒng)層次結(jié)構(gòu)在 VFS 上面,是對(duì)諸如 open、close、read 和 write 之類的函數(shù)的一個(gè)通用 API 抽象。在 VFS 下面是文件系統(tǒng)抽象,它定義了上層函數(shù)的實(shí)現(xiàn)方式。它們是給定文件系統(tǒng)(超過(guò) 50 個(gè))的插件。文件系統(tǒng)的源代碼可以在 ./linux/fs 中找到。文件系統(tǒng)層之下是緩沖區(qū)緩存,它為文件系統(tǒng)層提供了一個(gè)通用函數(shù)集(與具體文件系統(tǒng)無(wú)關(guān))。這個(gè)緩存層通過(guò)將數(shù)據(jù)保留一段時(shí)間(或者隨即預(yù)先讀取數(shù)據(jù)以便在需要是就可用)優(yōu)化了對(duì)物理設(shè)備的訪問(wèn)。緩沖區(qū)緩存之下是設(shè)備驅(qū)動(dòng)程序,它實(shí)現(xiàn)了特定物理設(shè)備的接口。
網(wǎng)絡(luò)堆棧在設(shè)計(jì)上遵循模擬協(xié)議本身的分層體系結(jié)構(gòu)。回想一下,Internet Protocol (IP) 是傳輸協(xié)議(通常稱為傳輸控制協(xié)議或 TCP)下面的核心網(wǎng)絡(luò)層協(xié)議。TCP 上面是 socket 層,它是通過(guò) SCI 進(jìn)行調(diào)用的。socket 層是網(wǎng)絡(luò)子系統(tǒng)的標(biāo)準(zhǔn) API,它為各種網(wǎng)絡(luò)協(xié)議提供了一個(gè)用戶接口。從原始幀訪問(wèn)到 IP 協(xié)議數(shù)據(jù)單元(PDU),再到 TCP 和 User Datagram Protocol (UDP),socket 層提供了一種標(biāo)準(zhǔn)化的方法來(lái)管理連接,并在各個(gè)終點(diǎn)之間移動(dòng)數(shù)據(jù)。內(nèi)核中網(wǎng)絡(luò)源代碼可以在 ./linux/net 中找到。
Linux 內(nèi)核中有大量代碼都在設(shè)備驅(qū)動(dòng)程序中,它們能夠運(yùn)轉(zhuǎn)特定的硬件設(shè)備。Linux 源碼樹(shù)提供了一個(gè)驅(qū)動(dòng)程序子目錄,這個(gè)目錄又進(jìn)一步劃分為各種支持設(shè)備,例如 Bluetooth、I2C、serial 等。設(shè)備驅(qū)動(dòng)程序的代碼可以在 ./linux/drivers 中找到。
盡管 Linux 很大程度上獨(dú)立于所運(yùn)行的體系結(jié)構(gòu),但是有些元素則必須考慮體系結(jié)構(gòu)才能正常操作并實(shí)現(xiàn)更高效率。./linux/arch 子目錄定義了內(nèi)核源代碼中依賴于體系結(jié)構(gòu)的部分,其中包含了各種特定于體系結(jié)構(gòu)的子目錄(共同組成了 BSP)。對(duì)于一個(gè)典型的桌面系統(tǒng)來(lái)說(shuō),使用的是 x86 目錄。每個(gè)體系結(jié)構(gòu)子目錄都包含了很多其他子目錄,每個(gè)子目錄都關(guān)注內(nèi)核中的一個(gè)特定方面,例如引導(dǎo)、內(nèi)核、內(nèi)存管理等。這些依賴體系結(jié)構(gòu)的代碼可以在 ./linux/arch 中找到。 如果 Linux 內(nèi)核的可移植性和效率還不夠好,Linux 還提供了其他一些特性,它們無(wú)法劃分到上面的分類中。作為一個(gè)生產(chǎn)操作系統(tǒng)和開(kāi)源軟件,Linux 是測(cè)試新協(xié)議及其增強(qiáng)的良好平臺(tái)。Linux 支持大量網(wǎng)絡(luò)協(xié)議,包括典型的 TCP/IP,以及高速網(wǎng)絡(luò)的擴(kuò)展(大于 1 Gigabit Ethernet [GbE] 和 10 GbE)。Linux 也可以支持諸如流控制傳輸協(xié)議(SCTP)之類的協(xié)議,它提供了很多比 TCP 更高級(jí)的特性(是傳輸層協(xié)議的接替者)。Linux 還是一個(gè)動(dòng)態(tài)內(nèi)核,支持動(dòng)態(tài)添加或刪除軟件組件。被稱為動(dòng)態(tài)可加載內(nèi)核模塊,它們可以在引導(dǎo)時(shí)根據(jù)需要(當(dāng)前特定設(shè)備需要這個(gè)模塊)或在任何時(shí)候由用戶插入。Linux 最新的一個(gè)增強(qiáng)是可以用作其他操作系統(tǒng)的操作系統(tǒng)(稱為系統(tǒng)管理程序)。最近,對(duì)內(nèi)核進(jìn)行了修改,稱為基于內(nèi)核的虛擬機(jī)(KVM)。這個(gè)修改為用戶空間啟用了一個(gè)新的接口,它可以允許其他操作系統(tǒng)在啟用了 KVM 的內(nèi)核之上運(yùn)行。除了運(yùn)行 Linux 的其他實(shí)例之外, Microsoft Windows也可以進(jìn)行虛擬化。惟一的限制是底層處理器必須支持新的虛擬化指令。Linux體系結(jié)構(gòu)和內(nèi)核結(jié)構(gòu)區(qū)別1.當(dāng)被問(wèn)到Linux體系結(jié)構(gòu)(就是Linux系統(tǒng)是怎么構(gòu)成的)時(shí),我們可以參照下圖這么回答:從大的方面講,Linux體系結(jié)構(gòu)可以分為兩塊:(1)用戶空間:用戶空間中又包含了,用戶的應(yīng)用程序,C庫(kù) (2)內(nèi)核空間:內(nèi)核空間包括,系統(tǒng)調(diào)用,內(nèi)核,以及與平臺(tái)架構(gòu)相關(guān)的代碼2.Linux體系結(jié)構(gòu)要分成用戶空間和內(nèi)核空間的原因: 1)現(xiàn)代CPU通常都實(shí)現(xiàn)了不同的工作模式, 以ARM為例:ARM實(shí)現(xiàn)了7種工作模式,不同模式下CPU可以執(zhí)行的指令或者訪問(wèn)的寄存器不同:
(6)數(shù)據(jù)訪問(wèn)終止 abt 以(2)X86為例:X86實(shí)現(xiàn)了4個(gè)不同級(jí)別的權(quán)限,Ring0—Ring3 ;Ring0下可以執(zhí)行特權(quán)指令,可以訪問(wèn)IO設(shè)備;Ring3則有很多的限制
2)所以,Linux從CPU的角度出發(fā),為了保護(hù)內(nèi)核的安全,把系統(tǒng)分成了2部分; 3.用戶空間和內(nèi)核空間是程序執(zhí)行的兩種不同狀態(tài),我們可以通過(guò)“系統(tǒng)調(diào)用”和“硬件中斷“來(lái)完成用戶空間到內(nèi)核空間的轉(zhuǎn)移4.Linux的內(nèi)核結(jié)構(gòu)(注意區(qū)分LInux體系結(jié)構(gòu)和Linux內(nèi)核結(jié)構(gòu))Linux驅(qū)動(dòng)的platform機(jī)制Linux的這種platform driver機(jī)制和傳統(tǒng)的device_driver機(jī)制相比,一個(gè)十分明顯的優(yōu)勢(shì)在于platform機(jī)制將本身的資源注冊(cè)進(jìn)內(nèi)核,由內(nèi)核統(tǒng)一管理,在驅(qū)動(dòng)程序中使用這些資源時(shí)通過(guò)platform_device提供的標(biāo)準(zhǔn)接口進(jìn)行申請(qǐng)并使用。這樣提高了驅(qū)動(dòng)和資源管理的獨(dú)立性,并且擁有較好的可移植性和安全性。下面是SPI驅(qū)動(dòng)層次示意圖,Linux中的SPI總線可理解為SPI控制器引出的總線: 和傳統(tǒng)的驅(qū)動(dòng)一樣,platform機(jī)制也分為三個(gè)步驟:
1、總線注冊(cè)階段:
內(nèi)核啟動(dòng)初始化時(shí)的main.c文件中的kernel_init()→do_basic_setup()→driver_init()→platform_bus_init()→bus_register(&platform_bus_type),注冊(cè)了一條platform總線(虛擬總線,platform_bus)。
2、添加設(shè)備階段:
設(shè)備注冊(cè)的時(shí)候Platform_device_register()→platform_device_add()→(pdev→dev.bus = &platform_bus_type)→device_add(),就這樣把設(shè)備給掛到虛擬的總線上。
3、驅(qū)動(dòng)注冊(cè)階段:
Platform_driver_register()→driver_register()→bus_add_driver()→driver_attach()→bus_for_each_dev(), 對(duì)在每個(gè)掛在虛擬的platform bus的設(shè)備作__driver_attach()→driver_probe_device(),判斷drv→bus→match()是否執(zhí)行成功,此時(shí)通過(guò)指針執(zhí)行platform_match→strncmp(pdev→name , drv→name , BUS_ID_SIZE),如果相符就調(diào)用really_probe(實(shí)際就是執(zhí)行相應(yīng)設(shè)備的platform_driver→probe(platform_device)。)開(kāi)始真正的探測(cè),如果probe成功,則綁定設(shè)備到該驅(qū)動(dòng)。
從上面可以看出,platform機(jī)制最后還是調(diào)用了bus_register() , device_add() , driver_register()這三個(gè)關(guān)鍵的函數(shù)。
下面看幾個(gè)結(jié)構(gòu)體:
struct platform_device (/include/linux/Platform_device.h) { const char * name; int id; struct device dev; u32 num_resources; struct resource * resource; };
Platform_device結(jié)構(gòu)體描述了一個(gè)platform結(jié)構(gòu)的設(shè)備,在其中包含了一般設(shè)備的結(jié)構(gòu)體struct device dev;設(shè)備的資源結(jié)構(gòu)體struct resource * resource;還有設(shè)備的名字const char * name。(注意,這個(gè)名字一定要和后面platform_driver.driver àname相同,原因會(huì)在后面說(shuō)明。)
該結(jié)構(gòu)體中最重要的就是resource結(jié)構(gòu),這也是之所以引入platform機(jī)制的原因。
struct resource ( /include/linux/ioport.h) { resource_size_t start; resource_size_t end; const char *name; unsigned long flags; struct resource *parent, *sibling, *child; };
其中 flags位表示該資源的類型,start和end分別表示該資源的起始地址和結(jié)束地址(/include/linux/Platform_device.h):
struct platform_driver { int (*probe)(struct platform_device *); int (*remove)(struct platform_device *); void (*shutdown)(struct platform_device *); int (*suspend)(struct platform_device *, pm_message_t state); int (*suspend_late)(struct platform_device *, pm_message_t state); int (*resume_early)(struct platform_device *); int (*resume)(struct platform_device *); struct device_driver driver; };
Platform_driver結(jié)構(gòu)體描述了一個(gè)platform結(jié)構(gòu)的驅(qū)動(dòng)。其中除了一些函數(shù)指針外,還有一個(gè)一般驅(qū)動(dòng)的device_driver結(jié)構(gòu)。
名字要一致的原因:
上面說(shuō)的驅(qū)動(dòng)在注冊(cè)的時(shí)候會(huì)調(diào)用函數(shù)bus_for_each_dev(), 對(duì)在每個(gè)掛在虛擬的platform bus的設(shè)備作__driver_attach()→driver_probe_device(),在此函數(shù)中會(huì)對(duì)dev和drv做初步的匹配,調(diào)用的是drv->bus->match所指向的函數(shù)。platform_driver_register函數(shù)中drv->driver.bus = &platform_bus_type,所以drv->bus->match就為platform_bus_type→match,為platform_match函數(shù),該函數(shù)如下:
static int platform_match(struct device * dev, struct device_driver * drv) { struct platform_device *pdev = container_of(dev, struct platform_device, dev);
return (strncmp(pdev->name, drv->name, BUS_ID_SIZE) == 0); }
是比較dev和drv的name,相同則會(huì)進(jìn)入really_probe()函數(shù),從而進(jìn)入自己寫的probe函數(shù)做進(jìn)一步的匹配。所以dev→name和driver→drv→name在初始化時(shí)一定要填一樣的。
不同類型的驅(qū)動(dòng),其match函數(shù)是不一樣的,這個(gè)platform的驅(qū)動(dòng),比較的是dev和drv的名字,還記得usb類驅(qū)動(dòng)里的match嗎?它比較的是Product ID和Vendor ID。
個(gè)人總結(jié)Platform機(jī)制的好處:
1、提供platform_bus_type類型的總線,把那些不是總線型的soc設(shè)備都添加到這條虛擬總線上。使得,總線——設(shè)備——驅(qū)動(dòng)的模式可以得到普及。
2、提供platform_device和platform_driver類型的數(shù)據(jù)結(jié)構(gòu),將傳統(tǒng)的device和driver數(shù)據(jù)結(jié)構(gòu)嵌入其中,并且加入resource成員,以便于和Open Firmware這種動(dòng)態(tài)傳遞設(shè)備資源的新型bootloader和kernel 接軌。
Linux內(nèi)核體系結(jié)構(gòu)因?yàn)長(zhǎng)inux內(nèi)核是單片的,所以它比其他類型的內(nèi)核占用空間最大,復(fù)雜度也最高。這是一個(gè)設(shè)計(jì)特性,在Linux早期引起了相當(dāng)多的爭(zhēng)論,并且仍然帶有一些與單內(nèi)核固有的相同的設(shè)計(jì)缺陷。為了解決這些缺陷,Linux內(nèi)核開(kāi)發(fā)人員所做的一件事就是使內(nèi)核模塊可以在運(yùn)行時(shí)加載和卸載,這意味著您可以動(dòng)態(tài)地添加或刪除內(nèi)核的特性。這不僅可以向內(nèi)核添加硬件功能,還可以包括運(yùn)行服務(wù)器進(jìn)程的模塊,比如低級(jí)別虛擬化,但也可以替換整個(gè)內(nèi)核,而不需要在某些情況下重啟計(jì)算機(jī)。
想象一下,如果您可以升級(jí)到Windows服務(wù)包,而不需要重新啟動(dòng)……
內(nèi)核模塊如果Windows已經(jīng)安裝了所有可用的驅(qū)動(dòng)程序,而您只需要打開(kāi)所需的驅(qū)動(dòng)程序怎么辦?這本質(zhì)上就是內(nèi)核模塊為L(zhǎng)inux所做的。內(nèi)核模塊,也稱為可加載內(nèi)核模塊(LKM),對(duì)于保持內(nèi)核在不消耗所有可用內(nèi)存的情況下與所有硬件一起工作是必不可少的。模塊通常向基本內(nèi)核添加設(shè)備、文件系統(tǒng)和系統(tǒng)調(diào)用等功能。lkm的文件擴(kuò)展名是.ko,通常存儲(chǔ)在/lib/modules目錄中。由于模塊的特性,您可以通過(guò)在啟動(dòng)時(shí)使用menuconfig命令將模塊設(shè)置為load或not load,或者通過(guò)編輯/boot/config文件,或者使用modprobe命令動(dòng)態(tài)地加載和卸載模塊,輕松定制內(nèi)核。第三方和封閉源碼模塊在一些發(fā)行版中是可用的,比如Ubuntu,默認(rèn)情況下可能無(wú)法安裝,因?yàn)檫@些模塊的源代碼是不可用的。該軟件的開(kāi)發(fā)人員(即nVidia、ATI等)不提供源代碼,而是構(gòu)建自己的模塊并編譯所需的.ko文件以便分發(fā)。雖然這些模塊像beer一樣是免費(fèi)的,但它們不像speech那樣是免費(fèi)的,因此不包括在一些發(fā)行版中,因?yàn)榫S護(hù)人員認(rèn)為它通過(guò)提供非免費(fèi)軟件“污染”了內(nèi)核。內(nèi)核并不神奇,但對(duì)于任何正常運(yùn)行的計(jì)算機(jī)來(lái)說(shuō),它都是必不可少的。Linux內(nèi)核不同于OS X和Windows,因?yàn)樗瑑?nèi)核級(jí)別的驅(qū)動(dòng)程序,并使許多東西“開(kāi)箱即用”。希望您能對(duì)軟件和硬件如何協(xié)同工作以及啟動(dòng)計(jì)算機(jī)所需的文件有更多的了解。
Linux 內(nèi)核學(xué)習(xí)經(jīng)驗(yàn)總結(jié)學(xué)習(xí)內(nèi)核,每個(gè)人都有自己的學(xué)習(xí)方法,仁者見(jiàn)仁智者見(jiàn)智。以下是我在學(xué)習(xí)過(guò)程中總結(jié)出來(lái)的東西,對(duì)自身來(lái)說(shuō),我認(rèn)為比較有效率,拿出來(lái)跟大家交流一下。內(nèi)核學(xué)習(xí),一偏之見(jiàn);疏漏難免,懇請(qǐng)指正。剛開(kāi)始學(xué)內(nèi)核的時(shí)候,不要執(zhí)著于一個(gè)方面,不要專注于一個(gè)子系統(tǒng)就一頭扎到實(shí)際的代碼行中去,因?yàn)檫@樣的話,牽涉的面會(huì)很廣,會(huì)碰到很多困難,容易產(chǎn)生挫敗感,一個(gè)函數(shù)體中(假設(shè)剛開(kāi)始的時(shí)候正在學(xué)習(xí)某個(gè)方面的某個(gè)具體的功能函數(shù))很可能摻雜著其他各個(gè)子系統(tǒng)方面設(shè)計(jì)理念(多是大量相關(guān)的數(shù)據(jù)結(jié)構(gòu)或者全局變量,用于支撐該子系統(tǒng)的管理工作)下相應(yīng)的代碼實(shí)現(xiàn),這個(gè)時(shí)候看到這些東西,紛繁蕪雜,是沒(méi)有頭緒而且很不理解的,會(huì)產(chǎn)生很多很多的疑問(wèn),(這個(gè)時(shí)候如果對(duì)這些疑問(wèn)糾纏不清,刨根問(wèn)底,那么事實(shí)上就是在學(xué)習(xí)當(dāng)前子系統(tǒng)的過(guò)程中頻繁的去涉足其他子系統(tǒng),這時(shí)候注意力就分散了),而事實(shí)上等了解了各個(gè)子系統(tǒng)后再回頭看這些東西的話,就簡(jiǎn)單多了,而且思路也會(huì)比較清晰。所以,要避免 “只見(jiàn)樹(shù)木,不見(jiàn)森林”,不要急于深入到底層代碼中去,不要過(guò)早研究底層代碼。我在大二的時(shí)候剛開(kāi)始接觸內(nèi)核,就犯了這個(gè)錯(cuò)誤,一頭扎到內(nèi)存管理里頭,去看非常底層的實(shí)現(xiàn)代碼,雖然也是建立在內(nèi)存管理的設(shè)計(jì)思想的基礎(chǔ)上,但是相對(duì)來(lái)說(shuō),比較孤立,因?yàn)榇藭r(shí)并沒(méi)有學(xué)習(xí)其它子系統(tǒng),應(yīng)該說(shuō)無(wú)論是視野還是思想,都比較狹隘,所以代碼中牽涉到的其它子系統(tǒng)的實(shí)現(xiàn)我都直接跳過(guò)了,這一點(diǎn)還算聰明,當(dāng)然也是迫不得已的。剛開(kāi)始,我認(rèn)為主要的問(wèn)題在于你知道不知道,而不是理解不理解,某個(gè)子系統(tǒng)的實(shí)現(xiàn)采用了某種策略、方法,而你在學(xué)習(xí)中需要做的就是知道有這么一回事兒,然后才是理解所描述的策略或者方法。根據(jù)自己的學(xué)習(xí)經(jīng)驗(yàn),剛開(kāi)始學(xué)習(xí)內(nèi)核的時(shí)候,我認(rèn)為要做的是在自己的腦海中建立起內(nèi)核的大體框架,理解各個(gè)子系統(tǒng)的設(shè)計(jì)理念和構(gòu)建思想,這些理念和思想會(huì)從宏觀上呈獻(xiàn)給你清晰的脈絡(luò),就像一個(gè)去除了枝枝葉葉的大樹(shù)的主干,一目了然;當(dāng)然,肯定還會(huì)涉及到具體的實(shí)現(xiàn)方法、函數(shù),但是此時(shí)接觸到的函數(shù)或者方法位于內(nèi)核實(shí)現(xiàn)的較高的層次,是主(要)函數(shù),已經(jīng)了解到這些函數(shù),針對(duì)的是哪些設(shè)計(jì)思想,實(shí)現(xiàn)了什么樣的功能,達(dá)成了什么樣的目的,混個(gè)臉熟的說(shuō)法在這兒也是成立的。至于該主函數(shù)所調(diào)用的其它的輔助性函數(shù)就等同于枝枝葉葉了,不必太早就去深究。此時(shí),也就初步建立起了內(nèi)核子系統(tǒng)框架和代碼實(shí)現(xiàn)之間的關(guān)聯(lián),關(guān)聯(lián)其實(shí)很簡(jiǎn)單,比如一看到某個(gè)函數(shù)名字,就想起這個(gè)函數(shù)是針對(duì)哪個(gè)子系統(tǒng)的,實(shí)現(xiàn)了什么功能。我認(rèn)為此時(shí)要看的就是LKD3,這本書算是泛泛而談,主要就是從概念,設(shè)計(jì),大的實(shí)現(xiàn)方法上描述各個(gè)子系統(tǒng),而對(duì)于具體的相關(guān)的函數(shù)實(shí)現(xiàn)的代碼講解很少涉及(對(duì)比于ULK3,此書主要就是關(guān)于具體函數(shù)代碼的具體實(shí)現(xiàn)的深入分析,當(dāng)然,你也可以看,但是過(guò)早看這本書,會(huì)感覺(jué)很痛苦,很枯燥無(wú)味,基本上都是函數(shù)的實(shí)現(xiàn)),很少,但不是沒(méi)有,這就很好,滿足我們當(dāng)前的需求,還避免我們過(guò)早深入到實(shí)際的代碼中去。而且本書在一些重要的點(diǎn)上還給出了寫程序時(shí)的注意事項(xiàng),算是指導(dǎo)性建議。主要的子系統(tǒng)包括:內(nèi)存管理,進(jìn)程管理和調(diào)度,系統(tǒng)調(diào)用,中斷和異常,內(nèi)核同步,時(shí)間和定時(shí)器管理,虛擬文件系統(tǒng),塊I/O層,設(shè)備和模塊。(這里的先后順序其實(shí)就是LKD3的目錄的順序)。我學(xué)習(xí)的時(shí)候是三本書交叉著看的,先看LKD3,專于一個(gè)子系統(tǒng),主要就是了解設(shè)計(jì)的原理和思想,當(dāng)然也會(huì)碰到對(duì)一些主要函數(shù)的介紹,但大多就是該函數(shù)基于前面介紹的思想和原理完成了什么樣的功能,該書并沒(méi)有就函數(shù)本身的實(shí)現(xiàn)進(jìn)行深入剖析。然后再看ULK3和PLKA上看同樣的子系統(tǒng),但是并不仔細(xì)分析底層具體函數(shù)的代碼,只是粗略地、不求甚解地看,甚至不看。因?yàn)椋行r(shí)候,在其中一本書的某個(gè)點(diǎn)上,卡殼了,不是很理解了,在另外的書上你可能就碰到對(duì)同一個(gè)問(wèn)題的不同角度的描述,說(shuō)不準(zhǔn)哪句話就能讓你豁然開(kāi)朗,如醍醐灌頂。我經(jīng)常碰到這種情況。并不是說(shuō)學(xué)習(xí)過(guò)程中對(duì)一些函數(shù)體的實(shí)現(xiàn)完全就忽略掉,只要自己想徹底了解其代碼實(shí)現(xiàn),沒(méi)有誰(shuí)會(huì)阻止你。我是在反復(fù)閱讀過(guò)程中慢慢深入的。比如VFS中文件打開(kāi)需要對(duì)路徑進(jìn)行分析,需要考慮的細(xì)節(jié)不少(.././之類的),但是其代碼實(shí)現(xiàn)是很好理解的。再比如,CFS調(diào)度中根據(jù)shedule latency、隊(duì)列中進(jìn)程個(gè)數(shù)及其nice值(使用的是動(dòng)態(tài)優(yōu)先級(jí))計(jì)算出分配給進(jìn)程的時(shí)間片,沒(méi)理由不看的,這個(gè)太重要了,而且也很有意思。ULK3也會(huì)有設(shè)計(jì)原理與思想之類的概括性介紹,基本上都位于某個(gè)主題的開(kāi)篇段落。但是更多的是對(duì)支持該原理和思想的主要函數(shù)實(shí)現(xiàn)的具體分析,同樣在首段,一句話綜述函數(shù)的功能,然后對(duì)函數(shù)的實(shí)現(xiàn)以1、2、3,或者a、b、c步驟的形式進(jìn)行講解。我只是有選擇性的看,有時(shí)候?qū)φ罩胹ource insight打開(kāi)的源碼,確認(rèn)一下代碼大體上確實(shí)是按書中所描述的步驟實(shí)現(xiàn)的,就當(dāng)是增加感性認(rèn)識(shí)。由于步驟中摻雜著各種針對(duì)不同實(shí)現(xiàn)目的安全性、有效性檢查,如果不理解就先跳過(guò)。這并不妨礙你對(duì)函數(shù)體功能實(shí)現(xiàn)的整體把握。PLKA介于LKD3和ULK3之間。我覺(jué)得PLKA的作者(看照片,真一德國(guó)帥小伙,技術(shù)如此了得)肯定看過(guò)ULK,無(wú)論他的本意還是有意,總之PLKA還是跟ULK有所不同,對(duì)函數(shù)的仔細(xì)講解都做補(bǔ)充說(shuō)明,去掉函數(shù)體中邊邊角角的情況,比如一些特殊情況的處理,有效性檢查等,而不妨礙對(duì)整個(gè)函數(shù)體功能的理解,這些他都有所交代,做了聲明;而且,就像LKD3一樣,在某些點(diǎn)上也給出了指導(dǎo)性編程建議。作者們甚至對(duì)同一個(gè)主要函數(shù)的講解的著重點(diǎn)都不一樣。這樣的話,對(duì)我們學(xué)習(xí)的人而言,有助于加深理解。另外,我認(rèn)為很重要的一點(diǎn)就是PLKA針對(duì)的2.6.24的內(nèi)核版本,而ULK是2.6.11,LKD3是2.6.34。在某些方面PLKA比較接近現(xiàn)代的實(shí)現(xiàn)。其實(shí)作者們之所以分別選擇11或者24,都是因?yàn)樵诎姹景l(fā)行樹(shù)中,這兩個(gè)版本在某些方面都做了不小的變動(dòng),或者說(shuō)是具有標(biāo)志性的轉(zhuǎn)折點(diǎn)(這些信息大多是在書中的引言部分介紹的,具體的細(xì)節(jié)我想不起來(lái)了)。Intel V3,針對(duì)X86的CPU,本書自然是系統(tǒng)編程的權(quán)威。內(nèi)核部分實(shí)現(xiàn)都可以在本書找到其根源。所以,在讀以上三本書某個(gè)子系統(tǒng)的時(shí)候,不要忘記可以在V3中相應(yīng)章節(jié)找到一些基礎(chǔ)性支撐信息。在讀書過(guò)程中,會(huì)產(chǎn)生相當(dāng)多的疑問(wèn),這一點(diǎn)是確信無(wú)疑的。大到搞不明白一個(gè)設(shè)計(jì)思想,小到不理解某行代碼的用途。各個(gè)方面,各種疑問(wèn),你完全可以把不理解的地方都記錄下來(lái)(不過(guò),我并沒(méi)有這么做,沒(méi)有把疑問(wèn)全部記下來(lái),只標(biāo)記了很少一部分我認(rèn)為很關(guān)鍵的幾個(gè)問(wèn)題),專門寫到一張紙上,不對(duì),一個(gè)本上,我確信會(huì)產(chǎn)生這么多的疑問(wèn),不然內(nèi)核相關(guān)的論壇早就可以關(guān)閉了。其實(shí),大部分的問(wèn)題(其中很多問(wèn)題都是你知道不知道有這么一回事的問(wèn)題)都可以迎刃而解,只要你肯回頭再看,書讀百遍,其義自現(xiàn)。多看幾遍,前前后后的聯(lián)系明白個(gè)七七八八是沒(méi)有問(wèn)題的。我也這么做了,針對(duì)某些子系統(tǒng)也看了好幾遍,切身體會(huì)。當(dāng)你按順序?qū)W習(xí)這些子系統(tǒng)的時(shí)候,前面的章節(jié)很可能會(huì)引用后面的章節(jié),就像PLKA的作者說(shuō)的那樣,完全沒(méi)有向后引用是不可能的,他能做的只是盡量減少這種引用而又不損害你對(duì)當(dāng)前問(wèn)題的理解。不理解,沒(méi)關(guān)系,跳過(guò)就行了。后面的章節(jié)同樣會(huì)有向前章節(jié)的引用,不過(guò)這個(gè)問(wèn)題就簡(jiǎn)單一些了 ,你可以再回頭去看相應(yīng)的介紹,當(dāng)時(shí)你不太理解的東西,很可能這個(gè)時(shí)候就知道了它的設(shè)計(jì)的目的以及具體的應(yīng)用。不求甚解只是暫時(shí)的。比如說(shuō),內(nèi)核各個(gè)子系統(tǒng)之間的交互和引用在代碼中的體現(xiàn)就是實(shí)現(xiàn)函數(shù)穿插調(diào)用,比如你在內(nèi)存管理章節(jié)學(xué)習(xí)了的內(nèi)存分配和釋放的函數(shù),而你是了解內(nèi)存在先的,在學(xué)習(xí)驅(qū)動(dòng)或者模塊的時(shí)候就會(huì)碰到這些函數(shù)的調(diào)用,這樣也就比較容易接受,不至于太過(guò)茫然;再比如,你了解了系統(tǒng)時(shí)間和定時(shí)器的管理,再回頭看中斷和異常中bottom half的調(diào)度實(shí)現(xiàn),你對(duì)它的理解就會(huì)加深一層。子系統(tǒng)進(jìn)行管理工作需要大量的數(shù)據(jù)結(jié)構(gòu)。子系統(tǒng)之間交互的一種方式就是各個(gè)子系統(tǒng)各自的主要數(shù)據(jù)結(jié)構(gòu)通過(guò)指針成員相互引用。學(xué)習(xí)過(guò)程中,參考書上在講解某個(gè)子系統(tǒng)的時(shí)候會(huì)對(duì)數(shù)據(jù)結(jié)構(gòu)中主要成員的用途解釋一下,但肯定不會(huì)覆蓋全部(成員比較多的情況,例如task_struct),對(duì)其它子系統(tǒng)基于某個(gè)功能實(shí)現(xiàn)的引用可能解釋了,也可能沒(méi)做解釋,還可能說(shuō)這個(gè)變量在何處會(huì)做進(jìn)一步說(shuō)明。所以,不要糾結(jié)于一個(gè)不理解的點(diǎn)上,暫且放過(guò),回頭還可以看的。之間的聯(lián)系可以在對(duì)各個(gè)子系統(tǒng)都有所了解之后再建立起來(lái)。其實(shí),我仍然在強(qiáng)調(diào)先理解概念和框架的重要性。等我們完成了建立框架這一步,就可以選擇一個(gè)比較感興趣的子系統(tǒng),比如驅(qū)動(dòng)、網(wǎng)絡(luò),或者文件系統(tǒng)之類的。這個(gè)時(shí)候你再去深入了解底層代碼實(shí)現(xiàn),相較于一開(kāi)始就鉆研代碼,更容易一些,而且碰到了不解之處,或者忘記了某個(gè)方面的實(shí)現(xiàn),此時(shí)你完全可以找到相應(yīng)的子系統(tǒng),因?yàn)槟阒涝谀娜フ遥槁┭a(bǔ)缺,不僅完成了對(duì)當(dāng)前函數(shù)的鉆研,而且可以回顧、溫習(xí)以前的內(nèi)容,融會(huì)貫通的時(shí)機(jī)就在這里了。《深入理解linux虛擬內(nèi)存》(2.4內(nèi)核版本),LDD3,《深入理解linux網(wǎng)絡(luò)技術(shù)內(nèi)幕》,幾乎每一個(gè)子系統(tǒng)都需要一本書的容量去講解,所以說(shuō),剛開(kāi)始學(xué)習(xí)不宜對(duì)某個(gè)模塊太過(guò)深入,等對(duì)各個(gè)子系統(tǒng)都有所了解了,再有針對(duì)性的去學(xué)習(xí)一個(gè)特定的子系統(tǒng)。這時(shí)候?qū)ζ渌到y(tǒng)的援引都可以讓我們不再感到茫然、復(fù)雜,不知所云。比如,LDD3中的以下所列章節(jié):構(gòu)造和運(yùn)行模塊,并發(fā)和競(jìng)態(tài),時(shí)間、延遲及延緩操作,分配內(nèi)存,中斷處理等,都屬于驅(qū)動(dòng)開(kāi)發(fā)的支撐性子系統(tǒng),雖說(shuō)本書對(duì)這些子系統(tǒng)都專門開(kāi)辟一個(gè)章節(jié)進(jìn)行講解,但是詳細(xì)程度怎么能比得上PLKA,ULK3,LKD3這三本書,看完這三本書,你會(huì)發(fā)現(xiàn)讀LDD3這些章節(jié)的時(shí)候簡(jiǎn)直跟喝白開(kāi)水一樣,太隨意了,因?yàn)長(zhǎng)DD3的講解比之LKD3更粗略。打好了基礎(chǔ),PCI、USB、TTY驅(qū)動(dòng),塊設(shè)備驅(qū)動(dòng),網(wǎng)卡驅(qū)動(dòng),需要了解和學(xué)習(xí)的東西就比較有針對(duì)性了。這些子系統(tǒng)就屬于通用子系統(tǒng),了解之后,基于這些子系統(tǒng)的子系統(tǒng)的開(kāi)發(fā)—驅(qū)動(dòng)(需進(jìn)一步針對(duì)硬件特性)和網(wǎng)絡(luò)(需進(jìn)一步理解各種協(xié)議)—相對(duì)而言,其學(xué)習(xí)難度大大降低,學(xué)習(xí)進(jìn)度大大加快,學(xué)習(xí)效率大大提升。說(shuō)著容易做來(lái)難。達(dá)到這樣一種效果的前提就是:必須得靜下心來(lái),認(rèn)真讀書,要看得進(jìn)去,PLKA,ULK3厚得都跟磚頭塊兒一樣,令人望之生畏,如果沒(méi)有興趣,沒(méi)有熱情,沒(méi)有毅力,無(wú)論如何都是不行,因?yàn)樾枰獣r(shí)間,需要很長(zhǎng)時(shí)間。我并不是說(shuō)必須打好了基礎(chǔ)才可以進(jìn)行驅(qū)動(dòng)開(kāi)發(fā),只是說(shuō)打好了基礎(chǔ)的情況下進(jìn)行開(kāi)發(fā)會(huì)更輕松,更有效率,而且自己對(duì)內(nèi)核代碼的駕馭能力會(huì)更強(qiáng)大。這只是我個(gè)人見(jiàn)解,我自己的學(xué)習(xí)方式,僅供參考。PLKA是個(gè)德國(guó)人用德語(yǔ)寫的,后來(lái)翻譯成英文,又從英文翻譯成中文,我在網(wǎng)上書店里沒(méi)有找到它的紙質(zhì)英文版,所以就買了中文版的。ULK3和LKD3都是英文版的。大牛們寫的書,遣詞造句真的是簡(jiǎn)潔,易懂,看原版對(duì)我們學(xué)習(xí)計(jì)算機(jī)編程的程序員來(lái)說(shuō)完全不成問(wèn)題,最好原汁原味。如果一本書確實(shí)翻譯地很好,我們當(dāng)然可以看中文版的,用母語(yǔ)進(jìn)行學(xué)習(xí),理解速度和學(xué)習(xí)進(jìn)度當(dāng)然是很快的,不作他想??从⑽牡臅r(shí)候不要腦子里想著把他翻譯成中文,沒(méi)必要。“比起知道你所用技術(shù)的重要性,成為某一個(gè)特別領(lǐng)域的專家是不重要的。知道某一個(gè)具體API調(diào)用一點(diǎn)好處都沒(méi)有,當(dāng)你需要他的時(shí)候只要查詢下就好了?!边@句話源于我看到的一篇翻譯過(guò)來(lái)的博客。我想強(qiáng)調(diào)的就是,這句話針應(yīng)用型編程再合適不過(guò),但是內(nèi)核API就不完全如此。內(nèi)核相當(dāng)復(fù)雜,學(xué)習(xí)起來(lái)很不容易,但是當(dāng)你學(xué)習(xí)到一定程度,你會(huì)發(fā)現(xiàn),如果自己打算寫內(nèi)核代碼,到最后要關(guān)注的仍然是API接口,只不過(guò)這些API絕大部分是跨平臺(tái)的,滿足可移植性。內(nèi)核黑客基本上已經(jīng)標(biāo)準(zhǔn)化、文檔化了這些接口,你所要做的只是調(diào)用而已。當(dāng)然,在使用的時(shí)候,最好對(duì)可移植性這一話題在內(nèi)核中的編碼約定爛熟于心,這樣才會(huì)寫出可移植性的代碼。就像應(yīng)用程序一樣,可以使用開(kāi)發(fā)商提供的動(dòng)態(tài)庫(kù)API,或者使用開(kāi)源API。同樣是調(diào)用API,不同點(diǎn)在于使用內(nèi)核API要比使用應(yīng)用API了解的東西要多出許多。當(dāng)你了解了操作系統(tǒng)的實(shí)現(xiàn)—這些實(shí)現(xiàn)可都是對(duì)應(yīng)用程序的基礎(chǔ)性支撐啊—你再去寫應(yīng)用程序的時(shí)候,應(yīng)用程序中用到的多線程,定時(shí)器,同步鎖機(jī)制等等等等,使用共享庫(kù)API的時(shí)候,聯(lián)系到操作系統(tǒng),從而把對(duì)該API的文檔描述同自己所了解到的這些方面在內(nèi)核中的相應(yīng)支撐性實(shí)現(xiàn)結(jié)合起來(lái)進(jìn)行考慮,這會(huì)指導(dǎo)你選擇使用哪一個(gè)API接口,選出效率最高的實(shí)現(xiàn)方式。對(duì)系統(tǒng)編程頗有了解的話,對(duì)應(yīng)用編程不無(wú)益處,甚至可以說(shuō)是大有好處。設(shè)計(jì)實(shí)現(xiàn)的本質(zhì),知道還是理解操作系統(tǒng)是介于底層硬件和應(yīng)用軟件之間的接口,其各個(gè)子系統(tǒng)的實(shí)現(xiàn)很大程度上依賴于硬件特性。書上介紹這些子系統(tǒng)的設(shè)計(jì)和實(shí)現(xiàn)的時(shí)候,我們讀過(guò)了,也就知道了,如果再深入考慮一下,為什么整體架構(gòu)要按照這種方式組織,為什么局部函數(shù)要遵循這樣的步驟處理,知其然,知其所以然,如果你知道了某個(gè)功能的實(shí)現(xiàn)是因?yàn)樾酒褪沁@么設(shè)計(jì)的,CPU就是這么做的,那么你的疑問(wèn)也就基本上到此為止了。再深究,就是芯片架構(gòu)方面的設(shè)計(jì)與實(shí)現(xiàn),對(duì)于程序員來(lái)講,無(wú)論是系統(tǒng)還是應(yīng)用程序員,足跡探究到這里,已經(jīng)解決了很多疑問(wèn),因?yàn)槲覀兊墓ぷ餍再|(zhì)偏軟,而這些東西實(shí)在是夠硬。比如,ULK3中講解的中斷和異常的實(shí)現(xiàn),究其根源,那是因?yàn)镮ntel x86系列就是這么設(shè)計(jì)的,去看看Intel V3手冊(cè)中相應(yīng)章節(jié)介紹,都可以為ULK3中描述的代碼實(shí)現(xiàn)方式找到注解。還有時(shí)間和定時(shí)器管理,同樣可以在Intel V3 對(duì)APIC的介紹中獲取足夠的信息,操作系統(tǒng)就是依據(jù)這些硬件特性來(lái)實(shí)現(xiàn)軟件方法定義的。又是那句話,不是理解不理解的問(wèn)題,而是知道不知道的問(wèn)題。有時(shí)候,知道了,就理解了。在整個(gè)學(xué)習(xí)過(guò)程中,知道,理解,知道,理解,知道……,交叉反復(fù)。為什么開(kāi)始和結(jié)尾都是知道,而理解只是中間步驟呢?世界上萬(wàn)事萬(wàn)物自有其規(guī)律,人類只是發(fā)現(xiàn)而已,實(shí)踐是第一位的,實(shí)踐就是知道的過(guò)程,實(shí)踐產(chǎn)生經(jīng)驗(yàn),經(jīng)驗(yàn)的總結(jié)就是理論,理論源于實(shí)踐,理論才需要理解。我們學(xué)習(xí)內(nèi)核,深入研究,搞來(lái)搞去,又回到了芯片上,芯片是物質(zhì)的,芯片的功用基于自然界中物質(zhì)本有的物理和電子特性。追本溯源,此之謂也。紙上得來(lái)終覺(jué)淺,絕知此事要躬行。只看書是絕對(duì)不行的,一定要結(jié)合課本給出的編程建議自己敲代碼。剛開(kāi)始就以模塊形式測(cè)試好了,或者自己編譯一個(gè)開(kāi)發(fā)版本的內(nèi)核。一臺(tái)機(jī)器的話,使用UML方式調(diào)試,內(nèi)核控制路走到哪一步,單步調(diào)試看看程序執(zhí)行過(guò)程,比書上的講解更直觀明了。一定要?jiǎng)邮謱?shí)際操作。LDD3 Linux Device Driver 3rdLKD3 Linux Kernel Development 3rdULK3 Understanding the Linux Kernel 3rdPLKA Professional Linux Kernel ArchitectureIntel V3 Intel? 64 and IA-32 Architectures Software Developer’s Manual Volume 3 (3A, 3B & 3C): System Programming Guide作者在寫書的時(shí)候,都是以自己的理解組織內(nèi)容,從自己的觀點(diǎn)看待一個(gè)主題,關(guān)注點(diǎn)跟作者自身有很大的關(guān)系。出書的時(shí)間有先后,后來(lái)人針對(duì)同一個(gè)主題想要出書而又不落入窠臼,最好有自己的切入方式,從自己的角度講解相關(guān)問(wèn)題,這才值得出這本書,千篇一律是個(gè)掉價(jià)的行為,書就不值錢了。http:///Articles/419855/ 此處是一篇關(guān)于LKD3的書評(píng),指出了其中的錯(cuò)誤,當(dāng)你讀完的時(shí)候,不妨去找找,看一下自己在其中所描述的地方有什么特別的印象。http:///Articles/161190/此處是一篇對(duì)ULK3的介紹,我認(rèn)為其中很關(guān)鍵的幾句話就可以給本書定位:Many of the key control paths in the kernel are described, step by step;一步一步地講述內(nèi)核控制路徑的實(shí)現(xiàn)。The level of detail sometimes makes it hard to get a sense for the big picture, but it does help somebody trying to figure out how a particular function works.對(duì)代碼講解的詳細(xì)程度有時(shí)候很難讓讀者把握住它的主旨大意,但是確實(shí)有助于讀者理解一個(gè)特定的函數(shù)到底是如何工作的。Indeed, that is perhaps the key feature which differentiates this book. It is very much a “how it works” book, designed to help people understand the code.事實(shí)上,這也正是本書與眾不同的地方。更像一個(gè)“如何工作”的書,幫助讀者理解代碼實(shí)現(xiàn)。It presents kernel functions and data structures, steps the reader through them, but does not, for example, emphasize the rules for using them. UTLK is a study guide, not a programming manual.本書描述了內(nèi)核函數(shù)和數(shù)據(jù)結(jié)構(gòu),引導(dǎo)讀者穿行于其間,但是,并沒(méi)有著重強(qiáng)調(diào)使用它們的法則。UTLK是一本學(xué)習(xí)指南,而不是編程手冊(cè)。 這幾句話對(duì)本書的描述非常到位?;诖?,作為指導(dǎo)性原則,我們就可以很有效率地使用它了。看一本技術(shù)書籍,書中的序言部分絕對(duì)是首先應(yīng)該翻閱的,其次就是目錄。我發(fā)現(xiàn)在閱讀過(guò)程中我會(huì)頻繁的查看目錄,甚至是喜歡看目錄。興趣的力量是無(wú)窮的。興趣能帶來(lái)激情,如果工作可以和興趣結(jié)合到一起,工作起來(lái)才會(huì)有熱情,那么工作就不只是工作了,更是一種享受。Linux,我的興趣,我的動(dòng)力,我的方向,我的未來(lái)!
|