一文讀懂Linux下如何訪(fǎng)問(wèn)I/O端口和I/O內存
一、I/O端口
本文引用地址:http://dyxdggzs.com/article/201712/373670.htm端口(port)是接口電路中能被CPU直接訪(fǎng)問(wèn)的寄存器的地址。幾乎每一種外設都是通過(guò)讀寫(xiě)設備上的寄存器來(lái)進(jìn)行的。CPU通過(guò)這些地址即端口向接口電路中的寄存器發(fā)送命令,讀取狀態(tài)和傳送數據。外設寄存器也稱(chēng)為“I/O端口”,通常包括:控制寄存器、狀態(tài)寄存器和數據寄存器三大類(lèi),而且一個(gè)外設的寄存器通常被連續地編址。
二、IO內存
例如,在PC上可以插上一塊圖形卡,有2MB的存儲空間,甚至可能還帶有ROM,其中裝有可執行代碼。

三、IO端口和IO內存的區分及聯(lián)系
這兩者如何區分就涉及到硬件知識,X86體系中,具有兩個(gè)地址空間:IO空間和內存空間,而RISC指令系統的CPU(如ARM、PowerPC等)通常只實(shí)現一個(gè)物理地址空間,即內存空間。
內存空間:內存地址尋址范圍,32位操作系統內存空間為2的32次冪,即4G。
IO空間:X86特有的一個(gè)空間,與內存空間彼此獨立的地址空間,32位X86有64K的IO空間。
IO端口:當寄存器或內存位于IO空間時(shí),稱(chēng)為IO端口。一般寄存器也俗稱(chēng)I/O端口,或者說(shuō)I/O ports,這個(gè)I/O端口可以被映射在Memory Space,也可以被映射在I/O Space。
IO內存:當寄存器或內存位于內存空間時(shí),稱(chēng)為IO內存。
四、外設IO端口物理地址的編址方式
CPU對外設IO端口物理地址的編址方式有兩種:一種是I/O映射方式(I/O-mapped),另一種是內存映射方式(Memory-mapped)。而具體采用哪一種則取決于CPU的體系結構。
1、統一編址
RISC指令系統的CPU(如,PowerPC、m68k、ARM等)通常只實(shí)現一個(gè)物理地址空間(RAM)。在這種情況下,外設I/O端口的物理地址就被映射到CPU的單一物理地址空間中,而成為內存的一部分。此時(shí),CPU可以象訪(fǎng)問(wèn)一個(gè)內存單元那樣訪(fǎng)問(wèn)外設I/O端口,而不需要設立專(zhuān)門(mén)的外設I/O指令。
統一編址也稱(chēng)為“I/O內存”方式,外設寄存器位于“內存空間”(很多外設有自己的內存、緩沖區,外設的寄存器和內存統稱(chēng)“I/O空間”)。
2、獨立編址
而另外一些體系結構的CPU(典型地如X86)則為外設專(zhuān)門(mén)實(shí)現了一個(gè)單獨地地址空間,稱(chēng)為“I/O地址空間”或者“I/O端口空間”。這是一個(gè)與CPU地RAM物理地址空間不同的地址空間,所有外設的I/O端口均在這一空間中進(jìn)行編址。CPU通過(guò)設立專(zhuān)門(mén)的I/O指令(如X86的IN和OUT指令)來(lái)訪(fǎng)問(wèn)這一空間中的地址單元(也即I/O端口)。與RAM物理地址空間相比,I/O地址空間通常都比較小,如x86 CPU的I/O空間就只有64KB(0-0xffff)。這是“I/O映射方式”的一個(gè)主要缺點(diǎn)。
獨立編址也稱(chēng)為“I/O端口”方式,外設寄存器位于“I/O(地址)空間”。
3、優(yōu)缺點(diǎn)
獨立編址主要優(yōu)點(diǎn)是:
1)I/O端口地址不占用存儲器空間;使用專(zhuān)門(mén)的I/O指令對端口進(jìn)行操作,I/O指令短,執行速度快。
2)并且由于專(zhuān)門(mén)I/O指令與存儲器訪(fǎng)問(wèn)指令有明顯的區別,使程序中I/O操作和存儲器操作層次清晰,程序的可讀性強。
3)同時(shí),由于使用專(zhuān)門(mén)的I/O指令訪(fǎng)問(wèn)端口,并且I/O端口地址和存儲器地址是分開(kāi)的,故I/O端口地址和存儲器地址可以重疊,而不會(huì )相互混淆。
4)譯碼電路比較簡(jiǎn)單(因為I/0端口的地址空間一般較小,所用地址線(xiàn)也就較少)。
其缺點(diǎn)是:只能用專(zhuān)門(mén)的I/0指令,訪(fǎng)問(wèn)端口的方法不如訪(fǎng)問(wèn)存儲器的方法多。
統一編址優(yōu)點(diǎn):
1)由于對I/O設備的訪(fǎng)問(wèn)是使用訪(fǎng)問(wèn)存儲器的指令,所以指令類(lèi)型多,功能齊全,這不僅使訪(fǎng)問(wèn)I/O端口可實(shí)現輸入/輸出操作,而且還可對端口內容進(jìn)行算術(shù)邏輯運算,移位等等;
2)另外,能給端口有較大的編址空間,這對大型控制系統和數據通信系統是很有意義的。
這種方式的缺點(diǎn)是端口占用了存儲器的地址空間,使存儲器容量減小,另外指令長(cháng)度比專(zhuān)門(mén)I/O指令要長(cháng),因而執行速度較慢。
究竟采用哪一種取決于系統的總體設計。在一個(gè)系統中也可以同時(shí)使用兩種方式,前提是首先要支持I/O獨立編址。Intel的x86微處理器都支持I/O 獨立編址,因為它們的指令系統中都有I/O指令,并設置了可以區分I/O訪(fǎng)問(wèn)和存儲器訪(fǎng)問(wèn)的控制信號引腳。而一些微處理器或單片機,為了減少引腳,從而減 少芯片占用面積,不支持I/O獨立編址,只能采用存儲器統一編址。
五、Linux下訪(fǎng)問(wèn)IO端口
對于某一既定的系統,它要么是獨立編址、要么是統一編址,具體采用哪一種則取決于CPU的體系結構。 如,PowerPC、m68k等采用統一編址,而X86等則采用獨立編址,存在IO空間的概念。
目前,大多數嵌入式微控制器如ARM、PowerPC等并不提供I/O空間,僅有內存空間,可直接用地址、指針訪(fǎng)問(wèn)。但對于Linux內核而言,它可能用于不同的CPU,所以它必須都要考慮這兩種方式,于是它采用一種新的方法,將基于I/O映射方式的或內存映射方式的I/O端口通稱(chēng)為“I/O區域”(I/O region),不論你采用哪種方式,都要先申請IO區域:request_resource(),結束時(shí)釋放它:release_resource()。
IO region是一種IO資源,因此它可以用resource結構類(lèi)型來(lái)描述。
訪(fǎng)問(wèn)IO端口有2種途徑:I/O映射方式(I/O-mapped)、內存映射方式(Memory-mapped)。前一種途徑不映射到內存空間,直接使用 intb()/outb()之類(lèi)的函數來(lái)讀寫(xiě)IO端口;后一種MMIO是先把IO端口映射到IO內存(“內存空間”),再使用訪(fǎng)問(wèn)IO內存的函數來(lái)訪(fǎng)問(wèn) IO端口。
1、I/O映射方式
直接使用IO端口操作函數:在設備打開(kāi)或驅動(dòng)模塊被加載時(shí)申請IO端口區域,之后使用inb(),outb()等進(jìn)行端口訪(fǎng)問(wèn),最后在設備關(guān)閉或驅動(dòng)被卸載時(shí)釋放IO端口范圍。
in、out、ins和outs匯編語(yǔ)言指令都可以訪(fǎng)問(wèn)I/O端口。內核中包含了以下輔助函數來(lái)簡(jiǎn)化這種訪(fǎng)問(wèn):
inb( )、inw( )、inl( )
分別從I/O端口讀取1、2或4個(gè)連續字節。后綴“b”、“w”、“l(fā)”分別代表一個(gè)字節(8位)、一個(gè)字(16位)以及一個(gè)長(cháng)整型(32位)。
inb_p( )、inw_p( )、inl_p( )
分別從I/O端口讀取1、2或4個(gè)連續字節,然后執行一條“啞元(dummy,即空指令)”指令使CPU暫停。
outb( )、outw( )、outl( )
分別向一個(gè)I/O端口寫(xiě)入1、2或4個(gè)連續字節。
outb_p( )、outw_p( )、outl_p( )
分別向一個(gè)I/O端口寫(xiě)入1、2或4個(gè)連續字節,然后執行一條“啞元”指令使CPU暫停。
insb( )、insw( )、insl( )
分別從I/O端口讀入以1、2或4個(gè)字節為一組的連續字節序列。字節序列的長(cháng)度由該函數的參數給出。
outsb( )、outsw( )、outsl( )
分別向I/O端口寫(xiě)入以1、2或4個(gè)字節為一組的連續字節序列。
流程如下:

評論