Skip to content

Linux Device Driver系列 1

引言

自由的作業系統中,例如linux,公開他們的內部是此類作業系統的優點之一,這讓原本只有一部分程式設計師了解的OS,能被公開的檢驗、了解、修改

其中,Device Driver是複雜OS系統中很好的入門磚

Device Driver可以是一個個不同的"黑盒子”,作為硬體、軟體之間的介面,並且抽象化地隱藏複雜的硬體實作,讓使用者可以統一呼叫、利用硬體資源

linux driver 可以藉由標準呼叫(standardized call)來統一的與特定裝置溝通,並且因為模組化,所以linux driver相對易寫

寫driver時雖然大部分有共同的規則與基礎,但還是須了解執行的裝置

Device Driver的角色

以功能角度

Device driver應該提供功能,而不是使用功能
這是unix 設計的核心思想之一,大多數程式設計問題可以分為 “提供甚麼功能”(mechanism)以及"怎麼使用功能”(policy)兩大部分
舉例而言:
圖形化介面是一種policy,他不需要知道硬體資源如何,都可以在不同機器上使用
而TCP/IP架構是一種mechanism,他提供傳輸的功能,但並沒有具體規定傳輸資料的功能

因此driver只提供 “抽象化界面"這個功能 (mechanism) 如何使用這個功能是高階系統的工作

並且由於高階系統目的不盡相同,越是單純的提供功能越好(policy free)

重點: driver的工作是提供硬體資源介面,不應干涉(預設)使用者目的”

當然出於某些目的,也有例外,比如IO driver為了簡化程式碼,必須限定提供byte-wide的存取,避免額外程式碼處理個別bit

以軟硬體角度

是一個介於應用程式與硬體之間的軟體層 (與OS同層)
driver設計師必須要考量很多問題,
比如:
提供甚麼功能 - 即使同一device也可能提供不同功能
同步性(Concurrency)的使用 - 有眾多不同的實作方式

補充:
(Concurrency vs Parallelism)
Concurrency : 多個人分解同一個工作,比如A負責洗菜、B負責炒菜、C負責上菜,會共用資源 ,實際例子:multi-thread
Parallelism : 多個人分別做同一個工作,比如A、B、C三條獨立又相同的生產線, 實際例子: 伺服器分流

重點: driver必須取捨 提供眾多的功能 與 撰寫的時間 與 複雜程度(error 發生率)

kernel的工作

Unix系統中,process會在執行時要求資源,比如計算能力、記憶體、網路連線 …
kernel(OS)就是一個大區塊的程式負責處理這些要求,並且大致可以分為

  1. Process Management
    kernal負責process的創造、消滅、處理IO, 甚至process之間的溝通(signal、pipe …)
    除此之外也會掌管process的排程,決定誰可以使用CPU

  2. Memory Management
    Memory是重要的資源,kernel會建立一個虛擬位址供process使用,以管理、分配有限的資源
    不同的系統有不同的記憶體分配機制,從最簡單的malloc/free 到 更為複雜的功能

  3. File System
    萬物於Unix皆視為檔案, kernel會建立結構化的檔案系統於非結構化的硬體中
    Unix也提供不同的檔案系統類型,比如Linux-standard ext3 、 FAT

  4. Divice Control
    幾乎所有的系統操作終端都是實體裝置,而操作執行device的code就稱為device driver, 這也是本書的重點

  5. Networking
    網路必須由OS管理,因為網路並不是一個特定process
    在給特定process處理之前,傳送封包與非同步事件必須被管理、認證、分配

Loadable Modules

linux一個很好的功能就是可以在系統執行時增加、移除kernel的功能
這些可被加入的程式碼片段被稱為module,而device driver也是其中之一

這些module可以分別使用insmod與rmmod程式來加進、移出kernel

下圖是個不同功能module的例子

Classes of Devices and Modules

linux的module基本上可以分為三類

  • char module
  • block module
  • network module
    分別對應到三種裝置類型
character devices

可以取用stream of bytes (比如檔案)
應用於至少有open,close,read,write的system call
應用例子有 text console (/dev/console) 以及 serial port

大多數character device只是資料流,所以無法往回 (printf buffer為例) (以序列為主,主要用於滑鼠、鍵盤、終端機… 參考這裡)

Block devices

block device通常可以建立檔案系統 (比如disk) unix系統中block devices會以block為單位 (通常是512bytes)處理資料讀寫

linux則是允許和char device一樣以byte為單位
因此兩者只差在kernel內部管理資料的方式

Network interface

網路交換一定要通過網路介面,也就是與其他host交換資料一定要通過Network interface
通常這個interface是硬體,但也有軟體的例子,比如loopback interface

補充 loopback interface
參考這裡 簡單來說就是常見的localhost,也就是IP 127.x.x.x (A類網路) 的部分都會使用此介面 以允許執行在同一臺主機上的客戶程式和伺服器程式通TCP/IP進行通訊

network driver 不知道連線相關的東西,只負責處理封包
並且只有在需要data transmission時會被呼叫

其他分類

driver也可以依對應到的裝置區分
比如USB(Universal serial bus) module、serial modules、 SCSI module …

實例: 一個USB module可能是char , block 與 network
char : usb serial port
block : usb memory card
network : usb Ethernet interface

安全議題

seruity check會被kernel code執行
只有有權限的(authorized)user可以載入module, 由init_module進行檢查

同時driver在寫入功能時也必須注意權限
當操作會使用global資源、可能消耗硬體、影響其他使用者時都必須要求執行權限

也必須要注意比如

  • buffer overrun等C語言容易犯的錯
  • 不要信任收到的input
  • 小心未初始化的memory,尤其是kernel掌管的memory (用完要清空,否則重要資訊(password、log)可能被偷)
  • 第三方的程式 (比如可能被鑽init_module的漏洞)

雜記

版本號

所有的linux software package都有對應的版本號
要對應好相對的版本才能正確地執行,並且現代的package management基本上都會檢查相依性
本書使用2.6 kernel 至2020已更新到5.8.5

小常識: 通常偶數版本的kernel 是穩定版,奇數版本的kernel是開發版

License

linux Version 2 以後的版本都有GNU General Public Licence (GPL)驗證
讓任何人都可以重新發布、甚至販售以被GPL認證的東西為基礎的產品,並且接收方可以收到原始碼,也可以做一樣的事情

參考資料

https://lwn.net/Kernel/LDD3/ chapter 1 : An Introdution to Device Drivers