Direct Memory Access (DMA)

Motivation

想像 CPU 要從磁碟讀一大塊資料。如果用傳統方式——programmed I/O (PIO)——CPU 必須親自盯著 status bit,等裝置準備好,然後一個 byte 一個 byte 把資料塞進 controller register。這對一顆昂貴的通用處理器來說是在浪費生命:整個過程 CPU 都在做搬運工的事,根本沒辦法處理其他運算

於是我們引入 DMA controller 接手這件事

Process

  1. CPU 告訴 device controller「去讀什麼」(寫 command register)
  2. CPU 設定好 DMA command block(source、destination、byte count)
  3. CPU 把 DMA command block 的位址告訴 DMA controller,然後離開去做別的事
  4. Device controller 開始執行命令,準備好一個 word 後,在 DMA-request 線上發訊號
  5. DMA controller 收到後搶佔 memory bus,把目標位址放上 memory-address 線,然後在 DMA-acknowledge 線上回應
  6. Device controller 收到 acknowledge 後,把那個 word 的資料寫入記憶體,然後撤掉 DMA-request 訊號
  7. DMA controller 看到 request 被撤掉,也放掉 acknowledge,bus 控制權釋放
  8. 步驟 4–7 重複,直到 byte count 歸零(所有資料搬完)
  9. DMA controller 發 interrupt 通知 CPU:「I/O request 完成了」
  10. CPU 收到 interrupt,去處理搬進來的資料

Scatter-Gather

Command block 可以不只描述一次連續搬移,而是列出一串 source/destination 位址對,讓 DMA controller 一口氣完成多段不連續的搬移

CPU 仍需要在每次搬移自行寫入 Device controller 的 Device registers

Problem

1. Double Buffering

DMA 的目標位址最好放在 kernel address space,原因是因為如果放在 user space,user process 可以在搬移過程中修改那塊記憶體,資料就會損毀

但資料在 kernel memory 裡,user thread 要存取時就得再做一次從 kernel memory 到 user memory 的 copy——這個額外的複製叫 double buffering,很沒效率。現代作業系統傾向直接用 lock 把那塊鎖起來並且在搬移完成後再 unlock

2. Cycle Stealing

DMA controller 使用 memory bus 的時候,CPU 就暫時被排除在外,沒辦法存取 main memory(雖然它還能用 cache 裡的資料繼續跑)。這叫做 cycle stealing——DMA 偷走了幾個 bus cycle

但這還是很划算因為使用 DMA 可以讓 CPU 可以真正專注在計算上