Skip to content

Instantly share code, notes, and snippets.

@pranav083
Last active May 14, 2025 01:48
Show Gist options
  • Save pranav083/9dd30f1aef00cf9ec5a43d6c59b99b2d to your computer and use it in GitHub Desktop.
Save pranav083/9dd30f1aef00cf9ec5a43d6c59b99b2d to your computer and use it in GitHub Desktop.
testing kernel with rust Linux v6.14

Setting Up Linux Kernel v6.14 with Rust Support

This guide provides step-by-step instructions to set up, build, and configure Linux kernel version 6.14 with Rust support on an Ubuntu 24.04 virtual machine (VM) running in QEMU. It includes version prerequisites, enabling Rust support, and building/testing sample Rust kernel modules (rust_mymodule and rust_usb_serial). The setup supports a physical QinHeng CH340 USB-serial device (0x1a86:0x7523) passed through to the VM and a virtual USB device (0x1234:0x5678) for testing.

Prerequisites

System Requirements

  • OS: Ubuntu 24.04 LTS (VM disk: u22s_rust.qcow2)
  • CPU: x86_64 architecture (QEMU with -cpu host)
  • Memory: 16 GB RAM (QEMU with -m 16G)
  • Disk Space: ~40 GB for kernel source, tools, and build artifacts
  • QEMU: Configured with KVM, VirtIO, and USB host passthrough
  • Internet: Required for downloading sources and tools

Software Versions

  • Rust: 1.83.0
  • Clang/LLVM: 19.1.7 or later
  • Bindgen: 0.71.1 or later
  • GCC: For kernel build dependencies
  • Make, Git, and Build Tools: Standard development tools

Package Installation

Install required packages in the Ubuntu 24.04 VM:

sudo apt update
sudo apt install -y build-essential flex bison libssl-dev libelf-dev libncurses-dev bc dwarves git python3 pahole cpio clang lld cargo rustc libclang-dev linux-headers-$(uname -r)

Setting Up Rust and LLVM

  1. Install Rust: Install Rust via rustup:

    curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
    source ~/.cargo/env
  2. Set Rust Version: Linux 6.14 requires Rust 1.83.0:

    rustup install 1.83.0
    rustup default 1.83.0
    rustup component add rust-src
    rustc --version  # Should output: rustc 1.83.0
  3. Install Bindgen: Install bindgen-cli for Rust bindings:

    cargo install --locked --version 0.71.1 bindgen-cli
    bindgen --version  # Should output: bindgen 0.71.1
  4. Install LLVM/Clang: Install Clang 19 for LLVM-based builds:

    wget https://apt.llvm.org/llvm.sh
    chmod +x llvm.sh
    sudo ./llvm.sh 19
    echo 'export PATH=/usr/lib/llvm-19/bin:$PATH' >> ~/.bashrc
    source ~/.bashrc
    sudo update-alternatives --install /usr/bin/clang clang /usr/bin/clang-19 100
    sudo update-alternatives --install /usr/bin/clang++ clang++ /usr/bin/clang++-19 100
    clang --version  # Should output: Ubuntu clang version 19.1.7

Setting Up QEMU VM

  1. VM Configuration: Ensure the VM is running with the following QEMU command:

    sudo qemu-system-x86_64 -enable-kvm -cpu host -m 16G -smp "$(nproc)" \
        -drive file=/home/mighty/script/vm/u22s_rust.qcow2,if=virtio,cache=none,aio=native,format=qcow2 \
        -net nic,model=virtio -net user,hostfwd=tcp::6657-:22 \
        -vga std -display gtk -boot menu=on \
        -device virtio-balloon -device virtio-rng-pci \
        -usb -device usb-host,vendorid=0x1a86,productid=0x7523 # only if using arduino uno or mega
  2. Verify USB Passthrough: Inside the VM, check for the CH340 device:

    lsusb

    Expected output:

    Bus 001 Device 002: ID 1a86:7523 QinHeng Electronics CH340 serial converter
    

Cloning and Configuring the Kernel

  1. Clone Linux 6.14: Clone the kernel source:

    git clone --branch v6.14 --depth 1 https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git ~/linux-6.14
    cd ~/linux-6.14
  2. Verify Rust Availability:

    rustup component add rust-src
    make LLVM=1 rustavailable

    Ensure no errors. If issues arise, verify rustc, bindgen, and libclang-dev.

  3. Creating Config: Use the current kernel config:

    make LLVM=1 defconfig
  4. Enable Rust and USB Support: Configure the kernel:

    make LLVM=1 menuconfig
    • Enable Rust:
      • General setup -> Rust language support -> Set CONFIG_RUST=y
    • Enable USB and TTY:
      • Device Drivers -> USB support -> Set CONFIG_USB=y and CONFIG_USB_SERIAL=y
      • Device Drivers -> Character devices -> Set CONFIG_TTY=y
    • Enable Rust samples:
      • Samples -> Rust samples -> Enable:
        • Minimal (CONFIG_SAMPLE_RUST_MINIMAL=m)
        • Printing macros (CONFIG_SAMPLE_RUST_PRINT=m)
        • Rust custom module sample (CONFIG_SAMPLE_RUST_MYMODULE=m) (after adding)
        • Rust virtual USB-serial driver sample (CONFIG_SAMPLE_RUST_USB_SERIAL=m) (after adding)
    • Save and exit.

