1 /* 2 * linux/arch/s390/mm/mmap.c 3 * 4 * flexible mmap layout support 5 * 6 * Copyright 2003-2004 Red Hat Inc., Durham, North Carolina. 7 * All Rights Reserved. 8 * 9 * This program is free software; you can redistribute it and/or modify 10 * it under the terms of the GNU General Public License as published by 11 * the Free Software Foundation; either version 2 of the License, or 12 * (at your option) any later version. 13 * 14 * This program is distributed in the hope that it will be useful, 15 * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 * GNU General Public License for more details. 18 * 19 * You should have received a copy of the GNU General Public License 20 * along with this program; if not, write to the Free Software 21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 22 * 23 * 24 * Started by Ingo Molnar <mingo@elte.hu> 25 */ 26 27 #include <linux/personality.h> 28 #include <linux/mm.h> 29 #include <linux/module.h> 30 #include <asm/pgalloc.h> 31 #include <asm/compat.h> 32 33 static unsigned long stack_maxrandom_size(void) 34 { 35 if (!(current->flags & PF_RANDOMIZE)) 36 return 0; 37 if (current->personality & ADDR_NO_RANDOMIZE) 38 return 0; 39 return STACK_RND_MASK << PAGE_SHIFT; 40 } 41 42 /* 43 * Top of mmap area (just below the process stack). 44 * 45 * Leave at least a ~32 MB hole. 46 */ 47 #define MIN_GAP (32*1024*1024) 48 #define MAX_GAP (STACK_TOP/6*5) 49 50 static inline unsigned long mmap_base(void) 51 { 52 unsigned long gap = rlimit(RLIMIT_STACK); 53 54 if (gap < MIN_GAP) 55 gap = MIN_GAP; 56 else if (gap > MAX_GAP) 57 gap = MAX_GAP; 58 59 return STACK_TOP - stack_maxrandom_size() - (gap & PAGE_MASK); 60 } 61 62 static inline int mmap_is_legacy(void) 63 { 64 if (current->personality & ADDR_COMPAT_LAYOUT) 65 return 1; 66 if (rlimit(RLIMIT_STACK) == RLIM_INFINITY) 67 return 1; 68 return sysctl_legacy_va_layout; 69 } 70 71 #ifndef CONFIG_64BIT 72 73 /* 74 * This function, called very early during the creation of a new 75 * process VM image, sets up which VM layout function to use: 76 */ 77 void arch_pick_mmap_layout(struct mm_struct *mm) 78 { 79 /* 80 * Fall back to the standard layout if the personality 81 * bit is set, or if the expected stack growth is unlimited: 82 */ 83 if (mmap_is_legacy()) { 84 mm->mmap_base = TASK_UNMAPPED_BASE; 85 mm->get_unmapped_area = arch_get_unmapped_area; 86 mm->unmap_area = arch_unmap_area; 87 } else { 88 mm->mmap_base = mmap_base(); 89 mm->get_unmapped_area = arch_get_unmapped_area_topdown; 90 mm->unmap_area = arch_unmap_area_topdown; 91 } 92 } 93 EXPORT_SYMBOL_GPL(arch_pick_mmap_layout); 94 95 #else 96 97 int s390_mmap_check(unsigned long addr, unsigned long len) 98 { 99 if (!is_compat_task() && 100 len >= TASK_SIZE && TASK_SIZE < (1UL << 53)) 101 return crst_table_upgrade(current->mm, 1UL << 53); 102 return 0; 103 } 104 105 static unsigned long 106 s390_get_unmapped_area(struct file *filp, unsigned long addr, 107 unsigned long len, unsigned long pgoff, unsigned long flags) 108 { 109 struct mm_struct *mm = current->mm; 110 unsigned long area; 111 int rc; 112 113 area = arch_get_unmapped_area(filp, addr, len, pgoff, flags); 114 if (!(area & ~PAGE_MASK)) 115 return area; 116 if (area == -ENOMEM && !is_compat_task() && TASK_SIZE < (1UL << 53)) { 117 /* Upgrade the page table to 4 levels and retry. */ 118 rc = crst_table_upgrade(mm, 1UL << 53); 119 if (rc) 120 return (unsigned long) rc; 121 area = arch_get_unmapped_area(filp, addr, len, pgoff, flags); 122 } 123 return area; 124 } 125 126 static unsigned long 127 s390_get_unmapped_area_topdown(struct file *filp, const unsigned long addr, 128 const unsigned long len, const unsigned long pgoff, 129 const unsigned long flags) 130 { 131 struct mm_struct *mm = current->mm; 132 unsigned long area; 133 int rc; 134 135 area = arch_get_unmapped_area_topdown(filp, addr, len, pgoff, flags); 136 if (!(area & ~PAGE_MASK)) 137 return area; 138 if (area == -ENOMEM && !is_compat_task() && TASK_SIZE < (1UL << 53)) { 139 /* Upgrade the page table to 4 levels and retry. */ 140 rc = crst_table_upgrade(mm, 1UL << 53); 141 if (rc) 142 return (unsigned long) rc; 143 area = arch_get_unmapped_area_topdown(filp, addr, len, 144 pgoff, flags); 145 } 146 return area; 147 } 148 /* 149 * This function, called very early during the creation of a new 150 * process VM image, sets up which VM layout function to use: 151 */ 152 void arch_pick_mmap_layout(struct mm_struct *mm) 153 { 154 /* 155 * Fall back to the standard layout if the personality 156 * bit is set, or if the expected stack growth is unlimited: 157 */ 158 if (mmap_is_legacy()) { 159 mm->mmap_base = TASK_UNMAPPED_BASE; 160 mm->get_unmapped_area = s390_get_unmapped_area; 161 mm->unmap_area = arch_unmap_area; 162 } else { 163 mm->mmap_base = mmap_base(); 164 mm->get_unmapped_area = s390_get_unmapped_area_topdown; 165 mm->unmap_area = arch_unmap_area_topdown; 166 } 167 } 168 EXPORT_SYMBOL_GPL(arch_pick_mmap_layout); 169 170 #endif 171