欧美性猛交xxxx免费看_牛牛在线视频国产免费_天堂草原电视剧在线观看免费_国产粉嫩高清在线观看_国产欧美日本亚洲精品一5区

0
  • 聊天消息
  • 系統(tǒng)消息
  • 評(píng)論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫(xiě)文章/發(fā)帖/加入社區(qū)
會(huì)員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識(shí)你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

什么是cpu的io端口?地址空間如何共享?

h1654155971.7688 ? 來(lái)源:互聯(lián)網(wǎng) ? 作者:佚名 ? 2017-11-15 15:13 ? 次閱讀

(一)地址的概念

1)物理地址:CPU地址總線傳來(lái)的地址,由硬件電路控制其具體含義。物理地址中很大一部分是留給內(nèi)存條中的內(nèi)存的,但也常被映射到其他存儲(chǔ)器上(如顯存、BIOS等)。在程序指令中的虛擬地址經(jīng)過(guò)段映射和頁(yè)面映射后,就生成了物理地址,這個(gè)物理地址被放到CPU的地址線上。

物理地址空間,一部分給物理RAM(內(nèi)存)用,一部分給總線用,這是由硬件設(shè)計(jì)來(lái)決定的,因此在32bits地址線的x86處理器中,物理地址空間是2的32次方,即4GB,但物理RAM一般不能上到4GB,因?yàn)檫€有一部分要給總線用(總線上還掛著別的許多設(shè)備)。在PC機(jī)中,一般是把低端物理地址給RAM用,高端物理地址給總線用。

2)總線地址:總線的地址線或在地址周期上產(chǎn)生的信號(hào)。外設(shè)使用的是總線地址,CPU使用的是物理地址。

物理地址與總線地址之間的關(guān)系由系統(tǒng)的設(shè)計(jì)決定的。在x86平臺(tái)上,物理地址就是總線地址,這是因?yàn)樗鼈児蚕硐嗤牡刂房臻g——這句話有點(diǎn)難理解,詳見(jiàn)下面的“獨(dú)立編址”。在其他平臺(tái)上,可能需要轉(zhuǎn)換/映射。比如:CPU需要訪問(wèn)物理地址是0xfa000的單元,那么在x86平臺(tái)上,會(huì)產(chǎn)生一個(gè)PCI總線上對(duì)0xfa000地址的訪問(wèn)。因?yàn)槲锢淼刂泛涂偩€地址相同。

3)虛擬地址:現(xiàn)代操作系統(tǒng)普遍采用虛擬內(nèi)存管理(VirtualMemory Management)機(jī)制,這需要MMU(MemoryManagement Unit)的支持。MMU通常是CPU的一部分,如果處理器沒(méi)有MMU,或者有MMU但沒(méi)有啟用,CPU執(zhí)行單元發(fā)出的內(nèi)存地址將直接傳到芯片引腳上,被內(nèi)存芯片(物理內(nèi)存)接收,這稱(chēng)為物理地址(Physical Address),如果處理器啟用了MMU,CPU執(zhí)行單元發(fā)出的內(nèi)存地址將被MMU截獲,從CPU到MMU的地址稱(chēng)為虛擬地址(Virtual Address),而MMU將這個(gè)地址翻譯成另一個(gè)地址發(fā)到CPU芯片的外部地址引腳上,也就是將虛擬地址映射成物理地址。

Linux中,進(jìn)程的4GB(虛擬)內(nèi)存分為用戶空間、內(nèi)核空間。用戶空間分布為0~3GB(即PAGE_OFFSET,在0X86中它等于0xC0000000),剩下的1G為內(nèi)核空間。程序員只能使用虛擬地址。系統(tǒng)中每個(gè)進(jìn)程有各自的私有用戶空間(0~3G),這個(gè)空間對(duì)系統(tǒng)中的其他進(jìn)程是不可見(jiàn)的。

CPU發(fā)出取指令請(qǐng)求時(shí)的地址是當(dāng)前上下文的虛擬地址,MMU再?gòu)捻?yè)表中找到這個(gè)虛擬地址的物理地址,完成取指。同樣讀取數(shù)據(jù)的也是虛擬地址,比如mov ax, var. 編譯時(shí)var就是一個(gè)虛擬地址,也是通過(guò)MMU從也表中來(lái)找到物理地址,再產(chǎn)生總線時(shí)序,完成取數(shù)據(jù)的。

(二)編址方式

1)對(duì)外設(shè)的編址

外設(shè)都是通過(guò)讀寫(xiě)設(shè)備上的寄存器來(lái)進(jìn)行的,外設(shè)寄存器也稱(chēng)為“I/O端口”,而IO端口有兩種編址方式:獨(dú)立編址和統(tǒng)一編制。

