Jump to page: 1 2
Thread overview
Writing a Linux driver in the D ecosystem
Oct 23, 2018
Eduard Staniloiu
Oct 23, 2018
rikki cattermole
Oct 23, 2018
welkam
Oct 23, 2018
welkam
Oct 24, 2018
sarn
Oct 25, 2018
Eduard Staniloiu
Oct 29, 2018
Eduard Staniloiu
Oct 29, 2018
Eduard Staniloiu
Oct 30, 2018
sarn
Oct 30, 2018
Eduard Staniloiu
Oct 30, 2018
Radu
Nov 22, 2018
Eduard Staniloiu
October 23, 2018
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
October 24, 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.
October 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

October 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
October 24, 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.)
October 25, 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:
>> 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.)

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,
Edi
October 29, 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:
>> 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.)
>
> 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,
> Edi

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,
Edi
October 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_shipped
>

Forgot to add link
[0] - https://stackoverflow.com/questions/6507631/linking-to-a-kernel-module-a-precompiled-object-file


October 30, 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().
October 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:
>> 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.)

Yes, this is working as expected.

>
> 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
	...
```
« First   ‹ Prev
1 2