1 // SPDX-License-Identifier: GPL-2.0
3 * linux/arch/arm/mm/mmap.c
7 #include <linux/mman.h>
9 #include <linux/sched/signal.h>
10 #include <linux/sched/mm.h>
12 #include <linux/personality.h>
13 #include <linux/random.h>
14 #include <asm/cachetype.h>
16 #define COLOUR_ALIGN(addr,pgoff) \
17 ((((addr)+SHMLBA-1)&~(SHMLBA-1)) + \
18 (((pgoff)<<PAGE_SHIFT) & (SHMLBA-1)))
21 * We need to ensure that shared mappings are correctly aligned to
22 * avoid aliasing issues with VIPT caches. We need to ensure that
23 * a specific page of an object is always mapped at a multiple of
26 * We unconditionally provide this function for all cases, however
27 * in the VIVT case, we optimise out the alignment rules.
30 arch_get_unmapped_area(struct file
*filp
, unsigned long addr
,
31 unsigned long len
, unsigned long pgoff
, unsigned long flags
)
33 struct mm_struct
*mm
= current
->mm
;
34 struct vm_area_struct
*vma
;
36 int aliasing
= cache_is_vipt_aliasing();
37 struct vm_unmapped_area_info info
;
40 * We only need to do colour alignment if either the I or D
44 do_align
= filp
|| (flags
& MAP_SHARED
);
47 * We enforce the MAP_FIXED case.
49 if (flags
& MAP_FIXED
) {
50 if (aliasing
&& flags
& MAP_SHARED
&&
51 (addr
- (pgoff
<< PAGE_SHIFT
)) & (SHMLBA
- 1))
61 addr
= COLOUR_ALIGN(addr
, pgoff
);
63 addr
= PAGE_ALIGN(addr
);
65 vma
= find_vma(mm
, addr
);
66 if (TASK_SIZE
- len
>= addr
&&
67 (!vma
|| addr
+ len
<= vm_start_gap(vma
)))
73 info
.low_limit
= mm
->mmap_base
;
74 info
.high_limit
= TASK_SIZE
;
75 info
.align_mask
= do_align
? (PAGE_MASK
& (SHMLBA
- 1)) : 0;
76 info
.align_offset
= pgoff
<< PAGE_SHIFT
;
77 return vm_unmapped_area(&info
);
81 arch_get_unmapped_area_topdown(struct file
*filp
, const unsigned long addr0
,
82 const unsigned long len
, const unsigned long pgoff
,
83 const unsigned long flags
)
85 struct vm_area_struct
*vma
;
86 struct mm_struct
*mm
= current
->mm
;
87 unsigned long addr
= addr0
;
89 int aliasing
= cache_is_vipt_aliasing();
90 struct vm_unmapped_area_info info
;
93 * We only need to do colour alignment if either the I or D
97 do_align
= filp
|| (flags
& MAP_SHARED
);
99 /* requested length too big for entire address space */
103 if (flags
& MAP_FIXED
) {
104 if (aliasing
&& flags
& MAP_SHARED
&&
105 (addr
- (pgoff
<< PAGE_SHIFT
)) & (SHMLBA
- 1))
110 /* requesting a specific address */
113 addr
= COLOUR_ALIGN(addr
, pgoff
);
115 addr
= PAGE_ALIGN(addr
);
116 vma
= find_vma(mm
, addr
);
117 if (TASK_SIZE
- len
>= addr
&&
118 (!vma
|| addr
+ len
<= vm_start_gap(vma
)))
122 info
.flags
= VM_UNMAPPED_AREA_TOPDOWN
;
124 info
.low_limit
= FIRST_USER_ADDRESS
;
125 info
.high_limit
= mm
->mmap_base
;
126 info
.align_mask
= do_align
? (PAGE_MASK
& (SHMLBA
- 1)) : 0;
127 info
.align_offset
= pgoff
<< PAGE_SHIFT
;
128 addr
= vm_unmapped_area(&info
);
131 * A failed mmap() very likely causes application failure,
132 * so fall back to the bottom-up function here. This scenario
133 * can happen with large stack limits and large mmap()
136 if (addr
& ~PAGE_MASK
) {
137 VM_BUG_ON(addr
!= -ENOMEM
);
139 info
.low_limit
= mm
->mmap_base
;
140 info
.high_limit
= TASK_SIZE
;
141 addr
= vm_unmapped_area(&info
);
148 * You really shouldn't be using read() or write() on /dev/mem. This
149 * might go away in the future.
151 int valid_phys_addr_range(phys_addr_t addr
, size_t size
)
153 if (addr
< PHYS_OFFSET
)
155 if (addr
+ size
> __pa(high_memory
- 1) + 1)
162 * Do not allow /dev/mem mappings beyond the supported physical range.
164 int valid_mmap_phys_addr_range(unsigned long pfn
, size_t size
)
166 return (pfn
+ (size
>> PAGE_SHIFT
)) <= (1 + (PHYS_MASK
>> PAGE_SHIFT
));
169 #ifdef CONFIG_STRICT_DEVMEM
171 #include <linux/ioport.h>
174 * devmem_is_allowed() checks to see if /dev/mem access to a certain
175 * address is valid. The argument is a physical page number.
176 * We mimic x86 here by disallowing access to system RAM as well as
177 * device-exclusive MMIO regions. This effectively disable read()/write()
180 int devmem_is_allowed(unsigned long pfn
)
182 if (iomem_is_exclusive(pfn
<< PAGE_SHIFT
))
184 if (!page_is_ram(pfn
))