Commit a507f25d authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'arm64-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/arm64/linux

Pull arm64 fixes from Catalin Marinas:

 - Update the compat layer to allow single-byte watchpoints on all
   addresses (similar to the native support)

 - arm_pmu: fix the restoration of the counters on the
   CPU_PM_ENTER_FAILED path

 - Fix build regression with vDSO and Makefile not stripping
   CROSS_COMPILE_COMPAT

 - Fix the CTR_EL0 (cache type register) sanitisation on heterogeneous
   machines (e.g. big.LITTLE)

 - Fix the interrupt controller priority mask value when pseudo-NMIs are
   enabled

 - arm64 kprobes fixes: recovering of the PSTATE.D flag in the
   single-step exception handler, NOKPROBE annotations for
   unwind_frame() and walk_stackframe(), remove unneeded
   rcu_read_lock/unlock from debug handlers

 - Several gcc fall-through warnings

 - Unused variable warnings

* tag 'arm64-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/arm64/linux:
  arm64: Make debug exception handlers visible from RCU
  arm64: kprobes: Recover pstate.D in single-step exception handler
  arm64/mm: fix variable 'tag' set but not used
  arm64/mm: fix variable 'pud' set but not used
  arm64: Remove unneeded rcu_read_lock from debug handlers
  arm64: unwind: Prohibit probing on return_address()
  arm64: Lower priority mask for GIC_PRIO_IRQON
  arm64/efi: fix variable 'si' set but not used
  arm64: cpufeature: Fix feature comparison for CTR_EL0.{CWG,ERG}
  arm64: vdso: Fix Makefile regression
  arm64: module: Mark expected switch fall-through
  arm64: smp: Mark expected switch fall-through
  arm64: hw_breakpoint: Fix warnings about implicit fallthrough
  drivers/perf: arm_pmu: Fix failure path in PM notifier
  arm64: compat: Allow single-byte watchpoints on all addresses
