aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHelge Deller <deller@gmx.de>2014-01-31 16:19:52 -0500
committerHelge Deller <deller@gmx.de>2014-02-02 15:00:13 -0500
commit9dabf60dc4abe6e06bebcc2ee46b4d76ec8741f2 (patch)
tree93b98d806b1941b91ac3de04b7bd730103d3fab8
parentf5a408d53edef3af07ac7697b8bc54a755628450 (diff)
parisc: add flexible mmap memory layout support
Add support for the flexible mmap memory layout (as described in http://lwn.net/Articles/91829). This is especially very interesting on parisc since we currently only support 32bit userspace (even with a 64bit Linux kernel). Signed-off-by: Helge Deller <deller@gmx.de>
-rw-r--r--arch/parisc/include/asm/elf.h4
-rw-r--r--arch/parisc/include/asm/pgtable.h1
-rw-r--r--arch/parisc/include/asm/processor.h2
-rw-r--r--arch/parisc/include/asm/thread_info.h10
-rw-r--r--arch/parisc/kernel/process.c21
-rw-r--r--arch/parisc/kernel/sys_parisc.c238
6 files changed, 233 insertions, 43 deletions
diff --git a/arch/parisc/include/asm/elf.h b/arch/parisc/include/asm/elf.h
index ad2b50397894..3391d061eccc 100644
--- a/arch/parisc/include/asm/elf.h
+++ b/arch/parisc/include/asm/elf.h
@@ -348,4 +348,8 @@ struct pt_regs; /* forward declaration... */
348 348
349#define ELF_HWCAP 0 349#define ELF_HWCAP 0
350 350
351struct mm_struct;
352extern unsigned long arch_randomize_brk(struct mm_struct *);
353#define arch_randomize_brk arch_randomize_brk
354
351#endif 355#endif
diff --git a/arch/parisc/include/asm/pgtable.h b/arch/parisc/include/asm/pgtable.h
index 34899b5d959a..22b89d1edba7 100644
--- a/arch/parisc/include/asm/pgtable.h
+++ b/arch/parisc/include/asm/pgtable.h
@@ -511,6 +511,7 @@ static inline void ptep_set_wrprotect(struct mm_struct *mm, unsigned long addr,
511/* We provide our own get_unmapped_area to provide cache coherency */ 511/* We provide our own get_unmapped_area to provide cache coherency */
512 512
513#define HAVE_ARCH_UNMAPPED_AREA 513#define HAVE_ARCH_UNMAPPED_AREA
514#define HAVE_ARCH_UNMAPPED_AREA_TOPDOWN
514 515
515#define __HAVE_ARCH_PTEP_TEST_AND_CLEAR_YOUNG 516#define __HAVE_ARCH_PTEP_TEST_AND_CLEAR_YOUNG
516#define __HAVE_ARCH_PTEP_GET_AND_CLEAR 517#define __HAVE_ARCH_PTEP_GET_AND_CLEAR
diff --git a/arch/parisc/include/asm/processor.h b/arch/parisc/include/asm/processor.h
index cc2290a3cace..198a86feb574 100644
--- a/arch/parisc/include/asm/processor.h
+++ b/arch/parisc/include/asm/processor.h
@@ -30,6 +30,8 @@
30#endif 30#endif
31#define current_text_addr() ({ void *pc; current_ia(pc); pc; }) 31#define current_text_addr() ({ void *pc; current_ia(pc); pc; })
32 32
33#define HAVE_ARCH_PICK_MMAP_LAYOUT
34
33#define TASK_SIZE_OF(tsk) ((tsk)->thread.task_size) 35#define TASK_SIZE_OF(tsk) ((tsk)->thread.task_size)
34#define TASK_SIZE TASK_SIZE_OF(current) 36#define TASK_SIZE TASK_SIZE_OF(current)
35#define TASK_UNMAPPED_BASE (current->thread.map_base) 37#define TASK_UNMAPPED_BASE (current->thread.map_base)
diff --git a/arch/parisc/include/asm/thread_info.h b/arch/parisc/include/asm/thread_info.h
index d5f97ea3a4e1..4b9b10ce1f9d 100644
--- a/arch/parisc/include/asm/thread_info.h
+++ b/arch/parisc/include/asm/thread_info.h
@@ -76,6 +76,16 @@ struct thread_info {
76#define _TIF_SYSCALL_TRACE_MASK (_TIF_SYSCALL_TRACE | _TIF_SINGLESTEP | \ 76#define _TIF_SYSCALL_TRACE_MASK (_TIF_SYSCALL_TRACE | _TIF_SINGLESTEP | \
77 _TIF_BLOCKSTEP | _TIF_SYSCALL_AUDIT) 77 _TIF_BLOCKSTEP | _TIF_SYSCALL_AUDIT)
78 78
79#ifdef CONFIG_64BIT
80# ifdef CONFIG_COMPAT
81# define is_32bit_task() (test_thread_flag(TIF_32BIT))
82# else
83# define is_32bit_task() (0)
84# endif
85#else
86# define is_32bit_task() (1)
87#endif
88
79#endif /* __KERNEL__ */ 89#endif /* __KERNEL__ */
80 90
81#endif /* _ASM_PARISC_THREAD_INFO_H */ 91#endif /* _ASM_PARISC_THREAD_INFO_H */
diff --git a/arch/parisc/kernel/process.c b/arch/parisc/kernel/process.c
index 55f92b614182..0bbbf0d3f608 100644
--- a/arch/parisc/kernel/process.c
+++ b/arch/parisc/kernel/process.c
@@ -13,7 +13,7 @@
13 * Copyright (C) 2000 Grant Grundler <grundler with parisc-linux.org> 13 * Copyright (C) 2000 Grant Grundler <grundler with parisc-linux.org>
14 * Copyright (C) 2001 Alan Modra <amodra at parisc-linux.org> 14 * Copyright (C) 2001 Alan Modra <amodra at parisc-linux.org>
15 * Copyright (C) 2001-2002 Ryan Bradetich <rbrad at parisc-linux.org> 15 * Copyright (C) 2001-2002 Ryan Bradetich <rbrad at parisc-linux.org>
16 * Copyright (C) 2001-2007 Helge Deller <deller at parisc-linux.org> 16 * Copyright (C) 2001-2014 Helge Deller <deller@gmx.de>
17 * Copyright (C) 2002 Randolph Chung <tausq with parisc-linux.org> 17 * Copyright (C) 2002 Randolph Chung <tausq with parisc-linux.org>
18 * 18 *
19 * 19 *
@@ -49,6 +49,7 @@
49#include <linux/kallsyms.h> 49#include <linux/kallsyms.h>
50#include <linux/uaccess.h> 50#include <linux/uaccess.h>
51#include <linux/rcupdate.h> 51#include <linux/rcupdate.h>
52#include <linux/random.h>
52 53
53#include <asm/io.h> 54#include <asm/io.h>
54#include <asm/asm-offsets.h> 55#include <asm/asm-offsets.h>
@@ -286,3 +287,21 @@ void *dereference_function_descriptor(void *ptr)
286 return ptr; 287 return ptr;
287} 288}
288#endif 289#endif
290
291static inline unsigned long brk_rnd(void)
292{
293 /* 8MB for 32bit, 1GB for 64bit */
294 if (is_32bit_task())
295 return (get_random_int() & 0x7ffUL) << PAGE_SHIFT;
296 else
297 return (get_random_int() & 0x3ffffUL) << PAGE_SHIFT;
298}
299
300unsigned long arch_randomize_brk(struct mm_struct *mm)
301{
302 unsigned long ret = PAGE_ALIGN(mm->brk + brk_rnd());
303
304 if (ret < mm->brk)
305 return mm->brk;
306 return ret;
307}
diff --git a/arch/parisc/kernel/sys_parisc.c b/arch/parisc/kernel/sys_parisc.c
index 0d3a9d4927b5..b7cadc4a06cd 100644
--- a/arch/parisc/kernel/sys_parisc.c
+++ b/arch/parisc/kernel/sys_parisc.c
@@ -5,6 +5,7 @@
5 * Copyright (C) 1999-2003 Matthew Wilcox <willy at parisc-linux.org> 5 * Copyright (C) 1999-2003 Matthew Wilcox <willy at parisc-linux.org>
6 * Copyright (C) 2000-2003 Paul Bame <bame at parisc-linux.org> 6 * Copyright (C) 2000-2003 Paul Bame <bame at parisc-linux.org>
7 * Copyright (C) 2001 Thomas Bogendoerfer <tsbogend at parisc-linux.org> 7 * Copyright (C) 2001 Thomas Bogendoerfer <tsbogend at parisc-linux.org>
8 * Copyright (C) 1999-2014 Helge Deller <deller@gmx.de>
8 * 9 *
9 * 10 *
10 * This program is free software; you can redistribute it and/or modify 11 * This program is free software; you can redistribute it and/or modify
@@ -23,6 +24,7 @@
23 */ 24 */
24 25
25#include <asm/uaccess.h> 26#include <asm/uaccess.h>
27#include <asm/elf.h>
26#include <linux/file.h> 28#include <linux/file.h>
27#include <linux/fs.h> 29#include <linux/fs.h>
28#include <linux/linkage.h> 30#include <linux/linkage.h>
@@ -32,78 +34,230 @@
32#include <linux/syscalls.h> 34#include <linux/syscalls.h>
33#include <linux/utsname.h> 35#include <linux/utsname.h>
34#include <linux/personality.h> 36#include <linux/personality.h>
37#include <linux/random.h>
35 38
36static unsigned long get_unshared_area(unsigned long addr, unsigned long len) 39/* we construct an artificial offset for the mapping based on the physical
40 * address of the kernel mapping variable */
41#define GET_LAST_MMAP(filp) \
42 (filp ? ((unsigned long) filp->f_mapping) >> 8 : 0UL)
43#define SET_LAST_MMAP(filp, val) \
44 { /* nothing */ }
45
46static int get_offset(unsigned int last_mmap)
37{ 47{
38 struct vm_unmapped_area_info info; 48 return (last_mmap & (SHMLBA-1)) >> PAGE_SHIFT;
49}
39 50
40 info.flags = 0; 51static unsigned long shared_align_offset(unsigned int last_mmap,
41 info.length = len; 52 unsigned long pgoff)
42 info.low_limit = PAGE_ALIGN(addr); 53{
43 info.high_limit = TASK_SIZE; 54 return (get_offset(last_mmap) + pgoff) << PAGE_SHIFT;
44 info.align_mask = 0;
45 info.align_offset = 0;
46 return vm_unmapped_area(&info);
47} 55}
48 56
49/* 57static inline unsigned long COLOR_ALIGN(unsigned long addr,
50 * We need to know the offset to use. Old scheme was to look for 58 unsigned int last_mmap, unsigned long pgoff)
51 * existing mapping and use the same offset. New scheme is to use the
52 * address of the kernel data structure as the seed for the offset.
53 * We'll see how that works...
54 *
55 * The mapping is cacheline aligned, so there's no information in the bottom
56 * few bits of the address. We're looking for 10 bits (4MB / 4k), so let's
57 * drop the bottom 8 bits and use bits 8-17.
58 */
59static int get_offset(struct address_space *mapping)
60{ 59{
61 return (unsigned long) mapping >> 8; 60 unsigned long base = (addr+SHMLBA-1) & ~(SHMLBA-1);
61 unsigned long off = (SHMLBA-1) &
62 (shared_align_offset(last_mmap, pgoff) << PAGE_SHIFT);
63
64 return base + off;