从 Linux 内核空间访问物理地址

如何解决从 Linux 内核空间访问物理地址

我正在编写一个内核模块,它需要访问内核空间和用户空间之外的内存区域。我知道这种内存的物理地址和大小。我已经尝试过使用 ioremap(),但是这样一个函数返回的虚拟地址指向的物理地址与我作为参数提供给 ioremap 的地址不同。然后我尝试在 ioremap() 之后使用 phys_to_virt(),这次获得的虚拟地址指向正确的物理地址,但是当我尝试访问此类内存区域内的元素时,我收到以下错误无法处理虚拟地址 ffffff801400000f 处的内核分页请求 我错了什么?

编辑: 代码片段:

#define FLAG_SIZE 1
#define BUF_SIZE 4
#define ELEM_SIZE 5

res = ioremap_nocache(MEMORY_ADDR,BUF_SIZE*ELEM_SIZE);
void *virt = phys_to_virt(MEMORY_ADDR);

        
printk(KERN_INFO "Physical address %px mapped in virtual address %px\n",virt_to_phys(virt),virt);
    
// DEBUG: print buffers content
char *flags = res + BUF_SIZE*(ELEM_SIZE-FLAG_SIZE);
for(i=0; i < BUF_SIZE; i++){
        printk(KERN_INFO "row %d [flag: %c]: %d\n",i,readb(flags + i),virt + i*ELEM_SIZE);
}

其中: -MEMORY_ADDR:是物理地址 -BUF_SIZE:缓冲区中的元素数 -ELEM_SIZE:元素的大小

标志缓冲区是位于此类内存区域末尾的字符数组

返回的完整输出是:

Physical address 1409286144 mapped in virtual address 335544320
Unable to handle kernel paging request at virtual address ffffff801400000f
Mem abort info:
  ESR = 0x96000006
  EC = 0x25: DABT (current EL),IL = 32 bits
  SET = 0,FnV = 0
  EA = 0,S1PTW = 0
Data abort info:
  ISV = 0,ISS = 0x00000006
  CM = 0,WnR = 0
swapper pgtable: 4k pages,39-bit VAs,pgdp=00000000407c8000
[ffffff801400000f] pgd=000000004fffb003,pud=000000004fffb003,pmd=0000000000000000
Internal error: Oops: 96000006 [#1] SMP
Modules linked in: source(O)
cpu: 1 PID: 107 Comm: ifconfig Tainted: G           O      5.4.88 #1
Hardware name: linux,dummy-virt (DT)
pstate: 20000005 (nzCv daif -PAN -UAO)
pc : getFlag+0x24/0x40 [source]
lr : shmem_net_open+0x168/0x2c0 [source]
sp : ffffffc010b4b9d0
x29: ffffffc010b4b9d0 x28: 0000000000001043 
x27: ffffff800e2b4c00 x26: ffffffc01077c000 
x25: 0000000000000005 x24: ffffffc008661158 
x23: 0000000000000004 x22: 0000000000000000 
x21: ffffff800e24e200 x20: ffffff800e255000 
x19: ffffff800e255858 x18: 0000000000020000 
x17: 000000004a0b804e x16: 0000000031b76cb0 
x15: ffffffc010859c40 x14: 0720072007200720 
x13: 0720073007320733 x12: 0734073407350735 
x11: 0733073307200773 x10: 0773076507720764 
x9 : 076407610720076c x8 : 000000000000006f 
x7 : 076907760720076e x6 : 0000000000000001 
x5 : ffffff800e255840 x4 : 0000000000000005 
x3 : 0000008040000000 x2 : 0000000000000000 
x1 : 000000000000000f x0 : ffffff801400000f 
Call trace:
 getFlag+0x24/0x40 [source]
 __dev_open+0xe4/0x160
 __dev_change_flags+0x160/0x1c0
 dev_change_flags+0x20/0x60
 devinet_ioctl+0x63c/0x700
 inet_ioctl+0x2f4/0x360
 sock_do_ioctl+0x44/0x2b0
 sock_ioctl+0x1c8/0x510
 do_vfs_ioctl+0x984/0xb70
 ksys_ioctl+0x44/0x90
 __arm64_sys_ioctl+0x1c/0xc0
 el0_svc_common.constprop.0+0x68/0x160
 el0_svc_handler+0x6c/0x90
 el0_svc+0x8/0x1fc
Code: 1b047c21 8b21c041 8b010000 cb030000 (39400000) 
---[ end trace 5a219c0b95978c47 ]---
Segmentation fault

使用的处理器是 Armv8 cortex 53

EDIT 2:更正了之前的代码片段,现在没有内核崩溃,但是输出不正确:

[SHMEM_NET] Physical address 0000000054000000 mapped in virtual address ffffffc01000d000
row 0 [flag: ]: 268488704
row 1 [flag: E]: 268488707
row 2 [flag: E]: 268488710
row 3 [flag: E]: 268488713
row 4 [flag: E]: 268488716

问题是我应该在第 0 行找到第一个“E”,而第 4 行应该在映射区域之外。而且,如果我现在修改这样的内存区域,本机可以看到修改内容,但访问相同内存区域的其他机器仍然看到旧值。

解决方法

ioremapphys_to_virt 返回的虚拟地址不一样。

ioremap:创建一个新的映射页表

phys_to_virt:从地址中减去一个固定的偏移量。检查 MMU 的 phy_offset。

如何测试?

void* addr1 = phys_to_virt(MEMORY_ADDR);
void* addr2 = ioremap_nocache(MEMORY_ADDR,BUF_SIZE*ELEM_SIZE);

printk(KERN_INFO "virt_addr1: %x\n",(unsigned int volatile *) addr1);
printk(KERN_INFO "virt_addr2: %x\n",(unsigned int volatile *) addr2);

你会看到 addr1 和 addr2 是不同的。我认为您不需要使用 phys_to_virt

简单使用:

void* virt_addr = ioremap_nocache(MEMORY_ADDR,BUF_SIZE*ELEM_SIZE);

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其他元素将获得点击?
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。)
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbcDriver发生异常。为什么?
这是用Java进行XML解析的最佳库。
Java的PriorityQueue的内置迭代器不会以任何特定顺序遍历数据结构。为什么?
如何在Java中聆听按键时移动图像。
Java“Program to an interface”。这是什么意思?
Java在半透明框架/面板/组件上重新绘画。
Java“ Class.forName()”和“ Class.forName()。newInstance()”之间有什么区别?
在此环境中不提供编译器。也许是在JRE而不是JDK上运行?
Java用相同的方法在一个类中实现两个接口。哪种接口方法被覆盖?
Java 什么是Runtime.getRuntime()。totalMemory()和freeMemory()?
java.library.path中的java.lang.UnsatisfiedLinkError否*****。dll
JavaFX“位置是必需的。” 即使在同一包装中
Java 导入两个具有相同名称的类。怎么处理?
Java 是否应该在HttpServletResponse.getOutputStream()/。getWriter()上调用.close()?
Java RegEx元字符(。)和普通点?