注释掉一个printk 语句会导致Linux 设备驱动程序测试崩溃

陈金

我在一个简单的 linux 驱动程序测试(arm64)中看到了一个奇怪的案例。
用户程序调用设备驱动程序的 ioctl 并将 uint64_t 的数组 'arg' 作为参数传递。顺便说一下,arg[2] 包含一个指向应用程序中变量的指针。下面是代码片段。

    case SetRunParameters:
        copy_from_user(args, (void __user *)arg, 8*3);
        offs = args[2] % PAGE_SIZE;
        down_read(&current->mm->mmap_sem);
        res = get_user_pages( (unsigned long)args[2], 1, 1, &pages, NULL);
        if (res) {
            kv_page_addr = kmap(pages);
            kv_addr = ((unsigned long long int)(kv_page_addr)+offs);
            args[2] = page_to_phys(pages) + offset; // args[2] changed to physical
        }
        else {
            printk("get_user_pages failed!\n");
        }
        up_read(&current->mm->mmap_sem);
        *(vaddr + REG_IOCTL_ARG/4) = virt_to_phys(args);  // from axpu_regs.h
        printk("ldd:writing %x at %px\n",cmdx,vaddr + REG_IOCTL_CMD/4); // <== line 248. not ok w/o this printk line why?..
        *(vaddr + REG_IOCTL_CMD/4) = cmdx;  // this command is different from ioctl cmd!
        put_page(pages); //page_cache_release(page);
        break;
    case ...

我在上面的代码中标记了第 248 行。如果我在那里注释掉 printk,则会出现陷阱并且虚拟机崩溃(我在 qemu 虚拟机上执行此操作)。cmdx是根据来自应用程序的ioctl命令一个整数值组,并且vaddr是设备(来自的ioremap获得)的虚拟地址。如果我保留printk,它会按我的预期工作。什么情况下可以做到这一点?(缓存还是 tlb?)

伊恩·阿博特

通过简单的 C 结构访问内存映射寄存器*(vaddr + REG_IOCTL_ARG/4)是一个坏主意。如果访问是volatile合格的,您可能会在某些平台上逃脱,但在某些平台上它不会可靠地工作或根本无法工作。访问内存映射寄存器的正确方法是通过#include <asm/io.h>声明的函数#include <linux/io.h>这些将处理任何特定于架构的要求,以确保就 CPU 而言,写入的顺序正确1

内存映射寄存器访问的函数在 Linux 内核文档中的Bus-Independent Device Accesses下进行了描述

这段代码:

        *(vaddr + REG_IOCTL_ARG/4) = virt_to_phys(args);
        *(vaddr + REG_IOCTL_CMD/4) = cmdx;

可以改写为:

        writel(virt_to_phys(args), vaddr + REG_IOCTL_ARG/4);
        writel(cmdx, vaddr + REG_IOCTL_CMD/4);

1如果寄存器写入的顺序很重要,则特定总线类型(例如 PCI)的写入顺序可能需要额外的代码来读取不同寄存器写入之间的寄存器。这是因为写入是异步“发布”到 PCI 总线的,并且 PCI 设备可能会乱序处理对不同寄存器的写入。在处理完所有先前的写入之前,设备不会处理中间寄存器读取,因此它可用于强制执行发布写入的顺序。

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章

写入Linux设备驱动程序会导致无限循环

如何使用设备树在一个Linux内核驱动程序中映射两个设备的资源?

是否可以编写一个应用程序来接口和激活底层的Linux内核设备驱动程序?

具有多个设备属性的Linux驱动程序链接到同一功能

可以在Linux中注册多个驱动程序以处理同一设备

一个简单的字符设备驱动程序

Linux设备驱动程序访问控制

IOCTL Linux设备驱动程序

Linux字符设备驱动程序问题

linux 设备驱动程序文档

尝试第一个日志语句时(如果不是管理员),Boost Log会导致崩溃

如何制作一个/a(API 或驱动程序)来处理 Linux 中 USB 设备端的所有 USB 串行请求?

Linux:如何查找用于设备的设备驱动程序?

如果两个不同的Linux Distro使用相同的内核,它们将支持相同的设备驱动程序吗?

GTX 760 SLI导致驱动程序故障并偶尔崩溃

崩溃导致驱动程序版本不匹配的glsl扩展

如何调试导致内核崩溃的驱动程序?

Linux内核驱动程序模块:使用单个驱动程序处理多个设备文件

Linux平台驱动程序和普通设备驱动程序有什么区别?

Django测试登录失败,除非注释掉或重命名了一个完全无关的,完全琐碎的功能

AMD驱动程序使Linux Mint 17 Cinnamon崩溃

Linux是否具有USB端口的设备驱动程序?

Linux:以独立方式编译内核设备驱动程序

长时间写入linux char设备驱动程序?

Linux 中的字符设备驱动程序读/写

raspberry pi:编写Linux设备驱动程序

Linux设备驱动程序:重温睡眠锁定

如何编写简单的Linux设备驱动程序?

如何练习编写真正的Linux设备驱动程序?