当我们写一些外设驱动,或者内核模块,经常会使用ioremap函数来映射寄存器io地址,来访问io空间,在ioremap函数的实现内部会对传入的参数进行判断,如果地址不属于io空间,则会内核会报Warnig。

从函数名字我们也可以看得出来,既然函数叫io remap,那么映射的地址空间必须是io的物理地址,所以如果映射的地址落在了ram地址空间,内核就会报warning!如下面的log

内核报warning的日志:

[    2.536156] ------------[ cut here ]------------
[    2.540766] WARNING: CPU: 0 PID: 1 at __ioremap_caller+0xd0/0xd8
[    2.546759] Modules linked in:
[    2.549804] 
[    2.551286] CPU: 0 PID: 1 Comm: swapper/0 Not tainted 4.9.30-rt19-EMBSYS-CGEL-6.1.R3-g51292b3-dirty #26
[    2.560664] Hardware name: MCS2 (DT)
[    2.564227] task: ffffffc2d7c98d00 task.stack: ffffffc2d7c9c000
[    2.570134] PC is at __ioremap_caller+0xd0/0xd8
[    2.574652] LR is at __ioremap_caller+0x54/0xd8
[    2.579170] pc : [<ffffff80080964e8>] lr : [<ffffff800809646c>] pstate: 80000045
[    2.586551] sp : ffffffc2d7c9fd40
[    2.589853] x29: ffffffc2d7c9fd40 x28: 0000000000000000 
[    2.595156] x27: ffffff80085bad50 x26: ffffff80085b5da8 
[    2.600459] x25: ffffff8008588aa0 x24: ffffff800864e950 
[    2.605762] x23: 00e8000000000707 x22: ffffff80085a3ab8 
[    2.611066] x21: 0000000000000000 x20: 0000000100200000 
[    2.616369] x19: 0000000001400000 x18: 0000000000000010 
[    2.621672] x17: 0000000000000001 x16: 0000000000000019 
[    2.626975] x15: 0000000000000006 x14: ffffff8088623bb7 
[    2.632278] x13: ffffff8008623bc5 x12: 0000000000000030 
[    2.637581] x11: 0101010101010101 x10: 7f7f7f7f7f7f7f7f 
[    2.642884] x9 : 6c646c616b69feff x8 : 0000000020000000 
[    2.648187] x7 : 0000000000000018 x6 : ffffff800863fb28 
[    2.653490] x5 : 0000000000000002 x4 : 0000000000000002 
[    2.658793] x3 : 0000000120000000 x2 : ffffff800863fb40 
[    2.664096] x1 : 0000000000000001 x0 : 0000000000000001 
[    2.669398] 
[    2.670880] ---[ end trace 52179c7400ddff0c ]---
[    2.675485] Call trace:
[    2.677921] Exception stack(0xffffffc2d7c9fb70 to 0xffffffc2d7c9fca0)
[    2.684349] fb60:                                   0000000001400000 0000008000000000
[    2.692166] fb80: ffffffc2d7c9fd40 ffffff80080964e8 ffffffc2d7c05100 ffffffc2d174c240
[    2.699983] fba0: ffffff80082e724c 00000000000000c0 00000000000003c0 000000007fffffff
[    2.707800] fbc0: 000000000000007f ffffff80086497c8 ffffffc2d7c1c608 0000000000000001
[    2.715617] fbe0: 00000000000003c0 000000007fffffff ffffff8008588aa0 ffffff80086497c8
[    2.723433] fc00: ffffffc2d7c9fc30 ffffff80082e724c 0000000000000001 0000000000000001
[    2.731250] fc20: ffffff800863fb40 0000000120000000 0000000000000002 0000000000000002
[    2.739067] fc40: ffffff800863fb28 0000000000000018 0000000020000000 6c646c616b69feff
[    2.746884] fc60: 7f7f7f7f7f7f7f7f 0101010101010101 0000000000000030 ffffff8008623bc5
[    2.754701] fc80: ffffff8088623bb7 0000000000000006 0000000000000019 0000000000000001
[    2.762518] [<ffffff80080964e8>] __ioremap_caller+0xd0/0xd8
[    2.768077] [<ffffff8008096500>] __ioremap+0x10/0x18
[    2.773032] [<ffffff80085a3ab8>] memblk_init+0x98/0x240
[    2.778246] [<ffffff8008082938>] do_one_initcall+0x38/0x120
[    2.783808] [<ffffff8008590cd0>] kernel_init_freeable+0x18c/0x228
[    2.789892] [<ffffff800847d658>] kernel_init+0x10/0x100
[    2.795105] [<ffffff8008082700>] ret_from_fork+0x10/0x50
[    2.801629] thread-exit capture initialized!

