Skip to content

Commit 60ea7bb

Browse files
committed
Merge branch 'parisc-4.6-4' of git://git.kernel.org/pub/scm/linux/kernel/git/deller/parisc-linux
Pull parisc ftrace fixes from Helge Deller: "This is (most likely) the last pull request for v4.6 for the parisc architecture. It fixes the FTRACE feature for parisc, which is horribly broken since quite some time and doesn't even compile. This patch just fixes the bare minimum (it actually removes more lines than it adds), so that the function tracer works again on 32- and 64bit kernels. I've queued up additional patches on top of this patch which e.g. add the syscall tracer, but those have to wait for the merge window for v4.7." * 'parisc-4.6-4' of git://git.kernel.org/pub/scm/linux/kernel/git/deller/parisc-linux: parisc: Fix ftrace function tracer
2 parents 806fdcc + 366dd4e commit 60ea7bb

File tree

8 files changed

+114
-168
lines changed

8 files changed

+114
-168
lines changed

arch/parisc/Kconfig

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,8 @@ config PARISC
44
select ARCH_MIGHT_HAVE_PC_PARPORT
55
select HAVE_IDE
66
select HAVE_OPROFILE
7-
select HAVE_FUNCTION_TRACER if 64BIT
8-
select HAVE_FUNCTION_GRAPH_TRACER if 64BIT
7+
select HAVE_FUNCTION_TRACER
8+
select HAVE_FUNCTION_GRAPH_TRACER
99
select ARCH_WANT_FRAME_POINTERS
1010
select RTC_CLASS
1111
select RTC_DRV_GENERIC

arch/parisc/Kconfig.debug

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,13 @@ menu "Kernel hacking"
22

33
source "lib/Kconfig.debug"
44

5+
config TRACE_IRQFLAGS_SUPPORT
6+
def_bool y
7+
58
config DEBUG_RODATA
69
bool "Write protect kernel read-only data structures"
710
depends on DEBUG_KERNEL
11+
default y
812
help
913
Mark the kernel read-only data as write-protected in the pagetables,
1014
in order to catch accidental (and incorrect) writes to such const

arch/parisc/Makefile

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -62,9 +62,7 @@ cflags-y += -mdisable-fpregs
6262

6363
# Without this, "ld -r" results in .text sections that are too big
6464
# (> 0x40000) for branches to reach stubs.
65-
ifndef CONFIG_FUNCTION_TRACER
66-
cflags-y += -ffunction-sections
67-
endif
65+
cflags-y += -ffunction-sections
6866

6967
# Use long jumps instead of long branches (needed if your linker fails to
7068
# link a too big vmlinux executable). Not enabled for building modules.

arch/parisc/include/asm/ftrace.h

Lines changed: 1 addition & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -4,23 +4,7 @@
44
#ifndef __ASSEMBLY__
55
extern void mcount(void);
66

7-
/*
8-
* Stack of return addresses for functions of a thread.
9-
* Used in struct thread_info
10-
*/
11-
struct ftrace_ret_stack {
12-
unsigned long ret;
13-
unsigned long func;
14-
unsigned long long calltime;
15-
};
16-
17-
/*
18-
* Primary handler of a function return.
19-
* It relays on ftrace_return_to_handler.
20-
* Defined in entry.S
21-
*/
22-
extern void return_to_handler(void);
23-
7+
#define MCOUNT_INSN_SIZE 4
248

259
extern unsigned long return_address(unsigned int);
2610

arch/parisc/kernel/Makefile

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,11 +15,7 @@ ifdef CONFIG_FUNCTION_TRACER
1515
# Do not profile debug and lowlevel utilities
1616
CFLAGS_REMOVE_ftrace.o = -pg
1717
CFLAGS_REMOVE_cache.o = -pg
18-
CFLAGS_REMOVE_irq.o = -pg
19-
CFLAGS_REMOVE_pacache.o = -pg
2018
CFLAGS_REMOVE_perf.o = -pg
21-
CFLAGS_REMOVE_traps.o = -pg
22-
CFLAGS_REMOVE_unaligned.o = -pg
2319
CFLAGS_REMOVE_unwind.o = -pg
2420
endif
2521