統(tǒng)一編址:外設(shè)接口中的IO寄存器(即IO端口)與主存單元一樣看待,每個(gè)端口占用一個(gè)存儲(chǔ)單元的地址,將主存的一部分劃出來(lái)用作IO地址空間,如,在 PDP-11中,把最高的4K主存作為IO設(shè)備寄存器地址。端口占用了存儲(chǔ)器的地址空間,使存儲(chǔ)量容量減小。

統(tǒng)一編址也稱(chēng)為“I/O內(nèi)存”方式,外設(shè)寄存器位于“內(nèi)存空間”(很多外設(shè)有自己的內(nèi)存、緩沖區(qū),外設(shè)的寄存器和內(nèi)存統(tǒng)稱(chēng)“I/O空間”)。

如,Samsung的S3C2440,是32位ARM處理器,它的4GB地址空間被外設(shè)、RAM等瓜分:

0x8000 1000 LED 8*8點(diǎn)陣的地址0x4800 0000 ~ 0x6000 0000 SFR(特殊暫存器)地址空間0x3800 1002 鍵盤(pán)地址0x3000 0000 ~ 0x3400 0000 SDRAM空間0x2000 0020 ~ 0x2000 002e IDE0x1900 0300 CS8900

獨(dú)立編址(單獨(dú)編址):IO地址與存儲(chǔ)地址分開(kāi)獨(dú)立編址,I/0端口地址不占用存儲(chǔ)空間的地址范圍,這樣,在系統(tǒng)中就存在了另一種與存儲(chǔ)地址無(wú)關(guān)的IO地址,CPU也必須具有專(zhuān)用與輸入輸出操作的IO指令(IN、OUT等)和控制邏輯。獨(dú)立編址下,地址總線上過(guò)來(lái)一個(gè)地址,設(shè)備不知道是給IO端口的、還是給存儲(chǔ)器的,于是處理器通過(guò)MEMR/MEMW和IOR/IOW兩組控制信號(hào)來(lái)實(shí)現(xiàn)對(duì)I/O端口和存儲(chǔ)器的不同尋址。如,intel80x86就采用單獨(dú)編址,CPU內(nèi)存和I/O是一起編址的,就是說(shuō)內(nèi)存一部分的地址和I/O地址是重疊的。

獨(dú)立編址也稱(chēng)為“I/O端口”方式,外設(shè)寄存器位于“I/O(地址)空間”。

對(duì)于x86架構(gòu)來(lái)說(shuō),通過(guò)IN/OUT指令訪問(wèn)。PC架構(gòu)一共有65536個(gè)8bit的I/O端口,組成64K個(gè)I/O地址空間,編號(hào)從0~0xFFFF,有16位,80x86用低16位地址線A0-A15來(lái)尋址。連續(xù)兩個(gè)8bit的端口可以組成一個(gè)16bit的端口,連續(xù)4個(gè)組成一個(gè) 32bit的端口。I/O地址空間和CPU的物理地址空間是兩個(gè)不同的概念,例如I/O地址空間為64K,一個(gè)32bit的CPU物理地址空間是4G。如,在Intel 8086+Redhat9.0 下用“more/proc/ioports”可看到:

0000-001f : dma10020-003f : pic10040-005f : timer0060-006f : keyboard0070-007f : rtc0080-008f : dma page reg00a0-00bf : pic200c0-00df : dma200f0-00ff : fpu0170-0177 : ide1……

不過(guò)Intelx86平臺(tái)普通使用了名為內(nèi)存映射(MMIO)的技術(shù),該技術(shù)是PCI規(guī)范的一部分,IO設(shè)備端口被映射到內(nèi)存空間,映射后,CPU訪問(wèn)IO端口就如同訪問(wèn)內(nèi)存一樣??碔ntelTA 719文檔給出的x86/x64系統(tǒng)典型內(nèi)存地址分配表:

系統(tǒng)資源 占用

BIOS 1M本地APIC4K芯片組保留 2MIO APIC 4KPCI設(shè)備256MPCI Express設(shè)備256MPCI設(shè)備(可選) 256M顯示幀緩存 16MTSEG 1M

對(duì)于某一既定的系統(tǒng),它要么是獨(dú)立編址、要么是統(tǒng)一編址,具體采用哪一種則取決于CPU的體系結(jié)構(gòu)。如,PowerPC、m68k等采用統(tǒng)一編址,而X86等則采用獨(dú)立編址,存在IO空間的概念。目前,大多數(shù)嵌入式微控制器如ARM、PowerPC等并不提供I/O空間,僅有內(nèi)存空間,可直接用地址、指針訪問(wèn)。但對(duì)于Linux內(nèi)核而言,它可能用于不同的CPU,所以它必須都要考慮這兩種方式,于是它采用一種新的方法,將基于I/O映射方式的或內(nèi)存映射方式的I/O端口通稱(chēng)為“I/O區(qū)域”(I/O region),不論你采用哪種方式,都要先申請(qǐng)IO區(qū)域:request_resource(),結(jié)束時(shí)釋放它:release_resource()。

