操作系统(一):Linux内核模块的创建
初入操作系统的坑,作为小白的我既忐忑又兴奋,希望能把课上的一些习题记录下来,一来可以让自己以后也回顾一下,二来也算是一个小小的教程,适合初学者看看,因为本人也是小白,如果有不严谨的地方欢迎指正。
这次的project主要是写Linux内核,话不多说,先上题目。
一、作业题目
-
Design a kernel module that creates a /proc file named /proc/jiffies
that reports the current value of jiffies when the /proc/jiffies file
is read, such as with the command
cat /proc/jiffies
Be sure to remove /proc/jiffies when the module is removed.第一题大概意思就是创建一个模块名字为“jiffies”,然后在命令行中输入“cat /proc/jiffies”就可以显示当前的jiffies值(至于jiffies是什么后面再讲)。
-
Design a kernel module that creates a proc file named /proc/seconds
that reports the number of elapsed seconds since the kernel module was
loaded. This will involve using the value of jiffies as well as the HZ
rate. When a user enters the command
cat /proc/seconds
your kernel module will report the number of seconds that have
elapsed since the kernel module was first loaded. Be sure to remove
/proc/seconds when the module is removed.第二题大概意思就是创建一个模块名字为“seconds”,然后在命令行中输入“cat /proc/seonds”就可以输出HZ.
二、开始做啦
1.首先了解一下jiffies和Hz是个什么玩意儿
jiffies是linux中一个与中断次数相关的值,而Hz是一秒内时钟中断的次数,jiffies与hz的关系就是,两个时间的jiffies之差除以频率数可以得到经过的时间,即公式:
( j i f f i e s l − j i f f i e s f ) / H z = s e c o n d s (jiffiesl-jiffiesf)/Hz = seconds (jiffiesl−jiffiesf)/Hz=seconds
2.直接开始做题吧
《1》作业一
(1)在主机编写一个jiffies.c文件
/*Create a proc named jiffies*/
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/proc_fs.h>
#include <linux/jiffies.h>
#include <asm/uaccess.h>
#define BUFFER_SIZE 128
#define PROC_NAME "jiffies"
ssize_t proc_read(struct file *file,char __user *usr_buf,size_t count,loff_t *pos);/*forward declartion*/
/*Declare the ower and read function*/
static struct file_operations proc_ops ={
.owner = THIS_MODULE, /*proc所有者*/
.read = proc_read, /*访问proc时需要调用的函数(即cat /proc/jiffies时访问proc_read函数*/
};
/*要记得proc_init始终返回0,proc_exit没有返回值。*/
/*Begin call this function when the module loaded*/
int proc_init(void)
{
proc_create(PROC_NAME,0666,NULL,&proc_ops); /*创建一个proc*/
printk(KERN_INFO "The /proc/jiffies loaded!\n");
return 0;
}
void proc_exit(void)
{
remove_proc_entry(PROC_NAME,NULL); /*删除该proc*/
printk(KERN_INFO "The /proc/jiffies unloaded!\n");
}
/*Implemention of proc_read,load模块后用"cat /proc/jiffies"即可查看buffer中的str*/
ssize_t proc_read(struct file *file, char __user *usr_buf, size_t count, loff_t *pos)
{
int rv=0; /*显示的信息的长度*/
char buffer[BUFFER_SIZE]; /*信息缓冲区*/
static int completed=0;
if (completed){
completed=0;
return 0;
}
completed=1;
/*下面这行将“”中的字符存入buffer,rv为写入的字符总数,不包括字符串追加在字符串末尾的空字符*/
rv=sprintf(buffer, "Now the jiffies value is %lu\n", jiffies);
copy_to_user(usr_buf,buffer,rv); /*从内核的buffer拷贝到用户的usr_buf*/
return rv;
}
module_init(proc_init);
module_exit(proc_exit);
MODULE_LICENSE("GPL"); /*许可*/
MODULE_DESCRIPTION("Display the jiffies value"); /*模型描述*/
MODULE_AUTHOR("Lily"); /*作者*/
(2)打开linux虚拟机(此处用osc10e)
cd final-src-osc10e #进入这个文件夹
mkdir ch1 #创建ch1文件夹
(3)将主机中的jiffies文件传到虚拟机
打开主机win的cmd(注意查看是否下载了openSSH客户端)
然后输入
scp -P 2222 source target #source是本地文件的目录,target是远程机子的目录
/*例如*/
scp -P 2222 C:\Users\lenovo\Desktop\jiffies.c osc@127.0.0.1:~ #传送到虚拟机的根目录
scp -P 2222 C:\Users\lenovo\Desktop\jiffies.c osc@127.0.0.1:~ /final-src-osc10e/ch1 #传送到ch1文件夹中
(4)打开虚拟机写Makefile
cd final-src-osc10e #进入这个文件夹
mkdir ch1 #创建ch1文件夹
cd ch1 #进入ch1文件夹
vim Makefile #在vim中创建并编写Makefile文件,打开后按“i”切换为可写模式
写完后按“Esc”,然后按“:wq”,最后按回车即保存完毕
不想保存则按“:q!”
Makefile文件代码如下:(注意Tab缩进)
obj-m += jiffies.o #换文件名的话替换这里的“jiffies”就行
all:
make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules
clean:
make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean
保存完了以后就ok啦,回到ch1文件夹中
#以下命令可能用得上
cd .. #返回上一级(可能会用上)
mv source target #移动文件,例如 mv ~/ch1/1.c ~/ch2 即把1.c文件从ch1移到ch2
重命名文件,如 mv ch1 ch2 将ch1重命名为ch2
rm ch1 #删除ch1文件夹
rm -rf ch1 #强行删除ch1文件夹
(5)开始测试
sudo dmesg -c #定期清除缓存区
make #编译
sudo insmod jiffies.ko #加载jiffies内核模块
dmesg #显示proc_init函数中要打印的东西,即The /proc/jiffies loaded!
cat /proc/jiffies #显示proc_read函数中要打印的东西
sudo rmmod jiffies #删除jiffies内核模块
dmesg #显示proc_exit函数中要打印的东西,检测是否正常删除
测试效果如下:
《2》作业二
(1)在主机编写一个seconds.c文件
/*Create a proc named seconds*/
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/proc_fs.h>
#include <asm/uaccess.h>
#include <linux/jiffies.h>/*For jiffies*/
#include <asm/param.h> /*For HZ*/
#define BUFFER_SIZE 128
#define PROC_NAME "seconds"
/*volatile:每次都实时读取该变量的值,而不是读取该变量在寄存器中的值,
volatile为了防止那些非线程安全的变量的变更导致的结果错误,比如多个线程竞争a变量的修改,
得到的某个时刻的a变量的值就不一定是当前的a变量了,而有可能是某一时刻a变量的值*/
unsigned long int volatile f_jiffies,l_jiffies;
const int hz=HZ;
ssize_t proc_read(struct file *file,char __user *usr_buf,size_t count,loff_t *pos);/*forward declartion*/
/*Declare the ower and read function*/
static struct file_operations proc_ops ={
.owner = THIS_MODULE,
.read = proc_read, /*.read is the name of thefunction proc read() that is to be called whenever /proc/hello is read.*/
};
/*Begin call this function when the module loaded*/
int proc_init(void)
{
proc_create(PROC_NAME,0666,NULL,&proc_ops);
f_jiffies = jiffies; #f_jiffies赋值
printk(KERN_INFO "The /proc/seconds loaded!\n");
return 0;
}
void proc_exit(void)
{
remove_proc_entry(PROC_NAME,NULL);
printk(KERN_INFO "The /proc/seconds unloaded!\n");
}
/*Implemention of proc_read*/
ssize_t proc_read(struct file *file, char __user *usr_buf, size_t count, loff_t *pos)
{
l_jiffies = jiffies; #l_jiffies赋值
int rv=0;
char buffer[BUFFER_SIZE];
static int completed=0;
if (completed){
completed=0;
return 0; /*proc_read逢0才停止,因此这个return 0保证只输出一次值,否则将无限循环输出*/
}
completed=1;
rv=sprintf(buffer, "The running time is %d s\n", ((l_jiffies-f_jiffies)/hz)); /*将jiffies的值存入buffer,rv为写入的字符总数,不包括字符串追加在字符串末尾的空字符*/
copy_to_user(usr_buf,buffer,rv); /*从内核的buffer拷贝到用户的usr_buf*/
return rv;
}
module_init(proc_init);
module_exit(proc_exit);
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("Show the program execution time");
MODULE_AUTHOR("Lily");
(2)打开linux虚拟机(此处用osc10e)
cd final-src-osc10e #进入这个文件夹
mkdir ch1 #创建ch1文件夹
(3)将主机中的jiffies文件传到虚拟机
打开主机win的cmd(注意查看是否下载了openSSH客户端)
然后输入
scp -P 2222 source target #source是本地文件的目录,target是远程机子的目录
/*例如*/
scp -P 2222 C:\Users\lenovo\Desktop\seconds.c osc@127.0.0.1:~ #传送到虚拟机的根目录
scp -P 2222 C:\Users\lenovo\Desktop\seconds.c osc@127.0.0.1:~ /final-src-osc10e/ch1 #传送到ch1文件夹中
(4)打开虚拟机写Makefile
cd final-src-osc10e #进入这个文件夹
mkdir ch1 #创建ch1文件夹
cd ch1 #进入ch1文件夹
vim Makefile #在vim中创建并编写Makefile文件,打开后按“i”切换为可写模式
写完后按“Esc”,然后按“:wq”,最后按回车即保存完毕
不想保存则按“:q!”
Makefile文件代码如下:
obj-m += seconds.o #换文件名的话替换这里的“seconds”就行
all:
make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules
clean:
make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean
保存完了以后就ok啦,回到ch1文件夹中
#以下命令可能用得上
cd .. #返回上一级(可能会用上)
mv source target #移动文件,例如 mv ~/ch1/1.c ~/ch2 即把1.c文件从ch1移到ch2
rm ch1 #删除ch1文件夹
(5)开始测试
sudo dmesg -c #定期清除缓存区
make #编译
sudo insmod seconds.ko #加载jiffies内核模块
dmesg #显示proc_init函数中要打印的东西,即The /proc/jiffies loaded!
cat /proc/seconds #显示proc_read函数中要打印的东西
sudo rmmod seconds #删除jiffies内核模块
dmesg #显示proc_exit函数中要打印的东西,检测是否正常删除
作业二和作业一就差不多了就多用了一个公式而已~