aboutsummaryrefslogtreecommitdiffstats
path: root/arch/sparc64/kernel/sys_sparc.c
diff options
context:
space:
mode:
authorDavid S. Miller <davem@sunset.davemloft.net>2006-03-02 21:12:27 -0500
committerDavid S. Miller <davem@sunset.davemloft.net>2006-03-20 04:14:14 -0500
commit8bcd17411643beb9a601e032d0cf1016909a81d3 (patch)
treefc71e788df4fada768247fa7c12e983d2f6f1a32 /arch/sparc64/kernel/sys_sparc.c
parent45f791eb0f03e760183d30d3f1f18dc2b8e902fe (diff)
[SPARC64]: Do not allow mapping pages within 4GB of 64-bit VA hole.
The UltraSPARC T1 manual recommends this because the chip could instruction prefetch into the VA hole, and this would also make decoding certain kinds of memory access traps more difficult (because the chip sign extends certain pieces of trap state). Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'arch/sparc64/kernel/sys_sparc.c')
-rw-r--r--arch/sparc64/kernel/sys_sparc.c90
1 files changed, 68 insertions, 22 deletions
diff --git a/arch/sparc64/kernel/sys_sparc.c b/arch/sparc64/kernel/sys_sparc.c
index 5f8c822a2b4a..095db723bb8a 100644
--- a/arch/sparc64/kernel/sys_sparc.c
+++ b/arch/sparc64/kernel/sys_sparc.c
@@ -33,14 +33,55 @@
33 33
34/* #define DEBUG_UNIMP_SYSCALL */ 34/* #define DEBUG_UNIMP_SYSCALL */
35 35
36/* XXX Make this per-binary type, this way we can detect the type of
37 * XXX a binary. Every Sparc executable calls this very early on.
38 */
39asmlinkage unsigned long sys_getpagesize(void) 36asmlinkage unsigned long sys_getpagesize(void)
40{ 37{
41 return PAGE_SIZE; 38 return PAGE_SIZE;
42} 39}
43 40
41#define VA_EXCLUDE_START (0x0000080000000000UL - (1UL << 32UL))
42#define VA_EXCLUDE_END (0xfffff80000000000UL + (1UL << 32UL))
43
44/* Does addr --> addr+len fall within 4GB of the VA-space hole or
45 * overflow past the end of the 64-bit address space?
46 */
47static inline int invalid_64bit_range(unsigned long addr, unsigned long len)
48{
49 unsigned long va_exclude_start, va_exclude_end;
50
51 va_exclude_start = VA_EXCLUDE_START;
52 va_exclude_end = VA_EXCLUDE_END;
53
54 if (unlikely(len >= va_exclude_start))
55 return 1;
56
57 if (unlikely((addr + len) < addr))
58 return 1;
59
60 if (unlikely((addr >= va_exclude_start && addr < va_exclude_end) ||
61 ((addr + len) >= va_exclude_start &&
62 (addr + len) < va_exclude_end)))
63 return 1;
64
65 return 0;
66}
67
68/* Does start,end straddle the VA-space hole? */
69static inline int straddles_64bit_va_hole(unsigned long start, unsigned long end)
70{
71 unsigned long va_exclude_start, va_exclude_end;
72
73 va_exclude_start = VA_EXCLUDE_START;
74 va_exclude_end = VA_EXCLUDE_END;
75
76 if (likely(start < va_exclude_start && end < va_exclude_start))
77 return 0;
78
79 if (likely(start >= va_exclude_end && end >= va_exclude_end))
80 return 0;
81
82 return 1;
83}
84
44#define COLOUR_ALIGN(addr,pgoff) \ 85#define COLOUR_ALIGN(addr,pgoff) \
45 ((((addr)+SHMLBA-1)&~(SHMLBA-1)) + \ 86 ((((addr)+SHMLBA-1)&~(SHMLBA-1)) + \
46 (((pgoff)<<PAGE_SHIFT) & (SHMLBA-1))) 87 (((pgoff)<<PAGE_SHIFT) & (SHMLBA-1)))
@@ -65,7 +106,7 @@ unsigned long arch_get_unmapped_area(struct file *filp, unsigned long addr, unsi
65 106
66 if (test_thread_flag(TIF_32BIT)) 107 if (test_thread_flag(TIF_32BIT))
67 task_size = 0xf0000000UL; 108 task_size = 0xf0000000UL;
68 if (len > task_size || len > -PAGE_OFFSET) 109 if (len > task_size || len >= VA_EXCLUDE_START)
69 return -ENOMEM; 110 return -ENOMEM;
70 111
71 do_color_align = 0; 112 do_color_align = 0;
@@ -100,9 +141,10 @@ full_search:
100 141
101 for (vma = find_vma(mm, addr); ; vma = vma->vm_next) { 142 for (vma = find_vma(mm, addr); ; vma = vma->vm_next) {
102 /* At this point: (!vma || addr < vma->vm_end). */ 143 /* At this point: (!vma || addr < vma->vm_end). */
103 if (addr < PAGE_OFFSET && -PAGE_OFFSET - len < addr) { 144 if (addr < VA_EXCLUDE_START &&
104 addr = PAGE_OFFSET; 145 (addr + len) >= VA_EXCLUDE_START) {
105 vma = find_vma(mm, PAGE_OFFSET); 146 addr = VA_EXCLUDE_END;
147 vma = find_vma(mm, VA_EXCLUDE_END);
106 } 148 }
107 if (task_size < addr) { 149 if (task_size < addr) {
108 if (start_addr != TASK_UNMAPPED_BASE) { 150 if (start_addr != TASK_UNMAPPED_BASE) {
@@ -174,12 +216,12 @@ unsigned long get_fb_unmapped_area(struct file *filp, unsigned long orig_addr, u
174asmlinkage unsigned long sparc_brk(unsigned long brk) 216asmlinkage unsigned long sparc_brk(unsigned long brk)
175{ 217{
176 /* People could try to be nasty and use ta 0x6d in 32bit programs */ 218 /* People could try to be nasty and use ta 0x6d in 32bit programs */
177 if (test_thread_flag(TIF_32BIT) && 219 if (test_thread_flag(TIF_32BIT) && brk >= 0xf0000000UL)
178 brk >= 0xf0000000UL)
179 return current->mm->brk; 220 return current->mm->brk;
180 221
181 if ((current->mm->brk & PAGE_OFFSET) != (brk & PAGE_OFFSET)) 222 if (unlikely(straddles_64bit_va_hole(current->mm->brk, brk)))
182 return current->mm->brk; 223 return current->mm->brk;
224
183 return sys_brk(brk); 225 return sys_brk(brk);
184} 226}
185 227
@@ -340,13 +382,16 @@ asmlinkage unsigned long sys_mmap(unsigned long addr, unsigned long len,
340 retval = -EINVAL; 382 retval = -EINVAL;
341 383
342 if (test_thread_flag(TIF_32BIT)) { 384 if (test_thread_flag(TIF_32BIT)) {
343 if (len > 0xf0000000UL || 385 if (len >= 0xf0000000UL)
344 ((flags & MAP_FIXED) && addr > 0xf0000000UL - len)) 386 goto out_putf;
387
388 if ((flags & MAP_FIXED) && addr > 0xf0000000UL - len)
345 goto out_putf; 389 goto out_putf;
346 } else { 390 } else {
347 if (len > -PAGE_OFFSET || 391 if (len >= VA_EXCLUDE_START)
348 ((flags & MAP_FIXED) && 392 goto out_putf;
349 addr < PAGE_OFFSET && addr + len > -PAGE_OFFSET)) 393
394 if ((flags & MAP_FIXED) && invalid_64bit_range(addr, len))
350 goto out_putf; 395 goto out_putf;
351 } 396 }
352 397
@@ -365,9 +410,9 @@ asmlinkage long sys64_munmap(unsigned long addr, size_t len)
365{ 410{
366 long ret; 411 long ret;
367 412
368 if (len > -PAGE_OFFSET || 413 if (invalid_64bit_range(addr, len))
369 (addr < PAGE_OFFSET && addr + len > -PAGE_OFFSET))
370 return -EINVAL; 414 return -EINVAL;
415
371 down_write(&current->mm->mmap_sem); 416 down_write(&current->mm->mmap_sem);
372 ret = do_munmap(current->mm, addr, len); 417 ret = do_munmap(current->mm, addr, len);
373 up_write(&current->mm->mmap_sem); 418 up_write(&current->mm->mmap_sem);
@@ -384,18 +429,19 @@ asmlinkage unsigned long sys64_mremap(unsigned long addr,
384{ 429{
385 struct vm_area_struct *vma; 430 struct vm_area_struct *vma;
386 unsigned long ret = -EINVAL; 431 unsigned long ret = -EINVAL;
432
387 if (test_thread_flag(TIF_32BIT)) 433 if (test_thread_flag(TIF_32BIT))
388 goto out; 434 goto out;
389 if (old_len > -PAGE_OFFSET || new_len > -PAGE_OFFSET) 435 if (unlikely(new_len >= VA_EXCLUDE_START))
390 goto out; 436 goto out;
391 if (addr < PAGE_OFFSET && addr + old_len > -PAGE_OFFSET) 437 if (unlikely(invalid_64bit_range(addr, old_len)))
392 goto out; 438 goto out;
439
393 down_write(&current->mm->mmap_sem); 440 down_write(&current->mm->mmap_sem);
394 if (flags & MREMAP_FIXED) { 441 if (flags & MREMAP_FIXED) {
395 if (new_addr < PAGE_OFFSET && 442 if (invalid_64bit_range(new_addr, new_len))
396 new_addr + new_len > -PAGE_OFFSET)
397 goto out_sem; 443 goto out_sem;
398 } else if (addr < PAGE_OFFSET && addr + new_len > -PAGE_OFFSET) { 444 } else if (invalid_64bit_range(addr, new_len)) {
399 unsigned long map_flags = 0; 445 unsigned long map_flags = 0;
400 struct file *file = NULL; 446 struct file *file = NULL;
401 447