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]
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>
30 #include <sys/model.h>
31 #include <sys/vnode.h>
32 #include <sys/systm.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
47 mmapobj_copy_64to32(mmapobj_result_t
*source
, mmapobj_result32_t
*dest
, int num
)
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
;
62 mmapobjsys(int fd
, uint_t flags
, mmapobj_result_t
*storage
,
63 uint_t
*elements
, void *arg
)
70 mmapobj_result_t stack_mr
[MOBJ_STACK_SEGS
];
71 mmapobj_result_t
*mrp
= stack_mr
;
75 int convert_64to32
= 0;
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
));
90 return (set_errno(EBADF
));
94 if ((fp
->f_flag
& FREAD
) == 0) {
99 error
= copyin(elements
, &num_mapped
, sizeof (uint_t
));
106 model
= get_udatamodel();
107 if (model
!= DATAMODEL_NATIVE
) {
108 ASSERT(model
== DATAMODEL_ILP32
);
112 if (flags
& MMOBJ_PADDING
) {
113 if (convert_64to32
) {
115 error
= copyin(arg
, &padding32
, sizeof (padding32
));
118 error
= copyin(arg
, &padding
, sizeof (padding
));
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.
132 padding
= P2ROUNDUP(padding
, PAGESIZE
);
138 /* turn off padding if no bytes were requested */
140 flags
= flags
& (~MMOBJ_PADDING
);
144 if (num_mapped
> MOBJ_STACK_SEGS
) {
145 num_mapped
= MOBJ_STACK_SEGS
;
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
,
154 alloc_num
= num_mapped
;
160 if (error
== 0 || error
== E2BIG
) {
161 error
= copyout(&num_mapped
, elements
, sizeof (uint_t
));
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
);
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
),
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
));
185 error
= copyout(mrp
, (void *)storage
,
186 num_mapped
* sizeof (mmapobj_result_t
));
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
);
203 alloc_num
* sizeof (mmapobj_result_t
));
209 return (set_errno(error
));