Linux核心訪問外設I O資源的方式

2021-08-25 18:59:54 字數 4613 閱讀 1517

linux核心訪問外設i/o資源的方式

我們知道缺省外設i/o資源是不在linux核心空間中的(如sram或硬體介面暫存器等),若需要訪問該外設i/o資源,必須先將其位址對映到核心空間中來,然後才能在核心空間中訪問它。

linux核心訪問外設i/o記憶體資源的方式有兩種:動態對映(ioremap)和靜態對映(map_desc)。

一、動態對映(ioremap)方式

ioremap巨集定義在asm/io.h內:

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

__ioremap函式原型為(arm/mm/ioremap.c):

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

size:要對映的空間的大小

flags:要對映的io空間和許可權有關的標誌

該函式返回對映後的核心虛擬位址(3g-4g). 接著便可以通過讀寫該返回的核心虛擬位址去訪問之這段i/o記憶體資源。

舉乙個簡單的例子: (取自s3c2410的iis音訊驅動)

#define s3c2410_pa_iis (0x55000000)

若要在核心空間(iis驅動)中訪問這段i/o暫存器(iis)資源需要先建立到核心位址空間的對映:

our_card->regs = ioremap(s3c2410_pa_iis, 0x100);

if (our_card->regs == null)

iotable_init核心提供,定義如下:

由上知道,s3c2410_map_io最終呼叫iotable_init建立對映表。

iotable_init函式的引數有兩個:乙個是map_desc型別的結構體,另乙個是該結構體的數量nr。這裡最關鍵的就是struct map_desc。map_desc結構體定義如下:

/* include/asm-arm/mach/map.h */

struct map_desc ;

這樣的話我們就知道了建立i/o對映表的大致流程為:只要定義相應i/o資源的map_desc結構體,並將該結構體傳給iotable_init函式執行,就可以建立相應的i/o資源到核心虛擬位址空間的對映表了。

我們來看看s3c2410是怎麼定義map_desc結構體的(即上面s3c2410_map_io函式內的s3c2410_iodesc)。

/* arch/arm/mach-s3c2410/s3c2410.c */

static struct map_desc s3c2410_iodesc __initdata = ;

iodesc_ent巨集如下:

#define iodesc_ent(x)

展開後等價於:

static struct map_desc s3c2410_iodesc __initdata = ,

…… };

s3c24xx_pa_ lcd和s3c24xx_va_ lcd為定義在map.h內的lcd暫存器的實體地址和虛擬位址。在這裡map_desc 結構體的virtual成員被初始化為s3c24xx_va_ lcd,pfn成員值通過__phys_to_pfn核心函式計算,只需要傳遞給它該i/o資源的實體地址就行。length為對映資源的大小。mt_device為i/o型別,通常定義為mt_device。

這裡最重要的即virtual 成員的值s3c24xx_va_ lcd,這個值即該i/o資源對映後的核心虛擬位址,建立對映表成功後,便可以在核心或驅動中直接通過該虛擬位址訪問這個i/o資源。

s3c24xx_va_ lcd以及s3c24xx_pa_ lcd定義如下:

/* include/asm-arm/arch-s3c2410/map.h */

/* lcd controller */

#define s3c24xx_va_lcd s3c2410_addr(0x00600000) //lcd對映後的虛擬位址

#define s3c2410_pa_lcd (0x4d000000) //lcd暫存器實體地址

#define s3c24xx_sz_lcd sz_1m //lcd暫存器大小

s3c2410_addr 定義如下:

#define s3c2410_addr(x) ((void __iomem *)0xf0000000 + (x))

這裡就是一種線性偏移關係,即s3c2410建立的i/o靜態對映表會被對映到0xf0000000之後。(這個線性偏移值可以改,也可以你自己在virtual成員裡手動定義乙個值,只要不和其他io資源對映位址衝突,但最好是在0xf0000000之後。)

io_address巨集定義如下:

/* include/asm/arch-versatile/hardware.h */

/* macro to get at io space when running virtually */

#define io_address(x) (((x) & 0x0fffffff) + (((x) >> 4) & 0x0f000000) + 0xf0000000) )

