diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2017-05-05 15:11:37 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2017-05-05 15:11:37 -0400 |
commit | ab182e67ec99ea0c8d7435a32a4a1ed9bb02559a (patch) | |
tree | fa71bef0067a61952561552c6652d922060f5530 /arch/arm64/mm/fault.c | |
parent | 7246f60068840847bdcf595be5f0b5ca632736e0 (diff) | |
parent | 92f66f84d9695d07adf9bc987bbcce4bf9b8e87c (diff) |
Merge tag 'arm64-upstream' of git://git.kernel.org/pub/scm/linux/kernel/git/arm64/linux
Pull arm64 updates from Catalin Marinas:
- kdump support, including two necessary memblock additions:
memblock_clear_nomap() and memblock_cap_memory_range()
- ARMv8.3 HWCAP bits for JavaScript conversion instructions, complex
numbers and weaker release consistency
- arm64 ACPI platform MSI support
- arm perf updates: ACPI PMU support, L3 cache PMU in some Qualcomm
SoCs, Cortex-A53 L2 cache events and DTLB refills, MAINTAINERS update
for DT perf bindings
- architected timer errata framework (the arch/arm64 changes only)
- support for DMA_ATTR_FORCE_CONTIGUOUS in the arm64 iommu DMA API
- arm64 KVM refactoring to use common system register definitions
- remove support for ASID-tagged VIVT I-cache (no ARMv8 implementation
using it and deprecated in the architecture) together with some
I-cache handling clean-up
- PE/COFF EFI header clean-up/hardening
- define BUG() instruction without CONFIG_BUG
* tag 'arm64-upstream' of git://git.kernel.org/pub/scm/linux/kernel/git/arm64/linux: (92 commits)
arm64: Fix the DMA mmap and get_sgtable API with DMA_ATTR_FORCE_CONTIGUOUS
arm64: Print DT machine model in setup_machine_fdt()
arm64: pmu: Wire-up Cortex A53 L2 cache events and DTLB refills
arm64: module: split core and init PLT sections
arm64: pmuv3: handle pmuv3+
arm64: Add CNTFRQ_EL0 trap handler
arm64: Silence spurious kbuild warning on menuconfig
arm64: pmuv3: use arm_pmu ACPI framework
arm64: pmuv3: handle !PMUv3 when probing
drivers/perf: arm_pmu: add ACPI framework
arm64: add function to get a cpu's MADT GICC table
drivers/perf: arm_pmu: split out platform device probe logic
drivers/perf: arm_pmu: move irq request/free into probe
drivers/perf: arm_pmu: split cpu-local irq request/free
drivers/perf: arm_pmu: rename irq request/free functions
drivers/perf: arm_pmu: handle no platform_device
drivers/perf: arm_pmu: simplify cpu_pmu_request_irqs()
drivers/perf: arm_pmu: factor out pmu registration
drivers/perf: arm_pmu: fold init into alloc
drivers/perf: arm_pmu: define armpmu_init_fn
...
Diffstat (limited to 'arch/arm64/mm/fault.c')
-rw-r--r-- | arch/arm64/mm/fault.c | 55 |
1 files changed, 36 insertions, 19 deletions
diff --git a/arch/arm64/mm/fault.c b/arch/arm64/mm/fault.c index 1b35b8bddbfb..37b95dff0b07 100644 --- a/arch/arm64/mm/fault.c +++ b/arch/arm64/mm/fault.c | |||
@@ -174,12 +174,33 @@ static bool is_el1_instruction_abort(unsigned int esr) | |||
174 | return ESR_ELx_EC(esr) == ESR_ELx_EC_IABT_CUR; | 174 | return ESR_ELx_EC(esr) == ESR_ELx_EC_IABT_CUR; |
175 | } | 175 | } |
176 | 176 | ||
177 | static inline bool is_permission_fault(unsigned int esr, struct pt_regs *regs, | ||
178 | unsigned long addr) | ||
179 | { | ||
180 | unsigned int ec = ESR_ELx_EC(esr); | ||
181 | unsigned int fsc_type = esr & ESR_ELx_FSC_TYPE; | ||
182 | |||
183 | if (ec != ESR_ELx_EC_DABT_CUR && ec != ESR_ELx_EC_IABT_CUR) | ||
184 | return false; | ||
185 | |||
186 | if (fsc_type == ESR_ELx_FSC_PERM) | ||
187 | return true; | ||
188 | |||
189 | if (addr < USER_DS && system_uses_ttbr0_pan()) | ||
190 | return fsc_type == ESR_ELx_FSC_FAULT && | ||
191 | (regs->pstate & PSR_PAN_BIT); | ||
192 | |||
193 | return false; | ||
194 | } | ||
195 | |||
177 | /* | 196 | /* |
178 | * The kernel tried to access some page that wasn't present. | 197 | * The kernel tried to access some page that wasn't present. |
179 | */ | 198 | */ |
180 | static void __do_kernel_fault(struct mm_struct *mm, unsigned long addr, | 199 | static void __do_kernel_fault(struct mm_struct *mm, unsigned long addr, |
181 | unsigned int esr, struct pt_regs *regs) | 200 | unsigned int esr, struct pt_regs *regs) |
182 | { | 201 | { |
202 | const char *msg; | ||
203 | |||
183 | /* | 204 | /* |
184 | * Are we prepared to handle this kernel fault? | 205 | * Are we prepared to handle this kernel fault? |
185 | * We are almost certainly not prepared to handle instruction faults. | 206 | * We are almost certainly not prepared to handle instruction faults. |
@@ -191,9 +212,20 @@ static void __do_kernel_fault(struct mm_struct *mm, unsigned long addr, | |||
191 | * No handler, we'll have to terminate things with extreme prejudice. | 212 | * No handler, we'll have to terminate things with extreme prejudice. |
192 | */ | 213 | */ |
193 | bust_spinlocks(1); | 214 | bust_spinlocks(1); |
194 | pr_alert("Unable to handle kernel %s at virtual address %08lx\n", | 215 | |
195 | (addr < PAGE_SIZE) ? "NULL pointer dereference" : | 216 | if (is_permission_fault(esr, regs, addr)) { |
196 | "paging request", addr); | 217 | if (esr & ESR_ELx_WNR) |
218 | msg = "write to read-only memory"; | ||
219 | else | ||
220 | msg = "read from unreadable memory"; | ||
221 | } else if (addr < PAGE_SIZE) { | ||
222 | msg = "NULL pointer dereference"; | ||
223 | } else { | ||
224 | msg = "paging request"; | ||
225 | } | ||
226 | |||
227 | pr_alert("Unable to handle kernel %s at virtual address %08lx\n", msg, | ||
228 | addr); | ||
197 | 229 | ||
198 | show_pte(mm, addr); | 230 | show_pte(mm, addr); |
199 | die("Oops", regs, esr); | 231 | die("Oops", regs, esr); |
@@ -287,21 +319,6 @@ out: | |||
287 | return fault; | 319 | return fault; |
288 | } | 320 | } |
289 | 321 | ||
290 | static inline bool is_permission_fault(unsigned int esr, struct pt_regs *regs) | ||
291 | { | ||
292 | unsigned int ec = ESR_ELx_EC(esr); | ||
293 | unsigned int fsc_type = esr & ESR_ELx_FSC_TYPE; | ||
294 | |||
295 | if (ec != ESR_ELx_EC_DABT_CUR && ec != ESR_ELx_EC_IABT_CUR) | ||
296 | return false; | ||
297 | |||
298 | if (system_uses_ttbr0_pan()) | ||
299 | return fsc_type == ESR_ELx_FSC_FAULT && | ||
300 | (regs->pstate & PSR_PAN_BIT); | ||
301 | else | ||
302 | return fsc_type == ESR_ELx_FSC_PERM; | ||
303 | } | ||
304 | |||
305 | static bool is_el0_instruction_abort(unsigned int esr) | 322 | static bool is_el0_instruction_abort(unsigned int esr) |
306 | { | 323 | { |
307 | return ESR_ELx_EC(esr) == ESR_ELx_EC_IABT_LOW; | 324 | return ESR_ELx_EC(esr) == ESR_ELx_EC_IABT_LOW; |
@@ -339,7 +356,7 @@ static int __kprobes do_page_fault(unsigned long addr, unsigned int esr, | |||
339 | mm_flags |= FAULT_FLAG_WRITE; | 356 | mm_flags |= FAULT_FLAG_WRITE; |
340 | } | 357 | } |
341 | 358 | ||
342 | if (addr < USER_DS && is_permission_fault(esr, regs)) { | 359 | if (addr < USER_DS && is_permission_fault(esr, regs, addr)) { |
343 | /* regs->orig_addr_limit may be 0 if we entered from EL0 */ | 360 | /* regs->orig_addr_limit may be 0 if we entered from EL0 */ |
344 | if (regs->orig_addr_limit == KERNEL_DS) | 361 | if (regs->orig_addr_limit == KERNEL_DS) |
345 | die("Accessing user space memory with fs=KERNEL_DS", regs, esr); | 362 | die("Accessing user space memory with fs=KERNEL_DS", regs, esr); |