arch/parisc/kernel/entry.S

Lines changed: 74 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1970,43 +1970,98 @@ pt_regs_ok:
19701970
b intr_restore
19711971
copy %r25,%r16
19721972

1973-
.import schedule,code
19741973
syscall_do_resched:
1975-
BL schedule,%r2
1974+
load32 syscall_check_resched,%r2 /* if resched, we start over again */
1975+
load32 schedule,%r19
1976+
bv %r0(%r19) /* jumps to schedule() */
19761977
#ifdef CONFIG_64BIT
19771978
ldo -16(%r30),%r29 /* Reference param save area */
19781979
#else
19791980
nop
19801981
#endif
1981-
b syscall_check_resched /* if resched, we start over again */
1982-
nop
19831982
ENDPROC(syscall_exit)
19841983

19851984

19861985
#ifdef CONFIG_FUNCTION_TRACER
1986+
19871987
.import ftrace_function_trampoline,code
1988-
ENTRY(_mcount)
1989-
copy %r3, %arg2
1988+
.align L1_CACHE_BYTES
1989+
.globl mcount
1990+
.type mcount, @function
1991+
ENTRY(mcount)
1992+
_mcount:
1993+
.export _mcount,data
1994+
.proc
1995+
.callinfo caller,frame=0
1996+
.entry
1997+
/*
1998+
* The 64bit mcount() function pointer needs 4 dwords, of which the
1999+
* first two are free. We optimize it here and put 2 instructions for
2000+
* calling mcount(), and 2 instructions for ftrace_stub(). That way we
2001+
* have all on one L1 cacheline.
2002+
*/
19902003
b ftrace_function_trampoline
2004+
copy %r3, %arg2 /* caller original %sp */
2005+
ftrace_stub:
2006+
.globl ftrace_stub
2007+
.type ftrace_stub, @function
2008+
#ifdef CONFIG_64BIT
2009+
bve (%rp)
2010+
#else
2011+
bv %r0(%rp)
2012+
#endif
19912013
nop
1992-
ENDPROC(_mcount)
2014+
#ifdef CONFIG_64BIT
2015+
.dword mcount
2016+
.dword 0 /* code in head.S puts value of global gp here */
2017+
#endif
2018+
.exit
2019+
.procend
2020+
ENDPROC(mcount)
19932021

2022+
.align 8
2023+
.globl return_to_handler
2024+
.type return_to_handler, @function
19942025
ENTRY(return_to_handler)
1995-
load32 return_trampoline, %rp
1996-
copy %ret0, %arg0
1997-
copy %ret1, %arg1
1998-
b ftrace_return_to_handler
1999-
nop
2000-
return_trampoline:
2001-
copy %ret0, %rp
2002-
copy %r23, %ret0
2003-
copy %r24, %ret1
2026+
.proc
2027+
.callinfo caller,frame=FRAME_SIZE
2028+
.entry
2029+
.export parisc_return_to_handler,data
2030+
parisc_return_to_handler:
2031+
copy %r3,%r1
2032+
STREG %r0,-RP_OFFSET(%sp) /* store 0 as %rp */
2033+
copy %sp,%r3
2034+
STREGM %r1,FRAME_SIZE(%sp)
2035+
STREG %ret0,8(%r3)
2036+
STREG %ret1,16(%r3)
20042037

2005-
.globl ftrace_stub
2006-
ftrace_stub:
2038+
#ifdef CONFIG_64BIT
2039+
loadgp
2040+
#endif
2041+
2042+
/* call ftrace_return_to_handler(0) */
2043+
#ifdef CONFIG_64BIT
2044+
ldo -16(%sp),%ret1 /* Reference param save area */
2045+
#endif
2046+
BL ftrace_return_to_handler,%r2
2047+
ldi 0,%r26
2048+
copy %ret0,%rp
2049+
2050+
/* restore original return values */
2051+
LDREG 8(%r3),%ret0
2052+
LDREG 16(%r3),%ret1
2053+
2054+
/* return from function */
2055+
#ifdef CONFIG_64BIT
2056+
bve (%rp)
2057+
#else
20072058
bv %r0(%rp)
2008-
nop
2059+
#endif
2060+
LDREGM -FRAME_SIZE(%sp),%r3
2061+
.exit
2062+
.procend
20092063
ENDPROC(return_to_handler)
2064+
20102065
#endif /* CONFIG_FUNCTION_TRACER */
20112066