s3c2410_iodesc這個對映表建立成功後,我們在核心中便可以直接通過s3c24xx_va_ lcd訪問lcd的暫存器資源。

如:s3c2410 lcd驅動的probe函式內

/* stop the video and unset envid if set */

info->regs.lcdcon1 &= ~s3c2410_lcdcon1_envid;

lcdcon1 = readl(s3c2410_lcdcon1); //read對映後的暫存器虛擬位址

writel(lcdcon1 & ~s3c2410_lcdcon1_envid, s3c2410_lcdcon1); //write對映後的虛擬位址

/* include/asm/arch-s3c2410/regs-lcd.h */

#define s3c2410_lcdreg(x) ((x) + s3c24xx_va_lcd)

/* lcd control registers */

#define s3c2410_lcdcon1 s3c2410_lcdreg(0x00)

到此,我們知道了通過map_desc結構體建立i/o記憶體資源靜態對映表的原理了。總結一下發現其實過程很簡單,一通過定義map_desc結構體建立靜態對映表,二在核心中通過建立對映後虛擬位址訪問該io資源。

三、i/o靜態對映方式應用例項

i/o靜態對映方式通常是用在暫存器資源的對映上,這樣在編寫核心**或驅動時就不需要再進行ioremap,直接使用對映後的核心虛擬位址訪問。同樣的io資源只需要在核心初始化過程中對映一次,以後就可以一直使用。

暫存器資源對映的例子上面講原理時已經介紹得很清楚了,這裡我舉乙個sram的例項介紹如何應用這種i/o靜態對映方式。當然原理和操作過程同暫存器資源是一樣的,可以把sram看成是大號的i/o暫存器資源。

比如我的板子在0x30000000位置有一塊64kb大小的sram。我們現在需要通過靜態對映的方式去訪問該sram。我們要做的事內容包括修改kernel**,新增sram資源相應的map_desc結構,建立sram到核心位址空間的靜態對映表。寫乙個sram module,在sram module 內直接通過靜態對映後的核心虛擬位址訪問該sram。

第一步:建立sram靜態對映表

在我板子的map_des結構體陣列(***_io_desc)內新增sram資源相應的map_desc。如下:

static struct map_desc ***_io_desc __initdata = ,,

};巨集***_sram_base為我板子上sram的實體地址,定義為0x30000000。我的kernel是通過io_address的方式計算核心虛擬位址的,這點和之前介紹的s3c2410有點不一樣。不過原理都是相同的,為乙個線性偏移, 範圍在0xf0000000之後。

sram module**如下:

/* sram testing module */

…… static void sram_test(void)

static int __init sram_init(void)

sram_test();

return 0;

} static void __exit sram_exit(void)

module_init(sram_init);

module_exit(sram_exit);

在開發板上執行結果如下:

/ # insmod bin/sram.ko

request sram mem region ............

hello,sram! ß 這句即列印的sram內的字串

/ # rmmod sram

release sram mem region success!

sram is close

實驗發現可以通過對映後的位址正常訪問sram。

核心訪問外設I O資源方式

參考 很多預設的外設i o資源是不在linux核心空間中,如sram 硬體暫存器,如果要訪問這些資源,就必須將它位址對映到核心空間。linux核心空間訪問外設i o資源有兩種方式 動態對映 ioremap 和靜態對映 map desc 一 動態對映 動態對映方式接觸應該比較多,即通過核心提供的ior...

Linux 核心訪問外設IO資源的方式

首先介紹一下i o埠和i o記憶體。1.i o埠 當乙個暫存器或記憶體位於i o空間時,稱其為i o埠。2.i o記憶體 當乙個暫存器或記憶體位於記憶體空間時,稱其為i o記憶體。再來看一下i o暫存器和常規記憶體的區別 i o暫存器具有邊際效應 side effect 而記憶體操作則沒有,記憶體寫...

外設I O資源的訪問方式

華清遠見嵌入式學院 講師。我們知道缺省外設i o資源是不在linux核心空間中的 如sram或硬體介面暫存器等 若需要訪問該外設i o資源,必須先將其位址對映到核心空間中來,然後才能在核心空間中訪問它。linux核心訪問外設i o記憶體資源的方式有兩種 動態對映 ioremap 和靜態對映 map ...