Adding Custom Rust Modules

Custom Module: rust_mymodule

A simple module that prints messages on load and unload.

  1. Create rust_mymodule.rs:

    cat > samples/rust/rust_mymodule.rs << 'EOF'
    // SPDX-License-Identifier: GPL-2.0
    //! Rust custom module sample.
    
    use kernel::prelude::*;
    
    module! {
        type: MyModule,
        name: "rust_mymodule",
        author: "YourName",
        description: "A custom Rust kernel module",
        license: "GPL",
    }
    
    struct MyModule;
    
    impl kernel::Module for MyModule {
        fn init(_module: &'static ThisModule) -> Result<Self> {
            pr_info!("Hello from My Rust Module!\n");
            Ok(MyModule)
        }
    }
    
    impl Drop for MyModule {
        fn drop(&mut self) {
            pr_info!("Goodbye from My Rust Module!\n");
        }
    }
    EOF
  2. Update samples/rust/Kconfig:

    echo '
    config SAMPLE_RUST_MYMODULE
        tristate "Rust custom module sample"
        depends on RUST
        help
            This option builds the Rust custom module sample.
    
            To compile this as a module, choose M here.
    ' >> samples/rust/Kconfig
  3. Update samples/rust/Makefile:

    echo 'obj-$(CONFIG_SAMPLE_RUST_MYMODULE) += rust_mymodule.o' >> samples/rust/Makefile
  4. Enable the Module:

    make LLVM=1 menuconfig

    Set Rust custom module sample to M.

Important: USB module part of code is untested

Virtual USB-Serial Driver: rust_usb_serial

A driver that registers a USB device and exposes /dev/ttyUSB0, supporting both a virtual device (0x1234:0x5678) and the CH340 (0x1a86:0x7523).

  1. Create rust_usb_serial.rs:

    cat > samples/rust/rust_usb_serial.rs << 'EOF'
    // SPDX-License-Identifier: GPL-2.0
    #![no_std]
    
    use kernel::prelude::*;
    use kernel::{
        c_str,
        error::code::ENOMEM,
        serial::tty::{self, TtyOperations, TtyPort, TtyPortOperations},
        usb::{self, Interface, UsbDevice},
    };
    
    module! {
        type: RustUsbSerial,
        name: "rust_usb_serial",
        author: "Pranav",
        description: "Virtual USB-serial driver in Rust",
        license: "GPL",
        params: {},
    }
    
    const VENDOR_ID: u16 = 0x1234;
    const PRODUCT_ID: u16 = 0x5678;
    const CH340_VENDOR_ID: u16 = 0x1a86;
    const CH340_PRODUCT_ID: u16 = 0x7523;
    const TTY_NAME: &str = "ttyUSB";
    
    kernel::module_usb_driver! {
        type: UsbSerialDriver,
        id_table: [
            { idVendor: VENDOR_ID, idProduct: PRODUCT_ID },
            { idVendor: CH340_VENDOR_ID, idProduct: CH340_PRODUCT_ID },
        ],
    }
    
    struct UsbSerialDriver;
    
    #[vtable]
    impl usb::Driver for UsbSerialDriver {
        type Data = Pin<Box<TtyPort>>;
    
        fn probe(device: &mut UsbDevice, _interface: Interface) -> Result<()> {
            pr_info!("Rust USB-serial: Probing device {:04x}:{:04x}\n", device.vendor_id(), device.product_id());
            let port = Pin::from(Box::try_new(TtyPort::new())?);
            port.as_ref().register(c_str!(TTY_NAME), 0, &device.device())?;
            device.set_data(port);
            Ok(())
        }
    
        fn disconnect(device: &mut UsbDevice) {
            pr_info!("Rust USB-serial: Disconnecting device\n");
        }
    }
    
    struct SerialPortOps;
    
    #[vtable]
    impl TtyPortOperations for SerialPortOps {
        fn port_activate(port: &TtyPort, _tty: &tty::Struct) -> Result<()> {
            pr_info!("Rust USB-serial: Port activated\n");
            Ok(())
        }
    
        fn port_shutdown(port: &TtyPort) {
            pr_info!("Rust USB-serial: Port shutdown\n");
        }
    }
    
    struct SerialTtyOps;
    
    #[vtable]
    impl TtyOperations for SerialTtyOps {
        type PortOps = SerialPortOps;
    
        fn open(tty: &tty::Struct, _file: &kernel::file::File) -> Result<()> {
            pr_info!("Hello, world!\n");
            tty::port::open::<Self>(tty)?;
            Ok(())
        }
    
        fn close(tty: &tty::Struct, _file: &kernel::file::File) {
            pr_info!("Rust USB-serial: TTY closed\n");
            tty::port::close::<Self>(tty);
        }
    
        fn install(port: &TtyPort, tty: &tty::Struct) -> Result<()> {
            tty::port::install::<Self>(port, tty)?;
            Ok(())
        }
    }
    
    struct RustUsbSerial;
    
    impl kernel::Module for RustUsbSerial {
        fn init(_module: &'static ThisModule) -> Result<Self> {
            pr_info!("Rust USB-serial: Initializing\n");
            Ok(RustUsbSerial)
        }
    }
    
    impl Drop for RustUsbSerial {
        fn drop(&mut self) {
            pr_info!("Rust USB-serial: Exiting\n");
        }
    }
    EOF
  2. Update samples/rust/Kconfig:

    echo '
    config SAMPLE_RUST_USB_SERIAL
        tristate "Rust virtual USB-serial driver sample"
        depends on RUST && USB && TTY
        help
            This option builds a Rust virtual USB-serial driver sample that registers
            a USB device (vendor 0x1234:0x5678 or 0x1a86:0x7523) and exposes a TTY device.
    
            To compile this as a module, choose M here.
    ' >> samples/rust/Kconfig
  3. Update samples/rust/Makefile:

    echo 'obj-$(CONFIG_SAMPLE_RUST_USB_SERIAL) += rust_usb_serial.o' >> samples/rust/Makefile
  4. Enable the Module:

    make LLVM=1 menuconfig

    Set Rust virtual USB-serial driver sample to M.

