虚拟内存实践

 

 

 

 

实现目的: 通过实验了解虚拟内存

 

 实验内容:在proc 文件系统下,我们建立一个文件,每次向这个文件写人字符时,调用相应的虚拟内存处理函数

  1. /* 
  2. mtest_dump_vma_list():打印出当前进程的各个VMA,这个功能我们简称"listvma" 
  3. mtest_find_vma(): 找出某个虚地址所在的VMA,这个功能我们简称“findvma" 
  4. my_follow_page( ):根据页表,求出某个虚地址所在的物理页面,这个功能我们简称"findpage" 
  5. mtest_write_val(), 在某个地址写上具体数据,这个功能我们简称“writeval". 
  6. */  
  7.   
  8. #include   
  9. #include   
  10. #include   
  11. #include   
  12. #include   
  13. #include   
  14. MODULE_LICENSE("GPL");  
  15. MODULE_DESCRIPTION("Fortune Cookie Kernel Module");  
  16.   
  17.   
  18. #include   
  19. #include   
  20. #include   
  21. #include   
  22. #include   
  23. MODULE_LICENSE("GPL");  
  24.   
  25. /* 
  26.     @如何编写代码查看自己的进程到底有哪些虚拟区? 
  27.      
  28.  
  29. */  
  30.   
  31. static void mtest_dump_vma_list(void)  
  32. {  
  33.     struct mm_struct *mm = current->mm;  
  34.     struct vm_area_struct *vma;  
  35.     printk("The current process is %s/n",current->comm);  
  36.     printk("mtest_dump_vma_list/n");  
  37.     down_read(&mm->mmap_sem);  
  38.     for (vma = mm->mmap;vma; vma = vma->vm_next) {  
  39.         printk("VMA 0x%lx-0x%lx ",  
  40.        vma->vm_start, vma->vm_end);  
  41.         if (vma->vm_flags & VM_WRITE)  
  42.             printk("WRITE ");  
  43.         if (vma->vm_flags & VM_READ)  
  44.             printk("READ ");  
  45.         if (vma->vm_flags & VM_EXEC)  
  46.             printk("EXEC ");  
  47.         printk("/n");  
  48.     }  
  49.     up_read(&mm->mmap_sem);  
  50. }  
  51.   
  52.   
  53. /* 
  54.     @如果知道某个虚地址,比如,0x8049000,  
  55.     又如何找到这个地址所在VMA是哪个? 
  56.  
  57.  
  58. */  
  59.   
  60.   
  61. static void  mtest_find_vma(unsigned long addr)  
  62. {  
  63.     struct vm_area_struct *vma;  
  64.     struct mm_struct *mm = current->mm;  
  65.   
  66.     printk("mtest_find_vma/n");  
  67.   
  68.     down_read(&mm->mmap_sem);  
  69.     vma = find_vma(mm, addr);  
  70.     if (vma && addr >= vma->vm_start) {  
  71.         printk("found vma 0x%lx-0x%lx flag %lx for addr 0x%lx/n",  
  72.             vma->vm_start, vma->vm_end, vma->vm_flags, addr);  
  73.     } else {  
  74.         printk("no vma found for %lx/n", addr);  
  75.     }  
  76.     up_read(&mm->mmap_sem);  
  77. }  
  78.   
  79. /* 
  80.  
  81.     @一个物理页在内核中用struct page来描述。 
  82.     给定一个虚存区VMA和一个虚地址addr, 
  83.     找出这个地址所在的物理页面page. 
  84.  
  85. */  
  86.   
  87.   
  88. static struct page *  
  89. my_follow_page(struct vm_area_struct *vma, unsigned long addr)  
  90. {  
  91.   
  92.                 pud_t *pud;  
  93.                 pmd_t *pmd;  
  94.            pgd_t *pgd;            
  95.                 pte_t *pte;  
  96.                 spinlock_t *ptl;  
  97.         struct page *page = NULL;  
  98.         struct mm_struct *mm = vma->vm_mm;  
  99.                 pgd = pgd_offset(mm, addr);  
  100.                 if (pgd_none(*pgd) || unlikely(pgd_bad(*pgd))) {  
  101.                         goto out;  
  102.         }  
  103.                 pud = pud_offset(pgd, addr);  
  104.                 if (pud_none(*pud) || unlikely(pud_bad(*pud)))  
  105.                         goto out;  
  106.                 pmd = pmd_offset(pud, addr);  
  107.                 if (pmd_none(*pmd) || unlikely(pmd_bad(*pmd))) {  
  108.                         goto out;  
  109.         }  
  110.                 pte = pte_offset_map_lock(mm, pmd, addr, &ptl);  
  111.                 if (!pte)  
  112.                         goto out;  
  113.         if (!pte_present(*pte))  
  114.             goto unlock;  
  115.         page = pfn_to_page(pte_pfn(*pte));  
  116.             if (!page)  
  117.             goto unlock;  
  118.         get_page(page);  
  119. unlock:  
  120.         pte_unmap_unlock(pte, ptl);  
  121. out:  
  122.         return page;  
  123. }  
  124.   
  125.   
  126. /* 
  127.  
  128. @ 根据页表,求出某个虚地址所在的物理页面, 
  129. 这个功能我们简称"findpage" 
  130.  
  131.  
  132. */  
  133.   
  134. static void   mtest_find_page(unsigned long addr)  
  135.   {  
  136.   
  137.     struct vm_area_struct *vma;  
  138.     struct mm_struct *mm = current->mm;  
  139.      unsigned long kernel_addr;  
  140.     struct page *page;  
  141.     printk("mtest_write_val/n");  
  142.     down_read(&mm->mmap_sem);  
  143.     vma = find_vma(mm, addr);  
  144.     page = my_follow_page(vma, addr);  
  145.   
  146.     if (!page)   
  147.     {      
  148.         printk("page not found  for 0x%lx/n", addr);  
  149.         goto out;  
  150.   
  151.     }  
  152.          printk("page  found  for 0x%lx/n", addr);  
  153.     kernel_addr = (unsigned long)page_address(page);  
  154.       
  155.         kernel_addr += (addr&~PAGE_MASK);  
  156.         printk("find  0x%lx to kernel address 0x%lx/n", addr, kernel_addr);    
  157.            
  158.   
  159.                    
  160.     out:  
  161.     up_read(&mm->mmap_sem);  
  162.   
  163. }  
  164.   
  165.   
  166.   
  167.   
  168. /* 
  169.     @你是否有这样的想法, 
  170.     给某个地址写入自己所想写的数据? 
  171.  
  172. */  
  173.   
  174.   
  175.   
  176. static void   
  177. mtest_write_val(unsigned long addr, unsigned long val)  
  178. {  
  179.     struct vm_area_struct *vma;  
  180.     struct mm_struct *mm = current->mm;  
  181.     struct page *page;  
  182.     unsigned long kernel_addr;  
  183.     printk("mtest_write_val/n");  
  184.     down_read(&mm->mmap_sem);  
  185.     vma = find_vma(mm, addr);  
  186.     if (vma && addr >= vma->vm_start && (addr + sizeof(val)) < vma->vm_end) {  
  187.         if (!(vma->vm_flags & VM_WRITE)) {  
  188.             printk("vma is not writable for 0x%lx/n", addr);  
  189.             goto out;  
  190.         }  
  191.         page = my_follow_page(vma, addr);  
  192.         if (!page) {      
  193.             printk("page not found  for 0x%lx/n", addr);  
  194.             goto out;  
  195.         }  
  196.           
  197.         kernel_addr = (unsigned long)page_address(page);  
  198.         kernel_addr += (addr&~PAGE_MASK);  
  199.         printk("write 0x%lx to address 0x%lx/n", val, kernel_addr);  
  200.         *(unsigned long *)kernel_addr = val;   
  201.         put_page(page);  
  202.           
  203.     } else {  
  204.         printk("no vma found for %lx/n", addr);  
  205.     }  
  206. out:  
  207.     up_read(&mm->mmap_sem);  
  208. }  
  209.   
  210.   
  211.   
  212. static ssize_t   
  213. mtest_write(struct file *file, const char __user * buffer,  
  214.                                    size_t count, loff_t * data)  
  215. {  
  216.   
  217.   
  218.     printk("mtest_write  ...........  /n");       
  219.     char buf[128];  
  220.     unsigned long val, val2;  
  221.     if (count > sizeof(buf))  
  222.         return -EINVAL;  
  223.       
  224.     if (copy_from_user(buf, buffer, count))  
  225.         return -EINVAL;  
  226.       
  227.     if (memcmp(buf, "listvma", 7) == 0)   
  228.         mtest_dump_vma_list();  
  229.       
  230.     else if (memcmp(buf, "findvma", 7) == 0) {  
  231.         if (sscanf(buf + 7, "%lx", &val) == 1) {  
  232.             mtest_find_vma(val);  
  233.         }  
  234.     }  
  235.   
  236.     else if (memcmp(buf, "findpage", 8) == 0) {  
  237.         if (sscanf(buf + 8, "%lx", &val) == 1) {  
  238.             mtest_find_page(val);  
  239.               
  240.            //my_follow_page(vma, addr);  
  241.               
  242.               
  243.         }  
  244.     }  
  245.   
  246.     else  if (memcmp(buf, "writeval", 8) == 0) {  
  247.         if (sscanf(buf + 8, "%lx %lx", &val, &val2) == 2) {  
  248.             mtest_write_val(val, val2);  
  249.         }  
  250.     }  
  251.     return count;  
  252. }  
  253.   
  254. static struct   
  255. file_operations proc_mtest_operations = {  
  256.     .write        = mtest_write  
  257. };  
  258.   
  259. static struct proc_dir_entry *mtest_proc_entry;  
  260.   
  261.   
  262. //整个操作我们以模块的形式实现,因此,模块的初始化和退出函数如下:  
  263. static int __init   
  264. mtest_init(void)  
  265. {  
  266.   
  267.     mtest_proc_entry = create_proc_entry("mtest", 0777, NULL);  
  268.     if (mtest_proc_entry == NULL) {  
  269.         printk("Error creating proc entry/n");  
  270.         return -1;  
  271.     }  
  272.     printk("create the filename mtest mtest_init sucess  /n");    
  273.     mtest_proc_entry->proc_fops = &proc_mtest_operations;  
  274.     return 0;  
  275. }  
  276.   
  277. static void   
  278. __exit mtest_exit(void)  
  279. {  
  280.      printk("exit the module......mtest_exit /n");    
  281.     remove_proc_entry("mtest", NULL);  
  282. }  
  283. MODULE_LICENSE("GPL");  
  284. MODULE_DESCRIPTION("mtest");  
  285. MODULE_AUTHOR("Zou Nan hai");  
  286.   
  287. module_init(mtest_init);  
  288. module_exit(mtest_exit);  

 

