ubuntu下调试驱动

使用 Ubuntu Linux 测试 Linux 驱动

1. 测试 Linux 驱动准备工作

​ 对于一个 Linux 驱动程序,一开始可以在 Ubuntu Linux 上做前期开发和测试。对于访问硬件部分也可以在 Ubuntu Linux 用软件进行模拟,切记不能代替真实的环境!当基本开发完成后,就需要在开发板或工程样机上使 用真实的硬件进行测试,当然,最后还需要在最终销售的产品上进行测试。最终测试通过,Linux 驱动才能算真 正开发完成。

1.1 实现步骤

1)先测试自己 ubuntu 虚拟机的版本号

sun@ubuntu:~$ uname -r

2)找到对应版本的内核源码编译的目录:

sun@ubuntu:/lib/modules$ ls
5.15.0-43-generic  5.15.0-56-generic  5.19.0-32-generic
5.15.0-53-generic  5.15.0-60-generic  5.19.0-35-generic

sun@ubuntu:/lib/modules$ cd 5.19.0-32-generic
sun@ubuntu:/lib/modules/5.19.0-32-generic$ ls
build              modules.builtin.alias.bin  modules.order
initrd             modules.builtin.bin        modules.softdep
kernel             modules.builtin.modinfo    modules.symbols
modules.alias      modules.dep                modules.symbols.bin
modules.alias.bin  modules.dep.bin            vdso
modules.builtin    modules.devname

sun@ubuntu:/lib/modules/5.19.0-32-generic$ cd build
sun@ubuntu:/lib/modules/5.19.0-32-generic/build$ ls
arch    Documentation  init      Kconfig   mm              scripts   ubuntu
block   drivers        io_uring  kernel    Module.symvers  security  usr
certs   fs             ipc       lib       net             sound     virt
crypto  include        Kbuild    Makefile  samples   

3)修改测试驱动程序的 Makefile 文件

KERNEL_DIR = /lib/modules/5.19.0-32-generic/build #ubuntu 内核目录
CUR_DIR = $(shell pwd)
MYAPP = virtdev_test
all:
	make -C $(KERNEL_DIR) M=$(CUR_DIR) modules
	gcc -o $(MYAPP) $(MYAPP).c
clean:
	make -C $(KERNEL_DIR) M=$(CUR_DIR) clean
	rm -rf $(MYAPP)
obj-m = virtdev_drv.o

2. 测试驱动程序

2.1 编写驱动程序 virtdev_drv.c

#include <linux/module.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/miscdevice.h>
#include <asm/uaccess.h>
#include <asm/atomic.h>
// 定义设备文件名
#define DEVICE_NAME "virtdev"
static int atom = 0;
// 参数 atom=0: 多个进程可以同时打开 vritdev 设备文件
// 参数 atom 非 0:同时只能有一个进程打开 virtdev 设备文件
static atomic_t int_atomic_available = ATOMIC_INIT(1);
// 原子变量值为 1
static int virtdev_open(struct inode *node, struct file *file)
{
    if (atom)
    {
        if (!atomic_dec_and_test(&int_atomic_available))
        {
            atomic_inc(&int_atomic_available);
            return -EBUSY;
        }
    }
    return 0;
}

static int virtdev_close(struct inode *node, struct file *file)
{
    if (atom)
    {
        atomic_inc(&int_atomic_available);
    }
    return 0;
}

static struct file_operations dev_fops =
{
    .owner = THIS_MODULE,
    .open = virtdev_open,
    .release = virtdev_close
};

static struct miscdevice misc = {
    .minor = MISC_DYNAMIC_MINOR,
    .name = DEVICE_NAME,
    .fops = &dev_fops
};

// 初始化 Linux 驱动
static int __init virtdev_init(void)
{
    // 建立设备文件
    int ret = misc_register(&misc);
    printk("<jaylen> atomic=%d\n", atom);
    printk("virtdev_init_success\n");
    return ret;
}

// 卸载 Linux 驱动
static void __exit virtdev_exit(void)
{
    printk("<jaylen> atomic=%d\n", atom);
    printk("<jaylen> virtdev_exit_success\n");
    // 删除设备文件
    misc_deregister(&misc);
}

// 注册初始化 Linux 驱动的函数
module_init(virtdev_init);
// 注册卸载 Linux 驱动的函数
module_exit(virtdev_exit);

module_param(atom, int, S_IRUGO | S_IWUSR);
MODULE_LICENSE("GPL");

