Merge "arm: mm: program ptes for access restriction"
This commit is contained in:
commit
8f0a76b8f6
4 changed files with 125 additions and 4 deletions
|
@ -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
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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)
|
||||||
|
|
Loading…
Add table
Reference in a new issue