digitalmars.D - Writing a Linux driver in the D ecosystem
- Eduard Staniloiu (15/15) Oct 23 2018 Hello, everyone!
- rikki cattermole (6/6) Oct 23 2018 I haven't attempted to do it just yet, but I would like to write up a
- welkam (19/22) Oct 23 2018 Is it possible to write Linux driver in D? Yes.
- welkam (9/15) Oct 23 2018 The only experience I have with C and D linking is DMD compiler.
- sarn (13/16) Oct 23 2018 Hi, I gave this a casual try once. The difficulty is the same
- Eduard Staniloiu (11/28) Oct 25 2018 Thank you all for your replies!
- Eduard Staniloiu (75/105) Oct 29 2018 Hello, everyone!
- Eduard Staniloiu (5/12) Oct 29 2018 Forgot to add link
- sarn (11/12) Oct 30 2018 Do you have the basic hello world module working? (Basically
- Eduard Staniloiu (32/45) Oct 30 2018 Here is the result of running `make`
- Radu (6/28) Oct 30 2018 Have you tried to build it with LDC? You might need to tweak the
- Eduard Staniloiu (24/57) Nov 22 2018 I've come back with an update.
Hello, everyone! We, here at UPB, were thinking if it would be possible to write a simple Linux driver. The long term goal would be to port an existing driver in D. We were wondering if anyone attempted to do this. There are several questions: * how can we build a driver using dmd/gdc/ldc? * how should the makefiles be changed * Is gdc the best option to create an object file that can link with the existing objects (that were generated by using gcc)? * if everything goes well, how can we insert the generated module? Would/Should it just work with insmod? We believe this is an interesting bachelors thesis project. Cheers, Edi
Oct 23 2018
I haven't attempted to do it just yet, but I would like to write up a Windows driver for my keyboard (yay Windows not being totally USB HID compliant). My current solution on D's side is -betterC with dmd (since I am only interested in x86). I'm not sure what the current state of gdc is for -betterC, but for ldc it may work for this purpose, no guarantees.
Oct 23 2018
On Tuesday, 23 October 2018 at 12:06:48 UTC, Eduard Staniloiu wrote:Hello, everyone! We, here at UPB, were thinking if it would be possible to write a simple Linux driver.Is it possible to write Linux driver in D? Yes. If you want to call C code from D then its easy. https://dlang.org/spec/interfaceToC.html If you want to call D code from C then it gets more tricky. Before C can use D code D runtime needs to be initialized by calling this function: https://dlang.org/library/core/runtime/runtime.initialize.html I am not familiar with driver architectures and dont know how convenient it is to add that init call but if its easy then what is left to do is to sprinkle your code with extern (c) and it should link and work. And if its not convenient then there is another option. Writing D code without its runtime. There is a compiler flag -betterC that removes D runtime but you also loose all functionality that depends on runtimes. Now you can write C type libraries with subset of D. Here is article on that. https://dlang.org/spec/betterc.html
Oct 23 2018
On Tuesday, 23 October 2018 at 12:06:48 UTC, Eduard Staniloiu wrote:* how should the makefiles be changed * Is gdc the best option to create an object file that can link with the existing objects (that were generated by using gcc)? * if everything goes well, how can we insert the generated module? Would/Should it just work with insmod?The only experience I have with C and D linking is DMD compiler. Parts of it are still in C and when I tried to compile DMD with clang/ldc and clang/dmd everything linked and worked without any change because both emit C ABI and ELF object files. If you write your code with -betterC and mark your functions with extern (C) the linker should treat your object file as it was compiled from C code
Oct 23 2018
On Tuesday, 23 October 2018 at 12:06:48 UTC, Eduard Staniloiu wrote:Hello, everyone! We, here at UPB, were thinking if it would be possible to write a simple Linux driver.Hi, I gave this a casual try once. The difficulty is the same difficulty you get trying to write Linux kernel modules in C++: the Linux build system is a mess of make files that are only designed for C, and don't represent a stable API between kernel source versions. If I had to write a Linux module in D, I'd write an interface layer in C that gets built using the normal Linux build system and can be linked to my D code. The interface would have to provide alternatives to the various Linux preprocessor macros. (I think trying to refactor the build system to work with dpp would be a total waste of time.)
Oct 23 2018
On Wednesday, 24 October 2018 at 06:36:51 UTC, sarn wrote:On Tuesday, 23 October 2018 at 12:06:48 UTC, Eduard Staniloiu wrote:Thank you all for your replies! We too, had the same feeling that it should be possible to do, based on the ABI and `-betterC`. Our concern was the build system, and how everything can be glued together. Thank you for the thin-layer C interface suggestion; I'll try to give it a go ("Hello, insmod") in the weekend. I'll give an update as soon as I have one. Cheers, EdiHello, everyone! We, here at UPB, were thinking if it would be possible to write a simple Linux driver.Hi, I gave this a casual try once. The difficulty is the same difficulty you get trying to write Linux kernel modules in C++: the Linux build system is a mess of make files that are only designed for C, and don't represent a stable API between kernel source versions. If I had to write a Linux module in D, I'd write an interface layer in C that gets built using the normal Linux build system and can be linked to my D code. The interface would have to provide alternatives to the various Linux preprocessor macros. (I think trying to refactor the build system to work with dpp would be a total waste of time.)
Oct 25 2018
On Thursday, 25 October 2018 at 12:35:56 UTC, Eduard Staniloiu wrote:On Wednesday, 24 October 2018 at 06:36:51 UTC, sarn wrote:Hello, everyone! I am trying to get a simple dummy module to work. I have a simple function written in D, named `call_d`, that I want to call from the `module_init` C function. I had the following plan: * build a .o from the D source file, using `dmd -c -betterC dsrc.d` * add `dsrc.o` to the list of objects in Kbuild * let make do it's magic Based on this stackoverflow Q/A [0], in order to tell Kbuild to use a prebuilt object, the object needs to end in `.o_shipped`; so, I named my `dsrc.o` accordingly -> dsrc.o_shipped Here are my files: // C Module ``` // hellomod.c #include <linux/kernel.h> #include <linux/init.h> #include <linux/module.h> MODULE_DESCRIPTION("My kernel module"); MODULE_AUTHOR("Me"); MODULE_LICENSE("GPL"); static int dummy_init(void) { int r = call_d(); printk( KERN_ALERT "Hi. got %d from D\n", r); return 0; } static void dummy_exit(void) { printk( KERN_ALERT "Bye\n" ); } module_init(dummy_init); module_exit(dummy_exit); ``` // D Source ``` // dsrc.d extern(C) int call_d() { return 10; } ``` // Kbuild ``` EXTRA_CFLAGS = -Wall -g obj-m = hellomod.o hellomod-y = dsrc.o_shipped ``` // Makefile ``` KDIR = /lib/modules/`uname -r`/build kbuild: » make -C $(KDIR) M=`pwd` clean: » make -C $(KDIR) M=`pwd` clean ``` I'm building my dsrc.o_shipped with `dmd -c -betterC dsrc.d -of=dsrc.o_shipped` When I `make` the build, I get the following warning: ``` WARNING: could not find /home/fawkes/ws/dlang/hello/.dsrc.o_shipped.cmd for /home/fawkes/ws/dlang/hello/dsrc.o_shipped ``` The hellomod.ko get's built, but when I `insmod` it, it doesn't print anything at `dmesg`. I don't get a Kernel panic/oops either. I know it's a long post, but any suggestions? Cheers, EdiOn Tuesday, 23 October 2018 at 12:06:48 UTC, Eduard Staniloiu wrote:Thank you all for your replies! We too, had the same feeling that it should be possible to do, based on the ABI and `-betterC`. Our concern was the build system, and how everything can be glued together. Thank you for the thin-layer C interface suggestion; I'll try to give it a go ("Hello, insmod") in the weekend. I'll give an update as soon as I have one. Cheers, EdiHello, everyone! We, here at UPB, were thinking if it would be possible to write a simple Linux driver.Hi, I gave this a casual try once. The difficulty is the same difficulty you get trying to write Linux kernel modules in C++: the Linux build system is a mess of make files that are only designed for C, and don't represent a stable API between kernel source versions. If I had to write a Linux module in D, I'd write an interface layer in C that gets built using the normal Linux build system and can be linked to my D code. The interface would have to provide alternatives to the various Linux preprocessor macros. (I think trying to refactor the build system to work with dpp would be a total waste of time.)
Oct 29 2018
On Monday, 29 October 2018 at 15:51:49 UTC, Eduard Staniloiu wrote:On Thursday, 25 October 2018 at 12:35:56 UTC, Eduard Staniloiu wrote: /* snip */ Based on this stackoverflow Q/A [0], in order to tell Kbuild to use a prebuilt object, the object needs to end in `.o_shipped`; so, I named my `dsrc.o` accordingly -> dsrc.o_shippedForgot to add link [0] - https://stackoverflow.com/questions/6507631/linking-to-a-kernel-module-a-precompiled-object-file
Oct 29 2018
On Monday, 29 October 2018 at 15:51:49 UTC, Eduard Staniloiu wrote:I know it's a long post, but any suggestions?Do you have the basic hello world module working? (Basically your C code minus the call to D code.) If that works, I'd confirm that the module contains what I expect using some basic binary analysis. This will do a disassembly of your module, resolving relocations: objdump -dr hellomod.ko All the functions you've defined should be in the .text section. You should see a call to call_d() in the disassembly of dummy_init().
Oct 30 2018
On Tuesday, 30 October 2018 at 07:24:51 UTC, sarn wrote:On Monday, 29 October 2018 at 15:51:49 UTC, Eduard Staniloiu wrote:Yes, this is working as expected.I know it's a long post, but any suggestions?Do you have the basic hello world module working? (Basically your C code minus the call to D code.)If that works, I'd confirm that the module contains what I expect using some basic binary analysis. This will do a disassembly of your module, resolving relocations: objdump -dr hellomod.ko All the functions you've defined should be in the .text section. You should see a call to call_d() in the disassembly of dummy_init().Here is the result of running `make` ``` make -C /lib/modules/`uname -r`/build M=`pwd` make[1]: Entering directory '/usr/src/linux-headers-4.10.0-28-generic' LD /home/fawkes/ws/dlang/hello/built-in.o LD [M] /home/fawkes/ws/dlang/hello/hellomod.o Building modules, stage 2. MODPOST 1 modules WARNING: could not find /home/fawkes/ws/dlang/hello/.dsrc.o_shipped.cmd for /home/fawkes/ws/dlang/hello/dsrc.o_shipped CC /home/fawkes/ws/dlang/hello/hellomod.mod.o LD [M] /home/fawkes/ws/dlang/hello/hellomod.ko make[1]: Leaving directory '/usr/src/linux-headers-4.10.0-28-generic' ``` And the result of the disassembly, result of `objdump -dr hellomod.ko` ``` hellomod.ko: file format elf64-x86-64 Disassembly of section .text.call_d: 0000000000000000 <call_d>: 0: 55 push %rbp 1: 48 8b ec mov %rsp,%rbp 4: b8 0a 00 00 00 mov $0xa,%eax 9: 5d pop %rbp a: c3 retq ... ```
Oct 30 2018
On Tuesday, 30 October 2018 at 09:10:02 UTC, Eduard Staniloiu wrote:On Tuesday, 30 October 2018 at 07:24:51 UTC, sarn wrote:Have you tried to build it with LDC? You might need to tweak the code generation, for example `-betterC -m64 -nodefaultlib --disable-red-zone -output-o -code-model=large -relocation-model=static`[...]Yes, this is working as expected.[...]Here is the result of running `make` ``` make -C /lib/modules/`uname -r`/build M=`pwd` make[1]: Entering directory '/usr/src/linux-headers-4.10.0-28-generic' LD /home/fawkes/ws/dlang/hello/built-in.o LD [M] /home/fawkes/ws/dlang/hello/hellomod.o Building modules, stage 2. MODPOST 1 modules WARNING: could not find /home/fawkes/ws/dlang/hello/.dsrc.o_shipped.cmd for /home/fawkes/ws/dlang/hello/dsrc.o_shipped CC /home/fawkes/ws/dlang/hello/hellomod.mod.o LD [M] /home/fawkes/ws/dlang/hello/hellomod.ko make[1]: Leaving directory '/usr/src/linux-headers-4.10.0-28-generic' ``` [...]
Oct 30 2018
On Tuesday, 30 October 2018 at 13:22:16 UTC, Radu wrote:On Tuesday, 30 October 2018 at 09:10:02 UTC, Eduard Staniloiu wrote:I've come back with an update. I've managed to make it work with both `dmd` and `ldc`. The issue was how I wrote the `Kbuild` file // Bad Kbuild ``` EXTRA_CFLAGS = -Wall -g obj-m = hellomod.o hellomod-y = dsrc.o_shipped ``` I was under the false impression that `hellomod-y = dsrc.o_shipped` will add the dsrc.o object to the `hellomod.o` object and create the .ko. It doesn't do that. I believe it will only link the dsrc.o and omit the `hellomod.o`. The correct `Kbuild` is // Bad Kbuild ``` EXTRA_CFLAGS = -Wall -g obj-m = mydriver.o hellomod-y = hellomod.o dsrc.o_shipped ``` Now everything works as expected. Thank you all for your support! EdiOn Tuesday, 30 October 2018 at 07:24:51 UTC, sarn wrote:Have you tried to build it with LDC? You might need to tweak the code generation, for example `-betterC -m64 -nodefaultlib --disable-red-zone -output-o -code-model=large -relocation-model=static`[...]Yes, this is working as expected.[...]Here is the result of running `make` ``` make -C /lib/modules/`uname -r`/build M=`pwd` make[1]: Entering directory '/usr/src/linux-headers-4.10.0-28-generic' LD /home/fawkes/ws/dlang/hello/built-in.o LD [M] /home/fawkes/ws/dlang/hello/hellomod.o Building modules, stage 2. MODPOST 1 modules WARNING: could not find /home/fawkes/ws/dlang/hello/.dsrc.o_shipped.cmd for /home/fawkes/ws/dlang/hello/dsrc.o_shipped CC /home/fawkes/ws/dlang/hello/hellomod.mod.o LD [M] /home/fawkes/ws/dlang/hello/hellomod.ko make[1]: Leaving directory '/usr/src/linux-headers-4.10.0-28-generic' ``` [...]
Nov 22 2018