首页 > 代码库 > Linux Kernel HomeWork---/proc/mtest

Linux Kernel HomeWork---/proc/mtest

Memory management

1.listvma

 

static void mtest_dump_vma_list(void)

{

    struct task_struct *task = current;                //get the task_struct of the current process

    struct mm_struct *mm = task->mm;

    struct vm_area_struct *vma;                //get the vma area of the current process

    int count = 0;     //the number of vma

    down_read(&mm->mmap_sem);

 

    for(vma = mm->mmap; vma; vma = vma->vm_next)

    {

        count++;

 

        printk("%d:  0x%lx 0x%lx ", count, vma->vm_start, vma->vm_end);

       

        if (vma->vm_flags & VM_READ)

            printk("r");

        else

            printk("-");

 

        if (vma->vm_flags & VM_WRITE)

            printk("w");

        else

            printk("-");

 

        if (vma->vm_flags & VM_WRITE)

            printk("x");

        else

            printk("-");

       

        printk("\n");

    }

 

    up_read(&mm->mmap_sem);

 

}

 

 

2.findpage addr

 

static struct page *

my_follow_page(struct vm_area_struct *vma, unsigned long addr)

{

    pgd_t *pgd;

    pmd_t *pmd;

    pud_t *pud;

    pte_t *pte;

 

    spinlock_t *ptl;

 

    struct page *page = NULL;

    struct mm_struct *mm = vma->vm_mm;

 

 

    pgd = pgd_offset(mm, addr);     //get pgd

    if (pgd_none(*pgd) || unlikely(pgd_bad(*pgd)))

        goto out;

 

    pud = pud_offset(pgd, addr);   //get pud

    if (pud_none(*pud) || unlikely(pmd_bad(*pud)))

        goto out;

 

    pmd = pmd_offset(pud, addr);   //get pmd

    if (pmd_none(*pmd) || unlikely(pmd_bad(*pmd)))

        goto out;

 

    pte = pte_offset_map_lock(mm, pmd, addr, &ptl); //get pte

 

    if (!pte)

        goto out;

 

    if (!pte_present(*pte))   //pte not in memory

        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;

 

}

 

static void mtest_find_page(unsigned long addr)

{

    struct vm_area_struct *vma;

    struct task_struct *task = current;

    struct mm_struct *mm = task->mm;

    unsigned long kernel_addr;

    struct page *page;

   

    down_read(&mm->mmap_sem);

    vma = find_vma(mm, addr);

    page = my_follow_page(vma, addr);

 

    if (!page)

    {

        printk("translation failed.\n");

        goto out;

    }

 

    kernel_addr = (unsigned long) page_address(page);

 

    kernel_addr += (addr & ~PAGE_MASK);

 

    printk("vma 0x%lx -> pma 0x%lx\n", addr, kernel_addr);

 

out:

    up_read(&mm->mmap_sem);

}

 

 

3.writeval addr val

 

static void

mtest_write_val(unsigned long addr, unsigned long val)

{

    struct vm_area_struct *vma;

    struct task_struct *task = current;

    struct mm_struct *mm = task->mm;

    struct page *page;

    unsigned long kernel_addr;

 

    down_read(&mm->mmap_sem);

    vma = find_vma(mm, addr);

 

    //test if it is a legal vma

    if (vma && addr >= vma->vm_start && (addr + sizeof(val)) < vma->vm_end)

    {

        if (!(vma->vm_flags & VM_WRITE))   //test if we have rights to write

        {

            printk("cannot write to 0x%lx\n", addr);

            goto out;

        }

 

        page = my_follow_page(vma, addr);

        if (!page)

        {

            printk("page not found 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);

}

 

 

4.To build a proc file

 

static ssize_t

mtest_write(struct file *file, const char __user *buffer, size_t count, loff_t *data)

{

    char buf[128];

    unsigned long val, val2;

 

    if (count > sizeof(buf))

        return -EINVAL;

 

    if (copy_from_user(buf, buffer, count))    //get the command from shell

        return -EINVAL;

 

    if (memcmp(buf, "listvma", 7) == 0)

        mtest_dump_vma_list();

    else if (memcmp(buf, "findpage", 8) == 0)

    {

        if (sscanf(buf+8, "%lx", &val) == 1)

            mtest_find_page(val);

    }

    else if (memcmp(buf, "writeval", 8) == 0)

    {

        if (sscanf(buf+8, "%lx %lx", &val, &val2) == 2)

        {

            mtest_write_val(val, val2);

        }

    }

    return count;

}

 

static struct

file_operations proc_mtest_operation = {

    write: mtest_write,

};

 

static int __init

mtest_init(void)

{

    proc_create("mtest", 0, NULL, &proc_mtest_operation);

    printk("Create mtest...\n");

    return 0;

}

 

static void __exit

mtest_exit(void)

{

    remove_proc_entry("mtest", NULL);

}

 

MODULE_LICENSE("GPL");

MODULE_DESCRIPTION("memory management task");

module_init(mtest_init);

module_exit(mtest_exit);

 

 

6.some head files that should be included

 

#include <linux/module.h>

#include <linux/kernel.h>

#include <linux/proc_fs.h>

#include <linux/string.h>

#include <linux/vmalloc.h>

#include <linux/init.h>

#include <linux/slab.h>

#include <linux/fs.h>

#include <linux/mm.h>

#include <linux/sched.h>

#include <linux/errno.h>

 

 

 

7. how to test

1) write a Makefile

2) type “make” in shell

3) type ”sudo insmod mtest.ko”

4) type “sudo -su”

5) type:   echo “listvma” > /proc/mtest

6) type: dmesg (then you will find a lot of vma)

7) choose one of them and type : echo “findpage 0x.........” > /proc/mtest

   then type : dmesg

   note: you may find that “translation failed” shows up. But that does not mean you fail the        test. Please choose an address between the start and the end of the vma listed.

             e.g. 0x123 – 0x345

             you may want to type: echo “findpage 0x300” > /proc/mtest

             because you cannot be sure if the beginning of the virtual address is used.

8) choose an address that you has rights to write.

     Then type: echo  “writeval 0x...    123” > /proc/mtest

     type: dmesg

     note: 123 can be any unsigned int

              you‘d better choose the same address to test in both step 7 and 8, so that you will see  

            if the physical address is consistent.

 

The End.