聊聊Linux用戶態驅動設計

序言

設備驅動能夠運行在內核態,也能夠運行在用戶態,用戶態驅動的利弊網上有不少的討論,並且有些還上升到政治性上,這裏再也不多作討論。無論用戶態驅動仍是內核態驅動,他們都有各自的缺點。內核態驅動的問題是:系統調用開銷大;學習曲線陡峭;接口穩定性差;調試困難;bug致命;編程語言選擇受限;而用戶態驅動面臨的挑戰是:如何中斷處理;如何DMA;如何管理設備的依賴關係;沒法使用內核服務等。對此,《User-Space Device Drivers in Linux: A First Look》 一文有較詳細描述。linux

多是爲了性能優化,或者爲了故障隔離,或者爲了逃避開源許可證的約束,無論是基於何種目的,linux已有多種用戶態驅動的實現,如UIO,VFIO、USB用戶態驅動等。它們在處理中斷、DMA、設備依賴管理等方面的設計方案和實現細節上各有千秋,這是《User-Space Device Drivers in Linux: A First Look》 沒有提到的,也是本文的重點。git

UIO

 

UIO 框架導出sysfs和/dev/uioX 2套用戶態接口,用戶對設備節點/dev/uioX進行設備控制,mmap()接口用於映射設備寄存器空間,write()接口用於控制中斷關閉/打開,read()接口用於等待一個設備中斷。編程

由於對於設備中斷的應答必須在內核空間進行,因此在內核空間有一小部分代碼用來應答中斷和禁止中斷,其他的工做所有留給用戶空間處理。若是用戶空間要等待一個設備中斷,它只須要簡單的阻塞在對 /dev/uioX的read()操做上。 當設備產生中斷時,read()操做當即返回。UIO 也實現了poll()系統調用,你可使用 select()來等待中斷的發生。select()有一個超時參數能夠用來實現有限時間內等待中斷。安全

UIO的幾個特色:性能優化

  • 一個UIO設備最多支持5個mem和portio空間mmap映射。 
  • UIO設備的中斷用戶態通訊機制基於wait_queue實現。
  • 一個UIO設備只支持一箇中斷號註冊,支持中斷共享。

總的來講,UIO框架適用於簡單設備的驅動,由於它不支持DMA,不能支持多箇中斷線,缺少邏輯設備抽象能力。數據結構

VFIO

 

 上文提到,UIO不支持DMA,因此經過DMA傳輸大流量數據的IO設備,如網卡、顯卡等設備,沒法使用UIO框架,VFIO作爲UIO的升級版,主要就是解決了這個問題。經過用戶態配置IOMMU接口,能夠將DMA地址空間映射限制在進程虛擬空間中。這對高性能驅動和虛擬化場景device passthrough尤爲重要。併發

在VFIO框架中,有幾個核心概念或對象:IOMMU、/dev/vfio、container、iommu_group。框架

  • IOMMU是一個硬件單元,它能夠把設備的IO地址映射成虛擬地址,爲設備提供頁表映射,設備經過IOMMU將數據直接DMA寫到用戶空間。之因此不共用MMU單元,是爲了保證和進程的頁表相互獨立,防止設備訪問進程的任意地址空間。因此VFIO的IOMMU功能保障了安全的非特權級別的用戶態設備驅動機制。
  •  /dev/vfio是一個設備文件,做爲一個IOMMU設備的用戶態呈現。
  • container是內核對象,表示一個IOMMU設備,是一個IOMMU設備的內核態呈現。因此在VFIO中,container是IOMMU操做的最小對象。
  • 在虛擬化場景下,一個物理網卡可能要虛擬成幾個虛擬網卡,或者說虛擬功能設備(VF),這幾個VF共用一個IOMMU,因此VFIO模型增長一個iommu_group的概念,用來表示共享同一個IOMMU的一組device。

VFIO的幾個特色:異步

  • VFIO設備支持多中斷號註冊。
  • 設備的中斷用戶態通訊機制基於eventfd/irqfd實現。用戶經過/dev/vfio設備select/poll/epoll,從而實現中斷從內核態到用戶態的異步事件通知。
  • 支持對物理設備進行邏輯抽象。
  • 僅支持pci intx中斷共享,其餘類型中斷不支持共享。
  • VFIO僅支持特定IOMMU設備,如x86與PowerPC平臺的PCI設備和ARM平臺的platform設備。

USB用戶態驅動

usbfs(USB file system)提供了一些在用戶空間下操做USB設備的函數接口和數據結構, 在開發用戶態驅動時, 能夠直接利用這些函數接口來實現對 USB 設備的控制和數據傳輸。
libusb對usb file system提供的函數接口和數據結構進行了封裝, 能夠有效減小程序中函數和數據結構使用不當形成的錯誤。Libusb 對 USB 設備的訪問提供了兩種機制, 同步訪問和異步訪問。
khubd是內核後臺線程,用來管理監視USB HUB的狀態, 一旦發生熱插拔就會喚醒這個線程, 進而添加或者移除設備,併發送netlink消息傳遞給用戶態空間。編程語言

USB 用戶態驅動框架的幾個特色:

  • 設備的中斷用戶態通訊機制基於netlink實現。
  • USB設備以usbdevfs (後更名爲usbfs)文件系統的形式(如/proc/bus/usb/BBB/DDD)對用戶態呈現。
  • 對usb的全部訪問經過usbfs ioctl實現,如control transfer, bulk transfer, reset等。
  • 僅支持USB設備

參考資料

Linux Kernel v4.4

User-Space Device Drivers in Linux: A First Look

User-Mode Driver Framework

VFIO Introduction

Linux iommu和vfio概念空間解構

相關文章
相關標籤/搜索