20135319zl内核模块编译报告

时间:2023-03-08 15:39:14

内核模块编程学习报告

1.编写一个简单的输出信息的模块

源代码:

20135319zl内核模块编译报告

Makefile

20135319zl内核模块编译报告

编译模块

20135319zl内核模块编译报告

加载模块

20135319zl内核模块编译报告

测试模块(dmesg)

20135319zl内核模块编译报告

卸载模块

Sudo rmmod 1

使用dmesg查看情况

20135319zl内核模块编译报告

2.输出当前进程信息

源代码(作为2.c)

修改makefile中的目标文件为2.o

20135319zl内核模块编译报告

编译,加载并测试模块

20135319zl内核模块编译报告

3.进程列表读取功能(3.c)

源代码

20135319zl内核模块编译报告

修改makefile为3.o

编译,加载并测试模块:

20135319zl内核模块编译报告

4.可读写的文件节点内核模块

在/proc文件系统中创建一个文件节点exp2

源代码

#include <linux/module.h>
#include <linux/init.h>
#include <linux/kernel.h> #include <linux/fs.h> // for basic filesystem
#include <linux/proc_fs.h> // for the proc filesystem
#include <linux/seq_file.h> // for sequence files
#include <linux/jiffies.h> // for jiffies
#include <linux/slab.h> // for kzalloc, kfree
#include <linux/uaccess.h> // for copy_from_user //static struct task_struct *pcurrent;
int print_current_task_info(void); // global var
static char *str = NULL; // seq_operations -> show
static int jif_show(struct seq_file *m, void *v)
{
//seq_printf(m, "current kernel time is %llu\n", (unsigned long long) get_jiffies_64()); seq_printf(m, "str is %s\n", str);
return 0; //!! must be 0, or will show nothing T.T
} // file_operations -> write
static ssize_t jif_write(struct file *file, const char __user *buffer, size_t count, loff_t *f_pos)
{
//分配临时缓冲区
char *tmp = kzalloc((count+1), GFP_KERNEL);
if (!tmp)
return -ENOMEM; //将用户态write的字符串拷贝到内核空间
//copy_to|from_user(to,from,cnt)
if (copy_from_user(tmp, buffer, count)) {
kfree(tmp);
return -EFAULT;
} //将str的旧空间释放,然后将tmp赋值给str
kfree(str);
str = tmp; return count;
} // seq_operations -> open
static int jif_open(struct inode *inode, struct file *file)
{
return single_open(file, jif_show, NULL);
} static const struct file_operations jif_fops =
{
.owner = THIS_MODULE,
.open = jif_open,
.read = seq_read,
.write = jif_write,
.llseek = seq_lseek,
.release = single_release,
}; // module init
static int __init jif_init(void)
{
struct proc_dir_entry* jif_file; jif_file = proc_create("exp2", 0, NULL, &jif_fops);
if (NULL == jif_file)
{
return -ENOMEM;
} return 0;
} // module exit
static void __exit jif_exit(void)
{
printk("******************************************\n");
remove_proc_entry("exp2", NULL);
kfree(str); } module_init(jif_init);
module_exit(jif_exit); MODULE_AUTHOR("why");
MODULE_LICENSE("GPL");

编译,加载模块

20135319zl内核模块编译报告

往新建立的exp2文件中写入字符串”zhuli”,可见结果:

20135319zl内核模块编译报告

5.虚拟地址转换模块

源代码:

