162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci// Copyright (C) 2018 Hangzhou C-SKY Microsystems co.,ltd. 362306a36Sopenharmony_ci 462306a36Sopenharmony_ci#include <linux/fs.h> 562306a36Sopenharmony_ci#include <linux/mm.h> 662306a36Sopenharmony_ci#include <linux/mman.h> 762306a36Sopenharmony_ci#include <linux/shm.h> 862306a36Sopenharmony_ci#include <linux/sched.h> 962306a36Sopenharmony_ci#include <linux/random.h> 1062306a36Sopenharmony_ci#include <linux/io.h> 1162306a36Sopenharmony_ci 1262306a36Sopenharmony_ci#define COLOUR_ALIGN(addr,pgoff) \ 1362306a36Sopenharmony_ci ((((addr)+SHMLBA-1)&~(SHMLBA-1)) + \ 1462306a36Sopenharmony_ci (((pgoff)<<PAGE_SHIFT) & (SHMLBA-1))) 1562306a36Sopenharmony_ci 1662306a36Sopenharmony_ci/* 1762306a36Sopenharmony_ci * We need to ensure that shared mappings are correctly aligned to 1862306a36Sopenharmony_ci * avoid aliasing issues with VIPT caches. We need to ensure that 1962306a36Sopenharmony_ci * a specific page of an object is always mapped at a multiple of 2062306a36Sopenharmony_ci * SHMLBA bytes. 2162306a36Sopenharmony_ci * 2262306a36Sopenharmony_ci * We unconditionally provide this function for all cases. 2362306a36Sopenharmony_ci */ 2462306a36Sopenharmony_ciunsigned long 2562306a36Sopenharmony_ciarch_get_unmapped_area(struct file *filp, unsigned long addr, 2662306a36Sopenharmony_ci unsigned long len, unsigned long pgoff, unsigned long flags) 2762306a36Sopenharmony_ci{ 2862306a36Sopenharmony_ci struct mm_struct *mm = current->mm; 2962306a36Sopenharmony_ci struct vm_area_struct *vma; 3062306a36Sopenharmony_ci int do_align = 0; 3162306a36Sopenharmony_ci struct vm_unmapped_area_info info; 3262306a36Sopenharmony_ci 3362306a36Sopenharmony_ci /* 3462306a36Sopenharmony_ci * We only need to do colour alignment if either the I or D 3562306a36Sopenharmony_ci * caches alias. 3662306a36Sopenharmony_ci */ 3762306a36Sopenharmony_ci do_align = filp || (flags & MAP_SHARED); 3862306a36Sopenharmony_ci 3962306a36Sopenharmony_ci /* 4062306a36Sopenharmony_ci * We enforce the MAP_FIXED case. 4162306a36Sopenharmony_ci */ 4262306a36Sopenharmony_ci if (flags & MAP_FIXED) { 4362306a36Sopenharmony_ci if (flags & MAP_SHARED && 4462306a36Sopenharmony_ci (addr - (pgoff << PAGE_SHIFT)) & (SHMLBA - 1)) 4562306a36Sopenharmony_ci return -EINVAL; 4662306a36Sopenharmony_ci return addr; 4762306a36Sopenharmony_ci } 4862306a36Sopenharmony_ci 4962306a36Sopenharmony_ci if (len > TASK_SIZE) 5062306a36Sopenharmony_ci return -ENOMEM; 5162306a36Sopenharmony_ci 5262306a36Sopenharmony_ci if (addr) { 5362306a36Sopenharmony_ci if (do_align) 5462306a36Sopenharmony_ci addr = COLOUR_ALIGN(addr, pgoff); 5562306a36Sopenharmony_ci else 5662306a36Sopenharmony_ci addr = PAGE_ALIGN(addr); 5762306a36Sopenharmony_ci 5862306a36Sopenharmony_ci vma = find_vma(mm, addr); 5962306a36Sopenharmony_ci if (TASK_SIZE - len >= addr && 6062306a36Sopenharmony_ci (!vma || addr + len <= vm_start_gap(vma))) 6162306a36Sopenharmony_ci return addr; 6262306a36Sopenharmony_ci } 6362306a36Sopenharmony_ci 6462306a36Sopenharmony_ci info.flags = 0; 6562306a36Sopenharmony_ci info.length = len; 6662306a36Sopenharmony_ci info.low_limit = mm->mmap_base; 6762306a36Sopenharmony_ci info.high_limit = TASK_SIZE; 6862306a36Sopenharmony_ci info.align_mask = do_align ? (PAGE_MASK & (SHMLBA - 1)) : 0; 6962306a36Sopenharmony_ci info.align_offset = pgoff << PAGE_SHIFT; 7062306a36Sopenharmony_ci return vm_unmapped_area(&info); 7162306a36Sopenharmony_ci} 72