虚拟地址转物理地址要用__pa

内核程序创建的一段地址连续的共享内存,通过内存映射可以让用户态进程存取。之前在RHEL/CentOS的x86_64架构上工作正常。后来在aarch64架构的银河麒麟(Linux内核版本为4.4.58)上总出现异常问题。

怀疑内存映射环节有问题。从https://elixir.bootlin.com/linux/v4.4.58/source/drivers/char/mem.c#L321上找到4.4.58内核版本的mmap_mem函数实现。与使用的代码相符。在该页面查找对mmap_mem的调用,发现如下代码段:

static int mmap_kmem(struct file *file, struct vm_area_struct *vma)
{
unsigned long pfn; /* Turn a kernel-virtual address into a physical page frame */
pfn = __pa((u64)vma->vm_pgoff << PAGE_SHIFT) >> PAGE_SHIFT; /*
* RED-PEN: on some architectures there is more mapped memory than
* available in mem_map which pfn_valid checks for. Perhaps should add a
* new macro here.
*
* RED-PEN: vmalloc is not supported right now.
*/
if (!pfn_valid(pfn))
return -EIO; vma->vm_pgoff = pfn;
return mmap_mem(file, vma);
}

进而怀疑是物理地址错位引起的问题。检视代码,发现由虚拟地址转换为物理地址的代码如下:

g_ulPa = addr - PAGE_OFFSET;

由上面的__pa找到4.4.58上arm64平台的定义:

https://elixir.bootlin.com/linux/v4.4.58/source/arch/arm64/include/asm/memory.h#L147

#define __pa(x)			__virt_to_phys((unsigned long)(x))

进而找到__virt_to_phys的定义:

https://elixir.bootlin.com/linux/v4.4.58/source/arch/arm64/include/asm/memory.h#L78

#define __virt_to_phys(x)	(((phys_addr_t)(x) - PAGE_OFFSET + PHYS_OFFSET))

在此前支持的x86_64架构上,PHY_OFFSET总是为0,因此上面转换地址的代码是没有问题的。但在arm架构就有问题了。

进一步发现,__pa比__virt_to_phys更为通用。Linux支持的所有CPU架构都有__pa,而__virt_to_phys则不是。

因此,最终改动一行代码,问题得到解决:

g_ulPa = __pa(addr);

内核进程读写用户态进程内存要用copy_from_user和copy_to_user

内核进程通过创建一个proc文件,用户态进程通过这个文件下发指令给内核进程,以实现对内核数据的存取等功能。这就涉及内核进程对用户态进程内存的读写操作。最初的代码实现是直接读写,一开始也没碰到问题。后来在一些新型的服务器上,直接引发了系统卡死的问题,机器重启无法进入系统。

内核程序处理proc指令的函数接口示意如下:

int procCmdHandler(..., const u8* pBuff, int size, ...)

输入输出参数pBuff是指向用户态地址的指针,内核程序不可以直接读写这个指针指向的内容,否则会在CPU指令集做了保护增强的新型服务器上引发系统卡死的问题。正确的做法是:

1、内核态程序读取用户态指针指向的数据,需要使用copy_from_user函数

2、内核态程序更改用户态指针指向的数据,需要使用copy_to_user函数

最新文章

  1. [LintCode] Trapping Rain Water 收集雨水
  2. 基于MVC4+EasyUI的Web开发框架经验总结
  3. [Effective JavaScript 笔记]第51条:在类数组对象上复用通用的数组方法
  4. js 函数声明方式以及javascript的历史
  5. kuangbin_ShortPath P (HDU 4725)
  6. linux各种查看端口号
  7. 有关java.lang.UnsupportedClassVersionError: Unsupported major.minor version 51.0
  8. ubuntu 下配置Python wxWidgets (复制自官方网站)
  9. QT5控件-QPushButton和QFocusFrame(按钮和焦点框)
  10. extjs tree check 级联选择
  11. Git安装及基本使用
  12. 制作简易计算器处理过程Servlet
  13. NYoj 部分和问题(深搜经典)
  14. js基础01
  15. Kafka的特点及使用场景
  16. 强大核心功能矩阵,详解腾讯云负载均衡CLB高可靠高性能背后架构
  17. nginx代理部署Vue与React项目
  18. js中浅拷贝和深拷贝以及深拷贝的实现
  19. 【浅说】堆(heap)和栈(stack)区别
  20. 【js】利用闭包消除回调函数启动时值已经发生变化的影响

热门文章

  1. Matplotlib和Seaborn演示Python可视化
  2. 如何使用Git Flow 进行hotfix
  3. js 跨域请求失败
  4. ;~ 小部分AutoHotkey脚本源代码测试模板样板.ahk
  5. 京东购物小程序 | Taro3 项目分包实践
  6. 【算法学习笔记】动态规划与数据结构的结合,在树上做DP
  7. http request 请求拦截器,有token值则配置上token值
  8. C++ //继承同名成员处理方式
  9. 关于修改.net core webapi中null默认返回的状态码。
  10. Create Shortcut to Get Jar File Meta Information