20122067
#ifdef CONFIG_IRQSTACKS

arch/parisc/kernel/ftrace.c

Lines changed: 23 additions & 123 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
/*
22
* Code for tracing calls in Linux kernel.
3-
* Copyright (C) 2009 Helge Deller <deller@gmx.de>
3+
* Copyright (C) 2009-2016 Helge Deller <deller@gmx.de>
44
*
55
* based on code for x86 which is:
66
* Copyright (C) 2007-2008 Steven Rostedt <srostedt@redhat.com>
@@ -13,104 +13,21 @@
1313
#include <linux/init.h>
1414
#include <linux/ftrace.h>
1515

16+
#include <asm/assembly.h>
1617
#include <asm/sections.h>
1718
#include <asm/ftrace.h>
1819

1920

20-
2121
#ifdef CONFIG_FUNCTION_GRAPH_TRACER
22-
23-
/* Add a function return address to the trace stack on thread info.*/
24-
static int push_return_trace(unsigned long ret, unsigned long long time,
25-
unsigned long func, int *depth)
26-
{
27-
int index;
28-
29-
if (!current->ret_stack)
30-
return -EBUSY;
31-
32-
/* The return trace stack is full */
33-
if (current->curr_ret_stack == FTRACE_RETFUNC_DEPTH - 1) {
34-
atomic_inc(&current->trace_overrun);
35-
return -EBUSY;
36-
}
37-
38-
index = ++current->curr_ret_stack;
39-
barrier();
40-
current->ret_stack[index].ret = ret;
41-
current->ret_stack[index].func = func;
42-
current->ret_stack[index].calltime = time;
43-
*depth = index;
44-
45-
return 0;
46-
}
47-
48-
/* Retrieve a function return address to the trace stack on thread info.*/
49-
static void pop_return_trace(struct ftrace_graph_ret *trace, unsigned long *ret)
50-
{
51-
int index;
52-
53-
index = current->curr_ret_stack;
54-
55-
if (unlikely(index < 0)) {
56-
ftrace_graph_stop();
57-
WARN_ON(1);
58-
/* Might as well panic, otherwise we have no where to go */
59-
*ret = (unsigned long)
60-
dereference_function_descriptor(&panic);
61-
return;
62-
}
63-
64-
*ret = current->ret_stack[index].ret;
65-
trace->func = current->ret_stack[index].func;
66-
trace->calltime = current->ret_stack[index].calltime;
67-
trace->overrun = atomic_read(&current->trace_overrun);
68-
trace->depth = index;
69-
barrier();
70-
current->curr_ret_stack--;
71-
72-
}
73-
74-
/*
75-
* Send the trace to the ring-buffer.
76-
* @return the original return address.
77-
*/
78-
unsigned long ftrace_return_to_handler(unsigned long retval0,
79-
unsigned long retval1)
80-
{
81-
struct ftrace_graph_ret trace;
82-
unsigned long ret;
83-
84-
pop_return_trace(&trace, &ret);
85-
trace.rettime = local_clock();
86-
ftrace_graph_return(&trace);
87-
88-
if (unlikely(!ret)) {
89-
ftrace_graph_stop();
90-
WARN_ON(1);
91-
/* Might as well panic. What else to do? */
92-
ret = (unsigned long)
93-
dereference_function_descriptor(&panic);
94-
}
95-
96-
/* HACK: we hand over the old functions' return values
97-
in %r23 and %r24. Assembly in entry.S will take care
98-
and move those to their final registers %ret0 and %ret1 */
99-
asm( "copy %0, %%r23 \n\t"
100-
"copy %1, %%r24 \n" : : "r" (retval0), "r" (retval1) );
101-
102-
return ret;
103-
}
104-
10522
/*
10623
* Hook the return address and push it in the stack of return addrs
10724
* in current thread info.
10825
*/
109-
void prepare_ftrace_return(unsigned long *parent, unsigned long self_addr)
26+
static void prepare_ftrace_return(unsigned long *parent, unsigned long self_addr)
11027
{
11128
unsigned long old;
112-
unsigned long long calltime;
11329
struct ftrace_graph_ent trace;
30+
extern int parisc_return_to_handler;
11431

11532
if (unlikely(ftrace_graph_is_dead()))
11633
return;
@@ -119,64 +36,47 @@ void prepare_ftrace_return(unsigned long *parent, unsigned long self_addr)
11936
return;
12037

12138
old = *parent;
122-
*parent = (unsigned long)
123-
dereference_function_descriptor(&return_to_handler);
12439

125-
if (unlikely(!__kernel_text_address(old))) {
126-
ftrace_graph_stop();
127-
*parent = old;
128-
WARN_ON(1);
129-
return;
130-
}
131-
132-
calltime = local_clock();
40+
trace.func = self_addr;
41+
trace.depth = current->curr_ret_stack + 1;
13342

134-
if (push_return_trace(old, calltime,
135-
self_addr, &trace.depth) == -EBUSY) {
136-
*parent = old;
43+
/* Only trace if the calling function expects to */
44+
if (!ftrace_graph_entry(&trace))
13745
return;
138-
}
13946

140-
trace.func = self_addr;
47+
if (ftrace_push_return_trace(old, self_addr, &trace.depth,
48+
0 ) == -EBUSY)
49+
return;
14150

142-
/* Only trace if the calling function expects to */
143-
if (!ftrace_graph_entry(&trace)) {
144-
current->curr_ret_stack--;
145-
*parent = old;
146-
}
51+
/* activate parisc_return_to_handler() as return point */
52+
*parent = (unsigned long) &parisc_return_to_handler;
14753
}
148-
14954
#endif /* CONFIG_FUNCTION_GRAPH_TRACER */
15055

