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 flush_cache_range(vma->vm_mm, vma->vm_start, vma->vm_end);
271 flush_cache_range(src_vma->vm_mm, src_vma->vm_start, src_vma->vm_end);
272 while (dtmp < vma->vm_end) {
273 while (src_vma && stmp > src_vma->vm_end)
274 src_vma = src_vma->vm_next;
275
276 src_dir = pgd_offset(tsk->mm, stmp);
277 src_middle = pmd_offset(src_dir, stmp);
278 src_table = pte_offset(src_middle, stmp);
279
280 dest_dir = pgd_offset(current->mm, dtmp);
281 dest_middle = pmd_alloc(dest_dir, dtmp);
282 if (!dest_middle)
283 return -ENOMEM;
284 dest_table = pte_alloc(dest_middle, dtmp);
285 if (!dest_table)
286 return -ENOMEM;
287
288 if (!pte_present(*src_table))
289 do_no_page(tsk, src_vma, stmp, 1);
290
291 if ((vma->vm_flags & VM_WRITE) && !pte_write(*src_table))
292 do_wp_page(tsk, src_vma, stmp, 1);
293
294 set_pte(src_table, pte_mkdirty(*src_table));
295 set_pte(dest_table, *src_table);
296 mem_map[MAP_NR(pte_page(*src_table))].count++;
297
298 stmp += PAGE_SIZE;
299 dtmp += PAGE_SIZE;
300 }
301
302 flush_tlb_range(vma->vm_mm, vma->vm_start, vma->vm_end);
303 flush_tlb_range(src_vma->vm_mm, src_vma->vm_start, src_vma->vm_end);
304 return 0;
305 }
306
307 static struct file_operations proc_mem_operations = {
308 mem_lseek,
309 mem_read,
310 mem_write,
311 NULL,
312 NULL,
313 NULL,
314 mem_mmap,
315 NULL,
316 NULL,
317 NULL
318 };
319
320 struct inode_operations proc_mem_inode_operations = {
321 &proc_mem_operations,
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 NULL,
337 NULL
338 };