第三章 設計與實作
3.1 核心模式驅動程式搬移(migration)
3.1.2 架構元件
3.1.2.3 Runtime Environment
我們將Runtime Environment 實作為一個使用者空間的靜態連結函式庫 Proxy Driver User Mode Device Driver
req req req
rsp rsp rsp
req
Metadata
….
Ring Section Data Section
Ring Producer Ring Consumer
Data Producer Data Consumer
Request Id
Data Start Size Cmd
(Statically-Link Library)。它主要負責兩個工作:
1. 提供驅動程式所需要的 API 以及模擬一些驅動程式需要用到的核心程式變數資 料。需要提供的API 類型根據原本核心分類有 IRQ,I/O Region,DMA,Timer queue…
等。這些API 依據實作的方式可以分為三類:
(a) 第一類API 需要核心支援,所以我們利用系統呼叫去向 Proxy Server 要求,Proxy Server 會進一步去向原本核心所提供的服務請求,中斷處理與存取 DMA 都屬於此
分類中。我們對於中斷處理與存取DMA 的方法如下:
中斷處理(Interrupt handler):
我們使用與澳洲新南威斯大學相同的方法[17],如 Figure 8,我們一開始在 /proc/irq/n(n 表示 irq 的號碼)目錄下去創造一個檔案 irq,當 Interrupt thread 去
打開/proc/irq/n/irq 時,在核心中將有一個我們自己寫的中斷處理函式會被註 冊。當Interrupt thread 讀取這個檔案,如果這個檔案中沒有資料,則 Interrupt thread 將會進入睡眠狀態,等待中斷發生。而當有中斷處理發生時,則核心中 的中斷處理函式則會寫入資料到這個檔案,接著Interrupt thread 則會被喚起去 讀取資料,並且去執行驅動程式中的中斷處理函式。
Figure 8:Interrupt Handler Flow
DMA 存取:
使用者模式驅動程式所用的緩衝(buffer)是利用虛擬位址(virtual address)做區 別,而有DMA 能力的裝置卻需要把這些位址轉換成 I/O 匯流排位址,I/O 匯 流排位址可能是物理記憶體位址或者是I/O 匯流排映射到物理記憶體的位址。
如果說裝置需要使用到DMA 的話,例如:PCI 裝置去請求 DMA 的
pci_alloc_consistent()函式, 我們會先在核心模式中去分配一塊 DMA 記憶體空
Main thread Interrupt thread User space
Kernel space
file
Interrupt handler
Hardware
/proc/irq/n/irq
間,然後把這塊記憶體空間映射到驅動程式的位址空間,讓驅動程式可以存 取,並且核心也要傳回真實的物理記憶體位址,讓驅動程式可以設定硬體時使 用。
(b) 第二類API 可以直接實作在使用者空間,存取記憶體映射 I/O (Memory-Mapping I/O)與計時器佇列(Timer queue)都屬於此分類。我們對於存取記憶體映射 I/O 與
計時器佇列模擬的方法如下:
記憶體映射 I/O (Memory-Mapping I/O):
有些裝置會映射它們的暫存器到記憶體位址空間,為了能夠去存取物理記憶體 位址,在Linux 中,/dev/mem 檔案可以提供存取物理記憶體的功能,我們可以 藉由對於/dev/mem 檔案用呼叫 mmap 的方式,把驅動程式所需要的位址區段映 射到使用者模式驅動程式的位址空間,讓驅動程式可以直接存取。
計時器佇列(Timer queue):
在核心中,計時器佇列的任務是執行一些驅動程式所設定多久之後要執行的 工作,相關函式有add_timer()-把工作加入計時器佇列中,以及 del_timer()-把 工作從計時器佇列中移除等。所以在驅動程式初始化時我們會去創造一個執行 緒去模擬計時器佇列的行為,當這個執行緒被排程到時,則會去檢查計時器佇 列中是否有需要執行的工作,如果有的話則去執行,若沒有的話則進入睡眠狀 態。
(c) 第三類為可以直接轉換成使用者空間函式庫中的函式,例如:printk()可以直接 轉換成printf()函式。
而需要提供的核心程式變數資料可能有jiffies,我們可以利用 gettimeofday()去實現。
2. Runtime Environment 並且負責接收來自 Shared Memory 中的 IO Requests,分辨是 哪一種函式類型,然後再呼叫驅動程式中處理此Request 的對應函式,例如:在驅動程 式註冊時,我們會去記錄驅動程式中提供給核心呼叫的函式,若Request 類型為 open(),
我們則可以去呼叫驅動程式中相對應的open()函式。當 IO Request 處理完畢之後,會將 此IO Request 對應的 IO Response 填入 Response Buffer 中,表示說這個 IO Request 已經 被處理完畢。