zoukankan      html  css  js  c++  java
  • 20135319zl内核模块编译报告

    内核模块编程学习报告

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

    源代码:

    Makefile

    编译模块

    加载模块

    测试模块(dmesg)

    卸载模块

    Sudo rmmod 1

    使用dmesg查看情况

    2.输出当前进程信息

    源代码(作为2.c)

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

    编译,加载并测试模块

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

    修改makefile为3.o

    编译,加载并测试模块:

    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
    ", (unsigned long long) get_jiffies_64());  
    
            seq_printf(m, "str is %s
    ", 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("******************************************
    ");
            remove_proc_entry("exp2", NULL);
            kfree(str);
    
        }
    
        module_init(jif_init);
        module_exit(jif_exit);
    
        MODULE_AUTHOR("why");
        MODULE_LICENSE("GPL");
    

    编译,加载模块

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

    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.
    ",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.
    ",pid);
            	return 0;
        	}
        	rcu_read_unlock();
    
    	printk("The page index_table address = 0x%p
    
    ",pcb_tmp->mm->pgd);
        
        	printk(KERN_ALERT "pgd=0x%p
    ",pcb_tmp->mm->pgd);
        	if(!find_vma(pcb_tmp->mm,va))
        	{
            	printk(KERN_ALERT "virt_addr 0x%lx not available.
    ",va);
            	return 0;
        	}
        	pgd_tmp=pgd_offset(pcb_tmp->mm,va);
        	printk(KERN_ALERT "pgd_tmp=0x%p
    ",pgd_tmp);
        	printk(KERN_ALERT "pgd_val(*pgd_tmp)=0x%lx
    
    ",pgd_val(*pgd_tmp));
       	 if(pgd_none(*pgd_tmp))
        	{
         	   printk(KERN_ALERT "Not mapped in pgd.
    ");
         	   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.
    ");
            	return 0;
        	}
        	if(!pte_present(*pte_tmp))
        	{
       	     	printk(KERN_ALERT "pte not in RAM,maybe swaped.
    ");
        	    	return 0;
        	}
        	pa=(pte_val(*pte_tmp)&PAGE_MASK)|(va&~PAGE_MASK);
        	printk(KERN_ALERT "Virtual address: 0x%lx in RAM is 0x%lx.
    ",va,pa);
        	printk(KERN_ALERT "Part content in 0x%lx is 0x%lx.
    ",pa,*(unsigned long*)((char *)pa+PAGE_OFFSET));
    	int i;
    	printk("some content:
    ");
    	for(i=0;i<40;i=i+4)
    	{
    		printk("%lx
    ",*(unsigned long*)((char*)pa+PAGE_OFFSET+i));
    	}	
        return 0;
    }
    
    static void find_pgd_exit(void)
    {
        	printk(KERN_ALERT "Goodbye.
    ");
    }
    
    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

    查询gedit的虚拟地址

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

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

    测试结果:

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

    验证模块功能

    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("******************************************
    ");
            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.
    ",va,pid);
    	
    	rcu_read_lock();
    	if(!(pcb_tmp = pid_task(find_vpid(pid),PIDTYPE_PID))) 
    	{
    		seq_printf(m,"can not find pro %ld .
    ", pid);
    		return 0;
    	}
    	rcu_read_unlock();
    
    	seq_printf(m,"ye_mu_lu_biao_ji_zhi = 0x%p
    ",pcb_tmp->mm->pgd);
    	if(!find_vma(pcb_tmp->mm,va))	
            {
            	seq_printf(m,"xu_ni_di_zhi%lxbu_cun_zai
    ",va);
            	return 0;
    	}
    
    	pgd_tmp=pgd_offset(pcb_tmp->mm,va);
    	seq_printf(m,"
    pgd=----0x%p
    ",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,"
    pte=----0x%p
    ",pte_tmp);
    	seq_printf(m,"
    
     pid=%ld
    va=%lx
    
    ",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.
    ",va,pa);
    	seq_printf(m, "bu_fen_nei_rong  0x%lx is  0x%lx.
    .
    ",pa,pa);
    	for(i=0;i<40;i=i+4)
    	seq_printf(m,"	%lx
    ",*(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
    ", (unsigned long long) get_jiffies_64());  
    
                //seq_printf(m, "str is %s
    ", 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内容,可见:

    模块功能实现

  • 相关阅读:
    学习 WCF (6)学习调用WCF服务的各种方法
    WCF 基础简介
    Ext.form 表单为什么第二次就不正常显示
    面向对象
    学习 WCF (4)学会使用配置文件
    临危不乱,.Net+IIS环境经常出现的问题及排障。
    Java调用wcf
    Extjs 动态生成表格
    面向对象分析与设计的意义是什么
    WCF配置文件详解
  • 原文地址:https://www.cnblogs.com/20135319zl/p/5560692.html
Copyright © 2011-2022 走看看