(三)不同體系結(jié)構(gòu)編址方式總結(jié)

幾乎每一種外設(shè)都是通過(guò)讀寫(xiě)設(shè)備上的寄存器來(lái)進(jìn)行的。外設(shè)寄存器也稱(chēng)為“I/O端口”,通常包括:控制寄存器、狀態(tài)寄存器和數(shù)據(jù)寄存器三大類(lèi),而且一個(gè)外設(shè)的寄存器通常被連續(xù)地編址。CPU對(duì)外設(shè)IO端口物理地址的編址方式有兩種:一種是I/O映射方式(I/O-mapped),另一種是內(nèi)存映射方式(Memory-mapped)。而具體采用哪一種則取決于CPU的體系結(jié)構(gòu)。

有些體系結(jié)構(gòu)的CPU(如,PowerPC、m68k等)通常只實(shí)現(xiàn)一個(gè)物理地址空間(RAM)。在這種情況下,外設(shè)I/O端口的物理地址就被映射到CPU的單一物理地址空間中,而成為內(nèi)存的一部分。此時(shí),CPU可以象訪問(wèn)一個(gè)內(nèi)存單元那樣訪問(wèn)外設(shè)I/O端口,而不需要設(shè)立專(zhuān)門(mén)的外設(shè)I/O指令。這就是所謂的“內(nèi)存映射方式”(Memory-mapped)。

而另外一些體系結(jié)構(gòu)的CPU(典型地如X86)則為外設(shè)專(zhuān)門(mén)實(shí)現(xiàn)了一個(gè)單獨(dú)地地址空間,稱(chēng)為“I/O地址空間”或者“I/O端口空間”。這是一個(gè)與CPU地RAM物理地址空間不同的地址空間,所有外設(shè)的I/O端口均在這一空間中進(jìn)行編址。CPU通過(guò)設(shè)立專(zhuān)門(mén)的I/O指令(如X86的IN和OUT指令)來(lái)訪問(wèn)這一空間中的地址單元(也即I/O端口)。這就是所謂的“I/O映射方式”(I/O-mapped)。與RAM物理地址空間相比,I/O地址空間通常都比較小,如x86 CPU的I/O空間就只有64KB(0-0xffff)。這是“I/O映射方式”的一個(gè)主要缺點(diǎn)。

Linux將基于I/O映射方式的或內(nèi)存映射方式的I/O端口通稱(chēng)為“I/O區(qū)域”(I/Oregion)。在討論對(duì)I/O區(qū)域的管理之前,我們首先來(lái)分析一下Linux是如何實(shí)現(xiàn)“I/O資源”這一抽象概念的.

(四)IO端口與IO內(nèi)存區(qū)別

在驅(qū)動(dòng)程序編寫(xiě)過(guò)程中,很少會(huì)注意到IO Port和IO Mem的區(qū)別。雖然使用一些不符合規(guī)范的代碼可以達(dá)到最終目的,這是極其不推薦使用的。

結(jié)合下圖,我們徹底講述IO端口和IO內(nèi)存以及內(nèi)存之間的關(guān)系。主存16M字節(jié)的SDRAM,外設(shè)是個(gè)視頻采集卡,上面有16M字節(jié)的SDRAM作為緩沖區(qū)。

1. CPU是i386架構(gòu)的情況

在i386系列的處理中,內(nèi)存和外部IO是獨(dú)立編址,也是獨(dú)立尋址的。MEM的內(nèi)存空間是32位可以尋址到4G,IO空間是16位可以尋址到64K。

在Linux內(nèi)核中,訪問(wèn)外設(shè)上的IO Port必須通過(guò)IO Port的尋址方式。而訪問(wèn)IO Mem就比較羅嗦,外部MEM不能和主存一樣訪問(wèn),雖然大小上不相上下,可是外部MEM是沒(méi)有在系統(tǒng)中注冊(cè)的。訪問(wèn)外部IO MEM必須通過(guò)remap映射到內(nèi)核的MEM空間后才能訪問(wèn)。

為了達(dá)到接口的同一性,內(nèi)核提供了IO Port到IO Mem的映射函數(shù)。映射后IO Port就可以看作是IO Mem,按照IO Mem的訪問(wèn)方式即可。

2. CPU是ARM或PPC架構(gòu)的情況

在這一類(lèi)的嵌入式處理器中,IO Port的尋址方式是采用內(nèi)存映射,也就是IO bus就是Mem bus。系統(tǒng)的尋址能力如果是32位,IO Port+Mem(包括IO Mem)可以達(dá)到4G

