18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci// Copyright (C) 2018 Hangzhou C-SKY Microsystems co.,ltd. 38c2ecf20Sopenharmony_ci 48c2ecf20Sopenharmony_ci#include <linux/fs.h> 58c2ecf20Sopenharmony_ci#include <linux/mm.h> 68c2ecf20Sopenharmony_ci#include <linux/mman.h> 78c2ecf20Sopenharmony_ci#include <linux/shm.h> 88c2ecf20Sopenharmony_ci#include <linux/sched.h> 98c2ecf20Sopenharmony_ci#include <linux/random.h> 108c2ecf20Sopenharmony_ci#include <linux/io.h> 118c2ecf20Sopenharmony_ci 128c2ecf20Sopenharmony_ci#define COLOUR_ALIGN(addr,pgoff) \ 138c2ecf20Sopenharmony_ci ((((addr)+SHMLBA-1)&~(SHMLBA-1)) + \ 148c2ecf20Sopenharmony_ci (((pgoff)<<PAGE_SHIFT) & (SHMLBA-1))) 158c2ecf20Sopenharmony_ci 168c2ecf20Sopenharmony_ci/* 178c2ecf20Sopenharmony_ci * We need to ensure that shared mappings are correctly aligned to 188c2ecf20Sopenharmony_ci * avoid aliasing issues with VIPT caches. We need to ensure that 198c2ecf20Sopenharmony_ci * a specific page of an object is always mapped at a multiple of 208c2ecf20Sopenharmony_ci * SHMLBA bytes. 218c2ecf20Sopenharmony_ci * 228c2ecf20Sopenharmony_ci * We unconditionally provide this function for all cases. 238c2ecf20Sopenharmony_ci */ 248c2ecf20Sopenharmony_ciunsigned long 258c2ecf20Sopenharmony_ciarch_get_unmapped_area(struct file *filp, unsigned long addr, 268c2ecf20Sopenharmony_ci unsigned long len, unsigned long pgoff, unsigned long flags) 278c2ecf20Sopenharmony_ci{ 288c2ecf20Sopenharmony_ci struct mm_struct *mm = current->mm; 298c2ecf20Sopenharmony_ci struct vm_area_struct *vma; 308c2ecf20Sopenharmony_ci int do_align = 0; 318c2ecf20Sopenharmony_ci struct vm_unmapped_area_info info; 328c2ecf20Sopenharmony_ci 338c2ecf20Sopenharmony_ci /* 348c2ecf20Sopenharmony_ci * We only need to do colour alignment if either the I or D 358c2ecf20Sopenharmony_ci * caches alias. 368c2ecf20Sopenharmony_ci */ 378c2ecf20Sopenharmony_ci do_align = filp || (flags & MAP_SHARED); 388c2ecf20Sopenharmony_ci 398c2ecf20Sopenharmony_ci /* 408c2ecf20Sopenharmony_ci * We enforce the MAP_FIXED case. 418c2ecf20Sopenharmony_ci */ 428c2ecf20Sopenharmony_ci if (flags & MAP_FIXED) { 438c2ecf20Sopenharmony_ci if (flags & MAP_SHARED && 448c2ecf20Sopenharmony_ci (addr - (pgoff << PAGE_SHIFT)) & (SHMLBA - 1)) 458c2ecf20Sopenharmony_ci return -EINVAL; 468c2ecf20Sopenharmony_ci return addr; 478c2ecf20Sopenharmony_ci } 488c2ecf20Sopenharmony_ci 498c2ecf20Sopenharmony_ci if (len > TASK_SIZE) 508c2ecf20Sopenharmony_ci return -ENOMEM; 518c2ecf20Sopenharmony_ci 528c2ecf20Sopenharmony_ci if (addr) { 538c2ecf20Sopenharmony_ci if (do_align) 548c2ecf20Sopenharmony_ci addr = COLOUR_ALIGN(addr, pgoff); 558c2ecf20Sopenharmony_ci else 568c2ecf20Sopenharmony_ci addr = PAGE_ALIGN(addr); 578c2ecf20Sopenharmony_ci 588c2ecf20Sopenharmony_ci vma = find_vma(mm, addr); 598c2ecf20Sopenharmony_ci if (TASK_SIZE - len >= addr && 608c2ecf20Sopenharmony_ci (!vma || addr + len <= vm_start_gap(vma))) 618c2ecf20Sopenharmony_ci return addr; 628c2ecf20Sopenharmony_ci } 638c2ecf20Sopenharmony_ci 648c2ecf20Sopenharmony_ci info.flags = 0; 658c2ecf20Sopenharmony_ci info.length = len; 668c2ecf20Sopenharmony_ci info.low_limit = mm->mmap_base; 678c2ecf20Sopenharmony_ci info.high_limit = TASK_SIZE; 688c2ecf20Sopenharmony_ci info.align_mask = do_align ? (PAGE_MASK & (SHMLBA - 1)) : 0; 698c2ecf20Sopenharmony_ci info.align_offset = pgoff << PAGE_SHIFT; 708c2ecf20Sopenharmony_ci return vm_unmapped_area(&info); 718c2ecf20Sopenharmony_ci} 72