Commit 09b56d5a authored by Linus Torvalds's avatar Linus Torvalds

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

Pull ARM updates from Russell King:

 - add support for ftrace-with-registers, which is needed for kgraft and
   other ftrace tools

 - support for mremap() for the sigpage/vDSO so that checkpoint/restore
   can work

 - add timestamps to each line of the register dump output

 - remove the unused KTHREAD_SIZE from nommu

 - align the ARM bitops APIs with the generic API (using unsigned long
   pointers rather than void pointers)

 - make the configuration of userspace Thumb support an expert option so
   that we can default it on, and avoid some hard to debug userspace
   crashes

* 'for-linus' of git://git.armlinux.org.uk/~rmk/linux-arm:
  ARM: 8684/1: NOMMU: Remove unused KTHREAD_SIZE definition
  ARM: 8683/1: ARM32: Support mremap() for sigpage/vDSO
  ARM: 8679/1: bitops: Align prototypes to generic API
  ARM: 8678/1: ftrace: Adds support for CONFIG_DYNAMIC_FTRACE_WITH_REGS
  ARM: make configuration of userspace Thumb support an expert option
  ARM: 8673/1: Fix __show_regs output timestamps
parents fe1b5180 98becb78
...@@ -58,6 +58,7 @@ config ARM ...@@ -58,6 +58,7 @@ config ARM
select HAVE_DMA_API_DEBUG select HAVE_DMA_API_DEBUG
select HAVE_DMA_CONTIGUOUS if MMU select HAVE_DMA_CONTIGUOUS if MMU
select HAVE_DYNAMIC_FTRACE if (!XIP_KERNEL) && !CPU_ENDIAN_BE32 && MMU select HAVE_DYNAMIC_FTRACE if (!XIP_KERNEL) && !CPU_ENDIAN_BE32 && MMU
select HAVE_DYNAMIC_FTRACE_WITH_REGS if HAVE_DYNAMIC_FTRACE
select HAVE_EFFICIENT_UNALIGNED_ACCESS if (CPU_V6 || CPU_V6K || CPU_V7) && MMU select HAVE_EFFICIENT_UNALIGNED_ACCESS if (CPU_V6 || CPU_V6K || CPU_V7) && MMU
select HAVE_EXIT_THREAD select HAVE_EXIT_THREAD
select HAVE_FTRACE_MCOUNT_RECORD if (!XIP_KERNEL) select HAVE_FTRACE_MCOUNT_RECORD if (!XIP_KERNEL)
......
...@@ -159,16 +159,16 @@ extern int _test_and_change_bit(int nr, volatile unsigned long * p); ...@@ -159,16 +159,16 @@ extern int _test_and_change_bit(int nr, volatile unsigned long * p);
/* /*
* Little endian assembly bitops. nr = 0 -> byte 0 bit 0. * Little endian assembly bitops. nr = 0 -> byte 0 bit 0.
*/ */
extern int _find_first_zero_bit_le(const void * p, unsigned size); extern int _find_first_zero_bit_le(const unsigned long *p, unsigned size);
extern int _find_next_zero_bit_le(const void * p, int size, int offset); extern int _find_next_zero_bit_le(const unsigned long *p, int size, int offset);
extern int _find_first_bit_le(const unsigned long *p, unsigned size); extern int _find_first_bit_le(const unsigned long *p, unsigned size);
extern int _find_next_bit_le(const unsigned long *p, int size, int offset); extern int _find_next_bit_le(const unsigned long *p, int size, int offset);
/* /*
* Big endian assembly bitops. nr = 0 -> byte 3 bit 0. * Big endian assembly bitops. nr = 0 -> byte 3 bit 0.
*/ */
extern int _find_first_zero_bit_be(const void * p, unsigned size); extern int _find_first_zero_bit_be(const unsigned long *p, unsigned size);
extern int _find_next_zero_bit_be(const void * p, int size, int offset); extern int _find_next_zero_bit_be(const unsigned long *p, int size, int offset);
extern int _find_first_bit_be(const unsigned long *p, unsigned size); extern int _find_first_bit_be(const unsigned long *p, unsigned size);
extern int _find_next_bit_be(const unsigned long *p, int size, int offset); extern int _find_next_bit_be(const unsigned long *p, int size, int offset);
......
#ifndef _ASM_ARM_FTRACE #ifndef _ASM_ARM_FTRACE
#define _ASM_ARM_FTRACE #define _ASM_ARM_FTRACE
#ifdef CONFIG_DYNAMIC_FTRACE_WITH_REGS
#define ARCH_SUPPORTS_FTRACE_OPS 1
#endif
#ifdef CONFIG_FUNCTION_TRACER #ifdef CONFIG_FUNCTION_TRACER
#define MCOUNT_ADDR ((unsigned long)(__gnu_mcount_nc)) #define MCOUNT_ADDR ((unsigned long)(__gnu_mcount_nc))
#define MCOUNT_INSN_SIZE 4 /* sizeof mcount call */ #define MCOUNT_INSN_SIZE 4 /* sizeof mcount call */
......
...@@ -11,12 +11,6 @@ ...@@ -11,12 +11,6 @@
#ifndef _ASMARM_PAGE_NOMMU_H #ifndef _ASMARM_PAGE_NOMMU_H
#define _ASMARM_PAGE_NOMMU_H #define _ASMARM_PAGE_NOMMU_H
#if !defined(CONFIG_SMALL_TASKS) && PAGE_SHIFT < 13
#define KTHREAD_SIZE (8192)
#else
#define KTHREAD_SIZE PAGE_SIZE
#endif
#define clear_page(page) memset((page), 0, PAGE_SIZE) #define clear_page(page) memset((page), 0, PAGE_SIZE)
#define copy_page(to,from) memcpy((to), (from), PAGE_SIZE) #define copy_page(to,from) memcpy((to), (from), PAGE_SIZE)
......
...@@ -92,12 +92,95 @@ ...@@ -92,12 +92,95 @@
2: mcount_exit 2: mcount_exit
.endm .endm
#ifdef CONFIG_DYNAMIC_FTRACE_WITH_REGS
.macro __ftrace_regs_caller
sub sp, sp, #8 @ space for PC and CPSR OLD_R0,
@ OLD_R0 will overwrite previous LR
add ip, sp, #12 @ move in IP the value of SP as it was
@ before the push {lr} of the mcount mechanism
str lr, [sp, #0] @ store LR instead of PC
ldr lr, [sp, #8] @ get previous LR
str r0, [sp, #8] @ write r0 as OLD_R0 over previous LR
stmdb sp!, {ip, lr}
stmdb sp!, {r0-r11, lr}
@ stack content at this point:
@ 0 4 48 52 56 60 64 68 72
@ R0 | R1 | ... | LR | SP + 4 | previous LR | LR | PSR | OLD_R0 |
mov r3, sp @ struct pt_regs*
ldr r2, =function_trace_op
ldr r2, [r2] @ pointer to the current
@ function tracing op
ldr r1, [sp, #S_LR] @ lr of instrumented func
ldr lr, [sp, #S_PC] @ get LR
mcount_adjust_addr r0, lr @ instrumented function
.globl ftrace_regs_call
ftrace_regs_call:
bl ftrace_stub
#ifdef CONFIG_FUNCTION_GRAPH_TRACER
.globl ftrace_graph_regs_call
ftrace_graph_regs_call:
mov r0, r0
#endif
@ pop saved regs
ldmia sp!, {r0-r12} @ restore r0 through r12
ldr ip, [sp, #8] @ restore PC
ldr lr, [sp, #4] @ restore LR
ldr sp, [sp, #0] @ restore SP
mov pc, ip @ return
.endm
#ifdef CONFIG_FUNCTION_GRAPH_TRACER
.macro __ftrace_graph_regs_caller
sub r0, fp, #4 @ lr of instrumented routine (parent)
@ called from __ftrace_regs_caller
ldr r1, [sp, #S_PC] @ instrumented routine (func)
mcount_adjust_addr r1, r1
mov r2, fp @ frame pointer
bl prepare_ftrace_return
@ pop registers saved in ftrace_regs_caller
ldmia sp!, {r0-r12} @ restore r0 through r12
ldr ip, [sp, #8] @ restore PC
ldr lr, [sp, #4] @ restore LR
ldr sp, [sp, #0] @ restore SP
mov pc, ip @ return
.endm
#endif
#endif
.macro __ftrace_caller suffix .macro __ftrace_caller suffix
mcount_enter mcount_enter
mcount_get_lr r1 @ lr of instrumented func mcount_get_lr r1 @ lr of instrumented func
mcount_adjust_addr r0, lr @ instrumented function mcount_adjust_addr r0, lr @ instrumented function
#ifdef CONFIG_DYNAMIC_FTRACE_WITH_REGS
ldr r2, =function_trace_op
ldr r2, [r2] @ pointer to the current
@ function tracing op
mov r3, #0 @ regs is NULL
#endif
.globl ftrace_call\suffix .globl ftrace_call\suffix
ftrace_call\suffix: ftrace_call\suffix:
bl ftrace_stub bl ftrace_stub
...@@ -212,6 +295,15 @@ UNWIND(.fnstart) ...@@ -212,6 +295,15 @@ UNWIND(.fnstart)
__ftrace_caller __ftrace_caller
UNWIND(.fnend) UNWIND(.fnend)
ENDPROC(ftrace_caller) ENDPROC(ftrace_caller)
#ifdef CONFIG_DYNAMIC_FTRACE_WITH_REGS
ENTRY(ftrace_regs_caller)
UNWIND(.fnstart)
__ftrace_regs_caller
UNWIND(.fnend)
ENDPROC(ftrace_regs_caller)
#endif
#endif #endif
#ifdef CONFIG_FUNCTION_GRAPH_TRACER #ifdef CONFIG_FUNCTION_GRAPH_TRACER
...@@ -220,6 +312,14 @@ UNWIND(.fnstart) ...@@ -220,6 +312,14 @@ UNWIND(.fnstart)
__ftrace_graph_caller __ftrace_graph_caller
UNWIND(.fnend) UNWIND(.fnend)
ENDPROC(ftrace_graph_caller) ENDPROC(ftrace_graph_caller)
#ifdef CONFIG_DYNAMIC_FTRACE_WITH_REGS
ENTRY(ftrace_graph_regs_caller)
UNWIND(.fnstart)
__ftrace_graph_regs_caller
UNWIND(.fnend)
ENDPROC(ftrace_graph_regs_caller)
#endif
#endif #endif
.purgem mcount_enter .purgem mcount_enter
......
...@@ -141,6 +141,15 @@ int ftrace_update_ftrace_func(ftrace_func_t func) ...@@ -141,6 +141,15 @@ int ftrace_update_ftrace_func(ftrace_func_t func)
ret = ftrace_modify_code(pc, 0, new, false); ret = ftrace_modify_code(pc, 0, new, false);
#ifdef CONFIG_DYNAMIC_FTRACE_WITH_REGS
if (!ret) {
pc = (unsigned long)&ftrace_regs_call;
new = ftrace_call_replace(pc, (unsigned long)func);
ret = ftrace_modify_code(pc, 0, new, false);
}
#endif
#ifdef CONFIG_OLD_MCOUNT #ifdef CONFIG_OLD_MCOUNT
if (!ret) { if (!ret) {
pc = (unsigned long)&ftrace_call_old; pc = (unsigned long)&ftrace_call_old;
...@@ -159,11 +168,29 @@ int ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr) ...@@ -159,11 +168,29 @@ int ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr)
unsigned long ip = rec->ip; unsigned long ip = rec->ip;
old = ftrace_nop_replace(rec); old = ftrace_nop_replace(rec);
new = ftrace_call_replace(ip, adjust_address(rec, addr));
return ftrace_modify_code(rec->ip, old, new, true);
}
#ifdef CONFIG_DYNAMIC_FTRACE_WITH_REGS
int ftrace_modify_call(struct dyn_ftrace *rec, unsigned long old_addr,
unsigned long addr)
{
unsigned long new, old;
unsigned long ip = rec->ip;
old = ftrace_call_replace(ip, adjust_address(rec, old_addr));
new = ftrace_call_replace(ip, adjust_address(rec, addr)); new = ftrace_call_replace(ip, adjust_address(rec, addr));
return ftrace_modify_code(rec->ip, old, new, true); return ftrace_modify_code(rec->ip, old, new, true);
} }
#endif
int ftrace_make_nop(struct module *mod, int ftrace_make_nop(struct module *mod,
struct dyn_ftrace *rec, unsigned long addr) struct dyn_ftrace *rec, unsigned long addr)
{ {
...@@ -231,6 +258,8 @@ void prepare_ftrace_return(unsigned long *parent, unsigned long self_addr, ...@@ -231,6 +258,8 @@ void prepare_ftrace_return(unsigned long *parent, unsigned long self_addr,
extern unsigned long ftrace_graph_call; extern unsigned long ftrace_graph_call;
extern unsigned long ftrace_graph_call_old; extern unsigned long ftrace_graph_call_old;
extern void ftrace_graph_caller_old(void); extern void ftrace_graph_caller_old(void);
extern unsigned long ftrace_graph_regs_call;
extern void ftrace_graph_regs_caller(void);
static int __ftrace_modify_caller(unsigned long *callsite, static int __ftrace_modify_caller(unsigned long *callsite,
void (*func) (void), bool enable) void (*func) (void), bool enable)
...@@ -253,6 +282,14 @@ static int ftrace_modify_graph_caller(bool enable) ...@@ -253,6 +282,14 @@ static int ftrace_modify_graph_caller(bool enable)
ftrace_graph_caller, ftrace_graph_caller,
enable); enable);
#ifdef CONFIG_DYNAMIC_FTRACE_WITH_REGS
if (!ret)
ret = __ftrace_modify_caller(&ftrace_graph_regs_call,
ftrace_graph_regs_caller,
enable);
#endif
#ifdef CONFIG_OLD_MCOUNT #ifdef CONFIG_OLD_MCOUNT
if (!ret) if (!ret)
ret = __ftrace_modify_caller(&ftrace_graph_call_old, ret = __ftrace_modify_caller(&ftrace_graph_call_old,
......
...@@ -123,10 +123,10 @@ void __show_regs(struct pt_regs *regs) ...@@ -123,10 +123,10 @@ void __show_regs(struct pt_regs *regs)
print_symbol("PC is at %s\n", instruction_pointer(regs)); print_symbol("PC is at %s\n", instruction_pointer(regs));
print_symbol("LR is at %s\n", regs->ARM_lr); print_symbol("LR is at %s\n", regs->ARM_lr);
printk("pc : [<%08lx>] lr : [<%08lx>] psr: %08lx\n" printk("pc : [<%08lx>] lr : [<%08lx>] psr: %08lx\n",
"sp : %08lx ip : %08lx fp : %08lx\n", regs->ARM_pc, regs->ARM_lr, regs->ARM_cpsr);
regs->ARM_pc, regs->ARM_lr, regs->ARM_cpsr, printk("sp : %08lx ip : %08lx fp : %08lx\n",
regs->ARM_sp, regs->ARM_ip, regs->ARM_fp); regs->ARM_sp, regs->ARM_ip, regs->ARM_fp);
printk("r10: %08lx r9 : %08lx r8 : %08lx\n", printk("r10: %08lx r9 : %08lx r8 : %08lx\n",
regs->ARM_r10, regs->ARM_r9, regs->ARM_r10, regs->ARM_r9,
regs->ARM_r8); regs->ARM_r8);
...@@ -404,9 +404,17 @@ static unsigned long sigpage_addr(const struct mm_struct *mm, ...@@ -404,9 +404,17 @@ static unsigned long sigpage_addr(const struct mm_struct *mm,
static struct page *signal_page; static struct page *signal_page;
extern struct page *get_signal_page(void); extern struct page *get_signal_page(void);
static int sigpage_mremap(const struct vm_special_mapping *sm,
struct vm_area_struct *new_vma)
{
current->mm->context.sigpage = new_vma->vm_start;
return 0;
}
static const struct vm_special_mapping sigpage_mapping = { static const struct vm_special_mapping sigpage_mapping = {
.name = "[sigpage]", .name = "[sigpage]",
.pages = &signal_page, .pages = &signal_page,
.mremap = sigpage_mremap,
}; };
int arch_setup_additional_pages(struct linux_binprm *bprm, int uses_interp) int arch_setup_additional_pages(struct linux_binprm *bprm, int uses_interp)
......
...@@ -54,8 +54,26 @@ static const struct vm_special_mapping vdso_data_mapping = { ...@@ -54,8 +54,26 @@ static const struct vm_special_mapping vdso_data_mapping = {
.pages = &vdso_data_page, .pages = &vdso_data_page,
}; };
static int vdso_mremap(const struct vm_special_mapping *sm,
struct vm_area_struct *new_vma)
{
unsigned long new_size = new_vma->vm_end - new_vma->vm_start;
unsigned long vdso_size;
/* without VVAR page */
vdso_size = (vdso_total_pages - 1) << PAGE_SHIFT;
if (vdso_size != new_size)
return -EINVAL;
current->mm->context.vdso = new_vma->vm_start;
return 0;
}
static struct vm_special_mapping vdso_text_mapping __ro_after_init = { static struct vm_special_mapping vdso_text_mapping __ro_after_init = {
.name = "[vdso]", .name = "[vdso]",
.mremap = vdso_mremap,
}; };
struct elfinfo { struct elfinfo {
......
...@@ -679,7 +679,7 @@ config ARCH_DMA_ADDR_T_64BIT ...@@ -679,7 +679,7 @@ config ARCH_DMA_ADDR_T_64BIT
bool bool
config ARM_THUMB config ARM_THUMB
bool "Support Thumb user binaries" if !CPU_THUMBONLY bool "Support Thumb user binaries" if !CPU_THUMBONLY && EXPERT
depends on CPU_THUMB_CAPABLE depends on CPU_THUMB_CAPABLE
default y default y
help help
...@@ -690,6 +690,10 @@ config ARM_THUMB ...@@ -690,6 +690,10 @@ config ARM_THUMB
instruction set resulting in smaller binaries at the expense of instruction set resulting in smaller binaries at the expense of
slightly less efficient code. slightly less efficient code.
If this option is disabled, and you run userspace that switches to
Thumb mode, signal handling will not work correctly, resulting in
segmentation faults or illegal instruction aborts.
If you don't know what this all is, saying Y is a safe choice. If you don't know what this all is, saying Y is a safe choice.
config ARM_THUMBEE config ARM_THUMBEE
......
...@@ -78,9 +78,6 @@ static int vdso_mremap(const struct vm_special_mapping *sm, ...@@ -78,9 +78,6 @@ static int vdso_mremap(const struct vm_special_mapping *sm,
if (image->size != new_size) if (image->size != new_size)
return -EINVAL; return -EINVAL;
if (WARN_ON_ONCE(current->mm != new_vma->vm_mm))
return -EFAULT;
vdso_fix_landing(image, new_vma); vdso_fix_landing(image, new_vma);
current->mm->context.vdso = (void __user *)new_vma->vm_start; current->mm->context.vdso = (void __user *)new_vma->vm_start;
......
...@@ -3186,8 +3186,12 @@ static int special_mapping_mremap(struct vm_area_struct *new_vma) ...@@ -3186,8 +3186,12 @@ static int special_mapping_mremap(struct vm_area_struct *new_vma)
{ {
struct vm_special_mapping *sm = new_vma->vm_private_data; struct vm_special_mapping *sm = new_vma->vm_private_data;
if (WARN_ON_ONCE(current->mm != new_vma->vm_mm))
return -EFAULT;
if (sm->mremap) if (sm->mremap)
return sm->mremap(sm, new_vma); return sm->mremap(sm, new_vma);
return 0; return 0;
} }
......
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