訪問(wèn)這類(lèi)IO Port時(shí),我們也可以用IO Port專(zhuān)用尋址方式。至于在對(duì)IO Port尋址時(shí),內(nèi)核是具體如何完成的,這個(gè)在內(nèi)核移植時(shí)就已經(jīng)完成。在這種架構(gòu)的處理器中,仍然保持對(duì)IO Port的支持,完全是i386架構(gòu)遺留下來(lái)的問(wèn)題,在此不多討論。而訪問(wèn)IO Mem的方式和i386一致。

3、IO端口和IO內(nèi)存的區(qū)分及聯(lián)系

這兩者如何區(qū)分就涉及到硬件知識(shí),X86體系中,具有兩個(gè)地址空間:IO空間和內(nèi)存空間,而RISC指令系統(tǒng)的CPU(如ARM、PowerPC等)通常只實(shí)現(xiàn)一個(gè)物理地址空間,即內(nèi)存空間。

內(nèi)存空間:內(nèi)存地址尋址范圍,32位操作系統(tǒng)內(nèi)存空間為2的32次冪,即4G。

IO空間:X86特有的一個(gè)空間,與內(nèi)存空間彼此獨(dú)立的地址空間,32位X86有64K的IO空間。

IO端口:當(dāng)寄存器或內(nèi)存位于IO空間時(shí),稱(chēng)為IO端口。一般寄存器也俗稱(chēng)I/O端口,或者說(shuō)I/Oports,這個(gè)I/O端口可以被映射在MemorySpace,也可以被映射在I/OSpace。

IO內(nèi)存:當(dāng)寄存器或內(nèi)存位于內(nèi)存空間時(shí),稱(chēng)為IO內(nèi)存。

(五)在Linux下對(duì)IO端口與IO內(nèi)存訪問(wèn)方式總結(jié)

1)在Linux下訪問(wèn)IO端口

對(duì)于某一既定的系統(tǒng),它要么是獨(dú)立編址、要么是統(tǒng)一編址,具體采用哪一種則取決于CPU的體系結(jié)構(gòu)。如,PowerPC、m68k等采用統(tǒng)一編址,而X86等則采用獨(dú)立編址,存在IO空間的概念。目前,大多數(shù)嵌入式微控制器如ARM、PowerPC等并不提供I/O空間,僅有內(nèi)存空間,可直接用地址、指針訪問(wèn)。但對(duì)于Linux內(nèi)核而言,它可能用于不同的CPU,所以它必須都要考慮這兩種方式,于是它采用一種新的方法,將基于I/O映射方式的或內(nèi)存映射方式的I/O端口通稱(chēng)為“I/O區(qū)域”(I/O region),不論你采用哪種方式,都要先申請(qǐng)IO區(qū)域:request_resource(),結(jié)束時(shí)釋放它:release_resource()。

IO region是一種IO資源,因此它可以用resource結(jié)構(gòu)類(lèi)型來(lái)描述。

訪問(wèn)IO端口有2種途徑:I/O映射方式(I/O-mapped)、內(nèi)存映射方式(Memory-mapped)。前一種途徑不映射到內(nèi)存空間,直接使用 intb()/outb()之類(lèi)的函數(shù)來(lái)讀寫(xiě)IO端口;后一種MMIO是先把IO端口映射到IO內(nèi)存(“內(nèi)存空間”),再使用訪問(wèn)IO內(nèi)存的函數(shù)來(lái)訪問(wèn) IO端口。

1、I/O映射方式

直接使用IO端口操作函數(shù):在設(shè)備打開(kāi)或驅(qū)動(dòng)模塊被加載時(shí)申請(qǐng)IO端口區(qū)域,之后使用inb(),outb()等進(jìn)行端口訪問(wèn),最后在設(shè)備關(guān)閉或驅(qū)動(dòng)被卸載時(shí)釋放IO端口范圍。

in、out、ins和outs匯編語(yǔ)言指令都可以訪問(wèn)I/O端口。內(nèi)核中包含了以下輔助函數(shù)來(lái)簡(jiǎn)化這種訪問(wèn):

inb( )、inw( )、inl( )分別從I/O端口讀取1、2或4個(gè)連續(xù)字節(jié)。后綴“b”、“w”、“l(fā)”分別代表一個(gè)字節(jié)(8位)、一個(gè)字(16位)以及一個(gè)長(zhǎng)整型(32位)。

inb_p( )、inw_p( )、inl_p( )

分別從I/O端口讀取1、2或4個(gè)連續(xù)字節(jié),然后執(zhí)行一條“啞元(dummy,即空指令)”指令使CPU暫停。

outb( )、outw( )、outl( )

