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

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

3天內不再提示

為什么Linux操作寄存器要ioremap

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

1. 原因

  • 這里只考慮有 MMU 的芯片,Linux 為了實現進程虛擬地址空間,在啟用 MMU 后,在內核中操作的都是虛擬地址,內核訪問不到物理地址。
  • 如果在驅動里直接訪問物理地址,等于訪問了一個非法地址,會導致內核崩潰,下面會有一個相關的小實驗。
  • 通過 ioremap 將物理地址映射為虛擬地址后,內核就能通過 ioremap() 返回的虛擬地址,以 虛擬地址->mmu頁表映射-> 物理地址 的形式正確地訪問到物理地址了。
  • ARM Linux 引入設備樹特性后,一些支持設備樹的設備驅動不再使用直接 ioremap(),改用 drivers/of/address.c/of_iomap(),of_iomap() 的內部仍然會調用 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");

實驗結果:

使用了 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() 的實現內幕

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

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

函數調用流程:

圖片

總結一下:

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

    關注

    450

    文章

    49636

    瀏覽量

    417144
  • 寄存器
    +關注

    關注

    31

    文章

    5253

    瀏覽量

    119201
  • Linux
    +關注

    關注

    87

    文章

    11123

    瀏覽量

    207908
收藏 人收藏

    評論

    相關推薦

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

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

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

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

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

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

    寄存器操作方法的經驗和其總結

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

    寄存器操作方法_對寄存器操作的通用方法總結

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

    寄存器變量

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

    C語言:寄存器操作

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

    STM32的寄存器操作

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

    簡述RAL寄存器模型基礎

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

    RAL寄存器模型操作圖鑒

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

    RAL寄存器模型操作指南

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

    Linux驅動操作寄存器

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

    Linux應用層操作寄存器

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

    如何在shell中操作寄存器

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

    Linux應用層操作寄存器

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