Skip to content
Snippets Groups Projects
Select Git revision
  • dd273a8071124c2235c45d2ca756acc90ca31ed3
  • vme-testing default
  • ci-test
  • master
  • remoteproc
  • am625-sk-ov5640
  • pcal6534-upstreaming
  • lps22df-upstreaming
  • msc-upstreaming
  • imx8mp
  • iio/noa1305
  • vme-next
  • vme-next-4.14-rc4
  • v4.14-rc4
  • v4.14-rc3
  • v4.14-rc2
  • v4.14-rc1
  • v4.13
  • vme-next-4.13-rc7
  • v4.13-rc7
  • v4.13-rc6
  • v4.13-rc5
  • v4.13-rc4
  • v4.13-rc3
  • v4.13-rc2
  • v4.13-rc1
  • v4.12
  • v4.12-rc7
  • v4.12-rc6
  • v4.12-rc5
  • v4.12-rc4
  • v4.12-rc3
32 results

pageattr.c

Blame
  • pageattr.c 2.26 KiB
    /*
     * Copyright (c) 2014, The Linux Foundation. All rights reserved.
     *
     * This program is free software; you can redistribute it and/or modify
     * it under the terms of the GNU General Public License version 2 and
     * only version 2 as published by the Free Software Foundation.
     *
     * This program is distributed in the hope that it will be useful,
     * but WITHOUT ANY WARRANTY; without even the implied warranty of
     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     * GNU General Public License for more details.
     */
    #include <linux/mm.h>
    #include <linux/module.h>
    
    #include <asm/pgtable.h>
    #include <asm/tlbflush.h>
    
    struct page_change_data {
    	pgprot_t set_mask;
    	pgprot_t clear_mask;
    };
    
    static int change_page_range(pte_t *ptep, pgtable_t token, unsigned long addr,
    			void *data)
    {
    	struct page_change_data *cdata = data;
    	pte_t pte = *ptep;
    
    	pte = clear_pte_bit(pte, cdata->clear_mask);
    	pte = set_pte_bit(pte, cdata->set_mask);
    
    	set_pte_ext(ptep, pte, 0);
    	return 0;
    }
    
    static int change_memory_common(unsigned long addr, int numpages,
    				pgprot_t set_mask, pgprot_t clear_mask)
    {
    	unsigned long start = addr;
    	unsigned long size = PAGE_SIZE*numpages;
    	unsigned long end = start + size;
    	int ret;
    	struct page_change_data data;
    
    	if (!IS_ALIGNED(addr, PAGE_SIZE)) {
    		start &= PAGE_MASK;
    		end = start + size;
    		WARN_ON_ONCE(1);
    	}
    
    	if (!numpages)
    		return 0;
    
    	if (start < MODULES_VADDR || start >= MODULES_END)
    		return -EINVAL;
    
    	if (end < MODULES_VADDR || start >= MODULES_END)
    		return -EINVAL;
    
    	data.set_mask = set_mask;
    	data.clear_mask = clear_mask;
    
    	ret = apply_to_page_range(&init_mm, start, size, change_page_range,
    					&data);
    
    	flush_tlb_kernel_range(start, end);
    	return ret;
    }
    
    int set_memory_ro(unsigned long addr, int numpages)
    {
    	return change_memory_common(addr, numpages,
    					__pgprot(L_PTE_RDONLY),
    					__pgprot(0));
    }
    
    int set_memory_rw(unsigned long addr, int numpages)
    {
    	return change_memory_common(addr, numpages,
    					__pgprot(0),
    					__pgprot(L_PTE_RDONLY));
    }
    
    int set_memory_nx(unsigned long addr, int numpages)
    {
    	return change_memory_common(addr, numpages,
    					__pgprot(L_PTE_XN),
    					__pgprot(0));
    }
    
    int set_memory_x(unsigned long addr, int numpages)
    {
    	return change_memory_common(addr, numpages,
    					__pgprot(0),
    					__pgprot(L_PTE_XN));
    }