操作系统(一):Linux内核模块的创建

操作系统(一):Linux内核模块的创建

初入操作系统的坑,作为小白的我既忐忑又兴奋,希望能把课上的一些习题记录下来,一来可以让自己以后也回顾一下,二来也算是一个小小的教程,适合初学者看看,因为本人也是小白,如果有不严谨的地方欢迎指正。

这次的project主要是写Linux内核,话不多说,先上题目。

一、作业题目

  1. 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是什么后面再讲)。

  2. 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 (jiffiesljiffiesf)/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函数中要打印的东西,检测是否正常删除

测试效果如下:
Alt
《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函数中要打印的东西,检测是否正常删除

作业二和作业一就差不多了就多用了一个公式而已~

第一次over~

评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值