WSL下添加系统调用
由于WSL的内核是在原版基础之上有做修改的,所以要先去下载内核的源码。https://github.com/microsoft/WSL2-Linux-Kernel.
查看当前系统内核版本
然后去源码中找到对应的版本并下载,下载完成后解压。
1 2
| tar -zvxf linux-msft-wsl-5.15.90.1.tar.gz cd WSL2-Linux-Kernel-linux-msft-wsl-5.15.90.1
|
新增系统调用号
在arch/x86/include/generated/uapi/asm/unistd_64.h中添加系统调用号
1
| #define __NR_my_func 335
|
注意这里的系统调用号可以随便取,但一定要是唯一的,不然会报错。my_func
是系统调用名。
修改系统调用向量表
修改arch/x86/entry/syscalls/syscall_64.tbl文件
1
| 335 64 my_oper sys_my_func
|
此处的系统调用号必须与之前声明的保持一致,my_func
为调用函数名,sys_my_func
为实际调用的函数。
添加系统调用的声明
在include/linux/syscalls.h中添加
1
| asmlinkage long sys_my_func(int count);
|
其中asmlinkage
是一个宏,用于声明函数的调用方式,long
是返回值类型,sys_my_func
为函数名,int count
为函数参数。
添加具体实现
在kernel/sys.c中添加
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61
| long my_oper(int *result, int num1, int num2, char *op) { if(op) { if(*op == '+') *result = num1 + num2; else if(*op == '-') *result = num1 - num2; else if(*op == '*') *result = num1 * num2; else if(*op == '\\') { if(num2 != 0) *result = num1 / num2; else printk("divided number can't bere zero.\n"); } } else printk("operator is empty.\n"); return 0; }
SYSCALL_DEFINE1(my_func, int, count) { printk("count is %d\n", count); struct timespec64 tstart, tend; ktime_get_real_ts64(&tstart); int i, result, times = count / 4; for(i = 0; i < times; ++i) { char op_add = '+'; my_oper(&result, 10, 10, &op_add); } printk("my_func op_add is ok. op_add count is :%d", i); for(i = 0; i < times; ++i) { char op_sub = '-'; my_oper(&result, 20, 10, &op_sub); } printk("my_func op_sub is ok. op_sub count is :%d", i);
for(i = 0; i < times; ++i) { char op_mul = '*'; my_oper(&result, 10, 10, &op_mul); } printk("my_func op_mul is ok. op_mul count is :%d", i);
for(i = 0; i < times; ++i) { char op_div = '\\'; my_oper(&result, 20, 10, &op_div); } printk("my_func op_div is ok. op_div count is :%d", i); ktime_get_real_ts64(&tend); printk("my_func running time is %ld usec/n", 1000000000 * (tend.tv_sec-tstart.tv_sec) + (tend.tv_nsec-tstart.tv_nsec)); return 0; }
|
DEFINE后面的数字是传入的参数个数,这里是1个,所以是1。my_func
是系统调用名,count
是传入的参数。
注意:函数实现不要写在条件编译的范围内。
编译内核
编译内核需要.config配置文件,可以通过make menuconfig
生成,也可以直接复制现有的.config文件。这里使用make menuconfig
生成。
![](/img/Linux/make-menuconfig.png)
make menuconfig
会打开一个配置界面,这里不需要修改别的配置,只需要修改内核版本号,以便与现在的内核区分开,然后保存退出。
编译内核
编译完成后,生成的内核文件在项目目录arch/x86/boot下面,文件名为
bzImage。
替换内核
将内核文件bzImage从wsl系统中拷贝出来,放在windows文件系统中任意路径下,例如C:_usr_kernel
然后进入C:.wslconfig 的文件,添加如下内容:
1 2
| [wsl2] kernel=C:\\wsl_usr_kernel\\bzImage
|
注意双反斜杠,否则不生效。然后在powershell中执行
重启wsl系统,查看内核版本
可以看到内核版本已经变成了我们刚刚编译的版本。
如果要恢复原来的内核,只需要删除.wslconfig文件,然后执行wsl --shutdown
重启wsl系统即可。