linux/arch/arm/mm/pageattr.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/*
   3 * Copyright (c) 2014, The Linux Foundation. All rights reserved.
   4 */
   5#include <linux/mm.h>
   6#include <linux/module.h>
   7
   8#include <asm/pgtable.h>
   9#include <asm/tlbflush.h>
  10#include <asm/set_memory.h>
  11
  12struct page_change_data {
  13        pgprot_t set_mask;
  14        pgprot_t clear_mask;
  15};
  16
  17static int change_page_range(pte_t *ptep, pgtable_t token, unsigned long addr,
  18                        void *data)
  19{
  20        struct page_change_data *cdata = data;
  21        pte_t pte = *ptep;
  22
  23        pte = clear_pte_bit(pte, cdata->clear_mask);
  24        pte = set_pte_bit(pte, cdata->set_mask);
  25
  26        set_pte_ext(ptep, pte, 0);
  27        return 0;
  28}
  29
  30static bool in_range(unsigned long start, unsigned long size,
  31        unsigned long range_start, unsigned long range_end)
  32{
  33        return start >= range_start && start < range_end &&
  34                size <= range_end - start;
  35}
  36
  37static int change_memory_common(unsigned long addr, int numpages,
  38                                pgprot_t set_mask, pgprot_t clear_mask)
  39{
  40        unsigned long start = addr & PAGE_MASK;
  41        unsigned long end = PAGE_ALIGN(addr) + numpages * PAGE_SIZE;
  42        unsigned long size = end - start;
  43        int ret;
  44        struct page_change_data data;
  45
  46        WARN_ON_ONCE(start != addr);
  47
  48        if (!size)
  49                return 0;
  50
  51        if (!in_range(start, size, MODULES_VADDR, MODULES_END) &&
  52            !in_range(start, size, VMALLOC_START, VMALLOC_END))
  53                return -EINVAL;
  54
  55        data.set_mask = set_mask;
  56        data.clear_mask = clear_mask;
  57
  58        ret = apply_to_page_range(&init_mm, start, size, change_page_range,
  59                                        &data);
  60
  61        flush_tlb_kernel_range(start, end);
  62        return ret;
  63}
  64
  65int set_memory_ro(unsigned long addr, int numpages)
  66{
  67        return change_memory_common(addr, numpages,
  68                                        __pgprot(L_PTE_RDONLY),
  69                                        __pgprot(0));
  70}
  71
  72int set_memory_rw(unsigned long addr, int numpages)
  73{
  74        return change_memory_common(addr, numpages,
  75                                        __pgprot(0),
  76                                        __pgprot(L_PTE_RDONLY));
  77}
  78
  79int set_memory_nx(unsigned long addr, int numpages)
  80{
  81        return change_memory_common(addr, numpages,
  82                                        __pgprot(L_PTE_XN),
  83                                        __pgprot(0));
  84}
  85
  86int set_memory_x(unsigned long addr, int numpages)
  87{
  88        return change_memory_common(addr, numpages,
  89                                        __pgprot(0),
  90                                        __pgprot(L_PTE_XN));
  91}
  92