-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
riscv: add ARCH_HAS_SET_MEMORY support
Add set_memory_ro/rw/x/nx architecture hooks to change the page attribution. Use own set_memory.h rather than generic set_memory.h (i.e. include/asm-generic/set_memory.h), because we want to add other function prototypes here. Signed-off-by: Zong Li <zong.li@sifive.com> Signed-off-by: Palmer Dabbelt <palmerdabbelt@google.com>
- Loading branch information
Zong Li
authored and
Palmer Dabbelt
committed
Mar 26, 2020
1 parent
9f40b6e
commit d3ab332
Showing
4 changed files
with
176 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
/* SPDX-License-Identifier: GPL-2.0-only */ | ||
/* | ||
* Copyright (C) 2019 SiFive | ||
*/ | ||
|
||
#ifndef _ASM_RISCV_SET_MEMORY_H | ||
#define _ASM_RISCV_SET_MEMORY_H | ||
|
||
/* | ||
* Functions to change memory attributes. | ||
*/ | ||
#ifdef CONFIG_MMU | ||
int set_memory_ro(unsigned long addr, int numpages); | ||
int set_memory_rw(unsigned long addr, int numpages); | ||
int set_memory_x(unsigned long addr, int numpages); | ||
int set_memory_nx(unsigned long addr, int numpages); | ||
#else | ||
static inline int set_memory_ro(unsigned long addr, int numpages) { return 0; } | ||
static inline int set_memory_rw(unsigned long addr, int numpages) { return 0; } | ||
static inline int set_memory_x(unsigned long addr, int numpages) { return 0; } | ||
static inline int set_memory_nx(unsigned long addr, int numpages) { return 0; } | ||
#endif | ||
|
||
#endif /* _ASM_RISCV_SET_MEMORY_H */ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,150 @@ | ||
// SPDX-License-Identifier: GPL-2.0-only | ||
/* | ||
* Copyright (C) 2019 SiFive | ||
*/ | ||
|
||
#include <linux/pagewalk.h> | ||
#include <asm/pgtable.h> | ||
#include <asm/tlbflush.h> | ||
#include <asm/bitops.h> | ||
|
||
struct pageattr_masks { | ||
pgprot_t set_mask; | ||
pgprot_t clear_mask; | ||
}; | ||
|
||
static unsigned long set_pageattr_masks(unsigned long val, struct mm_walk *walk) | ||
{ | ||
struct pageattr_masks *masks = walk->private; | ||
unsigned long new_val = val; | ||
|
||
new_val &= ~(pgprot_val(masks->clear_mask)); | ||
new_val |= (pgprot_val(masks->set_mask)); | ||
|
||
return new_val; | ||
} | ||
|
||
static int pageattr_pgd_entry(pgd_t *pgd, unsigned long addr, | ||
unsigned long next, struct mm_walk *walk) | ||
{ | ||
pgd_t val = READ_ONCE(*pgd); | ||
|
||
if (pgd_leaf(val)) { | ||
val = __pgd(set_pageattr_masks(pgd_val(val), walk)); | ||
set_pgd(pgd, val); | ||
} | ||
|
||
return 0; | ||
} | ||
|
||
static int pageattr_p4d_entry(p4d_t *p4d, unsigned long addr, | ||
unsigned long next, struct mm_walk *walk) | ||
{ | ||
p4d_t val = READ_ONCE(*p4d); | ||
|
||
if (p4d_leaf(val)) { | ||
val = __p4d(set_pageattr_masks(p4d_val(val), walk)); | ||
set_p4d(p4d, val); | ||
} | ||
|
||
return 0; | ||
} | ||
|
||
static int pageattr_pud_entry(pud_t *pud, unsigned long addr, | ||
unsigned long next, struct mm_walk *walk) | ||
{ | ||
pud_t val = READ_ONCE(*pud); | ||
|
||
if (pud_leaf(val)) { | ||
val = __pud(set_pageattr_masks(pud_val(val), walk)); | ||
set_pud(pud, val); | ||
} | ||
|
||
return 0; | ||
} | ||
|
||
static int pageattr_pmd_entry(pmd_t *pmd, unsigned long addr, | ||
unsigned long next, struct mm_walk *walk) | ||
{ | ||
pmd_t val = READ_ONCE(*pmd); | ||
|
||
if (pmd_leaf(val)) { | ||
val = __pmd(set_pageattr_masks(pmd_val(val), walk)); | ||
set_pmd(pmd, val); | ||
} | ||
|
||
return 0; | ||
} | ||
|
||
static int pageattr_pte_entry(pte_t *pte, unsigned long addr, | ||
unsigned long next, struct mm_walk *walk) | ||
{ | ||
pte_t val = READ_ONCE(*pte); | ||
|
||
val = __pte(set_pageattr_masks(pte_val(val), walk)); | ||
set_pte(pte, val); | ||
|
||
return 0; | ||
} | ||
|
||
static int pageattr_pte_hole(unsigned long addr, unsigned long next, | ||
int depth, struct mm_walk *walk) | ||
{ | ||
/* Nothing to do here */ | ||
return 0; | ||
} | ||
|
||
const static struct mm_walk_ops pageattr_ops = { | ||
.pgd_entry = pageattr_pgd_entry, | ||
.p4d_entry = pageattr_p4d_entry, | ||
.pud_entry = pageattr_pud_entry, | ||
.pmd_entry = pageattr_pmd_entry, | ||
.pte_entry = pageattr_pte_entry, | ||
.pte_hole = pageattr_pte_hole, | ||
}; | ||
|
||
static int __set_memory(unsigned long addr, int numpages, pgprot_t set_mask, | ||
pgprot_t clear_mask) | ||
{ | ||
int ret; | ||
unsigned long start = addr; | ||
unsigned long end = start + PAGE_SIZE * numpages; | ||
struct pageattr_masks masks = { | ||
.set_mask = set_mask, | ||
.clear_mask = clear_mask | ||
}; | ||
|
||
if (!numpages) | ||
return 0; | ||
|
||
down_read(&init_mm.mmap_sem); | ||
ret = walk_page_range_novma(&init_mm, start, end, &pageattr_ops, NULL, | ||
&masks); | ||
up_read(&init_mm.mmap_sem); | ||
|
||
flush_tlb_kernel_range(start, end); | ||
|
||
return ret; | ||
} | ||
|
||
int set_memory_ro(unsigned long addr, int numpages) | ||
{ | ||
return __set_memory(addr, numpages, __pgprot(_PAGE_READ), | ||
__pgprot(_PAGE_WRITE)); | ||
} | ||
|
||
int set_memory_rw(unsigned long addr, int numpages) | ||
{ | ||
return __set_memory(addr, numpages, __pgprot(_PAGE_READ | _PAGE_WRITE), | ||
__pgprot(0)); | ||
} | ||
|
||
int set_memory_x(unsigned long addr, int numpages) | ||
{ | ||
return __set_memory(addr, numpages, __pgprot(_PAGE_EXEC), __pgprot(0)); | ||
} | ||
|
||
int set_memory_nx(unsigned long addr, int numpages) | ||
{ | ||
return __set_memory(addr, numpages, __pgprot(0), __pgprot(_PAGE_EXEC)); | ||
} |