WSL 2 没有 /lib/modules/

WSL 2 没有 /lib/modules/

我有一个 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 中编译和使用内核

  1. 在 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)
    
  2. 从 Windows 中,复制\\wsl$\<DISTRO>\home\<USER>\WSL2-Linux-Kernel\arch\x86\boot\bzimage到您的 Windows 配置文件(%userprofile%,例如C:\Users\<Windows_user>

  3. 创建包含以下内容的文件%userprofile%\.wslconfig

    [wsl2]
    kernel=C:\\Users\\WIN10_USER\\bzimage
    

    注意:双反斜杠 ( \\) 是必需的。另外,为了避免潜在的旧错误,请确保不要在任何一行上留下任何尾随空格。

  4. 在 PowerShell 中,运行wsl --shutdown

  5. 重新开启您的 WSL2 风味

如何编译模块

注意:您需要从 Makefile 执行这些操作/home/$USER/或调整 Makefile 以匹配您的位置。

  1. 创建一个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
    
  2. 跑步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 上加载模块的人:

  1. sudo -e /etc/modules-load.d/modules.conf(或您首选的编辑器sudo
  2. 添加您想要加载的内核模块的名称,每个模块一行。
  3. 退出 WSL。
  4. 从 PowerShell 或 CMD 运行wsl --shutdown.
  5. 重新启动 WSL。你的模块应该已经加载。

在 WSL2 Ubuntu Focal 上测试。

答案4

我试图做一个 Yocto 构建,它在 Ubuntu 22.04 本机上运行良好,但在 WSL2 上失败,因为它找不到/lib/modules/5.15.90.1-microsoft-standard-WSL2murata-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

相关内容