Building and Installing

  1. Clean the Build:

    make LLVM=1 M=samples/rust clean
  2. Build Rust Modules:

    make LLVM=1 -j$(nproc) M=samples/rust
  3. Build Kernel and Modules:

    make LLVM=1 -j$(nproc)
    make LLVM=1 modules
  4. Install:

    sudo make LLVM=1 modules_install
    sudo make LLVM=1 install
    sudo update-grub
    sudo reboot

Testing Rust Modules

Test rust_mymodule

  1. Load:

    sudo modprobe rust_mymodule
  2. Check Logs:

    dmesg | tail -n 20

    Expected:

    [  123.456789] Hello from My Rust Module!
    
  3. Unload:

    sudo rmmod rust_mymodule

    Expected:

    [  123.456789] Goodbye from My Rust Module!
    

Test rust_usb_serial

  1. Load:

    sudo rmmod ch341  # Unload default CH340 driver
    sudo modprobe rust_usb_serial
  2. Test with CH340:

    ls /dev/ttyUSB0
    sudo cat /dev/ttyUSB0

    Or:

    echo "test" | sudo tee /dev/ttyUSB0
  3. Test with Virtual Device: In a separate terminal, run QEMU with a virtual USB device:

    sudo qemu-system-x86_64 -m 512 -kernel /boot/vmlinuz-$(uname -r) \
        -initrd /boot/initrd.img-$(uname -r) \
        -append "root=/dev/sda console=ttyS0" \
        -nographic -usb -device usb-ehci,id=ehci \
        -device usb-serial,vendorid=0x1234,productid=0x5678

    Then:

    ls /dev/ttyUSB0
    sudo cat /dev/ttyUSB0
  4. Check Logs:

    dmesg | tail -n 20

    Expected:

    [  123.456789] Rust USB-serial: Initializing
    [  123.456790] Rust USB-serial: Probing device 1a86:7523  # or 1234:5678
    [  123.456791] Rust USB-serial: Port activated
    [  123.456792] Hello, world!
    
  5. Unload:

    sudo rmmod rust_usb_serial
    sudo modprobe ch341  # Restore CH340 driver