追溯一下代码,让我们找到真正的原因,先找到ioremap的定义,ioremap是一条宏定义:(arch/arm64/include/asm/io.h)

#define ioremap(addr, size)        __ioremap((addr), (size), __pgprot(PROT_DEVICE_nGnRE))

__ioremap函数的定义如下,最终会调用__ioremap_caller函数:(arch/arm64/mm/ioremap.c)

void __iomem *__ioremap(phys_addr_t phys_addr, size_t size, pgprot_t prot)
{return __ioremap_caller(phys_addr, size, prot,__builtin_return_address(0));
}

__ioremap_caller函数实现很短,注意其中的WARN_ON()函数,WARN_ON是内核常用的断言,当条件为真时,会调用dump_stack打印堆栈,就会看到上面的一长串warning打印,相应的断言还有BUG_ON。如果触发了BUG_ON,内核一般会panic。但WARN_ON不会使内核崩溃。

下面函数中调用了WARN_ON来进行物理地址检查,并且,由注释“Don't allow RAM to be mapped.”也可以看出,ioremap不允许映射ram地址。

static void __iomem *__ioremap_caller(phys_addr_t phys_addr, size_t size,pgprot_t prot, void *caller)
{unsigned long last_addr;unsigned long offset = phys_addr & ~PAGE_MASK;int err;unsigned long addr;struct vm_struct *area;/** Page align the mapping address and size, taking account of any* offset.*/phys_addr &= PAGE_MASK;size = PAGE_ALIGN(size + offset);/** Don't allow wraparound, zero size or outside PHYS_MASK.*/last_addr = phys_addr + size - 1;if (!size || last_addr < phys_addr || (last_addr & ~PHYS_MASK))return NULL;/** Don't allow RAM to be mapped.*/WARN_ON(pfn_valid(__phys_to_pfn(phys_addr))); /* 检查phys_addr是否是一个有效的物理地址 */area = get_vm_area_caller(size, VM_IOREMAP, caller);if (!area)return NULL;addr = (unsigned long)area->addr;area->phys_addr = phys_addr;err = ioremap_page_range(addr, addr + size, phys_addr, prot);if (err) {vunmap((void *)addr);return NULL;}return (void __iomem *)(offset + addr);
}

kernel用pfn_valid(__phys_to_pfn(phys_addr))来判断该地址是否为一个有效的系统ram地址,因为物理地址可以转换成一个有效的页帧号。

---以上代码摘自linux-4.9.30版本内核。

