]>
Commit | Line | Data |
---|---|---|
04277e02 | 1 | /* Copyright (C) 1991-2019 Free Software Foundation, Inc. |
ebbad4cc | 2 | This file is part of the GNU C Library. |
28f540f4 | 3 | |
ebbad4cc | 4 | The GNU C Library is free software; you can redistribute it and/or |
41bdb6e2 AJ |
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. | |
28f540f4 | 8 | |
ebbad4cc UD |
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 | |
41bdb6e2 | 12 | Lesser General Public License for more details. |
28f540f4 | 13 | |
41bdb6e2 | 14 | You should have received a copy of the GNU Lesser General Public |
59ba27a6 PE |
15 | License along with the GNU C Library; if not, see |
16 | <http://www.gnu.org/licenses/>. */ | |
28f540f4 | 17 | |
28f540f4 RM |
18 | #include <errno.h> |
19 | #include <hurd.h> | |
20 | #include <hurd/resource.h> | |
21 | #include <cthreads.h> /* For `struct mutex'. */ | |
22 | ||
23 | ||
683158e0 RM |
24 | /* Initial maximum size of the data segment (this is arbitrary). */ |
25 | #define DATA_SIZE (128 * 1024 * 1024) | |
28f540f4 | 26 | |
28f540f4 RM |
27 | /* Up to the page including this address is allocated from the kernel. |
28 | This address is the data resource limit. */ | |
29 | vm_address_t _hurd_data_end; | |
30 | ||
31 | /* Up to this address is actually available to the user. | |
32 | Pages beyond the one containing this address allow no access. */ | |
51ec5cb2 | 33 | vm_address_t _hurd_brk = 0; |
28f540f4 | 34 | |
2cc7dc4d RM |
35 | /* This name is used by the Linux crtbeginS.o for reasons you don't even |
36 | want to think about it. It's just easier to provide some definition for | |
37 | it than even to explain the braindamage involved. */ | |
51ec5cb2 | 38 | weak_alias (_hurd_brk, ___brk_addr) |
2cc7dc4d | 39 | |
28f540f4 RM |
40 | struct mutex _hurd_brk_lock; |
41 | ||
42 | extern int __data_start, _end; | |
c6496762 RM |
43 | weak_extern (__data_start) |
44 | static vm_address_t static_data_start; | |
28f540f4 RM |
45 | |
46 | ||
47 | /* Set the end of the process's data space to INADDR. | |
48 | Return 0 if successful, -1 if not. */ | |
49 | int | |
ebbad4cc | 50 | __brk (void *inaddr) |
28f540f4 RM |
51 | { |
52 | int ret; | |
53 | HURD_CRITICAL_BEGIN; | |
54 | __mutex_lock (&_hurd_brk_lock); | |
55 | ret = _hurd_set_brk ((vm_address_t) inaddr); | |
56 | __mutex_unlock (&_hurd_brk_lock); | |
57 | HURD_CRITICAL_END; | |
58 | return ret; | |
59 | } | |
60 | weak_alias (__brk, brk) | |
61 | ||
62 | ||
63 | int | |
64 | _hurd_set_brk (vm_address_t addr) | |
65 | { | |
1043890b | 66 | error_t err = 0; |
28f540f4 RM |
67 | vm_address_t pagend = round_page (addr); |
68 | vm_address_t pagebrk = round_page (_hurd_brk); | |
69 | long int rlimit; | |
70 | ||
71 | if (pagend <= pagebrk) | |
72 | { | |
73 | if (pagend < pagebrk) | |
55ffcab7 RM |
74 | { |
75 | /* XXX wish this were atomic... */ | |
76 | /* First deallocate the memory to release its backing space. */ | |
77 | __vm_deallocate (__mach_task_self (), pagend, pagebrk - pagend); | |
78 | /* Now reallocate it with no access allowed. */ | |
79 | err = __vm_map (__mach_task_self (), | |
6abc15e9 | 80 | &pagend, pagebrk - pagend, |
55ffcab7 RM |
81 | 0, 0, MACH_PORT_NULL, 0, 0, |
82 | 0, VM_PROT_READ|VM_PROT_WRITE|VM_PROT_EXECUTE, | |
83 | VM_INHERIT_COPY); | |
84 | /* XXX what if error? */ | |
85 | } | |
28f540f4 RM |
86 | _hurd_brk = addr; |
87 | return 0; | |
88 | } | |
89 | ||
90 | __mutex_lock (&_hurd_rlimit_lock); | |
91 | rlimit = _hurd_rlimits[RLIMIT_DATA].rlim_cur; | |
92 | __mutex_unlock (&_hurd_rlimit_lock); | |
93 | ||
c6496762 | 94 | if (addr - static_data_start > rlimit) |
28f540f4 RM |
95 | { |
96 | /* Need to increase the resource limit. */ | |
97 | errno = ENOMEM; | |
98 | return -1; | |
99 | } | |
100 | ||
683158e0 | 101 | if (pagend > _hurd_data_end) |
28f540f4 | 102 | { |
1043890b ST |
103 | vm_address_t alloc_start = _hurd_data_end; |
104 | ||
683158e0 | 105 | /* We didn't allocate enough space! Hopefully we can get some more! */ |
1043890b ST |
106 | |
107 | if (_hurd_data_end > pagebrk) | |
108 | /* First finish allocation. */ | |
109 | err = __vm_protect (__mach_task_self (), pagebrk, | |
110 | alloc_start - pagebrk, 0, | |
111 | VM_PROT_READ|VM_PROT_WRITE|VM_PROT_EXECUTE); | |
112 | if (! err) | |
113 | _hurd_brk = alloc_start; | |
114 | ||
115 | if (! err) | |
116 | err = __vm_allocate (__mach_task_self (), &alloc_start, | |
117 | pagend - alloc_start, 0); | |
118 | ||
683158e0 RM |
119 | if (! err) |
120 | _hurd_data_end = pagend; | |
28f540f4 | 121 | } |
683158e0 RM |
122 | else |
123 | /* Make the memory accessible. */ | |
124 | err = __vm_protect (__mach_task_self (), pagebrk, pagend - pagebrk, | |
125 | 0, VM_PROT_READ|VM_PROT_WRITE|VM_PROT_EXECUTE); | |
126 | ||
127 | if (err) | |
128 | return __hurd_fail (err); | |
28f540f4 RM |
129 | |
130 | _hurd_brk = addr; | |
131 | return 0; | |
132 | } | |
133 | ||
134 | static void | |
135 | init_brk (void) | |
136 | { | |
137 | vm_address_t pagend; | |
138 | ||
139 | __mutex_init (&_hurd_brk_lock); | |
140 | ||
c6496762 RM |
141 | static_data_start = (vm_address_t) (&__data_start ?: &_end); |
142 | ||
28f540f4 RM |
143 | /* If _hurd_brk is already set, don't change it. The assumption is that |
144 | it was set in a previous run before something like Emacs's unexec was | |
145 | called and dumped all the data up to the break at that point. */ | |
146 | if (_hurd_brk == 0) | |
147 | _hurd_brk = (vm_address_t) &_end; | |
148 | ||
149 | pagend = round_page (_hurd_brk); | |
150 | ||
c6496762 | 151 | _hurd_data_end = round_page (static_data_start + DATA_SIZE); |
28f540f4 RM |
152 | |
153 | if (pagend < _hurd_data_end) | |
154 | { | |
155 | /* We use vm_map to allocate and change permissions atomically. */ | |
156 | if (__vm_map (__mach_task_self (), &pagend, _hurd_data_end - pagend, | |
157 | 0, 0, MACH_PORT_NULL, 0, 0, | |
158 | 0, VM_PROT_READ|VM_PROT_WRITE|VM_PROT_EXECUTE, | |
159 | VM_INHERIT_COPY)) | |
160 | /* Couldn't allocate the memory. The break will be very short. */ | |
161 | _hurd_data_end = pagend; | |
162 | } | |
163 | ||
164 | (void) &init_brk; /* Avoid ``defined but not used'' warning. */ | |
165 | } | |
166 | text_set_element (_hurd_preinit_hook, init_brk); |