parents 9100fc5a d8bb6718
...@@ -52,7 +52,7 @@ ifeq ($(CONFIG_GENERIC_COMPAT_VDSO), y) ...@@ -52,7 +52,7 @@ ifeq ($(CONFIG_GENERIC_COMPAT_VDSO), y)
ifeq ($(CONFIG_CC_IS_CLANG), y) ifeq ($(CONFIG_CC_IS_CLANG), y)
$(warning CROSS_COMPILE_COMPAT is clang, the compat vDSO will not be built) $(warning CROSS_COMPILE_COMPAT is clang, the compat vDSO will not be built)
else ifeq ($(CROSS_COMPILE_COMPAT),) else ifeq ($(strip $(CROSS_COMPILE_COMPAT)),)
$(warning CROSS_COMPILE_COMPAT not defined or empty, the compat vDSO will not be built) $(warning CROSS_COMPILE_COMPAT not defined or empty, the compat vDSO will not be built)
else ifeq ($(shell which $(CROSS_COMPILE_COMPAT)gcc 2> /dev/null),) else ifeq ($(shell which $(CROSS_COMPILE_COMPAT)gcc 2> /dev/null),)
$(error $(CROSS_COMPILE_COMPAT)gcc not found, check CROSS_COMPILE_COMPAT) $(error $(CROSS_COMPILE_COMPAT)gcc not found, check CROSS_COMPILE_COMPAT)
......
...@@ -155,6 +155,12 @@ static inline void gic_pmr_mask_irqs(void) ...@@ -155,6 +155,12 @@ static inline void gic_pmr_mask_irqs(void)
BUILD_BUG_ON(GICD_INT_DEF_PRI < (GIC_PRIO_IRQOFF | BUILD_BUG_ON(GICD_INT_DEF_PRI < (GIC_PRIO_IRQOFF |
GIC_PRIO_PSR_I_SET)); GIC_PRIO_PSR_I_SET));
BUILD_BUG_ON(GICD_INT_DEF_PRI >= GIC_PRIO_IRQON); BUILD_BUG_ON(GICD_INT_DEF_PRI >= GIC_PRIO_IRQON);
/*
* Need to make sure IRQON allows IRQs when SCR_EL3.FIQ is cleared
* and non-secure PMR accesses are not subject to the shifts that
* are applied to IRQ priorities
*/
BUILD_BUG_ON((0x80 | (GICD_INT_DEF_PRI >> 1)) >= GIC_PRIO_IRQON);
gic_write_pmr(GIC_PRIO_IRQOFF); gic_write_pmr(GIC_PRIO_IRQOFF);
} }
......
...@@ -35,9 +35,10 @@ ...@@ -35,9 +35,10 @@
*/ */
enum ftr_type { enum ftr_type {
FTR_EXACT, /* Use a predefined safe value */ FTR_EXACT, /* Use a predefined safe value */
FTR_LOWER_SAFE, /* Smaller value is safe */ FTR_LOWER_SAFE, /* Smaller value is safe */
FTR_HIGHER_SAFE,/* Bigger value is safe */ FTR_HIGHER_SAFE, /* Bigger value is safe */
FTR_HIGHER_OR_ZERO_SAFE, /* Bigger value is safe, but 0 is biggest */
}; };
#define FTR_STRICT true /* SANITY check strict matching required */ #define FTR_STRICT true /* SANITY check strict matching required */
......
...@@ -13,6 +13,8 @@ ...@@ -13,6 +13,8 @@
#define DAIF_PROCCTX 0 #define DAIF_PROCCTX 0
#define DAIF_PROCCTX_NOIRQ PSR_I_BIT #define DAIF_PROCCTX_NOIRQ PSR_I_BIT
#define DAIF_ERRCTX (PSR_I_BIT | PSR_A_BIT) #define DAIF_ERRCTX (PSR_I_BIT | PSR_A_BIT)
#define DAIF_MASK (PSR_D_BIT | PSR_A_BIT | PSR_I_BIT | PSR_F_BIT)
/* mask/save/unmask/restore all exceptions, including interrupts. */ /* mask/save/unmask/restore all exceptions, including interrupts. */
static inline void local_daif_mask(void) static inline void local_daif_mask(void)
......
...@@ -105,7 +105,11 @@ static inline unsigned long efi_get_max_initrd_addr(unsigned long dram_base, ...@@ -105,7 +105,11 @@ static inline unsigned long efi_get_max_initrd_addr(unsigned long dram_base,
((protocol##_t *)instance)->f(instance, ##__VA_ARGS__) ((protocol##_t *)instance)->f(instance, ##__VA_ARGS__)
#define alloc_screen_info(x...) &screen_info #define alloc_screen_info(x...) &screen_info
#define free_screen_info(x...)
static inline void free_screen_info(efi_system_table_t *sys_table_arg,
struct screen_info *si)
{
}
/* redeclare as 'hidden' so the compiler will generate relative references */ /* redeclare as 'hidden' so the compiler will generate relative references */
extern struct screen_info screen_info __attribute__((__visibility__("hidden"))); extern struct screen_info screen_info __attribute__((__visibility__("hidden")));
......
...@@ -210,7 +210,11 @@ extern u64 vabits_user; ...@@ -210,7 +210,11 @@ extern u64 vabits_user;
#define __tag_reset(addr) untagged_addr(addr) #define __tag_reset(addr) untagged_addr(addr)
#define __tag_get(addr) (__u8)((u64)(addr) >> 56) #define __tag_get(addr) (__u8)((u64)(addr) >> 56)
#else #else
#define __tag_set(addr, tag) (addr) static inline const void *__tag_set(const void *addr, u8 tag)
{
return addr;
}
#define __tag_reset(addr) (addr) #define __tag_reset(addr) (addr)
#define __tag_get(addr) 0 #define __tag_get(addr) 0
#endif #endif
...@@ -301,8 +305,8 @@ static inline void *phys_to_virt(phys_addr_t x) ...@@ -301,8 +305,8 @@ static inline void *phys_to_virt(phys_addr_t x)
#define page_to_virt(page) ({ \ #define page_to_virt(page) ({ \
unsigned long __addr = \ unsigned long __addr = \
((__page_to_voff(page)) | PAGE_OFFSET); \ ((__page_to_voff(page)) | PAGE_OFFSET); \
unsigned long __addr_tag = \ const void *__addr_tag = \
__tag_set(__addr, page_kasan_tag(page)); \ __tag_set((void *)__addr, page_kasan_tag(page)); \
((void *)__addr_tag); \ ((void *)__addr_tag); \
}) })
......
...@@ -447,8 +447,8 @@ extern pgprot_t phys_mem_access_prot(struct file *file, unsigned long pfn, ...@@ -447,8 +447,8 @@ extern pgprot_t phys_mem_access_prot(struct file *file, unsigned long pfn,
PMD_TYPE_SECT) PMD_TYPE_SECT)
#if defined(CONFIG_ARM64_64K_PAGES) || CONFIG_PGTABLE_LEVELS < 3 #if defined(CONFIG_ARM64_64K_PAGES) || CONFIG_PGTABLE_LEVELS < 3
#define pud_sect(pud) (0) static inline bool pud_sect(pud_t pud) { return false; }
#define pud_table(pud) (1) static inline bool pud_table(pud_t pud) { return true; }
#else #else
#define pud_sect(pud) ((pud_val(pud) & PUD_TYPE_MASK) == \ #define pud_sect(pud) ((pud_val(pud) & PUD_TYPE_MASK) == \
PUD_TYPE_SECT) PUD_TYPE_SECT)
......
...@@ -30,7 +30,7 @@ ...@@ -30,7 +30,7 @@
* in the the priority mask, it indicates that PSR.I should be set and * in the the priority mask, it indicates that PSR.I should be set and
* interrupt disabling temporarily does not rely on IRQ priorities. * interrupt disabling temporarily does not rely on IRQ priorities.
*/ */
#define GIC_PRIO_IRQON 0xc0 #define GIC_PRIO_IRQON 0xe0
#define GIC_PRIO_IRQOFF (GIC_PRIO_IRQON & ~0x80) #define GIC_PRIO_IRQOFF (GIC_PRIO_IRQON & ~0x80)
#define GIC_PRIO_PSR_I_SET (1 << 4) #define GIC_PRIO_PSR_I_SET (1 << 4)
......
...@@ -225,8 +225,8 @@ static const struct arm64_ftr_bits ftr_ctr[] = { ...@@ -225,8 +225,8 @@ static const struct arm64_ftr_bits ftr_ctr[] = {
ARM64_FTR_BITS(FTR_VISIBLE, FTR_STRICT, FTR_EXACT, 31, 1, 1), /* RES1 */ ARM64_FTR_BITS(FTR_VISIBLE, FTR_STRICT, FTR_EXACT, 31, 1, 1), /* RES1 */
ARM64_FTR_BITS(FTR_VISIBLE, FTR_STRICT, FTR_LOWER_SAFE, CTR_DIC_SHIFT, 1, 1), ARM64_FTR_BITS(FTR_VISIBLE, FTR_STRICT, FTR_LOWER_SAFE, CTR_DIC_SHIFT, 1, 1),
ARM64_FTR_BITS(FTR_VISIBLE, FTR_STRICT, FTR_LOWER_SAFE, CTR_IDC_SHIFT, 1, 1), ARM64_FTR_BITS(FTR_VISIBLE, FTR_STRICT, FTR_LOWER_SAFE, CTR_IDC_SHIFT, 1, 1),
ARM64_FTR_BITS(FTR_VISIBLE, FTR_STRICT, FTR_HIGHER_SAFE, CTR_CWG_SHIFT, 4, 0), ARM64_FTR_BITS(FTR_VISIBLE, FTR_STRICT, FTR_HIGHER_OR_ZERO_SAFE, CTR_CWG_SHIFT, 4, 0),
ARM64_FTR_BITS(FTR_VISIBLE, FTR_STRICT, FTR_HIGHER_SAFE, CTR_ERG_SHIFT, 4, 0), ARM64_FTR_BITS(FTR_VISIBLE, FTR_STRICT, FTR_HIGHER_OR_ZERO_SAFE, CTR_ERG_SHIFT, 4, 0),
ARM64_FTR_BITS(FTR_VISIBLE, FTR_STRICT, FTR_LOWER_SAFE, CTR_DMINLINE_SHIFT, 4, 1), ARM64_FTR_BITS(FTR_VISIBLE, FTR_STRICT, FTR_LOWER_SAFE, CTR_DMINLINE_SHIFT, 4, 1),
/* /*
* Linux can handle differing I-cache policies. Userspace JITs will * Linux can handle differing I-cache policies. Userspace JITs will
...@@ -468,6 +468,10 @@ static s64 arm64_ftr_safe_value(const struct arm64_ftr_bits *ftrp, s64 new, ...@@ -468,6 +468,10 @@ static s64 arm64_ftr_safe_value(const struct arm64_ftr_bits *ftrp, s64 new,
case FTR_LOWER_SAFE: case FTR_LOWER_SAFE:
ret = new < cur ? new : cur; ret = new < cur ? new : cur;
break; break;
case FTR_HIGHER_OR_ZERO_SAFE:
if (!cur || !new)
break;
/* Fallthrough */
case FTR_HIGHER_SAFE: case FTR_HIGHER_SAFE:
ret = new > cur ? new : cur; ret = new > cur ? new : cur;
break; break;
......
...@@ -207,16 +207,16 @@ static int call_step_hook(struct pt_regs *regs, unsigned int esr) ...@@ -207,16 +207,16 @@ static int call_step_hook(struct pt_regs *regs, unsigned int esr)
list = user_mode(regs) ? &user_step_hook : &kernel_step_hook; list = user_mode(regs) ? &user_step_hook : &kernel_step_hook;
rcu_read_lock(); /*
* Since single-step exception disables interrupt, this function is
* entirely not preemptible, and we can use rcu list safely here.
*/
list_for_each_entry_rcu(hook, list, node) { list_for_each_entry_rcu(hook, list, node) {
retval = hook->fn(regs, esr); retval = hook->fn(regs, esr);
if (retval == DBG_HOOK_HANDLED) if (retval == DBG_HOOK_HANDLED)
break; break;
} }
rcu_read_unlock();
return retval; return retval;
} }
NOKPROBE_SYMBOL(call_step_hook); NOKPROBE_SYMBOL(call_step_hook);
...@@ -305,14 +305,16 @@ static int call_break_hook(struct pt_regs *regs, unsigned int esr) ...@@ -305,14 +305,16 @@ static int call_break_hook(struct pt_regs *regs, unsigned int esr)
list = user_mode(regs) ? &user_break_hook : &kernel_break_hook; list = user_mode(regs) ? &user_break_hook : &kernel_break_hook;
rcu_read_lock(); /*
* Since brk exception disables interrupt, this function is
* entirely not preemptible, and we can use rcu list safely here.
*/
list_for_each_entry_rcu(hook, list, node) { list_for_each_entry_rcu(hook, list, node) {
unsigned int comment = esr & ESR_ELx_BRK64_ISS_COMMENT_MASK; unsigned int comment = esr & ESR_ELx_BRK64_ISS_COMMENT_MASK;
if ((comment & ~hook->mask) == hook->imm) if ((comment & ~hook->mask) == hook->imm)
fn = hook->fn; fn = hook->fn;
} }
rcu_read_unlock();
return fn ? fn(regs, esr) : DBG_HOOK_ERROR; return fn ? fn(regs, esr) : DBG_HOOK_ERROR;
} }
......
...@@ -536,13 +536,18 @@ int hw_breakpoint_arch_parse(struct perf_event *bp, ...@@ -536,13 +536,18 @@ int hw_breakpoint_arch_parse(struct perf_event *bp,
/* Aligned */ /* Aligned */
break; break;
case 1: case 1:
/* Allow single byte watchpoint. */
if (hw->ctrl.len == ARM_BREAKPOINT_LEN_1)
break;
case 2: case 2:
/* Allow halfword watchpoints and breakpoints. */ /* Allow halfword watchpoints and breakpoints. */
if (hw->ctrl.len == ARM_BREAKPOINT_LEN_2) if (hw->ctrl.len == ARM_BREAKPOINT_LEN_2)
break; break;
/* Fallthrough */
case 3:
/* Allow single byte watchpoint. */
if (hw->ctrl.len == ARM_BREAKPOINT_LEN_1)
break;
/* Fallthrough */
default: default:
return -EINVAL; return -EINVAL;
} }
......
...@@ -314,18 +314,21 @@ int apply_relocate_add(Elf64_Shdr *sechdrs, ...@@ -314,18 +314,21 @@ int apply_relocate_add(Elf64_Shdr *sechdrs,
/* MOVW instruction relocations. */ /* MOVW instruction relocations. */
case R_AARCH64_MOVW_UABS_G0_NC: case R_AARCH64_MOVW_UABS_G0_NC:
overflow_check = false; overflow_check = false;
/* Fall through */
case R_AARCH64_MOVW_UABS_G0: case R_AARCH64_MOVW_UABS_G0:
ovf = reloc_insn_movw(RELOC_OP_ABS, loc, val, 0, ovf = reloc_insn_movw(RELOC_OP_ABS, loc, val, 0,
AARCH64_INSN_IMM_MOVKZ); AARCH64_INSN_IMM_MOVKZ);
break; break;
case R_AARCH64_MOVW_UABS_G1_NC: case R_AARCH64_MOVW_UABS_G1_NC:
overflow_check = false; overflow_check = false;
/* Fall through */
case R_AARCH64_MOVW_UABS_G1: case R_AARCH64_MOVW_UABS_G1:
ovf = reloc_insn_movw(RELOC_OP_ABS, loc, val, 16, ovf = reloc_insn_movw(RELOC_OP_ABS, loc, val, 16,
AARCH64_INSN_IMM_MOVKZ); AARCH64_INSN_IMM_MOVKZ);
break; break;
case R_AARCH64_MOVW_UABS_G2_NC: case R_AARCH64_MOVW_UABS_G2_NC:
overflow_check = false; overflow_check = false;
/* Fall through */
case R_AARCH64_MOVW_UABS_G2: case R_AARCH64_MOVW_UABS_G2:
ovf = reloc_insn_movw(RELOC_OP_ABS, loc, val, 32, ovf = reloc_insn_movw(RELOC_OP_ABS, loc, val, 32,
AARCH64_INSN_IMM_MOVKZ); AARCH64_INSN_IMM_MOVKZ);
...@@ -393,6 +396,7 @@ int apply_relocate_add(Elf64_Shdr *sechdrs, ...@@ -393,6 +396,7 @@ int apply_relocate_add(Elf64_Shdr *sechdrs,
break; break;
case R_AARCH64_ADR_PREL_PG_HI21_NC: case R_AARCH64_ADR_PREL_PG_HI21_NC:
overflow_check = false; overflow_check = false;
/* Fall through */
case R_AARCH64_ADR_PREL_PG_HI21: case R_AARCH64_ADR_PREL_PG_HI21:
ovf = reloc_insn_adrp(me, sechdrs, loc, val); ovf = reloc_insn_adrp(me, sechdrs, loc, val);
if (ovf && ovf != -ERANGE) if (ovf && ovf != -ERANGE)
......
...@@ -21,6 +21,7 @@ ...@@ -21,6 +21,7 @@
#include <asm/ptrace.h> #include <asm/ptrace.h>
#include <asm/cacheflush.h> #include <asm/cacheflush.h>
#include <asm/debug-monitors.h> #include <asm/debug-monitors.h>
#include <asm/daifflags.h>
#include <asm/system_misc.h> #include <asm/system_misc.h>
#include <asm/insn.h> #include <asm/insn.h>
#include <linux/uaccess.h> #include <linux/uaccess.h>
...@@ -167,33 +168,6 @@ static void __kprobes set_current_kprobe(struct kprobe *p) ...@@ -167,33 +168,6 @@ static void __kprobes set_current_kprobe(struct kprobe *p)
__this_cpu_write(current_kprobe, p); __this_cpu_write(current_kprobe, p);
} }
/*
* When PSTATE.D is set (masked), then software step exceptions can not be
* generated.
* SPSR's D bit shows the value of PSTATE.D immediately before the
* exception was taken. PSTATE.D is set while entering into any exception
* mode, however software clears it for any normal (none-debug-exception)
* mode in the exception entry. Therefore, when we are entering into kprobe
* breakpoint handler from any normal mode then SPSR.D bit is already
* cleared, however it is set when we are entering from any debug exception
* mode.
* Since we always need to generate single step exception after a kprobe
* breakpoint exception therefore we need to clear it unconditionally, when
* we become sure that the current breakpoint exception is for kprobe.
*/
static void __kprobes
spsr_set_debug_flag(struct pt_regs *regs, int mask)
{
unsigned long spsr = regs->pstate;
if (mask)
spsr |= PSR_D_BIT;
else
spsr &= ~PSR_D_BIT;
regs->pstate = spsr;
}
/* /*
* Interrupts need to be disabled before single-step mode is set, and not * Interrupts need to be disabled before single-step mode is set, and not
* reenabled until after single-step mode ends. * reenabled until after single-step mode ends.
...@@ -205,17 +179,17 @@ spsr_set_debug_flag(struct pt_regs *regs, int mask) ...@@ -205,17 +179,17 @@ spsr_set_debug_flag(struct pt_regs *regs, int mask)
static void __kprobes kprobes_save_local_irqflag(struct kprobe_ctlblk *kcb, static void __kprobes kprobes_save_local_irqflag(struct kprobe_ctlblk *kcb,
struct pt_regs *regs) struct pt_regs *regs)
{ {
kcb->saved_irqflag = regs->pstate; kcb->saved_irqflag = regs->pstate & DAIF_MASK;
regs->pstate |= PSR_I_BIT; regs->pstate |= PSR_I_BIT;
/* Unmask PSTATE.D for enabling software step exceptions. */
regs->pstate &= ~PSR_D_BIT;
} }
static void __kprobes kprobes_restore_local_irqflag(struct kprobe_ctlblk *kcb, static void __kprobes kprobes_restore_local_irqflag(struct kprobe_ctlblk *kcb,
struct pt_regs *regs) struct pt_regs *regs)
{ {
if (kcb->saved_irqflag & PSR_I_BIT) regs->pstate &= ~DAIF_MASK;
regs->pstate |= PSR_I_BIT; regs->pstate |= kcb->saved_irqflag;
else
regs->pstate &= ~PSR_I_BIT;
} }
static void __kprobes static void __kprobes
...@@ -252,8 +226,6 @@ static void __kprobes setup_singlestep(struct kprobe *p, ...@@ -252,8 +226,6 @@ static void __kprobes setup_singlestep(struct kprobe *p,
set_ss_context(kcb, slot); /* mark pending ss */ set_ss_context(kcb, slot); /* mark pending ss */
spsr_set_debug_flag(regs, 0);
/* IRQs and single stepping do not mix well. */ /* IRQs and single stepping do not mix well. */
kprobes_save_local_irqflag(kcb, regs); kprobes_save_local_irqflag(kcb, regs);
kernel_enable_single_step(regs); kernel_enable_single_step(regs);
......
...@@ -8,6 +8,7 @@ ...@@ -8,6 +8,7 @@
#include <linux/export.h> #include <linux/export.h>
#include <linux/ftrace.h> #include <linux/ftrace.h>
#include <linux/kprobes.h>
#include <asm/stack_pointer.h> #include <asm/stack_pointer.h>
#include <asm/stacktrace.h> #include <asm/stacktrace.h>
...@@ -29,6 +30,7 @@ static int save_return_addr(struct stackframe *frame, void *d) ...@@ -29,6 +30,7 @@ static int save_return_addr(struct stackframe *frame, void *d)
return 0; return 0;
} }
} }
NOKPROBE_SYMBOL(save_return_addr);
void *return_address(unsigned int level) void *return_address(unsigned int level)
{ {
...@@ -49,3 +51,4 @@ void *return_address(unsigned int level) ...@@ -49,3 +51,4 @@ void *return_address(unsigned int level)
return NULL; return NULL;
} }
EXPORT_SYMBOL_GPL(return_address); EXPORT_SYMBOL_GPL(return_address);
NOKPROBE_SYMBOL(return_address);
...@@ -152,8 +152,8 @@ int __cpu_up(unsigned int cpu, struct task_struct *idle) ...@@ -152,8 +152,8 @@ int __cpu_up(unsigned int cpu, struct task_struct *idle)
pr_crit("CPU%u: died during early boot\n", cpu); pr_crit("CPU%u: died during early boot\n", cpu);
break; break;
} }
/* Fall through */
pr_crit("CPU%u: may not have shut down cleanly\n", cpu); pr_crit("CPU%u: may not have shut down cleanly\n", cpu);
/* Fall through */
case CPU_STUCK_IN_KERNEL: case CPU_STUCK_IN_KERNEL:
pr_crit("CPU%u: is stuck in kernel\n", cpu); pr_crit("CPU%u: is stuck in kernel\n", cpu);
if (status & CPU_STUCK_REASON_52_BIT_VA) if (status & CPU_STUCK_REASON_52_BIT_VA)
......
...@@ -7,6 +7,7 @@ ...@@ -7,6 +7,7 @@
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/export.h> #include <linux/export.h>
#include <linux/ftrace.h> #include <linux/ftrace.h>
#include <linux/kprobes.h>
#include <linux/sched.h> #include <linux/sched.h>
#include <linux/sched/debug.h> #include <linux/sched/debug.h>
#include <linux/sched/task_stack.h> #include <linux/sched/task_stack.h>
...@@ -111,6 +112,7 @@ int notrace unwind_frame(struct task_struct *tsk, struct stackframe *frame) ...@@ -111,6 +112,7 @@ int notrace unwind_frame(struct task_struct *tsk, struct stackframe *frame)
return 0; return 0;
} }
NOKPROBE_SYMBOL(unwind_frame);
void notrace walk_stackframe(struct task_struct *tsk, struct stackframe *frame, void notrace walk_stackframe(struct task_struct *tsk, struct stackframe *frame,
int (*fn)(struct stackframe *, void *), void *data) int (*fn)(struct stackframe *, void *), void *data)
...@@ -125,6 +127,7 @@ void notrace walk_stackframe(struct task_struct *tsk, struct stackframe *frame, ...@@ -125,6 +127,7 @@ void notrace walk_stackframe(struct task_struct *tsk, struct stackframe *frame,
break; break;
} }
} }
NOKPROBE_SYMBOL(walk_stackframe);
#ifdef CONFIG_STACKTRACE #ifdef CONFIG_STACKTRACE
struct stack_trace_data { struct stack_trace_data {
......
...@@ -777,6 +777,53 @@ void __init hook_debug_fault_code(int nr, ...@@ -777,6 +777,53 @@ void __init hook_debug_fault_code(int nr,
debug_fault_info[nr].name = name; debug_fault_info[nr].name = name;
} }
/*
* In debug exception context, we explicitly disable preemption despite
* having interrupts disabled.
* This serves two purposes: it makes it much less likely that we would
* accidentally schedule in exception context and it will force a warning
* if we somehow manage to schedule by accident.
*/
static void debug_exception_enter(struct pt_regs *regs)
{
/*
* Tell lockdep we disabled irqs in entry.S. Do nothing if they were
* already disabled to preserve the last enabled/disabled addresses.
*/
if (interrupts_enabled(regs))
trace_hardirqs_off();
if (user_mode(regs)) {
RCU_LOCKDEP_WARN(!rcu_is_watching(), "entry code didn't wake RCU");
} else {
/*
* We might have interrupted pretty much anything. In
* fact, if we're a debug exception, we can even interrupt
* NMI processing. We don't want this code makes in_nmi()
* to return true, but we need to notify RCU.
*/
rcu_nmi_enter();
}
preempt_disable();
/* This code is a bit fragile. Test it. */
RCU_LOCKDEP_WARN(!rcu_is_watching(), "exception_enter didn't work");
}
NOKPROBE_SYMBOL(debug_exception_enter);
static void debug_exception_exit(struct pt_regs *regs)
{
preempt_enable_no_resched();
if (!user_mode(regs))
rcu_nmi_exit();
if (interrupts_enabled(regs))
trace_hardirqs_on();
}
NOKPROBE_SYMBOL(debug_exception_exit);
#ifdef CONFIG_ARM64_ERRATUM_1463225 #ifdef CONFIG_ARM64_ERRATUM_1463225
DECLARE_PER_CPU(int, __in_cortex_a76_erratum_1463225_wa); DECLARE_PER_CPU(int, __in_cortex_a76_erratum_1463225_wa);
...@@ -817,12 +864,7 @@ asmlinkage void __exception do_debug_exception(unsigned long addr_if_watchpoint, ...@@ -817,12 +864,7 @@ asmlinkage void __exception do_debug_exception(unsigned long addr_if_watchpoint,
if (cortex_a76_erratum_1463225_debug_handler(regs)) if (cortex_a76_erratum_1463225_debug_handler(regs))
return; return;
/* debug_exception_enter(regs);
* Tell lockdep we disabled irqs in entry.S. Do nothing if they were
* already disabled to preserve the last enabled/disabled addresses.
*/
if (interrupts_enabled(regs))
trace_hardirqs_off();
if (user_mode(regs) && !is_ttbr0_addr(pc)) if (user_mode(regs) && !is_ttbr0_addr(pc))
arm64_apply_bp_hardening(); arm64_apply_bp_hardening();
...@@ -832,7 +874,6 @@ asmlinkage void __exception do_debug_exception(unsigned long addr_if_watchpoint, ...@@ -832,7 +874,6 @@ asmlinkage void __exception do_debug_exception(unsigned long addr_if_watchpoint,
inf->sig, inf->code, (void __user *)pc, esr); inf->sig, inf->code, (void __user *)pc, esr);
} }
if (interrupts_enabled(regs)) debug_exception_exit(regs);
trace_hardirqs_on();
} }
NOKPROBE_SYMBOL(do_debug_exception); NOKPROBE_SYMBOL(do_debug_exception);
...@@ -723,8 +723,8 @@ static int cpu_pm_pmu_notify(struct notifier_block *b, unsigned long cmd, ...@@ -723,8 +723,8 @@ static int cpu_pm_pmu_notify(struct notifier_block *b, unsigned long cmd,
cpu_pm_pmu_setup(armpmu, cmd); cpu_pm_pmu_setup(armpmu, cmd);
break; break;
case CPU_PM_EXIT: case CPU_PM_EXIT:
cpu_pm_pmu_setup(armpmu, cmd);
case CPU_PM_ENTER_FAILED: case CPU_PM_ENTER_FAILED:
cpu_pm_pmu_setup(armpmu, cmd);
armpmu->start(armpmu); armpmu->start(armpmu);
break; break;
default: default:
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment