mmu頁表映射-> 物理地址 的形式正確地訪問到物理地址了。 ARM Linux 引入設(shè)備樹特性后,一些支持設(shè)備樹的設(shè)備" />
0
  • 聊天消息
  • 系統(tǒng)消息
  • 評論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會員中心
創(chuàng)作中心

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

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

為什么Linux操作寄存器要ioremap

麥辣雞腿堡 ? 來源:老吳嵌入式 ? 作者:吳偉東Jack ? 2023-07-20 10:23 ? 次閱讀

1. 原因

  • 這里只考慮有 MMU 的芯片Linux 為了實現(xiàn)進程虛擬地址空間,在啟用 MMU 后,在內(nèi)核中操作的都是虛擬地址,內(nèi)核訪問不到物理地址。
  • 如果在驅(qū)動里直接訪問物理地址,等于訪問了一個非法地址,會導(dǎo)致內(nèi)核崩潰,下面會有一個相關(guān)的小實驗。
  • 通過 ioremap 將物理地址映射為虛擬地址后,內(nèi)核就能通過 ioremap() 返回的虛擬地址,以 虛擬地址->mmu頁表映射-> 物理地址 的形式正確地訪問到物理地址了。
  • ARM Linux 引入設(shè)備樹特性后,一些支持設(shè)備樹的設(shè)備驅(qū)動不再使用直接 ioremap(),改用 drivers/of/address.c/of_iomap(),of_iomap() 的內(nèi)部仍然會調(diào)用 ioremap(),例如:
clk-rk3288.c (driversclkrockchip)
static void rk3288_clk_init(struct device_node *np) {
    rk3288_cru_base = of_iomap(np, 0);
    [...]
}

2. ioremap() 實驗

實驗環(huán)境:

  • Linux-4.14 + Allwinner/H3。

實驗代碼:

#include < linux/init.h >
#include < linux/module.h >
#include < linux/sched.h >
#include < asm/io.h >

#define USE_IOREMAP

#define H3_GPIO_BASE (0x01C20800)

static volatile unsigned long *gpio_regs = NULL;

static int __init ioremap_mod_init(void)
{

    int i = 0;
    printk(KERN_INFO "ioremap_mod initn");

#ifdef USE_IOREMAP
    gpio_regs = (volatile unsigned long *)ioremap(H3_GPIO_BASE, 1024);
#else
    gpio_regs = (volatile unsigned long *)H3_GPIO_BASE;
#endif

    for (i=0; i< 3; i++)
        printk(KERN_INFO "reg[%d] = %lxn", i, gpio_regs[i]);

    return 0;
}
module_init(ioremap_mod_init);

static void __exit ioremap_mod_exit(void)
{
    printk(KERN_INFO "ioremap_mod exitn ");

#ifdef USE_IOREMAP
    iounmap(gpio_regs);
#endif 
}

module_exit(ioremap_mod_exit);

MODULE_AUTHOR("es-hacker");
MODULE_LICENSE("GPL v2");

實驗結(jié)果:

使用了 ioremap()

$ insmod ioremap
ioremap_mod init
reg[0] = 71227722
reg[1] = 33322177
reg[2] = 773373

未使用 ioremap():

$ insmod ioremap_mod.ko

