如何测试自己的Linux模块?

时间:2014-09-27 17:10:12

标签: linux linux-kernel linux-device-driver

今天我开始开发Linux模块。编写,编译和与Helloworld合作相当困难,但我已经完成了。

我的第二个模块具有开放,写入和读取功能,但我真的不知道如何测试它。 Write方法只是生成printk()。我的模块已加载,其名称为iamnoob。如何测试这个write(...)函数并在var / log / syslog中找到smth? 猫> iamnoob只是将文件写入目录。与cp和其他相同。

对于noob问题,我已经用谷歌搜索了,但没有找到答案。抱歉英语不好。

1 个答案:

答案 0 :(得分:2)

基本内核模块通常包括注册字符设备。 简单的实现需要:

  • 注册具有特定主要&的chrdev区域较小。
  • 分配文件操作结构并实现基本的读/写API。
  • 使用文件操作结构初始化并将字符设备注册到主要/次要区域。

请参阅以下代码段作为模块的模板(仅读取/写入API):

#include <linux/module.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <asm-generic/uaccess.h>

#define MY_BUFFER_SIZE   (1024 * 10)
#define MY_CHRDEV_MAJOR  217
#define MY_CHRDEV_MINOR  0

static struct cdev my_cdev;
static unsigned char *my_buf;
static dev_t my_dev = MKDEV(MY_CHRDEV_MAJOR, MY_CHRDEV_MINOR);

ssize_t my_read(struct file *file, char __user * buf, size_t count, loff_t * ppos)
{
    int size;

    size = MY_BUFFER_SIZE - 100 - (int)*ppos;
    if (size > count)
        size = count;

    if (copy_to_user(buf, my_buf + *ppos, count))
        return -EFAULT;

    *ppos += size;
    return size;
}

ssize_t my_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos)
{
    int size;

    size = MY_BUFFER_SIZE - 100 - (int)*ppos;
    if (size > count)
        size = count;

    if (copy_from_user(my_buf + *ppos, buf, count))
        return -EFAULT;

    *ppos += size;
    return size;
}

long my_unlocked_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
    printk ("%s!\n", __FUNCTION__);
    return 0;
}

int my_mmap(struct file *f, struct vm_area_struct *vma)
{
    printk ("%s!\n", __FUNCTION__);
    return 0;
}
int my_open(struct inode *i, struct file *f)
{
    printk ("%s!\n", __FUNCTION__);
    return 0;
}
int my_release(struct inode *i, struct file *f)
{
    printk ("%s!\n", __FUNCTION__);
    return 0;
}

struct file_operations my_fops =
{
    .owner =   THIS_MODULE,
    .read =    &my_read,
    .write =   &my_write,
    .unlocked_ioctl = &my_unlocked_ioctl,
    .mmap =    &my_mmap,
    .open =    &my_open,
    .release = &my_release,
};


static int __init my_module_init(void)
{
    int line = 0;
    unsigned char *pos;

    printk ("%s!\n", __FUNCTION__);
    my_buf = (unsigned char *)kzalloc(MY_BUFFER_SIZE, 0);
    if (my_buf == NULL) {
        printk("%s - failed to kzallocate buf!\n", __FUNCTION__);
        return -1;
    }
    pos = my_buf;
    while (pos - my_buf < MY_BUFFER_SIZE - 100) {
        sprintf(pos, "Line #%d\n", line++);
        pos += strlen(pos);
    }
    cdev_init(&my_cdev, &my_fops);
    if (register_chrdev_region(my_dev, 1, "my_dev")) {
        pr_err("Failed to allocate device number\n");
    }
    cdev_add(&my_cdev, my_dev, 1);
    printk ("%s - registered chrdev\n", __FUNCTION__);
    return 0;
}

static void __exit my_module_exit(void)
{
    printk ("my_module_exit.\n");
    unregister_chrdev_region(my_dev, 1);
    return;
}
module_init(my_module_init);
module_exit(my_module_exit);
MODULE_LICENSE("GPL");

该模块使用缓冲区进行文件操作,因此可以在任何机器上进行测试,无论其硬件如何。确保避免不必要的printk,因为循环可能会损害内核的稳定性。

完成此操作后,在用户空间shell中,您应该创建一个/ dev节点来表示您的角色设备:

sudo mknod /dev/[dev_name] c [major] [minor]

例如:

sudo mknod /dev/my_dev c 217 0

然后,您可以使用以下命令测试读/写API:

sudo insmod my_modult.ko
cat /dev/my_dev
less -f /dev/my_dev
sudo su
root> echo "This is a test" > /dev/my_dev
root> exit
cat /dev/my_dev

上面列出的shell命令执行read,然后以root身份登录(允许写入设备),写入char dev,然后退出并再次读取以查看更改。

现在,如果需要,您通常会实施ioctl和mmap。