aboutsummaryrefslogtreecommitdiffstats
path: root/arch/sparc64/kernel
diff options
context:
space:
mode:
Diffstat (limited to 'arch/sparc64/kernel')
-rw-r--r--arch/sparc64/kernel/binfmt_aout32.c2
-rw-r--r--arch/sparc64/kernel/sys_sparc.c190
2 files changed, 183 insertions, 9 deletions
diff --git a/arch/sparc64/kernel/binfmt_aout32.c b/arch/sparc64/kernel/binfmt_aout32.c
index cb9ecd0172c0..d7caa60a0074 100644
--- a/arch/sparc64/kernel/binfmt_aout32.c
+++ b/arch/sparc64/kernel/binfmt_aout32.c
@@ -239,6 +239,8 @@ static int load_aout32_binary(struct linux_binprm * bprm, struct pt_regs * regs)
239 (current->mm->start_data = N_DATADDR(ex)); 239 (current->mm->start_data = N_DATADDR(ex));
240 current->mm->brk = ex.a_bss + 240 current->mm->brk = ex.a_bss +
241 (current->mm->start_brk = N_BSSADDR(ex)); 241 (current->mm->start_brk = N_BSSADDR(ex));
242 current->mm->free_area_cache = current->mm->mmap_base;
243 current->mm->cached_hole_size = 0;
242 244
243 current->mm->mmap = NULL; 245 current->mm->mmap = NULL;
244 compute_creds(bprm); 246 compute_creds(bprm);
diff --git a/arch/sparc64/kernel/sys_sparc.c b/arch/sparc64/kernel/sys_sparc.c
index 8840415408be..61dffb9349bd 100644
--- a/arch/sparc64/kernel/sys_sparc.c
+++ b/arch/sparc64/kernel/sys_sparc.c
@@ -82,9 +82,34 @@ static inline int straddles_64bit_va_hole(unsigned long start, unsigned long end
82 return 1; 82 return 1;
83} 83}
84 84
85#define COLOUR_ALIGN(addr,pgoff) \ 85/* These functions differ from the default implementations in
86 ((((addr)+SHMLBA-1)&~(SHMLBA-1)) + \ 86 * mm/mmap.c in two ways:
87 (((pgoff)<<PAGE_SHIFT) & (SHMLBA-1))) 87 *
88 * 1) For file backed MAP_SHARED mmap()'s we D-cache color align,
89 * for fixed such mappings we just validate what the user gave us.
90 * 2) For 64-bit tasks we avoid mapping anything within 4GB of
91 * the spitfire/niagara VA-hole.
92 */
93
94static inline unsigned long COLOUR_ALIGN(unsigned long addr,
95 unsigned long pgoff)
96{
97 unsigned long base = (addr+SHMLBA-1)&~(SHMLBA-1);
98 unsigned long off = (pgoff<<PAGE_SHIFT) & (SHMLBA-1);
99
100 return base + off;
101}
102
103static inline unsigned long COLOUR_ALIGN_DOWN(unsigned long addr,
104 unsigned long pgoff)
105{
106 unsigned long base = addr & ~(SHMLBA-1);
107 unsigned long off = (pgoff<<PAGE_SHIFT) & (SHMLBA-1);
108
109 if (base + off <= addr)
110 return base + off;
111 return base - off;
112}
88 113
89unsigned long arch_get_unmapped_area(struct file *filp, unsigned long addr, unsigned long len, unsigned long pgoff, unsigned long flags) 114unsigned long arch_get_unmapped_area(struct file *filp, unsigned long addr, unsigned long len, unsigned long pgoff, unsigned long flags)
90{ 115{
@@ -106,7 +131,7 @@ unsigned long arch_get_unmapped_area(struct file *filp, unsigned long addr, unsi
106 131
107 if (test_thread_flag(TIF_32BIT)) 132 if (test_thread_flag(TIF_32BIT))
108 task_size = 0xf0000000UL; 133 task_size = 0xf0000000UL;
109 if (len > task_size || len >= VA_EXCLUDE_START) 134 if (unlikely(len > task_size || len >= VA_EXCLUDE_START))
110 return -ENOMEM; 135 return -ENOMEM;
111 136
112 do_color_align = 0; 137 do_color_align = 0;
@@ -125,11 +150,12 @@ unsigned long arch_get_unmapped_area(struct file *filp, unsigned long addr, unsi
125 return addr; 150 return addr;
126 } 151 }
127 152
128 if (len <= mm->cached_hole_size) { 153 if (len > mm->cached_hole_size) {
154 start_addr = addr = mm->free_area_cache;
155 } else {
156 start_addr = addr = TASK_UNMAPPED_BASE;
129 mm->cached_hole_size = 0; 157 mm->cached_hole_size = 0;
130 mm->free_area_cache = TASK_UNMAPPED_BASE;
131 } 158 }
132 start_addr = addr = mm->free_area_cache;
133 159
134 task_size -= len; 160 task_size -= len;
135 161
@@ -146,7 +172,7 @@ full_search:
146 addr = VA_EXCLUDE_END; 172 addr = VA_EXCLUDE_END;
147 vma = find_vma(mm, VA_EXCLUDE_END); 173 vma = find_vma(mm, VA_EXCLUDE_END);
148 } 174 }
149 if (task_size < addr) { 175 if (unlikely(task_size < addr)) {
150 if (start_addr != TASK_UNMAPPED_BASE) { 176 if (start_addr != TASK_UNMAPPED_BASE) {
151 start_addr = addr = TASK_UNMAPPED_BASE; 177 start_addr = addr = TASK_UNMAPPED_BASE;
152 mm->cached_hole_size = 0; 178 mm->cached_hole_size = 0;
@@ -154,7 +180,7 @@ full_search:
154 } 180 }
155 return -ENOMEM; 181 return -ENOMEM;
156 } 182 }
157 if (!vma || addr + len <= vma->vm_start) { 183 if (likely(!vma || addr + len <= vma->vm_start)) {
158 /* 184 /*
159 * Remember the place where we stopped the search: 185 * Remember the place where we stopped the search:
160 */ 186 */
@@ -170,6 +196,121 @@ full_search:
170 } 196 }
171} 197}
172 198
199unsigned long
200arch_get_unmapped_area_topdown(struct file *filp, const unsigned long addr0,
201 const unsigned long len, const unsigned long pgoff,
202 const unsigned long flags)
203{
204 struct vm_area_struct *vma;
205 struct mm_struct *mm = current->mm;
206 unsigned long task_size = 0xf0000000UL;
207 unsigned long addr = addr0;
208 int do_color_align;
209
210 /* This should only ever run for 32-bit processes. */
211 BUG_ON(!test_thread_flag(TIF_32BIT));
212
213 if (flags & MAP_FIXED) {
214 /* We do not accept a shared mapping if it would violate
215 * cache aliasing constraints.
216 */
217 if ((flags & MAP_SHARED) &&
218 ((addr - (pgoff << PAGE_SHIFT)) & (SHMLBA - 1)))
219 return -EINVAL;
220 return addr;
221 }
222
223 if (unlikely(len > task_size))
224 return -ENOMEM;
225
226 do_color_align = 0;
227 if (filp || (flags & MAP_SHARED))
228 do_color_align = 1;
229
230 /* requesting a specific address */
231 if (addr) {
232 if (do_color_align)
233 addr = COLOUR_ALIGN(addr, pgoff);
234 else
235 addr = PAGE_ALIGN(addr);
236
237 vma = find_vma(mm, addr);
238 if (task_size - len >= addr &&
239 (!vma || addr + len <= vma->vm_start))
240 return addr;
241 }
242
243 /* check if free_area_cache is useful for us */
244 if (len <= mm->cached_hole_size) {
245 mm->cached_hole_size = 0;
246 mm->free_area_cache = mm->mmap_base;
247 }
248
249 /* either no address requested or can't fit in requested address hole */
250 addr = mm->free_area_cache;
251 if (do_color_align) {
252 unsigned long base = COLOUR_ALIGN_DOWN(addr-len, pgoff);
253
254 addr = base + len;
255 }
256
257 /* make sure it can fit in the remaining address space */
258 if (likely(addr > len)) {
259 vma = find_vma(mm, addr-len);
260 if (!vma || addr <= vma->vm_start) {
261 /* remember the address as a hint for next time */
262 return (mm->free_area_cache = addr-len);
263 }
264 }
265
266 if (unlikely(mm->mmap_base < len))
267 goto bottomup;
268
269 addr = mm->mmap_base-len;
270 if (do_color_align)
271 addr = COLOUR_ALIGN_DOWN(addr, pgoff);
272
273 do {
274 /*
275 * Lookup failure means no vma is above this address,
276 * else if new region fits below vma->vm_start,
277 * return with success:
278 */
279 vma = find_vma(mm, addr);
280 if (likely(!vma || addr+len <= vma->vm_start)) {
281 /* remember the address as a hint for next time */
282 return (mm->free_area_cache = addr);
283 }
284
285 /* remember the largest hole we saw so far */
286 if (addr + mm->cached_hole_size < vma->vm_start)
287 mm->cached_hole_size = vma->vm_start - addr;
288
289 /* try just below the current vma->vm_start */
290 addr = vma->vm_start-len;
291 if (do_color_align)
292 addr = COLOUR_ALIGN_DOWN(addr, pgoff);
293 } while (likely(len < vma->vm_start));
294
295bottomup:
296 /*
297 * A failed mmap() very likely causes application failure,
298 * so fall back to the bottom-up function here. This scenario
299 * can happen with large stack limits and large mmap()
300 * allocations.
301 */
302 mm->cached_hole_size = ~0UL;
303 mm->free_area_cache = TASK_UNMAPPED_BASE;
304 addr = arch_get_unmapped_area(filp, addr0, len, pgoff, flags);
305 /*
306 * Restore the topdown base:
307 */
308 mm->free_area_cache = mm->mmap_base;
309 mm->cached_hole_size = ~0UL;
310
311 return addr;
312}
313
173/* Try to align mapping such that we align it as much as possible. */ 314/* Try to align mapping such that we align it as much as possible. */
174unsigned long get_fb_unmapped_area(struct file *filp, unsigned long orig_addr, unsigned long len, unsigned long pgoff, unsigned long flags) 315unsigned long get_fb_unmapped_area(struct file *filp, unsigned long orig_addr, unsigned long len, unsigned long pgoff, unsigned long flags)
175{ 316{
@@ -213,6 +354,37 @@ unsigned long get_fb_unmapped_area(struct file *filp, unsigned long orig_addr, u
213 return addr; 354 return addr;
214} 355}
215 356
357/* Essentially the same as PowerPC... */
358void arch_pick_mmap_layout(struct mm_struct *mm)
359{
360 /*
361 * Fall back to the standard layout if the personality
362 * bit is set, or if the expected stack growth is unlimited:
363 */
364 if (!test_thread_flag(TIF_32BIT) ||
365 (current->personality & ADDR_COMPAT_LAYOUT) ||
366 current->signal->rlim[RLIMIT_STACK].rlim_cur == RLIM_INFINITY ||
367 sysctl_legacy_va_layout) {
368 mm->mmap_base = TASK_UNMAPPED_BASE;
369 mm->get_unmapped_area = arch_get_unmapped_area;
370 mm->unmap_area = arch_unmap_area;
371 } else {
372 /* We know it's 32-bit */
373 unsigned long task_size = 0xf0000000UL;
374 unsigned long gap;
375
376 gap = current->signal->rlim[RLIMIT_STACK].rlim_cur;
377 if (gap < 128 * 1024 * 1024)
378 gap = 128 * 1024 * 1024;
379 if (gap > (task_size / 6 * 5))
380 gap = (task_size / 6 * 5);
381
382 mm->mmap_base = task_size - (gap & PAGE_MASK);
383 mm->get_unmapped_area = arch_get_unmapped_area_topdown;
384 mm->unmap_area = arch_unmap_area_topdown;
385 }
386}
387
216asmlinkage unsigned long sparc_brk(unsigned long brk) 388asmlinkage unsigned long sparc_brk(unsigned long brk)
217{ 389{
218 /* People could try to be nasty and use ta 0x6d in 32bit programs */ 390 /* People could try to be nasty and use ta 0x6d in 32bit programs */