每種外設都通過讀寫暫存器進行控制,大部分外設都有幾個暫存器,不管在記憶體位址空間還是在i/o位址空間,這些暫存器的訪問位址是連續的。和裝置通訊的另一種主要機制是通過使用對映到記憶體的暫存器或裝置記憶體。這兩種都稱為io記憶體,因為暫存器和記憶體的區別對軟體是透明的。在硬體層,記憶體區域和io區域沒有概念上的區別:他們都通過向位址匯流排和控制匯流排傳送電平訊號進行訪問,再通過資料匯流排讀寫資料。
儘管硬體暫存器和記憶體非常相似,但程式設計師在訪問io暫存器的時候必須注意避免由於cpu或編譯器不恰當地優化而改變預期的io動作。
io暫存器和ram的主要是區別是io操作具有***,而記憶體操作沒有:記憶體寫操作的唯一結果是在指定位置儲存乙個值;記憶體讀操作則僅僅返回指定位置最後一次寫入的數值,
編譯器能夠將資料快取在io暫存器中而不寫入記憶體,即使儲存資料,讀寫操作也都能在快取記憶體中進行而不訪問物理ram。無論在編譯器一級還是硬體一級,指令的重新排序都有可能發生:乙個指令序列如果以不同於程式文字的序列執行往往能執行的更快。
處理器無法預料某些其他程序是否會依賴於記憶體訪問的順序。編譯器或cpu可能會自作聰明地重新排序所要求的操作,結果會發生奇怪的錯誤,並且很難除錯。因此,驅動程式必須確保不使用快取記憶體,並且在訪問暫存器時不發生讀或寫指令的重新排序。
由硬體自身快取引起的問題很好解決:只要把底層硬體設定成在訪問io區域時(不管是記憶體還是埠)時禁止硬體快取即可。
由編譯器或硬體重新排序引起的問題的解決辦法是:對硬體必須以特定順序執行的操作之間設定記憶體屏障。linux提供以下函式。
#include
void barrier(void *)
在尚未取得對這些埠的獨佔訪問之前,我們不應該對這些埠進行操作,核心為我們提供了乙個註冊用的介面,它允許驅動程式宣告自己需要操作的埠。該介面的核心函式是request_region:
#include struct resource *request_region(unsigned long first , unsigned long n, const char *name)
這個函式告訴核心,我們要使用起始於first的n個埠,引數name是裝置的名字,如果分配不成功,則返回null值。
如果我們不再使用某組io埠,則應該使用下面的函式將這麼埠返回給系統。
void release_region(unsigned long start ,unsigned long n)
當驅動程式請求了需要使用的io埠範圍後,必須讀取或寫入這麼埠。為此,大多數硬體會把8位、16位和32位的埠區分開。linux核心標頭檔案中()定義了如下一些訪問io埠的內聯函式。
unsigned inb(unsigned port)
void outb(unsigned char byte, unsigned port)
位元組(8位)讀寫埠。16位為short,32位為longword。
以上的io操作都是一次傳輸乙個資料,作為補充,有些處理器實現了一次傳輸乙個資料序列的特殊指令,序列中的資料單位可以是位元組、字或雙字。這些指令稱為串操作指令。
在使用之前,必須首先分配io記憶體區域,用於分配記憶體區域的介面如下所示:
#include struct resource *request_mem_region(unsigned long start , unsigned long len.char *name)
該函式從start開始分配len位元組長的記憶體區域,如果失敗,返回null。
當不再使用已分配的記憶體區域時,使用下面的介面釋放:
void release_mem_region(unsigned long start ,unsigned long len)
分配記憶體並不是訪問這些記憶體之前的唯一步驟,我們還必須確保該io記憶體核心是可訪問的。獲取io記憶體並不僅僅意味著可引用相應的指標,在許多系統上,io記憶體根本不能通過這樣的方式;在很多系統中,io記憶體不能通過這樣的方式直接訪問。因此,我們首先必須得建立對映,對映的建立由ioremap()函式完成。
#include void *ioremap(unsigned long phys_addr,unsigned long size)
在某些平台上,我們可以將ioremap()返回的值直接當作指標引用。但是這種不具有可移植性。訪問io記憶體的正確方法是通過一組專用於此目的的函式。
以8位為例,16、32位都是一樣的
unsigned ioread8(void *addr);
其中addr是ioremap()的返回值;返回值則是從給定io記憶體讀取到的值
void iowrite8(u8 value, void *addr);
void iowrite8_rep(void *addr, void *buf, unsigned long count);
從給定的buf向給定的addr讀取或寫入count個值
I O埠與I O記憶體
埠的概念 裝置通過系統匯流排上的介面與cpu相連,介面電路中含有多種暫存器,cpu向裝置讀寫資料實際上是向介面上的暫存器讀寫資料,這些暫存器稱為i o埠。乙個介面通常包含控制埠,資料埠,狀態埠。對於x86平台,實體地址就是匯流排位址。linux中,程序中的4gb虛擬記憶體分為使用者空間和核心空間,使...
裝置I O 埠和I O 記憶體的訪問
幾乎每一種外設都是通過讀寫裝置上的暫存器來進行的,通常包括控制暫存器 狀態暫存器和資料暫存器三大類,外設的暫存器通常被連續地編址。根據cpu體系結構的不同,cpu對io埠的編址方式有兩種 典型地,如x86處理器為外設專門實現了乙個單獨的位址空間,稱為 i o位址空間 或者 i o埠空間 cpu通過專...
IO埠 IO記憶體 IO空間 記憶體空間的含義和聯絡
1,io空間 x86乙個特有的空間,與記憶體空間獨立的空間,同樣利用io空間可以運算元據,只不過是利用對應的io埠操作函式,例如inb inbw inl outb outw outl 等。2,記憶體空間 記憶體位址的定址範圍,例如32位作業系統記憶體空間為2的32次冪,即4g。3,io埠 當外部暫存...