下面为Makefile

 

view plain copy to clipboard print ?
  1. obj-m := mm.o  
  2.   
  3. # KDIR is the location of the kernel source.  The current standard is  
  4. # to link to the associated source tree from the directory containing  
  5. # the compiled modules.  
  6. KDIR  := /lib/modules/$(shell uname -r)/build  
  7.   
  8. # PWD is the current working directory and the location of our module  
  9. # source files.  
  10. PWD   := $(shell pwd)  
  11.   
  12. # default is the default make target.  The rule here says to run make  
  13. # with a working directory of the directory containing the kernel  
  14. # source and compile only the modules in the PWD (local) directory.  
  15. default:  
  16.         $(MAKE) -C $(KDIR) M=$(PWD) modules  
  17. clean:  
  18.         rm -rf *.o *.ko *.mod.c  

 

下面为测试用例

[root@HBIDS proc]# echo "listvma" > mtest
[root@HBIDS proc]# echo "listvma" > mtest
[root@HBIDS proc]# echo "findvma0xb7f2b001" > mtest
[root@HBIDS proc]# echo "findpage0xb7f2b001" > mtest
[root@HBIDS proc]# echo "writeval0xb7f2b001 123456" > mtest

打印结果为

The current process is bash
mtest_dump_vma_list
VMA 0x8048000-0x80dc000 READ EXEC
VMA 0x80dc000-0x80e2000 WRITE READ EXEC
VMA 0x80e2000-0x811e000 WRITE READ EXEC
VMA 0x42000000-0x4212e000 READ EXEC
VMA 0x4212e000-0x42131000 WRITE READ EXEC
VMA 0x42131000-0x42133000 WRITE READ EXEC
VMA 0xb7d00000-0xb7f00000 READ EXEC
VMA 0xb7f00000-0xb7f0b000 READ EXEC
VMA 0xb7f0b000-0xb7f0c000 WRITE READ EXEC
VMA 0xb7f0c000-0xb7f0d000 WRITE READ EXEC
VMA 0xb7f0d000-0xb7f0f000 READ EXEC
VMA 0xb7f0f000-0xb7f10000 WRITE READ EXEC
VMA 0xb7f10000-0xb7f13000 READ EXEC
VMA 0xb7f13000-0xb7f14000 WRITE READ EXEC
VMA 0xb7f2b000-0xb7f31000 READ EXEC
VMA 0xb7f31000-0xb7f32000 WRITE READ EXEC
VMA 0xb7f32000-0xb7f47000 READ EXEC
VMA 0xb7f47000-0xb7f48000 WRITE READ EXEC
VMA 0xbfd31000-0xbfd47000 WRITE READ EXEC
mtest_write  ...........
mtest_find_vma
found vma 0xb7f47000-0xb7f48000 flag 100877 for addr 0xb7f47001
mtest_write  ...........
mtest_write_val
page  found  for 0xb7f47001
find  0xb7f47001 to kernel address 0xc8c4e001
mtest_write  ...........
mtest_write_val
write 0x1234 to address 0xc8c4e001

你可能感兴趣的:(虚拟内存实践)