Troubleshooting

  • Rust Build Errors:
    • Verify versions: rustc --version, bindgen --version, clang --version.
    • Check logs:
      grep -i "error\|warning" build.log
  • No /dev/ttyUSB0:
    • Ensure CONFIG_USB=y, CONFIG_TTY=y, CONFIG_USB_SERIAL=y:
      grep CONFIG_USB .config
      grep CONFIG_TTY .config
      grep CONFIG_USB_SERIAL .config
    • Check dmesg for probe errors.
  • Module Load Fails:
    • Verify kernel/module version match: uname -r.
    • Check CONFIG_MODVERSIONS:
      grep CONFIG_MODVERSIONS .config
      grep CONFIG_EXTENDED_MODVERSIONS .config
  • CH340 Issues:
    • Ensure USB passthrough: lsusb.
    • Unload conflicting drivers: sudo rmmod ch341.

Notes on Your Setup and USB-Serial Driver

  1. QEMU VM Configuration:

    • Your QEMU command passes the CH340 device (0x1a86:0x7523) to the VM, confirmed by lsusb. The rust_usb_serial driver in the README.md includes both the virtual device (0x1234:0x5678) and CH340 IDs to support testing in both scenarios.
    • The VM uses 16 GB RAM and all CPU cores (-smp "$(nproc)"), ensuring sufficient resources for kernel builds.
  2. CH340 Device:

    • The CH340 is typically handled by the ch341 module. To test with rust_usb_serial, you must unload ch341 first (sudo rmmod ch341). The README.md includes this step.
    • If you prefer to test only the virtual device, remove the CH340 ID from the id_table in rust_usb_serial.rs.
  3. Recent Build Issues:

    • Your rust_mymodule build failed due to allocator_api and global_asm features (command #448). The fixed version in the README.md (same as your command #453) removes these, ensuring it builds successfully.
    • Confirm the build worked:
      ls -l samples/rust/rust_mymodule.ko
      sudo modprobe rust_mymodule
      dmesg | tail -n 20
  4. Virtual USB Device Testing:

    • Your history shows use of VirtualUSBDevice (commands #486–508). The README.md includes QEMU-based testing, but you can also use VirtualUSBDevice:
      cd ~/VirtualUSBDevice
      make clean && make
      sudo modprobe vhci-hcd
      sudo ./VirtualUSBDevice
      sudo modprobe rust_usb_serial
      ls /dev/ttyUSB0
  5. Tool Versions:

    • rustc 1.83.0, bindgen 0.71.1, and clang 19.1.7 are correct and exceed the minimum requirements for Linux 6.14.

Missing Information

To finalize the setup and ensure everything works:

  1. Kernel Config Confirmation:

    grep CONFIG_USB /boot/config-$(uname -r)
    grep CONFIG_TTY /boot/config-$(uname -r)
    grep CONFIG_USB_SERIAL /boot/config-$(uname -r)
    grep CONFIG_SAMPLE_RUST_USB_SERIAL .config

    Ensure CONFIG_USB=y, CONFIG_TTY=y, CONFIG_USB_SERIAL=y, and CONFIG_SAMPLE_RUST_USB_SERIAL=m.

  2. Current Kernel Version:

    uname -a

    Confirm it’s Linux 6.14 and matches the built modules.

  3. Build Status of rust_usb_serial: Have you created and built rust_usb_serial.rs? If not, follow the README.md steps.

    ls samples/rust/rust_usb_serial.rs
    ls -l samples/rust/rust_usb_serial.ko
  4. CH340 vs. Virtual Device: Do you want rust_usb_serial to prioritize the CH340 (0x1a86:0x7523) or the virtual device (0x1234:0x5678)? The README.md supports both, but I can adjust the id_table if you prefer one.

  5. Build Logs: If any builds fail, share:

    grep -i "error\|warning" build.log

Next Steps

  1. Follow the README.md:

    • Set up rust_mymodule and rust_usb_serial as described.
    • Build and test both modules.
    • Use the QEMU or VirtualUSBDevice instructions for virtual device testing.
  2. Test with CH340:

    sudo rmmod ch341
    sudo modprobe rust_usb_serial
    ls /dev/ttyUSB0
    sudo cat /dev/ttyUSB0
    dmesg | tail -n 20
  3. Share Results:

    • Confirm rust_mymodule works (dmesg output).
    • Report if rust_usb_serial builds and creates /dev/ttyUSB0.
    • Provide the requested config outputs.
  4. Optional Enhancements:

    • Add read/write support to rust_usb_serial for data transfer.
    • Move modules to rust-out-of-tree-module (share ls -R ~/rust-out-of-tree-module if needed).

Resources

@pranav083
Copy link
Author

@pranav083
Copy link
Author

pranav083 commented Apr 7, 2025

https://hackerbikepacker.com/rust-in-linux-kernel-configuration

avoid this line from above setup

rustup override set $(scripts/min-tool-version.sh rustc)

rust@linuxrust:~/linux$ make LLVM=1 rustavailable
Rust is available!
rust@linuxrust:~/linux$ clang --version
Ubuntu clang version 18.1.3 (1ubuntu1)
Target: x86_64-pc-linux-gnu
Thread model: posix
InstalledDir: /lib/llvm-18/bin
rust@linuxrust:~/linux$ rustc -vV
rustc 1.83.0 (90b35a623 2024-11-26)
binary: rustc
commit-hash: 90b35a6239c3d8bdabc530a6a0816f7ff89a0aaf
commit-date: 2024-11-26
host: x86_64-unknown-linux-gnu
release: 1.83.0
LLVM version: 19.1.1
rust@linuxrust:~/linux$ 

make LLVM=1 KCFLAGS="-Wno-frame-larger-than" -j$(nproc) > build.log 2> error.log

rest follow from the above build

@pranav083
Copy link
Author

Setting Up Linux Kernel v6.14 with Rust Support

This guide provides step-by-step instructions to set up, build, and configure Linux kernel version 6.14 with Rust support on an Ubuntu 24.04 virtual machine (VM) running in QEMU. It includes version prerequisites, enabling Rust support, and building/testing sample Rust kernel modules (rust_mymodule and rust_usb_serial). The setup supports a physical QinHeng CH340 USB-serial device (0x1a86:0x7523) passed through to the VM and a virtual USB device (0x1234:0x5678) for testing.

Prerequisites

System Requirements

  • OS: Ubuntu 24.04 LTS (VM disk: u22s_rust.qcow2)
  • CPU: x86_64 architecture (QEMU with -cpu host)
  • Memory: 16 GB RAM (QEMU with -m 16G)
  • Disk Space: ~40 GB for kernel source, tools, and build artifacts
  • QEMU: Configured with KVM, VirtIO, and USB host passthrough
  • Internet: Required for downloading sources and tools

Software Versions

  • Rust: 1.83.0
  • Clang/LLVM: 19.1.7 or later
  • Bindgen: 0.71.1 or later
  • GCC: For kernel build dependencies
  • Make, Git, and Build Tools: Standard development tools

Package Installation

Install required packages in the Ubuntu 24.04 VM:

sudo apt update
sudo apt install -y build-essential flex bison libssl-dev libelf-dev libncurses-dev bc dwarves git python3 pahole cpio clang lld cargo rustc libclang-dev linux-headers-$(uname -r)

Setting Up Rust and LLVM

  1. Install Rust:
    Install Rust via rustup:

    curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
    source ~/.cargo/env
  2. Set Rust Version:
    Linux 6.14 requires Rust 1.83.0:

    rustup install 1.83.0
    rustup default 1.83.0
    rustup component add rust-src
    rustc --version  # Should output: rustc 1.83.0
  3. Install Bindgen:
    Install bindgen-cli for Rust bindings:

    cargo install --locked --version 0.71.1 bindgen-cli
    bindgen --version  # Should output: bindgen 0.71.1
  4. Install LLVM/Clang:
    Install Clang 19 for LLVM-based builds:

    wget https://apt.llvm.org/llvm.sh
    chmod +x llvm.sh
    sudo ./llvm.sh 19
    echo 'export PATH=/usr/lib/llvm-19/bin:$PATH' >> ~/.bashrc
    source ~/.bashrc
    sudo update-alternatives --install /usr/bin/clang clang /usr/bin/clang-19 100
    sudo update-alternatives --install /usr/bin/clang++ clang++ /usr/bin/clang++-19 100
    clang --version  # Should output: Ubuntu clang version 19.1.7

Setting Up QEMU VM

  1. VM Configuration:
    Ensure the VM is running with the following QEMU command:

    sudo qemu-system-x86_64 -enable-kvm -cpu host -m 16G -smp "$(nproc)" \
        -drive file=/home/mighty/script/vm/u22s_rust.qcow2,if=virtio,cache=none,aio=native,format=qcow2 \
        -net nic,model=virtio -net user,hostfwd=tcp::6657-:22 \
        -vga std -display gtk -boot menu=on \
        -device virtio-balloon -device virtio-rng-pci \
        -usb -device usb-host,vendorid=0x1a86,productid=0x7523 # only if using arduino uno or mega
  2. Verify USB Passthrough:
    Inside the VM, check for the CH340 device:

    lsusb

    Expected output:

    Bus 001 Device 002: ID 1a86:7523 QinHeng Electronics CH340 serial converter
    

Cloning and Configuring the Kernel

  1. Clone Linux 6.14:
    Clone the kernel source:

    git clone --branch v6.14 --depth 1 https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git ~/linux-6.14
    cd ~/linux-6.14
  2. Verify Rust Availability:

    rustup component add rust-src
    make LLVM=1 rustavailable

    Ensure no errors. If issues arise, verify rustc, bindgen, and libclang-dev.

  3. Creating Config:
    Use the current kernel config:

    make LLVM=1 defconfig
  4. Enable Rust and USB Support:
    Configure the kernel:

    make LLVM=1 menuconfig
    • Enable Rust:
      • General setup -> Rust language support -> Set CONFIG_RUST=y
    • Enable USB and TTY:
      • Device Drivers -> USB support -> Set CONFIG_USB=y and CONFIG_USB_SERIAL=y
      • Device Drivers -> Character devices -> Set CONFIG_TTY=y
    • Enable Rust samples:
      • Samples -> Rust samples -> Enable:
        • Minimal (CONFIG_SAMPLE_RUST_MINIMAL=m)
        • Printing macros (CONFIG_SAMPLE_RUST_PRINT=m)
        • Rust custom module sample (CONFIG_SAMPLE_RUST_MYMODULE=m) (after adding)
        • Rust virtual USB-serial driver sample (CONFIG_SAMPLE_RUST_USB_SERIAL=m) (after adding)
    • Save and exit.

Adding Custom Rust Modules

Custom Module: rust_mymodule

A simple module that prints messages on load and unload.

  1. Create rust_mymodule.rs:

    cat > samples/rust/rust_mymodule.rs << 'EOF'
    // SPDX-License-Identifier: GPL-2.0
    //! Rust custom module sample.
    
    use kernel::prelude::*;
    
    module! {
        type: MyModule,
        name: "rust_mymodule",
        author: "YourName",
        description: "A custom Rust kernel module",
        license: "GPL",
    }
    
    struct MyModule;
    
    impl kernel::Module for MyModule {
        fn init(_module: &'static ThisModule) -> Result<Self> {
            pr_info!("Hello from My Rust Module!\n");
            Ok(MyModule)
        }
    }
    
    impl Drop for MyModule {
        fn drop(&mut self) {
            pr_info!("Goodbye from My Rust Module!\n");
        }
    }
    EOF
  2. Update samples/rust/Kconfig:

    echo '
    config SAMPLE_RUST_MYMODULE
        tristate "Rust custom module sample"
        depends on RUST
        help
            This option builds the Rust custom module sample.
    
            To compile this as a module, choose M here.
    ' >> samples/rust/Kconfig
  3. Update samples/rust/Makefile:

    echo 'obj-$(CONFIG_SAMPLE_RUST_MYMODULE) += rust_mymodule.o' >> samples/rust/Makefile
  4. Enable the Module:

    make LLVM=1 menuconfig

    Set Rust custom module sample to M.

Important: USB module part of code is untested

Virtual USB-Serial Driver: rust_usb_serial

A driver that registers a USB device and exposes /dev/ttyUSB0, supporting both a virtual device (0x1234:0x5678) and the CH340 (0x1a86:0x7523).

  1. Create rust_usb_serial.rs:

    cat > samples/rust/rust_usb_serial.rs << 'EOF'
    // SPDX-License-Identifier: GPL-2.0
    #![no_std]
    
    use kernel::prelude::*;
    use kernel::{
        c_str,
        error::code::ENOMEM,
        serial::tty::{self, TtyOperations, TtyPort, TtyPortOperations},
        usb::{self, Interface, UsbDevice},
    };
    
    module! {
        type: RustUsbSerial,
        name: "rust_usb_serial",
        author: "Pranav",
        description: "Virtual USB-serial driver in Rust",
        license: "GPL",
        params: {},
    }
    
    const VENDOR_ID: u16 = 0x1234;
    const PRODUCT_ID: u16 = 0x5678;
    const CH340_VENDOR_ID: u16 = 0x1a86;
    const CH340_PRODUCT_ID: u16 = 0x7523;
    const TTY_NAME: &str = "ttyUSB";
    
    kernel::module_usb_driver! {
        type: UsbSerialDriver,
        id_table: [
            { idVendor: VENDOR_ID, idProduct: PRODUCT_ID },
            { idVendor: CH340_VENDOR_ID, idProduct: CH340_PRODUCT_ID },
        ],
    }
    
    struct UsbSerialDriver;
    
    #[vtable]
    impl usb::Driver for UsbSerialDriver {
        type Data = Pin<Box<TtyPort>>;
    
        fn probe(device: &mut UsbDevice, _interface: Interface) -> Result<()> {
            pr_info!("Rust USB-serial: Probing device {:04x}:{:04x}\n", device.vendor_id(), device.product_id());
            let port = Pin::from(Box::try_new(TtyPort::new())?);
            port.as_ref().register(c_str!(TTY_NAME), 0, &device.device())?;
            device.set_data(port);
            Ok(())
        }
    
        fn disconnect(device: &mut UsbDevice) {
            pr_info!("Rust USB-serial: Disconnecting device\n");
        }
    }
    
    struct SerialPortOps;
    
    #[vtable]
    impl TtyPortOperations for SerialPortOps {
        fn port_activate(port: &TtyPort, _tty: &tty::Struct) -> Result<()> {
            pr_info!("Rust USB-serial: Port activated\n");
            Ok(())
        }
    
        fn port_shutdown(port: &TtyPort) {
            pr_info!("Rust USB-serial: Port shutdown\n");
        }
    }
    
    struct SerialTtyOps;
    
    #[vtable]
    impl TtyOperations for SerialTtyOps {
        type PortOps = SerialPortOps;
    
        fn open(tty: &tty::Struct, _file: &kernel::file::File) -> Result<()> {
            pr_info!("Hello, world!\n");
            tty::port::open::<Self>(tty)?;
            Ok(())
        }
    
        fn close(tty: &tty::Struct, _file: &kernel::file::File) {
            pr_info!("Rust USB-serial: TTY closed\n");
            tty::port::close::<Self>(tty);
        }
    
        fn install(port: &TtyPort, tty: &tty::Struct) -> Result<()> {
            tty::port::install::<Self>(port, tty)?;
            Ok(())
        }
    }
    
    struct RustUsbSerial;
    
    impl kernel::Module for RustUsbSerial {
        fn init(_module: &'static ThisModule) -> Result<Self> {
            pr_info!("Rust USB-serial: Initializing\n");
            Ok(RustUsbSerial)
        }
    }
    
    impl Drop for RustUsbSerial {
        fn drop(&mut self) {
            pr_info!("Rust USB-serial: Exiting\n");
        }
    }
    EOF
  2. Update samples/rust/Kconfig:

    echo '
    config SAMPLE_RUST_USB_SERIAL
        tristate "Rust virtual USB-serial driver sample"
        depends on RUST && USB && TTY
        help
            This option builds a Rust virtual USB-serial driver sample that registers
            a USB device (vendor 0x1234:0x5678 or 0x1a86:0x7523) and exposes a TTY device.
    
            To compile this as a module, choose M here.
    ' >> samples/rust/Kconfig
  3. Update samples/rust/Makefile:

    echo 'obj-$(CONFIG_SAMPLE_RUST_USB_SERIAL) += rust_usb_serial.o' >> samples/rust/Makefile
  4. Enable the Module:

    make LLVM=1 menuconfig

    Set Rust virtual USB-serial driver sample to M.

Building and Installing

  1. Clean the Build:

    make LLVM=1 M=samples/rust clean
  2. Build Rust Modules:

    make LLVM=1 -j$(nproc) M=samples/rust
  3. Build Kernel and Modules:

    make LLVM=1 -j$(nproc)
    make LLVM=1 modules
  4. Install:

    sudo make LLVM=1 modules_install
    sudo make LLVM=1 install
    sudo update-grub
    sudo reboot

Testing Rust Modules

Test rust_mymodule

  1. Load:

    sudo modprobe rust_mymodule
  2. Check Logs:

    dmesg | tail -n 20

    Expected:

    [  123.456789] Hello from My Rust Module!
    
  3. Unload:

    sudo rmmod rust_mymodule

    Expected:

    [  123.456789] Goodbye from My Rust Module!
    

Test rust_usb_serial

  1. Load:

    sudo rmmod ch341  # Unload default CH340 driver
    sudo modprobe rust_usb_serial
  2. Test with CH340:

    ls /dev/ttyUSB0
    sudo cat /dev/ttyUSB0

    Or:

    echo "test" | sudo tee /dev/ttyUSB0
  3. Test with Virtual Device:
    In a separate terminal, run QEMU with a virtual USB device:

    sudo qemu-system-x86_64 -m 512 -kernel /boot/vmlinuz-$(uname -r) \
        -initrd /boot/initrd.img-$(uname -r) \
        -append "root=/dev/sda console=ttyS0" \
        -nographic -usb -device usb-ehci,id=ehci \
        -device usb-serial,vendorid=0x1234,productid=0x5678

    Then:

    ls /dev/ttyUSB0
    sudo cat /dev/ttyUSB0
  4. Check Logs:

    dmesg | tail -n 20

    Expected:

    [  123.456789] Rust USB-serial: Initializing
    [  123.456790] Rust USB-serial: Probing device 1a86:7523  # or 1234:5678
    [  123.456791] Rust USB-serial: Port activated
    [  123.456792] Hello, world!
    
  5. Unload:

    sudo rmmod rust_usb_serial
    sudo modprobe ch341  # Restore CH340 driver

Troubleshooting

  • Rust Build Errors:
    • Verify versions: rustc --version, bindgen --version, clang --version.
    • Check logs:
      grep -i "error\|warning" build.log
  • No /dev/ttyUSB0:
    • Ensure CONFIG_USB=y, CONFIG_TTY=y, CONFIG_USB_SERIAL=y:
      grep CONFIG_USB .config
      grep CONFIG_TTY .config
      grep CONFIG_USB_SERIAL .config
    • Check dmesg for probe errors.
  • Module Load Fails:
    • Verify kernel/module version match: uname -r.
    • Check CONFIG_MODVERSIONS:
      grep CONFIG_MODVERSIONS .config
      grep CONFIG_EXTENDED_MODVERSIONS .config
  • CH340 Issues:
    • Ensure USB passthrough: lsusb.
    • Unload conflicting drivers: sudo rmmod ch341.

Notes on Your Setup and USB-Serial Driver

  1. QEMU VM Configuration:

    • Your QEMU command passes the CH340 device (0x1a86:0x7523) to the VM, confirmed by lsusb. The rust_usb_serial driver in the README.md includes both the virtual device (0x1234:0x5678) and CH340 IDs to support testing in both scenarios.
    • The VM uses 16 GB RAM and all CPU cores (-smp "$(nproc)"), ensuring sufficient resources for kernel builds.
  2. CH340 Device:

    • The CH340 is typically handled by the ch341 module. To test with rust_usb_serial, you must unload ch341 first (sudo rmmod ch341). The README.md includes this step.
    • If you prefer to test only the virtual device, remove the CH340 ID from the id_table in rust_usb_serial.rs.
  3. Recent Build Issues:

    • Your rust_mymodule build failed due to allocator_api and global_asm features (command #448). The fixed version in the README.md (same as your command #453) removes these, ensuring it builds successfully.
    • Confirm the build worked:
      ls -l samples/rust/rust_mymodule.ko
      sudo modprobe rust_mymodule
      dmesg | tail -n 20
  4. Virtual USB Device Testing:

    • Your history shows use of VirtualUSBDevice (commands #486–508). The README.md includes QEMU-based testing, but you can also use VirtualUSBDevice:
      cd ~/VirtualUSBDevice
      make clean && make
      sudo modprobe vhci-hcd
      sudo ./VirtualUSBDevice
      sudo modprobe rust_usb_serial
      ls /dev/ttyUSB0
  5. Tool Versions:

    • rustc 1.83.0, bindgen 0.71.1, and clang 19.1.7 are correct and exceed the minimum requirements for Linux 6.14.

Missing Information

To finalize the setup and ensure everything works:

  1. Kernel Config Confirmation:

    grep CONFIG_USB /boot/config-$(uname -r)
    grep CONFIG_TTY /boot/config-$(uname -r)
    grep CONFIG_USB_SERIAL /boot/config-$(uname -r)
    grep CONFIG_SAMPLE_RUST_USB_SERIAL .config

    Ensure CONFIG_USB=y, CONFIG_TTY=y, CONFIG_USB_SERIAL=y, and CONFIG_SAMPLE_RUST_USB_SERIAL=m.

  2. Current Kernel Version:

    uname -a

    Confirm it’s Linux 6.14 and matches the built modules.

  3. Build Status of rust_usb_serial:
    Have you created and built rust_usb_serial.rs? If not, follow the README.md steps.

    ls samples/rust/rust_usb_serial.rs
    ls -l samples/rust/rust_usb_serial.ko
  4. CH340 vs. Virtual Device:
    Do you want rust_usb_serial to prioritize the CH340 (0x1a86:0x7523) or the virtual device (0x1234:0x5678)? The README.md supports both, but I can adjust the id_table if you prefer one.

  5. Build Logs:
    If any builds fail, share:

    grep -i "error\|warning" build.log

Next Steps

  1. Follow the README.md:

    • Set up rust_mymodule and rust_usb_serial as described.
    • Build and test both modules.
    • Use the QEMU or VirtualUSBDevice instructions for virtual device testing.
  2. Test with CH340:

    sudo rmmod ch341
    sudo modprobe rust_usb_serial
    ls /dev/ttyUSB0
    sudo cat /dev/ttyUSB0
    dmesg | tail -n 20
  3. Share Results:

    • Confirm rust_mymodule works (dmesg output).
    • Report if rust_usb_serial builds and creates /dev/ttyUSB0.
    • Provide the requested config outputs.
  4. Optional Enhancements:

    • Add read/write support to rust_usb_serial for data transfer.
    • Move modules to rust-out-of-tree-module (share ls -R ~/rust-out-of-tree-module if needed).

Resources

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment