tar: use utime() to restore timestamps
[minix.git] / servers / vm / mmap.c
blob8a9bf22e6ce6c5da0fb5eabdbf3092f1f400b8a7
2 #define _SYSTEM 1
4 #include <minix/callnr.h>
5 #include <minix/com.h>
6 #include <minix/config.h>
7 #include <minix/const.h>
8 #include <minix/ds.h>
9 #include <minix/endpoint.h>
10 #include <minix/keymap.h>
11 #include <minix/minlib.h>
12 #include <minix/type.h>
13 #include <minix/ipc.h>
14 #include <minix/sysutil.h>
15 #include <minix/syslib.h>
16 #include <minix/safecopies.h>
17 #include <minix/bitmap.h>
18 #include <minix/debug.h>
20 #include <sys/mman.h>
21 #include <sys/param.h>
23 #include <errno.h>
24 #include <assert.h>
25 #include <string.h>
26 #include <env.h>
27 #include <stdio.h>
28 #include <fcntl.h>
30 #include "glo.h"
31 #include "proto.h"
32 #include "util.h"
33 #include "region.h"
35 /*===========================================================================*
36 * do_mmap *
37 *===========================================================================*/
38 int do_mmap(message *m)
40 int r, n;
41 struct vmproc *vmp;
42 int mfflags = 0;
43 vir_bytes addr;
44 struct vir_region *vr = NULL;
45 int execpriv = 0;
47 /* RS and VFS can do slightly more special mmap() things */
48 if(m->m_source == VFS_PROC_NR || m->m_source == RS_PROC_NR)
49 execpriv = 1;
51 if(m->VMM_FLAGS & MAP_THIRDPARTY) {
52 if(!execpriv) return EPERM;
53 if((r=vm_isokendpt(m->VMM_FORWHOM, &n)) != OK)
54 return ESRCH;
55 } else {
56 /* regular mmap, i.e. for caller */
57 if((r=vm_isokendpt(m->m_source, &n)) != OK) {
58 panic("do_mmap: message from strange source: %d",
59 m->m_source);
63 vmp = &vmproc[n];
65 if(m->VMM_FD == -1 || (m->VMM_FLAGS & MAP_ANON)) {
66 mem_type_t *mt;
67 u32_t vrflags = VR_ANON | VR_WRITABLE;
68 size_t len = (vir_bytes) m->VMM_LEN;
70 if(m->VMM_FD != -1 || len <= 0) {
71 return EINVAL;
74 /* Contiguous phys memory has to be preallocated. */
75 if((m->VMM_FLAGS & (MAP_CONTIG|MAP_PREALLOC)) == MAP_CONTIG) {
76 return EINVAL;
79 if(m->VMM_FLAGS & MAP_PREALLOC) mfflags |= MF_PREALLOC;
80 if(m->VMM_FLAGS & MAP_LOWER16M) vrflags |= VR_LOWER16MB;
81 if(m->VMM_FLAGS & MAP_LOWER1M) vrflags |= VR_LOWER1MB;
82 if(m->VMM_FLAGS & MAP_ALIGN64K) vrflags |= VR_PHYS64K;
83 if(m->VMM_FLAGS & MAP_UNINITIALIZED) {
84 if(!execpriv) return EPERM;
85 vrflags |= VR_UNINITIALIZED;
87 if(m->VMM_FLAGS & MAP_CONTIG) {
88 vrflags |= VR_CONTIG;
89 mt = &mem_type_anon_contig;
90 } else mt = &mem_type_anon;
92 if(len % VM_PAGE_SIZE)
93 len += VM_PAGE_SIZE - (len % VM_PAGE_SIZE);
95 vr = NULL;
96 if (m->VMM_ADDR || (m->VMM_FLAGS & MAP_FIXED)) {
97 /* An address is given, first try at that address. */
98 addr = m->VMM_ADDR;
99 vr = map_page_region(vmp, addr, 0, len,
100 vrflags, mfflags, mt);
101 if(!vr && (m->VMM_FLAGS & MAP_FIXED))
102 return ENOMEM;
104 if (!vr) {
105 /* No address given or address already in use. */
106 vr = map_page_region(vmp, 0, VM_DATATOP, len,
107 vrflags, mfflags, mt);
109 if (!vr) {
110 return ENOMEM;
112 } else {
113 return ENOSYS;
116 /* Return mapping, as seen from process. */
117 assert(vr);
118 m->VMM_RETADDR = vr->vaddr;
121 return OK;
124 /*===========================================================================*
125 * map_perm_check *
126 *===========================================================================*/
127 int map_perm_check(endpoint_t caller, endpoint_t target,
128 phys_bytes physaddr, phys_bytes len)
130 int r;
132 /* TTY and memory are allowed to do anything.
133 * They have to be special cases as they have to be able to do
134 * anything; TTY even on behalf of anyone for the TIOCMAPMEM
135 * ioctl. MEM just for itself.
137 if(caller == TTY_PROC_NR)
138 return OK;
139 if(caller != target)
140 return EPERM;
141 if(caller == MEM_PROC_NR)
142 return OK;
144 /* Anyone else needs explicit permission from the kernel (ultimately
145 * set by PCI).
147 r = sys_privquery_mem(caller, physaddr, len);
149 return r;
152 /*===========================================================================*
153 * do_map_phys *
154 *===========================================================================*/
155 int do_map_phys(message *m)
157 int r, n;
158 struct vmproc *vmp;
159 endpoint_t target;
160 struct vir_region *vr;
161 vir_bytes len;
162 phys_bytes startaddr;
163 size_t offset;
165 target = m->VMMP_EP;
166 len = m->VMMP_LEN;
168 if (len <= 0) return EINVAL;
170 if(target == SELF)
171 target = m->m_source;
173 if((r=vm_isokendpt(target, &n)) != OK)
174 return EINVAL;
176 startaddr = (vir_bytes)m->VMMP_PHADDR;
178 /* First check permission, then round range down/up. Caller can't
179 * help it if we can't map in lower than page granularity.
181 if(map_perm_check(m->m_source, target, startaddr, len) != OK) {
182 printf("VM: unauthorized mapping of 0x%lx by %d\n",
183 startaddr, m->m_source);
184 return EPERM;
187 vmp = &vmproc[n];
189 offset = startaddr % VM_PAGE_SIZE;
190 len += offset;
191 startaddr -= offset;
193 if(len % VM_PAGE_SIZE)
194 len += VM_PAGE_SIZE - (len % VM_PAGE_SIZE);
196 if(!(vr = map_page_region(vmp, 0, VM_DATATOP, len,
197 VR_DIRECT | VR_WRITABLE, 0, &mem_type_directphys))) {
198 return ENOMEM;
201 phys_setphys(vr, startaddr);
203 m->VMMP_VADDR_REPLY = (void *) (vr->vaddr + offset);
205 return OK;
208 /*===========================================================================*
209 * do_remap *
210 *===========================================================================*/
211 int do_remap(message *m)
213 int dn, sn;
214 vir_bytes da, sa;
215 size_t size;
216 u32_t flags;
217 struct vir_region *src_region, *vr;
218 struct vmproc *dvmp, *svmp;
219 int r;
220 int readonly;
222 if(m->m_type == VM_REMAP)
223 readonly = 0;
224 else if(m->m_type == VM_REMAP_RO)
225 readonly = 1;
226 else panic("do_remap: can't be");
228 da = (vir_bytes) m->VMRE_DA;
229 sa = (vir_bytes) m->VMRE_SA;
230 size = m->VMRE_SIZE;
232 if (size <= 0) return EINVAL;
234 if ((r = vm_isokendpt((endpoint_t) m->VMRE_D, &dn)) != OK)
235 return EINVAL;
236 if ((r = vm_isokendpt((endpoint_t) m->VMRE_S, &sn)) != OK)
237 return EINVAL;
239 dvmp = &vmproc[dn];
240 svmp = &vmproc[sn];
242 if (!(src_region = map_lookup(svmp, sa, NULL)))
243 return EINVAL;
245 if(src_region->vaddr != sa) {
246 printf("VM: do_remap: not start of region.\n");
247 return EFAULT;
250 if (size % VM_PAGE_SIZE)
251 size += VM_PAGE_SIZE - size % VM_PAGE_SIZE;
253 if(size != src_region->length) {
254 printf("VM: do_remap: not size of region.\n");
255 return EFAULT;
258 flags = VR_SHARED;
259 if(!readonly)
260 flags |= VR_WRITABLE;
262 if(da)
263 vr = map_page_region(dvmp, da, 0, size, flags, 0,
264 &mem_type_shared);
265 else
266 vr = map_page_region(dvmp, 0, VM_DATATOP, size, flags, 0,
267 &mem_type_shared);
269 if(!vr) {
270 printf("VM: re-map of shared area failed\n");
271 return ENOMEM;
274 shared_setsource(vr, svmp->vm_endpoint, src_region);
276 m->VMRE_RETA = (char *) vr->vaddr;
277 return OK;
280 /*===========================================================================*
281 * do_get_phys *
282 *===========================================================================*/
283 int do_get_phys(message *m)
285 int r, n;
286 struct vmproc *vmp;
287 endpoint_t target;
288 phys_bytes ret;
289 vir_bytes addr;
291 target = m->VMPHYS_ENDPT;
292 addr = m->VMPHYS_ADDR;
294 if ((r = vm_isokendpt(target, &n)) != OK)
295 return EINVAL;
297 vmp = &vmproc[n];
299 r = map_get_phys(vmp, addr, &ret);
301 m->VMPHYS_RETA = ret;
302 return r;
305 /*===========================================================================*
306 * do_get_refcount *
307 *===========================================================================*/
308 int do_get_refcount(message *m)
310 int r, n;
311 struct vmproc *vmp;
312 endpoint_t target;
313 u8_t cnt;
314 vir_bytes addr;
316 target = m->VMREFCNT_ENDPT;
317 addr = m->VMREFCNT_ADDR;
319 if ((r = vm_isokendpt(target, &n)) != OK)
320 return EINVAL;
322 vmp = &vmproc[n];
324 r = map_get_ref(vmp, addr, &cnt);
326 m->VMREFCNT_RETC = cnt;
327 return r;
330 /*===========================================================================*
331 * do_munmap *
332 *===========================================================================*/
333 int do_munmap(message *m)
335 int r, n;
336 struct vmproc *vmp;
337 vir_bytes addr, len, offset;
338 struct vir_region *vr;
339 endpoint_t target = SELF;
341 if(m->m_type == VM_UNMAP_PHYS) {
342 target = m->VMUP_EP;
343 } else if(m->m_type == VM_SHM_UNMAP) {
344 target = m->VMUN_ENDPT;
347 if(target == SELF)
348 target = m->m_source;
350 if((r=vm_isokendpt(target, &n)) != OK) {
351 panic("do_mmap: message from strange source: %d", m->m_source);
354 vmp = &vmproc[n];
356 if(m->m_type == VM_UNMAP_PHYS) {
357 addr = (vir_bytes) m->VMUP_VADDR;
358 } else if(m->m_type == VM_SHM_UNMAP) {
359 addr = (vir_bytes) m->VMUN_ADDR;
360 } else addr = (vir_bytes) m->VMUM_ADDR;
362 if(!(vr = map_lookup(vmp, addr, NULL))) {
363 printf("VM: unmap: virtual address 0x%lx not found in %d\n",
364 addr, target);
365 return EFAULT;
368 if(addr % VM_PAGE_SIZE)
369 return EFAULT;
371 if(m->m_type == VM_UNMAP_PHYS || m->m_type == VM_SHM_UNMAP) {
372 len = vr->length;
373 } else len = roundup(m->VMUM_LEN, VM_PAGE_SIZE);
375 offset = addr - vr->vaddr;
377 if(offset + len > vr->length) {
378 printf("munmap: addr 0x%lx len 0x%lx spills out of region\n",
379 addr, len);
380 return EFAULT;
383 if(map_unmap_region(vmp, vr, offset, len) != OK)
384 panic("do_munmap: map_unmap_region failed");
386 return OK;