WSL2でカーネルモジュールを作る

Linux driver について学習したいけど、LinuxPCは無いし、VirtualBoxやDualbootは起動に手間がかかるので、お手軽にWSL2でドライバを作ってみました。

※環境：Windows10

##### 1. WSLのバージョンを確認
powershellで以下を実行。
```text:powershell
PS C:\WINDOWS\system32> wsl -l -v
  NAME              STATE           VERSION
* Ubuntu20.04LTS    Running         2
PS C:\WINDOWS\system32>
```

VERSION が1であれば、```wsl --set-default-version 2``` で WSL2 へ update する。
（Windowsの再起動やBIOS設定の変更が必要かも）

##### 2. WSL2のカーネルバージョンを確認

```text:
$ uname -r
5.10.60.1-microsoft-standard-WSL2+
```
##### 3. WSL2カーネルソースの取得・ビルド
最終的に以下のフォルダ構成を目指します。
```text:
$ tree -d -L 2
.
└── linux_driver
    ├── WSL2-Linux-Kernel
    └── hello
```
親Dirを作成、kernel source を取得。
```text:
$ mkdir linux_driver
$ cd linux_driver
$ git clone https://github.com/microsoft/WSL2-Linux-Kernel.git
```
clone が完了したら、branch をWSL2のカーネルバージョンと同じtagへcheckoutする。

```text:
$ cd WSL2-Linux-Kernel
$ git tag -l | grep 5.10
linux-msft-wsl-5.10.102.1
linux-msft-wsl-5.10.16.3
linux-msft-wsl-5.10.43.3
linux-msft-wsl-5.10.60.1
linux-msft-wsl-5.10.74.3
linux-msft-wsl-5.10.81.1
linux-msft-wsl-5.10.93.2
v2.6.25.10
v2.6.35.10
v3.15.10
v4.15.10
$ git checkout linux-msft-wsl-5.10.60.1
$ git branch
* (HEAD detached at linux-msft-wsl-5.10.60.1)
  linux-msft-wsl-5.10.y
```
##### 4. カーネルのビルド

```text:
$ sudo install build-essential flex bison libssl-dev libelf-dev
$ cd WSL2-Linux-Kernel
$ cp Microsoft/config-ws .config
$ make
```
　→　make でエラーが起きたため、```make menuconfig``` が必要だった。
```text:
$ sudo apt-get install libncurses-dev
$ make menuconfig
```
特に何もいじらず、saveしてexit。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/146096/879aa5e1-7ac0-edf8-fbca-902937bcecbd.png)

makeをリトライ。
```text:
$ make
```
※30分くらいかかります

##### 5. WSL2のカーネル設定をupdate
ビルド成果物をWindowsへコピー。
```text:
$ sudo cp arch/x86_64/boot/bzImage /mnt/c/Users/ユーザー名
```
以下の内容の .wslconfig を作成、C:Users/ユーザー名 へ保存。
```text:
[wsl2]
kernel=C:\\Users\\ユーザー名\\bzImage
```
管理者権限でpowershellを起動、wslを再起動
```text:powershell
wsl --shutdown
```

##### 6. Linuxドライバの作成
```text:
$ mkdir hello
$ cd hello
```
以下のhello.cとMakefileを作成する。
```c:hello.c
#include <linux/module.h>

static int hello_init(void)
{
    printk("hello world.\n");
    return 0;
}

static void hello_exit(void)
{
    printk("Goodbye, cruel world.\n");
}

module_init(hello_init);
module_exit(hello_exit);
```
```makefile:Makefile
obj-m := hello.o

all:
        make -C ../WSL2-Linux-Kernel M=`pwd` modules
clean:
        make -C ../WSL2-Linux-Kernel M=`pwd` clean
```
※MakefileはTab文字インデントなので注意

makeを実行。
```text:
$ make
make -C ../WSL2-Linux-Kernel M=`pwd` modules
make[1]: Entering directory '/home/fokko/linux_driver/WSL2-Linux-Kernel'
  CC [M]  /home/fokko/linux_driver/hello/hello.o
  MODPOST /home/fokko/linux_driver/hello/Module.symvers
WARNING: modpost: missing MODULE_LICENSE() in /home/fokko/linux_driver/hello/hello.o
  CC [M]  /home/fokko/linux_driver/hello/hello.mod.o
  LD [M]  /home/fokko/linux_driver/hello/hello.ko
make[1]: Leaving directory '/home/fokko/linux_driver/WSL2-Linux-Kernel'
```
hello.ko が出来ていれば成功。
```text:
fokko@Fokko:~/linux_driver/hello$ ls
Makefile  Module.symvers  hello.c  hello.ko  hello.mod  hello.mod.c  hello.mod.o  hello.o  modules.order
fokko@Fokko:~/linux_driver/hello$
```

hello.ko の対象カーネルがWSL2のカーネルと同じかチェック。
```text:
$ modinfo hello.ko
filename:       /home/fokko/linux_driver/hello/hello.ko
srcversion:     D0AC9F814F54BCA6F71E701
depends:
retpoline:      Y
name:           hello
vermagic:       5.10.60.1-microsoft-standard-WSL2+ SMP mod_unload modversions
fokko@Fokko:~/linux_driver/hello$
```
insmod/rmmod で driver を登録。
```text:
$ sudo insmod hello.ko
$ sudo rmmod hello
```
dmesg で hello/goodbye が出力されればOK。
```text:
$ dmesg | tail
[   64.310628] WSL2: Performing memory compaction.
[  365.318054] WSL2: Performing memory compaction.
[  426.326189] WSL2: Performing memory compaction.
[  547.332114] WSL2: Performing memory compaction.
[  612.340814] WSL2: Performing memory compaction.
[ 1528.597697] hello: loading out-of-tree module taints kernel.
[ 1528.597725] hello: module license 'unspecified' taints kernel.
[ 1528.597727] Disabling lock debugging due to kernel taint
[ 1586.862607] hello world.
[ 1590.233958] Goodbye, cruel world.
```
##### 追伸:
最初、insmod で ```insmod: ERROR: could not insert module hello.ko: Invalid module format``` というエラーが出て悩んでいましたが、"5. WSL2のカーネル設定をupdate" を行って解決できました。
参考：https://unix.stackexchange.com/questions/594470/wsl-2-does-not-have-lib-modules