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]
23 * Copyright 2013 OmniTI Computer Consulting, Inc. All rights reserved.
24 * Copyright 2017 Joyent, Inc.
28 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
29 * Use is subject to license terms.
32 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
33 /* All Rights Reserved */
35 #include <sys/types.h>
36 #include <sys/inttypes.h>
37 #include <sys/param.h>
38 #include <sys/sysmacros.h>
39 #include <sys/systm.h>
40 #include <sys/signal.h>
42 #include <sys/errno.h>
45 #include <sys/tuneable.h>
46 #include <sys/debug.h>
47 #include <sys/cmn_err.h>
49 #include <sys/vnode.h>
54 #include <sys/vmparam.h>
55 #include <sys/fcntl.h>
56 #include <sys/lwpchan_impl.h>
57 #include <sys/nbmlock.h>
62 #include <vm/seg_dev.h>
63 #include <vm/seg_vn.h>
69 * If set, we will not randomize mappings where the 'addr' argument is
70 * non-NULL and not an alignment.
72 int aslr_respect_mmap_hint
= 1;
74 static int brk_lpg(caddr_t nva
);
75 static int grow_lpg(caddr_t sp
);
84 * Serialize brk operations on an address space.
85 * This also serves as the lock protecting p_brksize
88 as_rangelock(p
->p_as
);
91 * As a special case to aid the implementation of sbrk(3C), if given a
92 * new brk of 0, return the current brk. We'll hide this in brk(3C).
95 intptr_t base
= (intptr_t)(p
->p_brkbase
+ p
->p_brksize
);
96 as_rangeunlock(p
->p_as
);
100 if (use_brk_lpg
&& (p
->p_flag
& SAUTOLPG
) != 0) {
101 error
= brk_lpg(nva
);
103 error
= brk_internal(nva
, p
->p_brkpageszc
);
105 as_rangeunlock(p
->p_as
);
106 return ((error
!= 0 ? set_errno(error
) : 0));
110 * Algorithm: call arch-specific map_pgsz to get best page size to use,
111 * then call brk_internal().
112 * Returns 0 on success.
117 struct proc
*p
= curproc
;
119 caddr_t addr
, brkend
;
120 caddr_t bssbase
= p
->p_bssbase
;
121 caddr_t brkbase
= p
->p_brkbase
;
125 oszc
= p
->p_brkpageszc
;
128 * If p_brkbase has not yet been set, the first call
129 * to brk_internal() will initialize it.
132 return (brk_internal(nva
, oszc
));
137 pgsz
= map_pgsz(MAPPGSZ_HEAP
, p
, bssbase
, len
, 0);
138 szc
= page_szc(pgsz
);
142 * 1. page_szc() returns -1 for invalid page size, so we want to
143 * ignore it in that case.
144 * 2. By design we never decrease page size, as it is more stable.
147 err
= brk_internal(nva
, oszc
);
148 /* If failed, back off to base page size. */
149 if (err
!= 0 && oszc
!= 0) {
150 err
= brk_internal(nva
, 0);
155 err
= brk_internal(nva
, szc
);
156 /* If using szc failed, map with base page size and return. */
159 err
= brk_internal(nva
, 0);
165 * Round up brk base to a large page boundary and remap
166 * anything in the segment already faulted in beyond that
169 addr
= (caddr_t
)P2ROUNDUP((uintptr_t)p
->p_bssbase
, pgsz
);
170 brkend
= brkbase
+ p
->p_brksize
;
172 /* Check that len is not negative. Update page size code for heap. */
173 if (addr
>= p
->p_bssbase
&& brkend
> addr
&& IS_P2ALIGNED(len
, pgsz
)) {
174 (void) as_setpagesize(p
->p_as
, addr
, len
, szc
, B_FALSE
);
175 p
->p_brkpageszc
= szc
;
179 return (err
); /* should always be 0 */
183 * Returns 0 on success.
186 brk_internal(caddr_t nva
, uint_t brkszc
)
188 caddr_t ova
; /* current break address */
191 struct proc
*p
= curproc
;
192 struct as
*as
= p
->p_as
;
198 * extend heap to brkszc alignment but use current p->p_brkpageszc
199 * for the newly created segment. This allows the new extension
200 * segment to be concatenated successfully with the existing brk
203 if ((szc
= brkszc
) != 0) {
204 pgsz
= page_get_pagesize(szc
);
205 ASSERT(pgsz
> PAGESIZE
);
210 mutex_enter(&p
->p_lock
);
211 as_rctl
= rctl_enforced_value(rctlproc_legacy
[RLIMIT_DATA
],
213 mutex_exit(&p
->p_lock
);
216 * If p_brkbase has not yet been set, the first call
217 * to brk() will initialize it.
219 if (p
->p_brkbase
== 0)
223 * Before multiple page size support existed p_brksize was the value
224 * not rounded to the pagesize (i.e. it stored the exact user request
225 * for heap size). If pgsz is greater than PAGESIZE calculate the
226 * heap size as the real new heap size by rounding it up to pgsz.
227 * This is useful since we may want to know where the heap ends
228 * without knowing heap pagesize (e.g. some old code) and also if
229 * heap pagesize changes we can update p_brkpageszc but delay adding
230 * new mapping yet still know from p_brksize where the heap really
231 * ends. The user requested heap end is stored in libc variable.
233 if (pgsz
> PAGESIZE
) {
234 caddr_t tnva
= (caddr_t
)P2ROUNDUP((uintptr_t)nva
, pgsz
);
235 size
= tnva
- p
->p_brkbase
;
236 if (tnva
< p
->p_brkbase
|| (size
> p
->p_brksize
&&
237 size
> (size_t)as_rctl
)) {
240 size
= nva
- p
->p_brkbase
;
243 size
= nva
- p
->p_brkbase
;
247 * use PAGESIZE to roundup ova because we want to know the real value
248 * of the current heap end in case p_brkpageszc changes since the last
249 * p_brksize was computed.
251 nva
= (caddr_t
)P2ROUNDUP((uintptr_t)nva
, pgsz
);
252 ova
= (caddr_t
)P2ROUNDUP((uintptr_t)(p
->p_brkbase
+ p
->p_brksize
),
255 if ((nva
< p
->p_brkbase
) || (size
> p
->p_brksize
&&
257 mutex_enter(&p
->p_lock
);
258 (void) rctl_action(rctlproc_legacy
[RLIMIT_DATA
], p
->p_rctls
, p
,
260 mutex_exit(&p
->p_lock
);
265 struct segvn_crargs crargs
=
266 SEGVN_ZFOD_ARGS(PROT_ZFOD
, PROT_ALL
);
268 if (!(p
->p_datprot
& PROT_EXEC
)) {
269 crargs
.prot
&= ~PROT_EXEC
;
273 * Add new zfod mapping to extend UNIX data segment
274 * AS_MAP_NO_LPOOB means use 0, and don't reapply OOB policies
275 * via map_pgszcvec(). Use AS_MAP_HEAP to get intermediate
276 * page sizes if ova is not aligned to szc's pgsz.
281 rbss
= (caddr_t
)P2ROUNDUP((uintptr_t)p
->p_bssbase
,
283 if (IS_P2ALIGNED(p
->p_bssbase
, pgsz
) || ova
> rbss
) {
284 crargs
.szc
= p
->p_brkpageszc
? p
->p_brkpageszc
:
286 } else if (ova
== rbss
) {
289 crargs
.szc
= AS_MAP_HEAP
;
292 crargs
.szc
= AS_MAP_NO_LPOOB
;
294 crargs
.lgrp_mem_policy_flags
= LGRP_MP_FLAG_EXTEND_UP
;
295 error
= as_map(as
, ova
, (size_t)(nva
- ova
), segvn_create
,
301 } else if (nva
< ova
) {
303 * Release mapping to shrink UNIX data segment.
305 (void) as_unmap(as
, nva
, (size_t)(ova
- nva
));
312 * Grow the stack to include sp. Return 1 if successful, 0 otherwise.
313 * This routine assumes that the stack grows downward.
318 struct proc
*p
= curproc
;
319 struct as
*as
= p
->p_as
;
320 size_t oldsize
= p
->p_stksize
;
325 * Serialize grow operations on an address space.
326 * This also serves as the lock protecting p_stksize
330 if (use_stk_lpg
&& (p
->p_flag
& SAUTOLPG
) != 0) {
333 err
= grow_internal(sp
, p
->p_stkpageszc
);
335 newsize
= p
->p_stksize
;
338 if (err
== 0 && newsize
> oldsize
) {
339 ASSERT(IS_P2ALIGNED(oldsize
, PAGESIZE
));
340 ASSERT(IS_P2ALIGNED(newsize
, PAGESIZE
));
342 * Set up translations so the process doesn't have to fault in
343 * the stack pages we just gave it.
345 (void) as_fault(as
->a_hat
, as
, p
->p_usrstack
- newsize
,
346 newsize
- oldsize
, F_INVAL
, S_WRITE
);
348 return ((err
== 0 ? 1 : 0));
352 * Algorithm: call arch-specific map_pgsz to get best page size to use,
353 * then call grow_internal().
354 * Returns 0 on success.
359 struct proc
*p
= curproc
;
367 newsize
= p
->p_usrstack
- sp
;
369 oszc
= p
->p_stkpageszc
;
370 pgsz
= map_pgsz(MAPPGSZ_STK
, p
, sp
, newsize
, 0);
371 szc
= page_szc(pgsz
);
375 * 1. page_szc() returns -1 for invalid page size, so we want to
376 * ignore it in that case.
377 * 2. By design we never decrease page size, as it is more stable.
378 * This shouldn't happen as the stack never shrinks.
381 err
= grow_internal(sp
, oszc
);
382 /* failed, fall back to base page size */
383 if (err
!= 0 && oszc
!= 0) {
384 err
= grow_internal(sp
, 0);
390 * We've grown sufficiently to switch to a new page size.
391 * So we are going to remap the whole segment with the new page size.
393 err
= grow_internal(sp
, szc
);
394 /* The grow with szc failed, so fall back to base page size. */
397 err
= grow_internal(sp
, 0);
403 * Round up stack pointer to a large page boundary and remap
404 * any pgsz pages in the segment already faulted in beyond that
407 saddr
= p
->p_usrstack
- p
->p_stksize
;
408 addr
= (caddr_t
)P2ROUNDUP((uintptr_t)saddr
, pgsz
);
409 growend
= (caddr_t
)P2ALIGN((uintptr_t)p
->p_usrstack
, pgsz
);
410 len
= growend
- addr
;
411 /* Check that len is not negative. Update page size code for stack. */
412 if (addr
>= saddr
&& growend
> addr
&& IS_P2ALIGNED(len
, pgsz
)) {
413 (void) as_setpagesize(p
->p_as
, addr
, len
, szc
, B_FALSE
);
414 p
->p_stkpageszc
= szc
;
418 return (err
); /* should always be 0 */
422 * This routine assumes that the stack grows downward.
423 * Returns 0 on success, errno on failure.
426 grow_internal(caddr_t sp
, uint_t growszc
)
428 struct proc
*p
= curproc
;
435 struct segvn_crargs crargs
= SEGVN_ZFOD_ARGS(PROT_ZFOD
, PROT_ALL
);
437 ASSERT(sp
< p
->p_usrstack
);
438 sp
= (caddr_t
)P2ALIGN((uintptr_t)sp
, PAGESIZE
);
441 * grow to growszc alignment but use current p->p_stkpageszc for
442 * the segvn_crargs szc passed to segvn_create. For memcntl to
443 * increase the szc, this allows the new extension segment to be
444 * concatenated successfully with the existing stack segment.
446 if ((szc
= growszc
) != 0) {
447 pgsz
= page_get_pagesize(szc
);
448 ASSERT(pgsz
> PAGESIZE
);
449 newsize
= p
->p_usrstack
- (caddr_t
)P2ALIGN((uintptr_t)sp
, pgsz
);
450 if (newsize
> (size_t)p
->p_stk_ctl
) {
453 newsize
= p
->p_usrstack
- sp
;
457 newsize
= p
->p_usrstack
- sp
;
460 if (newsize
> (size_t)p
->p_stk_ctl
) {
461 (void) rctl_action(rctlproc_legacy
[RLIMIT_STACK
], p
->p_rctls
, p
,
467 oldsize
= p
->p_stksize
;
468 ASSERT(P2PHASE(oldsize
, PAGESIZE
) == 0);
470 if (newsize
<= oldsize
) { /* prevent the stack from shrinking */
474 if (!(p
->p_stkprot
& PROT_EXEC
)) {
475 crargs
.prot
&= ~PROT_EXEC
;
478 * extend stack with the proposed new growszc, which is different
479 * than p_stkpageszc only on a memcntl to increase the stack pagesize.
480 * AS_MAP_NO_LPOOB means use 0, and don't reapply OOB policies via
481 * map_pgszcvec(). Use AS_MAP_STACK to get intermediate page sizes
482 * if not aligned to szc's pgsz.
485 caddr_t oldsp
= p
->p_usrstack
- oldsize
;
486 caddr_t austk
= (caddr_t
)P2ALIGN((uintptr_t)p
->p_usrstack
,
489 if (IS_P2ALIGNED(p
->p_usrstack
, pgsz
) || oldsp
< austk
) {
490 crargs
.szc
= p
->p_stkpageszc
? p
->p_stkpageszc
:
492 } else if (oldsp
== austk
) {
495 crargs
.szc
= AS_MAP_STACK
;
498 crargs
.szc
= AS_MAP_NO_LPOOB
;
500 crargs
.lgrp_mem_policy_flags
= LGRP_MP_FLAG_EXTEND_DOWN
;
503 * The stack is about to grow into its guard. This can be acceptable
504 * if the size restriction on the stack has been expanded since its
505 * initialization during exec(). In such cases, the guard segment will
506 * be shrunk, provided the new size is reasonable.
508 new_start
= (uintptr_t)p
->p_usrstack
- newsize
;
509 if (p
->p_stkg_start
!= 0 && new_start
> p
->p_stkg_start
&&
510 new_start
< p
->p_stkg_end
) {
511 const size_t unmap_sz
= p
->p_stkg_end
- new_start
;
512 const size_t remain_sz
= new_start
- p
->p_stkg_start
;
513 extern size_t stack_guard_min_sz
;
515 /* Do not allow the guard to shrink below minimum size */
516 if (remain_sz
< stack_guard_min_sz
) {
520 error
= as_unmap(p
->p_as
, (caddr_t
)new_start
, unmap_sz
);
524 p
->p_stkg_end
-= unmap_sz
;
527 if ((error
= as_map(p
->p_as
, (caddr_t
)new_start
, newsize
- oldsize
,
528 segvn_create
, &crargs
)) != 0) {
529 if (error
== EAGAIN
) {
530 cmn_err(CE_WARN
, "Sorry, no swap space to grow stack "
531 "for pid %d (%s)", p
->p_pid
, PTOU(p
)->u_comm
);
535 p
->p_stksize
= newsize
;
540 * Find address for user to map. If MAP_FIXED is not specified, we can pick
541 * any address we want, but we will first try the value in *addrp if it is
542 * non-NULL and _MAP_RANDOMIZE is not set. Thus this is implementing a way to
543 * try and get a preferred address.
546 choose_addr(struct as
*as
, caddr_t
*addrp
, size_t len
, offset_t off
,
547 int vacalign
, uint_t flags
)
549 caddr_t basep
= (caddr_t
)(uintptr_t)((uintptr_t)*addrp
& PAGEMASK
);
552 ASSERT(AS_ISCLAIMGAP(as
)); /* searches should be serialized */
553 if (flags
& MAP_FIXED
) {
554 (void) as_unmap(as
, *addrp
, len
);
556 } else if (basep
!= NULL
&&
557 ((flags
& (MAP_ALIGN
| _MAP_RANDOMIZE
)) == 0) &&
558 !as_gap(as
, len
, &basep
, &lenp
, 0, *addrp
)) {
559 /* User supplied address was available */
563 * No user supplied address or the address supplied was not
566 map_addr(addrp
, len
, off
, vacalign
, flags
);
575 * Used for MAP_ANON - fast way to get anonymous pages
578 zmap(struct as
*as
, caddr_t
*addrp
, size_t len
, uint_t uprot
, int flags
,
581 struct segvn_crargs vn_a
;
584 if (((PROT_ALL
& uprot
) != uprot
))
587 if ((flags
& MAP_FIXED
) != 0) {
591 * Use the user address. First verify that
592 * the address to be used is page aligned.
593 * Then make some simple bounds checks.
595 if (((uintptr_t)*addrp
& PAGEOFFSET
) != 0)
598 userlimit
= flags
& _MAP_LOW32
?
599 (caddr_t
)USERLIMIT32
: as
->a_userlimit
;
600 switch (valid_usr_range(*addrp
, len
, uprot
, as
, userlimit
)) {
611 * No need to worry about vac alignment for anonymous
612 * pages since this is a "clone" object that doesn't
615 error
= choose_addr(as
, addrp
, len
, pos
, ADDR_NOVACALIGN
, flags
);
621 * Use the seg_vn segment driver; passing in the NULL amp
622 * gives the desired "cloning" effect.
626 vn_a
.type
= flags
& MAP_TYPE
;
628 vn_a
.maxprot
= PROT_ALL
;
629 vn_a
.flags
= flags
& ~MAP_TYPE
;
633 vn_a
.lgrp_mem_policy_flags
= 0;
635 return (as_map(as
, *addrp
, len
, segvn_create
, &vn_a
));
638 #define RANDOMIZABLE_MAPPING(addr, flags) (((flags & MAP_FIXED) == 0) && \
639 !(((flags & MAP_ALIGN) == 0) && (addr != 0) && aslr_respect_mmap_hint))
642 smmap_common(caddr_t
*addrp
, size_t len
,
643 int prot
, int flags
, struct file
*fp
, offset_t pos
)
646 struct as
*as
= curproc
->p_as
;
647 uint_t uprot
, maxprot
, type
;
651 if ((flags
& ~(MAP_SHARED
| MAP_PRIVATE
| MAP_FIXED
|
652 _MAP_LOW32
| MAP_NORESERVE
| MAP_ANON
| MAP_ALIGN
|
653 MAP_TEXT
| MAP_INITDATA
)) != 0) {
654 /* | MAP_RENAME */ /* not implemented, let user know */
658 if ((flags
& MAP_TEXT
) && !(prot
& PROT_EXEC
)) {
662 if ((flags
& (MAP_TEXT
| MAP_INITDATA
)) == (MAP_TEXT
| MAP_INITDATA
)) {
666 if ((flags
& (MAP_FIXED
| _MAP_RANDOMIZE
)) ==
667 (MAP_FIXED
| _MAP_RANDOMIZE
)) {
672 * If it's not a fixed allocation and mmap ASLR is enabled, randomize
675 if (RANDOMIZABLE_MAPPING(*addrp
, flags
) &&
676 secflag_enabled(curproc
, PROC_SEC_ASLR
))
677 flags
|= _MAP_RANDOMIZE
;
679 type
= flags
& MAP_TYPE
;
680 if (type
!= MAP_PRIVATE
&& type
!= MAP_SHARED
)
684 if (flags
& MAP_ALIGN
) {
685 if (flags
& MAP_FIXED
)
688 /* alignment needs to be a power of 2 >= page size */
689 if (((uintptr_t)*addrp
< PAGESIZE
&& (uintptr_t)*addrp
!= 0) ||
690 !ISP2((uintptr_t)*addrp
))
694 * Check for bad lengths and file position.
695 * We let the fop_map routine check for negative lengths
696 * since on some vnode types this might be appropriate.
698 if (len
== 0 || (pos
& (uoff_t
)PAGEOFFSET
) != 0)
701 maxprot
= PROT_ALL
; /* start out allowing all accesses */
702 uprot
= prot
| PROT_USER
;
705 ASSERT(flags
& MAP_ANON
);
706 /* discard lwpchan mappings, like munmap() */
707 if ((flags
& MAP_FIXED
) && curproc
->p_lcp
!= NULL
)
708 lwpchan_delete_mapping(curproc
, *addrp
, *addrp
+ len
);
710 error
= zmap(as
, addrp
, len
, uprot
, flags
, pos
);
713 * Tell machine specific code that lwp has mapped shared memory
715 if (error
== 0 && (flags
& MAP_SHARED
)) {
717 LWP_MMODEL_SHARED_AS(*addrp
, len
);
720 } else if ((flags
& MAP_ANON
) != 0)
725 /* Can't execute code from "noexec" mounted filesystem. */
726 if ((vp
->v_vfsp
->vfs_flag
& VFS_NOEXEC
) != 0)
727 maxprot
&= ~PROT_EXEC
;
730 * These checks were added as part of large files.
732 * Return ENXIO if the initial position is negative; return EOVERFLOW
733 * if (offset + len) would overflow the maximum allowed offset for the
734 * type of file descriptor being used.
736 if (vp
->v_type
== VREG
) {
739 if ((offset_t
)len
> (OFFSET_MAX(fp
) - pos
))
743 if (type
== MAP_SHARED
&& (fp
->f_flag
& FWRITE
) == 0) {
744 /* no write access allowed */
745 maxprot
&= ~PROT_WRITE
;
749 * XXX - Do we also adjust maxprot based on protections
750 * of the vnode? E.g. if no execute permission is given
751 * on the vnode for the current user, maxprot probably
752 * should disallow PROT_EXEC also? This is different
753 * from the write access as this would be a per vnode
754 * test as opposed to a per fd test for writability.
758 * Verify that the specified protections are not greater than
759 * the maximum allowable protections. Also test to make sure
760 * that the file descriptor does allows for read access since
761 * "write only" mappings are hard to do since normally we do
762 * the read from the file before the page can be written.
764 if (((maxprot
& uprot
) != uprot
) || (fp
->f_flag
& FREAD
) == 0)
768 * If the user specified an address, do some simple checks here
770 if ((flags
& MAP_FIXED
) != 0) {
774 * Use the user address. First verify that
775 * the address to be used is page aligned.
776 * Then make some simple bounds checks.
778 if (((uintptr_t)*addrp
& PAGEOFFSET
) != 0)
781 userlimit
= flags
& _MAP_LOW32
?
782 (caddr_t
)USERLIMIT32
: as
->a_userlimit
;
783 switch (valid_usr_range(*addrp
, len
, uprot
, as
, userlimit
)) {
794 if ((prot
& (PROT_READ
| PROT_WRITE
| PROT_EXEC
)) &&
795 nbl_need_check(vp
)) {
799 nbl_start_crit(vp
, RW_READER
);
801 error
= nbl_svmand(vp
, fp
->f_cred
, &svmand
);
804 if ((prot
& PROT_WRITE
) && (type
== MAP_SHARED
)) {
805 if (prot
& (PROT_READ
| PROT_EXEC
)) {
813 if (nbl_conflict(vp
, nop
, 0, LONG_MAX
, svmand
, NULL
)) {
819 /* discard lwpchan mappings, like munmap() */
820 if ((flags
& MAP_FIXED
) && curproc
->p_lcp
!= NULL
)
821 lwpchan_delete_mapping(curproc
, *addrp
, *addrp
+ len
);
824 * Ok, now let the vnode map routine do its thing to set things up.
826 error
= fop_map(vp
, pos
, as
,
827 addrp
, len
, uprot
, maxprot
, flags
, fp
->f_cred
, NULL
);
831 * Tell machine specific code that lwp has mapped shared memory
833 if (flags
& MAP_SHARED
) {
835 LWP_MMODEL_SHARED_AS(*addrp
, len
);
837 if (vp
->v_type
== VREG
&&
838 (flags
& (MAP_TEXT
| MAP_INITDATA
)) != 0) {
840 * Mark this as an executable vnode
842 mutex_enter(&vp
->v_lock
);
843 vp
->v_flag
|= VVMEXEC
;
844 mutex_exit(&vp
->v_lock
);
856 * LP64 mmap(2) system call: 64-bit offset, 64-bit address.
858 * The "large file" mmap routine mmap64(2) is also mapped to this routine
859 * by the 64-bit version of libc.
861 * Eventually, this should be the only version, and have smmap_common()
862 * folded back into it again. Some day.
865 smmap64(caddr_t addr
, size_t len
, int prot
, int flags
, int fd
, off_t pos
)
870 if (fd
== -1 && (flags
& MAP_ANON
) != 0)
871 error
= smmap_common(&addr
, len
, prot
, flags
,
872 NULL
, (offset_t
)pos
);
873 else if ((fp
= getf(fd
)) != NULL
) {
874 error
= smmap_common(&addr
, len
, prot
, flags
,
880 return (error
? (caddr_t
)(uintptr_t)set_errno(error
) : addr
);
884 #if defined(_SYSCALL32_IMPL) || defined(_ILP32)
887 * ILP32 mmap64(2) system call: 64-bit offset, 32-bit address.
889 * Now things really get ugly because we can't use the C-style
890 * calling convention for more than 6 args, and 64-bit parameter
891 * passing on 32-bit systems is less than clean.
899 * 32-bit contents, 64-bit cells
908 * 32-bit contents, 32-bit cells
919 smmaplf32(struct mmaplf32a
*uap
, rval_t
*rvp
)
923 caddr_t a
= uap
->addr
;
924 int flags
= (int)uap
->flags
;
925 int fd
= (int)uap
->fd
;
927 offset_t off
= ((uoff_t
)uap
->offhi
<< 32) | (uoff_t
)uap
->offlo
;
929 offset_t off
= ((uoff_t
)uap
->offlo
<< 32) | (uoff_t
)uap
->offhi
;
932 if (flags
& _MAP_LOW32
)
934 else if (fd
== -1 && (flags
& MAP_ANON
) != 0)
935 error
= smmap_common(&a
, uap
->len
, (int)uap
->prot
,
936 flags
| _MAP_LOW32
, NULL
, off
);
937 else if ((fp
= getf(fd
)) != NULL
) {
938 error
= smmap_common(&a
, uap
->len
, (int)uap
->prot
,
939 flags
| _MAP_LOW32
, fp
, off
);
945 rvp
->r_val1
= (uintptr_t)a
;
949 #endif /* _SYSCALL32_IMPL || _ILP32 */
952 munmap(caddr_t addr
, size_t len
)
954 struct proc
*p
= curproc
;
955 struct as
*as
= p
->p_as
;
957 if (((uintptr_t)addr
& PAGEOFFSET
) != 0 || len
== 0)
958 return (set_errno(EINVAL
));
960 if (valid_usr_range(addr
, len
, 0, as
, as
->a_userlimit
) != RANGE_OKAY
)
961 return (set_errno(EINVAL
));
964 * Discard lwpchan mappings.
966 if (p
->p_lcp
!= NULL
)
967 lwpchan_delete_mapping(p
, addr
, addr
+ len
);
968 if (as_unmap(as
, addr
, len
) != 0)
969 return (set_errno(EINVAL
));
975 mprotect(caddr_t addr
, size_t len
, int prot
)
977 struct as
*as
= curproc
->p_as
;
978 uint_t uprot
= prot
| PROT_USER
;
981 if (((uintptr_t)addr
& PAGEOFFSET
) != 0 || len
== 0)
982 return (set_errno(EINVAL
));
984 switch (valid_usr_range(addr
, len
, prot
, as
, as
->a_userlimit
)) {
988 return (set_errno(ENOTSUP
));
991 return (set_errno(ENOMEM
));
994 error
= as_setprot(as
, addr
, len
, uprot
);
996 return (set_errno(error
));
1000 #define MC_CACHE 128 /* internal result buffer */
1001 #define MC_QUANTUM (MC_CACHE * PAGESIZE) /* addresses covered in loop */
1004 mincore(caddr_t addr
, size_t len
, char *vecp
)
1006 struct as
*as
= curproc
->p_as
;
1007 caddr_t ea
; /* end address of loop */
1008 size_t rl
; /* inner result length */
1009 char vec
[MC_CACHE
]; /* local vector cache */
1014 model
= get_udatamodel();
1016 * Validate form of address parameters.
1018 if (model
== DATAMODEL_NATIVE
) {
1021 llen
= (int32_t)(size32_t
)len
;
1023 if (((uintptr_t)addr
& PAGEOFFSET
) != 0 || llen
<= 0)
1024 return (set_errno(EINVAL
));
1026 if (valid_usr_range(addr
, len
, 0, as
, as
->a_userlimit
) != RANGE_OKAY
)
1027 return (set_errno(ENOMEM
));
1030 * Loop over subranges of interval [addr : addr + len), recovering
1031 * results internally and then copying them out to caller. Subrange
1032 * is based on the size of MC_CACHE, defined above.
1034 for (ea
= addr
+ len
; addr
< ea
; addr
+= MC_QUANTUM
) {
1035 error
= as_incore(as
, addr
,
1036 (size_t)MIN(MC_QUANTUM
, ea
- addr
), vec
, &rl
);
1038 rl
= (rl
+ PAGESIZE
- 1) / PAGESIZE
;
1039 if (copyout(vec
, vecp
, rl
) != 0)
1040 return (set_errno(EFAULT
));
1044 return (set_errno(ENOMEM
));