OpenCores
URL https://opencores.org/ocsvn/or1k/or1k/trunk

Subversion Repositories or1k

[/] [or1k/] [trunk/] [rc203soc/] [sw/] [uClinux/] [fs/] [proc/] [mem.c] - Blame information for rev 1765

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 1628 jcastillo
/*
2
 *  linux/fs/proc/mem.c
3
 *
4
 *  Copyright (C) 1991, 1992  Linus Torvalds
5
 */
6
 
7
/*
8
 * uClinux revisions for NO_MM
9
 * Copyright (C) 1998  Kenneth Albanowski <kjahds@kjahds.com>,
10
 *                     The Silver Hammer Group, Ltd.
11
 */
12
 
13
#include <linux/types.h>
14
#include <linux/errno.h>
15
#include <linux/sched.h>
16
#include <linux/kernel.h>
17
#include <linux/mm.h>
18
 
19
#include <asm/page.h>
20
#include <asm/segment.h>
21
#include <asm/io.h>
22
#include <asm/pgtable.h>
23
 
24
#ifndef NO_MM
25
 
26
/*
27
 * mem_write isn't really a good idea right now. It needs
28
 * to check a lot more: if the process we try to write to
29
 * dies in the middle right now, mem_write will overwrite
30
 * kernel memory.. This disables it altogether.
31
 */
32
#define mem_write NULL
33
 
34
static int check_range(struct mm_struct * mm, unsigned long addr, int count)
35
{
36
        struct vm_area_struct *vma;
37
        int retval;
38
 
39
        vma = find_vma(mm, addr);
40
        if (!vma)
41
                return -EACCES;
42
        if (vma->vm_start > addr)
43
                return -EACCES;
44
        if (!(vma->vm_flags & VM_READ))
45
                return -EACCES;
46
        while ((retval = vma->vm_end - addr) < count) {
47
                struct vm_area_struct *next = vma->vm_next;
48
                if (!next)
49
                        break;
50
                if (vma->vm_end != next->vm_start)
51
                        break;
52
                if (!(next->vm_flags & VM_READ))
53
                        break;
54
                vma = next;
55
        }
56
        if (retval > count)
57
                retval = count;
58
        return retval;
59
}
60
 
61
static struct task_struct * get_task(int pid)
62
{
63
        struct task_struct * tsk = current;
64
 
65
        if (pid != tsk->pid) {
66
                int i;
67
                tsk = NULL;
68
                for (i = 1 ; i < NR_TASKS ; i++)
69
                        if (task[i] && task[i]->pid == pid) {
70
                                tsk = task[i];
71
                                break;
72
                        }
73
                /*
74
                 * allow accesses only under the same circumstances
75
                 * that we would allow ptrace to work
76
                 */
77
                if (tsk) {
78
                        if (!(tsk->flags & PF_PTRACED)
79
                            || tsk->state != TASK_STOPPED
80
                            || tsk->p_pptr != current)
81
                                tsk = NULL;
82
                }
83
        }
84
        return tsk;
85
}
86
 
87
static int mem_read(struct inode * inode, struct file * file,char * buf, int count)
88
{
89
        pgd_t *page_dir;
90
        pmd_t *page_middle;
91
        pte_t pte;
92
        char * page;
93
        struct task_struct * tsk;
94
        unsigned long addr;
95
        char *tmp;
96
        int i;
97
 
98
        if (count < 0)
99
                return -EINVAL;
100
        tsk = get_task(inode->i_ino >> 16);
101
        if (!tsk)
102
                return -ESRCH;
103
        addr = file->f_pos;
104
        count = check_range(tsk->mm, addr, count);
105
        if (count < 0)
106
                return count;
107
        tmp = buf;
108
        while (count > 0) {
109
                if (current->signal & ~current->blocked)
110
                        break;
111
                page_dir = pgd_offset(tsk->mm,addr);
112
                if (pgd_none(*page_dir))
113
                        break;
114
                if (pgd_bad(*page_dir)) {
115
                        printk("Bad page dir entry %08lx\n", pgd_val(*page_dir));
116
                        pgd_clear(page_dir);
117
                        break;
118
                }
119
                page_middle = pmd_offset(page_dir,addr);
120
                if (pmd_none(*page_middle))
121
                        break;
122
                if (pmd_bad(*page_middle)) {
123
                        printk("Bad page middle entry %08lx\n", pmd_val(*page_middle));
124
                        pmd_clear(page_middle);
125
                        break;
126
                }
127
                pte = *pte_offset(page_middle,addr);
128
                if (!pte_present(pte))
129
                        break;
130
                page = (char *) pte_page(pte) + (addr & ~PAGE_MASK);
131
                i = PAGE_SIZE-(addr & ~PAGE_MASK);
132
                if (i > count)
133
                        i = count;
134
                memcpy_tofs(tmp, page, i);
135
                addr += i;
136
                tmp += i;
137
                count -= i;
138
        }
139
        file->f_pos = addr;
140
        return tmp-buf;
141
}
142
 
