162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * ARC700 mmap
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * (started from arm version - for VIPT alias handling)
662306a36Sopenharmony_ci *
762306a36Sopenharmony_ci * Copyright (C) 2013 Synopsys, Inc. (www.synopsys.com)
862306a36Sopenharmony_ci */
962306a36Sopenharmony_ci
1062306a36Sopenharmony_ci#include <linux/fs.h>
1162306a36Sopenharmony_ci#include <linux/mm.h>
1262306a36Sopenharmony_ci#include <linux/mman.h>
1362306a36Sopenharmony_ci#include <linux/sched/mm.h>
1462306a36Sopenharmony_ci
1562306a36Sopenharmony_ci#include <asm/cacheflush.h>
1662306a36Sopenharmony_ci
1762306a36Sopenharmony_ci#define COLOUR_ALIGN(addr, pgoff)			\
1862306a36Sopenharmony_ci	((((addr) + SHMLBA - 1) & ~(SHMLBA - 1)) +	\
1962306a36Sopenharmony_ci	 (((pgoff) << PAGE_SHIFT) & (SHMLBA - 1)))
2062306a36Sopenharmony_ci
2162306a36Sopenharmony_ci/*
2262306a36Sopenharmony_ci * Ensure that shared mappings are correctly aligned to
2362306a36Sopenharmony_ci * avoid aliasing issues with VIPT caches.
2462306a36Sopenharmony_ci * We need to ensure that
2562306a36Sopenharmony_ci * a specific page of an object is always mapped at a multiple of
2662306a36Sopenharmony_ci * SHMLBA bytes.
2762306a36Sopenharmony_ci */
2862306a36Sopenharmony_ciunsigned long
2962306a36Sopenharmony_ciarch_get_unmapped_area(struct file *filp, unsigned long addr,
3062306a36Sopenharmony_ci		unsigned long len, unsigned long pgoff, unsigned long flags)
3162306a36Sopenharmony_ci{
3262306a36Sopenharmony_ci	struct mm_struct *mm = current->mm;
3362306a36Sopenharmony_ci	struct vm_area_struct *vma;
3462306a36Sopenharmony_ci	int do_align = 0;
3562306a36Sopenharmony_ci	int aliasing = cache_is_vipt_aliasing();
3662306a36Sopenharmony_ci	struct vm_unmapped_area_info info;
3762306a36Sopenharmony_ci
3862306a36Sopenharmony_ci	/*
3962306a36Sopenharmony_ci	 * We only need to do colour alignment if D cache aliases.
4062306a36Sopenharmony_ci	 */
4162306a36Sopenharmony_ci	if (aliasing)
4262306a36Sopenharmony_ci		do_align = filp || (flags & MAP_SHARED);
4362306a36Sopenharmony_ci
4462306a36Sopenharmony_ci	/*
4562306a36Sopenharmony_ci	 * We enforce the MAP_FIXED case.
4662306a36Sopenharmony_ci	 */
4762306a36Sopenharmony_ci	if (flags & MAP_FIXED) {
4862306a36Sopenharmony_ci		if (aliasing && flags & MAP_SHARED &&
4962306a36Sopenharmony_ci		    (addr - (pgoff << PAGE_SHIFT)) & (SHMLBA - 1))
5062306a36Sopenharmony_ci			return -EINVAL;
5162306a36Sopenharmony_ci		return addr;
5262306a36Sopenharmony_ci	}
5362306a36Sopenharmony_ci
5462306a36Sopenharmony_ci	if (len > TASK_SIZE)
5562306a36Sopenharmony_ci		return -ENOMEM;
5662306a36Sopenharmony_ci
5762306a36Sopenharmony_ci	if (addr) {
5862306a36Sopenharmony_ci		if (do_align)
5962306a36Sopenharmony_ci			addr = COLOUR_ALIGN(addr, pgoff);
6062306a36Sopenharmony_ci		else
6162306a36Sopenharmony_ci			addr = PAGE_ALIGN(addr);
6262306a36Sopenharmony_ci
6362306a36Sopenharmony_ci		vma = find_vma(mm, addr);
6462306a36Sopenharmony_ci		if (TASK_SIZE - len >= addr &&
6562306a36Sopenharmony_ci		    (!vma || addr + len <= vm_start_gap(vma)))
6662306a36Sopenharmony_ci			return addr;
6762306a36Sopenharmony_ci	}
6862306a36Sopenharmony_ci
6962306a36Sopenharmony_ci	info.flags = 0;
7062306a36Sopenharmony_ci	info.length = len;
7162306a36Sopenharmony_ci	info.low_limit = mm->mmap_base;
7262306a36Sopenharmony_ci	info.high_limit = TASK_SIZE;
7362306a36Sopenharmony_ci	info.align_mask = do_align ? (PAGE_MASK & (SHMLBA - 1)) : 0;
7462306a36Sopenharmony_ci	info.align_offset = pgoff << PAGE_SHIFT;
7562306a36Sopenharmony_ci	return vm_unmapped_area(&info);
7662306a36Sopenharmony_ci}
7762306a36Sopenharmony_ci
7862306a36Sopenharmony_cistatic const pgprot_t protection_map[16] = {
7962306a36Sopenharmony_ci	[VM_NONE]					= PAGE_U_NONE,
8062306a36Sopenharmony_ci	[VM_READ]					= PAGE_U_R,
8162306a36Sopenharmony_ci	[VM_WRITE]					= PAGE_U_R,
8262306a36Sopenharmony_ci	[VM_WRITE | VM_READ]				= PAGE_U_R,
8362306a36Sopenharmony_ci	[VM_EXEC]					= PAGE_U_X_R,
8462306a36Sopenharmony_ci	[VM_EXEC | VM_READ]				= PAGE_U_X_R,
8562306a36Sopenharmony_ci	[VM_EXEC | VM_WRITE]				= PAGE_U_X_R,
8662306a36Sopenharmony_ci	[VM_EXEC | VM_WRITE | VM_READ]			= PAGE_U_X_R,
8762306a36Sopenharmony_ci	[VM_SHARED]					= PAGE_U_NONE,
8862306a36Sopenharmony_ci	[VM_SHARED | VM_READ]				= PAGE_U_R,
8962306a36Sopenharmony_ci	[VM_SHARED | VM_WRITE]				= PAGE_U_W_R,
9062306a36Sopenharmony_ci	[VM_SHARED | VM_WRITE | VM_READ]		= PAGE_U_W_R,
9162306a36Sopenharmony_ci	[VM_SHARED | VM_EXEC]				= PAGE_U_X_R,
9262306a36Sopenharmony_ci	[VM_SHARED | VM_EXEC | VM_READ]			= PAGE_U_X_R,
9362306a36Sopenharmony_ci	[VM_SHARED | VM_EXEC | VM_WRITE]		= PAGE_U_X_W_R,
9462306a36Sopenharmony_ci	[VM_SHARED | VM_EXEC | VM_WRITE | VM_READ]	= PAGE_U_X_W_R
9562306a36Sopenharmony_ci};
9662306a36Sopenharmony_ciDECLARE_VM_GET_PAGE_PROT
97