一文教你搞懂Linux內(nèi)核
在操作系統(tǒng)的世界里,Linux內(nèi)核層就如同脈搏一樣,維持著系統(tǒng)的運轉(zhuǎn)。相當(dāng)于一座橋梁,內(nèi)核層的首要任務(wù)是確保硬件和軟件如同兩條交匯的河流順暢溝通。此外,它還得操控著系統(tǒng)中一些至關(guān)重要的資源,就像指揮一場交響樂,讓各個樂器得以協(xié)調(diào)演奏。
關(guān)于Linux內(nèi)核的結(jié)構(gòu),可以把它簡單分成三個層次,就像一個三層蛋糕,頂層是應(yīng)用程序,中間是系統(tǒng)調(diào)用,而底層則是內(nèi)核本身。每一層都有其獨特的角色,卻又緊密相連,使整個系統(tǒng)高效運轉(zhuǎn)。
Linux內(nèi)核的底蘊可不簡單,它既有輕巧的特點,又擁有強大的能力。它的靈活性讓開發(fā)者們能根據(jù)不同需求進(jìn)行裁剪和修改,仿佛是一件千變?nèi)f化的服裝,能適應(yīng)各種場合。
Linux內(nèi)核預(yù)備工作
理解Linux內(nèi)核最好預(yù)備的知識點:
懂C語言
懂一點操作系統(tǒng)的知識
熟悉少量相關(guān)算法
懂計算機體系結(jié)構(gòu)
Linux內(nèi)核的特點:
結(jié)合了unix操作系統(tǒng)的一些基礎(chǔ)概念
Linux內(nèi)核的任務(wù):
1.從技術(shù)層面講,內(nèi)核是硬件與軟件之間的一個中間層。作用是將應(yīng)用層序的請求傳遞給硬件,并充當(dāng)?shù)讓域?qū)動程序,對系統(tǒng)中的各種設(shè)備和組件進(jìn)行尋址。
2.從應(yīng)用程序的層面講,應(yīng)用程序與硬件沒有聯(lián)系,只與內(nèi)核有聯(lián)系,內(nèi)核是應(yīng)用程序知道的層次中的最底層。在實際工作中內(nèi)核抽象了相關(guān)細(xì)節(jié)。
3.內(nèi)核是一個資源管理程序。負(fù)責(zé)將可用的共享資源(CPU時間、磁盤空間、網(wǎng)絡(luò)連接等)分配得到各個系統(tǒng)進(jìn)程。
4.內(nèi)核就像一個庫,提供了一組面向系統(tǒng)的命令。系統(tǒng)調(diào)用對于應(yīng)用程序來說,就像調(diào)用普通函數(shù)一樣。
內(nèi)核實現(xiàn)策略:
1.微內(nèi)核。最基本的功能由中央內(nèi)核(微內(nèi)核)實現(xiàn)。所有其他的功能都委托給一些獨立進(jìn)程,這些進(jìn)程通過明確定義的通信接口與中心內(nèi)核通信。
2.宏內(nèi)核。內(nèi)核的所有代碼,包括子系統(tǒng)(如內(nèi)存管理、文件管理、設(shè)備驅(qū)動程序)都打包到一個文件中。內(nèi)核中的每一個函數(shù)都可以訪問到內(nèi)核中所有其他部分。目前支持模塊的動態(tài)裝卸(裁剪)。Linux內(nèi)核就是基于這個策略實現(xiàn)的。
哪些地方用到了內(nèi)核機制?
1.進(jìn)程(在cpu的虛擬內(nèi)存中分配地址空間,各個進(jìn)程的地址空間完全獨立;同時執(zhí)行的進(jìn)程數(shù)最多不超過cpu數(shù)目)之間進(jìn)行通 信,需要使用特定的內(nèi)核機制。
2.進(jìn)程間切換(同時執(zhí)行的進(jìn)程數(shù)最多不超過cpu數(shù)目),也需要用到內(nèi)核機制。
進(jìn)程切換也需要像FreeRTOS任務(wù)切換一樣保存狀態(tài),并將進(jìn)程置于閑置狀態(tài)/恢復(fù)狀態(tài)。
3.進(jìn)程的調(diào)度。確認(rèn)哪個進(jìn)程運行多長的時間。
Linux進(jìn)程
1.采用層次結(jié)構(gòu),每個進(jìn)程都依賴于一個父進(jìn)程。內(nèi)核啟動init程序作為第一個進(jìn)程。該進(jìn)程負(fù)責(zé)進(jìn)一步的系統(tǒng)初始化操作。init進(jìn)程是進(jìn)程樹的根,所有的進(jìn)程都直接或者間接起源于該進(jìn)程。
2.通過pstree命令查詢。實際上得系統(tǒng)第一個進(jìn)程是systemd,而不是init(這也是疑問點)
3.系統(tǒng)中每一個進(jìn)程都有一個唯一標(biāo)識符(ID),用戶(或其他進(jìn)程)可以使用ID來訪問進(jìn)程。
Linux內(nèi)核源代碼的目錄結(jié)構(gòu)
Linux內(nèi)核源代碼包括三個主要部分:
1. 內(nèi)核核心代碼,包括第3章所描述的各個子系統(tǒng)和子模塊,以及其它的支撐子系統(tǒng),例如電源管理、Linux初始化等
2. 其它非核心代碼,例如庫文件(因為Linux內(nèi)核是一個自包含的內(nèi)核,即內(nèi)核不依賴其它的任何軟件,自己就可以編譯通過)、固件集合、KVM(虛擬機技術(shù))等
3. 編譯腳本、配置文件、幫助文檔、版權(quán)說明等輔助性文件
使用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ū)動的網(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è)備樹(Device Tree)文件。init/ ---- Linux系統(tǒng)啟動初始化相關(guān)的代碼。
block/ ---- 提供塊設(shè)備的層次。
sound/ ---- 音頻相關(guān)的驅(qū)動及子系統(tǒng),可以看作“音頻子系統(tǒng)”。
drivers/ ---- 設(shè)備驅(qū)動(在Linux kernel 3.10中,設(shè)備驅(qū)動占了49.4的代碼量)。lib/ ---- 實現(xiàn)需要在內(nèi)核中使用的庫函數(shù),例如CRC、FIFO、list、MD5等。
crypto/ ----- 加密、解密相關(guān)的庫函數(shù)。
security/ ---- 提供安全特性(SELinux)。
virt/ ---- 提供虛擬機技術(shù)(KVM等)的支持。
usr/ ---- 用于生成initramfs的代碼。
firmware/ ---- 保存用于驅(qū)動第三方設(shè)備的固件。samples/ ---- 一些示例代碼。
tools/ ---- 一些常用工具,如性能剖析、自測試等。Kconfig, Kbuild, Makefile, scripts/ ---- 用于內(nèi)核編譯的配置文件、腳本等。COPYING ---- 版權(quán)聲明。
MAINTAINERS ----維護(hù)者名單。
CREDITS ---- Linux主要的貢獻(xiàn)者名單。
REPORTING-BUGS ---- Bug上報的指南。Documentation, README ---- 幫助、說明文檔。
Linux內(nèi)核體系結(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)換的機制。這點非常重要,因為內(nèi)核和用戶空間的應(yīng)用程序使用的是不同的保護(hù)地址空間。每個用戶空間的進(jìn)程都使用自己的虛擬地址空間,而內(nèi)核則占用單獨的地址空間。
Linux 內(nèi)核可以進(jìn)一步劃分成 3 層。最上面是系統(tǒng)調(diào)用接口,它實現(xiàn)了一些基本的功能,例如 read 和 write。系統(tǒng)調(diào)用接口之下是內(nèi)核代碼,可以更精確地定義為獨立于體系結(jié)構(gòu)的內(nèi)核代碼。這些代碼是 Linux 所支持的所有處理器體系結(jié)構(gòu)所通用的。在這些代碼之下是依賴于體系結(jié)構(gòu)的代碼,構(gòu)成了通常稱為 BSP(Board Support Package)的部分。這些代碼用作給定體系結(jié)構(gòu)的處理器和特定于平臺的代碼。
Linux 內(nèi)核實現(xiàn)了很多重要的體系結(jié)構(gòu)屬性。在或高或低的層次上,內(nèi)核被劃分為多個子系統(tǒng)。Linux 也可以看作是一個整體,因為它會將所有這些基本服務(wù)都集成到內(nèi)核中。這與微內(nèi)核的體系結(jié)構(gòu)不同,后者會提供一些基本的服務(wù),例如通信、I/O、內(nèi)存和進(jìn)程管理,更具體的服務(wù)都是插入到微內(nèi)核層中的。每種內(nèi)核都有自己的優(yōu)點,不過這里并不對此進(jìn)行討論。
隨著時間的流逝,Linux 內(nèi)核在內(nèi)存和 CPU 使用方面具有較高的效率,并且非常穩(wěn)定。但是對于 Linux 來說,最為有趣的是在這種大小和復(fù)雜性的前提下,依然具有良好的可移植性。Linux 編譯后可在大量處理器和具有不同體系結(jié)構(gòu)約束和需求的平臺上運行。一個例子是 Linux 可以在一個具有內(nèi)存管理單元(MMU)的處理器上運行,也可以在那些不提供 MMU 的處理器上運行。 Linux 內(nèi)核的 uClinux 移植提供了對非 MMU 的支持。
Linux內(nèi)核的主要組件有:系統(tǒng)調(diào)用接口、進(jìn)程管理、內(nèi)存管理、虛擬文件系統(tǒng)、網(wǎng)絡(luò)堆棧、設(shè)備驅(qū)動程序、硬件架構(gòu)的相關(guān)代碼。
(1)系統(tǒng)調(diào)用接口
SCI 層提供了某些機制執(zhí)行從用戶空間到內(nèi)核的函數(shù)調(diào)用。正如前面討論的一樣,這個接口依賴于體系結(jié)構(gòu),甚至在相同的處理器家族內(nèi)也是如此。SCI 實際上是一個非常有用的函數(shù)調(diào)用多路復(fù)用和多路分解服務(wù)。在 ./linux/kernel 中您可以找到 SCI 的實現(xiàn),并在 ./linux/arch 中找到依賴于體系結(jié)構(gòu)的部分。
(2)進(jìn)程管理
進(jìn)程管理的重點是進(jìn)程的執(zhí)行。在內(nèi)核中,這些進(jìn)程稱為線程,代表了單獨的處理器虛擬化(線程代碼、數(shù)據(jù)、堆棧和 CPU 寄存器)。在用戶空間,通常使用進(jìn)程 這個術(shù)語,不過 Linux 實現(xiàn)并沒有區(qū)分這兩個概念(進(jìn)程和線程)。內(nèi)核通過 SCI 提供了一個應(yīng)用程序編程接口(API)來創(chuàng)建一個新進(jìn)程(fork、exec 或 Portable Operating System Interface [POSIX] 函數(shù)),停止進(jìn)程(kill、exit),并在它們之間進(jìn)行通信和同步(signal 或者 POSIX 機制)。
進(jìn)程管理還包括處理活動進(jìn)程之間共享 CPU 的需求。內(nèi)核實現(xiàn)了一種新型的調(diào)度算法,不管有多少個線程在競爭 CPU,這種算法都可以在固定時間內(nèi)進(jìn)行操作。這種算法就稱為 O(1) 調(diào)度程序,這個名字就表示它調(diào)度多個線程所使用的時間和調(diào)度一個線程所使用的時間是相同的。O(1) 調(diào)度程序也可以支持多處理器(稱為對稱多處理器或 SMP)。您可以在 ./linux/kernel 中找到進(jìn)程管理的源代碼,在 ./linux/arch 中可以找到依賴于體系結(jié)構(gòu)的源代碼。
(3)內(nèi)存管理
內(nèi)核所管理的另外一個重要資源是內(nèi)存。為了提高效率,如果由硬件管理虛擬內(nèi)存,內(nèi)存是按照所謂的內(nèi)存頁 方式進(jìn)行管理的(對于大部分體系結(jié)構(gòu)來說都是 4KB)。Linux 包括了管理可用內(nèi)存的方式,以及物理和虛擬映射所使用的硬件機制。不過內(nèi)存管理要管理的可不止 4KB 緩沖區(qū)。Linux 提供了對 4KB 緩沖區(qū)的抽象,例如 slab 分配器。這種內(nèi)存管理模式使用 4KB 緩沖區(qū)為基數(shù),然后從中分配結(jié)構(gòu),并跟蹤內(nèi)存頁使用情況,比如哪些內(nèi)存頁是滿的,哪些頁面沒有完全使用,哪些頁面為空。這樣就允許該模式根據(jù)系統(tǒng)需要來動態(tài)調(diào)整內(nèi)存使用。為了支持多個用戶使用內(nèi)存,有時會出現(xiàn)可用內(nèi)存被消耗光的情況。由于這個原因,頁面可以移出內(nèi)存并放入磁盤中。這個過程稱為交換,因為頁面會被從內(nèi)存交換到硬盤上。內(nèi)存管理的源代碼可以在 ./linux/mm 中找到。
(4)虛擬文件系統(tǒng)
虛擬文件系統(tǒng)(VFS)是 Linux 內(nèi)核中非常有用的一個方面,因為它為文件系統(tǒng)提供了一個通用的接口抽象。VFS 在 SCI 和內(nèi)核所支持的文件系統(tǒng)之間提供了一個交換層。
在 VFS 上面,是對諸如 open、close、read 和 write 之類的函數(shù)的一個通用 API 抽象。在 VFS 下面是文件系統(tǒng)抽象,它定義了上層函數(shù)的實現(xiàn)方式。它們是給定文件系統(tǒng)(超過 50 個)的插件。文件系統(tǒng)的源代碼可以在 ./linux/fs 中找到。文件系統(tǒng)層之下是緩沖區(qū)緩存,它為文件系統(tǒng)層提供了一個通用函數(shù)集(與具體文件系統(tǒng)無關(guān))。這個緩存層通過將數(shù)據(jù)保留一段時間(或者隨即預(yù)先讀取數(shù)據(jù)以便在需要是就可用)優(yōu)化了對物理設(shè)備的訪問。緩沖區(qū)緩存之下是設(shè)備驅(qū)動程序,它實現(xiàn)了特定物理設(shè)備的接口。
(5)網(wǎng)絡(luò)堆棧
網(wǎng)絡(luò)堆棧在設(shè)計上遵循模擬協(xié)議本身的分層體系結(jié)構(gòu)?;叵胍幌?,Internet Protocol (IP) 是傳輸協(xié)議(通常稱為傳輸控制協(xié)議或 TCP)下面的核心網(wǎng)絡(luò)層協(xié)議。TCP 上面是 socket 層,它是通過 SCI 進(jìn)行調(diào)用的。socket 層是網(wǎng)絡(luò)子系統(tǒng)的標(biāo)準(zhǔn) API,它為各種網(wǎng)絡(luò)協(xié)議提供了一個用戶接口。從原始幀訪問到 IP 協(xié)議數(shù)據(jù)單元(PDU),再到 TCP 和 User Datagram Protocol (UDP),socket 層提供了一種標(biāo)準(zhǔn)化的方法來管理連接,并在各個終點之間移動數(shù)據(jù)。內(nèi)核中網(wǎng)絡(luò)源代碼可以在 ./linux/net 中找到。
(6)設(shè)備驅(qū)動程序
Linux 內(nèi)核中有大量代碼都在設(shè)備驅(qū)動程序中,它們能夠運轉(zhuǎn)特定的硬件設(shè)備。Linux 源碼樹提供了一個驅(qū)動程序子目錄,這個目錄又進(jìn)一步劃分為各種支持設(shè)備,例如 Bluetooth、I2C、serial 等。設(shè)備驅(qū)動程序的代碼可以在 ./linux/drivers 中找到。
(7)依賴體系結(jié)構(gòu)的代碼
盡管 Linux 很大程度上獨立于所運行的體系結(jié)構(gòu),但是有些元素則必須考慮體系結(jié)構(gòu)才能正常操作并實現(xiàn)更高效率。./linux/arch 子目錄定義了內(nèi)核源代碼中依賴于體系結(jié)構(gòu)的部分,其中包含了各種特定于體系結(jié)構(gòu)的子目錄(共同組成了 BSP)。對于一個典型的桌面系統(tǒng)來說,使用的是 x86 目錄。每個體系結(jié)構(gòu)子目錄都包含了很多其他子目錄,每個子目錄都關(guān)注內(nèi)核中的一個特定方面,例如引導(dǎo)、內(nèi)核、內(nèi)存管理等。這些依賴體系結(jié)構(gòu)的代碼可以在 ./linux/arch 中找到。
如果 Linux 內(nèi)核的可移植性和效率還不夠好,Linux 還提供了其他一些特性,它們無法劃分到上面的分類中。作為一個生產(chǎn)操作系統(tǒng)和開源軟件,Linux 是測試新協(xié)議及其增強的良好平臺。Linux 支持大量網(wǎng)絡(luò)協(xié)議,包括典型的 TCP/IP,以及高速網(wǎng)絡(luò)的擴展(大于 1 Gigabit Ethernet [GbE] 和 10 GbE)。Linux 也可以支持諸如流控制傳輸協(xié)議(SCTP)之類的協(xié)議,它提供了很多比 TCP 更高級的特性(是傳輸層協(xié)議的接替者)。 Linux 還是一個動態(tài)內(nèi)核,支持動態(tài)添加或刪除軟件組件。被稱為動態(tài)可加載內(nèi)核模塊,它們可以在引導(dǎo)時根據(jù)需要(當(dāng)前特定設(shè)備需要這個模塊)或在任何時候由用戶插入。 Linux 最新的一個增強是可以用作其他操作系統(tǒng)的操作系統(tǒng)(稱為系統(tǒng)管理程序)。最近,對內(nèi)核進(jìn)行了修改,稱為基于內(nèi)核的虛擬機(KVM)。這個修改為用戶空間啟用了一個新的接口,它可以允許其他操作系統(tǒng)在啟用了 KVM 的內(nèi)核之上運行。除了運行 Linux 的其他實例之外, Microsoft Windows也可以進(jìn)行虛擬化。惟一的限制是底層處理器必須支持新的虛擬化指令。
Linux體系結(jié)構(gòu)和內(nèi)核結(jié)構(gòu)區(qū)別
1.當(dāng)被問到Linux體系結(jié)構(gòu)(就是Linux系統(tǒng)是怎么構(gòu)成的)時,我們可以這么回答:從大的方面講,Linux體系結(jié)構(gòu)可以分為兩塊:
(1)用戶空間:用戶空間中又包含了,用戶的應(yīng)用程序,C庫
(2)內(nèi)核空間:內(nèi)核空間包括,系統(tǒng)調(diào)用,內(nèi)核,以及與平臺架構(gòu)相關(guān)的代碼 2.Linux體系結(jié)構(gòu)要分成用戶空間和內(nèi)核空間的原因:
1)現(xiàn)代CPU通常都實現(xiàn)了不同的工作模式,
以ARM為例:ARM實現(xiàn)了7種工作模式,不同模式下CPU可以執(zhí)行的指令或者訪問的寄存器不同:
(1)用戶模式 usr (2)系統(tǒng)模式 sys (3)管理模式 svc (4)快速中斷 fiq (5)外部中斷 irq (6)數(shù)據(jù)訪問終止 abt (7)未定義指令異常
以(2)X86為例:X86實現(xiàn)了4個不同級別的權(quán)限,Ring0—Ring3 ;Ring0下可以執(zhí)行特權(quán)指令,可以訪問IO設(shè)備;Ring3則有很多的限制
2)所以,Linux從CPU的角度出發(fā),為了保護(hù)內(nèi)核的安全,把系統(tǒng)分成了2部分;
3.用戶空間和內(nèi)核空間是程序執(zhí)行的兩種不同狀態(tài),我們可以通過“系統(tǒng)調(diào)用”和“硬件中斷“來完成用戶空間到內(nèi)核空間的轉(zhuǎn)移
4.Linux的內(nèi)核結(jié)構(gòu)(注意區(qū)分LInux體系結(jié)構(gòu)和Linux內(nèi)核結(jié)構(gòu))
Linux驅(qū)動的platform機制
Linux的這種platform driver機制和傳統(tǒng)的device_driver機制相比,一個十分明顯的優(yōu)勢在于platform機制將本身的資源注冊進(jìn)內(nèi)核,由內(nèi)核統(tǒng)一管理,在驅(qū)動程序中使用這些資源時通過platform_device提供的標(biāo)準(zhǔn)接口進(jìn)行申請并使用。這樣提高了驅(qū)動和資源管理的獨立性,并且擁有較好的可移植性和安全性。Linux中的SPI總線可理解為SPI控制器引出的總線:
和傳統(tǒng)的驅(qū)動一樣,platform機制也分為三個步驟:
1、總線注冊階段:
內(nèi)核啟動初始化時的main.c文件中的kernel_init()→do_basic_setup()→driver_init()→platform_bus_init()→bus_register(&platform_bus_type),注冊了一條platform總線(虛擬總線,platform_bus)。
2、添加設(shè)備階段:
設(shè)備注冊的時候Platform_device_register()→platform_device_add()→(pdev→dev.bus = &platform_bus_type)→device_add(),就這樣把設(shè)備給掛到虛擬的總線上。
3、驅(qū)動注冊階段:
Platform_driver_register()→driver_register()→bus_add_driver()→driver_attach()→bus_for_each_dev(), 對在每個掛在虛擬的platform bus的設(shè)備作__driver_attach()→driver_probe_device(),判斷drv→bus→match()是否執(zhí)行成功,此時通過指針執(zhí)行platform_match→strncmp(pdev→name , drv→name , BUS_ID_SIZE),如果相符就調(diào)用really_probe(實際就是執(zhí)行相應(yīng)設(shè)備的platform_driver→probe(platform_device)。)開始真正的探測,如果probe成功,則綁定設(shè)備到該驅(qū)動。
從上面可以看出,platform機制最后還是調(diào)用了bus_register() , device_add() , driver_register()這三個關(guān)鍵的函數(shù)。
下面看幾個結(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)體描述了一個platform結(jié)構(gòu)的設(shè)備,在其中包含了一般設(shè)備的結(jié)構(gòu)體struct device dev;設(shè)備的資源結(jié)構(gòu)體struct resource * resource;還有設(shè)備的名字const char * name。(注意,這個名字一定要和后面platform_driver.driver àname相同,原因會在后面說明。)
該結(jié)構(gòu)體中最重要的就是resource結(jié)構(gòu),這也是之所以引入platform機制的原因。
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)體描述了一個platform結(jié)構(gòu)的驅(qū)動。其中除了一些函數(shù)指針外,還有一個一般驅(qū)動的device_driver結(jié)構(gòu)。
名字要一致的原因:
上面說的驅(qū)動在注冊的時候會調(diào)用函數(shù)bus_for_each_dev(), 對在每個掛在虛擬的platform bus的設(shè)備作__driver_attach()→driver_probe_device(),在此函數(shù)中會對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,相同則會進(jìn)入really_probe()函數(shù),從而進(jìn)入自己寫的probe函數(shù)做進(jìn)一步的匹配。所以dev→name和driver→drv→name在初始化時一定要填一樣的。
不同類型的驅(qū)動,其match函數(shù)是不一樣的,這個platform的驅(qū)動,比較的是dev和drv的名字,還記得usb類驅(qū)動里的match嗎?它比較的是Product ID和Vendor ID。
個人總結(jié)Platform機制的好處:
1、提供platform_bus_type類型的總線,把那些不是總線型的soc設(shè)備都添加到這條虛擬總線上。使得,總線——設(shè)備——驅(qū)動的模式可以得到普及。
2、提供platform_device和platform_driver類型的數(shù)據(jù)結(jié)構(gòu),將傳統(tǒng)的device和driver數(shù)據(jù)結(jié)構(gòu)嵌入其中,并且加入resource成員,以便于和Open Firmware這種動態(tài)傳遞設(shè)備資源的新型bootloader和kernel 接軌。