143
#ifndef mem_write
144
 
145
static int mem_write(struct inode * inode, struct file * file,char * buf, int count)
146
{
147
        pgd_t *page_dir;
148
        pmd_t *page_middle;
149
        pte_t pte;
150
        char * page;
151
        struct task_struct * tsk;
152
        unsigned long addr;
153
        char *tmp;
154
        int i;
155
 
156
        if (count < 0)
157
                return -EINVAL;
158
        addr = file->f_pos;
159
        tsk = get_task(inode->i_ino >> 16);
160
        if (!tsk)
161
                return -ESRCH;
162
        tmp = buf;
163
        while (count > 0) {
164
                if (current->signal & ~current->blocked)
165
                        break;
166
                page_dir = pgd_offset(tsk,addr);
167
                if (pgd_none(*page_dir))
168
                        break;
169
                if (pgd_bad(*page_dir)) {
170
                        printk("Bad page dir entry %08lx\n", pgd_val(*page_dir));
171
                        pgd_clear(page_dir);
172
                        break;
173
                }
174
                page_middle = pmd_offset(page_dir,addr);
175
                if (pmd_none(*page_middle))
176
                        break;
177
                if (pmd_bad(*page_middle)) {
178
                        printk("Bad page middle entry %08lx\n", pmd_val(*page_middle));
179
                        pmd_clear(page_middle);
180
                        break;
181
                }
182
                pte = *pte_offset(page_middle,addr);
183
                if (!pte_present(pte))
184
                        break;
185
                if (!pte_write(pte))
186
                        break;
187
                page = (char *) pte_page(pte) + (addr & ~PAGE_MASK);
188
                i = PAGE_SIZE-(addr & ~PAGE_MASK);
189
                if (i > count)
190
                        i = count;
191
                memcpy_fromfs(page, tmp, i);
192
                addr += i;
193
                tmp += i;
194
                count -= i;
195
        }
196
        file->f_pos = addr;
197
        if (tmp != buf)
198
                return tmp-buf;
199
        if (current->signal & ~current->blocked)
200
                return -ERESTARTSYS;
201
        return 0;
202
}
203
 
204
#endif
205
 
206
static int mem_lseek(struct inode * inode, struct file * file, off_t offset, int orig)
207
{
208
        switch (orig) {
209
                case 0:
210
                        file->f_pos = offset;
211
                        return file->f_pos;
212
                case 1:
213
                        file->f_pos += offset;
214
                        return file->f_pos;
215
                default:
216
                        return -EINVAL;
217
        }
218
}
219
 
220
/*
221
 * This isn't really reliable by any means..
222
 */
223
int mem_mmap(struct inode * inode, struct file * file,
224
             struct vm_area_struct * vma)
