Unleashed v1.4
[unleashed.git] / kernel / syscall / mmapobjsys.c
blob59f62f0ffc3a0f5f009dd75bf2a2d95682983953
1 /*
2 * CDDL HEADER START
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
19 * CDDL HEADER END
22 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
26 #include <sys/types.h>
27 #include <sys/errno.h>
28 #include <sys/mman.h>
29 #include <sys/cred.h>
30 #include <sys/model.h>
31 #include <sys/vnode.h>
32 #include <sys/systm.h>
33 #include <sys/kmem.h>
34 #include <sys/file.h>
35 #include <sys/vfs.h>
36 #include <sys/sysmacros.h>
37 #include <sys/mmapobj.h>
40 * We will "allocate" this many mmapobj_result_t segments on the stack
41 * in an attempt to avoid the need to call kmem_alloc. This value should
42 * cover 99% of the known ELF libraries as well as AOUT (4.x) libraries.
44 #define MOBJ_STACK_SEGS 6
46 static void
47 mmapobj_copy_64to32(mmapobj_result_t *source, mmapobj_result32_t *dest, int num)
49 int i;
51 for (i = 0; i < num; i++) {
52 dest[i].mr_addr = (caddr32_t)(uintptr_t)source[i].mr_addr;
53 dest[i].mr_msize = (size32_t)source[i].mr_msize;
54 dest[i].mr_fsize = (size32_t)source[i].mr_fsize;
55 dest[i].mr_offset = (size32_t)source[i].mr_offset;
56 dest[i].mr_prot = source[i].mr_prot;
57 dest[i].mr_flags = source[i].mr_flags;
61 int
62 mmapobjsys(int fd, uint_t flags, mmapobj_result_t *storage,
63 uint_t *elements, void *arg)
65 uint_t num_mapped;
66 uint_t num_in;
67 int error;
68 int old_error;
69 size_t padding = 0;
70 mmapobj_result_t stack_mr[MOBJ_STACK_SEGS];
71 mmapobj_result_t *mrp = stack_mr;
72 struct file *fp;
73 struct vnode *vp;
74 model_t model;
75 int convert_64to32 = 0;
76 uint_t alloc_num = 0;
79 /* Verify flags */
80 if ((flags & ~MMOBJ_ALL_FLAGS) != 0) {
81 return (set_errno(EINVAL));
84 if (((flags & MMOBJ_PADDING) == 0) && arg != NULL) {
85 return (set_errno(EINVAL));
88 fp = getf(fd);
89 if (fp == NULL) {
90 return (set_errno(EBADF));
92 vp = fp->f_vnode;
94 if ((fp->f_flag & FREAD) == 0) {
95 error = EACCES;
96 goto out;
99 error = copyin(elements, &num_mapped, sizeof (uint_t));
100 if (error) {
101 error = EFAULT;
102 goto out;
105 num_in = num_mapped;
106 model = get_udatamodel();
107 if (model != DATAMODEL_NATIVE) {
108 ASSERT(model == DATAMODEL_ILP32);
109 convert_64to32 = 1;
112 if (flags & MMOBJ_PADDING) {
113 if (convert_64to32) {
114 size32_t padding32;
115 error = copyin(arg, &padding32, sizeof (padding32));
116 padding = padding32;
117 } else {
118 error = copyin(arg, &padding, sizeof (padding));
120 if (error) {
121 error = EFAULT;
122 goto out;
126 * Need to catch overflow here for the 64 bit case. For the
127 * 32 bit case, overflow would round up to 4G which would
128 * not be able to fit in any address space and thus ENOMEM
129 * would be returned after calling into mmapobj.
131 if (padding) {
132 padding = P2ROUNDUP(padding, PAGESIZE);
133 if (padding == 0) {
134 error = ENOMEM;
135 goto out;
138 /* turn off padding if no bytes were requested */
139 if (padding == 0) {
140 flags = flags & (~MMOBJ_PADDING);
144 if (num_mapped > MOBJ_STACK_SEGS) {
145 num_mapped = MOBJ_STACK_SEGS;
147 retry:
148 error = mmapobj(vp, flags, mrp, &num_mapped, padding, fp->f_cred);
150 if (error == E2BIG && alloc_num == 0) {
151 if (num_mapped > MOBJ_STACK_SEGS && num_mapped <= num_in) {
152 mrp = kmem_alloc(sizeof (mmapobj_result_t) * num_mapped,
153 KM_SLEEP);
154 alloc_num = num_mapped;
155 goto retry;
159 old_error = error;
160 if (error == 0 || error == E2BIG) {
161 error = copyout(&num_mapped, elements, sizeof (uint_t));
162 if (error) {
163 error = EFAULT;
165 * We only mapped in segments if the mmapobj call
166 * succeeded, so only unmap for that case.
168 if (old_error == 0) {
169 mmapobj_unmap(mrp, num_mapped, num_mapped, 0);
171 } else if (num_in < num_mapped) {
172 ASSERT(old_error == E2BIG);
173 error = E2BIG;
174 } else {
175 if (convert_64to32) {
176 mmapobj_result32_t *mrp32;
177 /* Need to translate from 64bit to 32bit */
178 mrp32 = kmem_alloc(num_mapped * sizeof (*mrp32),
179 KM_SLEEP);
180 mmapobj_copy_64to32(mrp, mrp32, num_mapped);
181 error = copyout(mrp32, (void *)storage,
182 num_mapped * sizeof (mmapobj_result32_t));
183 kmem_free(mrp32, num_mapped * sizeof (*mrp32));
184 } else {
185 error = copyout(mrp, (void *)storage,
186 num_mapped * sizeof (mmapobj_result_t));
188 if (error) {
189 error = EFAULT;
190 mmapobj_unmap(mrp, num_mapped, num_mapped, 0);
196 * If stack_mr was not large enough, then we had to allocate
197 * a larger piece of memory to hold the mmapobj_result array.
199 if (alloc_num != 0) {
200 ASSERT(mrp != stack_mr);
201 ASSERT(num_mapped > MOBJ_STACK_SEGS);
202 kmem_free(mrp,
203 alloc_num * sizeof (mmapobj_result_t));
206 out:
207 releasef(fd);
208 if (error) {
209 return (set_errno(error));
210 } else {
211 return (0);