zoukankan      html  css  js  c++  java
  • Linux实践二:模块

    一、基本模块的实现:

    1.进程遍历打印输出

    2.简单地编写一个新的系统调用(替换空的系统调用号)

    基本模块学到的知识点:

    1.相关指令

      make oldconfig 配置内核

      make 编译内核

      make modules_instal 编译安装内核模块

      make install 引导新编译的内核

      uname –a 查看内核版本

      lsmod 查看加载的模块

      insmod 加载模块

      rmmod 卸载模块

      dmesg 显示开机信息

    基础模块一:系统调用(替换空的233)

    文件Makefile

    obj-m :=syscall.o
    PWD := $(shell pwd)
    KDIR:=/lib/modules/4.4.0-21-generic/build
    all:
            make -C $(KDIR) M=$(PWD) modules
    clean:
            make -C $(KDIR) M=$(PWD) clean
    

      uname -r 显示当前使用的内核信息,确定自己当前linux的内核版本是多少

     

    测试代码:

    #include <stdio.h>
    #include <stdlib.h>
    int main()
    {
    unsigned long x = 0;
    x = syscall(223);        //测试223号系统调用
    printf("Hello, %ld
    ", x);
    return 0;
    }
    

      

      

    make -C $(LINUX_KERNEL_PATH) 指明跳转到内核源码目录下读取那里的Makefile

    M=$(CURRENT_PATH) 表明返回到当前目录继续执行当前的Makefile。

         

    头文件module.h,必须包含此文件;

    头文件kernel.h,包含常用的内核函数;

    头文件init.h包含宏_init和_exit,允许释放内核占用的内存。

    基础模块二:进程遍历

     

    二、深入

    学习一:页表模块 

        基本思路:

      1.研究学习学姐的实践指导书,由于新版本的Ubuntu需要的是四级页表,根据百度的一些知识,将学姐的代码由二级页表修改成四级页表

    重点是理解页表结构

      2.进一步修改页表,修改权限,使得用户态的可以变成内核态(研究中)。

    对于页的保护通常设置一个存取控制字段。当这个字段占一位时,用于规定该页中的内
    
    容允许写还是读;如果存取控制字段占两位,那么它可以表示存取控制为读写、只读和
    
    只运行三种。当进程写一个只读页时,系统就会通过中断来报错。
    

      模块参数以module_param(name,type,perm)的形式定义,其中name为参数名,type为参数的数据类型,perm是一个权限值,控制谁可以存取模块参数在sysfs中的表示。

    页全局目录(Page Global Directory)
    • 页上级目录(Page Upper Directory)
    • 页中间目录(Page Middle Directory)
    • 页表(Page Table)
        页全局目录包含若干页上级目录的地址,页上级目录又依次包含若干页中间目录的地址,而页中间目录又包含若干页表的地址。每一个页表项指向一个页框。线性地址因此被分成五个部分。图中没有显示位数,因为每一部分的大小与具体的计算机体系结构有关。

    #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("weiwei");
    
    MODULE_DESCRIPTION("GET WESSAGE");
    

      

    •  页全局目录(Page Global Directory)
    •  页上级目录(Page Upper Directory)
    •  页中间目录(Page Middle Directory)
    •  页表(Page Table)

        页全局目录包含若干页上级目录的地址,页上级目录又依次包含若干页中间目录的地址,而页中间目录又包含若干页表的地址。每一个页表项指向一个页框。线性地址因此被分成五个部分。

    修改权限的思路,查看页表的读写,u/s的值,然后通过相关的设置函数进行修改

    函数名称

    说明

    pte_user( )

    读 User/Supervisor 标志。

    pte_read( )

    读 User/Supervisor 标志(表示 80x86 处理器上的页不受读的保护)。

    pte_write( )

    读 Read/Write 标志。

    pte_exec( )

    读 User/Supervisor 标志( 80x86 处理器上的页不受代码执行的保护)。

    pte_dirty( )

    读 Dirty 标志。

    pte_young( )

    读 Accessed 标志。

    pte_file( )

    读 Dirty 标志(当 Present 标志被清除而 Dirty 标志被设置时,页属于一个非线性磁盘文件映射)。

    设置页表项中各标志的值的函数:

    函数名称

    说明

    mk_pte_huge( )

    设置页表项中的 Page Size 和 Present 标志。

    pte_wrprotect( )

    清除 Read/Write 标志。

    pte_rdprotect( )

    清除 User/Supervisor 标志。

    pte_exprotect( )

    清除 User/Supervisor 标志。

    pte_mkwrite( )

    设置 Read/Write 标志。

    pte_mkread( )

    设置 User/Supervisor 标志。

    pte_mkexec( )

    设置 User/Supervisor 标志。

    pte_mkclean( )

    清除 Dirty 标志。

    pte_mkdirty( )

    设置 Dirty 标志。

    pte_mkold( )

    清除 Accessed 标志(把此页标记为未访问)。

    pte_mkyoung( )

    设置 Accessed 标志(把此页标记为访问过)。

    pte_modify(p,v)

    把页表项 p 的所有访问权限设置为指定的值 v 。

    ptep_set_wrprotect()

    与 pte_wrprotect( ) 类似,但作用于指向页表项的指针。

    ptep_set_access_flags( )

    如果 Dirty 标志被设置为 1 则将页的访问权设置为指定的值,并调用flush_tlb_page() 函数。

    ptep_mkdirty( )

    与 pte_mkdirty( ) 类似,但作用于指向页表项的指针。

    ptep_test_and_clear_dirty( )

    与 pte_mkclean( ) 类似,但作用于指向页表项的指针并返回 Dirty 标志的旧值。

    ptep_test_and_clear_young( )

    与 pte_mkold( ) 类似,但作用于指向页表项的指针并返回 Accessed标志的旧值。

     

    学习二:系统调用

    学习三:进程模块

     

  • 相关阅读:
    Confluence 6 尝试从 XML 备份中恢复时解决错误
    Confluence 6 XML 备份恢复失败的问题解决
    Confluence 6 找到在创建 XML 备份的时候出现的错误
    Confluence 6 XML 备份失败的问题解决
    c trans
    How To Use API Online?
    c string
    c function
    c array
    FileCopy
  • 原文地址:https://www.cnblogs.com/zhengwei0712/p/5514025.html
Copyright © 2011-2022 走看看