225
{
226
        struct task_struct *tsk;
227
        pgd_t *src_dir, *dest_dir;
228
        pmd_t *src_middle, *dest_middle;
229
        pte_t *src_table, *dest_table;
230
        unsigned long stmp, dtmp, mapnr;
231
        struct vm_area_struct *src_vma = NULL;
232
 
233
        /* Get the source's task information */
234
 
235
        tsk = get_task(inode->i_ino >> 16);
236
 
237
        if (!tsk)
238
                return -ESRCH;
239
 
240
        /* Ensure that we have a valid source area.  (Has to be mmap'ed and
241
         have valid page information.)  We can't map shared memory at the
242
         moment because working out the vm_area_struct & nattach stuff isn't
243
         worth it. */
244
 
245
        src_vma = tsk->mm->mmap;
246
        stmp = vma->vm_offset;
247
        while (stmp < vma->vm_offset + (vma->vm_end - vma->vm_start)) {
248
                while (src_vma && stmp > src_vma->vm_end)
249
                        src_vma = src_vma->vm_next;
250
                if (!src_vma || (src_vma->vm_flags & VM_SHM))
251
                        return -EINVAL;
252
 
253
                src_dir = pgd_offset(tsk->mm, stmp);
254
                if (pgd_none(*src_dir))
255
                        return -EINVAL;
256
                if (pgd_bad(*src_dir)) {
257
                        printk("Bad source page dir entry %08lx\n", pgd_val(*src_dir));
258
                        return -EINVAL;
259
                }
260
                src_middle = pmd_offset(src_dir, stmp);
261
                if (pmd_none(*src_middle))
262
                        return -EINVAL;
263
                if (pmd_bad(*src_middle)) {
264
                        printk("Bad source page middle entry %08lx\n", pmd_val(*src_middle));
265
                        return -EINVAL;
266
                }
267
                src_table = pte_offset(src_middle, stmp);
268
                if (pte_none(*src_table))
269
                        return -EINVAL;
270
 
271
                if (stmp < src_vma->vm_start) {
272
                        if (!(src_vma->vm_flags & VM_GROWSDOWN))
273
                                return -EINVAL;
274
                        if (src_vma->vm_end - stmp > current->rlim[RLIMIT_STACK].rlim_cur)
275
                                return -EINVAL;
276
                }
277
                stmp += PAGE_SIZE;
278
        }
279
 
280
        src_vma = tsk->mm->mmap;
281
        stmp    = vma->vm_offset;
282
        dtmp    = vma->vm_start;
283
 
284
        flush_cache_range(vma->vm_mm, vma->vm_start, vma->vm_end);
285
        flush_cache_range(src_vma->vm_mm, src_vma->vm_start, src_vma->vm_end);
286
        while (dtmp < vma->vm_end) {
287
                while (src_vma && stmp > src_vma->vm_end)
288
                        src_vma = src_vma->vm_next;
289
 
290
                src_dir = pgd_offset(tsk->mm, stmp);
291
                src_middle = pmd_offset(src_dir, stmp);
292
                src_table = pte_offset(src_middle, stmp);
293
 
294
                dest_dir = pgd_offset(current->mm, dtmp);
295
                dest_middle = pmd_alloc(dest_dir, dtmp);
296
                if (!dest_middle)
297
                        return -ENOMEM;
298
                dest_table = pte_alloc(dest_middle, dtmp);
299
                if (!dest_table)
300
                        return -ENOMEM;
301
 
302
                if (!pte_present(*src_table))
303
                        do_no_page(tsk, src_vma, stmp, 1);
304
 
305
                if ((vma->vm_flags & VM_WRITE) && !pte_write(*src_table))
306
                        do_wp_page(tsk, src_vma, stmp, 1);
307
 
308
                set_pte(src_table, pte_mkdirty(*src_table));
309
                set_pte(dest_table, *src_table);
310
                mapnr = MAP_NR(pte_page(*src_table));
311
                if (mapnr < MAP_NR(high_memory))
312
                        mem_map[mapnr].count++;
313
 
314
                stmp += PAGE_SIZE;
315
                dtmp += PAGE_SIZE;
316
        }
317
 
318
        flush_tlb_range(vma->vm_mm, vma->vm_start, vma->vm_end);
319
        flush_tlb_range(src_vma->vm_mm, src_vma->vm_start, src_vma->vm_end);
320
        return 0;
321
}
322
 
323
static struct file_operations proc_mem_operations = {
324
        mem_lseek,
325
        mem_read,
326
        mem_write,
327
        NULL,           /* mem_readdir */
328
        NULL,           /* mem_select */
329
        NULL,           /* mem_ioctl */
330
        mem_mmap,       /* mmap */
331
        NULL,           /* no special open code */
332
        NULL,           /* no special release code */
333
        NULL            /* can't fsync */
334
};
335
 
336
struct inode_operations proc_mem_inode_operations = {
337
        &proc_mem_operations,   /* default base directory file-ops */
338
        NULL,                   /* create */
339
        NULL,                   /* lookup */
340
        NULL,                   /* link */
341
        NULL,                   /* unlink */
342
        NULL,                   /* symlink */
343
        NULL,                   /* mkdir */
344
        NULL,                   /* rmdir */
345
        NULL,                   /* mknod */
346
        NULL,                   /* rename */
347
        NULL,                   /* readlink */
348
        NULL,                   /* follow_link */
349
        NULL,                   /* readpage */
350
        NULL,                   /* writepage */
351
        NULL,                   /* bmap */
352
        NULL,                   /* truncate */
353
        NULL                    /* permission */
354
};
355
 
356
#else /* NO_MM */
357
 
358
/*
359
 * mem_write isn't really a good idea right now. It needs
360
 * to check a lot more: if the process we try to write to
361
 * dies in the middle right now, mem_write will overwrite
362
 * kernel memory.. This disables it altogether.
363
 */
