diff options
| author | Helge Deller <deller@gmx.de> | 2014-01-31 16:19:52 -0500 |
|---|---|---|
| committer | Helge Deller <deller@gmx.de> | 2014-02-02 15:00:13 -0500 |
| commit | 9dabf60dc4abe6e06bebcc2ee46b4d76ec8741f2 (patch) | |
| tree | 93b98d806b1941b91ac3de04b7bd730103d3fab8 | |
| parent | f5a408d53edef3af07ac7697b8bc54a755628450 (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.h | 4 | ||||
| -rw-r--r-- | arch/parisc/include/asm/pgtable.h | 1 | ||||
| -rw-r--r-- | arch/parisc/include/asm/processor.h | 2 | ||||
| -rw-r--r-- | arch/parisc/include/asm/thread_info.h | 10 | ||||
| -rw-r--r-- | arch/parisc/kernel/process.c | 21 | ||||
| -rw-r--r-- | arch/parisc/kernel/sys_parisc.c | 238 |
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 | ||
| 351 | struct mm_struct; | ||
| 352 | extern 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 | |||
| 291 | static 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 | |||
| 300 | unsigned 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 | ||
| 36 | static 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 | |||
| 46 | static 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; | 51 | static 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 | /* | 57 | static 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 | */ | ||
| 59 | static 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; | ||
