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


上面只是做了一些小小的改动,在load模块的时候输出了VMA的信息。

下面贴出来Makefile的内容

obj-m:=vma.o
KDIR:=/lib/modules/$(shell uname -r)/build

PWD:=$(shell pwd)

default:
	$(MAKE) -C $(KDIR) M=$(PWD) modules
clean:
	rm -rf *.o *.ko *.mod.o

 

测试首先

#make

然后

#insmod vma.ko

然后

这一步原来在老师的测试里是用的

#echo "hello" mtest

但是在我的机器上没反应

由于在创建Proc文件系统的时候传过去的参数是null,那么应该是挂载在/proc根目录下的

所以改成 

#echo "hello" /proc/mtest

这样dmesg都可以看到信息了


其实老师好像有个my_follow_page函数没有测试完成,我测测在继续贴吧

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
<br> <img src=DownloadFilesinterface_activeximagesskincrafter_scr.jpg><br><br> 对于程序员来说,用户希望开发出来的应用程序界面足够酷,甚至可以按他们的需求更换界面,这无疑是种苛求!<br> 不过,现在这种苛求对SkinCrafter来说已经变成了小菜一碟!<br> <br> SkinCrafter 让程序开发者为自己的应用程序创建个性化的、风格独特的程序界面,而且程序界面是可更换的,简单易用的操作让原本平淡无奇的应用程序界面变得个性十足!相信独特而又美观的界面让你开发出来的应用程序在同类产品中更具有竞争力!<br> <br> SkinCrafter让你的程序界面变得个性十足:<br> <br> <img src=DownloadFilesinterface_activeximagesskincrafter_big.jpg border="0"> <br> <br> SkinCrafter的关键特色: 让程序开发者为自己的应用程序创建个性化的、风格独特的程序界面,而且程序界面是可更换的; 支持所有的WIN32操作平台,包括.NET; 支持所有的常用开发工具:.NET、MS Visual C++、MS Visual Basic、Borland Delphi、CA 等; SkinCrafter自带界面皮肤编辑器Skin Editor,可以对程序界面进行编辑; 即可针对完整的应用程序定制界面也可针对单个控件定制界面; SkinCrafter自带界面区域编辑器Region Editor,可以编辑做出各种形状的窗体。 对所有的Windowns界面标准元素都能进行Resizing、Reshaping、Recoloring等配置。 SkinCrafter 的下载: <br>

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值