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