ARM體系結構下面記憶體和i o對映區別

2021-08-13 07:36:27 字數 4662 閱讀 4686

arm體系結構下面記憶體和i/o對映區別

(1)關於io與記憶體空間:

在x86處理器中存在著i/o空間的概念,i/o空間是相對於記憶體空間而言的,它通過特定的指令in、out來訪問。埠號標識了外設的暫存器位址。intel語法的in、out指令格式為:

in 累加器,

out ,累加器

目前,大多數嵌入式微控制器如arm、powerpc等中並不提供i/o空間,而僅存在記憶體空間。記憶體空間可以直接通過位址、指標來訪問,程式和程式執行中使用的變數和其他資料都存在於記憶體空間中。 

即便是在x86處理器中,雖然提供了i/o空間,如果由我們自己設計電路板,外設仍然可以只掛接在記憶體空間。此時,cpu可以像訪問乙個記憶體單元那樣訪問外設i/o埠,而不需要設立專門的i/o指令。因此,記憶體空間是必須的,而i/o空間是可選的。 

(2)inb和outb:

在linux裝置驅動中,宜使用linux核心提供的函式來訪問定位於i/o空間的埠,這些函式包括:

· 讀寫位元組埠(8位寬)

unsigned inb(unsigned port); 

void outb(unsigned char byte, unsigned port); 

· 讀寫字埠(16位寬)

unsigned inw(unsigned port); 

void outw(unsigned short word, unsigned port); 

· 讀寫長字埠(32位寬)

unsigned inl(unsigned port); 

void outl(unsigned longword, unsigned port); 

· 讀寫一串位元組

void insb(unsigned port, void *addr, unsigned long count); 

void outsb(unsigned port, void *addr, unsigned long count);

· insb()從埠port開始讀count個位元組埠,並將讀取結果寫入addr指向的記憶體;outsb()將addr指向的記憶體的count個位元組連續地寫入port開始的埠。

· 讀寫一串字

void insw(unsigned port, void *addr, unsigned long count); 

void outsw(unsigned port, void *addr, unsigned long count); 

· 讀寫一串長字

void insl(unsigned port, void *addr, unsigned long count); 

void outsl(unsigned port, void *addr, unsigned long count); 

上述各函式中i/o埠號port的型別高度依賴於具體的硬體平台,因此,只是寫出了unsigned。

(3)readb和writeb:

在裝置的實體地址被對映到虛擬位址之後,儘管可以直接通過指標訪問這些位址,但是工程師宜使用linux核心的如下一組函式來完成裝置記憶體對映的虛擬位址的讀寫,這些函式包括:

· 讀i/o記憶體

unsigned int ioread8(void *addr);

unsigned int ioread16(void *addr);

unsigned int ioread32(void *addr);

與上述函式對應的較早版本的函式為(這些函式在linux 2.6中仍然被支援):

unsigned readb(address);

unsigned readw(address);

unsigned readl(address);

· 寫i/o記憶體

void iowrite8(u8 value, void *addr);

void iowrite16(u16 value, void *addr);

void iowrite32(u32 value, void *addr);

與上述函式對應的較早版本的函式為(這些函式在linux 2.6中仍然被支援):

void writeb(unsigned value, address);

void writew(unsigned value, address);

void writel(unsigned value, address);

(4)把i/o埠對映到「記憶體空間」:

void *ioport_map(unsigned long port, unsigned int count);

通過這個函式,可以把port開始的count個連續的i/o埠重對映為一段「記憶體空間」。然後就可以在其返回的位址上像訪問i/o記憶體一樣訪問這些i/o埠。當不再需要這種對映時,需要呼叫下面的函式來撤消:

void ioport_unmap(void *addr);

實際上,分析ioport_map()的源**可發現,所謂的對映到記憶體空間行為實際上是給開發人員製造的乙個「假象」,並沒有對映到核心虛擬位址,僅僅是為了讓工程師可使用統一的i/o記憶體訪問介面訪問i/o埠。

11.2.7 i/o 空間的對映

很多硬體裝置都有自己的記憶體,通常稱之為i/o空間。例如,所有比較新的圖形卡都有幾mb的ram,稱為視訊記憶體,用它來存放要在螢幕上顯示的螢幕影像。

1.位址對映

根據裝置和匯流排型別的不同,pc體系結構中的i/o空間可以在三個不同的實體地址範圍之間進行對映:

(1)對於連線到isa匯流排上的大多數裝置

i/o空間通常被對映到從0xa0000到0xfffff的實體地址範圍,這就在640k和1mb之間留出了一段空間,這就是所謂的「洞」。

(2)對於使用vesa本地匯流排(vlb)的一些老裝置

這是主要由圖形卡使用的一條專用匯流排:i/o空間被對映到從0xe00000到0xffffff的位址範圍中,也就是14mb到16mb之間。因為這些裝置使頁表的初始化更加複雜,因此已經不生產這種裝置。

