1 // SPDX-License-Identifier: GPL-2.0 2 // Copyright (C) 2018 Hangzhou C-SKY Microsystems co.,ltd. 3 4 #include <linux/fs.h> 5 #include <linux/mm.h> 6 #include <linux/mman.h> 7 #include <linux/shm.h> 8 #include <linux/sched.h> 9 #include <linux/random.h> 10 #include <linux/io.h> 11 12 #define COLOUR_ALIGN(addr,pgoff) \ 13 ((((addr)+SHMLBA-1)&~(SHMLBA-1)) + \ 14 (((pgoff)<<PAGE_SHIFT) & (SHMLBA-1))) 15 16 /* 17 * We need to ensure that shared mappings are correctly aligned to 18 * avoid aliasing issues with VIPT caches. We need to ensure that 19 * a specific page of an object is always mapped at a multiple of 20 * SHMLBA bytes. 21 * 22 * We unconditionally provide this function for all cases. 23 */ 24 unsigned long 25 arch_get_unmapped_area(struct file *filp, unsigned long addr, 26 unsigned long len, unsigned long pgoff, 27 unsigned long flags, vm_flags_t vm_flags) 28 { 29 struct mm_struct *mm = current->mm; 30 struct vm_area_struct *vma; 31 int do_align = 0; 32 struct vm_unmapped_area_info info = { 33 .length = len, 34 .low_limit = mm->mmap_base, 35 .high_limit = TASK_SIZE, 36 .align_offset = pgoff << PAGE_SHIFT 37 }; 38 39 /* 40 * We only need to do colour alignment if either the I or D 41 * caches alias. 42 */ 43 do_align = filp || (flags & MAP_SHARED); 44 45 /* 46 * We enforce the MAP_FIXED case. 47 */ 48 if (flags & MAP_FIXED) { 49 if (flags & MAP_SHARED && 50 (addr - (pgoff << PAGE_SHIFT)) & (SHMLBA - 1)) 51 return -EINVAL; 52 return addr; 53 } 54 55 if (len > TASK_SIZE) 56 return -ENOMEM; 57 58 if (addr) { 59 if (do_align) 60 addr = COLOUR_ALIGN(addr, pgoff); 61 else 62 addr = PAGE_ALIGN(addr); 63 64 vma = find_vma(mm, addr); 65 if (TASK_SIZE - len >= addr && 66 (!vma || addr + len <= vm_start_gap(vma))) 67 return addr; 68 } 69 70 info.align_mask = do_align ? (PAGE_MASK & (SHMLBA - 1)) : 0; 71 return vm_unmapped_area(&info); 72 } 73