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

Subversion Repositories or1k

[/] [or1k/] [trunk/] [rc203soc/] [sw/] [uClinux/] [mmnommu/] [mmap.c] - Blame information for rev 1634

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 1634 jcastillo
/*
2
 *      linux/mm/mmap.c
3
 *
4
 * Written by obz.
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
 * Copyright (C) 1999  D. Jeff Dionne <jeff@uclinux.org>,
12
 *                     Rt-Control, Inc.
13
 */
14
 
15
#include <linux/stat.h>
16
#include <linux/sched.h>
17
#include <linux/kernel.h>
18
#include <linux/mm.h>
19
#include <linux/shm.h>
20
#include <linux/errno.h>
21
#include <linux/mman.h>
22
#include <linux/string.h>
23
#include <linux/malloc.h>
24
#include <linux/pagemap.h>
25
#include <linux/swap.h>
26
 
27
#include <asm/segment.h>
28
#include <asm/system.h>
29
#include <asm/pgtable.h>
30
 
31
/* If defined, warn whenever someone mmaps a block that has more then this
32
   number of bytes in slack space (due to kmalloc granularity). */
33
 
34
/*#define WARN_ON_SLACK 1024*/
35
 
36
/*
37
 * Combine the mmap "prot" and "flags" argument into one "vm_flags" used
38
 * internally. Essentially, translate the "PROT_xxx" and "MAP_xxx" bits
39
 * into "VM_xxx".
40
 */
41
static inline unsigned long vm_flags(unsigned long prot, unsigned long flags)
42
{
43
#define _trans(x,bit1,bit2) \
44
((bit1==bit2)?(x&bit1):(x&bit1)?bit2:0)
45
 
46
        unsigned long prot_bits, flag_bits;
47
        prot_bits =
48
                _trans(prot, PROT_READ, VM_READ) |
49
                _trans(prot, PROT_WRITE, VM_WRITE) |
50
                _trans(prot, PROT_EXEC, VM_EXEC);
51
        flag_bits =
52
                _trans(flags, MAP_GROWSDOWN, VM_GROWSDOWN) |
53
                _trans(flags, MAP_DENYWRITE, VM_DENYWRITE) |
54
                _trans(flags, MAP_EXECUTABLE, VM_EXECUTABLE);
55
        return prot_bits | flag_bits;
56
#undef _trans
57
}
58
 
59
asmlinkage unsigned long sys_brk(unsigned long brk)
60
{
61
        return -ENOSYS;
62
}
63
 
64
#ifdef DEBUG_MMAP
65
 
66
#undef do_mmap
67
unsigned long do_mmap_flf(struct file * file, unsigned long addr, unsigned long len,
68
        unsigned long prot, unsigned long flags, unsigned long off, char*filename, int line, char*function)
69
{
70
        unsigned long result;
71
        printk("%s @%s:%d: do_mmap by pid %d of %lu", function, filename, line, current->pid, len);
72
 
73
        result=do_mmap(file,addr,len,prot,flags,off);
74
 
75
        if (result >= -4096) /* so to speak... */
76
                printk(" = %lx\n", result);
77
        else
78
        if (is_in_rom(result))
79
                printk("-%lu = %lx\n", len, result);
80
        else
81
        printk("+%lu+%lu+%lu = %lx\n",
82
                ksize(result)-len,
83
                ksize(current->mm->tblock.next),
84
                ksize(current->mm->tblock.next->rblock),
85
                result);
86
        return result;
87
}
88
#endif /* DEBUG_MMAP */
89
 
90
#ifdef DEBUG
91
static void show_process_blocks(void)
92
{
93
        struct mm_tblock_struct * tblock, *tmp;
94
 
95
        printk("Process blocks %d:", current->pid);
96
 
97
        tmp = &current->mm->tblock;
98
        while (tmp) {
99
                printk(" %p: %p", tmp, tmp->rblock);
100
                if (tmp->rblock)
101
                        printk(" (%d @%p #%d)", ksize(tmp->rblock->kblock), tmp->rblock->kblock, tmp->rblock->refcount);
102
                if (tmp->next)
103
                        printk(" ->");
104
                else
105
                        printk(".");
106
                tmp = tmp->next;
107
        }
108
        printk("\n");
109
}
110
#endif /* DEBUG */
111
 
112
extern unsigned long askedalloc, realalloc;
113
 
114
unsigned long do_mmap(struct file * file, unsigned long addr, unsigned long len,
115
        unsigned long prot, unsigned long flags, unsigned long off)
