Commit 7782aae4 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'for-linus' of git://git.armlinux.org.uk/~rmk/linux-arm

Pull ARM updates from Russell King:

 - Print an un-hashed userspace PC on undefined instruction exception

 - Disable FDPIC ABI

 - Remove redundant vfp_flush/release_thread functions

 - Use raw_cpu_* rather than this_cpu_* in handle_bad_stack()

 - Avoid needlessly long backtraces when show_regs() is called

 - Fix an issue with stack traces through call_with_stack()

 - Avoid stack traces saving a duplicate exception PC value

 - Pass a void pointer to virt_to_page() in DMA mapping code

 - Fix kasan maps for modules when CONFIG_KASAN_VMALLOC=n

 - Show FDT region and page table level names in kernel page tables dump

* tag 'for-linus' of git://git.armlinux.org.uk/~rmk/linux-arm:
  ARM: 9246/1: dump: show page table level name
  ARM: 9245/1: dump: show FDT region
  ARM: 9242/1: kasan: Only map modules if CONFIG_KASAN_VMALLOC=n
  ARM: 9240/1: dma-mapping: Pass (void *) to virt_to_page()
  ARM: 9234/1: stacktrace: Avoid duplicate saving of exception PC value
  ARM: 9233/1: stacktrace: Skip frame pointer boundary check for call_with_stack()
  ARM: 9224/1: Dump the stack traces based on the parameter 'regs' of show_regs()
  ARM: 9232/1: Replace this_cpu_* with raw_cpu_* in handle_bad_stack()
  ARM: 9228/1: vfp: kill vfp_flush/release_thread()
  ARM: 9226/1: disable FDPIC ABI
  ARM: 9221/1: traps: print un-hashed user pc on undefined instruction
parents 833477fc e66372ec
...@@ -22,6 +22,9 @@ GZFLAGS :=-9 ...@@ -22,6 +22,9 @@ GZFLAGS :=-9
# Never generate .eh_frame # Never generate .eh_frame
KBUILD_CFLAGS += $(call cc-option,-fno-dwarf2-cfi-asm) KBUILD_CFLAGS += $(call cc-option,-fno-dwarf2-cfi-asm)
# Disable FDPIC ABI
KBUILD_CFLAGS += $(call cc-option,-mno-fdpic)
# This should work on most of the modern platforms # This should work on most of the modern platforms
KBUILD_DEFCONFIG := multi_v7_defconfig KBUILD_DEFCONFIG := multi_v7_defconfig
......
...@@ -46,9 +46,6 @@ union vfp_state { ...@@ -46,9 +46,6 @@ union vfp_state {
struct vfp_hard_struct hard; struct vfp_hard_struct hard;
}; };
extern void vfp_flush_thread(union vfp_state *);
extern void vfp_release_thread(union vfp_state *);
#define FP_HARD_SIZE 35 #define FP_HARD_SIZE 35
struct fp_hard_struct { struct fp_hard_struct {
......
...@@ -21,6 +21,9 @@ struct stackframe { ...@@ -21,6 +21,9 @@ struct stackframe {
struct llist_node *kr_cur; struct llist_node *kr_cur;
struct task_struct *tsk; struct task_struct *tsk;
#endif #endif
#ifdef CONFIG_UNWINDER_FRAME_POINTER
bool ex_frame;
#endif
}; };
static __always_inline static __always_inline
...@@ -34,6 +37,9 @@ void arm_get_current_stackframe(struct pt_regs *regs, struct stackframe *frame) ...@@ -34,6 +37,9 @@ void arm_get_current_stackframe(struct pt_regs *regs, struct stackframe *frame)
frame->kr_cur = NULL; frame->kr_cur = NULL;
frame->tsk = current; frame->tsk = current;
#endif #endif
#ifdef CONFIG_UNWINDER_FRAME_POINTER
frame->ex_frame = in_entry_text(frame->pc);
#endif
} }
extern int unwind_frame(struct stackframe *frame); extern int unwind_frame(struct stackframe *frame);
...@@ -41,5 +47,7 @@ extern void walk_stackframe(struct stackframe *frame, ...@@ -41,5 +47,7 @@ extern void walk_stackframe(struct stackframe *frame,
int (*fn)(struct stackframe *, void *), void *data); int (*fn)(struct stackframe *, void *), void *data);
extern void dump_mem(const char *lvl, const char *str, unsigned long bottom, extern void dump_mem(const char *lvl, const char *str, unsigned long bottom,
unsigned long top); unsigned long top);
extern void dump_backtrace(struct pt_regs *regs, struct task_struct *tsk,
const char *loglvl);
#endif /* __ASM_STACKTRACE_H */ #endif /* __ASM_STACKTRACE_H */
...@@ -201,7 +201,7 @@ void __show_regs(struct pt_regs *regs) ...@@ -201,7 +201,7 @@ void __show_regs(struct pt_regs *regs)
void show_regs(struct pt_regs * regs) void show_regs(struct pt_regs * regs)
{ {
__show_regs(regs); __show_regs(regs);
dump_stack(); dump_backtrace(regs, NULL, KERN_DEFAULT);
} }
ATOMIC_NOTIFIER_HEAD(thread_notify_head); ATOMIC_NOTIFIER_HEAD(thread_notify_head);
......
...@@ -47,6 +47,7 @@ void *return_address(unsigned int level) ...@@ -47,6 +47,7 @@ void *return_address(unsigned int level)
frame.kr_cur = NULL; frame.kr_cur = NULL;
frame.tsk = current; frame.tsk = current;
#endif #endif
frame.ex_frame = false;
walk_stackframe(&frame, save_return_addr, &data); walk_stackframe(&frame, save_return_addr, &data);
......
...@@ -9,6 +9,8 @@ ...@@ -9,6 +9,8 @@
#include <asm/stacktrace.h> #include <asm/stacktrace.h>
#include <asm/traps.h> #include <asm/traps.h>
#include "reboot.h"
#if defined(CONFIG_FRAME_POINTER) && !defined(CONFIG_ARM_UNWIND) #if defined(CONFIG_FRAME_POINTER) && !defined(CONFIG_ARM_UNWIND)
/* /*
* Unwind the current stack frame and store the new register values in the * Unwind the current stack frame and store the new register values in the
...@@ -39,29 +41,74 @@ ...@@ -39,29 +41,74 @@
* Note that with framepointer enabled, even the leaf functions have the same * Note that with framepointer enabled, even the leaf functions have the same
* prologue and epilogue, therefore we can ignore the LR value in this case. * prologue and epilogue, therefore we can ignore the LR value in this case.
*/ */
int notrace unwind_frame(struct stackframe *frame)
extern unsigned long call_with_stack_end;
static int frame_pointer_check(struct stackframe *frame)
{ {
unsigned long high, low; unsigned long high, low;
unsigned long fp = frame->fp; unsigned long fp = frame->fp;
unsigned long pc = frame->pc;
/*
* call_with_stack() is the only place we allow SP to jump from one
* stack to another, with FP and SP pointing to different stacks,
* skipping the FP boundary check at this point.
*/
if (pc >= (unsigned long)&call_with_stack &&
pc < (unsigned long)&call_with_stack_end)
return 0;
/* only go to a higher address on the stack */ /* only go to a higher address on the stack */
low = frame->sp; low = frame->sp;
high = ALIGN(low, THREAD_SIZE); high = ALIGN(low, THREAD_SIZE);
#ifdef CONFIG_CC_IS_CLANG
/* check current frame pointer is within bounds */ /* check current frame pointer is within bounds */
#ifdef CONFIG_CC_IS_CLANG
if (fp < low + 4 || fp > high - 4) if (fp < low + 4 || fp > high - 4)
return -EINVAL; return -EINVAL;
frame->sp = frame->fp;
frame->fp = READ_ONCE_NOCHECK(*(unsigned long *)(fp));
frame->pc = READ_ONCE_NOCHECK(*(unsigned long *)(fp + 4));
#else #else
/* check current frame pointer is within bounds */
if (fp < low + 12 || fp > high - 4) if (fp < low + 12 || fp > high - 4)
return -EINVAL; return -EINVAL;
#endif
return 0;
}
int notrace unwind_frame(struct stackframe *frame)
{
unsigned long fp = frame->fp;
if (frame_pointer_check(frame))
return -EINVAL;
/*
* When we unwind through an exception stack, include the saved PC
* value into the stack trace.
*/
if (frame->ex_frame) {
struct pt_regs *regs = (struct pt_regs *)frame->sp;
/*
* We check that 'regs + sizeof(struct pt_regs)' (that is,
* &regs[1]) does not exceed the bottom of the stack to avoid
* accessing data outside the task's stack. This may happen
* when frame->ex_frame is a false positive.
*/
if ((unsigned long)&regs[1] > ALIGN(frame->sp, THREAD_SIZE))
return -EINVAL;
frame->pc = regs->ARM_pc;
frame->ex_frame = false;
return 0;
}
/* restore the registers from the stack frame */ /* restore the registers from the stack frame */
#ifdef CONFIG_CC_IS_CLANG
frame->sp = frame->fp;
frame->fp = READ_ONCE_NOCHECK(*(unsigned long *)(fp));
frame->pc = READ_ONCE_NOCHECK(*(unsigned long *)(fp + 4));
#else
frame->fp = READ_ONCE_NOCHECK(*(unsigned long *)(fp - 12)); frame->fp = READ_ONCE_NOCHECK(*(unsigned long *)(fp - 12));
frame->sp = READ_ONCE_NOCHECK(*(unsigned long *)(fp - 8)); frame->sp = READ_ONCE_NOCHECK(*(unsigned long *)(fp - 8));
frame->pc = READ_ONCE_NOCHECK(*(unsigned long *)(fp - 4)); frame->pc = READ_ONCE_NOCHECK(*(unsigned long *)(fp - 4));
...@@ -72,6 +119,9 @@ int notrace unwind_frame(struct stackframe *frame) ...@@ -72,6 +119,9 @@ int notrace unwind_frame(struct stackframe *frame)
(void *)frame->fp, &frame->kr_cur); (void *)frame->fp, &frame->kr_cur);
#endif #endif
if (in_entry_text(frame->pc))
frame->ex_frame = true;
return 0; return 0;
} }
#endif #endif
...@@ -102,7 +152,6 @@ static int save_trace(struct stackframe *frame, void *d) ...@@ -102,7 +152,6 @@ static int save_trace(struct stackframe *frame, void *d)
{ {
struct stack_trace_data *data = d; struct stack_trace_data *data = d;
struct stack_trace *trace = data->trace; struct stack_trace *trace = data->trace;
struct pt_regs *regs;
unsigned long addr = frame->pc; unsigned long addr = frame->pc;
if (data->no_sched_functions && in_sched_functions(addr)) if (data->no_sched_functions && in_sched_functions(addr))
...@@ -113,19 +162,6 @@ static int save_trace(struct stackframe *frame, void *d) ...@@ -113,19 +162,6 @@ static int save_trace(struct stackframe *frame, void *d)
} }
trace->entries[trace->nr_entries++] = addr; trace->entries[trace->nr_entries++] = addr;
if (trace->nr_entries >= trace->max_entries)
return 1;
if (!in_entry_text(frame->pc))
return 0;
regs = (struct pt_regs *)frame->sp;
if ((unsigned long)&regs[1] > ALIGN(frame->sp, THREAD_SIZE))
return 0;
trace->entries[trace->nr_entries++] = regs->ARM_pc;
return trace->nr_entries >= trace->max_entries; return trace->nr_entries >= trace->max_entries;
} }
...@@ -167,6 +203,9 @@ static noinline void __save_stack_trace(struct task_struct *tsk, ...@@ -167,6 +203,9 @@ static noinline void __save_stack_trace(struct task_struct *tsk,
frame.kr_cur = NULL; frame.kr_cur = NULL;
frame.tsk = tsk; frame.tsk = tsk;
#endif #endif
#ifdef CONFIG_UNWINDER_FRAME_POINTER
frame.ex_frame = false;
#endif
walk_stackframe(&frame, save_trace, &data); walk_stackframe(&frame, save_trace, &data);
} }
...@@ -188,6 +227,9 @@ void save_stack_trace_regs(struct pt_regs *regs, struct stack_trace *trace) ...@@ -188,6 +227,9 @@ void save_stack_trace_regs(struct pt_regs *regs, struct stack_trace *trace)
frame.kr_cur = NULL; frame.kr_cur = NULL;
frame.tsk = current; frame.tsk = current;
#endif #endif
#ifdef CONFIG_UNWINDER_FRAME_POINTER
frame.ex_frame = in_entry_text(frame.pc);
#endif
walk_stackframe(&frame, save_trace, &data); walk_stackframe(&frame, save_trace, &data);
} }
......
...@@ -205,14 +205,14 @@ static void dump_instr(const char *lvl, struct pt_regs *regs) ...@@ -205,14 +205,14 @@ static void dump_instr(const char *lvl, struct pt_regs *regs)
} }
#ifdef CONFIG_ARM_UNWIND #ifdef CONFIG_ARM_UNWIND
static inline void dump_backtrace(struct pt_regs *regs, struct task_struct *tsk, void dump_backtrace(struct pt_regs *regs, struct task_struct *tsk,
const char *loglvl) const char *loglvl)
{ {
unwind_backtrace(regs, tsk, loglvl); unwind_backtrace(regs, tsk, loglvl);
} }
#else #else
static void dump_backtrace(struct pt_regs *regs, struct task_struct *tsk, void dump_backtrace(struct pt_regs *regs, struct task_struct *tsk,
const char *loglvl) const char *loglvl)
{ {
unsigned int fp, mode; unsigned int fp, mode;
int ok = 1; int ok = 1;
...@@ -487,7 +487,7 @@ asmlinkage void do_undefinstr(struct pt_regs *regs) ...@@ -487,7 +487,7 @@ asmlinkage void do_undefinstr(struct pt_regs *regs)
die_sig: die_sig:
#ifdef CONFIG_DEBUG_USER #ifdef CONFIG_DEBUG_USER
if (user_debug & UDBG_UNDEFINED) { if (user_debug & UDBG_UNDEFINED) {
pr_info("%s (%d): undefined instruction: pc=%p\n", pr_info("%s (%d): undefined instruction: pc=%px\n",
current->comm, task_pid_nr(current), pc); current->comm, task_pid_nr(current), pc);
__show_regs(regs); __show_regs(regs);
dump_instr(KERN_INFO, regs); dump_instr(KERN_INFO, regs);
...@@ -920,9 +920,9 @@ asmlinkage void handle_bad_stack(struct pt_regs *regs) ...@@ -920,9 +920,9 @@ asmlinkage void handle_bad_stack(struct pt_regs *regs)
{ {
unsigned long tsk_stk = (unsigned long)current->stack; unsigned long tsk_stk = (unsigned long)current->stack;
#ifdef CONFIG_IRQSTACKS #ifdef CONFIG_IRQSTACKS
unsigned long irq_stk = (unsigned long)this_cpu_read(irq_stack_ptr); unsigned long irq_stk = (unsigned long)raw_cpu_read(irq_stack_ptr);
#endif #endif
unsigned long ovf_stk = (unsigned long)this_cpu_read(overflow_stack_ptr); unsigned long ovf_stk = (unsigned long)raw_cpu_read(overflow_stack_ptr);
console_verbose(); console_verbose();
pr_emerg("Insufficient stack space to handle exception!"); pr_emerg("Insufficient stack space to handle exception!");
......
...@@ -46,4 +46,6 @@ UNWIND( .setfp fpreg, sp ) ...@@ -46,4 +46,6 @@ UNWIND( .setfp fpreg, sp )
pop {fpreg, pc} pop {fpreg, pc}
UNWIND( .fnend ) UNWIND( .fnend )
#endif #endif
.globl call_with_stack_end
call_with_stack_end:
ENDPROC(call_with_stack) ENDPROC(call_with_stack)
...@@ -307,7 +307,7 @@ void __init dma_contiguous_remap(void) ...@@ -307,7 +307,7 @@ void __init dma_contiguous_remap(void)
static int __dma_update_pte(pte_t *pte, unsigned long addr, void *data) static int __dma_update_pte(pte_t *pte, unsigned long addr, void *data)
{ {
struct page *page = virt_to_page(addr); struct page *page = virt_to_page((void *)addr);
pgprot_t prot = *(pgprot_t *)data; pgprot_t prot = *(pgprot_t *)data;
set_pte_ext(pte, mk_pte(page, prot), 0); set_pte_ext(pte, mk_pte(page, prot), 0);
......
...@@ -26,7 +26,7 @@ static struct addr_marker address_markers[] = { ...@@ -26,7 +26,7 @@ static struct addr_marker address_markers[] = {
{ MODULES_VADDR, "Modules" }, { MODULES_VADDR, "Modules" },
{ PAGE_OFFSET, "Kernel Mapping" }, { PAGE_OFFSET, "Kernel Mapping" },
{ 0, "vmalloc() Area" }, { 0, "vmalloc() Area" },
{ VMALLOC_END, "vmalloc() End" }, { FDT_FIXED_BASE, "FDT Area" },
{ FIXADDR_START, "Fixmap Area" }, { FIXADDR_START, "Fixmap Area" },
{ VECTORS_BASE, "Vectors" }, { VECTORS_BASE, "Vectors" },
{ VECTORS_BASE + PAGE_SIZE * 2, "Vectors End" }, { VECTORS_BASE + PAGE_SIZE * 2, "Vectors End" },
...@@ -200,6 +200,7 @@ static const struct prot_bits section_bits[] = { ...@@ -200,6 +200,7 @@ static const struct prot_bits section_bits[] = {
}; };
struct pg_level { struct pg_level {
const char *name;
const struct prot_bits *bits; const struct prot_bits *bits;
size_t num; size_t num;
u64 mask; u64 mask;
...@@ -213,9 +214,11 @@ static struct pg_level pg_level[] = { ...@@ -213,9 +214,11 @@ static struct pg_level pg_level[] = {
}, { /* p4d */ }, { /* p4d */
}, { /* pud */ }, { /* pud */
}, { /* pmd */ }, { /* pmd */
.name = (CONFIG_PGTABLE_LEVELS > 2) ? "PMD" : "PGD",
.bits = section_bits, .bits = section_bits,
.num = ARRAY_SIZE(section_bits), .num = ARRAY_SIZE(section_bits),
}, { /* pte */ }, { /* pte */
.name = "PTE",
.bits = pte_bits, .bits = pte_bits,
.num = ARRAY_SIZE(pte_bits), .num = ARRAY_SIZE(pte_bits),
}, },
...@@ -282,7 +285,8 @@ static void note_page(struct pg_state *st, unsigned long addr, ...@@ -282,7 +285,8 @@ static void note_page(struct pg_state *st, unsigned long addr,
delta >>= 10; delta >>= 10;
unit++; unit++;
} }
pt_dump_seq_printf(st->seq, "%9lu%c", delta, *unit); pt_dump_seq_printf(st->seq, "%9lu%c %s", delta, *unit,
pg_level[st->level].name);
if (st->current_domain) if (st->current_domain)
pt_dump_seq_printf(st->seq, " %s", pt_dump_seq_printf(st->seq, " %s",
st->current_domain); st->current_domain);
......
...@@ -268,12 +268,17 @@ void __init kasan_init(void) ...@@ -268,12 +268,17 @@ void __init kasan_init(void)
/* /*
* 1. The module global variables are in MODULES_VADDR ~ MODULES_END, * 1. The module global variables are in MODULES_VADDR ~ MODULES_END,
* so we need to map this area. * so we need to map this area if CONFIG_KASAN_VMALLOC=n. With
* VMALLOC support KASAN will manage this region dynamically,
* refer to kasan_populate_vmalloc() and ARM's implementation of
* module_alloc().
* 2. PKMAP_BASE ~ PKMAP_BASE+PMD_SIZE's shadow and MODULES_VADDR * 2. PKMAP_BASE ~ PKMAP_BASE+PMD_SIZE's shadow and MODULES_VADDR
* ~ MODULES_END's shadow is in the same PMD_SIZE, so we can't * ~ MODULES_END's shadow is in the same PMD_SIZE, so we can't
* use kasan_populate_zero_shadow. * use kasan_populate_zero_shadow.
*/ */
create_mapping((void *)MODULES_VADDR, (void *)(PKMAP_BASE + PMD_SIZE)); if (!IS_ENABLED(CONFIG_KASAN_VMALLOC) && IS_ENABLED(CONFIG_MODULES))
create_mapping((void *)MODULES_VADDR, (void *)(MODULES_END));
create_mapping((void *)PKMAP_BASE, (void *)(PKMAP_BASE + PMD_SIZE));
/* /*
* KAsan may reuse the contents of kasan_early_shadow_pte directly, so * KAsan may reuse the contents of kasan_early_shadow_pte directly, so
......
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