|
|
1.1 root 1: /*
2: * linux/mm/mmap.c
3: *
4: * Written by obz.
5: */
6: #include <sys/stat.h>
7: #include <linux/sched.h>
8: #include <linux/kernel.h>
9: #include <asm/segment.h>
10: #include <asm/system.h>
11: #include <errno.h>
12: #include <sys/mman.h>
13:
14: /*
15: * description of effects of mapping type and prot in current implementation.
16: * this is due to the current handling of page faults in memory.c. the expected
17: * behavior is in parens:
18: *
19: * map_type prot
20: * PROT_NONE PROT_READ PROT_WRITE PROT_EXEC
21: * MAP_SHARED r: (no) yes r: (yes) yes r: (no) yes r: (no) no
22: * w: (no) yes w: (no) copy w: (yes) yes w: (no) no
23: * x: (no) no x: (no) no x: (no) no x: (yes) no
24: *
25: * MAP_PRIVATE r: (no) yes r: (yes) yes r: (no) yes r: (no) no
26: * w: (no) copy w: (no) copy w: (copy) copy w: (no) no
27: * x: (no) no x: (no) no x: (no) no x: (yes) no
28: *
29: * the permissions are encoded as cxwr (copy,exec,write,read)
30: */
31: #define MTYP(T) ((T) & MAP_TYPE)
32: #define PREAD(T,P) (((P) & PROT_READ) ? 1 : 0)
33: #define PWRITE(T,P) (((P) & PROT_WRITE) ? (MTYP(T) == MAP_SHARED ? 2 : 10) : 0)
34: #define PEXEC(T,P) (((P) & PROT_EXEC) ? 4 : 0)
35: #define PERMISS(T,P) (PREAD(T,P)|PWRITE(T,P)|PEXEC(T,P))
36:
37: #define CODE_SPACE(addr) ((((addr)+4095)&~4095) < \
38: current->start_code + current->end_code)
39:
40: extern int remap_page_range(unsigned long from, unsigned long to,
41: unsigned long size, int permiss);
42: extern int unmap_page_range(unsigned long from, unsigned long size);
43:
44: static caddr_t
45: mmap_chr(unsigned long addr, size_t len, int prot, int flags,
46: struct inode *inode, unsigned long off)
47: {
48: int major, minor;
49: extern unsigned long HIGH_MEMORY;
50:
51: major = MAJOR(inode->i_rdev);
52: minor = MINOR(inode->i_rdev);
53:
54: /*
55: * for character devices, only /dev/mem may be mapped. when the
56: * swapping code is modified to allow arbitrary sources of pages,
57: * then we can open it up to regular files.
58: */
59:
60: if (major != 1 || minor != 1)
61: return (caddr_t)-ENODEV;
62:
63: /*
64: * we only allow mappings from address 0 to HIGH_MEMORY, since thats
65: * the range of our memory [actually this is a lie. the buffer cache
66: * and ramdisk occupy higher memory, but the paging stuff won't
67: * let us map to it anyway, so we break it here].
68: *
69: * this call is very dangerous! because of the lack of adequate
70: * tagging of frames, it is possible to mmap over a frame belonging
71: * to another (innocent) process. with MAP_SHARED|MAP_WRITE, this
72: * rogue process can trample over the other's data! we ignore this :{
73: * for now, we hope people will malloc the required amount of space,
74: * then mmap over it. the mm needs serious work before this can be
75: * truly useful.
76: */
77:
78: if (len > HIGH_MEMORY || off > HIGH_MEMORY - len) /* avoid overflow */
79: return (caddr_t)-ENXIO;
80:
81: if (remap_page_range(addr, off, len, PERMISS(flags, prot)))
82: return (caddr_t)-EAGAIN;
83:
84: return (caddr_t)addr;
85: }
86:
87: caddr_t
88: sys_mmap(unsigned long *buffer)
89: {
90: unsigned long base, addr;
91: unsigned long len, limit, off;
92: int prot, flags, fd;
93: struct file *file;
94: struct inode *inode;
95:
96: addr = (unsigned long) get_fs_long(buffer); /* user address space*/
97: len = (size_t) get_fs_long(buffer+1); /* nbytes of mapping */
98: prot = (int) get_fs_long(buffer+2); /* protection */
99: flags = (int) get_fs_long(buffer+3); /* mapping type */
100: fd = (int) get_fs_long(buffer+4); /* object to map */
101: off = (unsigned long) get_fs_long(buffer+5); /* offset in object */
102:
103: if (fd >= NR_OPEN || fd < 0 || !(file = current->filp[fd]))
104: return (caddr_t) -EBADF;
105: if (addr > TASK_SIZE || (addr+(unsigned long) len) > TASK_SIZE)
106: return (caddr_t) -EINVAL;
107: inode = file->f_inode;
108:
109: /*
110: * do simple checking here so the lower-level routines won't have
111: * to. we assume access permissions have been handled by the open
112: * of the memory object, so we don't do any here.
113: */
114:
115: switch (flags & MAP_TYPE) {
116: case MAP_SHARED:
117: if ((prot & PROT_WRITE) && !(file->f_mode & 2))
118: return (caddr_t)-EINVAL;
119: /* fall through */
120: case MAP_PRIVATE:
121: if (!(file->f_mode & 1))
122: return (caddr_t)-EINVAL;
123: break;
124:
125: default:
126: return (caddr_t)-EINVAL;
127: }
128:
129: /*
130: * obtain the address to map to. we verify (or select) it and ensure
131: * that it represents a valid section of the address space. we assume
132: * that if PROT_EXEC is specified this should be in the code segment.
133: */
134: if (prot & PROT_EXEC) {
135: base = get_base(current->ldt[1]); /* cs */
136: limit = get_limit(0x0f); /* cs limit */
137: } else {
138: base = get_base(current->ldt[2]); /* ds */
139: limit = get_limit(0x17); /* ds limit */
140: }
141:
142: if (flags & MAP_FIXED) {
143: /*
144: * if MAP_FIXED is specified, we have to map exactly at this
145: * address. it must be page aligned and not ambiguous.
146: */
147: if ((addr & 0xfff) || addr > 0x7fffffff || addr == 0 ||
148: (off & 0xfff))
149: return (caddr_t)-EINVAL;
150: if (addr + len > limit)
151: return (caddr_t)-ENOMEM;
152: } else {
153: /*
154: * we're given a hint as to where to put the address.
155: * that we still need to search for a range of pages which
156: * are not mapped and which won't impact the stack or data
157: * segment.
158: * in linux, we only have a code segment and data segment.
159: * since data grows up and stack grows down, we're sort of
160: * stuck. placing above the data will break malloc, below
161: * the stack will cause stack overflow. because of this
162: * we don't allow nonspecified mappings...
163: */
164: return (caddr_t)-ENOMEM;
165: }
166:
167: /*
168: * determine the object being mapped and call the appropriate
169: * specific mapper. the address has already been validated, but
170: * not unmapped
171: */
172: if (S_ISCHR(inode->i_mode))
173: addr = (unsigned long)mmap_chr(base + addr, len, prot, flags,
174: inode, off);
175: else
176: addr = (unsigned long)-ENODEV;
177: if ((long)addr > 0)
178: addr -= base;
179:
180: return (caddr_t)addr;
181: }
182:
183: int sys_munmap(unsigned long addr, size_t len)
184: {
185: unsigned long base, limit;
186:
187: base = get_base(current->ldt[2]); /* map into ds */
188: limit = get_limit(0x17); /* ds limit */
189:
190: if ((addr & 0xfff) || addr > 0x7fffffff || addr == 0 ||
191: addr + len > limit)
192: return -EINVAL;
193: if (unmap_page_range(base + addr, len))
194: return -EAGAIN; /* should never happen */
195: return 0;
196: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.