(3)對於連線到pci匯流排的裝置

i/o空間被對映到很大的實體地址區間,位於ram實體地址的頂端。這種裝置的處理比較簡單。

2.訪問i/o空間

核心如何訪問乙個i/o空間單元?讓我們從pc體系結構開始入手,這個問題很容易就可以解決,之後我們再進一步討論其他體系結構。

不要忘了核心程式作用於虛擬位址,因此i/o空間單元必須表示成大於page_offset的位址。在後面的討論中,我們假設page_offset等於0xc0000000,也就是說,核心虛擬位址是在第4g。

核心驅動程式必須把i/o空間單元的實體地址轉換成核心空間的虛擬位址。在pc體系結構中,這可以簡單地把32位的實體地址和0xc0000000常量進行或運算得到。例如,假設核心需要把實體地址為0x000b0fe4的i/o單元的值存放在t1中,把實體地址為0xfc000000的i/o單元的值存放在t2中,就可以使用下面的表示式來完成這項功能:

t1 = *((unsigned char *)(0xc00b0fe4)); 

t2 = *((unsigned char *)(0xfc000000)); 

在第六章我們已經介紹過,在初始化階段,核心已經把可用的ram物理位址對映到虛擬位址空間第4g的最初部分。因此,分頁機制把出現在第乙個語句中的虛擬位址0xc00b0fe4對映回到原來的i/o實體地址0x000b0fe4,這正好落在從640k到1mb的這段「isa洞」中。這正是我們所期望的。

但是,對於第二個語句來說,這裡有乙個問題,因為其i/o實體地址超過了系統ram的最大實體地址。因此,虛擬位址0xfc000000就不需要與實體地址0xfc000000相對應。在這種情況下,為了在核心頁表中包括對這個i/o實體地址進行對映的虛擬位址,必須對頁表進行修改:這可以通過呼叫ioremap( )函式來實現。ioremap( )和vmalloc( )函式類似,都呼叫get_vm_area( ) 建立乙個新的vm_struct描述符,其描述的虛擬位址區間為所請求i/o空間區的大小。然後,ioremap( )函式適當地更新所有程序的對應頁表項。

因此,第二個語句的正確形式應該為:

io_mem = ioremap(0xfb000000, 0x200000); 

t2 = *((unsigned char *)(io_mem + 0x100000)); 

第一條語句建立乙個2mb的虛擬位址區間,從0xfb000000開始;第二條語句讀取位址0xfc000000的記憶體單元。驅動程式以後要取消這種對映,就必須使用iounmap( )函式。

現在讓我們考慮一下除pc之外的體系結構。在這種情況下,把i/o實體地址加上0xc0000000常量所得到的相應虛擬位址並不總是正確的。為了提高核心的可移植性,linux特意包含了下面這些巨集來訪問i/o空間:

readb, readw, readl 

分別從乙個i/o空間單元讀取1、2或者4個位元組

writeb, writew, writel 

分別向乙個i/o空間單元寫入1、2或者4個位元組

memcpy_fromio, memcpy_toio 

把乙個資料塊從乙個i/o空間單元拷貝到動態記憶體中,另乙個函式正好相反,把乙個資料塊從動態記憶體中拷貝到乙個i/o空間單元

memset_io 

用乙個固定的值填充乙個i/o空間區域

對於0xfc000000 i/o單元的訪問推薦使用這樣的方法:

io_mem = ioremap(0xfb000000, 0x200000); 

t2 = readb(io_mem + 0x100000); 

使用這些巨集,就可以隱藏不同平台訪問i/o空間所用方法的差異。

ARM體系結構

arm是 advanced risc machines 高階精簡指令系統處理器 的縮寫,是arm公司提供的一種微處理器智財權 ip 核 arm既可以認為是乙個公司的名字,也可以認為是對一類微處理器的通稱,還可以認為是一種技術的名字 arm微處理器的特點 1 體積小 低功耗 低成本 高效能 2 支援t...

ARM體系結構

一 arm公司簡介 arm公司成立於1990年11月,主要設計arm系列risc處理器核心 arm公司主要做授權,不生產任何一款具體的晶元。二 arm公司產業鏈 arm 將技術授權給合作廠商 廠商 生產各具特色的具體晶元,廠商就包括飛利浦 英特爾 三星等 三 arm微處理器的應用領域 工業控制 無線...

ARM體系結構

arm 核心採用精簡指令集結構 risc,reduced instruction set computer 體系結構。其目標是設計出一套能在高時鐘頻率下單週期執行 簡單而有效的指令集,risc 的設計重點在於降低硬體執行指令的複雜度,這是因為軟體比硬體容易提供更大的靈活性和更高的智慧型。與其相對的傳...