#include <linux/module.h>
#include <asm/pgtable.h>
#include <linux/version.h>
#include <asm/page.h>
#include <linux/gfp.h>
#include <linux/page-flags.h>
#include <linux/sched.h>//find_task_by_vpid
#include <linux/mm.h>//find_vma MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("CONVERT USER VIRTUAL ADDRESS TO PHYADDRESS"); static int pid;
static unsigned long va; module_param(pid,int,0644);
module_param(va,ulong,0644); static int find_pgd_init(void)
{
unsigned long pa=0;
struct task_struct *pcb_tmp=NULL;
pgd_t *pgd_tmp=NULL;
pud_t *pud_tmp=NULL;
pmd_t *pmd_tmp=NULL;
pte_t *pte_tmp=NULL; printk(KERN_ALERT "test:va=0x%lx,pid=%d.\n",va,pid); rcu_read_lock();
if( !( pcb_tmp = pid_task(find_vpid(pid), PIDTYPE_PID) ) )
{
rcu_read_unlock();
printk(KERN_ALERT "Can't find the task %d.\n",pid);
return 0;
}
rcu_read_unlock(); printk("The page index_table address = 0x%p\n\n",pcb_tmp->mm->pgd); printk(KERN_ALERT "pgd=0x%p\n",pcb_tmp->mm->pgd);
if(!find_vma(pcb_tmp->mm,va))
{
printk(KERN_ALERT "virt_addr 0x%lx not available.\n",va);
return 0;
}
pgd_tmp=pgd_offset(pcb_tmp->mm,va);
printk(KERN_ALERT "pgd_tmp=0x%p\n",pgd_tmp);
printk(KERN_ALERT "pgd_val(*pgd_tmp)=0x%lx\n\n",pgd_val(*pgd_tmp));
if(pgd_none(*pgd_tmp))
{
printk(KERN_ALERT "Not mapped in pgd.\n");
return 0;
} pud_tmp=pud_offset(pgd_tmp,va);
pmd_tmp=pmd_offset(pud_tmp,va); pte_tmp=pte_offset_kernel(pmd_tmp,va);
if(pte_none(*pte_tmp))
{
printk(KERN_ALERT "Not mapped in pte.\n");
return 0;
}
if(!pte_present(*pte_tmp))
{
printk(KERN_ALERT "pte not in RAM,maybe swaped.\n");
return 0;
}
pa=(pte_val(*pte_tmp)&PAGE_MASK)|(va&~PAGE_MASK);
printk(KERN_ALERT "Virtual address: 0x%lx in RAM is 0x%lx.\n",va,pa);
printk(KERN_ALERT "Part content in 0x%lx is 0x%lx.\n",pa,*(unsigned long*)((char *)pa+PAGE_OFFSET));
int i;
printk("some content:\n");
for(i=0;i<40;i=i+4)
{
printk("%lx\n",*(unsigned long*)((char*)pa+PAGE_OFFSET+i));
}
return 0;
} static void find_pgd_exit(void)
{
printk(KERN_ALERT "Goodbye.\n");
} module_init(find_pgd_init);
module_exit(find_pgd_exit); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Why"); MODULE_DESCRIPTION("GET WESSAGE");

源代码中find_pgd_init()为模块初始化函数,find_pgd_exit为模块析构函数。

代码中还定义了所要传入的参数,即所指定进程的进程号pid,数据类型为int,模块参数以module_param(name,type,perm)的形式定义,其中name为参数名,type为参数的数据类型,perm是一个权限值,控制谁可以存取模块参数在sysfs中的表示。此处还要注意的是要对内核模块的初始化函数和析构函数进行声明,即指明哪个函数是内核模块的初始化函数,哪个是内核模块的析构函数。

module_init()指明的是模块初始化函数,module_exit()指明的是模块析构函数。

MODULE LICENSE、MODULE_AUTHOR、MODULE_DESCRIPTION 分别为模块证书、模块作者和模块描述。

选取gedit验证模块

查询当前开启的gedit的pid

20135319zl内核模块编译报告

查询gedit的虚拟地址

20135319zl内核模块编译报告

可见此时gedit的pid为5207,虚拟地址的16进制表示为0x805e604,使用计算器转换为10进制为134604292

编译,加载并测试模块,可见:(加载模块时需要做如下操作)

20135319zl内核模块编译报告

测试结果:

20135319zl内核模块编译报告

可见,输出序列为53,83,ec ,08…

20135319zl内核模块编译报告

验证模块功能

6.使用文件节点存储页表查询结果

源代码:

#include <linux/module.h>  

#include <linux/init.h>  

#include <linux/kernel.h>  

#include <linux/fs.h>     // for basic filesystem  

#include <linux/proc_fs.h>    // for the proc filesystem  

#include <linux/seq_file.h>   // for sequence files  

#include <linux/jiffies.h>    // for jiffies  

#include <linux/slab.h>       // for kzalloc, kfree  

#include <linux/uaccess.h>    // for copy_from_user 

#include <asm/pgtable.h>

#include <linux/version.h>

