如何将虚拟地址从用户空间转换为物理地址?在 linux 设备驱动程序中 app.cdriver.cdriver.c运行输出

如何解决如何将虚拟地址从用户空间转换为物理地址?在 linux 设备驱动程序中 app.cdriver.cdriver.c运行输出

我正在测试一个简单的字符设备驱动程序和一个使用该驱动程序的应用程序。所以我想传递一个数组的地址,并在驱动中看到数组地址和第一个数组元素值作为第一步(顺便说一下,第一个元素本身就是一个指针)。

app.c

uint64_t __attribute__(( aligned(64) )) args[32]; // set to enough size

printf("args = %p\n",args);
printf("app : args[0] = %p\n",((uint64_t *)args)[0]);

ioctl(fd,CallSetBareMetalMode,uint64_t)args);

driver.c

static long my_ioctl(struct file *file,unsigned int cmd,unsigned long arg)
{
    switch(cmd) {
         case CallSetBareMetalMode:
            printk("driver:cmd = %x,arg = %p\n",cmd,(uint64_t *)arg);  // line 177
            printk("driver:arg[0] = %llx\n",((uint64_t *)arg)[0]);

执行时,打印显示如下。

args = 0x442f40
app : args[0] = 443040
[12603.293899] driver:cmd = 40086142,arg = 0000000030dec968
[12603.294509] Unable to handle kernel access to user memory outside uaccess routines at virtual address 0000000000442f40

Q1:这不是我的主要问题,但为什么驱动程序中的 args 值打印为 0000000030dec968?
但是如果我在第 177 行更改打印,

printk("driver:cmd = %x,arg = %lx\n",(uint64_t *)arg);  // line 177

对于打印,arg 至少打印正确。

args = 0x442f40
app : args[0] = 443040
[13204.162435] driver:cmd = 40086142,arg = 442f40
[13204.162886] Unable to handle kernel access to user memory outside uaccess routines at virtual address 0000000000442f40

现在,我发现我应该使用 copy_from_user 函数来使用来自用户空间的地址。所以我将第 178 行改为

copy_from_user(&value,(void __user *)arg,8);
printk("value (arg[0]) = %llx\n",value);

驱动程序打印

[13812.691957] driver:cmd = 40086142,arg = 442f40
[13812.693277] value (arg[0]) = 443040

好的,用户空间的虚拟地址就获取到了。现在是我真正的问题..
Q2 :我必须将用户空间的虚拟地址更改为“物理地址”并将此值写入寄存器或内存。如何将此用户空间虚拟地址更改为物理地址? (记得我在内核空间,因为我在驱动程序中,对吗?)如果我使用 copy_to_user 函数将这个转换后的物理地址写入内存位置(当然在用户虚拟地址,只有写入的数据是物理地址),它将是与原始应用程序共享的相同物理页面吗?用简单的代码解释将不胜感激。

添加

我将 77 写入 test_val 并将 test_val 的地址传递给 args[2]。然后我像以前一样将 args 的地址传递给驱动程序。

app.c

uint64_t __attribute__(( aligned(64) )) args[32]; 
uint64_t test_val = 77;
args[2] = (uint64_t) &test_val; // let's see it's changed to 78
printf("app : args[2] = %p,*args[2] = %lld\n",args[2],*(uint64_t *)args[2]);
ioctl(fd,(uint64_t)args);

driver.c

static long my_ioctl(struct file *file,unsigned long arg)
{
    switch(cmd) {
    case CallSetBareMetalMode:
        printk("driver:cmd = %x,arg);
        copy_from_user(&args,8*3);
        printk("args[2] = %llx\n",args[2]);
        offs = args[2] % 4096;

        down_read(&current->mm->mmap_sem);
        res = get_user_pages( (unsigned long)args[2],1,&pages,NULL);
        printk("get_user_pages done! args[2] = %px\n",args[2]);

        if (res) {
            printk(KERN_INFO "Got mmaped.\n");
            kvpaddr = kmap(pages);
            printk("kmap done!\n");
            printk(KERN_INFO "kvpaddr = %px,ofs = %x\n",kvpaddr,offs);
            printk("xx = %llx\n",((unsigned long long int)(kvpaddr)+offs));
            *(uint64_t *)((unsigned long long int)(kvpaddr)+offs) = 78;
            printk(KERN_INFO "changed value : %lld\n",\
             *(uint64_t *)((unsigned int)(kvpaddr)+offs));
            put_page(pages); //page_cache_release(page);
            printk("put_page done!\n");
        }
        else {
            printk("get_user_pages failed!\n");
        }
        up_read(&current->mm->mmap_sem);

运行输出

args = 0x442f40
app : args[0] = 0x443040
app : args[2] = 0xffffd2e44d98,*args[2] = 77
[85194.544029] driver:cmd = 40086142,arg = 442f40
[85194.544822] args[2] = ffffd2e44d98
[85194.545613] get_user_pages done! args[2] = 0000ffffd2e44d98
[85194.546004] Got mmaped.
[85194.546248] kmap done!
[85194.546536] kvpaddr = ffff00001f7c0000,ofs = d98
[85194.546976] kvaddr = ffff00001f7c0d98
[85194.548645] Unable to handle kernel paging request at virtual address 000000001f7c0d98
[85194.549245] Mem abort info:
[85194.549513]   ESR = 0x96000006
[85194.549929]   EC = 0x25: DABT (current EL),IL = 32 bits
[85194.550364]   SET = 0,FnV = 0
[85194.550719]   EA = 0,S1PTW = 0
[85194.551008] Data abort info:
[85194.551555]   ISV = 0,ISS = 0x00000006
[85194.551938]   CM = 0,WnR = 0
[85194.552609] user pgtable: 4k pages,48-bit VAs,pgdp=00000000568fb000
[85194.553441] [000000001f7c0d98] pgd=0000000056209003,pud=0000000047b97003,pmd=0000000000000000
[85194.555783] Internal error: Oops: 96000006 [#16] SMP
[85194.556761] Modules linked in: chr_drv_ex1(OE) nls_iso8859_1 dm_multipath scsi_dh_rdac scsi_dh_emc scsi_dh_alua qemu_fw_cfg sch_fq_codel ppdev lp parport drm ip_tables x_tables autofs4 btrfs zstd_compress raid10 raid456 async_raid6_recov async_memcpy async_pq async_xor async_tx xor xor_neon raid6_pq libcrc32c raid1 raid0 multipath linear crct10dif_ce ghash_ce sm4_ce sm4_generic sm3_ce sm3_generic sha3_ce sha3_generic sha512_ce sha512_arm64 sha2_ce sha256_arm64 sha1_ce virtio_net net_failover virtio_blk failover aes_neon_bs aes_neon_blk aes_ce_blk crypto_simd cryptd aes_ce_cipher [last unloaded: chr_drv_ex1]
[85194.563741] CPU: 2 PID: 4258 Comm: test_axpu_app Tainted: G      D W  OE     5.4.0-77-generic #86-Ubuntu
[85194.564638] Hardware name: QEMU QEMU Ab21q Virtual Machine,BIOS 0.0.0 02/06/2015
[85194.565687] pstate: 60400005 (nZCv daif +PAN -UAO)
[85194.568143] pc : my_ioctl+0x310/0x370 [chr_drv_ex1]
[85194.568854] lr : my_ioctl+0x300/0x370 [chr_drv_ex1]
[85194.569473] sp : ffff80001372bd30
[85194.569838] x29: ffff80001372bd30 x28: ffff000009f7bc00 
[85194.570354] x27: 0000000000000000 x26: 0000000000000000 
[85194.570796] x25: 0000000056000000 x24: ffff00000d3c35e0 
[85194.571308] x23: ffff000016875600 x22: 0000000000000d98 
[85194.571870] x21: 000000001f7c0d98 x20: 0000000000442f40 
[85194.572273] x19: ffff00001f7c0000 x18: 0000000000000010 
[85194.572669] x17: 0000000000000000 x16: 0000000000000000 
[85194.573126] x15: ffff000009f7c128 x14: ffffffffffffffff 
[85194.573632] x13: ffff80009372ba77 x12: ffff80001372ba7f 
[85194.574127] x11: ffff800011b9e000 x10: 0000000000000000 
[85194.574578] x9 : ffff800011db4000 x8 : 00000000000005f2 
[85194.575193] x7 : 0000000000000017 x6 : ffff800011db39d4 
[85194.575700] x5 : 0000000000000000 x4 : ffff00001feb5250 
[85194.576139] x3 : ffff00001fec56c8 x2 : 0000000000000000 
[85194.576550] x1 : 0000000000000000 x0 : ffff80000924b220 
[85194.577379] Call trace:
[85194.577805]  my_ioctl+0x310/0x370 [chr_drv_ex1]
[85194.579423]  do_vfs_ioctl+0xc64/0xe60
[85194.579846]  ksys_ioctl+0x88/0xb8
[85194.580116]  __arm64_sys_ioctl+0x2c/0x228
[85194.580479]  el0_svc_common.constprop.0+0xe4/0x1f0
[85194.580929]  el0_svc_handler+0x38/0xa8
[85194.581293]  el0_svc+0x10/0x2c8
[85194.582065] Code: d28009c0 f8336ac0 b0000000 91088000 (f94002a1) 
[85194.583646] ---[ end trace bd1ac75ca265aec2 ]---
[85194.590696] Device File closed..
Segmentation fault (core dumped)

我以为我将用户虚拟地址更改为内核虚拟地址,但是写入内核虚拟地址会导致陷阱。有人可以帮我吗?

解决方法

首先使用 virt_to_phys() 只应该与内核 lowmem(直接映射的 RAM 区域)区域一起使用,因此您无法获得用户空间的物理地址,甚至不允许使用内核空间区域,例如vmalloc。仅允许与 lowmem 区域一起使用,因为它位于 PAGE_OFFSET 的固定偏移量。

如果我是对的,您尝试直接写入物理内存,并希望您的结果能在用户空间应用程序中看到。如果这是您想要的,则没有办法做到这一点(至少是一种简单的方法)。


hack 就像:您需要查看应用程序的页表并记录该地址在物理内存中的位置。 x86 页表地址存储在 CR3 寄存器中。下一个问题是 CPU 已经设置为保护模式,并在 PG 中设置了 CR0 标志(即使用分页),这使得 MMU 将地址读取为虚拟地址并进行转换本身到物理(你不能干涉)。因此,要访问物理内存,您必须切换到禁用分页的实模式(如果您将使用实模式,则必须如此)。这可能意味着您将不得不调用 BIOS 例程来为您完成繁重的工作。

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

相关推荐


使用本地python环境可以成功执行 import pandas as pd import matplotlib.pyplot as plt # 设置字体 plt.rcParams['font.sans-serif'] = ['SimHei'] # 能正确显示负号 p
错误1:Request method ‘DELETE‘ not supported 错误还原:controller层有一个接口,访问该接口时报错:Request method ‘DELETE‘ not supported 错误原因:没有接收到前端传入的参数,修改为如下 参考 错误2:cannot r
错误1:启动docker镜像时报错:Error response from daemon: driver failed programming external connectivity on endpoint quirky_allen 解决方法:重启docker -> systemctl r
错误1:private field ‘xxx‘ is never assigned 按Altʾnter快捷键,选择第2项 参考:https://blog.csdn.net/shi_hong_fei_hei/article/details/88814070 错误2:启动时报错,不能找到主启动类 #
报错如下,通过源不能下载,最后警告pip需升级版本 Requirement already satisfied: pip in c:\users\ychen\appdata\local\programs\python\python310\lib\site-packages (22.0.4) Coll
错误1:maven打包报错 错误还原:使用maven打包项目时报错如下 [ERROR] Failed to execute goal org.apache.maven.plugins:maven-resources-plugin:3.2.0:resources (default-resources)
错误1:服务调用时报错 服务消费者模块assess通过openFeign调用服务提供者模块hires 如下为服务提供者模块hires的控制层接口 @RestController @RequestMapping("/hires") public class FeignControl
错误1:运行项目后报如下错误 解决方案 报错2:Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.8.1:compile (default-compile) on project sb 解决方案:在pom.
参考 错误原因 过滤器或拦截器在生效时,redisTemplate还没有注入 解决方案:在注入容器时就生效 @Component //项目运行时就注入Spring容器 public class RedisBean { @Resource private RedisTemplate<String
使用vite构建项目报错 C:\Users\ychen\work>npm init @vitejs/app @vitejs/create-app is deprecated, use npm init vite instead C:\Users\ychen\AppData\Local\npm-
参考1 参考2 解决方案 # 点击安装源 协议选择 http:// 路径填写 mirrors.aliyun.com/centos/8.3.2011/BaseOS/x86_64/os URL类型 软件库URL 其他路径 # 版本 7 mirrors.aliyun.com/centos/7/os/x86
报错1 [root@slave1 data_mocker]# kafka-console-consumer.sh --bootstrap-server slave1:9092 --topic topic_db [2023-12-19 18:31:12,770] WARN [Consumer clie
错误1 # 重写数据 hive (edu)> insert overwrite table dwd_trade_cart_add_inc > select data.id, > data.user_id, > data.course_id, > date_format(
错误1 hive (edu)> insert into huanhuan values(1,'haoge'); Query ID = root_20240110071417_fe1517ad-3607-41f4-bdcf-d00b98ac443e Total jobs = 1
报错1:执行到如下就不执行了,没有显示Successfully registered new MBean. [root@slave1 bin]# /usr/local/software/flume-1.9.0/bin/flume-ng agent -n a1 -c /usr/local/softwa
虚拟及没有启动任何服务器查看jps会显示jps,如果没有显示任何东西 [root@slave2 ~]# jps 9647 Jps 解决方案 # 进入/tmp查看 [root@slave1 dfs]# cd /tmp [root@slave1 tmp]# ll 总用量 48 drwxr-xr-x. 2
报错1 hive> show databases; OK Failed with exception java.io.IOException:java.lang.RuntimeException: Error in configuring object Time taken: 0.474 se
报错1 [root@localhost ~]# vim -bash: vim: 未找到命令 安装vim yum -y install vim* # 查看是否安装成功 [root@hadoop01 hadoop]# rpm -qa |grep vim vim-X11-7.4.629-8.el7_9.x
修改hadoop配置 vi /usr/local/software/hadoop-2.9.2/etc/hadoop/yarn-site.xml # 添加如下 <configuration> <property> <name>yarn.nodemanager.res