2.2 编写应用程序 virtdev_test.c

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <errno.h>
int main(int argc, char *argv[])
{
    printf("app pid=%d is running\n", getpid());
    int fd = open("/dev/virtdev", O_RDWR);
    printf("ret:%d\n", fd);
    if (fd < 0)
    {
        printf("errno:%d\n", errno);
    }
    else
    {
        sleep(10);
        close(fd);
    }
    printf("app pid=%d is over\n", getpid());
    return 0;
}

2.3 编译驱动

在 ubuntu 普通用户下完成编译驱动

un@ubuntu:ubuntu_drv_test$ make
make -C /lib/modules/5.19.0-32-generic/build M=/home/sun/work/ubuntu_drv_test modules
make[1]: 进入目录“/usr/src/linux-headers-5.19.0-32-generic”
warning: the compiler differs from the one used to build the kernel
  The kernel was built by: x86_64-linux-gnu-gcc (Ubuntu 11.3.0-1ubuntu1~22.04) 11.3.0
  You are using:           gcc (Ubuntu 11.3.0-1ubuntu1~22.04) 11.3.0
  CC [M]  /home/sun/work/ubuntu_drv_test/virtdev_drv.o
  MODPOST /home/sun/work/ubuntu_drv_test/Module.symvers
  CC [M]  /home/sun/work/ubuntu_drv_test/virtdev_drv.mod.o
  LD [M]  /home/sun/work/ubuntu_drv_test/virtdev_drv.ko
  BTF [M] /home/sun/work/ubuntu_drv_test/virtdev_drv.ko
Skipping BTF generation for /home/sun/work/ubuntu_drv_test/virtdev_drv.ko due to unavailability of vmlinux
make[1]: 离开目录“/usr/src/linux-headers-5.19.0-32-generic”
gcc -o virtdev_test virtdev_test.c

1.2.4 测试驱动

在 ubuntu 下需要切换到管理员用户下才能安装测试驱动

sun@ubuntu:ubuntu_drv_test$ sudo su
root@ubuntu:/home/sun/work/ubuntu_drv_test# ls
hello_test     Module.symvers  virtdev_drv.mod    virtdev_drv.o
Makefile       virtdev_drv.c   virtdev_drv.mod.c  virtdev_test
modules.order  virtdev_drv.ko  virtdev_drv.mod.o  virtdev_test.c


安装驱动

root@ubuntu:/home/sun/work/ubuntu_drv_test# insmod virtdev_drv.ko 

传参加载驱动

root@ubuntu:/home/sun/work/ubuntu_drv_test# insmod virtdev_drv.ko atom=1

打印并清空缓冲区日志 dmesg -c, 以下是测试过程

驱动加载过程

root@ubuntu:/home/sun/work/ubuntu_drv_test# dmesg
[25849.067381] <robin> atomic=0
[25849.067387] <robin> virtdev_exit_success
[25867.980387] <robin> atomic=1
[25867.980395] virtdev_init_success

root@ubuntu:/home/sun/work/ubuntu_drv_test# lsmod
Module                  Size  Used by
virtdev_drv            16384  1

root@ubuntu:/home/sun/work/ubuntu_drv_test# ls /dev/virtdev -al
crw------- 1 root root 10, 121  3月 11 22:14 /dev/virtdev

用户测试

sun@ubuntu:ubuntu_drv_test$ sudo ./virtdev_test 
app pid=43934 is running
ret:3
app pid=43934 is over

驱动卸载

root@ubuntu:/home/sun/work/ubuntu_drv_test# rmmod virtdev_drv
root@ubuntu:/home/sun/work/ubuntu_drv_test# dmesg 
[25849.067381] <robin> atomic=0
[25849.067387] <robin> virtdev_exit_success
[25867.980387] <robin> atomic=1
[25867.980395] virtdev_init_success
[26054.089448] <robin> atomic=1
[26054.089456] <robin> virtdev_exit_success

3 Linux 内核日志查看之 dmesg 命令简介

Linux 内核启动时会加载硬件驱动,在有新硬件时也会加载驱动,如果想要查看内核的活动,可以使用 dmesg 命令。Linux 内核日志存储在一个 ring-buffer 中,它的大小是固定的,当队列满时,新的消息会覆盖掉最旧的消 息。实际上,在 boot 阶段,所有的应用还没有启动,syslogd 也未启动,这时内核日志是非常重要的信息。 除了设备初始化日志、内核模块日志,它还会包含一些应用崩溃的相关信息记录,了解 dmesg 的使用对于调 试程序相当重要。

对于嵌入式设备的调试,它会比较清楚地展现当前的 log 信息。 dmesg -c 显示并清除当前的日志内容。 下次再 dmesg 时就没有以前的日志了。

  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Engineer-Jaylen_Sun

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值