#include <asm/page.h>

#include <linux/gfp.h>

#include <linux/page-flags.h>

#include <linux/sched.h>//find_task_by_vpid

#include <linux/mm.h>//find_vma

static unsigned long pid=5263;
static unsigned long va=134604292;
int i=0;
unsigned long pa = 0; //static struct task_struct *pcurrent; int print_current_task_info(void);
static int jif_show(struct seq_file *m, void *v); // global var //static char *str = NULL;
// file_operations -> write
static ssize_t jif_write(struct file *file, const char __user *buffer, size_t count, loff_t *f_pos)
{ unsigned long *tmp = kzalloc((count+1), GFP_KERNEL);
if (!tmp)
return -ENOMEM; //copy_to|from_user(to,from,cnt)
if (copy_from_user(tmp, buffer, count)) {
kfree(tmp);
return -EFAULT;
} kfree(tmp);
//pid = *tmp; return count;
} // seq_operations -> open
static int jif_open(struct inode *inode, struct file *file)
{
return single_open(file, jif_show, NULL);
} static const struct file_operations jif_fops =
{
.owner = THIS_MODULE,
.open = jif_open,
.read = seq_read,
.write = jif_write,
.llseek = seq_lseek,
.release = single_release,
}; // module init
static int __init jif_init(void)
{
struct proc_dir_entry* jif_file; jif_file = proc_create("exp4", 0, NULL, &jif_fops);
if (NULL == jif_file)
{
return -ENOMEM;
} return 0;
} // module exit
static void __exit jif_exit(void)
{
printk("******************************************\n");
remove_proc_entry("exp4", NULL);
kfree(pid); } static int find_pgd_init(struct seq_file *m)
{
struct task_struct *pcb_tmp = NULL;
pgd_t *pgd_tmp = NULL;
pte_t *pte_tmp = NULL; pud_t *pud_tmp = NULL;
pmd_t *pmd_tmp = NULL; seq_printf(m,"test:va=0x%lx,pid=%ld.\n",va,pid); rcu_read_lock();
if(!(pcb_tmp = pid_task(find_vpid(pid),PIDTYPE_PID)))
{
seq_printf(m,"can not find pro %ld .\n", pid);
return 0;
}
rcu_read_unlock(); seq_printf(m,"ye_mu_lu_biao_ji_zhi = 0x%p\n",pcb_tmp->mm->pgd);
if(!find_vma(pcb_tmp->mm,va))
{
seq_printf(m,"xu_ni_di_zhi%lxbu_cun_zai\n",va);
return 0;
} pgd_tmp=pgd_offset(pcb_tmp->mm,va);
seq_printf(m,"\npgd=----0x%p\n",pgd_tmp); pud_tmp=pud_offset(pgd_tmp,va);
pmd_tmp=pmd_offset(pud_tmp,va); pte_tmp=pte_offset_kernel(pmd_tmp,va); seq_printf(m,"\npte=----0x%p\n",pte_tmp);
seq_printf(m,"\n\n pid=%ld\nva=%lx\n\n",pid,va); pa=(pte_val(*pte_tmp)&PAGE_MASK)|(va&~PAGE_MASK);
seq_printf(m, "xu_ni_di_zhi %lx qi_zai_nei_cun_zhong %lx.\n",va,pa);
seq_printf(m, "bu_fen_nei_rong 0x%lx is 0x%lx.\n.\n",pa,pa);
for(i=0;i<40;i=i+4)
seq_printf(m,"\t%lx\n",*(unsigned long*)((char*)pa+PAGE_OFFSET+i)); return 0;
} // seq_operations -> show static int jif_show(struct seq_file *m, void *v)
{
//seq_printf(m, "current kernel time is %llu\n", (unsigned long long) get_jiffies_64()); //seq_printf(m, "str is %s\n", str);
find_pgd_init(m);
return 0; //!! must be 0, or will show nothing T.T
} MODULE_LICENSE("GPL"); MODULE_AUTHOR("ny"); MODULE_DESCRIPTION("GET WESSAGE"); module_init(jif_init); module_exit(jif_exit);

其中参数pid和va在一开始写入源代码。

编译,加载模块后,直接显示创建的文件exp4内容,可见:

20135319zl内核模块编译报告

模块功能实现