Linux實踐二:模塊

 

1、基本模塊的實現:

1.進程遍歷打印輸出

2.簡單地編寫一個新的系統調用(替換空的系統調用號)

基本模塊學到的知識點:

1.相關指令linux

  make oldconfig 配置內核shell

  make 編譯內核app

  make modules_instal 編譯安裝內核模塊函數

  make install 引導新編譯的內核學習

  uname –a 查看內核版本測試

  lsmod 查看加載的模塊ui

  insmod 加載模塊spa

  rmmod 卸載模塊指針

  dmesg 顯示開機信息blog

基礎模塊一:系統調用(替換空的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\n", x);
return 0;
}

  

  

make -C $(LINUX_KERNEL_PATH) 指明跳轉到內核源碼目錄下讀取那裏的Makefile

M=$(CURRENT_PATH) 代表返回到當前目錄繼續執行當前的Makefile。

     

頭文件module.h,必須包含此文件;

頭文件kernel.h,包含經常使用的內核函數;

頭文件init.h包含宏_init和_exit,容許釋放內核佔用的內存。

基礎模塊二:進程遍歷

 

2、深刻

學習一:頁表模塊 

    基本思路:

  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.\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("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標誌的舊值。

 

學習二:系統調用

學習三:進程模塊

相關文章
相關標籤/搜索