WSL 2에는 /lib/modules/가 없습니다.

WSL 2에는 /lib/modules/가 없습니다.

내 노트북의 Ubuntu 20에서 실행되는 hello world 커널 모듈의 소스 코드가 있습니다. 이제 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

[편집 2] 이것은 내 커널 모듈입니다.

    #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. 우분투/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\bzimageWindows 프로필에 복사합니다( %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 버전의 커널이 전혀 제공되지 않습니다. Microsoft가 자체 제품을 출시하기 때문에 이렇게 할 이유가 없습니다. 이러한 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-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

관련 정보