歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
Linux教程網 >> Linux基礎 >> Linux教程 >> 在Fedora 18 內核版本3.8.0下測試虛擬內存實踐

在Fedora 18 內核版本3.8.0下測試虛擬內存實踐

日期:2017/2/28 14:50:15   编辑:Linux教程

在Fedora 18 內核版本3.8.0下測試虛擬內存實踐

由於內核文件版本不同,難免有一些問題,只要把頭文件關系理清楚就行了,這裡不說了,下面直接貼出來測試過可以用的代碼吧。

/*
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>
#include <linux/sched.h>
#include <linux/highmem.h>
MODULE_LICENSE("GPL");

/*
@如何編寫代碼查看自己的進程到底有哪些虛擬區?


*/

#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 = 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)
{


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

Copyright © Linux教程網 All Rights Reserved