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