Unable to handle kernel paging request at virtual address 01c20800
pgd = c9ece7c0
[01c20800] *pgd=6ddd7003, *pmd=00000000
Internal error: Oops: 206 [#1] SMP ARM
CPU: 1 PID: 1253 Comm: insmod Tainted: G           O    4.14.111 #116
Hardware name: sun8i
task: ef15d140 task.stack: edc50000
PC is at ioremap_mod_init+0x3c/0x1000 [ioremap_mod]
LR is at ioremap_mod_init+0x14/0x1000 [ioremap_mod]
pc : [< bf5d903c >]    lr : [< bf5d9014 >]    psr: 600e0013
sp : edc51df8  ip : 00000007  fp : 118fa95c
r10: 00000001  r9 : ee7056c0  r8 : bf5d6048
r7 : bf5d6000  r6 : 00000000  r5 : bf5d6200  r4 : 00000000
r3 : 01c20800  r2 : 01c20800  r1 : 00000000  r0 : bf5d5048
Flags: nZCv  IRQs on  FIQs on  Mode SVC_32  ISA ARM  Segment user
Control: 30c5387d  Table: 49ece7c0  DAC: b106c794
Process insmod (pid: 1253, stack limit = 0xedc50210)

[

3. ioremap() 的實現(xiàn)內(nèi)幕

ioremap() 的實現(xiàn)內(nèi)幕會涉及到比較多的內(nèi)存管理的知識,這里我們拋開代碼細節(jié)簡單了解一下原理就好。

  • ioremap() 將 vmalloc 區(qū)的某段虛擬內(nèi)存塊映射到 io memory,其實現(xiàn)原理與vmalloc() 類似,都是通過在 vmalloc 區(qū)分配虛擬地址塊,然后修改內(nèi)核頁表的方式將其映射到設(shè)備的 I/O 地址空間。
  • 與 vmalloc() 不同的是,ioremap 并不需要通過伙伴系統(tǒng)去分配物理頁,因為ioremap 要映射的目標(biāo)地址是 io memory,不是物理內(nèi)存 (RAM)。

函數(shù)調(diào)用流程:

圖片

總結(jié)一下:

  • 相關(guān)檢查;
  • 分配一個 vm_struct 結(jié)構(gòu)體,內(nèi)核在管理虛擬內(nèi)存中的 vmalloc 區(qū)時,內(nèi)核必須跟蹤哪些子區(qū)域被使用、哪些是空閑的,對應(yīng)的數(shù)據(jù)結(jié)構(gòu)就是 vm_strcut。
  • 初始化 vm_struct;
  • 建立頁表;
聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問題,請聯(lián)系本站處理。 舉報投訴
  • 芯片
    +關(guān)注

    關(guān)注

    455

    文章

    50818

    瀏覽量

    423722
  • 寄存器
    +關(guān)注

    關(guān)注

    31

    文章

    5343

    瀏覽量

    120385
  • Linux
    +關(guān)注

    關(guān)注

    87

    文章

    11304

    瀏覽量

    209539
收藏 人收藏

    評論

    相關(guān)推薦

    linux系統(tǒng)中內(nèi)存分配基本原理分析

    訪問外設(shè)的寄存器(一般包括數(shù)據(jù)寄存器、控制寄存器與狀態(tài)寄存器),需要在驅(qū)動初始化中將外設(shè)所處的物理地址映射為虛擬地址,linux為應(yīng)對該問題
    發(fā)表于 03-28 09:16 ?791次閱讀

    寄存器是什么?怎么操作寄存器點亮LED燈?

    寄存器,是集成電路中非常重要的一種存儲單元,通常由觸發(fā)組成。在集成電路設(shè)計中,寄存器可分為電路內(nèi)部使用的寄存器和充當(dāng)內(nèi)外部接口的寄存器這兩
    的頭像 發(fā)表于 07-21 16:59 ?4044次閱讀
    <b class='flag-5'>寄存器</b>是什么?怎么<b class='flag-5'>操作</b><b class='flag-5'>寄存器</b>點亮LED燈?

    iTOP-4412開發(fā)板ioremap控制GPIO寄存器

    GPIO的讀和寫以及其它任意功能。 需要的基礎(chǔ)知識虛擬地址和物理地址內(nèi)存管理單元概念linux 驅(qū)動模塊的加載 主要內(nèi)容GPIO 的寄存器文檔詳細介紹和說明函數(shù) ioremap的用法
    發(fā)表于 05-16 15:13

    寄存器操作方法的經(jīng)驗和其總結(jié)

    接觸了一陣子的STM32函數(shù)庫,使用起來挺方便的,但是很少有處理會有函數(shù)庫,大部分情況下還是自己來對寄存器進行操作,所以還是不要生疏了對寄存器
    的頭像 發(fā)表于 12-19 09:30 ?8760次閱讀
    對<b class='flag-5'>寄存器</b><b class='flag-5'>操作</b>方法的經(jīng)驗和其總結(jié)

    寄存器操作方法_對寄存器操作的通用方法總結(jié)

    本文主要詳解寄存器操作方法以及對寄存器操作的通用方法總結(jié),具體的跟隨小編來了解一下。
    的頭像 發(fā)表于 05-22 15:53 ?2.3w次閱讀

    寄存器變量

    C語言中使用關(guān)鍵字register來聲明局部變量為寄存器變量。寄存器變量的值會被存放在CPU的寄存器中,每當(dāng)需要使用它們時,CPU就可以直接使用,而無須再通過控制從內(nèi)存中獲取。由于
    發(fā)表于 06-03 10:13 ?2383次閱讀

    C語言:寄存器操作

    C語言:寄存器操作
    發(fā)表于 01-13 12:56 ?6次下載
    C語言:<b class='flag-5'>寄存器</b><b class='flag-5'>操作</b>

    STM32的寄存器操作

    STM32的寄存器操作在使用STM32單片機編程時一般都用ST給的庫函數(shù)編程,庫函數(shù)編程的底層就是對單片機寄存器操作,庫函數(shù)就是一系列寄存器
    發(fā)表于 01-13 15:43 ?19次下載
    STM32的<b class='flag-5'>寄存器</b><b class='flag-5'>操作</b>

    簡述RAL寄存器模型基礎(chǔ)

    RAL(Register Abstract Layer,寄存器抽象層),通常也叫寄存器模型,顧名思義就是對寄存器這個部件的建模。本文介紹的內(nèi)容,包括對UVM
    的頭像 發(fā)表于 02-14 16:55 ?2728次閱讀
    簡述RAL<b class='flag-5'>寄存器</b>模型基礎(chǔ)

    RAL寄存器模型操作圖鑒

    寄存器模型操作,指的是通過寄存器模型對RTL中寄存器進行讀寫訪問,或者同步寄存器模型與RTL中寄存器
    的頭像 發(fā)表于 05-17 09:01 ?942次閱讀
    RAL<b class='flag-5'>寄存器</b>模型<b class='flag-5'>操作</b>圖鑒

    RAL寄存器模型操作指南

    寄存器模型操作,指的是通過寄存器模型對RTL中寄存器進行讀寫訪問,或者同步寄存器模型與RTL中寄存器
    的頭像 發(fā)表于 07-12 09:37 ?1091次閱讀
    RAL<b class='flag-5'>寄存器</b>模型<b class='flag-5'>操作</b>指南

    Linux驅(qū)動操作寄存器

    ,第四個參數(shù)是映射的大小。 驅(qū)動中操作: #define?OFFSET??0x60?//某個寄存器的偏移地址 static?int?my_probe(struct?platform_device
    的頭像 發(fā)表于 09-26 16:34 ?832次閱讀

    Linux應(yīng)用層操作寄存器

    應(yīng)用層操作寄存器 驅(qū)動中操作寄存器,需要先進行映射將物理地址轉(zhuǎn)為虛擬地址。 但如果想在應(yīng)用層中操作寄存器
    的頭像 發(fā)表于 09-26 16:37 ?968次閱讀

    如何在shell中操作寄存器

    shell 中操作寄存器可以使用 devmem 命令. devmem 命令其實就是上述應(yīng)用層操作寄存器生成的可執(zhí)行文件,只不過busybox已經(jīng)幫我們實現(xiàn)了。 devmem 命令格式:
    的頭像 發(fā)表于 09-26 16:39 ?1060次閱讀

    Linux應(yīng)用層操作寄存器

    --- > [*] /dev/mem virtual device support Linux應(yīng)用層操作寄存器 除了直接使用devmem,我們也可以在Linux應(yīng)用層自己實現(xiàn)一個de
    的頭像 發(fā)表于 10-08 15:16 ?1226次閱讀
    <b class='flag-5'>Linux</b>應(yīng)用層<b class='flag-5'>操作</b><b class='flag-5'>寄存器</b>