您的位置:首页 > 其它

从虚拟地址转为物理地址

2012-05-23 17:24 148 查看
/*

mtest_dump_vma_list():打印出当前进程的各个VMA,这个功能我们简称”listvma”

mtest_find_vma(): 找出某个虚地址所在的VMA,这个功能我们简称“findvma”

my_follow_page( ):根据页表,求出某个虚地址所在的物理页面,这个功能我们简称”findpage”

mtest_write_val(), 在某个地址写上具体数据,这个功能我们简称“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>

MODULE_LICENSE("GPL");

/*

@如何编写代码查看自己的进程到底有哪些虚拟区?

*/

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 = 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);

}

/*

@如果知道某个虚地址,比如,0×8049000,

又如何找到这个地址所在VMA是哪个?

*/

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来描述。

给定一个虚存区VMA和一个虚地址addr,

找出这个地址所在的物理页面page.

*/

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;

}

/*

@ 根据页表,求出某个虚地址所在的物理页面,

这个功能我们简称”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);

}

/*

@你是否有这样的想法,

给某个地址写入自己所想写的数据?

*/

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)

{

char buf[128];

unsigned long val, val2;

printk("mtest_write ……….. \n");

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 %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;

//整个操作我们以模块的形式实现,因此,模块的初始化和退出函数如下:

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;

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);
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: