輸入輸出系統與裝置管理

記憶體映射輸入輸出(memory-mapped I/O)

假設你不再給每台辦公室機器在另一面牆上一個特殊信箱,而是乾脆從普通檔案櫃裡撥出幾個抽屜給它們。「5000 號抽屜是影印機的命令格;寫進去,影印機就會運轉。」現在你用操作任何抽屜時一模一樣的動作來操作這台機器。記憶體映射輸入輸出正是這麼做:把裝置控制器的暫存器接線成看起來像普通記憶體位址,於是 CPU 用單純的載入與儲存指令就能控制裝置。

具體來說,位址空間中某些範圍被劃出來,不通往 RAM,而是導向裝置控制器。例如,寫入位址 0xB8000 可能會在文字螢幕上放一個字元;讀取某個位址可能會傳回一張網路卡的狀態。當 CPU 對這樣的位址執行一個普通的儲存指令時,匯流排硬體會辨識出這個範圍,把存取轉向控制器而非記憶體。好處是完整、豐富的指令集都能用在裝置上——你能讀、能寫、甚至做複合運算——完全不需要特殊的 IN/OUT 指令,而驅動程式碼看起來就像普通的指標程式碼。壞處是那些位址是從記憶體映射裡被偷走的,而且必須告訴編譯器不要把這類存取最佳化掉(在 C 裡,那個暫存器指標被標記為 volatile),因為連續讀同一個狀態位址兩次,正當地可能得到兩個不同的答案。

為什麼重要:記憶體映射輸入輸出是現代硬體上的主流方案,在 ARM 之類的架構上更是唯一方案,也是讓高頻寬裝置可行的關鍵——顯示卡的影格緩衝區(framebuffer)就只是一大塊被映射的記憶體,CPU(或 GPU)往裡面寫像素。作業系統必須只把這些裝置區域映射進核心的位址空間,絕不能粗心地映射進使用者程式,否則任何行程都能直接驅動硬體、繞過所有保護。

在經典的 PC 文字螢幕上,從記憶體位址 0xB8000 開始的那些位元組就是螢幕本身。把字元 'A' 的代碼存進那裡,左上角就會出現一個 A——不需要任何特殊的輸入輸出指令,只是一次普通的寫入。

裝置的暫存器就住在記憶體位址空間裡,用普通的載入/儲存來驅動。

被記憶體映射的暫存器不是 RAM:它有副作用、也可能自行改變,所以它的讀寫不能像普通記憶體那樣被重排或快取——這正是要標記 volatile、並在驅動程式中特別小心的原因。

又称
MMIO記憶體對映輸入輸出