分別向一個(gè)I/O端口寫(xiě)入1、2或4個(gè)連續(xù)字節(jié)。

outb_p( )、outw_p( )、outl_p( )

分別向一個(gè)I/O端口寫(xiě)入1、2或4個(gè)連續(xù)字節(jié),然后執(zhí)行一條“啞元”指令使CPU暫停。

insb( )、insw( )、insl( )

分別從I/O端口讀入以1、2或4個(gè)字節(jié)為一組的連續(xù)字節(jié)序列。字節(jié)序列的長(zhǎng)度由該函數(shù)的參數(shù)給出。

outsb( )、outsw( )、outsl( )分別向I/O端口寫(xiě)入以1、2或4個(gè)字節(jié)為一組的連續(xù)字節(jié)序列。

流程如下:

雖然訪問(wèn)I/O端口非常簡(jiǎn)單,但是檢測(cè)哪些I/O端口已經(jīng)分配給I/O設(shè)備可能就不這么簡(jiǎn)單了,對(duì)基于ISA總線的系統(tǒng)來(lái)說(shuō)更是如此。通常,I/O設(shè)備驅(qū)動(dòng)程序?yàn)榱颂綔y(cè)硬件設(shè)備,需要盲目地向某一I/O端口寫(xiě)入數(shù)據(jù);但是,如果其他硬件設(shè)備已經(jīng)使用這個(gè)端口,那么系統(tǒng)就會(huì)崩潰。為了防止這種情況的發(fā)生,內(nèi)核必須使用“資源”來(lái)記錄分配給每個(gè)硬件設(shè)備的I/O端口。資源表示某個(gè)實(shí)體的一部分,這部分被互斥地分配給設(shè)備驅(qū)動(dòng)程序。在這里,資源表示I/O端口地址的一個(gè)范圍。每個(gè)資源對(duì)應(yīng)的信息存放在resource數(shù)據(jù)結(jié)構(gòu)中:

1.structresource{

2.resource_size_tstart;//資源范圍的開(kāi)始

3.resource_size_tend;//資源范圍的結(jié)束

4.constchar*name;//資源擁有者的名字

5.unsignedlongflags;//各種標(biāo)志

6.structresource*parent,*sibling,*child;//指向資源樹(shù)中父親,兄弟和孩子的指針

7.};

所有的同種資源都插入到一個(gè)樹(shù)型數(shù)據(jù)結(jié)構(gòu)(父親、兄弟和孩子)中;例如,表示I/O端口地址范圍的所有資源都包括在一個(gè)根節(jié)點(diǎn)為ioport_resource的樹(shù)中。節(jié)點(diǎn)的孩子被收集在一個(gè)鏈表中,其第一個(gè)元素由child指向。sibling字段指向鏈表中的下一個(gè)節(jié)點(diǎn)。

為什么使用樹(shù)?例如,考慮一下IDE硬盤(pán)接口所使用的I/O端口地址-比如說(shuō)從0xf000到 0xf00f。那么,start字段為0xf000且end 字段為0xf00f的這樣一個(gè)資源包含在樹(shù)中,控制器的常規(guī)名字存放在name字段中。但是,IDE設(shè)備驅(qū)動(dòng)程序需要記住另外的信息,也就是IDE鏈主盤(pán)使用0xf000到0xf007的子范圍,從盤(pán)使用0xf008到0xf00f的子范圍。為了做到這點(diǎn),設(shè)備驅(qū)動(dòng)程序把兩個(gè)子范圍對(duì)應(yīng)的孩子插入到從0xf000到0xf00f的整個(gè)范圍對(duì)應(yīng)的資源下。一般來(lái)說(shuō),樹(shù)中的每個(gè)節(jié)點(diǎn)肯定相當(dāng)于父節(jié)點(diǎn)對(duì)應(yīng)范圍的一個(gè)子范圍。I/O端口資源樹(shù)(ioport_resource)的根節(jié)點(diǎn)跨越了整個(gè)I/O地址空間(從端口0到65535)。

任何設(shè)備驅(qū)動(dòng)程序都可以使用下面三個(gè)函數(shù),傳遞給它們的參數(shù)為資源樹(shù)的根節(jié)點(diǎn)和要插入的新資源數(shù)據(jù)結(jié)構(gòu)的地址:

request_resource() //把一個(gè)給定范圍分配給一個(gè)I/O設(shè)備。

allocate_resource() //在資源樹(shù)中尋找一個(gè)給定大小和排列方式的可用范圍;若存在,將這個(gè)范圍分配給一個(gè)I/O設(shè)備(主要由PCI設(shè)備驅(qū)動(dòng)程序使用,可以使用任意的端口號(hào)和主板上的內(nèi)存地址對(duì)其進(jìn)行配置)。

