Merge "arm: mm: program ptes for access restriction"

This commit is contained in:
Linux Build Service Account 2017-02-08 17:48:07 -08:00 committed by Gerrit - the friendly Code Review server
commit 8f0a76b8f6
4 changed files with 125 additions and 4 deletions

View file

@ -230,6 +230,9 @@ config NEED_RET_TO_USER
config ARCH_MTD_XIP config ARCH_MTD_XIP
bool bool
config ARCH_WANT_KMAP_ATOMIC_FLUSH
bool
config VECTORS_BASE config VECTORS_BASE
hex hex
default 0xffff0000 if MMU || CPU_HIGH_VECTOR default 0xffff0000 if MMU || CPU_HIGH_VECTOR
@ -652,6 +655,7 @@ config ARCH_QCOM
select SPARSE_IRQ select SPARSE_IRQ
select USE_OF select USE_OF
select PINCTRL select PINCTRL
select ARCH_WANT_KMAP_ATOMIC_FLUSH
help help
Support for Qualcomm MSM/QSD based systems. This runs on the Support for Qualcomm MSM/QSD based systems. This runs on the
apps processor of the MSM/QSD and depends on a shared memory apps processor of the MSM/QSD and depends on a shared memory

View file

@ -320,6 +320,17 @@
alignment = <0x0 0x400000>; alignment = <0x0 0x400000>;
size = <0x0 0x5c00000>; size = <0x0 0x5c00000>;
}; };
/* global autoconfigured region for contiguous allocations */
linux,cma {
compatible = "shared-dma-pool";
alloc-ranges = <0x0 0x00000000 0x0 0xffffffff>;
reusable;
alignment = <0x0 0x400000>;
size = <0x0 0x2000000>;
linux,cma-default;
};
}; };
bluetooth: bt_wcn3990 { bluetooth: bt_wcn3990 {

View file

@ -10,6 +10,7 @@
* published by the Free Software Foundation. * published by the Free Software Foundation.
*/ */
#include <linux/cpu.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/highmem.h> #include <linux/highmem.h>
#include <linux/interrupt.h> #include <linux/interrupt.h>
@ -147,3 +148,58 @@ void *kmap_atomic_pfn(unsigned long pfn)
return (void *)vaddr; return (void *)vaddr;
} }
#ifdef CONFIG_ARCH_WANT_KMAP_ATOMIC_FLUSH
static void kmap_remove_unused_cpu(int cpu)
{
int start_idx, idx, type;
pagefault_disable();
type = kmap_atomic_idx();
start_idx = type + 1 + KM_TYPE_NR * cpu;
for (idx = start_idx; idx < KM_TYPE_NR + KM_TYPE_NR * cpu; idx++) {
unsigned long vaddr = __fix_to_virt(FIX_KMAP_BEGIN + idx);
pte_t ptep;
ptep = get_top_pte(vaddr);
if (ptep)
set_top_pte(vaddr, __pte(0));
}
pagefault_enable();
}
static void kmap_remove_unused(void *unused)
{
kmap_remove_unused_cpu(smp_processor_id());
}
void kmap_atomic_flush_unused(void)
{
on_each_cpu(kmap_remove_unused, NULL, 1);
}
static int hotplug_kmap_atomic_callback(struct notifier_block *nfb,
unsigned long action, void *hcpu)
{
switch (action & (~CPU_TASKS_FROZEN)) {
case CPU_DYING:
kmap_remove_unused_cpu((int)hcpu);
break;
default:
break;
}
return NOTIFY_OK;
}
static struct notifier_block hotplug_kmap_atomic_notifier = {
.notifier_call = hotplug_kmap_atomic_callback,
};
static int __init init_kmap_atomic(void)
{
return register_hotcpu_notifier(&hotplug_kmap_atomic_notifier);
}
early_initcall(init_kmap_atomic);
#endif

View file

