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,
/* ![[previous]](../icons/n_left.png)
![[next]](../icons/right.png)
![[first]](../icons/n_first.png)
![[last]](../icons/last.png)
![[top]](../icons/top.png)
![[bottom]](../icons/bottom.png)
![[index]](../icons/index.png)
*/
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)
/* ![[previous]](../icons/left.png)
![[next]](../icons/right.png)
![[first]](../icons/first.png)
![[last]](../icons/last.png)
![[top]](../icons/top.png)
![[bottom]](../icons/bottom.png)
![[index]](../icons/index.png)
*/
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)
/* ![[previous]](../icons/left.png)
![[next]](../icons/n_right.png)
![[first]](../icons/first.png)
![[last]](../icons/n_last.png)
![[top]](../icons/top.png)
![[bottom]](../icons/bottom.png)
![[index]](../icons/index.png)
*/
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 }