最美情侣中文字幕电影,在线麻豆精品传媒,在线网站高清黄,久久黄色视频

歡迎光臨散文網(wǎng) 會員登陸 & 注冊

Linux內(nèi)核IO內(nèi)存使用分析思路

2022-03-29 10:21 作者:四川學(xué)到牛科技  | 我要投稿

Linux內(nèi)核IO內(nèi)存

在嵌入式開發(fā)中,所有芯片對外設(shè)進(jìn)行處理都是通過讀寫設(shè)備上的寄存器進(jìn)行的。外設(shè)的寄存器在內(nèi)存中單獨(dú)分出一部分作為特殊功能寄存器進(jìn)行編址。在低級嵌入式設(shè)備中,我們通過直接操作外設(shè)寄存器即可控制外設(shè)的工作。在高級設(shè)備中,設(shè)備加載了操作系統(tǒng),操作系統(tǒng)中的內(nèi)存管理單元(MMU)對設(shè)備內(nèi)存進(jìn)行重新管理,從而無法直接進(jìn)行操作。目前市面上,根據(jù)不同CPU體系架構(gòu),CPU對外設(shè)端口的編址方式一般有兩種:IO映射方式(IO mapped)和內(nèi)存映射方式(memory mapped)。

IO映射方式,主要指外設(shè)地址空間和內(nèi)存地址空間是獨(dú)立開的,根據(jù)不同的訪問指令進(jìn)行對應(yīng)操作。典型的如x86處理器的設(shè)備。

圖 1 IO映射方式

內(nèi)存映射方式,主要指內(nèi)存地址空間和外設(shè)地址空間的訪問時(shí)一樣的。只是訪問的地址不同。典型的如RISC指令系統(tǒng)的嵌入式設(shè)備CPU(如ARM、PowerPC等)。

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

通常情況,外設(shè)的IO內(nèi)存資源的物理地址在硬件設(shè)計(jì)的時(shí)候已經(jīng)確定,并且該物理地址是已知的。但是操作系統(tǒng)通過內(nèi)存管理單元(MMU)管理系統(tǒng)的虛擬地址到物理地址的訪問。在設(shè)備運(yùn)行時(shí),對于驅(qū)動開發(fā)人員來說,可以被直接用于編程的是虛擬地址,開發(fā)人員需要使用內(nèi)存映射機(jī)制將物理地址映射到虛擬地址,從而通過虛擬地址訪問外設(shè)IO。

Linux內(nèi)核源碼中io.h文件聲明了函數(shù)ioremap()和iounmap(),該函數(shù)主要用于將IO內(nèi)存資源的物理地址到虛擬地址的映射和解除映射。

// ioremap宏定義在asm/io.h內(nèi):

#define? ?ioremap(cookie,size)? ? __ioremap(cookie,size,0)

// __ioremap函數(shù)原型為(arm/mm/ioremap.c):

void__iomem * __ioremap(unsigned long phys_addr, size_t size, unsigned long flags);

參數(shù):

phys_addr:映射的起始IO地址

size:映射的空間大小

flags:映射的IO空間和權(quán)限有關(guān)的標(biāo)志

返回值:映射后的內(nèi)核虛擬地址(3G-4G)?

iounmap函數(shù)用于解除ioremap()所做的映射,原型如下:

void iounmap(void * addr);

? ? 在將I/O外設(shè)的寄存器物理地址映射成虛擬地址后,我們就可以象讀寫內(nèi)存那樣直接對I/O內(nèi)存資源進(jìn)行讀寫了。Linux內(nèi)核為了保證驅(qū)動程序的跨平臺的可移植性,提供了特定的讀寫函數(shù)來訪問I/O內(nèi)存資源。

讀寫I/O的函數(shù)如下所示:

// IO內(nèi)存讀取函數(shù),參數(shù)p為讀取的虛擬地址。分別可以讀取8位、16位和32位

#define ioread8(p)? ? ? ({ unsigned int __v = __raw_readb(p); __iormb(); __v; })

#define ioread16(p)? ? ?({ unsigned int __v = le16_to_cpu((__force __le16)__raw_readw(p)); __iormb(); __v; })

#define ioread32(p)? ? ?({ unsigned int __v = le32_to_cpu((__force __le32)__raw_readl(p)); __iormb(); __v; })

// IO內(nèi)存寫入函數(shù),參數(shù)p為寫入的虛擬地址,v為寫入值。分別可以寫入8位、16位和32位

#define iowrite8(v,p)? ?({ __iowmb(); __raw_writeb(v, p); })

#define iowrite16(v,p)? ({ __iowmb(); __raw_writew((__force __u16)cpu_to_le16(v), p); })

#define iowrite32(v,p)? ({ __iowmb(); __raw_writel((__force __u32)cpu_to_le32(v), p); })

以下示例程序以tiny4412開發(fā)板為例,對開發(fā)板LED燈進(jìn)行IO控制。

#include <linux/kernel.h>

#include <linux/init.h>

#include <linux/module.h>

#include <linux/sched.h>

#include <asm/io.h>

MODULE_LICENSE("GPL");


//? 內(nèi)核IO映射后的虛擬地址

unsigned int virt ;


int test_init()

{

// 映射的物理地址范圍:0x11000 000? - 0x11000 fff

virt = ioremap( 0x11000000, 4096 );??

// 通過指針讀寫內(nèi)存

// unsigned int *gpm4con = (unsigned int *)(virt + 0x02e0);

// unsigned int *gpm4dat = (unsigned int *)(virt + 0x02e4);

// *gpm4con = 0x1111;

// *gpm4dat &= ~0xf;?

// *gpm4dat |= 0xf;?


// 通過IO函數(shù)操作

iowrite32( 0x1111, virt + 0x02e0 );

unsigned int val = ioread32( virt + 0x02e4 );

iowrite32( val | 0xf , virt +0x02e4 );

return 0;

}


void test_exit()

{

iounmap( virt );

}


module_init( test_init );

module_exit( test_exit );

文章來源:學(xué)到牛牛 www.xuedaon.com

Linux內(nèi)核IO內(nèi)存使用分析思路的評論 (共 條)

分享到微博請遵守國家法律
伊宁县| 墨脱县| 西和县| 宁波市| 江源县| 景德镇市| 通化市| 婺源县| 阿拉善左旗| 榆社县| 长乐市| 彰化市| 罗平县| 吉安县| 中西区| 绍兴市| 香格里拉县| 遂川县| 天津市| 卓资县| 丹阳市| 德格县| 泰兴市| 安丘市| 镇安县| 东海县| 凭祥市| 垣曲县| 宣化县| 万山特区| 渑池县| 神木县| 库伦旗| 康乐县| 马关县| 芷江| 托克托县| 洛南县| 永兴县| 普安县| 阿勒泰市|