116
{
117
        void * result;
118
        struct mm_tblock_struct * tblock;
119
 
120
        if ((flags & MAP_SHARED) && (prot & PROT_WRITE) && (file)) {
121
                printk("MAP_SHARED not supported (cannot write mappings to disk)\n");
122
                return -EINVAL;
123
        }
124
 
125
        if ((prot & PROT_WRITE) && (flags & MAP_PRIVATE)) {
126
                printk("Private writable mappings not supported\n");
127
                return -EINVAL;
128
        }
129
 
130
        /*
131
         * determine the object being mapped and call the appropriate
132
         * specific mapper.
133
         */
134
 
135
        if (file) {
136
                struct vm_area_struct vma;
137
                int error;
138
 
139
 
140
                if (!file->f_op)
141
                        return -ENODEV;
142
 
143
                vma.vm_start = addr;
144
                vma.vm_end = addr + len;
145
                vma.vm_flags = vm_flags(prot,flags) /*| mm->def_flags*/;
146
 
147
                if (file->f_mode & 1)
148
                        vma.vm_flags |= VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC;
149
                if (flags & MAP_SHARED) {
150
                        vma.vm_flags |= VM_SHARED | VM_MAYSHARE;
151
                        /*
152
                         * This looks strange, but when we don't have the file open
153
                         * for writing, we can demote the shared mapping to a simpler
154
                         * private mapping. That also takes care of a security hole
155
                         * with ptrace() writing to a shared mapping without write
156
                         * permissions.
157
                         *
158
                         * We leave the VM_MAYSHARE bit on, just to get correct output
159
                         * from /proc/xxx/maps..
160
                         */
161
                        if (!(file->f_mode & 2))
162
                                vma.vm_flags &= ~(VM_MAYWRITE | VM_SHARED);
163
                }
164
                vma.vm_offset = off;
165
 
166
#ifdef MAGIC_ROM_PTR
167
                /* First, try simpler routine designed to give us a ROM pointer. */
168
 
169
                if (file->f_op->romptr && !(prot & PROT_WRITE)) {
170
                        error = file->f_op->romptr(file->f_inode, file, &vma);
171
                        /*printk("romptr mmap returned %d /%x\n", error, vma.vm_start);*/
172
 
173
                        if (!error)
174
                                return vma.vm_start;
175
                        else if (error != -ENOSYS)
176
                                return error;
177
                } else
178
#endif /* MAGIC_ROM_PTR */
179
                /* Then try full mmap routine, which might return a RAM pointer,
180
                   or do something truly complicated. */
181
 
182
                if (file->f_op->mmap) {
183
                        error = file->f_op->mmap(file->f_inode, file, &vma);
184
 
185
                        /*printk("mmap mmap returned %d /%x\n", error, vma.vm_start);*/
186
                        if (!error)
187
                                return vma.vm_start;
188
                        else if (error != -ENOSYS)
189
                                return error;
190
                } else
191
                        return -ENODEV; /* No mapping operations defined */
192
 
193
                /* An ENOSYS error indicates that mmap isn't possible (as opposed to
194
                   tried but failed) so we'll fall through to the copy. */
195
        }
196
 
197
        tblock = (struct mm_tblock_struct *)
198
                        kmalloc(sizeof(struct mm_tblock_struct), GFP_KERNEL);
199
        if (!tblock) {
200
                printk("Allocation of tblock for %lu byte allocation from process %d failed\n", len, current->pid);
201
                show_buffers();
202
                show_free_areas();
203
                return -ENOMEM;
204
        }
205
 
206
        tblock->rblock = (struct mm_rblock_struct *)
207
                        kmalloc(sizeof(struct mm_rblock_struct), GFP_KERNEL);
208
 
209
        if (!tblock->rblock) {
210
                printk("Allocation of rblock for %lu byte allocation from process %d failed\n", len, current->pid);
211
                show_buffers();
212
                show_free_areas();
213
                kfree(tblock);
214
                return -ENOMEM;
215
        }
216
 
217
 
218
        result = kmalloc(len, GFP_KERNEL);
219
        if (!result) {
220
                printk("Allocation of length %lu from process %d failed\n", len, current->pid);
221
                show_buffers();
222
                show_free_areas();
223
                kfree(tblock->rblock);
224
                kfree(tblock);
225
                return -ENOMEM;
226
        }
227
 
228
        tblock->rblock->refcount = 1;
229
        tblock->rblock->kblock = result;
230
        tblock->rblock->size = len;
231
 
232
        realalloc += ksize(result);
233
        askedalloc += len;
234
 
235
#ifdef WARN_ON_SLACK    
236
        if ((len+WARN_ON_SLACK) <= ksize(result))
237
                printk("Allocation of %lu bytes from process %d has %lu bytes of slack\n", len, current->pid, ksize(result)-len);
238
#endif
239
 
240
        if (file) {
241
                int error;
242
                int old_fs = get_fs();
243
                set_fs(KERNEL_DS);
244
                error = file->f_op->read(file->f_inode, file, (char*)result, len);
245
                set_fs(old_fs);
246
                if (error < 0) {
247
                        kfree(result);
248
                        kfree(tblock->rblock);
249
                        kfree(tblock);
250
                        return error;
251
                }
252
                if (error<len)
253
                        memset(result+error, '\0', len-error);
254
        } else {
255
                memset(result, '\0', len);
256
        }
257
 
258
 
259
        realalloc += ksize(tblock);
260
        askedalloc += sizeof(struct mm_tblock_struct);
261
 
262
        realalloc += ksize(tblock->rblock);
263
        askedalloc += sizeof(struct mm_rblock_struct);
264
 
265
        tblock->next = current->mm->tblock.next;
266
        current->mm->tblock.next = tblock;
267
 
268
#ifdef DEBUG
269
        printk("do_mmap:\n");
270
        show_process_blocks();
271
#endif    
272
 
273
        return (unsigned long)result;
274
}
275
 
