|
|
1.1 root 1: /*
2: * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
3: *
4: * @APPLE_LICENSE_HEADER_START@
5: *
6: * Portions Copyright (c) 1999 Apple Computer, Inc. All Rights
7: * Reserved. This file contains Original Code and/or Modifications of
8: * Original Code as defined in and that are subject to the Apple Public
9: * Source License Version 1.1 (the "License"). You may not use this file
10: * except in compliance with the License. Please obtain a copy of the
11: * License at http://www.apple.com/publicsource and read it before using
12: * this file.
13: *
14: * The Original Code and all software distributed under the License are
15: * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
16: * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
17: * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
18: * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
19: * License for the specific language governing rights and limitations
20: * under the License.
21: *
22: * @APPLE_LICENSE_HEADER_END@
23: */
24:
25: /*
26: * Copyright (c) 1988 University of Utah.
27: * Copyright (c) 1991, 1993
28: * The Regents of the University of California. All rights reserved.
29: *
30: * This code is derived from software contributed to Berkeley by
31: * the Systems Programming Group of the University of Utah Computer
32: * Science Department.
33: *
34: * Redistribution and use in source and binary forms, with or without
35: * modification, are permitted provided that the following conditions
36: * are met:
37: * 1. Redistributions of source code must retain the above copyright
38: * notice, this list of conditions and the following disclaimer.
39: * 2. Redistributions in binary form must reproduce the above copyright
40: * notice, this list of conditions and the following disclaimer in the
41: * documentation and/or other materials provided with the distribution.
42: * 3. All advertising materials mentioning features or use of this software
43: * must display the following acknowledgement:
44: * This product includes software developed by the University of
45: * California, Berkeley and its contributors.
46: * 4. Neither the name of the University nor the names of its contributors
47: * may be used to endorse or promote products derived from this software
48: * without specific prior written permission.
49: *
50: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
51: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
52: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
53: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
54: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
55: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
56: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
57: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
58: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
59: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
60: * SUCH DAMAGE.
61: *
62: * from: Utah $Hdr: vm_mmap.c 1.6 91/10/21$
63: *
64: * @(#)vm_mmap.c 8.10 (Berkeley) 2/19/95
65: */
66:
67: /*
68: * Mapped file (mmap) interface to VM
69: */
70:
71: #import <sys/param.h>
72: #import <sys/systm.h>
73: #import <sys/filedesc.h>
74: #import <sys/proc.h>
75: #import <sys/resourcevar.h>
76: #import <sys/buf.h>
77: #import <sys/vnode.h>
78: #import <sys/acct.h>
79: #import <sys/wait.h>
80: #import <sys/file.h>
81: #import <sys/vadvise.h>
82: #import <sys/trace.h>
83: #import <sys/mman.h>
84: #import <sys/conf.h>
85: #import <mach/kern_return.h>
86: #import <kern/task.h>
87: #import <mach/vm_param.h>
88: #import <vm/vm_map.h>
89: #import <vm/vm_pager.h>
90: #import <vm/vnode_pager.h>
91: #import <kern/mapfs.h>
92: #import <miscfs/specfs/specdev.h>
93:
94: struct sbrk_args {
95: int incr;
96: };
97:
98: /* ARGSUSED */
99: int
100: sbrk(p, uap, retval)
101: struct proc *p;
102: struct sbrk_args *uap;
103: register_t *retval;
104: {
105: /* Not yet implemented */
106: kprintf("sbrk(): not supported!\n");
107: return (EOPNOTSUPP);
108: }
109:
110: struct sstk_args {
111: int incr;
112: } *uap;
113:
114: /* ARGSUSED */
115: int
116: sstk(p, uap, retval)
117: struct proc *p;
118: struct sstk_args *uap;
119: register_t *retval;
120: {
121: /* Not yet implemented */
122: kprintf("sstk(): not supported!\n");
123: return (EOPNOTSUPP);
124: }
125:
126: #if COMPAT_43
127: /* ARGSUSED */
128: int
129: ogetpagesize(p, uap, retval)
130: struct proc *p;
131: void *uap;
132: register_t *retval;
133: {
134:
135: *retval = PAGE_SIZE;
136: return (0);
137: }
138: #endif /* COMPAT_43 */
139:
140: struct osmmap_args {
141: caddr_t addr;
142: int len;
143: int prot;
144: int share;
145: int fd;
146: long pos;
147: };
148:
149: osmmap(curp, uap, retval)
150: struct proc *curp;
151: register struct osmmap_args *uap;
152: register_t *retval;
153: {
154: struct mmap_args {
155: caddr_t addr;
156: size_t len;
157: int prot;
158: int flags;
159: int fd;
160: #ifdef DOUBLE_ALIGN_PARAMS
161: long pad;
162: #endif
163: off_t pos;
164: } newargs;
165:
166: if ((uap->share == MAP_SHARED )|| (uap->share == MAP_PRIVATE )) {
167: newargs.addr = uap->addr;
168: newargs.len = (size_t)uap->len;
169: newargs.prot = uap->prot;
170: newargs.flags = uap->share;
171: newargs.fd = uap->fd;
172: newargs.pos = (off_t)uap->pos;
173: return(mmap(curp,&newargs, retval));
174: } else
175: return(EINVAL);
176: }
177:
178: struct mmap_args {
179: caddr_t addr;
180: size_t len;
181: int prot;
182: int flags;
183: int fd;
184: #ifdef DOUBLE_ALIGN_PARAMS
185: long pad;
186: #endif
187: off_t pos;
188: };
189:
190: mmap(p, uap, retval)
191: struct proc *p;
192: struct mmap_args *uap;
193: register_t *retval;
194: {
195: /*
196: * Map in special device (must be SHARED) or file
197: */
198: struct file *fp;
199: register struct vnode *vp;
200: int flags;
201: int prot;
202: int err=0;
203: vm_map_t user_map;
204: kern_return_t result;
205: vm_offset_t user_addr;
206: vm_size_t user_size;
207: vm_offset_t file_pos;
208: boolean_t find_space;
209: extern vm_object_t vm_object_special();
210:
211: user_addr = (vm_offset_t)uap->addr;
212: user_size = (vm_size_t) uap->len;
213:
214: prot = (uap->prot & VM_PROT_ALL);
215: flags = uap->flags;
216:
217: /*
218: * The vm code does not have prototypes & compileser doesn't do the'
219: * the right thing when you cast 64bit value and pass it in function
220: * call. So here it is.
221: */
222: file_pos = (vm_offset_t)uap->pos;
223:
224: /* Anonymous mapping not supported, for now. */
225: if (((flags & MAP_FIXED) && !page_aligned(user_addr)) ||
226: (user_size < 0) || (flags & MAP_ANON)) {
227: return(EINVAL);
228: }
229:
230: err = fdgetf(p, uap->fd, &fp);
231: if (err)
232: return(err);
233:
234: if (fp->f_type != DTYPE_VNODE)
235: return(EBADF);
236: vp = (struct vnode *)fp->f_data;
237:
238: /*
239: * We bend a little - round the start and end addresses
240: * to the nearest page boundary.
241: */
242: user_addr = trunc_page(user_addr);
243: user_size = round_page(user_size);
244:
245: /*
246: * File can be COPIED at an arbitrary offset.
247: * File can only be SHARED if the offset is at a
248: * page boundary.
249: */
250:
251: if ((flags & MAP_SHARED) && ((vm_offset_t)file_pos & page_mask)) {
252: return(EINVAL);
253: }
254:
255: /*
256: * File must be writable if memory will be.
257: */
258: if ((prot & PROT_WRITE) && (fp->f_flag&FWRITE) == 0) {
259: if ((flags & MAP_PRIVATE) == 0) {
260: /* #2211802 */
261: /* If private map, its okay to have write access
262: as allocated space is both read and write
263: */
264: return(EACCES);
265: }
266: }
267: if ((prot & PROT_READ) && (fp->f_flag&FREAD) == 0) {
268: return(EACCES);
269: }
270: /*
271: * Bug# 2203998 -> zero sized length is a valid arg
272: * in 4.4; for ex, copy of zero sized file
273: * will call mmap with length 0
274: */
275: if (user_size == 0)
276: return(0);
277:
278: /*
279: * memory must exist and be writable (even if we're
280: * just reading)
281: */
282:
283: user_map = current_task()->map;
284:
285: #if 0
286: if (!vm_map_check_protection(user_map, user_addr,
287: (vm_offset_t)(user_addr + user_size),
288: VM_PROT_READ|VM_PROT_WRITE)) {
289: return(EINVAL);
290: }
291: #endif
292: if (flags & MAP_FIXED) {
293: find_space = FALSE;
294: } else {
295: find_space = TRUE;
296: }
297:
298: if (vp->v_type == VCHR || vp->v_type == VSTR) {
299: return(EOPNOTSUPP);
300: }
301: else {
302: /*
303: * Map in a file. May be PRIVATE (copy-on-write)
304: * or SHARED (changes go back to file)
305: */
306: vm_pager_t pager;
307: vm_map_t copy_map;
308: vm_offset_t off;
309: struct vm_info *vmp;
310:
311: /*
312: * Only allow regular files for the moment.
313: */
314: if (vp->v_type != VREG) {
315: return(EBADF);
316: }
317:
318: pager = vnode_pager_setup(vp, FALSE, TRUE);
319:
320: /*
321: * Set credentials:
322: * FIXME: if we're writing the file we need a way to
323: * ensure that someone doesn't replace our R/W creds
324: * with ones that only work for read.
325: */
326: vmp = vp->v_vm_info;
327: if (vmp->cred == NULL) {
328: crhold(p->p_ucred);
329: vmp->cred = p->p_ucred;
330: }
331: /* Find space if not MAP_FIXED; otherwise validate */
332: /* This also fixes 2215605 */
333: result = vm_map_find(user_map, NULL, (vm_offset_t) 0,
334: &user_addr, user_size, find_space);
335: if (result != KERN_SUCCESS) {
336: goto out;
337: }
338: if (flags & MAP_SHARED) {
339: /*
340: * Map it directly, allowing modifications
341: * to go out to the inode.
342: */
343: (void) vm_deallocate(user_map, user_addr, user_size);
344: result = vm_allocate_with_pager(user_map,
345: &user_addr, user_size, find_space,
346: pager,
347: (vm_offset_t)file_pos);
348: if (result != KERN_SUCCESS) {
349: goto out;
350: }
351: }
352: else {
353: #if 0
354: /* Moved to cover both shared and private cases */
355: result = vm_map_find(user_map, NULL, (vm_offset_t) 0,
356: &user_addr, user_size, find_space);
357: if (result != KERN_SUCCESS) {
358: goto out;
359: }
360: #endif /* 0 */
361: /*
362: * Copy-on-write of file. Map into private
363: * map, then copy into our address space.
364: */
365: copy_map = vm_map_create(pmap_create(user_size),
366: 0, user_size, TRUE);
367: off = 0;
368: result = vm_allocate_with_pager(copy_map,
369: &off, user_size, find_space,
370: pager,
371: (vm_offset_t)file_pos);
372: if (result != KERN_SUCCESS) {
373: vm_map_deallocate(copy_map);
374: goto out;
375: }
376: result = vm_map_copy(user_map, copy_map,
377: user_addr, user_size,
378: 0, FALSE, FALSE);
379: if (result != KERN_SUCCESS) {
380: vm_map_deallocate(copy_map);
381: goto out;
382: }
383: vm_map_deallocate(copy_map);
384: }
385: }
386:
387: /*
388: * Our memory defaults to read-write. If it shouldn't
389: * be readable, protect it.
390: */
391: if ((prot & PROT_WRITE) == 0) {
392: result = vm_protect(user_map, user_addr, user_size,
393: FALSE, VM_PROT_READ);
394: if (result != KERN_SUCCESS) {
395: (void) vm_deallocate(user_map, user_addr, user_size);
396: goto out;
397: }
398: }
399:
400: /*
401: * Shared memory is also shared with children
402: */
403: /*
404: * HACK HACK HACK
405: * Since this memory CAN'T be made copy-on-write, and since
406: * its users fork, we must change its inheritance to SHARED.
407: * HACK HACK HACK
408: */
409: if (flags & MAP_SHARED) {
410: result = vm_inherit(user_map, user_addr, user_size,
411: VM_INHERIT_SHARE);
412: if (result != KERN_SUCCESS) {
413: (void) vm_deallocate(user_map, user_addr, user_size);
414: goto out;
415: }
416: }
417:
418: *fdflags(p, uap->fd) |= UF_MAPPED;
419:
420: if (result == KERN_SUCCESS)
421: *retval = (register_t)user_addr;
422: /* FALL THROUGH */
423: out:
424: switch (result) {
425: case KERN_SUCCESS:
426: return (0);
427: case KERN_INVALID_ADDRESS:
428: case KERN_NO_SPACE:
429: return (ENOMEM);
430: case KERN_PROTECTION_FAILURE:
431: return (EACCES);
432: default:
433: return (EINVAL);
434: }
435: }
436:
437: struct msync_args {
438: caddr_t addr;
439: int len;
440: };
441: int
442: msync(p, uap, retval)
443: struct proc *p;
444: struct msync_args *uap;
445: register_t *retval;
446: {
447: /* Not yet implemented */
448: return (EOPNOTSUPP);
449: }
450:
451:
452: mremap()
453: {
454: /* Not yet implemented */
455: return (EOPNOTSUPP);
456: }
457:
458: struct munmap_args {
459: caddr_t addr;
460: int len;
461: };
462: munmap(p, uap, retval)
463: struct proc *p;
464: struct munmap_args *uap;
465: register_t *retval;
466:
467: {
468: vm_offset_t user_addr;
469: vm_size_t user_size;
470: kern_return_t result;
471:
472: user_addr = (vm_offset_t) uap->addr;
473: user_size = (vm_size_t) uap->len;
474:
475: /*
476: * user size is allocated to page boundary and size from
477: * the user land is not necessarily in multiple of page size
478: */
479: user_size = round_page(user_size);
480: if ((user_addr & page_mask) ||
481: (user_size & page_mask)) {
482: return(EINVAL);
483: }
484: result = vm_deallocate(current_task()->map, user_addr, user_size);
485: if (result != KERN_SUCCESS) {
486: return(EINVAL);
487: }
488: return(0);
489: }
490:
491: void
492: munmapfd(p, fd)
493: struct proc *p;
494: int fd;
495: {
496: /*
497: * XXX should vm_deallocate any regions mapped to this file
498: */
499: *fdflags(p, fd) &= ~UF_MAPPED;
500: }
501:
502: struct mprotect_args {
503: caddr_t addr;
504: int len;
505: int prot;
506: };
507: int
508: mprotect(p, uap, retval)
509: struct proc *p;
510: struct mprotect_args *uap;
511: register_t *retval;
512: {
513: vm_size_t size;
514: register vm_prot_t prot;
515: caddr_t addr;
516: int len;
517: vm_map_t user_map;
518:
519: addr = uap->addr;
520: len = uap->len;
521: prot = (vm_prot_t)(uap->prot & VM_PROT_ALL);
522:
523: if (((unsigned long)addr & page_mask) || len < 0)
524: return(EINVAL);
525: size = (vm_size_t)len;
526:
527: user_map = current_task()->map;
528: switch (vm_map_protect(user_map, addr, addr+size, prot,
529: FALSE)) {
530: case KERN_SUCCESS:
531: return (0);
532: case KERN_PROTECTION_FAILURE:
533: return (EACCES);
534: }
535: return (EINVAL);
536: }
537:
538: struct madvise_args {
539: caddr_t addr;
540: int len;
541: int behav;
542: };
543: /* ARGSUSED */
544: int
545: madvise(p, uap, retval)
546: struct proc *p;
547: struct madvise_args *uap;
548: register_t *retval;
549: {
550: /* Not yet implemented */
551: return (EOPNOTSUPP);
552: }
553:
554: struct mincore_args {
555: caddr_t addr;
556: int len;
557: char * vec;
558: };
559: /* ARGSUSED */
560: int
561: mincore(p, uap, retval)
562: struct proc *p;
563: struct mincore_args *uap;
564: register_t *retval;
565: {
566: /* Not yet implemented */
567: return (EOPNOTSUPP);
568: }
569:
570: struct mlock_args {
571: caddr_t addr;
572: size_t len;
573: };
574: int
575: mlock(p, uap, retval)
576: struct proc *p;
577: struct mlock_args *uap;
578: register_t *retval;
579: {
580: /* Not yet implemented */
581: return (EOPNOTSUPP);
582: }
583:
584: struct munlock_args {
585: caddr_t addr;
586: size_t len;
587: };
588: int
589: munlock(p, uap, retval)
590: struct proc *p;
591: struct munlock_args *uap;
592: register_t *retval;
593: {
594: /* Not yet implemented */
595: return (EOPNOTSUPP);
596: }
597:
598: int
599: map_fd(fd, offset, va, findspace, size)
600: int fd;
601: vm_offset_t offset;
602: vm_offset_t *va;
603: boolean_t findspace;
604: vm_size_t size;
605: {
606: struct file *fp;
607: register struct vnode *vp;
608: vm_map_t user_map;
609: kern_return_t result;
610: vm_offset_t user_addr;
611: vm_size_t user_size;
612: vm_pager_t pager;
613: vm_map_t copy_map;
614: vm_offset_t off;
615:
616: user_map = current_task()->map;
617:
618: /*
619: * Find the inode; verify that it's a regular file.
620: */
621: if (getvnode(current_proc(), fd, &fp))
622: return (KERN_INVALID_ARGUMENT);
623:
624: vp = (struct vnode *)fp->f_data;
625: if (vp->v_type != VREG)
626: return(KERN_INVALID_ARGUMENT);
627:
628: user_size = round_page(size);
629:
630: if (findspace) {
631: /*
632: * Allocate dummy memory.
633: */
634: result = vm_allocate(user_map, &user_addr, size, TRUE);
635: if (result != KERN_SUCCESS)
636: return(result);
637: if (copyout(&user_addr, va, sizeof(vm_offset_t))) {
638: (void) vm_deallocate(user_map, user_addr, size);
639: return(KERN_INVALID_ADDRESS);
640: }
641: }
642: else {
643: /*
644: * Get user's address, and verify that it's
645: * page-aligned and writable.
646: */
647:
648: if (copyin(va, &user_addr, sizeof(vm_offset_t)))
649: return(KERN_INVALID_ADDRESS);
650: if ((trunc_page(user_addr) != user_addr))
651: return(KERN_INVALID_ARGUMENT);
652: if (!vm_map_check_protection(user_map, user_addr,
653: (vm_offset_t)(user_addr + user_size),
654: VM_PROT_READ|VM_PROT_WRITE))
655: return(KERN_INVALID_ARGUMENT);
656: }
657:
658: /*
659: * Allow user to map in a zero length file.
660: */
661: if (size == 0)
662: return KERN_SUCCESS;
663:
664: /*
665: * Map in the file.
666: */
667:
668: pager = vnode_pager_setup(vp, FALSE, TRUE);
669:
670: /*
671: * Map into private map, then copy into our address space.
672: */
673: copy_map = vm_map_create(pmap_create(user_size), 0, user_size, TRUE);
674: off = 0;
675: result = vm_allocate_with_pager(copy_map, &off, user_size, FALSE,
676: pager,
677: offset);
678: if (result == KERN_SUCCESS)
679: result = vm_map_copy(user_map, copy_map, user_addr, user_size,
680: 0, FALSE, FALSE);
681:
682: if ((result != KERN_SUCCESS) && findspace)
683: (void) vm_deallocate(user_map, user_addr, user_size);
684:
685: vm_map_deallocate(copy_map);
686:
687: /*
688: * Set credentials.
689: */
690: if (vp->v_vm_info->cred == NULL) {
691: crhold(current_proc()->p_ucred);
692: vp->v_vm_info->cred = current_proc()->p_ucred;
693: }
694:
695: return(result);
696: }
697:
698:
699: /* BEGIN DEFUNCT */
700: struct obreak_args {
701: char *nsiz;
702: };
703: obreak(p, uap, retval)
704: struct proc *p;
705: struct obreak_args *uap;
706: register_t *retval;
707: {
708: /* Not implemented, obsolete */
709: return (ENOMEM);
710: }
711:
712: int both;
713:
714: ovadvise()
715: {
716:
717: #ifdef lint
718: both = 0;
719: #endif
720: }
721: /* END DEFUNCT */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.