内核ioremap接口报Warning问题相关推荐

  1. 接口报错500是什么意思_一次排查服务器端接口报500错误的经历

    1 出现问题情景 该问题来自我实习期间完成的一个博客后端系统,具体如下:当我辛辛苦苦在编辑器里完成文章格式修改(字数较多,一般大于3000字:字数较少时不会出现问题),以及相关目录和标签的选定,点击提 ...

  2. Linux内核IOREMAP驱动

    1 Linux内核IOREMAP驱动 在内核驱动的代码中,存在大量代码使用ioremap进行物理地址和虚拟地址映射,使得内核更加容易操作硬件,对比于简单的gpio控制,实际的代码同样是使用了iorem ...

  3. 学霸学长如何第一时间收到接口报错?不用测试妹子再质疑你是不是接口挂了

    不知道大家有没有遇到过这种情况的 客户端:后端接口报错了,我解析数据失败,你看看为啥? 服务端:好,我查查log.你把请求参数给我打印出来. 客户端:我咋打印? 服务端:....我还是自己查log吧 ...

  4. 宝塔部署项目报Warning: require(): open_basedir restriction in effect的解决方案

    宝塔部署项目报Warning: require(): open_basedir restriction in effect的解决方案 参考文章: (1)宝塔部署项目报Warning: require( ...

  5. msf 启动报[-] * WARNING: No database support: No database YAML file解决方法

    msf 启动报[-] * WARNING: No database support: No database YAML file解决方法 参考文章: (1)msf 启动报[-] * WARNING: ...

  6. vue 打包后访问接口报错404 解决方案 (前提是在vue里使用了代理)

    vue 打包后访问接口报错404 解决方案 (前提是在vue里使用了代理) 参考文章: (1)vue 打包后访问接口报错404 解决方案 (前提是在vue里使用了代理) (2)https://www. ...

  7. 使用 Feign 调用分页接口报错:Method has too many Body parameters(亲测)

    一.背景 接口定义: @ApiOperation(value = "分页查询会话") @PostMapping(Routes.SESSIONS_QUERY) JsonResult& ...

  8. 接口报Provisional headers are shown原因和解决方法

    1.前端访问后端接口报has been blocked by CORS policy: Request header field authorization is not allowed by Acc ...

  9. linux内核支持的加密算法,Linux Kernel(Android) 加密算法总结(三)-应用程序调用内核加密算法接口...

    本文将主要介绍,如何在应用程序空间中(user space) 调用内核空间(kernel space)加密模块提供的加密算法API. 方法一:通过调用crypto: af_alg - User-spa ...

最新文章

  1. Java中的读/写锁
  2. 数据结构树的基本操作_树的各类基本操作(数据结构)
  3. JAXB和java.util.Map
  4. mysql冷热数据LRU_浅析MySQL的lru链表
  5. cmd xcopy 拷贝文件夹_u盘文件夹被病毒隐藏怎么解决 u盘文件夹被病毒隐藏解决方法【详细步骤】...
  6. $(document).ready()和onload区别
  7. [置顶] 提高生产力:开源Java工具包Jodd(Java的”瑞士军刀”)
  8. JavaScript继承方式详解[转]
  9. python结巴分词代码_结巴分词Python代码
  10. 台式计算机显卡最高温度多少,台式机的正常温度是多少
  11. u3d计算机获取键盘输入,Unity 中的键盘输入
  12. 计算机键盘功能教案,键盘认识教案
  13. 现场工程师出手-PCAPHub与云SSH隧道稳妥实现异地LAN IIoT联测
  14. webuploader上传图片插件案例
  15. ZZULIOJ 1055兔子繁殖问题
  16. C初阶必写的C语言小游戏—扫雷,一看就会,看完就能写
  17. css:css样式背景图片设置透明度,css如何设置背景图片的透明度
  18. donet还是java
  19. OpenGL API - 笔记汇总
  20. lol聊天服务器断开无法修复,英雄联盟无法聊天说话处理办法

热门文章

  1. 一些选好虚拟主机控制面板的秘诀
  2. Mac系统下获取/创建ssh key
  3. 2012年2月4日汇报Axure RP Pro 6.5 Beta简体中文加强测试版进展
  4. 【python】利用python计算A类不确定度
  5. Unix痛恨者手册--巨经典
  6. php与ui设计的区别,UI设计和平面设计的区别
  7. 解决plt.show()闪退
  8. 随笔分类 - 深入解析Windows操作系统笔记
  9. 哈工大2021算法设计与分析期末试题
  10. C语言入门经典第1课