内核模块或用户 space 应用程序
Kernel module or user space application
我进退两难。我不知道以下情况的最佳方法是什么,然后花时间开发内核模块是否有意义。
我有像许多模块(大约 30 个)一样暴露的硬件 (FPGA)。每个模块可以这样定义:
- 模块的基地址;
- 字段的偏移量(从基地址开始);
- 每个模块的最大字段数约为 10;
- 每个字段都有自己的类型,如 uint32_t、float32_t、uint32_t[] 等;
- 某些字段仅 read/write 而其他字段只读;
- 通常一个模块是准备就绪的。我的意思是没有必要实现任何逻辑来检查是否可以写入字段(少数情况除外)。
在目标设备上有一个自定义 Linux 发行版(从 Yocto 构建)。
你觉得哪个更好?
用户 space 中使用 mmap(/dev/mem 映射所有
模块)然后 reads/writes 直接 from/to 内存。我有一个 C++
实施并且它正在运行但也许它不是最好的
解决方案...我需要手动设置所有偏移量,使用许多
reinterpret_cast<> 正确读取数据,如果有的话
错误导致应用程序崩溃;
实现一个字符设备
驱动程序公开每个模块,如 /dev/module1、/dev/module2 等?
并在用户 space open/write/read/release/ioctl 中使用。我刚刚
开始阅读大量关于 Linux 内核开发的手册,我
我不太确定字符设备在这里是否是个好主意,尤其是
如何向用户公开这么多模块和这么多字段space;
- 其他
非常感谢您的任何想法。
使用 /dev/mem
非常简单,但它也会导致一些严重的安全问题。您要么必须 运行 您的应用程序作为 root,要么使 /dev/mem
文件可供其他用户访问,这在设计中都是不受欢迎的,在某些时候将成为产品。如果恶意进程可以访问 /dev/mem
文件,它可能会访问存储在 RAM 中的任何秘密或破坏任何应用程序 - 包括内核本身。即使您的应用程序是唯一能够访问此文件的应用程序,您代码的任何安全问题都会成为整个系统的安全问题。
准备驱动程序显然不是一件容易的事,但允许您将(通常是简单的)特权代码与用户 space 中的应用程序分开。在最简单的情况下,您只需提供一些寄存器读写方法(通过 ioctl)。这些应该检查地址是否对齐并约束到设备地址 space。此外,驱动程序通常会执行任何额外的地址转换 - 因此客户端应用程序不需要知道您的设备映射到哪个物理地址(例如 PCI Express 就是这种情况)。
我不建议从头开始编写驱动程序,而是重新利用一些现有代码。在提到的 PCI Express 案例中,我使用了两个灵感来源 - 此处描述的 Xilinx 驱动程序:https://www.xilinx.com/support/answers/65444.html (sources included) and more complicated 'pcieuni' and 'gpcieuni' from ChimeraTk project (https://github.com/ChimeraTK).
我进退两难。我不知道以下情况的最佳方法是什么,然后花时间开发内核模块是否有意义。
我有像许多模块(大约 30 个)一样暴露的硬件 (FPGA)。每个模块可以这样定义:
- 模块的基地址;
- 字段的偏移量(从基地址开始);
- 每个模块的最大字段数约为 10;
- 每个字段都有自己的类型,如 uint32_t、float32_t、uint32_t[] 等;
- 某些字段仅 read/write 而其他字段只读;
- 通常一个模块是准备就绪的。我的意思是没有必要实现任何逻辑来检查是否可以写入字段(少数情况除外)。
在目标设备上有一个自定义 Linux 发行版(从 Yocto 构建)。
你觉得哪个更好?
用户 space 中使用 mmap(/dev/mem 映射所有 模块)然后 reads/writes 直接 from/to 内存。我有一个 C++ 实施并且它正在运行但也许它不是最好的 解决方案...我需要手动设置所有偏移量,使用许多 reinterpret_cast<> 正确读取数据,如果有的话 错误导致应用程序崩溃;
实现一个字符设备 驱动程序公开每个模块,如 /dev/module1、/dev/module2 等? 并在用户 space open/write/read/release/ioctl 中使用。我刚刚 开始阅读大量关于 Linux 内核开发的手册,我 我不太确定字符设备在这里是否是个好主意,尤其是 如何向用户公开这么多模块和这么多字段space;
- 其他
非常感谢您的任何想法。
使用 /dev/mem
非常简单,但它也会导致一些严重的安全问题。您要么必须 运行 您的应用程序作为 root,要么使 /dev/mem
文件可供其他用户访问,这在设计中都是不受欢迎的,在某些时候将成为产品。如果恶意进程可以访问 /dev/mem
文件,它可能会访问存储在 RAM 中的任何秘密或破坏任何应用程序 - 包括内核本身。即使您的应用程序是唯一能够访问此文件的应用程序,您代码的任何安全问题都会成为整个系统的安全问题。
准备驱动程序显然不是一件容易的事,但允许您将(通常是简单的)特权代码与用户 space 中的应用程序分开。在最简单的情况下,您只需提供一些寄存器读写方法(通过 ioctl)。这些应该检查地址是否对齐并约束到设备地址 space。此外,驱动程序通常会执行任何额外的地址转换 - 因此客户端应用程序不需要知道您的设备映射到哪个物理地址(例如 PCI Express 就是这种情况)。
我不建议从头开始编写驱动程序,而是重新利用一些现有代码。在提到的 PCI Express 案例中,我使用了两个灵感来源 - 此处描述的 Xilinx 驱动程序:https://www.xilinx.com/support/answers/65444.html (sources included) and more complicated 'pcieuni' and 'gpcieuni' from ChimeraTk project (https://github.com/ChimeraTK).