@ -625,6 +625,9 @@ struct section_perm {
pmdval_t mask; pmdval_t mask;
pmdval_t prot; pmdval_t prot;
pmdval_t clear; pmdval_t clear;
pteval_t ptemask;
pteval_t pteprot;
pteval_t pteclear;
}; };
static struct section_perm nx_perms[] = { static struct section_perm nx_perms[] = {
@ -634,6 +637,8 @@ static struct section_perm nx_perms[] = {
.end = (unsigned long)_stext, .end = (unsigned long)_stext,
.mask = ~PMD_SECT_XN, .mask = ~PMD_SECT_XN,
.prot = PMD_SECT_XN, .prot = PMD_SECT_XN,
.ptemask = ~L_PTE_XN,
.pteprot = L_PTE_XN,
}, },
/* Make init RW (set NX). */ /* Make init RW (set NX). */
{ {
@ -641,6 +646,8 @@ static struct section_perm nx_perms[] = {
.end = (unsigned long)_sdata, .end = (unsigned long)_sdata,
.mask = ~PMD_SECT_XN, .mask = ~PMD_SECT_XN,
.prot = PMD_SECT_XN, .prot = PMD_SECT_XN,
.ptemask = ~L_PTE_XN,
.pteprot = L_PTE_XN,
}, },
#ifdef CONFIG_DEBUG_RODATA #ifdef CONFIG_DEBUG_RODATA
/* Make rodata NX (set RO in ro_perms below). */ /* Make rodata NX (set RO in ro_perms below). */
@ -649,6 +656,8 @@ static struct section_perm nx_perms[] = {
.end = (unsigned long)__init_begin, .end = (unsigned long)__init_begin,
.mask = ~PMD_SECT_XN, .mask = ~PMD_SECT_XN,
.prot = PMD_SECT_XN, .prot = PMD_SECT_XN,
.ptemask = ~L_PTE_XN,
.pteprot = L_PTE_XN,
}, },
#endif #endif
}; };
@ -667,6 +676,8 @@ static struct section_perm ro_perms[] = {
.prot = PMD_SECT_APX | PMD_SECT_AP_WRITE, .prot = PMD_SECT_APX | PMD_SECT_AP_WRITE,
.clear = PMD_SECT_AP_WRITE, .clear = PMD_SECT_AP_WRITE,
#endif #endif
.ptemask = ~L_PTE_RDONLY,
.pteprot = L_PTE_RDONLY,
}, },
}; };
#endif #endif
@ -676,6 +687,35 @@ static struct section_perm ro_perms[] = {
* copied into each mm). During startup, this is the init_mm. Is only * copied into each mm). During startup, this is the init_mm. Is only
* safe to be called with preemption disabled, as under stop_machine(). * safe to be called with preemption disabled, as under stop_machine().
*/ */
struct pte_data {
pteval_t mask;
pteval_t val;
};
static int __pte_update(pte_t *ptep, pgtable_t token, unsigned long addr,
void *d)
{
struct pte_data *data = d;
pte_t pte = *ptep;
pte = __pte((pte_val(*ptep) & data->mask) | data->val);
set_pte_ext(ptep, pte, 0);
return 0;
}
static inline void pte_update(unsigned long addr, pteval_t mask,
pteval_t prot, struct mm_struct *mm)
{
struct pte_data data;
data.mask = mask;
data.val = prot;
apply_to_page_range(mm, addr, SECTION_SIZE, __pte_update, &data);
flush_tlb_kernel_range(addr, addr + SECTION_SIZE);
}
static inline void section_update(unsigned long addr, pmdval_t mask, static inline void section_update(unsigned long addr, pmdval_t mask,
pmdval_t prot, struct mm_struct *mm) pmdval_t prot, struct mm_struct *mm)
{ {
@ -724,11 +764,21 @@ void set_section_perms(struct section_perm *perms, int n, bool set,
for (addr = perms[i].start; for (addr = perms[i].start;
addr < perms[i].end; addr < perms[i].end;
addr += SECTION_SIZE) addr += SECTION_SIZE) {
section_update(addr, perms[i].mask, pmd_t *pmd;
set ? perms[i].prot : perms[i].clear, mm);
}
pmd = pmd_offset(pud_offset(pgd_offset(mm, addr),
addr), addr);
if (pmd_bad(*pmd))
section_update(addr, perms[i].mask,
set ? perms[i].prot : perms[i].clear,
mm);
else
pte_update(addr, perms[i].ptemask,
set ? perms[i].pteprot : perms[i].pteclear,
mm);
}
}
} }
static void update_sections_early(struct section_perm perms[], int n) static void update_sections_early(struct section_perm perms[], int n)