1 /* Copyright (C) 2020-2024 Free Software Foundation, Inc.
2 This file is part of the GNU C Library.
4 The GNU C Library is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Lesser General Public
6 License as published by the Free Software Foundation; either
7 version 2.1 of the License, or (at your option) any later version.
9 The GNU C Library is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 Lesser General Public License for more details.
14 You should have received a copy of the GNU Lesser General Public
15 License along with the GNU C Library; if not, see
16 <https://www.gnu.org/licenses/>. */
18 #include <sys/types.h>
26 /* Remap pages mapped by the range [ADDR,ADDR+OLD_LEN) to new length
27 NEW_LEN. If MREMAP_MAYMOVE is set in FLAGS the returned address
28 may differ from ADDR. If MREMAP_FIXED is set in FLAGS the function
29 takes another parameter which is a fixed address at which the block
30 resides after a successful call. */
33 __mremap (void *addr
, size_t old_len
, size_t new_len
, int flags
, ...)
36 vm_address_t vm_addr
= (vm_address_t
) addr
;
37 vm_offset_t new_vm_addr
= 0;
39 vm_address_t begin
= vm_addr
;
46 memory_object_name_t obj
;
49 if ((flags
& ~(MREMAP_MAYMOVE
| MREMAP_FIXED
)) ||
50 ((flags
& MREMAP_FIXED
) && !(flags
& MREMAP_MAYMOVE
)) ||
51 (old_len
== 0 && !(flags
& MREMAP_MAYMOVE
)))
52 return (void *) (long int) __hurd_fail (EINVAL
);
54 if (flags
& MREMAP_FIXED
)
57 va_start (arg
, flags
);
58 new_vm_addr
= (vm_offset_t
) va_arg (arg
, void *);
62 err
= __vm_region (__mach_task_self (),
63 &begin
, &len
, &prot
, &max_prot
, &inherit
,
64 &shared
, &obj
, &offset
);
66 return (void *) (uintptr_t) __hurd_fail (err
);
74 if (begin
< vm_addr
|| (old_len
!= 0 && old_len
!= len
))
82 if ((flags
& MREMAP_FIXED
) &&
83 ((new_vm_addr
+ new_len
> vm_addr
&& new_vm_addr
< end
)))
85 /* Overlapping is not supported, like in Linux. */
90 /* FIXME: locked memory. */
92 if (old_len
!= 0 && !(flags
& MREMAP_FIXED
))
94 /* A mere change of the existing map. */
98 new_vm_addr
= vm_addr
;
105 __mach_port_deallocate (__mach_task_self (), obj
);
106 err
= __vm_deallocate (__mach_task_self (),
107 begin
+ new_len
, len
- new_len
);
108 new_vm_addr
= vm_addr
;
113 err
= __vm_map (__mach_task_self (),
114 &end
, new_len
- len
, 0, 0,
115 obj
, offset
+ len
, 0, prot
, max_prot
, inherit
);
118 /* Ok, that worked. Now coalesce them. */
119 new_vm_addr
= vm_addr
;
121 /* XXX this is not atomic as it is in unix! */
122 err
= __vm_deallocate (__mach_task_self (), begin
, new_len
);
125 __vm_deallocate (__mach_task_self (), end
, new_len
- len
);
129 err
= __vm_map (__mach_task_self (),
130 &begin
, new_len
, 0, 0,
131 obj
, offset
, 0, prot
, max_prot
, inherit
);
134 /* Oops, try to remap before reporting. */
135 __vm_map (__mach_task_self (),
137 obj
, offset
, 0, prot
, max_prot
, inherit
);
144 if (!(flags
& MREMAP_MAYMOVE
))
146 /* Can not map here */
151 err
= __vm_map (__mach_task_self (),
152 &new_vm_addr
, new_len
, 0,
153 new_vm_addr
== 0, obj
, offset
,
154 old_len
== 0, prot
, max_prot
, inherit
);
156 if (err
== KERN_NO_SPACE
&& (flags
& MREMAP_FIXED
))
158 /* XXX this is not atomic as it is in unix! */
159 /* The region is already allocated; deallocate it first. */
160 err
= __vm_deallocate (__mach_task_self (), new_vm_addr
, new_len
);
162 err
= __vm_map (__mach_task_self (),
163 &new_vm_addr
, new_len
, 0,
165 old_len
== 0, prot
, max_prot
, inherit
);
169 /* Alright, can remove old mapping. */
170 __vm_deallocate (__mach_task_self (), begin
, len
);
173 __mach_port_deallocate (__mach_task_self (), obj
);
175 return (void *) (uintptr_t) __hurd_fail (err
);
176 return (void *) new_vm_addr
;
179 libc_hidden_def (__mremap
)
180 weak_alias (__mremap
, mremap
)