276
 
277
asmlinkage int sys_munmap(unsigned long addr, size_t len)
278
{
279
        return do_munmap(addr, len);
280
}
281
 
282
#ifdef DEBUG_MMAP
283
#undef do_munmap
284
int do_munmap_flf(unsigned long addr, size_t len, char * filename, int line, char*function)
285
{
286
        printk("do_munmap of %lx bytes at %x invoked from %s @%s:%d\n", ksize(addr), addr, function, filename, line);
287
        return do_munmap(addr,len);
288
}
289
 
290
#endif
291
 
292
 
293
/*
294
 * Munmap is split into 2 main parts -- this part which finds
295
 * what needs doing, and the areas themselves, which do the
296
 * work.  This now handles partial unmappings.
297
 * Jeremy Fitzhardine <jeremy@sw.oz.au>
298
 */
299
int do_munmap(unsigned long addr, size_t len)
300
{
301
        struct mm_tblock_struct * tblock, *tmp;
302
 
303
#ifdef MAGIC_ROM_PTR
304
        /* For efficiency's sake, if the pointer is obviously in ROM,
305
           don't bother walking the lists to free it */
306
        if (is_in_rom(addr))
307
                return 0;
308
#endif
309
 
310
#ifdef DEBUG
311
        printk("do_munmap:\n");
312
#endif
313
 
314
        tmp = &current->mm->tblock;
315
        while ((tblock=tmp->next) && (tblock->rblock) && (tblock->rblock->kblock != (void*)addr))
316
                tmp = tblock;
317
 
318
        if (!tblock) {
319
                printk("munmap of non-mmaped memory by process %d (%s): %p\n", current->pid, current->comm, (void*)addr);
320
                return -EINVAL;
321
        }
322
        if(tblock->rblock)
323
                if(!--tblock->rblock->refcount) {
324
                        if (tblock->rblock->kblock) {
325
                                realalloc -= ksize(tblock->rblock->kblock);
326
                                askedalloc -= tblock->rblock->size;
327
                                kfree(tblock->rblock->kblock);
328
                        }
329
 
330
                        realalloc -= ksize(tblock->rblock);
331
                        askedalloc -= sizeof(struct mm_rblock_struct);
332
                        kfree(tblock->rblock);
333
                }
334
        tmp->next = tblock->next;
335
        realalloc -= ksize(tblock);
336
        askedalloc -= sizeof(struct mm_tblock_struct);
337
        kfree(tblock);
338
 
339
#ifdef DEBUG
340
        show_process_blocks();
341
#endif    
342
 
343
        return -EINVAL;
344
}
345
 
346
/* Release all mmaps. */
347
void exit_mmap(struct mm_struct * mm)
348
{
349
        struct mm_tblock_struct * tmp = &mm->tblock;
350
        /*unsigned long flags;*/
351
 
352
        if (!mm)
353
                return;
354
 
355
        if (mm->executable)
356
                iput(mm->executable);
357
        mm->executable = 0;
358
 
359
        /*save_flags(flags); cli();*/
360
 
361
        if (mm->count > 1) {
362
                /*restore_flags(flags);*/
363
                return;
364
        }
365
 
366
#ifdef DEBUG
367
        printk("Exit_mmap:\n");
368
#endif
369
 
370
        while((tmp = tmp->next)) {
371
                if (tmp->rblock) {
372
                        if (!--tmp->rblock->refcount) {
373
                                if (tmp->rblock->kblock) {
374
                                        realalloc -= ksize(tmp->rblock->kblock);
375
                                        askedalloc -= tmp->rblock->size;
376
                                        kfree(tmp->rblock->kblock);
377
                                }
378
                                realalloc -= ksize(tmp->rblock);
379
                                askedalloc -= sizeof(struct mm_rblock_struct);
380
                                kfree(tmp->rblock);
381
                        }
382
                        tmp->rblock = 0;
383
                }
384
                mm->tblock.next = tmp->next;
385
                realalloc -= ksize(tmp);
386
                askedalloc -= sizeof(struct mm_tblock_struct);
387
                kfree(tmp);
388
        }
389
 
390
#ifdef DEBUG
391
        show_process_blocks();
392
#endif    
393
 
394
        /*restore_flags(flags);*/
395
 
396
}

powered by: WebSVN 2.1.0

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