我有一个 hello world 内核模块的源代码,它可以在笔记本电脑的 Ubuntu 20 中运行。现在我尝试在 Ubuntu 20 中但在 WSL2 中编译相同的代码。为此,我正在使用这个:
make -C /sys/modules/$(shell uname -r)/build M=$(PWD) modules
问题是那/lib/modules
是空的。看来WSL2没有带来任何东西/lib/modules/4.19.104-microsoft-standard/build
我尝试使用以下方式获取标题:
sudo apt search linux-headers-`uname -r`
Sorting... Done
Full Text Search... Done
但模块文件夹中没有填充任何内容
我需要做什么才能使该文件夹包含所有必需的模块?
[编辑]
感谢@HannahJ,让我们更加接近。
我在做:
> sudo make -C /home/<user>/WSL2-Linux-Kernel M=$(pwd) modules
SL2-Linux-Kernel M=$(pwd) modules
make: Entering directory '/home/<user>/WSL2-Linux-Kernel'
CC [M] /home/<user>/containers-assembly-permissionsdemo/demo-2/lkm_example.o
Building modules, stage 2.
MODPOST 1 modules
CC /home/<user>/containers-assembly-permissionsdemo/demo-2/lkm_example.mod.o
LD [M] /home/<user>/containers-assembly-permissionsdemo/demo-2/lkm_example.ko
make: Leaving directory '/home/<user>/WSL2-Linux-Kernel'
最后,我lkm_example.ko
创建了文件。
在那之后:
> sudo insmod lkm_example.ko
insmod: ERROR: could not insert module lkm_example.ko: Invalid module format
> dmesg
[200617.480635] lkm_example: no symbol version for module_layout
[200617.480656] lkm_example: loading out-of-tree module taints kernel.
[200617.481542] module: x86/modules: Skipping invalid relocation target, existing value is nonzero for type 1, loc 0000000074f1d70f, val ffffffffc0000158
> sudo modinfo lkm_example.ko
filename: /home/<user>/containers-assembly-permissionsdemo/demo-2/lkm_example.ko
version: 0.01
description: A simple example Linux module.
author: Carlos Garcia
license: GPL
srcversion: F8B272146BAA2381B6332DE
depends:
retpoline: Y
name: lkm_example
vermagic: 4.19.84-microsoft-standard+ SMP mod_unload modversions
这是我的 Makefile
obj-m += lkm_example.o
all:
make -C /home/<usr>/WSL2-Linux-Kernel M=$(PWD) modules
clean:
make -C /home/<usr>/WSL2-Linux-Kernel M=$(PWD) clean
test:
# We put a — in front of the rmmod command to tell make to ignore
# an error in case the module isn’t loaded.
-sudo rmmod lkm_example
# Clear the kernel log without echo
sudo dmesg -C
# Insert the module
sudo insmod lkm_example.ko
# Display the kernel log
dmesg
unload:
sudo rm /dev/lkm_example
sudo rmmod lkm_example
[Edit2] 这是我的内核模块:
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <asm/uaccess.h>
#include <linux/init_task.h>
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Carlos Garcia");
MODULE_DESCRIPTION("A simple example Linux module.");
MODULE_VERSION("0.01");
/* Prototypes for device functions */
static int device_open(struct inode *, struct file *);
static int device_release(struct inode *, struct file *);
static ssize_t device_read(struct file *, char *, size_t, loff_t *);
static ssize_t device_write(struct file *, const char *, size_t, loff_t *);
static int major_num;
static int device_open_count = 0;
static char msg_buffer[MSG_BUFFER_LEN];
static char *msg_ptr;
/* This structure points to all of the device functions */
static struct file_operations file_ops = {
.read = device_read,
.write = device_write,
.open = device_open,
.release = device_release
};
/* When a process reads from our device, this gets called. */
static ssize_t device_read(struct file *flip, char *buffer, size_t len, loff_t *offset)
{
...
}
/* Called when a process tries to write to our device */
static ssize_t device_write(struct file *flip, const char *buffer, size_t len, loff_t *offset)
{
...
}
/* Called when a process opens our device */
static int device_open(struct inode *inode, struct file *file)
{
...
try_module_get(THIS_MODULE);
}
/* Called when a process closes our device */
static int device_release(struct inode *inode, struct file *file)
{
...
module_put(THIS_MODULE);
}
static int __init lkm_example_init(void)
{
...
major_num = register_chrdev(0, "lkm_example", &file_ops);
if (major_num < 0)
{
printk(KERN_ALERT "Could not register device: % d\n", major_num);
return major_num;
}
else
{
printk(KERN_INFO "lkm_example module loaded with device major number % d\n", major_num);
return 0;
}
}
static void __exit lkm_example_exit(void)
{
/* Remember — we have to clean up after ourselves. Unregister the character device. */
unregister_chrdev(major_num, DEVICE_NAME);
printk(KERN_INFO "Goodbye, World !\n");
}
/* Register module functions */
module_init(lkm_example_init);
module_exit(lkm_example_exit);
答案1
我必须为一项作业执行此操作,所以我想我会在这里分享我的解决方案。
基础 WSL2 内核不允许加载模块。您必须编译并使用您自己的内核版本。
如何在 WSL2 中编译和使用内核
在 Ubuntu/WSL 中:
sudo apt install build-essential flex bison libssl-dev libelf-dev git dwarves git clone https://github.com/microsoft/WSL2-Linux-Kernel.git cd WSL2-Linux-Kernel cp Microsoft/config-wsl .config make -j $(expr $(nproc) - 1)
从 Windows 中,复制
\\wsl$\<DISTRO>\home\<USER>\WSL2-Linux-Kernel\arch\x86\boot\bzimage
到您的 Windows 配置文件(%userprofile%
,例如C:\Users\<Windows_user>
)创建包含以下内容的文件
%userprofile%\.wslconfig
:[wsl2] kernel=C:\\Users\\WIN10_USER\\bzimage
注意:双反斜杠 (
\\
) 是必需的。另外,为了避免潜在的旧错误,请确保不要在任何一行上留下任何尾随空格。在 PowerShell 中,运行
wsl --shutdown
重新开启您的 WSL2 风味
如何编译模块
注意:您需要从 Makefile 执行这些操作/home/$USER/
或调整 Makefile 以匹配您的位置。
创建一个
Makefile
包含:obj-m:=lkm_example.o all: make -C $(shell pwd)/WSL2-Linux-Kernel M=$(shell pwd) modules clean: make -C $(shell pwd)/WSL2-Linux-Kernel M=$(shell pwd) clean
跑步
make
.wslconfig
文件步骤的来源这里。
答案2
适用于 Linux 版本 2 的 Windows 子系统使用 Microsoft 的自定义 Linux 内核,其中包含编译的所有驱动程序。虽然它支持模块,但它不包含任何模块,正如您可以从配置文件。因此,没有理由发送/lib/modules
目录。
此外,大多数可用于 WSL 的 Linux 发行版根本不附带内核的 WSL 版本。由于微软推出了自己的产品,因此没有理由这样做。这些 Linux 发行版不提供 Microsoft 内核的构建包,因为他们不对此负责; Microsoft 是,您需要与他们讨论这些软件包。
如果您使用标准工具,您可能可以将模块加载到内核中,但您可能需要针对适当的源代码树进行构建。您可以尝试在我上面链接到的 GitHub 存储库中找到合适的版本,或者您可能需要联系 Microsoft 并询问 GPLv2 下的源代码,他们需要根据要求向您提供该源代码。
我要指出的是,WSL 的设计目的不是允许加载自定义内核模块;它并不是被设计成一个完整的 Linux 环境,而是允许人们在 Windows 上开发和运行标准的 Linux 应用程序。如果您想要进行 Linux 内核开发,您可能需要完整的 Linux 安装。
答案3
对于那些需要在 WSL2 上加载模块的人:
sudo -e /etc/modules-load.d/modules.conf
(或您首选的编辑器sudo
)- 添加您想要加载的内核模块的名称,每个模块一行。
- 退出 WSL。
- 从 PowerShell 或 CMD 运行
wsl --shutdown
. - 重新启动 WSL。你的模块应该已经加载。
在 WSL2 Ubuntu Focal 上测试。
答案4
我试图做一个 Yocto 构建,它在 Ubuntu 22.04 本机上运行良好,但在 WSL2 上失败,因为它找不到/lib/modules/5.15.90.1-microsoft-standard-WSL2
:
murata-wireless/cyw-fmac - WSL2 上的构建失败
我最终找到了这个解决方法:
sudo apt-get install -y linux-headers-generic
ll /lib/modules
# Note the directory that has been installed here, e.g. `5.15.0-67-generic/
# Use "uname -r" or note the directory the build above failed to find, e.g. `/lib/modules/5.15.90.1-microsoft-standard-WSL2`
sudo ln -s /lib/modules/5.15.0-67-generic /lib/modules/5.15.90.1-microsoft-standard-WSL2
更新:对 WSL2 的更新可能会破坏此问题,因为目录名称可能会更改,例如 5.15.0-67-generic/ 升级到 5.15.0-69-generic/。我创建了一个脚本来自动执行此操作:
#!/bin/bash
set -e
WSL2_VERSION=$(uname -r)
echo "WSL2_VERSION = $WSL2_VERSION"
WSL2_LINK="/lib/modules/$WSL2_VERSION"
if [ -L "${WSL2_LINK}" ]; then
if [ -e "${WSL2_LINK}" ]; then
echo "Good link"
exit 0
else
echo "Broken link"
rm "${WSL2_LINK}"
fi
elif [ -e "${WSL2_LINK}" ]; then
echo "Not a link"
exit 1
else
echo "Missing"
fi
shopt -s nullglob
for filename in /lib/modules/*; do
echo "$filename"
if [ -z "$HEADERS_DIR" ]; then
HEADERS_DIR="$filename"
else
echo "HEADERS_DIR already set to $HEADERS_DIR, fail"
exit 1
fi
done
if [ -n "$HEADERS_DIR" ]; then
echo "Create symbolic link $WSL2_LINK => $HEADERS_DIR"
ln -s "$HEADERS_DIR" "$WSL2_LINK"
fi