Friday, March 9, 2018

BSD Kernel Hacking - Part 2 (character pseudo-devices)

Continuing on from the last post, I now tackle character devices. It turns out that OpenBSD is quite a lot different than FreeBSD in the way that devices are registered. To begin, I need to set up a cdevsw entry for the new device. Rather than defining the struct directly in the implementation code, it is implemented via a macro which is called in the cdevsw struct definition in sys/arch/amd64/amd64/conf.c

As opposed to FreeBSD, the cdevsw structs are built out by a macro, this macro will take the number of devices being initialized, and the name of the module passed to it (e.g. "cdev_example_init(1, example)") and fill out struct cdevsw to point to the appropriate functions via name concatenation (e.g. the open function will be registered as exampleopen).

I begin by adding a cdev_example_init macro to sys/sys/conf.h, then call the macro within the cdevsw[] array in sys/arch/amd64/amd64/conf.c. Also, while I'm in here, I add a call to the cdev_decl() macro. This should take care of the cdevsw setup portion of the code.

From there, I add example.c under sys/dev/ and build out basic open, close, read, and write functions for it, and add it to files.conf. Much to my surprise, after fixing a few compile errors for missing headers, the kernel compiles and installs fine. Once the machine had booted into my new kernel, I ran a "doas mknod /dev/example c 98 0" to create a node for the device in /dev. In this case, 98 was the position in the cdevsw[] array where my call to cdev_exampl_init landed. In OpenBSD, the major node number is simply an index into the cdevsw array.

I had to switch from using copystr to uiomove in order to get I/O working properly, but once I did, the basic interface code worked fine.

Finally, I decided to work with the MAKEDEV script to ensure that my device would be present in a release, if I so chose to make one. The script required me to add a new case for "example)" with a call to the M function and a few parameters to set the device node name, Major/Minor numbers, permissions, and ownership. In order for etc/etc.amd64/MAKEDEV to be copied to /dev by sysmerge, I had to do a full build of the system. This is a bit time consuming, and there might be a better way, but it worked for my immediate purposes.

No comments:

Post a Comment