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