qemu安装驱动开发环境

当然可以!**QEMU 是一个强大的硬件模拟工具**,非常适合用于学习 Linux 驱动开发,尤其是在没有物理开发板的情况下。以下是详细的配置和使用指南:

---

### **一、QEMU 在驱动开发中的核心优势**
1. **无需硬件**:模拟 CPU(如 x86、ARM)、外设(如 PCI 设备、USB、网卡),可直接测试驱动逻辑。
2. **调试友好**:支持 GDB 远程调试内核和驱动代码,可设置断点、单步执行。
3. **灵活定制**:自由添加虚拟硬件(如自定义 PCI 设备),模拟真实场景。
4. **跨平台兼容**:在 macOS/Linux/Windows 上均可运行。

---

### **二、在 MacBook 上安装 QEMU**
#### **1. 安装 QEMU**
- **通过 Homebrew 安装**(推荐):
  ```bash
  brew install qemu
  • 验证安装:
    qemu-system-x86_64 --version
    

2. 准备 Linux 镜像

  • 下载预构建的 Linux 镜像(例如 Ubuntu):
    # 下载 Ubuntu Cloud 镜像(轻量级)
    wget https://cloud-images.ubuntu.com/focal/current/focal-server-cloudimg-amd64.img
    
  • 创建虚拟磁盘
    qemu-img create -f qcow2 ubuntu-driver.qcow2 10G
    

三、启动 QEMU 虚拟机

1. 基础命令

qemu-system-x86_64 \
  -machine accel=hvf,type=q35 \  # 启用硬件加速(Intel Mac)
  -cpu host \                    # 使用宿主机 CPU 特性
  -smp 4 \                       # 分配 4 核 CPU
  -m 4G \                        # 分配 4GB 内存
  -drive file=ubuntu-driver.qcow2,format=qcow2 \  # 虚拟磁盘
  -cdrom ubuntu-22.04.4-live-server-amd64.iso \    # 安装镜像
  -net nic -net user,hostfwd=tcp::2222-:22 \       # 网络端口转发(SSH)
  -nographic                      # 无图形界面(可选)

2. 配置 SSH 访问

  • 启动时添加端口转发参数:
    -net user,hostfwd=tcp::2222-:22
    
  • 在虚拟机内安装 OpenSSH:
    sudo apt install openssh-server
    
  • 通过宿主机访问虚拟机:
    ssh -p 2222 user@localhost
    

四、使用 QEMU 学习驱动开发的实战步骤

1. 编写一个简单的字符设备驱动

  • 代码示例my_driver.c):
    #include <linux/module.h>
    #include <linux/fs.h>
    
    #define DEVICE_NAME "my_device"
    
    static int major_num;
    
    static int device_open(struct inode *inode, struct file *file) {
        printk(KERN_INFO "Device opened\n");
        return 0;
    }
    
    static struct file_operations fops = {
        .open = device_open,
    };
    
    static int __init my_driver_init(void) {
        major_num = register_chrdev(0, DEVICE_NAME, &fops);
        printk(KERN_INFO "Driver loaded, major number: %d\n", major_num);
        return 0;
    }
    
    static void __exit my_driver_exit(void) {
        unregister_chrdev(major_num, DEVICE_NAME);
        printk(KERN_INFO "Driver unloaded\n");
    }
    
    module_init(my_driver_init);
    module_exit(my_driver_exit);
    MODULE_LICENSE("GPL");
    

2. 编译驱动并加载到 QEMU 虚拟机

  • 编译驱动
    # 在宿主机上交叉编译(需安装内核头文件)
    make -C /lib/modules/$(uname -r)/build M=$(pwd) modules
    
  • 传输驱动到 QEMU 虚拟机
    scp -P 2222 my_driver.ko user@localhost:~
    
  • 在虚拟机中加载驱动
    sudo insmod my_driver.ko
    dmesg | tail  # 查看加载日志
    

3. 调试驱动

  • 启用 QEMU 的 GDB 调试支持
    qemu-system-x86_64 -s -S ...
    
    • -s:在 1234 端口开启 GDB 服务。
    • -S:启动时暂停 CPU,等待调试器连接。
  • 使用 GDB 连接
    gdb vmlinux  # vmlinux 为内核符号文件
    (gdb) target remote :1234
    (gdb) b my_driver_init  # 在驱动初始化函数设置断点
    (gdb) continue
    

五、模拟真实硬件设备进行驱动开发

1. 添加自定义 PCI 设备

  • 编写 QEMU 设备模型(需 C 语言开发):
    #include "hw/pci/pci.h"
    typedef struct {
        PCIDevice pdev;
        uint32_t regs[256];
    } MyPCIDevice;
    
    static void my_pci_realize(PCIDevice *pdev, Error **errp) {
        // 硬件初始化逻辑
    }
    
    static void my_pci_class_init(ObjectClass *klass, void *data) {
        DeviceClass *dc = DEVICE_CLASS(klass);
        PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
        k->realize = my_pci_realize;
        k->vendor_id = 0x1234;  // 自定义厂商 ID
        k->device_id = 0x5678;  // 自定义设备 ID
    }
    
    // 注册设备到 QEMU
    static TypeInfo my_pci_info = {
        .name = "my-pci-device",
        .parent = TYPE_PCI_DEVICE,
        .instance_size = sizeof(MyPCIDevice),
        .class_init = my_pci_class_init,
    };
    
  • 重新编译 QEMU 并启动虚拟机
    ./configure --target-list=x86_64-softmmu --enable-debug
    make && make install
    qemu-system-x86_64 -device my-pci-device ...
    

2. 编写对应的 Linux 驱动

  • 探测 PCI 设备
    static int my_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) {
        printk(KERN_INFO "Found My PCI Device!\n");
        return 0;
    }
    
    static struct pci_device_id my_pci_ids[] = {
        { PCI_DEVICE(0x1234, 0x5678) },  // 匹配 QEMU 中的设备 ID
        { 0 }
    };
    
    static struct pci_driver my_pci_driver = {
        .name = "my_pci_driver",
        .id_table = my_pci_ids,
        .probe = my_pci_probe,
    };
    
    module_pci_driver(my_pci_driver);
    

六、常见问题与解决

  1. QEMU 性能慢

    • 优化方案:启用 KVM 加速(仅限 Linux 宿主机)或 macOS 的 HVF(Hypervisor.framework)。
      -machine accel=hvf  # macOS 专用加速
      
  2. 驱动无法识别模拟设备

    • 检查步骤
      1. 在 QEMU 中确认设备已添加:info qtree
      2. 在 Linux 虚拟机中执行 lspci -v 查看设备列表。
  3. 内核模块版本不匹配

    • 解决:在 QEMU 虚拟机中编译驱动,而非宿主机。

七、学习资源推荐


通过 QEMU,你可以在 MacBook 上完整模拟出接近真实的驱动开发环境,从简单的字符设备到复杂的 PCI 设备驱动均可覆盖。这种方法不仅成本低,还能通过自定义硬件模型深入理解驱动与硬件的交互机制。

--2025-04-26 01:31:44-- https://releases.ubuntu.com/22.04/ubuntu-22.04.4-live-server-amd64.iso
正在解析主机 releases.ubuntu.com (releases.ubuntu.com)... 91.189.91.107, 185.125.190.40, 91.189.91.109, ...
正在连接 releases.ubuntu.com (releases.ubuntu.com)|91.189.91.107|:443... 已连接
已发出 HTTP 请求,正在等待回应... 404 Not Found
2025-04-26 01:31:45 错误 404:Not Found。

你遇到的 404 错误 是由于 Ubuntu 镜像的版本号或 URL 路径不正确 导致的。以下是具体解决方案:


一、问题原因

  • 错误 URL:你尝试下载的 ubuntu-22.04.4-live-server-amd64.iso 已不存在(可能版本号过期或路径调整)。
  • 系统时间异常:日志中的时间戳 2025-04-26 显示系统时间错误,可能影响 HTTPS 证书验证(但此处主要是 URL 问题)。

二、解决方案

1. 使用正确的 Ubuntu 22.04 LTS 镜像 URL

  • 推荐下载链接
    # Ubuntu 22.04.3 LTS (当前最新版)
    wget https://releases.ubuntu.com/22.04/ubuntu-22.04.3-live-server-amd64.iso
    
    # 或直接访问官网手动下载:
    # https://releases.ubuntu.com/22.04/
    
  • 注意:Ubuntu 镜像文件名通常不包含小版本号(如 .4),直接使用 ubuntu-22.04-live-server-amd64.iso

2. 通过国内镜像加速下载(适用于中国用户)

  • 阿里云镜像
    wget https://mirrors.aliyun.com/ubuntu-releases/22.04/ubuntu-22.04.3-live-server-amd64.iso
    
  • 清华镜像
    wget https://mirrors.tuna.tsinghua.edu.cn/ubuntu-releases/22.04/ubuntu-22.04.3-live-server-amd64.iso
    

3. 校验文件完整性

下载完成后,检查 SHA256 校验值:

echo "e7a97d7d9a5dbe5bedf6f3cabe6f586b67116a7a9c2e12e7def3f3e11b6e363a *ubuntu-22.04.3-live-server-amd64.iso" | shasum -a 256 --check
  • 输出应为:ubuntu-22.04.3-live-server-amd64.iso: OK

三、修复系统时间(关键步骤)

系统时间错误可能导致 HTTPS 证书验证失败(尽管此处是 404,但未来时间可能影响其他操作):

# 在 Mac 上同步时间
sudo sntp -sS time.apple.com

四、完整 QEMU 启动命令示例

使用下载好的 ISO 启动虚拟机:

qemu-system-x86_64 \
  -machine accel=hvf,type=q35 \
  -cpu qemu64,-ht \
  -smp 4 -m 4G \
  -drive file=ubuntu.qcow2,format=qcow2 \
  -cdrom ubuntu-22.04.3-live-server-amd64.iso \
  -boot order=cd \
  -nic user,hostfwd=tcp::2222-:22 \
  -nographic

五、其他替代方案

如果仍需旧版 22.04.4,可通过 Ubuntu 旧版本存档 下载:

wget http://old-releases.ubuntu.com/releases/22.04.4/ubuntu-22.04.4-live-server-amd64.iso

通过以上步骤,你应该能成功下载 Ubuntu 镜像并正常启动 QEMU 虚拟机。如果仍有问题,建议优先使用国内镜像源或检查网络连接。

你在安装 Ubuntu 系统时手动设置的密码就是登录凭证。如果忘记密码或未设置,需要通过以下方法重置:


一、密码未设置的常见场景

1. 使用 Ubuntu Cloud 镜像(如 *-cloudimg-*.iso

  • 默认用户ubuntu
  • 默认密码无密码(需通过 SSH 密钥登录)。
    • 若未配置密钥,需在首次启动时通过 cloud-init 注入密码(需额外配置)。

2. 使用 Ubuntu Server Live 镜像(如 *-live-server-*.iso

  • 安装过程中会强制要求设置用户名和密码,需回忆安装时输入的密码。

二、重置密码步骤(适用于已安装的系统)

若完全忘记密码,可通过 QEMU 进入 GRUB 恢复模式重置:

1. 重启虚拟机并进入 GRUB 菜单

  • 关闭当前虚拟机:
    # 在 QEMU 窗口中按 `Ctrl+A` 后按 `X` 强制退出
    
  • 重新启动并捕获 GRUB 菜单:
    qemu-system-x86_64 ... -monitor stdio  # 保持 QEMU 监控界面
    
    在启动时按住 Shift 键(QEMU 窗口中快速按 ESC 键)。

2. 修改 GRUB 启动参数

  • 在 GRUB 菜单中选中 Ubuntu 条目,按 e 进入编辑模式。
  • 找到 linux 开头的行,将 ro 改为 rw init=/bin/bash
    - linux /boot/vmlinuz-... ro quiet splash
    + linux /boot/vmlinuz-... rw init=/bin/bash quiet splash
    
  • Ctrl+XF10 启动到单用户模式。

3. 挂载文件系统并重置密码

mount -o remount,rw /        # 重新挂载根目录为可写
passwd username             # 替换 username 为你的用户名(如 ubuntu)
sync                        # 同步数据到磁盘
exec /sbin/init             # 重启系统

三、预防措施

  1. 记录密码:安装系统时务必记录设置的密码。
  2. 使用 SSH 密钥登录(推荐):
    # 在宿主机生成密钥对
    ssh-keygen -t ed25519
    # 将公钥复制到虚拟机
    ssh-copy-id -i ~/.ssh/id_ed25519.pub -p 2222 user@localhost
    

四、快速验证方法

如果无法重置密码,可重新创建虚拟机并确保记录密码

# 删除旧虚拟磁盘
rm ubuntu-driver.qcow2
# 重新安装系统(注意安装过程中设置密码)
qemu-system-x86_64 ... -cdrom ubuntu-22.04.3-live-server-amd64.iso

通过以上步骤,你应该能恢复或重置虚拟机的登录密码。如果仍有问题,建议重新安装系统并确保在安装过程中正确设置凭据。
一、重装的话需要清理旧虚拟环境
删除旧的虚拟磁盘文件
bash
rm ubuntu-driver.qcow2
创建新的虚拟磁盘

bash
qemu-img create -f qcow2 ubuntu-driver.qcow2 20G

安装成功以后移除-cdrom ubuntu-22.04.4-live-server-amd64.iso 启动ubuntu -nographic这个参数安装的时候去掉 用图形化的 不然默认密码没设置ssh登录没密码

qemu-system-x86_64 -machine accel=hvf,type=q35 -cpu host -smp 4 -m 4G -drive file=ubuntu-driver.qcow2,format=qcow2 -net nic -net user,hostfwd=tcp::2222-:22

宿主机ssh登录

ssh -p 2222 username@localhost

ubuntu正确关闭

sudo poweroff

在 macOS 的 QEMU 虚拟机中安装 Ubuntu 后,学习 Linux 驱动开发可以遵循以下系统化的步骤:


1. 确认开发环境

  • 安装编译工具和内核头文件
    sudo apt update
    sudo apt install build-essential git
    sudo apt install linux-headers-$(uname -r)  # 安装当前内核版本的头文件
    
  • 验证内核模块编译环境
    创建一个测试目录,编写一个简单的 hello.c 内核模块:
    #include <linux/init.h>
    #include <linux/module.h>
    
    MODULE_LICENSE("GPL");
    
    static int __init hello_init(void) {
        printk(KERN_INFO "Hello, Linux Driver!\n");
        return 0;
    }
    
    static void __exit hello_exit(void) {
        printk(KERN_INFO "Goodbye, Linux Driver!\n");
    }
    
    module_init(hello_init);
    module_exit(hello_exit);
    
    编写 Makefile
    obj-m += hello.o
    all:
        make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules
    clean:
        make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean
    
    编译并加载模块:
    make
    sudo insmod hello.ko
    dmesg | tail  # 查看输出
    sudo rmmod hello
    

2. 学习内核模块基础

  • 核心概念
    • 模块初始化 (module_init) 和退出 (module_exit)
    • 使用 printk 输出日志(注意日志级别)
    • 模块参数传递 (module_param)
  • 调试技巧
    • dmesg -w 实时监控内核日志
    • 使用 sudo modinfo hello.ko 查看模块信息

3. 实现字符设备驱动

  • 关键步骤
    1. 分配设备号
      dev_t dev = MKDEV(major_num, 0);
      int ret = alloc_chrdev_region(&dev, 0, 1, "my_device");
      
    2. 创建设备类
      struct class *cls = class_create(THIS_MODULE, "my_class");
      
    3. 实现文件操作接口 (file_operations):
      static struct file_operations fops = {
          .owner = THIS_MODULE,
          .read = my_read,
          .write = my_write,
          .open = my_open,
          .release = my_release,
      };
      
    4. 注册字符设备
      cdev_init(&my_cdev, &fops);
      cdev_add(&my_cdev, dev, 1);
      
    5. 创建设备节点
      sudo mknod /dev/my_device c <major> 0
      

4. 在 QEMU 中调试驱动

  • 启用内核调试符号
    重新编译内核(可选,适合深入学习):
    apt install linux-source-$(uname -r)
    tar -xf /usr/src/linux-source-*.tar.xz
    cd linux-source-*/
    make menuconfig  # 确保启用 CONFIG_DEBUG_INFO
    make -j$(nproc)
    
  • 使用 QEMU 和 GDB
    启动 QEMU 时添加调试选项:
    qemu-system-x86_64 -kernel /path/to/bzImage -s -S
    
    在另一个终端中连接 GDB:
    gdb vmlinux
    (gdb) target remote :1234
    

5. 实战项目:虚拟硬件驱动

  • 模拟一个虚拟设备
    1. 在 QEMU 中通过 -device 添加虚拟 PCI 设备(需自定义设备模型,较复杂)。
    2. 更简单的方式:编写一个基于内存的虚拟字符设备驱动(例如实现一个可读写的缓冲区)。
  • 代码示例(部分):
    static char device_buffer[1024];
    
    static ssize_t my_read(struct file *filp, char __user *buf, size_t len, loff_t *off) {
        if (*off >= sizeof(device_buffer)) return 0;
        size_t remaining = sizeof(device_buffer) - *off;
        len = min(len, remaining);
        if (copy_to_user(buf, device_buffer + *off, len)) return -EFAULT;
        *off += len;
        return len;
    }
    

6. 学习资源推荐


7. 常见问题解决

  • 模块版本不匹配
    sudo apt install linux-modules-extra-$(uname -r)
    sudo depmod -a
    
  • 权限问题
    sudo chmod 666 /dev/my_device  # 临时解决设备节点权限
    

通过以上步骤,你可以在虚拟机中安全地探索 Linux 驱动开发。从简单模块开始,逐步过渡到复杂设备驱动,结合调试工具和社区资源,持续实践和迭代。

ubuntu@ubuntu:~/cstudy$ vim hello.c
ubuntu@ubuntu:~/cstudy$ vim Makefile
ubuntu@ubuntu:~/cstudy$ make
Makefile:3: *** missing separator. Stop.
ubuntu@ubuntu:~/cstudy$ vim Makefile
ubuntu@ubuntu:~/cstudy$ make
make -C /lib/modules/5.15.0-138-generic/build M=/home/ubuntu/cstudy modules
make[1]: Entering directory '/usr/src/linux-headers-5.15.0-138-generic'
CC [M] /home/ubuntu/cstudy/hello.o
MODPOST /home/ubuntu/cstudy/Module.symvers
CC [M] /home/ubuntu/cstudy/hello.mod.o
LD [M] /home/ubuntu/cstudy/hello.ko
BTF [M] /home/ubuntu/cstudy/hello.ko
Skipping BTF generation for /home/ubuntu/cstudy/hello.ko due to unavailability of vmlinux
make[1]: Leaving directory '/usr/src/linux-headers-5.15.0-138-generic'
ubuntu@ubuntu:~/cstudy$ sudo insmod hello.ko
ubuntu@ubuntu:~/cstudy$ dmesg | tail
dmesg: read kernel buffer failed: Operation not permitted
ubuntu@ubuntu:~/cstudy$ sudo dmesg | tail
[ 14.525355] clocksource: wd-tsc-wd read-back delay of 241000ns, clock-skew test skipped!
[ 16.114050] loop3: detected capacity change from 0 to 8
[ 16.538507] kauditd_printk_skb: 29 callbacks suppressed
[ 16.538510] audit: type=1400 audit(1745668628.982:41): apparmor="STATUS" operation="profile_replace" profile="unconfined" name="/usr/lib/snapd/snap-confine" pid=821 comm="apparmor_parser"
[ 16.569251] audit: type=1400 audit(1745668629.010:42): apparmor="STATUS" operation="profile_replace" profile="unconfined" name="/usr/lib/snapd/snap-confine//mount-namespace-capture-helper" pid=821 comm="apparmor_parser"
[ 316.908635] clocksource: timekeeping watchdog on CPU2: hpet wd-wd read-back delay of 563000ns
[ 316.908648] clocksource: wd-tsc-wd read-back delay of 258000ns, clock-skew test skipped!
[ 500.400671] hello: loading out-of-tree module taints kernel.
[ 500.400849] hello: module verification failed: signature and/or required key missing - tainting kernel
[ 500.403079] Hello, Linux Driver!
ubuntu@ubuntu:~/cstudy$ sudo rmmod hello
ubuntu@ubuntu:~/cstudy$ sudo dmesg | tail
[ 16.538510] audit: type=1400 audit(1745668628.982:41): apparmor="STATUS" operation="profile_replace" profile="unconfined" name="/usr/lib/snapd/snap-confine" pid=821 comm="apparmor_parser"
[ 16.569251] audit: type=1400 audit(1745668629.010:42): apparmor="STATUS" operation="profile_replace" profile="unconfined" name="/usr/lib/snapd/snap-confine//mount-namespace-capture-helper" pid=821 comm="apparmor_parser"
[ 316.908635] clocksource: timekeeping watchdog on CPU2: hpet wd-wd read-back delay of 563000ns
[ 316.908648] clocksource: wd-tsc-wd read-back delay of 258000ns, clock-skew test skipped!
[ 500.400671] hello: loading out-of-tree module taints kernel.
[ 500.400849] hello: module verification failed: signature and/or required key missing - tainting kernel
[ 500.403079] Hello, Linux Driver!
[ 628.092069] clocksource: timekeeping watchdog on CPU2: hpet wd-wd read-back delay of 380000ns
[ 628.092080] clocksource: wd-tsc-wd read-back delay of 213000ns, clock-skew test skipped!
[ 647.172756] Goodbye, Linux Driver!
ubuntu@ubuntu:~/cstudy$ sudo modinfo hello.ko
filename: /home/ubuntu/cstudy/hello.ko
license: GPL
srcversion: BB1EF5C5FB26E9AA50C887B
depends:
retpoline: Y
name: hello
vermagic: 5.15.0-138-generic SMP mod_unload modversions

posted @ 2025-04-26 02:38  奔付山河  阅读(215)  评论(0)    收藏  举报