release_resource() //釋放以前分配給I/O設(shè)備的給定范圍。

內(nèi)核也為以上函數(shù)定義了一些應(yīng)用于I/O端口的快捷函數(shù):request_region( )分配I/O端口的給定范圍,release_region( )釋放以前分配給I/O端口的范圍。當(dāng)前分配給I/O設(shè)備的所有I/O地址的樹(shù)都可以從/proc/ioports文件中獲得。

2、內(nèi)存映射方式

將IO端口映射為內(nèi)存進(jìn)行訪問(wèn),在設(shè)備打開(kāi)或驅(qū)動(dòng)模塊被加載時(shí),申請(qǐng)IO端口區(qū)域并使用ioport_map()映射到內(nèi)存,之后使用IO內(nèi)存的函數(shù)進(jìn)行端口訪問(wèn),最后,在設(shè)備關(guān)閉或驅(qū)動(dòng)模塊被卸載時(shí)釋放IO端口并釋放映射。

映射函數(shù)的原型為:

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

通過(guò)這個(gè)函數(shù),可以把port開(kāi)始的count個(gè)連續(xù)的I/O端口重映射為一段“內(nèi)存空間”。然后就可以在其返回的地址上像訪問(wèn)I/O內(nèi)存一樣訪問(wèn)這些I/O端口。但請(qǐng)注意,在進(jìn)行映射前,還必須通過(guò)request_region()分配I/O端口。

當(dāng)不再需要這種映射時(shí),需要調(diào)用下面的函數(shù)來(lái)撤消:

void ioport_unmap(void *addr);

在設(shè)備的物理地址被映射到虛擬地址之后,盡管可以直接通過(guò)指針訪問(wèn)這些地址,但是宜使用Linux內(nèi)核的如下一組函數(shù)來(lái)完成訪問(wèn)I/O內(nèi)存:讀I/O內(nèi)存

unsigned int ioread8(void *addr);unsigned int ioread16(void *addr);unsigned int ioread32(void *addr);

與上述函數(shù)對(duì)應(yīng)的較早版本的函數(shù)為(這些函數(shù)在Linux 2.6中仍然被支持):

unsigned readb(address);unsigned readw(address);unsigned readl(address);

·寫(xiě)I/O內(nèi)存

void iowrite8(u8 value, void *addr);void iowrite16(u16 value, void *addr);void iowrite32(u32 value, void *addr);

與上述函數(shù)對(duì)應(yīng)的較早版本的函數(shù)為(這些函數(shù)在Linux 2.6中仍然被支持):

void writeb(unsigned value, address);void writew(unsigned value, address);void writel(unsigned value, address);

流程如下:

2)Linux下訪問(wèn)IO內(nèi)存

IO內(nèi)存的訪問(wèn)方法是:首先調(diào)用request_mem_region()申請(qǐng)資源,接著將寄存器地址通過(guò)ioremap()映射到內(nèi)核空間的虛擬地址,之后就可以Linux設(shè)備訪問(wèn)編程接口訪問(wèn)這些寄存器了,訪問(wèn)完成后,使用ioremap()對(duì)申請(qǐng)的虛擬地址進(jìn)行釋放,并釋放release_mem_region()申請(qǐng)的IO內(nèi)存資源。

struct resource*requset_mem_region(unsigned long start, unsigned long len,char *name);

這個(gè)函數(shù)從內(nèi)核申請(qǐng)len個(gè)內(nèi)存地址(在3G~4G之間的虛地址),而這里的start為I/O物理地址,name為設(shè)備的名稱(chēng)。注意,如果分配成功,則返回非NULL,否則,返回NULL。

另外,可以通過(guò)/proc/iomem查看系統(tǒng)給各種設(shè)備的內(nèi)存范圍。

要釋放所申請(qǐng)的I/O內(nèi)存,應(yīng)當(dāng)使用release_mem_region()函數(shù):

void release_mem_region(unsigned longstart, unsigned long len)

申請(qǐng)一組I/O內(nèi)存后,調(diào)用ioremap()函數(shù):

void* ioremap(unsigned long phys_addr, unsigned long size, unsigned long flags);

其中三個(gè)參數(shù)的含義為:phys_addr:與requset_mem_region函數(shù)中參數(shù)start相同的I/O物理地址;size:要映射的空間的大小;flags:要映射的IO空間的和權(quán)限有關(guān)的標(biāo)志;

功能:將一個(gè)I/O地址空間映射到內(nèi)核的虛擬地址空間上(通過(guò)requset _mem_region()申請(qǐng)到的)

流程如下:

3)ioremap和ioport_map

下面具體看一下ioport_map和ioport_umap的源碼:

1.void__iomem*ioport_map(unsignedlongport,unsignedintnr)

2.{

3.if(port>PIO_MASK)

4.returnNULL;

5.return(void__iomem*)(unsignedlong)(port+PIO_OFFSET);

6.}

7.

8.voidioport_unmap(void__iomem*addr)

9.{

10./*Nothingtodo*/

11.}

ioport_map僅僅是將port加上PIO_OFFSET(64k),而ioport_unmap則什么都不做。這樣portio的64k空間就被映射到虛擬地址的64k~128k之間,而ioremap返回的虛擬地址則肯定在3G之上。ioport_map函數(shù)的目的是試圖提供與ioremap一致的虛擬地址空間。分析ioport_map()的源代碼可發(fā)現(xiàn),所謂的映射到內(nèi)存空間行為實(shí)際上是給開(kāi)發(fā)人員制造的一個(gè)“假象”,并沒(méi)有映射到內(nèi)核虛擬地址,僅僅是為了讓工程師可使用統(tǒng)一的I/O內(nèi)存訪問(wèn)接口ioread8/iowrite8(......)訪問(wèn)I/O端口。

最后來(lái)看一下ioread8的源碼,其實(shí)現(xiàn)也就是對(duì)虛擬地址進(jìn)行了判斷,以區(qū)分IO端口和IO內(nèi)存,然后分別使用inb/outb和readb/writeb來(lái)讀寫(xiě)。

1.unsignedintfastcallioread8(void__iomem*addr)

2.{

3.IO_COND(addr,returninb(port),returnreadb(addr));

4.}

5.

6.#defineVERIFY_PIO(port)BUG_ON((port&~PIO_MASK)!=PIO_OFFSET)

7.#defineIO_COND(addr,is_pio,is_mmio)do{\

8.unsignedlongport=(unsignedlong__force)addr;\

9.if(port

10.VERIFY_PIO(port);\

11.port&=PIO_MASK;\

12.is_pio;\

13.}else{\

14.is_mmio;\

15.}\

16.}while(0)

17.

18.展開(kāi):

19.unsignedintfastcallioread8(void__iomem*addr)

20.{

21.unsignedlongport=(unsignedlong__force)addr;

22.if(port

23.BUG_ON((port&~PIO_MASK)!=PIO_OFFSET);

24.port&=PIO_MASK;

25.returninb(port);

26.}else{

27.returnreadb(addr);

28.}

29.}

聲明:本文內(nèi)容及配圖由入駐作者撰寫(xiě)或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場(chǎng)。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問(wèn)題,請(qǐng)聯(lián)系本站處理。 舉報(bào)投訴
  • BIOS
    +關(guān)注

    關(guān)注

    5

    文章

    470

    瀏覽量

    45967
  • CPU設(shè)計(jì)
    +關(guān)注

    關(guān)注

    0

    文章

    8

    瀏覽量

    10565
  • IO端口
    +關(guān)注

    關(guān)注

    0

    文章

    31

    瀏覽量

    10746

原文標(biāo)題:詳解IO端口與IO內(nèi)存

文章出處:【微信號(hào):weixin21ic,微信公眾號(hào):21ic電子網(wǎng)】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。

收藏 人收藏

    評(píng)論

    相關(guān)推薦

    一文讀懂i/o端口地址譯碼

    I/O端口是接口電路中能被CPU直接訪問(wèn)的寄存器。訪問(wèn)端口就是訪問(wèn)接口電路中的寄存器。一個(gè)接口電路(外設(shè))通常擁有不止一個(gè)端口,如命令口、狀態(tài)口、數(shù)據(jù)口等。
    的頭像 發(fā)表于 11-16 09:40 ?1.4w次閱讀
    一文讀懂i/o<b class='flag-5'>端口地址</b>譯碼

    Linux如何證明線程共享進(jìn)程的地址空間

    所有的書(shū)上都說(shuō),進(jìn)程中的所有線程共享進(jìn)程的地址空間,如上圖中的藍(lán)框都在一個(gè)進(jìn)程中。那么該如何證明這個(gè)結(jié)論呢?
    發(fā)表于 08-25 16:22 ?500次閱讀
    Linux如何證明線程<b class='flag-5'>共享</b>進(jìn)程的<b class='flag-5'>地址</b><b class='flag-5'>空間</b>

    EC SRAM映射到CPU Memory空間共享內(nèi)存設(shè)計(jì)

    ShareMemory,顧名思義就是共享內(nèi)存。這個(gè)概念在很多計(jì)算機(jī)系統(tǒng)中都存在,本文特指 EC SRAM 映射到 CPU Memory 空間共享內(nèi)存設(shè)計(jì)。
    的頭像 發(fā)表于 11-18 15:11 ?1862次閱讀
    EC SRAM映射到<b class='flag-5'>CPU</b> Memory<b class='flag-5'>空間</b>的<b class='flag-5'>共享</b>內(nèi)存設(shè)計(jì)

    #硬聲創(chuàng)作季 01-IO端口

    IO端口
    發(fā)布于 :2022年10月26日 22:43:43

    詳解io端口io內(nèi)存

    與存儲(chǔ)地址分開(kāi)獨(dú)立編址,I/0端口地址不占用存儲(chǔ)空間地址范圍,這樣,在系統(tǒng)中就存在了另一種與存儲(chǔ)地址無(wú)關(guān)的
    發(fā)表于 06-07 15:41

    IO設(shè)計(jì)基本理論

    IO設(shè)計(jì)基本理論1. IO接口和IO端口IO端口IO
    發(fā)表于 07-22 08:36

    AVR IO端口的特性與應(yīng)用

    AVR IO端口的特性與應(yīng)用 AVR的IO端口特性分析:
    發(fā)表于 03-11 21:50 ?1272次閱讀
    AVR <b class='flag-5'>IO</b><b class='flag-5'>端口</b>的特性與應(yīng)用

    IO接口地址譯碼電路

    IO接口地址譯碼電路 如上圖1所示地址空間280H~2BFH共分8條譯碼輸出線:Y0~Y7 其地址分別是280H~287H、288H~28
    發(fā)表于 03-25 09:27 ?4988次閱讀
    <b class='flag-5'>IO</b>接口<b class='flag-5'>地址</b>譯碼電路

    io端口編址方式有哪些?

    每個(gè)連接到I/O總線上的設(shè)備都有自己的I/O地址集,即所謂的I/O端口在IBM PC體系結(jié)構(gòu)中,I/O地址空間一共提供了65,536個(gè)8位的I/O
    發(fā)表于 12-01 16:06 ?1.7w次閱讀
    <b class='flag-5'>io</b><b class='flag-5'>端口</b>編址方式有哪些?

    IO端口IO內(nèi)存區(qū)別詳解

    地址的概念 1)物理地址CPU地址總線傳來(lái)的地址,由硬件電路控制其具體含義。物理地址中很大一部
    發(fā)表于 01-17 12:40 ?1980次閱讀
    <b class='flag-5'>IO</b><b class='flag-5'>端口</b>與<b class='flag-5'>IO</b>內(nèi)存區(qū)別詳解

    STM32端口IO方向設(shè)置問(wèn)題

    STM32端口IO方向設(shè)置問(wèn)題STM32端口寄存器配置STM32 的 IO 口可以由軟件配置成如下 8 種模式: 1、輸入浮空 2、輸入上拉 3、輸入下拉 4、模擬輸入 5、開(kāi)漏輸出
    發(fā)表于 11-29 13:36 ?28次下載
    STM32<b class='flag-5'>端口</b><b class='flag-5'>IO</b>方向設(shè)置問(wèn)題

    詳解io端口io內(nèi)存

    的虛擬地址經(jīng)過(guò)段映射和頁(yè)面映射后,就生成了物理地址,這個(gè)物理地址被放到CPU地址線上。 物理地址
    發(fā)表于 02-11 15:37 ?0次下載
    詳解<b class='flag-5'>io</b><b class='flag-5'>端口</b>與<b class='flag-5'>io</b>內(nèi)存

    PCI總線地址空間與系統(tǒng)地址空間的關(guān)系

    1、PCI地址空間 PCI總線具有32位數(shù)據(jù)/地址復(fù)用總線,所以其存儲(chǔ)地址空間為2的32次方=4GB。也就是PCI上的所有設(shè)備共同映射到這4
    的頭像 發(fā)表于 01-06 08:30 ?2447次閱讀

    PCI/PCIe地址空間的概念

    地址空間的概念 以人類(lèi)為例: 爺爺生了4個(gè)小孩,排行1234 老大又生了4個(gè)小孩,排行1234 這兩個(gè)“1234”輩分不一樣,空間不一樣 嵌入式系統(tǒng)中的地址
    的頭像 發(fā)表于 07-30 09:38 ?759次閱讀
    PCI/PCIe<b class='flag-5'>地址</b><b class='flag-5'>空間</b>的概念

    Linux虛擬地址空間和物理地址空間的關(guān)系

    過(guò)程,這其實(shí)也是MMU的工作原理。 我們知道,在Linux中,每個(gè)進(jìn)程都有自己獨(dú)立的地址空間,且互不干擾。每個(gè)進(jìn)程的地址空間又分為用戶空間
    的頭像 發(fā)表于 10-08 11:40 ?1272次閱讀
    Linux虛擬<b class='flag-5'>地址</b><b class='flag-5'>空間</b>和物理<b class='flag-5'>地址</b><b class='flag-5'>空間</b>的關(guān)系