151-
152-
void ftrace_function_trampoline(unsigned long parent,
56+
void notrace ftrace_function_trampoline(unsigned long parent,
15357
unsigned long self_addr,
15458
unsigned long org_sp_gr3)
15559
{
156-
extern ftrace_func_t ftrace_trace_function;
60+
extern ftrace_func_t ftrace_trace_function; /* depends on CONFIG_DYNAMIC_FTRACE */
61+
extern int ftrace_graph_entry_stub(struct ftrace_graph_ent *trace);
15762

15863
if (ftrace_trace_function != ftrace_stub) {
159-
ftrace_trace_function(parent, self_addr);
64+
/* struct ftrace_ops *op, struct pt_regs *regs); */
65+
ftrace_trace_function(parent, self_addr, NULL, NULL);
16066
return;
16167
}
68+
16269
#ifdef CONFIG_FUNCTION_GRAPH_TRACER
163-
if (ftrace_graph_entry && ftrace_graph_return) {
164-
unsigned long sp;
70+
if (ftrace_graph_return != (trace_func_graph_ret_t) ftrace_stub ||
71+
ftrace_graph_entry != ftrace_graph_entry_stub) {
16572
unsigned long *parent_rp;
16673

167-
asm volatile ("copy %%r30, %0" : "=r"(sp));
168-
/* sanity check: is stack pointer which we got from
169-
assembler function in entry.S in a reasonable
170-
range compared to current stack pointer? */
171-
if ((sp - org_sp_gr3) > 0x400)
172-
return;
173-
17474
/* calculate pointer to %rp in stack */
175-
parent_rp = (unsigned long *) org_sp_gr3 - 0x10;
75+
parent_rp = (unsigned long *) (org_sp_gr3 - RP_OFFSET);
17676
/* sanity check: parent_rp should hold parent */
17777
if (*parent_rp != parent)
17878
return;
179-
79+
18080
prepare_ftrace_return(parent_rp, self_addr);
18181
return;
18282
}

0 commit comments

Comments
 (0)