【HUST】网安|操作系统实验|实验四 设备管理、文件管理
文章目錄
- 任務
- 任務1 編寫一個Linux內核模塊,并完成安裝/卸載等操作。
- 1. 提示
- 2. 任務代碼
- 3. 結果及說明
- 任務2 編寫Linux驅動程序并編程應用程序測試。
- 1. 提示
- 2. 任務代碼
- 3. 結果及說明
- 任務3 編寫Linux驅動程序并編程應用程序測試。
- 1. 提示
- 2. 任務代碼
- 3. 結果及說明
任務
一、實驗目的
1)理解設備是文件的概念。
2)掌握Linux模塊、驅動的概念和編程流程
3)Windows /Linux下掌握文件讀寫基本操作
二、實驗內容
1)編寫一個Linux內核模塊,并完成安裝/卸載等操作。
2)編寫Linux驅動程序并編程應用程序測試。功能:write幾個整數進去,read出其和或差或最大值。
3)編寫Linux驅動程序并編程應用程序測試。功能:有序讀寫內核緩沖區,返回實際讀寫字節數。
任務1 編寫一個Linux內核模塊,并完成安裝/卸載等操作。
1. 提示
提示1:安裝時和退出時在內核緩沖區顯示不同的字符串。
提示2:相關函數:module_init( )、 module_exit( )
提示3: MODULE_LICENSE( )、 MODULE_AUTHOR ( )等可選
提示4:安裝命令:insmod XXXX.ko
提示5:擴展:編寫帶參數的模塊程序
int mytest = 100;
module_param(mytest, int, 0644);
2. 任務代碼
先安裝一個必要的軟件包(否則會有warning):
sudo apt install libelf-dev
文件code1.c:
#include<linux/init.h>
#include<linux/kernel.h>
#include<linux/module.h>
#include<linux/moduleparam.h>
#include<linux/sched.h>
MODULE_LICENSE("GPL");
static char* yourID="shandianchengzi";
module_param(yourID,charp,0644);
static int code1_init(void){
//輸出歡迎信息
printk(KERN_ALERT"Hello, dear %s!\n", yourID);
return 0;
}
static void code1_exit(void){
printk(KERN_ALERT"Goodbye, %s!\n", yourID);
}
module_init(code1_init);
module_exit(code1_exit);
Makefile:
obj-m += code1.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
然后運行:
sudo make
3. 結果及說明
1)模塊作用:實驗文件編譯生成的ko模塊可接收charp型參數,默認為"shandianchengzi"。當用戶加載模塊時輸出"Hello, dear 參數!\n",退出時輸出"GoodBye, 參數!\n"。
2)如何向模塊中傳入參數:函數原型module_param(name, type, perm),參數name,type是自己定義的變量的類型,perm是權限。
其中常用的權限:①0755->用戶具有讀/寫/執行權限,組用戶和其它用戶具有讀/寫權限;②0644->用戶具有讀/寫權限,組用戶和其它用戶具有只讀權限;
一般賦予目錄0755權限,而文件賦予0644權限。
3)編譯:
4)結果:
先用sudo dmesg -C清空緩沖區,然后使用sudo insmod code1.ko yourID='shandianchengzi'裝入內核并修改參數值,再dmesg顯示當前內容。再使用sudo rmmod code1.ko卸載內核,再dmesg顯示當前內容。與預期相符。
參考:
主要:Linux中添加一個帶參數的模塊
傳入字符串的設計:第四章Linux內核模塊之五(模塊參數)
任務2 編寫Linux驅動程序并編程應用程序測試。
1. 提示
提示1:參考任務1
提示2:至少實現xx_open,xx_write,xx_read等函數
提示3:功能:
xx_write( )寫進去2個整數
xx_read( )讀回結果(和或差或最大值)
提示4: [可選的設備注冊方式,其余方式參考baidu]
struct miscdevice mydemodrv_misc_device ;
ret = misc_register( &mydemodrv_misc_device )
2. 任務代碼
code2.c:
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/uaccess.h>
#include <linux/init.h>
#include <linux/miscdevice.h>
#define NAME "code2"
MODULE_LICENSE("GPL");
static struct device *mydemodrv_device;
static int a=0,b=0;
static int demodrv_open(struct inode *inode, struct file *file)
{
int major = MAJOR(inode->i_rdev);
int minor = MINOR(inode->i_rdev);
printk("%s: major=%d, minor=%d\n", __func__, major, minor);
return 0;
}
static int demodrv_release(struct inode *inode, struct file *file)
{
return 0;
}
static ssize_t
demodrv_read(struct file *file, char __user *buf, size_t lbuf, loff_t *ppos)
{
printk("%s: a+b=%d\n", __func__,a+b);
return 0;
}
static ssize_t
demodrv_write(struct file *file, const char __user *buf, size_t count, loff_t *f_pos)
{
if(count>64)
{
count = 64;
}
char temp[64];
if(copy_from_user(temp,buf,count))
{
return -EFAULT;
}
sscanf(temp, "%d%d",&a,&b);
printk("%s: a=%d,b=%d\n", __func__,a,b);
return count;
}
static const struct file_operations demodrv_fops = {
.owner = THIS_MODULE,
.open = demodrv_open,
.release = demodrv_release,
.read = demodrv_read,
.write = demodrv_write
};
static struct miscdevice mydemodrv_misc_device = {
.minor = MISC_DYNAMIC_MINOR,
.name = NAME,
.fops = &demodrv_fops,
};
static int __init code2_init(void)
{
int ret;
ret = misc_register(&mydemodrv_misc_device);
if (ret) {
printk("failed register code2 misc device\n");
return ret;
}
mydemodrv_device = mydemodrv_misc_device.this_device;
printk("succeeded register char device: %s\n", NAME);
return 0;
}
static void __exit code2_exit(void)
{
printk("removing device: %s\n", NAME);
misc_deregister(&mydemodrv_misc_device);
}
module_init(code2_init);
module_exit(code2_exit);
測試程序:
test.c:
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#define DEV_NAME "/dev/code2"
int main()
{
char buffer[64];
int fd,a,b;
fd = open(DEV_NAME, O_RDWR | O_CREAT);
if (fd < 0) {
printf("open device %s failded\n", DEV_NAME);
return -1;
}
printf("請輸入兩個整數:");
scanf("%d%d",&a,&b);
sprintf(buffer,"%d %d",a,b);
write(fd,buffer,64);
read(fd, buffer, 64);
close(fd);
return 0;
}
3. 結果及說明
1)編譯:
2)結果:完成的是求和功能。
3)遇到的問題:最開始,打開文件指針的時候用了O_RDONLY,只讀。后來寫write的時候死活讀不進去。。。
懷疑是中間文件沒刪、模塊代碼返回值不能size_t強轉ssize_t等問題,結果原來是因為這個。。。。。。。
改成O_RDWR | O_CREAT。
參考:《內核kernel:misc機制字符設備驅動模塊編寫》
O_RDWR | O_CREAT參考:3.8 write函數-文件數據寫
4)用的方法是先讀入緩沖區,再用sscanf讀。我覺得傳整型指針有點麻煩,要寫兩個write。
5)設備讀不了寫不了裝不了用不了沒輸出:
甚至把模塊卸載了,它還在!
這是因為在裝入模塊之前,不慎調用test程序,已經提前申請打開了設備,以致于裝載的時候未裝載成功。
如果出現這種情況,運行:
sudo rm /dev/code2
任務3 編寫Linux驅動程序并編程應用程序測試。
1. 提示
提示1:參考任務1
提示2:至少實現xx_open,xx_write,xx_read等函數
提示3:功能:
內核分配一定長度的緩沖區,比如64字節。
xx_write()寫進去若干字符,注意維護寫入位置。下次繼續寫的話,接著該位置往后寫,直到緩沖區末尾。要返回實際寫入字數。
xx_read()讀出若干字符串,注意維護讀出位置。下次繼續讀的話,接著該位置往后讀,直到緩沖區末尾。要返回實際讀回字數。
擴展:
▲緩沖區設置為循環緩沖區?
▲如何避免寫覆蓋,避免讀重復?
2. 任務代碼
code3.c
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/uaccess.h>
#include <linux/init.h>
#include <linux/miscdevice.h>
#include <linux/slab.h> /*kmalloc*/
#define NAME "code3"
MODULE_LICENSE("GPL");
static struct device *mydemodrv_device;
static char *device_buffer;
static size_t pos;
#define MAX_DEVICE_BUFFER_SIZE 64
static int demodrv_open(struct inode *inode, struct file *file)
{
device_buffer = kmalloc(MAX_DEVICE_BUFFER_SIZE, GFP_KERNEL);
pos=0;
return 0;
}
static ssize_t
demodrv_read(struct file *file, char __user *buf, size_t lbuf, loff_t *ppos)
{
if(pos < lbuf)
{
lbuf = pos;
}
if(copy_to_user(buf,device_buffer+pos-lbuf,lbuf))
{
return -EFAULT;
}
pos=pos-lbuf;
printk("%s: 讀出%ld字節,讀出后指針位置為%ld\n", __func__, lbuf, pos);
return lbuf;
}
static ssize_t
demodrv_write(struct file *file, const char __user *buf, size_t count, loff_t *f_pos)
{
if(pos + count > 64)
{
count = 64-pos;
if(count < 0)
return count;
}
if(copy_from_user(device_buffer+pos,buf,count))
{
return -EFAULT;
}
pos=pos+count;
printk("%s: 寫入%ld字節,寫完后緩沖區為%s\n", __func__, count, device_buffer);
return count;
}
static const struct file_operations demodrv_fops = {
.owner = THIS_MODULE,
.open = demodrv_open,
.read = demodrv_read,
.write = demodrv_write
};
static struct miscdevice mydemodrv_misc_device = {
.minor = MISC_DYNAMIC_MINOR,
.name = NAME,
.fops = &demodrv_fops,
};
static int __init code3_init(void)
{
int ret;
ret = misc_register(&mydemodrv_misc_device);
if (ret) {
printk("failed register code2 misc device\n");
return ret;
}
mydemodrv_device = mydemodrv_misc_device.this_device;
printk("succeeded register char device: %s\n", NAME);
return 0;
}
static void __exit code3_exit(void)
{
kfree(device_buffer);
printk("removing device: %s\n", NAME);
misc_deregister(&mydemodrv_misc_device);
}
module_init(code3_init);
module_exit(code3_exit);
測試程序:
test.c:
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#define DEV_NAME "/dev/code3"
int main()
{
char buffer[64];
int fd,a,b;
fd = open(DEV_NAME, O_RDWR | O_CREAT);
if (fd < 0) {
printf("open device %s failded\n", DEV_NAME);
return -1;
}
printf("請輸入向緩沖區寫的內容:");
scanf("%s",buffer);
write(fd,buffer,strlen(buffer));
read(fd, buffer, 64);
printf("從緩沖區讀:%s\n", buffer);
close(fd);
return 0;
}
3. 結果及說明
1)kmalloc頭文件是#include <linux/slab.h>。
2)編譯:
3)運行:
4)遇到的問題2:copy_to_user和copy_from_user的to和from參數是反過來的,一開始沒注意。
5)遇到的問題3:
下面這個不行:
if(pos - lbuf < 0)
{
lbuf = pos;
}
改成這個才行:
if(pos < lbuf)
{
lbuf = pos;
}
因為size_t是unsigned類型的,所以不能直接跟0比較。
總結
以上是生活随笔為你收集整理的【HUST】网安|操作系统实验|实验四 设备管理、文件管理的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: vivo官网APP首页端智能业务实践
- 下一篇: Vue相关笔记