This source file includes following definitions.
- check_range
- mem_read
- mem_write
- mem_lseek
- mem_mmap
1
2
3
4
5
6
7 #include <linux/types.h>
8 #include <linux/errno.h>
9 #include <linux/sched.h>
10 #include <linux/kernel.h>
11 #include <linux/mm.h>
12
13 #include <asm/page.h>
14 #include <asm/segment.h>
15 #include <asm/io.h>
16 #include <asm/pgtable.h>
17
18
19
20
21
22
23
24 #define mem_write NULL
25
26 static int check_range(struct task_struct * tsk, unsigned long addr, int count)
27 {
28 struct vm_area_struct *vma;
29 int retval;
30
31 vma = find_vma(tsk, addr);
32 if (!vma)
33 return -EACCES;
34 if (vma->vm_start > addr)
35 return -EACCES;
36 if (!(vma->vm_flags & VM_READ))
37 return -EACCES;
38 while ((retval = vma->vm_end - addr) < count) {
39 struct vm_area_struct *next = vma->vm_next;
40 if (!next)
41 break;
42 if (vma->vm_end != next->vm_start)
43 break;
44 if (!(next->vm_flags & VM_READ))
45 break;
46 vma = next;
47 }
48 if (retval > count)
49 retval = count;
50 return retval;
51 }
52
53 static int mem_read(struct inode * inode, struct file * file,char * buf, int count)
54 {
55 pgd_t *page_dir;
56 pmd_t *page_middle;
57 pte_t pte;
58 char * page;
59 struct task_struct * tsk;
60 unsigned long addr, pid;
61 char *tmp;
62 int i;
63
64 if (count < 0)
65 return -EINVAL;
66 pid = inode->i_ino;
67 pid >>= 16;
68 if (pid != current->pid)
69 return -EACCES;
70 tsk = current;
71 addr = file->f_pos;
72 count = check_range(tsk, addr, count);
73 if (count < 0)
74 return count;
75 tmp = buf;
76 while (count > 0) {
77 if (current->signal & ~current->blocked)
78 break;
79 page_dir = pgd_offset(tsk->mm,addr);
80 if (pgd_none(*page_dir))
81 break;
82 if (pgd_bad(*page_dir)) {
83 printk("Bad page dir entry %08lx\n", pgd_val(*page_dir));
84 pgd_clear(page_dir);
85 break;
86 }
87 page_middle = pmd_offset(page_dir,addr);
88 if (pmd_none(*page_middle))
89 break;
90 if (pmd_bad(*page_middle)) {
91 printk("Bad page middle entry %08lx\n", pmd_val(*page_middle));
92 pmd_clear(page_middle);
93 break;
94 }
95 pte = *pte_offset(page_middle,addr);
96 if (!pte_present(pte))
97 break;
98 page = (char *) pte_page(pte) + (addr & ~PAGE_MASK);
99 i = PAGE_SIZE-(addr & ~PAGE_MASK);
100 if (i > count)
101 i = count;
102 memcpy_tofs(tmp, page, i);
103 addr += i;
104 tmp += i;
105 count -= i;
106 }
107 file->f_pos = addr;
108 return tmp-buf;
109 }
110
111 #ifndef mem_write
112
113 static int mem_write(struct inode * inode, struct file * file,char * buf, int count)
114 {
115 pgd_t *page_dir;
116 pmd_t *page_middle;
117 pte_t pte;
118 char * page;
119 struct task_struct * tsk;
120 unsigned long addr, pid;
121 char *tmp;
122 int i;
123
124 if (count < 0)
125 return -EINVAL;
126 addr = file->f_pos;
127 pid = inode->i_ino;
128 pid >>= 16;
129 if (pid != current->pid)
130 return -EACCES;
131 tsk = current;
132 tmp = buf;
133 while (count > 0) {
134 if (current->signal & ~current->blocked)
135 break;
136 page_dir = pgd_offset(tsk,addr);
137 if (pgd_none(*page_dir))
138 break;
139 if (pgd_bad(*page_dir)) {
140 printk("Bad page dir entry %08lx\n", pgd_val(*page_dir));
141 pgd_clear(page_dir);
142 break;
143 }
144 page_middle = pmd_offset(page_dir,addr);
145 if (pmd_none(*page_middle))
146 break;
147 if (pmd_bad(*page_middle)) {
148 printk("Bad page middle entry %08lx\n", pmd_val(*page_middle));
149 pmd_clear(page_middle);
150 break;
151 }
152 pte = *pte_offset(page_middle,addr);
153 if (!pte_present(pte))
154 break;
155 if (!pte_write(pte))
156 break;
157 page = (char *) pte_page(pte) + (addr & ~PAGE_MASK);
158 i = PAGE_SIZE-(addr & ~PAGE_MASK);
159 if (i > count)
160 i = count;
161 memcpy_fromfs(page, tmp, i);
162 addr += i;
163 tmp += i;
164 count -= i;
165 }
166 file->f_pos = addr;
167 if (tmp != buf)
168 return tmp-buf;
169 if (current->signal & ~current->blocked)
170 return -ERESTARTSYS;
171 return 0;
172 }
173
174 #endif
175
176 static int mem_lseek(struct inode * inode, struct file * file, off_t offset, int orig)
177 {
178 switch (orig) {
179 case 0:
180 file->f_pos = offset;
181 return file->f_pos;
182 case 1:
183 file->f_pos += offset;
184 return file->f_pos;
185 default:
186 return -EINVAL;
187 }
188 }
189
190
191
192
193 int mem_mmap(struct inode * inode, struct file * file,
194 struct vm_area_struct * vma)
195 {
196 struct task_struct *tsk;
197 pgd_t *src_dir, *dest_dir;
198 pmd_t *src_middle, *dest_middle;
199 pte_t *src_table, *dest_table;
200 unsigned long stmp, dtmp;
201 struct vm_area_struct *src_vma = NULL;
202 int i;
203
204
205
206 tsk = NULL;
207 for (i = 1 ; i < NR_TASKS ; i++)
208 if (task[i] && task[i]->pid == (inode->i_ino >> 16)) {
209 tsk = task[i];
210 break;
211 }
212
213 if (!tsk)
214 return -EACCES;
215
216
217
218
219
220
221 src_vma = tsk->mm->mmap;
222 stmp = vma->vm_offset;
223 while (stmp < vma->vm_offset + (vma->vm_end - vma->vm_start)) {
224 while (src_vma && stmp > src_vma->vm_end)
225 src_vma = src_vma->vm_next;
226 if (!src_vma || (src_vma->vm_flags & VM_SHM))
227 return -EINVAL;
228
229 src_dir = pgd_offset(tsk->mm, stmp);
230 if (pgd_none(*src_dir))
231 return -EINVAL;
232 if (pgd_bad(*src_dir)) {
233 printk("Bad source page dir entry %08lx\n", pgd_val(*src_dir));
234 return -EINVAL;
235 }
236 src_middle = pmd_offset(src_dir, stmp);
237 if (pmd_none(*src_middle))
238 return -EINVAL;
239 if (pmd_bad(*src_middle)) {
240 printk("Bad source page middle entry %08lx\n", pmd_val(*src_middle));
241 return -EINVAL;
242 }
243 src_table = pte_offset(src_middle, stmp);
244 if (pte_none(*src_table))
245 return -EINVAL;
246
247 if (stmp < src_vma->vm_start) {
248 if (!(src_vma->vm_flags & VM_GROWSDOWN))
249 return -EINVAL;
250 if (src_vma->vm_end - stmp > current->rlim[RLIMIT_STACK].rlim_cur)
251 return -EINVAL;
252 }
253 stmp += PAGE_SIZE;
254 }
255
256 src_vma = tsk->mm->mmap;
257 stmp = vma->vm_offset;
258 dtmp = vma->vm_start;
259
260 flush_cache_range(vma->vm_mm, vma->vm_start, vma->vm_end);
261 flush_cache_range(src_vma->vm_mm, src_vma->vm_start, src_vma->vm_end);
262 while (dtmp < vma->vm_end) {
263 while (src_vma && stmp > src_vma->vm_end)
264 src_vma = src_vma->vm_next;
265
266 src_dir = pgd_offset(tsk->mm, stmp);
267 src_middle = pmd_offset(src_dir, stmp);
268 src_table = pte_offset(src_middle, stmp);
269
270 dest_dir = pgd_offset(current->mm, dtmp);
271 dest_middle = pmd_alloc(dest_dir, dtmp);
272 if (!dest_middle)
273 return -ENOMEM;
274 dest_table = pte_alloc(dest_middle, dtmp);
275 if (!dest_table)
276 return -ENOMEM;
277
278 if (!pte_present(*src_table))
279 do_no_page(tsk, src_vma, stmp, 1);
280
281 if ((vma->vm_flags & VM_WRITE) && !pte_write(*src_table))
282 do_wp_page(tsk, src_vma, stmp, 1);
283
284 set_pte(src_table, pte_mkdirty(*src_table));
285 set_pte(dest_table, *src_table);
286 mem_map[MAP_NR(pte_page(*src_table))].count++;
287
288 stmp += PAGE_SIZE;
289 dtmp += PAGE_SIZE;
290 }
291
292 flush_tlb_range(vma->vm_mm, vma->vm_start, vma->vm_end);
293 flush_tlb_range(src_vma->vm_mm, src_vma->vm_start, src_vma->vm_end);
294 return 0;
295 }
296
297 static struct file_operations proc_mem_operations = {
298 mem_lseek,
299 mem_read,
300 mem_write,
301 NULL,
302 NULL,
303 NULL,
304 mem_mmap,
305 NULL,
306 NULL,
307 NULL
308 };
309
310 struct inode_operations proc_mem_inode_operations = {
311 &proc_mem_operations,
312 NULL,
313 NULL,
314 NULL,
315 NULL,
316 NULL,
317 NULL,
318 NULL,
319 NULL,
320 NULL,
321 NULL,
322 NULL,
323 NULL,
324 NULL,
325 NULL,
326 NULL,
327 NULL
328 };