【OS】操作系统-实验四:驱动程序的编写


操作环境:

  • 主机:MacOS 10.13.3
  • 虚拟机软件:Parallels Desktop
  • Linux:Ubuntu 16.04 Kernal 4.13.0-36-generic

实验要求:

  1. 编写一个字符设备驱动程序,要求实现对该字符设备的打开、读、写、I/O控制和关闭 5 个基本操作。为了避免牵涉到汇编语言,这个字符设备并非一个真实的字符设备,而是用一段内存空间来模拟的。以模块方式加载该驱动程序。

  2. 编写一个应用程序,测试(1)中实现的驱动程序的正确性。

  3. 有兴趣的读者还可以编写一个块设备的驱动程序。

  4. 请根据自身情况,进一步阅读分析程序中用到的相关内核函数的源码实现。

操作说明:

  • 储存空间设计:

    • 一个char类型的指针作为字符设备
    • 由于无法使用malloc()函数,所以空间变化使用一大一小两个数组暴力表示
    • 小空间大小为32字节,大空间大小为64字节,用于测试ioctl()
  • 五个操作函数的实现:

    1. OPEN:
      • dmesg输出 char_dev device open
    2. WRITE:
      • dmesg输出 char_dev device is write!
      • 将信息拷贝给用户
    3. READ:dmesg输出 char_dev device is read!
      • 从用户拷贝信息到数组
    4. RELEASE:
      • dmesg输出 char_dev device release!
    5. IOCTL:
      • cmd = 0: dmesg输出 char_dev device received cmd 0!
      • cmd = 1: 换一个大一点的储存空间
      • 其他:dmesg输出 No such command!
  • 建立设备节点:# mknod /dev/aeonnicdev 666 0

  • 测试命令:$ make && sudo insmod aeonni_Cdriver.ko && gcc test.c -o test && ./test && sudo rmmod aeonni_Cdriver

  • 测试结果:
    result.png

附录:

  1. 驱动内核模块代码 aeonni_Cdriver.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
#include <linux/fs.h>
#include <linux/types.h>
#include <linux/cdev.h>
#include <linux/uaccess.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/slab.h>

#define DEV_MAJOR 666
#define DEV_MINOR 0
#define aeonni_count 1

static char mem1[32];
static char mem2[64] ;

static char *mem = mem1;


static struct cdev my_cdev;

static int char_dev_open(struct inode *inode, struct file *filp) {
printk("char_dev device open! \n");
return 0;
}

ssize_t char_dev_read(struct file *file, char __user *buff, size_t count, loff_t *offp) {
printk("char_dev device is read! \n");
copy_to_user(buff, mem, count);
return count;
}

ssize_t char_dev_write(struct file *file, const char __user *buff, size_t count, loff_t *offp) {
printk("char_dev device is write! \n");
copy_from_user(mem, buff, count);
return count;
}

static long char_dev_ioctl(struct file *flip, unsigned int cmd, unsigned long arg) {
switch(cmd) {
case 0: printk("char_dev device received cmd 0! \n"); break;
case 1: mem = mem2; printk("Mem growed! \n"); break;
default: printk("No such command! \n");
}
}

static int char_dev_release(struct inode *inode, struct file *file) {
printk("char_dev device release! \n");
return 0;
}


static struct file_operations aeonni_fops =
{
.owner = THIS_MODULE,
.open = char_dev_open,
.release = char_dev_release,
.read = char_dev_read,
.write = char_dev_write,
.unlocked_ioctl = char_dev_ioctl,
};

static void __exit aeonni_cdev_exit(void) {

printk("Exit aeonni_cdev!\n");

cdev_del(&my_cdev);

dev_t aeonni_dev_t = MKDEV(DEV_MAJOR, DEV_MINOR);
unregister_chrdev_region(aeonni_dev_t, aeonni_count);

}

static int __init aeonni_cdev_init(void) {

printk("Init aeonni_cdev!\n");

dev_t aeonni_dev_t = MKDEV(DEV_MAJOR, DEV_MINOR);

register_chrdev_region(aeonni_dev_t, aeonni_count, "aeonni_cdev");

cdev_init(&my_cdev, &aeonni_fops);
my_cdev.owner = THIS_MODULE;

// registe cdev struct
cdev_add(&my_cdev, aeonni_dev_t, aeonni_count);
return 0;
}

module_init(aeonni_cdev_init);
module_exit(aeonni_cdev_exit);

MODULE_LICENSE("GPL");
MODULE_AUTHOR("Genius.AEONNI.COM");
MODULE_DESCRIPTION("This module is for the Exercise5.");
  1. 测试代码 test.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
#include <stdio.h>  
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/syscall.h>
#include <sys/ioctl.h>

char str[100];

int main() {
int fp = 0;
fp = open("/dev/aeonnicdev",O_RDWR);
printf("%d\n",fp);
read(fp, str, 10);
printf("%s\n",str);
write(fp,"abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz",52);
read(fp, str, 10);
ioctl(fp,1);
write(fp,"abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz",52);
read(fp, str, 10);
printf("%s\n",str);
ioctl(fp,0);
ioctl(fp,2);
close(fp);

return 0;
}

Comments

Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×