xref: /kernel/linux/linux-6.6/arch/arm64/mm/mmap.c (revision 62306a36)
162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Based on arch/arm/mm/mmap.c
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Copyright (C) 2012 ARM Ltd.
662306a36Sopenharmony_ci */
762306a36Sopenharmony_ci
862306a36Sopenharmony_ci#include <linux/io.h>
962306a36Sopenharmony_ci#include <linux/memblock.h>
1062306a36Sopenharmony_ci#include <linux/mm.h>
1162306a36Sopenharmony_ci#include <linux/types.h>
1262306a36Sopenharmony_ci
1362306a36Sopenharmony_ci#include <asm/cpufeature.h>
1462306a36Sopenharmony_ci#include <asm/page.h>
1562306a36Sopenharmony_ci
1662306a36Sopenharmony_cistatic pgprot_t protection_map[16] __ro_after_init = {
1762306a36Sopenharmony_ci	[VM_NONE]					= PAGE_NONE,
1862306a36Sopenharmony_ci	[VM_READ]					= PAGE_READONLY,
1962306a36Sopenharmony_ci	[VM_WRITE]					= PAGE_READONLY,
2062306a36Sopenharmony_ci	[VM_WRITE | VM_READ]				= PAGE_READONLY,
2162306a36Sopenharmony_ci	/* PAGE_EXECONLY if Enhanced PAN */
2262306a36Sopenharmony_ci	[VM_EXEC]					= PAGE_READONLY_EXEC,
2362306a36Sopenharmony_ci	[VM_EXEC | VM_READ]				= PAGE_READONLY_EXEC,
2462306a36Sopenharmony_ci	[VM_EXEC | VM_WRITE]				= PAGE_READONLY_EXEC,
2562306a36Sopenharmony_ci	[VM_EXEC | VM_WRITE | VM_READ]			= PAGE_READONLY_EXEC,
2662306a36Sopenharmony_ci	[VM_SHARED]					= PAGE_NONE,
2762306a36Sopenharmony_ci	[VM_SHARED | VM_READ]				= PAGE_READONLY,
2862306a36Sopenharmony_ci	[VM_SHARED | VM_WRITE]				= PAGE_SHARED,
2962306a36Sopenharmony_ci	[VM_SHARED | VM_WRITE | VM_READ]		= PAGE_SHARED,
3062306a36Sopenharmony_ci	/* PAGE_EXECONLY if Enhanced PAN */
3162306a36Sopenharmony_ci	[VM_SHARED | VM_EXEC]				= PAGE_READONLY_EXEC,
3262306a36Sopenharmony_ci	[VM_SHARED | VM_EXEC | VM_READ]			= PAGE_READONLY_EXEC,
3362306a36Sopenharmony_ci	[VM_SHARED | VM_EXEC | VM_WRITE]		= PAGE_SHARED_EXEC,
3462306a36Sopenharmony_ci	[VM_SHARED | VM_EXEC | VM_WRITE | VM_READ]	= PAGE_SHARED_EXEC
3562306a36Sopenharmony_ci};
3662306a36Sopenharmony_ci
3762306a36Sopenharmony_ci/*
3862306a36Sopenharmony_ci * You really shouldn't be using read() or write() on /dev/mem.  This might go
3962306a36Sopenharmony_ci * away in the future.
4062306a36Sopenharmony_ci */
4162306a36Sopenharmony_ciint valid_phys_addr_range(phys_addr_t addr, size_t size)
4262306a36Sopenharmony_ci{
4362306a36Sopenharmony_ci	/*
4462306a36Sopenharmony_ci	 * Check whether addr is covered by a memory region without the
4562306a36Sopenharmony_ci	 * MEMBLOCK_NOMAP attribute, and whether that region covers the
4662306a36Sopenharmony_ci	 * entire range. In theory, this could lead to false negatives
4762306a36Sopenharmony_ci	 * if the range is covered by distinct but adjacent memory regions
4862306a36Sopenharmony_ci	 * that only differ in other attributes. However, few of such
4962306a36Sopenharmony_ci	 * attributes have been defined, and it is debatable whether it
5062306a36Sopenharmony_ci	 * follows that /dev/mem read() calls should be able traverse
5162306a36Sopenharmony_ci	 * such boundaries.
5262306a36Sopenharmony_ci	 */
5362306a36Sopenharmony_ci	return memblock_is_region_memory(addr, size) &&
5462306a36Sopenharmony_ci	       memblock_is_map_memory(addr);
5562306a36Sopenharmony_ci}
5662306a36Sopenharmony_ci
5762306a36Sopenharmony_ci/*
5862306a36Sopenharmony_ci * Do not allow /dev/mem mappings beyond the supported physical range.
5962306a36Sopenharmony_ci */
6062306a36Sopenharmony_ciint valid_mmap_phys_addr_range(unsigned long pfn, size_t size)
6162306a36Sopenharmony_ci{
6262306a36Sopenharmony_ci	return !(((pfn << PAGE_SHIFT) + size) & ~PHYS_MASK);
6362306a36Sopenharmony_ci}
6462306a36Sopenharmony_ci
6562306a36Sopenharmony_cistatic int __init adjust_protection_map(void)
6662306a36Sopenharmony_ci{
6762306a36Sopenharmony_ci	/*
6862306a36Sopenharmony_ci	 * With Enhanced PAN we can honour the execute-only permissions as
6962306a36Sopenharmony_ci	 * there is no PAN override with such mappings.
7062306a36Sopenharmony_ci	 */
7162306a36Sopenharmony_ci	if (cpus_have_const_cap(ARM64_HAS_EPAN)) {
7262306a36Sopenharmony_ci		protection_map[VM_EXEC] = PAGE_EXECONLY;
7362306a36Sopenharmony_ci		protection_map[VM_EXEC | VM_SHARED] = PAGE_EXECONLY;
7462306a36Sopenharmony_ci	}
7562306a36Sopenharmony_ci
7662306a36Sopenharmony_ci	return 0;
7762306a36Sopenharmony_ci}
7862306a36Sopenharmony_ciarch_initcall(adjust_protection_map);
7962306a36Sopenharmony_ci
8062306a36Sopenharmony_cipgprot_t vm_get_page_prot(unsigned long vm_flags)
8162306a36Sopenharmony_ci{
8262306a36Sopenharmony_ci	pteval_t prot = pgprot_val(protection_map[vm_flags &
8362306a36Sopenharmony_ci				   (VM_READ|VM_WRITE|VM_EXEC|VM_SHARED)]);
8462306a36Sopenharmony_ci
8562306a36Sopenharmony_ci	if (vm_flags & VM_ARM64_BTI)
8662306a36Sopenharmony_ci		prot |= PTE_GP;
8762306a36Sopenharmony_ci
8862306a36Sopenharmony_ci	/*
8962306a36Sopenharmony_ci	 * There are two conditions required for returning a Normal Tagged
9062306a36Sopenharmony_ci	 * memory type: (1) the user requested it via PROT_MTE passed to
9162306a36Sopenharmony_ci	 * mmap() or mprotect() and (2) the corresponding vma supports MTE. We
9262306a36Sopenharmony_ci	 * register (1) as VM_MTE in the vma->vm_flags and (2) as
9362306a36Sopenharmony_ci	 * VM_MTE_ALLOWED. Note that the latter can only be set during the
9462306a36Sopenharmony_ci	 * mmap() call since mprotect() does not accept MAP_* flags.
9562306a36Sopenharmony_ci	 * Checking for VM_MTE only is sufficient since arch_validate_flags()
9662306a36Sopenharmony_ci	 * does not permit (VM_MTE & !VM_MTE_ALLOWED).
9762306a36Sopenharmony_ci	 */
9862306a36Sopenharmony_ci	if (vm_flags & VM_MTE)
9962306a36Sopenharmony_ci		prot |= PTE_ATTRINDX(MT_NORMAL_TAGGED);
10062306a36Sopenharmony_ci
10162306a36Sopenharmony_ci	return __pgprot(prot);
10262306a36Sopenharmony_ci}
10362306a36Sopenharmony_ciEXPORT_SYMBOL(vm_get_page_prot);
104