Linux Virtual Memory

 

  This is the 3rd assignment of course CS353, in which we are required to write a module to explore Linux virtual memory.

 

  Here is the content of ~/Documents/Makefile:

1 obj-m:=mtest.o
2 all:
3     make -C /lib/modules/$(shell uname -r)/build M=$(shell pwd) modules
4 clean:
5     make -C /lib/modules/$(shell uname -r)/build M=$(shell pwd) clean

 

  I wrote the source code in file ~/Documents/mtest.c:

  1 #include <linux/kernel.h>
  2 #include <linux/module.h>
  3 #include <linux/init.h>
  4 #include <linux/proc_fs.h>
  5 #include <linux/seq_file.h>
  6 #include <asm/uaccess.h>
  7 #include <linux/sched.h>
  8 #include <linux/mm.h>
  9 #include <asm/page.h>
 10 #include <asm/pgtable.h>
 11 #include <linux/highmem.h>
 12 #include <linux/mm_types.h>
 13 
 14 #define SIZE 1024
 15 #define VMACACHE_BITS 2
 16 #define VMACACHE_SIZE (1U << VMACACHE_BITS)
 17 
 18 char BUF[SIZE];
 19 
 20 /* Translate hex string into unsigned long */
 21 static unsigned long atol(char *str,unsigned long *pos)
 22 {
 23     unsigned long val = 0L, tmp;
 24     for (;*(str+(*pos))== ;(*pos)++);
 25     for (;*(str+(*pos))!= ;(*pos)++) {
 26         char ch = *(str+(*pos));
 27         if (ch==x) {
 28             continue;
 29         } else if (ch>=0&&ch<=9) {
 30             tmp = ch-0;
 31         } else if (ch>=A&&ch<=F) {
 32             tmp = 10+ch-A;
 33         } else if (ch>=a&&ch<=f) {
 34             tmp = 10+ch-a;
 35         } else {
 36             return 0;
 37         }
 38         val <<= 4;
 39         val += tmp;
 40     }
 41     return val;
 42 }
 43 
 44 /* List the virtual memory areas of *current */
 45 static void listvma(void)
 46 {
 47     struct vm_area_struct *vma;
 48     unsigned long start, end;
 49     vm_flags_t flags;
 50     /* traverse the virtual memory areas
 51         in the form of LINKED-LIST (mm->mmap)
 52         rather than RB-TREE (mm->mm_rb)    */
 53     for (vma=current->mm->mmap;vma;vma=vma->vm_next) {
 54         start = vma->vm_start;
 55         if (stack_guard_page_start(vma, start))
 56             start += PAGE_SIZE;
 57         end = vma->vm_end;
 58         if (stack_guard_page_end(vma, end))
 59             end -= PAGE_SIZE;
 60         flags = vma->vm_flags;
 61         printk(KERN_INFO "%lx-%lx %c%c%c%c\n",
 62                 start,
 63                 end,
 64                 (flags & VM_READ) ? r : -,
 65                 (flags & VM_WRITE) ? w : -,
 66                 (flags & VM_EXEC) ? x : -,
 67                 (flags & VM_MAYSHARE) ? s : p);
 68     }
 69     
 70 }
 71 
 72 /* Given a virtual address, return the page */
 73 static struct page *findpage(unsigned long va,unsigned char wrt)
 74 {
 75     struct page *pg = NULL ;
 76     struct vm_area_struct *vma = NULL;
 77     pgd_t *pgd = NULL;
 78     pud_t *pud = NULL;
 79     pmd_t *pmd = NULL;
 80     pte_t *ptep = NULL;
 81     spinlock_t *ptlp = NULL;
 82     printk(KERN_INFO "va = %lx\n",va);
 83     vma = find_vma(current->mm,va);
 84     if (!vma || va < vma->vm_start) {
 85         // the virtual address is not available
 86         goto OUT;
 87     } else if (wrt && !(vma->vm_flags&VM_WRITE)) {
 88         // the virtual memory area is not writable
 89         goto OUT;
 90     }
 91     printk(KERN_INFO "vma -> %p\n",vma);
 92     /* Page Global Directory */
 93     pgd = pgd_offset(current->mm,va);
 94     if (pgd_none(*pgd) || unlikely(pgd_bad(*pgd))) {
 95         goto OUT;
 96     }
 97     printk(KERN_INFO "pgd = %lx\n",(long)pgd_val(*pgd));
 98     /* Page Upper Directory */
 99     pud = pud_offset(pgd,va);
100     if (pud_none(*pud) || unlikely(pud_bad(*pud))) {
101         goto OUT;
102     }
103     printk(KERN_INFO "pud = %lx\n",(long)pud_val(*pud));
104     /* Page Middle Directory */
105     pmd = pmd_offset(pud,va);
106     if (pmd_none(*pmd) || unlikely(pmd_bad(*pmd))) {
107         goto OUT;
108     }
109     printk(KERN_INFO "pmd = %lx\n",(long)pmd_val(*pmd));
110     /* Page Table Entry */
111     ptep = pte_offset_map_lock(current->mm,pmd,va,&ptlp);
112     printk(KERN_INFO "ptep -> %p\n",ptep);
113     if (!ptep) {
114         goto OUT;
115     }
116     printk(KERN_INFO "pte = %lx\n",(long)pte_val(*ptep));
117     if (!pte_present(*ptep)) {
118         goto UNLOCK;
119     }
120     //pg = vm_normal_page(vma,va,*ptep);
121     pg = pfn_to_page(pte_pfn(*ptep));
122     if (pg) {
123         get_page(pg);
124     }
125 UNLOCK:
126     pte_unmap_unlock(ptep,ptlp);
127 OUT:
128     return pg;
129 }
130 
131 
132 static void mtest_operate(void)
133 {
134     BUF[strlen(BUF)-1] =  ;
135     down_read(&current->mm->mmap_sem);
136     if (!strncmp(BUF,"listvma ",8)) {
137         listvma();
138     } else if (!strncmp(BUF,"findpage ",9)) {
139         unsigned long pos = 9, va;
140         struct page *pg = NULL;
141         va = atol(BUF,&pos);
142         if ((pg = findpage(va,0))) {
143             unsigned long pa;
144             pa = ((long)page_address(pg))|(va&~PAGE_MASK);
145             printk(KERN_INFO "%lx\n",pa);
146         } else {
147             printk(KERN_INFO "translation not found\n");
148         }
149     } else if (!strncmp(BUF,"writeval ",9)) {
150         unsigned long pos = 9, va;
151         struct page *pg = NULL;
152         va = atol(BUF,&pos);
153         if ((pg = findpage(va,1))) {
154             *(unsigned long *)va = atol(BUF,&pos);
155             put_page(pg);
156             printk(KERN_INFO "successful\n");
157         }  else {
158             printk(KERN_INFO "the page is not writable\n");
159         }
160     }
161     up_read(&current->mm->mmap_sem);
162 }
163 
164 
165 /*    
166  *    Basic functions of the proc fs entry /proc/mtest
167  *    mtest_open and mtest_show supports command "cat"
168  *    mtest_write supports command "echo"
169  */
170 
171 static int mtest_show(struct seq_file *m,void *v)
172 {
173     seq_printf(m,"%s\n",BUF);
174     return 0;
175 }
176 
177 static int mtest_open(struct inode *inode,struct file *file)
178 {
179     return single_open(file,mtest_show,NULL);
180 }
181 
182 static ssize_t mtest_write(struct file *filp,const char __user *buf,size_t len,loff_t *pos)
183 {
184     memset(BUF,0,SIZE);
185     if (copy_from_user(BUF,buf,len)){
186         return -EFAULT;
187     }
188     mtest_operate();
189     return len;
190 }
191 
192 static const struct file_operations mtest_fops = {
193     .owner = THIS_MODULE,
194     .read = seq_read,
195     .write = mtest_write,
196     .llseek = seq_lseek,
197     .open = mtest_open,
198     .release = single_release,
199 };
200 
201 static int __init mtest_init(void)
202 {
203     struct proc_dir_entry *entry = NULL;
204     entry = proc_create("mtest",0666,NULL,&mtest_fops);
205     if (!entry) {
206         printk(KERN_INFO "Error: create_proc_entry failed\n");
207         return -1;
208     } else {
209         printk(KERN_INFO "Kernel: mtest init\n");
210         return 0;
211     }
212 }
213 
214 static void __exit mtest_exit(void)
215 {
216     remove_proc_entry("mtest",NULL);
217     printk(KERN_INFO "Kernel: mtest exit\n");
218 }
219 
220 module_init(mtest_init);
221 module_exit(mtest_exit);
222 
223 MODULE_LICENSE("GPL");
224 MODULE_AUTHOR("ZUO NAN");

 

  We are also required to design a user program to write data to a virtual address (./test/c):

 1 #include <stdio.h>
 2 
 3 #define SIZE 128
 4 
 5 unsigned char BUF[SIZE];
 6 
 7 int main()
 8 {
 9     unsigned long val = 0;
10     
11     while (1) {
12         printf("Command: ");
13         memset(BUF,0,SIZE);
14         scanf("%s",&BUF);
15         if (!strcmp(BUF,"write")) {
16             memset(BUF,0,SIZE);
17             scanf("%s",&BUF);
18             printf("writeval %p %s\n",&val,BUF);
19             if (!freopen("/proc/mtest","w",stdout)){
20                 printf("proc entry not found\n");
21                 exit(1);
22             }
23             printf("writeval %p %s\n",&val,BUF);
24             if (!freopen("/dev/tty","w",stdout)){
25                 printf("stdout not recovered\n");
26                 exit(2);
27             }
28         } else if (!strcmp(BUF,"print")) {
29             printf("%lx\n",val);
30         } else if (!strcmp(BUF,"exit")) {
31             break;
32         }
33     }
34     return 0;
35 }

 

  Here are some testing results of my programs.

 

  (1) To test the compilation and insertion of the module:

技术分享

 

  (2) To test LISTVMA instruction:

技术分享

 

  (3) To test FINDPAGE and WRITEVAL:

技术分享

 

  (4) To test the user program:

技术分享

 

  (5) To test the removal of the module:

技术分享

 

郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。