1 /* $NetBSD: osf1_mmap.c,v 1.14 2009/05/18 12:39:02 njoly Exp $ */
2 
3 /*
4  * Copyright (c) 1999 Christopher G. Demetriou.  All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  * 3. All advertising materials mentioning features or use of this software
15  *    must display the following acknowledgement:
16  *      This product includes software developed by Christopher G. Demetriou
17  *	for the NetBSD Project.
18  * 4. The name of the author may not be used to endorse or promote products
19  *    derived from this software without specific prior written permission
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
22  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
23  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
24  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
25  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
26  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
30  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31  */
32 
33 #include <sys/cdefs.h>
34 __KERNEL_RCSID(0, "$NetBSD: osf1_mmap.c,v 1.14 2009/05/18 12:39:02 njoly Exp $");
35 
36 #include <sys/param.h>
37 #include <sys/systm.h>
38 #include <sys/proc.h>
39 #include <sys/mman.h>
40 #include <sys/mount.h>
41 #include <sys/syscallargs.h>
42 #include <uvm/uvm.h>				/* XXX see mmap emulation */
43 
44 #include <compat/osf1/osf1.h>
45 #include <compat/osf1/osf1_syscallargs.h>
46 #include <compat/osf1/osf1_cvt.h>
47 
48 int
osf1_sys_madvise(struct lwp * l,const struct osf1_sys_madvise_args * uap,register_t * retval)49 osf1_sys_madvise(struct lwp *l, const struct osf1_sys_madvise_args *uap, register_t *retval)
50 {
51 	struct sys_madvise_args a;
52 	int error;
53 
54 	SCARG(&a, addr) = SCARG(uap, addr);
55 	SCARG(&a, len) = SCARG(uap, len);
56 
57 	error = 0;
58 	switch (SCARG(uap, behav)) {
59 	case OSF1_MADV_NORMAL:
60 		SCARG(&a, behav) = MADV_NORMAL;
61 		break;
62 
63 	case OSF1_MADV_RANDOM:
64 		SCARG(&a, behav) = MADV_RANDOM;
65 		break;
66 
67 	case OSF1_MADV_SEQUENTIAL:
68 		SCARG(&a, behav) = MADV_SEQUENTIAL;
69 		break;
70 
71 	case OSF1_MADV_WILLNEED:
72 		SCARG(&a, behav) = MADV_WILLNEED;
73 		break;
74 
75 	case OSF1_MADV_DONTNEED_COMPAT:
76 		SCARG(&a, behav) = MADV_DONTNEED;
77 		break;
78 
79 	case OSF1_MADV_SPACEAVAIL:
80 		SCARG(&a, behav) = MADV_SPACEAVAIL;
81 		break;
82 
83 	case OSF1_MADV_DONTNEED:
84 		/*
85 		 * XXX not supported.  In Digital UNIX, this flushes all
86 		 * XXX data in the region and replaces it with ZFOD pages.
87 		 */
88 		error = EINVAL;
89 		break;
90 
91 	default:
92 		error = EINVAL;
93 		break;
94 	}
95 
96 	if (error == 0) {
97 		error = sys_madvise(l, &a, retval);
98 
99 		/*
100 		 * NetBSD madvise() currently always returns ENOSYS.
101 		 * Digital UNIX says that non-operational requests (i.e.
102 		 * valid, but unimplemented 'behav') will return success.
103 		 */
104 		if (error == ENOSYS)
105 			error = 0;
106 	}
107 	return (error);
108 }
109 
110 int
osf1_sys_mmap(struct lwp * l,const struct osf1_sys_mmap_args * uap,register_t * retval)111 osf1_sys_mmap(struct lwp *l, const struct osf1_sys_mmap_args *uap, register_t *retval)
112 {
113 	struct proc *p = l->l_proc;
114 	struct sys_mmap_args a;
115 	unsigned long leftovers;
116 
117 	SCARG(&a, addr) = SCARG(uap, addr);
118 	SCARG(&a, len) = SCARG(uap, len);
119 	SCARG(&a, fd) = SCARG(uap, fd);
120 	SCARG(&a, PAD) = 0;
121 	SCARG(&a, pos) = SCARG(uap, pos);
122 
123 	/* translate prot */
124 	SCARG(&a, prot) = emul_flags_translate(osf1_mmap_prot_xtab,
125 	    SCARG(uap, prot), &leftovers);
126 	if (leftovers != 0)
127 		return (EINVAL);
128 
129 	/* translate flags */
130 	SCARG(&a, flags) = emul_flags_translate(osf1_mmap_flags_xtab,
131 	    SCARG(uap, flags), &leftovers);
132 	if (leftovers != 0)
133 		return (EINVAL);
134 
135 	/*
136 	 * XXX The following code is evil.
137 	 *
138 	 * The OSF/1 mmap() function attempts to map non-fixed entries
139 	 * near the address that the user specified.  Therefore, for
140 	 * non-fixed entires we try to find space in the address space
141 	 * starting at that address.  If the user specified zero, we
142 	 * start looking at at least PAGE_SIZE, so that programs can't
143 	 * accidentally live through deferencing NULL.
144 	 *
145 	 * The need for this kludgery is increased by the fact that
146 	 * the loader data segment is mapped at
147 	 * (end of user address space) - 1G, MAXDSIZ is 1G, and
148 	 * the VM system tries allocate non-fixed mappings _AFTER_
149 	 * (start of data) + MAXDSIZ.  With the loader, of course,
150 	 * that means that it'll start trying at
151 	 * (end of user address space), and will never succeed!
152 	 *
153 	 * Notes:
154 	 *
155 	 * * Though we find space here, if something else (e.g. a second
156 	 *   thread) were mucking with the address space the mapping
157 	 *   we found might be used by another mmap(), and this call
158 	 *   would clobber that region.
159 	 *
160 	 * * In general, tricks like this only work for MAP_ANON mappings,
161 	 *   because of sharing/cache issues.  That's not a problem on
162 	 *   the Alpha, and though it's not good style to abuse that fact,
163 	 *   there's little choice.
164 	 *
165 	 * * In order for this to be done right, the VM system should
166 	 *   really try to use the requested 'addr' passed in to mmap()
167 	 *   as a hint, even if non-fixed.  If it's passed as zero,
168 	 *   _maybe_ then try (start of data) + MAXDSIZ, or maybe
169 	 *   provide a better way to avoid the data region altogether.
170 	 */
171 	if ((SCARG(&a, flags) & MAP_FIXED) == 0) {
172 		vaddr_t addr = round_page((vaddr_t)SCARG(&a, addr));
173 		vsize_t size = round_page((vsize_t)SCARG(&a, len));
174 		int fixed = 0;
175 
176 		vm_map_lock(&p->p_vmspace->vm_map);
177 
178 		/* if non-NULL address given, start looking there */
179 		if (addr != 0 && uvm_map_findspace(&p->p_vmspace->vm_map,
180 		    addr, size, &addr, NULL, 0, 0, 0) != NULL) {
181 			fixed = 1;
182 			goto done;
183 		}
184 
185 		/* didn't find anything.  take it again from the top. */
186 		if (uvm_map_findspace(&p->p_vmspace->vm_map, PAGE_SIZE, size,
187 		    &addr, NULL, 0, 0, 0) != NULL) {
188 			fixed = 1;
189 			goto done;
190 		}
191 
192 done:
193 		vm_map_unlock(&p->p_vmspace->vm_map);
194 		if (fixed) {
195 			SCARG(&a, flags) |= MAP_FIXED;
196 			SCARG(&a, addr) = (void *)addr;
197 		}
198 	}
199 
200 	return sys_mmap(l, &a, retval);
201 }
202 
203 int
osf1_sys_mprotect(struct lwp * l,const struct osf1_sys_mprotect_args * uap,register_t * retval)204 osf1_sys_mprotect(struct lwp *l, const struct osf1_sys_mprotect_args *uap, register_t *retval)
205 {
206 	struct sys_mprotect_args a;
207 	unsigned long leftovers;
208 
209 	SCARG(&a, addr) = SCARG(uap, addr);
210 	SCARG(&a, len) = SCARG(uap, len);
211 
212 	/* translate prot */
213 	SCARG(&a, prot) = emul_flags_translate(osf1_mmap_prot_xtab,
214 	    SCARG(uap, prot), &leftovers);
215 	if (leftovers != 0)
216 		return (EINVAL);
217 
218 	return sys_mprotect(l, &a, retval);
219 }
220