1. 程式人生 > >[現代作業系統] I/O之硬體原理

[現代作業系統] I/O之硬體原理

I/O 硬體原理

I/O 裝置

塊裝置 (block device)

把資訊儲存在固定大小的塊中, 每個塊都有自己的地址. 每個塊可以獨立於其他塊讀寫. 如 硬碟, CD-ROM , USB 盤 …

字元裝置 (character device)

字元裝置以字元為單位傳送或接收一個字元流, 而不考慮任何塊結構. 它是不可定址的.
如印表機, 網路介面, 滑鼠 (用作指點裝置)…

裝置控制器 (device controller / adapter)

I/O 裝置一般由兩部分組成: 機械部分和電子部分.
電子部分就是裝置控制器. 常以插入 (PCI) 擴充套件槽中的印刷電路板的形式出現.

控制器與裝置之間的介面是很低層次的介面. 它的任務就是把序列的位流轉換為位元組塊, 並進行必要的錯誤校正.

記憶體對映 I/O

每個控制器有幾個暫存器, OS 可以讀寫來了解, 更改裝置的狀態資訊. 控制器還有 OS 可以讀寫的 資料緩衝區.

問題來了: CPU 如何與裝置的控制暫存器和資料緩衝區通訊.

方案

  • 方法一: 每個控制暫存器被分配一個 I/O 埠 (所有埠形成埠空間, 受保護不被普通使用者訪問). 然後可以設定指令來讀寫,
    IN REG, PORT將讀取控制器暫存器 PORT 中的內容到 CPU 暫存器 REG

  • 方法二: 記憶體對映 I/O. 將所有控制暫存器對映到記憶體空間, 都被分配唯一的地址, 且這些記憶體地址不會再分配.

工作原理

CPU 讀入一個字時, 不論是從記憶體還是 I/O 埠, 都將目的地址放在匯流排的地址線上, 匯流排控制線置 READ 訊號看. 還要用一條線表明是 I/O 空間 還是記憶體空間. 如果是 I/O 空間, I/O 裝置將響應請求.

優點

  • 如果需要特殊的 I/O 指令讀寫裝置控制暫存器, 那麼訪問這些暫存器需要使用匯編程式碼, 呼叫這樣的過程需要增加開銷,
    對於 ` 記憶體對映 I/O , 裝置控制暫存器只是記憶體中的變數, 和其他變數一樣定址, 可以直 C 語言編寫驅動程式

  • 對於記憶體對映 I/O , 不需要特殊的保護機制來阻止使用者程序執行 I/O 操作. 作業系統只需注意不要將記憶體對映的地址對映到使用者虛擬地址空間. 更有利的是, 如果有多個裝置, 可以將記憶體對映 I/O 對映到不同的頁, 可以分配特定的頁給使用者, 使其使用驅動程式, 而且不擔心各驅動程式之間的影響

缺點

  • 不能對裝置控制器的暫存器進行 cache, 因為裝置的狀態改變, 軟體將沒有辦法發現. 所以硬體必須對每個頁面具備選擇性的禁用 chche. 增加了複雜性

  • 在記憶體對映機器上, 具有單獨的記憶體匯流排會使 I/O 裝置沒有辦法檢視記憶體地址, 因為記憶體地址旁路到記憶體總線上, 沒有辦法響應.

DMA(直接儲存器存取, Direct Memory Access)

獨立於 CPU 訪問系統匯流排

工作原理

也就是不用浪費 CPU 處理緩衝區到記憶體的時間, 相當於另有一個” CPU ” 專門處理 磁碟 到 記憶體 的 I/O

對 CPU 的延遲

週期竊取 (Cycle Stealing)

注意 上面的操作是字模式傳送, 在 DMA 請求傳送一個字並且得到這個字時, CPU 不能使用匯流排, 必須等待.

突發模式 (burst mode)

上面是字傳輸模式, 對於塊模式下的傳送, DMA 會發起一連串的傳送, 然後才釋放匯流排. 這比周期竊取效率更高.

上面 的模式是飛越模式(fly-by mode), 即 DMA 控制器直接通知裝置控制器將資料傳送到 主存, 只請求一次匯流排

某些 DMA 使用其他模式. 讓裝置控制器將字傳送到 DMA, 然後 DMA 再 請求匯流排將資料傳送到其他地方 (其他裝置, 主存…), 這樣會多消耗一個匯流排週期, 但是更加靈活: 可以 裝置->裝置, 記憶體->記憶體(記憶體讀, 然後 記憶體寫)

不使用 DMA 的考慮:
* CPU 比 DMA 快得多, 當限制因素不是 I/O 裝置的讀寫速度時, 沒必要使用 DMA
* 去除 DMA 而用 CPU 使用軟體做所有工作可以節省硬體的開銷

中斷

當一個 I/O 裝置完成 jcgz 它的工作後, 它就產生一箇中斷, 通過在分配給它的一條匯流排訊號線上置起訊號.
中斷

如果有多箇中斷請求, 按優先順序, 如果還沒有被處理, 裝置一直髮出中斷知道得到 CPU 服務

中斷控制器通過在地址先上放置一個數字(中斷向量 interrupt vector)表明哪個裝置需要關注, 同時向 CPU 發出中斷

中斷訊號導致 CPU 停止當前工作, 並處理其他事情. 根據中斷向量跳轉到需要的中斷服務程式

問題

開始中斷服務之前, 硬體需要儲存資訊

哪些訊號需要儲存?

至少程式計數器, 至多可見的暫存器, 一些內部暫存器…

儲存在哪裡?

  • 如果放在內部暫存器, 那麼中斷控制器之後無法得到應答, 知道所有可能的相關資訊被讀出, 以免第二個中斷重寫內部暫存器儲存狀態. 這樣在中斷被禁止時將導致長時間的宕機, 並可能丟失中斷和資料
  • 如果在堆疊中, 使用誰的堆疊?
    • 如果使用當前堆疊, 可能是使用者程序的, 堆疊指標可能是不合法的.
    • 可能指向一個頁面的末端, 若干次記憶體寫之後, 可能超出頁面發生頁面故障. 那麼在何處儲存狀態以處理頁面故障?
    • 如果用核心堆疊. 切換到和心態可能要求改變 MMU 上下文, 並且可能使 cache 和 TLB 的大部分失效. 靜態地或動態地重新狀態所有東西將增加處理一箇中斷的時間, 因而浪費 CPU 的時間

誰來儲存?

對誰可見就誰來儲存

考慮流水線, 超標量 (內部並行)

在流水線滿的時候, 如果出現一箇中斷, 由於許多指令處於不同的正在執行的截斷. 程式計數器可能無法正確反應已經執行的指令和未執行之間的邊界.
在超標量機器上, 指令可能分解成微操作, 為操作可能亂序執行
* 精確中斷 (precise interrupt): 將機器留在一個明確狀態

  • 不精確中斷 (imprecise interrupt)
    不滿足上面的條件