364
#define mem_write NULL
365
 
366
static struct task_struct * get_task(int pid)
367
{
368
        struct task_struct * tsk = current;
369
 
370
        if (pid != tsk->pid) {
371
                int i;
372
                tsk = NULL;
373
                for (i = 1 ; i < NR_TASKS ; i++)
374
                        if (task[i] && task[i]->pid == pid) {
375
                                tsk = task[i];
376
                                break;
377
                        }
378
                /*
379
                 * allow accesses only under the same circumstances
380
                 * that we would allow ptrace to work
381
                 */
382
                if (tsk) {
383
                        if (!(tsk->flags & PF_PTRACED)
384
                            || tsk->state != TASK_STOPPED
385
                            || tsk->p_pptr != current)
386
                                tsk = NULL;
387
                }
388
        }
389
        return tsk;
390
}
391
 
392
static int mem_read(struct inode * inode, struct file * file,char * buf, int count)
393
{
394
        struct task_struct * tsk;
395
        unsigned long addr;
396
        char *tmp;
397
        int i;
398
 
399
        if (count < 0)
400
                return -EINVAL;
401
        tsk = get_task(inode->i_ino >> 16);
402
        if (!tsk)
403
                return -ESRCH;
404
        addr = file->f_pos;
405
        tmp = buf;
406
        while (count > 0) {
407
                if (current->signal & ~current->blocked)
408
                        break;
409
                i = count;
410
                memcpy_tofs(tmp, (void*)addr, i);
411
                addr += i;
412
                tmp += i;
413
                count -= i;
414
        }
415
        file->f_pos = addr;
416
        return tmp-buf;
417
}
418
 
419
#ifndef mem_write
420
 
421
static int mem_write(struct inode * inode, struct file * file,char * buf, int count)
422
{
423
        struct task_struct * tsk;
424
        unsigned long addr;
425
        char *tmp;
426
        int i;
427
 
428
        if (count < 0)
429
                return -EINVAL;
430
        addr = file->f_pos;
431
        tsk = get_task(inode->i_ino >> 16);
432
        if (!tsk)
433
                return -ESRCH;
434
        tmp = buf;
435
        while (count > 0) {
436
                if (current->signal & ~current->blocked)
437
                        break;
438
                i = count;
439
                memcpy_fromfs((void*)addr, tmp, i);
440
                addr += i;
441
                tmp += i;
442
                count -= i;
443
        }
444
        file->f_pos = addr;
445
        if (tmp != buf)
446
                return tmp-buf;
447
        if (current->signal & ~current->blocked)
448
                return -ERESTARTSYS;
449
        return 0;
450
}
451
 
452
#endif
453
 
454
int mem_mmap(struct inode * inode, struct file * file,
455
             struct vm_area_struct * vma)
456
{
457
        vma->vm_start = vma->vm_offset;
458
        return 0;
459
}
460
 
461
static int mem_lseek(struct inode * inode, struct file * file, off_t offset, int orig)
462
{
463
        switch (orig) {
464
                case 0:
465
                        file->f_pos = offset;
466
                        return file->f_pos;
467
                case 1:
468
                        file->f_pos += offset;
469
                        return file->f_pos;
470
                default:
471
                        return -EINVAL;
472
        }
473
}
474
 
475
static struct file_operations proc_mem_operations = {
476
        mem_lseek,
477
        mem_read,
478
        mem_write,
479
        NULL,           /* mem_readdir */
480
        NULL,           /* mem_select */
481
        NULL,           /* mem_ioctl */
482
        mem_mmap,       /* mmap */
483
        NULL,           /* no special open code */
484
        NULL,           /* no special release code */
485
        NULL            /* can't fsync */
486
};
487
 
488
struct inode_operations proc_mem_inode_operations = {
489
        &proc_mem_operations,   /* default base directory file-ops */
490
        NULL,                   /* create */
491
        NULL,                   /* lookup */
492
        NULL,                   /* link */
493
        NULL,                   /* unlink */
494
        NULL,                   /* symlink */
495
        NULL,                   /* mkdir */
496
        NULL,                   /* rmdir */
497
        NULL,                   /* mknod */
498
        NULL,                   /* rename */
499
        NULL,                   /* readlink */
500
        NULL,                   /* follow_link */
501
        NULL,                   /* readpage */
502
        NULL,                   /* writepage */
503
        NULL,                   /* bmap */
504
        NULL,                   /* truncate */
505
        NULL                    /* permission */
506
};
507
 
508
#endif /* NO_MM */

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.