日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > linux >内容正文

linux

Linux操作寄存器前为什么要ioremap

發布時間:2023/12/20 linux 28 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Linux操作寄存器前为什么要ioremap 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

1. 原因

  • 這里只考慮有 MMU 的芯片,Linux 為了實現進程虛擬地址空間,在啟用 MMU 后,在內核中操作的都是虛擬地址,內核訪問不到物理地址。

  • 如果在驅動里直接訪問物理地址,等于訪問了一個非法地址,會導致內核崩潰,下面會有一個相關的小實驗。

  • 通過 ioremap 將物理地址映射為虛擬地址后,內核就能通過 ioremap() 返回的虛擬地址,以 虛擬地址->mmu頁表映射-> 物理地址 的形式正確地訪問到物理地址了。

  • ARM Linux 引入設備樹特性后,一些支持設備樹的設備驅動不再使用直接 ioremap(),改用 drivers/of/address.c/of_iomap(),of_iomap() 的內部仍然會調用 ioremap(),例如:

clk-rk3288.c?(drivers\clk\rockchip) static?void?rk3288_clk_init(struct?device_node?*np)?{rk3288_cru_base?=?of_iomap(np,?0);[...] }

2. ioremap() 實驗

實驗環境:

  • 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?init\n");#ifdef?USE_IOREMAPgpio_regs?=?(volatile?unsigned?long?*)ioremap(H3_GPIO_BASE,?1024); #elsegpio_regs?=?(volatile?unsigned?long?*)H3_GPIO_BASE; #endiffor?(i=0;?i<3;?i++)printk(KERN_INFO?"reg[%d]?=?%lx\n",?i,?gpio_regs[i]);return?0; } module_init(ioremap_mod_init);static?void?__exit?ioremap_mod_exit(void) {printk(KERN_INFO?"ioremap_mod?exit\n?");#ifdef?USE_IOREMAPiounmap(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.koUnable?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)[<bf5d903c>]?(ioremap_mod_init?[ioremap_mod])?from?[<c0201a70>]?(do_one_initcall+0x40/0x16c) [<c0201a70>]?(do_one_initcall)?from?[<c02b20c8>]?(do_init_module+0x60/0x1f0) [<c02b20c8>]?(do_init_module)?from?[<c02b1214>]?(load_module+0x1b48/0x2250) [<c02b1214>]?(load_module)?from?[<c02b1ad8>]?(SyS_finit_module+0x8c/0x9c) [<c02b1ad8>]?(SyS_finit_module)?from?[<c0221f80>]?(ret_fast_syscall+0x0/0x4c) Code:?e5953000?e3050048?e1a01004?e34b0f5d?(e7932104)? ---[?end?trace?928c64a33a054308?]--- Segmentation?fault

3. ioremap() 的實現內幕

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

  • ioremap() 將 vmalloc 區的某段虛擬內存塊映射到 io memory,其實現原理與vmalloc() 類似,都是通過在 vmalloc 區分配虛擬地址塊,然后修改內核頁表的方式將其映射到設備的 I/O 地址空間。

  • 與 vmalloc() 不同的是,ioremap 并不需要通過伙伴系統去分配物理頁,因為ioremap 要映射的目標地址是 io memory,不是物理內存 (RAM)。

函數調用流程:

點擊查看大圖

總結一下:

  • 相關檢查;

  • 分配一個 vm_struct 結構體,內核在管理虛擬內存中的 vmalloc 區時,內核必須跟蹤哪些子區域被使用、哪些是空閑的,對應的數據結構就是 vm_strcut。

  • 初始化 vm_struct;

  • 建立頁表;

4. 相關參考

  • 深入理解 Linux 內核 / 8.3.2

  • 深入 Linux 內核架構 / 3.5.7

  • 深入理解Linux設備驅動程序內核機制 / 3.5.3

  • https://blog.csdn.net/njuitjf/article/details/40745227

#推薦閱讀:

? ??專輯|Linux文章匯總

? ??專輯|程序人生

? ??專輯|C語言

嵌入式Linux

微信掃描二維碼,關注我的公眾號?

總結

以上是生活随笔為你收集整理的Linux操作寄存器前为什么要ioremap的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。