xref: /openbmc/linux/arch/mips/mm/mmap.c (revision 7fe2f639)
1 /*
2  * This file is subject to the terms and conditions of the GNU General Public
3  * License.  See the file "COPYING" in the main directory of this archive
4  * for more details.
5  *
6  * Copyright (C) 2011 Wind River Systems,
7  *   written by Ralf Baechle <ralf@linux-mips.org>
8  */
9 #include <linux/errno.h>
10 #include <linux/mm.h>
11 #include <linux/mman.h>
12 #include <linux/module.h>
13 #include <linux/random.h>
14 #include <linux/sched.h>
15 
16 unsigned long shm_align_mask = PAGE_SIZE - 1;	/* Sane caches */
17 
18 EXPORT_SYMBOL(shm_align_mask);
19 
20 #define COLOUR_ALIGN(addr,pgoff)				\
21 	((((addr) + shm_align_mask) & ~shm_align_mask) +	\
22 	 (((pgoff) << PAGE_SHIFT) & shm_align_mask))
23 
24 unsigned long arch_get_unmapped_area(struct file *filp, unsigned long addr,
25 	unsigned long len, unsigned long pgoff, unsigned long flags)
26 {
27 	struct vm_area_struct * vmm;
28 	int do_color_align;
29 
30 	if (len > TASK_SIZE)
31 		return -ENOMEM;
32 
33 	if (flags & MAP_FIXED) {
34 		/* Even MAP_FIXED mappings must reside within TASK_SIZE.  */
35 		if (TASK_SIZE - len < addr)
36 			return -EINVAL;
37 
38 		/*
39 		 * We do not accept a shared mapping if it would violate
40 		 * cache aliasing constraints.
41 		 */
42 		if ((flags & MAP_SHARED) &&
43 		    ((addr - (pgoff << PAGE_SHIFT)) & shm_align_mask))
44 			return -EINVAL;
45 		return addr;
46 	}
47 
48 	do_color_align = 0;
49 	if (filp || (flags & MAP_SHARED))
50 		do_color_align = 1;
51 	if (addr) {
52 		if (do_color_align)
53 			addr = COLOUR_ALIGN(addr, pgoff);
54 		else
55 			addr = PAGE_ALIGN(addr);
56 		vmm = find_vma(current->mm, addr);
57 		if (TASK_SIZE - len >= addr &&
58 		    (!vmm || addr + len <= vmm->vm_start))
59 			return addr;
60 	}
61 	addr = current->mm->mmap_base;
62 	if (do_color_align)
63 		addr = COLOUR_ALIGN(addr, pgoff);
64 	else
65 		addr = PAGE_ALIGN(addr);
66 
67 	for (vmm = find_vma(current->mm, addr); ; vmm = vmm->vm_next) {
68 		/* At this point:  (!vmm || addr < vmm->vm_end). */
69 		if (TASK_SIZE - len < addr)
70 			return -ENOMEM;
71 		if (!vmm || addr + len <= vmm->vm_start)
72 			return addr;
73 		addr = vmm->vm_end;
74 		if (do_color_align)
75 			addr = COLOUR_ALIGN(addr, pgoff);
76 	}
77 }
78 
79 void arch_pick_mmap_layout(struct mm_struct *mm)
80 {
81 	unsigned long random_factor = 0UL;
82 
83 	if (current->flags & PF_RANDOMIZE) {
84 		random_factor = get_random_int();
85 		random_factor = random_factor << PAGE_SHIFT;
86 		if (TASK_IS_32BIT_ADDR)
87 			random_factor &= 0xfffffful;
88 		else
89 			random_factor &= 0xffffffful;
90 	}
91 
92 	mm->mmap_base = TASK_UNMAPPED_BASE + random_factor;
93 	mm->get_unmapped_area = arch_get_unmapped_area;
94 	mm->unmap_area = arch_unmap_area;
95 }
96 
97 static inline unsigned long brk_rnd(void)
98 {
99 	unsigned long rnd = get_random_int();
100 
101 	rnd = rnd << PAGE_SHIFT;
102 	/* 8MB for 32bit, 256MB for 64bit */
103 	if (TASK_IS_32BIT_ADDR)
104 		rnd = rnd & 0x7ffffful;
105 	else
106 		rnd = rnd & 0xffffffful;
107 
108 	return rnd;
109 }
110 
111 unsigned long arch_randomize_brk(struct mm_struct *mm)
112 {
113 	unsigned long base = mm->brk;
114 	unsigned long ret;
115 
116 	ret = PAGE_ALIGN(base + brk_rnd());
117 
118 	if (ret < mm->brk)
119 		return mm->brk;
120 
121 	return ret;
122 }
123