Wednesday, February 23, 2022

[SOLVED] Kernel module or user space application

Issue

I have a dilemma. I do not know what is the best approach to the following scenario and then if it makes sense to invest time on developing a kernel module.

I have hardware (FPGA) that is exposed like many modules (around 30). Each module can be defined like:

  • Base address of the module;
  • Fields' offset (from base address);
  • The maximum number of fields per modules is around 10;
  • Each field has its own type like uint32_t, float32_t, uint32_t[] etc;
  • Some fields are read/write only and other read only;
  • Usually a module is ready as is. I mean that it is not necessary to implement any logic to check if it is possible to write to a field (except in few cases).

On the target device there is a custom Linux distribution (built from Yocto).

What do you think is better?

  1. Application in user space that uses mmap (/dev/mem to map all modules) and then reads/writes directly from/to memory. I have a C++ implementation and it is working but maybe it is not the best solution... I need to set manually all offsets, using many reinterpret_cast<> to read data properly and if something it is wrong the application crashes;

  2. Implement a character device driver to expose each module like /dev/module1, /dev/module2 etc? and use in user space open/write/read/release/ioctl. I have just started to read a huge manual about Linux kernel development and I am not so sure if a character device is a good idea here, especially how to expose so many modules with so many fields to user space;

  3. Other.

Thank you a lot for any ideas.


Solution

Using /dev/mem is quite straightforward, however it also causes some serious security issues. You either have to run your application as root or make the /dev/mem file accessible for other users, which are both unwelcome in designs that at some point will become products. If a malicious process can access the /dev/mem file it can possibly access any secret stored in RAM or corrupt any application - including the kernel itself. Even if your application is the only one able to access this file, any security concern of your code becomes the security concern of the whole system.

Preparing the driver is obviously not an easy task, but allows you to separate the (usually simple) privileged code from the applications in user space. In a simplest case you only have to provide some register read and write methods (through ioctl). These should check if the address is well aligned and constrained to the device address space. Additionally, the driver usually performs any additional address translation - so the client application does not need to know under which physical address was your device mapped (which is the case e.g. with PCI Express).

I would not recommend writing the driver from scratch, but to repurpose some existent code. In the mentioned case of PCI Express I have used two sources of inspiration - the Xilinx driver described here: https://www.xilinx.com/support/answers/65444.html (sources included) and more complicated 'pcieuni' and 'gpcieuni' from ChimeraTk project (https://github.com/ChimeraTK).



Answered By - Olek
Answer Checked By - Dawn Plyler (WPSolving Volunteer)