Test Virtual Memory practices in 3.ora 18 kernel version 3.8.0
Because the kernel file versions are different, there are inevitably some problems. You just need to clarify the relationship between the header files. Here we will not talk about it. Below we will directly post the code that can be used for testing.
/*
Mtest_dump_vma_list (): prints the VMA of the current process. This function is short for listvma"
Mtest_find_vma (): Find the VMA where a virtual address is located. This function is short for "findvma"
My_follow_page (): Find the physical page of a virtual address based on the page table. This function is short for "findpage"
Mtest_write_val (): Write the specific data in an address. This function is short for "writeval ".
*/
# Include <linux/module. h>
# Include <linux/kernel. h>
# Include <linux/proc_fs.h>
# Include <linux/string. h>
# Include <linux/vmalloc. h>
# Include <asm/uaccess. h>
# Include <linux/init. h>
# Include <linux/slab. h>
# Include <linux/mm. h>
# Include <linux/vmalloc. h>
# Include <linux/sched. h>
# Include <linux/highmem. h>
MODULE_LICENSE ("GPL ");
/*
@ How do I write code to check the virtual zones of my processes?
*/
# Define current get_current ()
Struct task_struct;
Static void mtest_dump_vma_list (void)
{
Struct mm_struct * mm = current-> mm;
Struct vm_area_struct * vma;
Printk ("The current process is % s \ n", current-> comm );
Printk ("mtest_dump_vma_list \ n ");
Down_read (& mm-> mmap_sem );
For (vma = mm-> mmap; vma = vma-> vm_next ){
Printk ("VMA 0x % lx-0x % lx ",
Vma-> vm_start, vma-> vm_end );
If (vma-> vm_flags & VM_WRITE)
Printk ("WRITE ");
If (vma-> vm_flags & VM_READ)
Printk ("READ ");
If (vma-> vm_flags & VM_EXEC)
Printk ("EXEC ");
Printk ("\ n ");
}
Up_read (& mm-> mmap_sem );
}
/*
@ If you know a virtual address, for example, 0 × 8049000,
How can I find the VMA where the address is located?
*/
Static void mtest_find_vma (unsigned long addr)
{
Struct vm_area_struct * vma;
Struct mm_struct * mm = current-> mm;
Printk ("mtest_find_vma \ n ");
Down_read (& mm-> mmap_sem );
Vma = find_vma (mm, addr );
If (vma & addr> = vma-> vm_start ){
Printk ("found vma 0x % lx-0x % lx flag % lx for addr 0x % lx \ n ",
Vma-> vm_start, vma-> vm_end, vma-> vm_flags, addr );
} Else {
Printk ("no vma found for % lx \ n", addr );
}
Up_read (& mm-> mmap_sem );
}
/*
@ Struct page is used to describe a physical page in the kernel.
Given a virtual storage zone VMA and a virtual address addr,
Find the physical page of the address.
*/
Static struct page *
My_follow_page (struct vm_area_struct * vma, unsigned long addr)
{
Pud_t * pud;
Pmd_t * pmd;
Pgd_t * pgd;
Pte_t * pte;
Spinlock_t * ptl;
Struct page * page = NULL;
Struct mm_struct * mm = vma-> vm_mm;
Pgd = pgd_offset (mm, addr );
If (pgd_none (* pgd) | unlikely (pgd_bad (* pgd ))){
Goto out;
}
Pud = pud_offset (pgd, addr );
If (pud_none (* pud) | unlikely (pud_bad (* pud )))
Goto out;
Pmd = pmd_offset (pud, addr );
If (pmd_none (* pmd) | unlikely (pmd_bad (* pmd ))){
Goto out;
}
Pte = pte_offset_map_lock (mm, pmd, addr, & ptl );
If (! Pte)
Goto out;
If (! Pte_present (* pte ))
Goto unlock;
Page = pfn_to_page (pte_pfn (* pte ));
If (! Page)
Goto unlock;
Get_page (page );
Unlock:
Pte_unmap_unlock (pte, ptl );
Out:
Return page;
}
/*
@ Obtain the physical page of a virtual address based on the page table,
This function is short for "findpage"
*/
Static void mtest_find_page (unsigned long addr)
{
Struct vm_area_struct * vma;
Struct mm_struct * mm = current-> mm;
Unsigned long kernel_addr;
Struct page * page;
Printk ("mtest_write_val \ n ");
Down_read (& mm-> mmap_sem );
Vma = find_vma (mm, addr );
Page = my_follow_page (vma, addr );
If (! Page)
{
Printk ("page not found for 0x % lx \ n", addr );
Goto out;
}
Printk ("page found for 0x % lx \ n", addr );
Kernel_addr = (unsigned long) page_address (page );
Kernel_addr + = (addr &~ PAGE_MASK );
Printk ("find 0x % lx to kernel address 0x % lx \ n", addr, kernel_addr );
Out:
Up_read (& mm-> mmap_sem );
}
/*
@ Do you have such an idea,
Write the data you want to write to an address?
*/
Static void
Mtest_write_val (unsigned long addr, unsigned long val)
{
Struct vm_area_struct * vma;
Struct mm_struct * mm = current-> mm;
Struct page * page;
Unsigned long kernel_addr;
Printk ("mtest_write_val \ n ");
Down_read (& mm-> mmap_sem );
Vma = find_vma (mm, addr );
If (vma & addr> = vma-> vm_start & (addr + sizeof (val) <vma-> vm_end ){
If (! (Vma-> vm_flags & VM_WRITE )){
Printk ("vma is not writable for 0x % lx \ n", addr );
Goto out;
}
Page = my_follow_page (vma, addr );
If (! Page ){
Printk ("page not found for 0x % lx \ n", addr );
Goto out;
}
Kernel_addr = (unsigned long) page_address (page );
Kernel_addr + = (addr &~ PAGE_MASK );
Printk ("write 0x % lx to address 0x % lx \ n", val, kernel_addr );
* (Unsigned long *) kernel_addr = val;
Put_page (page );
} Else {
Printk ("no vma found for % lx \ n", addr );
}
Out:
Up_read (& mm-> mmap_sem );
}
Static ssize_t
Mtest_write (struct file * file, const char _ user * buffer,
Size_t count, loff_t * data)
{
Printk ("mtest_write... \ n ");
Char buf [128];
Unsigned long val, val2;
If (count> sizeof (buf ))
Return-EINVAL;
If (copy_from_user (buf, buffer, count ))
Return-EINVAL;
If (memcmp (buf, "listvma", 7) = 0)
Mtest_dump_vma_list ();
Else if (memcmp (buf, "findvma", 7) = 0 ){
If (sscanf (buf + 7, "% lx", & val) = 1 ){
Mtest_find_vma (val );
}
}
Else if (memcmp (buf, "findpage", 8) = 0 ){
If (sscanf (buf + 8, "% lx", & val) = 1 ){
Mtest_find_page (val );
// My_follow_page (vma, addr );
}
}
Else if (memcmp (buf, "writeval", 8) = 0 ){
If (sscanf (buf + 8, "% lx", & val, & val2) = 2 ){
Mtest_write_val (val, val2 );
}
}
Return count;
}
Static struct
File_operations proc_mtest_operations = {
. Write = mtest_write
};
Static struct proc_dir_entry * mtest_proc_entry;
// The entire operation is implemented in the form of a module. Therefore, the initialization and exit functions of the module are as follows:
Static int _ init
Mtest_init (void)
{
Mtest_proc_entry = create_proc_entry ("mtest", 0777, NULL );
If (mtest_proc_entry = NULL ){
Printk ("Error creating proc entry \ n ");
Return-1;
}
Printk ("create the filename mtest mtest_init sucess \ n ");
Mtest_proc_entry-> proc_fops = & proc_mtest_operations;
Mtest_dump_vma_list ();
Return 0;
}
Static void
_ Exit mtest_exit (void)
{
Printk ("exit the module mtest_exit \ n ");
Remove_proc_entry ("mtest", NULL );
}
MODULE_LICENSE ("GPL ");
MODULE_DESCRIPTION ("mtest ");
MODULE_AUTHOR ("Zou Nan hai ");
Module_init (mtest_init );
Module_exit (mtest_exit );