Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > linux.kernel > #1317041 > unrolled thread
| Started by | Torsten Duwe <duwe@lst.de> |
|---|---|
| First post | 2016-01-25 18:10 +0100 |
| Last post | 2016-01-27 14:50 +0100 |
| Articles | 5 — 3 participants |
Back to article view | Back to linux.kernel
This discussion starts older than the indexed window; earlier articles aren't shown. The article labeled Started by
below is the oldest one visible, not the original post.
[PATCH v6 1/9] ppc64 (le): prepare for -mprofile-kernel Torsten Duwe <duwe@lst.de> - 2016-01-25 18:10 +0100
Re: [PATCH v6 1/9] ppc64 (le): prepare for -mprofile-kernel Michael Ellerman <mpe@ellerman.id.au> - 2016-01-27 11:20 +0100
Re: [PATCH v6 1/9] ppc64 (le): prepare for -mprofile-kernel Torsten Duwe <duwe@lst.de> - 2016-01-27 11:50 +0100
Re: [PATCH v6 1/9] ppc64 (le): prepare for -mprofile-kernel Alan Modra <amodra@gmail.com> - 2016-01-27 14:00 +0100
Re: [PATCH v6 1/9] ppc64 (le): prepare for -mprofile-kernel Torsten Duwe <duwe@lst.de> - 2016-01-27 14:50 +0100
| From | Torsten Duwe <duwe@lst.de> |
|---|---|
| Date | 2016-01-25 18:10 +0100 |
| Subject | [PATCH v6 1/9] ppc64 (le): prepare for -mprofile-kernel |
| Message-ID | <qUSOm-7cE-21@gated-at.bofh.it> |
The gcc switch -mprofile-kernel, available for ppc64 on gcc > 4.8.5,
allows to call _mcount very early in the function, which low-level
ASM code and code patching functions need to consider.
Especially the link register and the parameter registers are still
alive and not yet saved into a new stack frame.
Signed-off-by: Torsten Duwe <duwe@suse.de>
---
arch/powerpc/kernel/entry_64.S | 45 +++++++++++++++++++++++++++++++++++++++--
arch/powerpc/kernel/ftrace.c | 12 +++++++++--
arch/powerpc/kernel/module_64.c | 14 +++++++++++++
3 files changed, 67 insertions(+), 4 deletions(-)
diff --git a/arch/powerpc/kernel/entry_64.S b/arch/powerpc/kernel/entry_64.S
index a94f155..e7cd043 100644
--- a/arch/powerpc/kernel/entry_64.S
+++ b/arch/powerpc/kernel/entry_64.S
@@ -1206,7 +1206,12 @@ _GLOBAL(enter_prom)
#ifdef CONFIG_DYNAMIC_FTRACE
_GLOBAL(mcount)
_GLOBAL(_mcount)
- blr
+ std r0,LRSAVE(r1) /* gcc6 does this _after_ this call _only_ */
+ mflr r0
+ mtctr r0
+ ld r0,LRSAVE(r1)
+ mtlr r0
+ bctr
_GLOBAL_TOC(ftrace_caller)
/* Taken from output of objdump from lib64/glibc */
@@ -1262,13 +1267,28 @@ _GLOBAL(ftrace_stub)
#ifdef CONFIG_FUNCTION_GRAPH_TRACER
_GLOBAL(ftrace_graph_caller)
+#ifdef CC_USING_MPROFILE_KERNEL
+ /* with -mprofile-kernel, parameter regs are still alive at _mcount */
+ std r10, 104(r1)
+ std r9, 96(r1)
+ std r8, 88(r1)
+ std r7, 80(r1)
+ std r6, 72(r1)
+ std r5, 64(r1)
+ std r4, 56(r1)
+ std r3, 48(r1)
+ mfctr r4 /* ftrace_caller has moved local addr here */
+ std r4, 40(r1)
+ mflr r3 /* ftrace_caller has restored LR from stack */
+#else
/* load r4 with local address */
ld r4, 128(r1)
- subi r4, r4, MCOUNT_INSN_SIZE
/* Grab the LR out of the caller stack frame */
ld r11, 112(r1)
ld r3, 16(r11)
+#endif
+ subi r4, r4, MCOUNT_INSN_SIZE
bl prepare_ftrace_return
nop
@@ -1277,6 +1297,26 @@ _GLOBAL(ftrace_graph_caller)
* prepare_ftrace_return gives us the address we divert to.
* Change the LR in the callers stack frame to this.
*/
+
+#ifdef CC_USING_MPROFILE_KERNEL
+ mtlr r3
+
+ ld r0, 40(r1)
+ mtctr r0
+ ld r10, 104(r1)
+ ld r9, 96(r1)
+ ld r8, 88(r1)
+ ld r7, 80(r1)
+ ld r6, 72(r1)
+ ld r5, 64(r1)
+ ld r4, 56(r1)
+ ld r3, 48(r1)
+
+ addi r1, r1, 112
+ mflr r0
+ std r0, LRSAVE(r1)
+ bctr
+#else
ld r11, 112(r1)
std r3, 16(r11)
@@ -1284,6 +1324,7 @@ _GLOBAL(ftrace_graph_caller)
mtlr r0
addi r1, r1, 112
blr
+#endif
_GLOBAL(return_to_handler)
/* need to save return values */
diff --git a/arch/powerpc/kernel/ftrace.c b/arch/powerpc/kernel/ftrace.c
index 44d4d8e..080c525 100644
--- a/arch/powerpc/kernel/ftrace.c
+++ b/arch/powerpc/kernel/ftrace.c
@@ -306,11 +306,19 @@ __ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr)
* The load offset is different depending on the ABI. For simplicity
* just mask it out when doing the compare.
*/
+#ifndef CC_USING_MPROFILE_KERNEL
if ((op[0] != 0x48000008) || ((op[1] & 0xffff0000) != 0xe8410000)) {
- pr_err("Unexpected call sequence: %x %x\n", op[0], op[1]);
+ pr_err("Unexpected call sequence at %p: %x %x\n",
+ ip, op[0], op[1]);
return -EINVAL;
}
-
+#else
+ /* look for patched "NOP" on ppc64 with -mprofile-kernel */
+ if (op[0] != 0x60000000) {
+ pr_err("Unexpected call at %p: %x\n", ip, op[0]);
+ return -EINVAL;
+ }
+#endif
/* If we never set up a trampoline to ftrace_caller, then bail */
if (!rec->arch.mod->arch.tramp) {
pr_err("No ftrace trampoline\n");
diff --git a/arch/powerpc/kernel/module_64.c b/arch/powerpc/kernel/module_64.c
index 6838451..30f6be1 100644
--- a/arch/powerpc/kernel/module_64.c
+++ b/arch/powerpc/kernel/module_64.c
@@ -475,6 +475,20 @@ static unsigned long stub_for_addr(Elf64_Shdr *sechdrs,
static int restore_r2(u32 *instruction, struct module *me)
{
if (*instruction != PPC_INST_NOP) {
+#ifdef CC_USING_MPROFILE_KERNEL
+ /* -mprofile_kernel sequence starting with
+ * mflr r0 and maybe std r0, LRSAVE(r1)
+ */
+ if ((instruction[-3] == 0x7c0802a6 &&
+ instruction[-2] == 0xf8010010) ||
+ instruction[-2] == 0x7c0802a6) {
+ /* Nothing to be done here, it's an _mcount
+ * call location and r2 will have to be
+ * restored in the _mcount function.
+ */
+ return 1;
+ };
+#endif
pr_err("%s: Expect noop after relocate, got %08x\n",
me->name, *instruction);
return 0;
--
1.8.5.6
[toc] | [next] | [standalone]
| From | Michael Ellerman <mpe@ellerman.id.au> |
|---|---|
| Date | 2016-01-27 11:20 +0100 |
| Message-ID | <qVvmG-1Z6-23@gated-at.bofh.it> |
| In reply to | #1317041 |
Hi Torsten,
On Mon, 2016-01-25 at 16:26 +0100, Torsten Duwe wrote:
> The gcc switch -mprofile-kernel, available for ppc64 on gcc > 4.8.5,
> allows to call _mcount very early in the function, which low-level
> ASM code and code patching functions need to consider.
> Especially the link register and the parameter registers are still
> alive and not yet saved into a new stack frame.
>
> Signed-off-by: Torsten Duwe <duwe@suse.de>
> ---
> arch/powerpc/kernel/entry_64.S | 45 +++++++++++++++++++++++++++++++++++++++--
> arch/powerpc/kernel/ftrace.c | 12 +++++++++--
> arch/powerpc/kernel/module_64.c | 14 +++++++++++++
> 3 files changed, 67 insertions(+), 4 deletions(-)
>
> diff --git a/arch/powerpc/kernel/entry_64.S b/arch/powerpc/kernel/entry_64.S
> index a94f155..e7cd043 100644
> --- a/arch/powerpc/kernel/entry_64.S
> +++ b/arch/powerpc/kernel/entry_64.S
> @@ -1206,7 +1206,12 @@ _GLOBAL(enter_prom)
> #ifdef CONFIG_DYNAMIC_FTRACE
> _GLOBAL(mcount)
> _GLOBAL(_mcount)
> - blr
> + std r0,LRSAVE(r1) /* gcc6 does this _after_ this call _only_ */
> + mflr r0
> + mtctr r0
> + ld r0,LRSAVE(r1)
> + mtlr r0
> + bctr
Can we use r11 instead? eg:
_GLOBAL(_mcount)
mflr r11
mtctr r11
mtlr r0
bctr
Otherwise I worry the std/ld is going to cause a load-hit-store. And it's just
plain more instructions too.
I don't quite grok the gcc code enough to tell if that's always safe, GCC does
use r11 sometimes, but I don't think it ever expects it to survive across
_mcount()?
> @@ -1262,13 +1267,28 @@ _GLOBAL(ftrace_stub)
>
> #ifdef CONFIG_FUNCTION_GRAPH_TRACER
> _GLOBAL(ftrace_graph_caller)
> +#ifdef CC_USING_MPROFILE_KERNEL
> + /* with -mprofile-kernel, parameter regs are still alive at _mcount */
> + std r10, 104(r1)
> + std r9, 96(r1)
> + std r8, 88(r1)
> + std r7, 80(r1)
> + std r6, 72(r1)
> + std r5, 64(r1)
> + std r4, 56(r1)
> + std r3, 48(r1)
> + mfctr r4 /* ftrace_caller has moved local addr here */
> + std r4, 40(r1)
> + mflr r3 /* ftrace_caller has restored LR from stack */
> +#else
> /* load r4 with local address */
> ld r4, 128(r1)
> - subi r4, r4, MCOUNT_INSN_SIZE
>
> /* Grab the LR out of the caller stack frame */
> ld r11, 112(r1)
> ld r3, 16(r11)
> +#endif
> + subi r4, r4, MCOUNT_INSN_SIZE
>
> bl prepare_ftrace_return
> nop
AFAICS these end up being the only instructions shared between the two
versions. Which I don't think is worth the semantic burden of all the #ifdefs.
So please just write it as two separate functions, one for
CC_USING_MPROFILE_KERNEL and one for not.
> @@ -1277,6 +1297,26 @@ _GLOBAL(ftrace_graph_caller)
> * prepare_ftrace_return gives us the address we divert to.
> * Change the LR in the callers stack frame to this.
> */
> +
> +#ifdef CC_USING_MPROFILE_KERNEL
> + mtlr r3
> +
> + ld r0, 40(r1)
> + mtctr r0
> + ld r10, 104(r1)
> + ld r9, 96(r1)
> + ld r8, 88(r1)
> + ld r7, 80(r1)
> + ld r6, 72(r1)
> + ld r5, 64(r1)
> + ld r4, 56(r1)
> + ld r3, 48(r1)
> +
> + addi r1, r1, 112
> + mflr r0
> + std r0, LRSAVE(r1)
> + bctr
> +#else
> ld r11, 112(r1)
> std r3, 16(r11)
>
> @@ -1284,6 +1324,7 @@ _GLOBAL(ftrace_graph_caller)
> mtlr r0
> addi r1, r1, 112
> blr
> +#endif
>
> _GLOBAL(return_to_handler)
> /* need to save return values */
> diff --git a/arch/powerpc/kernel/ftrace.c b/arch/powerpc/kernel/ftrace.c
> index 44d4d8e..080c525 100644
> --- a/arch/powerpc/kernel/ftrace.c
> +++ b/arch/powerpc/kernel/ftrace.c
> @@ -306,11 +306,19 @@ __ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr)
> * The load offset is different depending on the ABI. For simplicity
> * just mask it out when doing the compare.
> */
> +#ifndef CC_USING_MPROFILE_KERNEL
> if ((op[0] != 0x48000008) || ((op[1] & 0xffff0000) != 0xe8410000)) {
> - pr_err("Unexpected call sequence: %x %x\n", op[0], op[1]);
> + pr_err("Unexpected call sequence at %p: %x %x\n",
> + ip, op[0], op[1]);
> return -EINVAL;
> }
> -
> +#else
> + /* look for patched "NOP" on ppc64 with -mprofile-kernel */
> + if (op[0] != 0x60000000) {
That is "PPC_INST_NOP".
> + pr_err("Unexpected call at %p: %x\n", ip, op[0]);
> + return -EINVAL;
> + }
> +#endif
Can you please break that out into a static inline, with separate versions for
the two cases.
We should aim for no #ifdefs inside functions.
> diff --git a/arch/powerpc/kernel/module_64.c b/arch/powerpc/kernel/module_64.c
> index 6838451..30f6be1 100644
> --- a/arch/powerpc/kernel/module_64.c
> +++ b/arch/powerpc/kernel/module_64.c
> @@ -475,6 +475,20 @@ static unsigned long stub_for_addr(Elf64_Shdr *sechdrs,
> static int restore_r2(u32 *instruction, struct module *me)
> {
> if (*instruction != PPC_INST_NOP) {
> +#ifdef CC_USING_MPROFILE_KERNEL
> + /* -mprofile_kernel sequence starting with
> + * mflr r0 and maybe std r0, LRSAVE(r1)
> + */
> + if ((instruction[-3] == 0x7c0802a6 &&
> + instruction[-2] == 0xf8010010) ||
> + instruction[-2] == 0x7c0802a6) {
> + /* Nothing to be done here, it's an _mcount
> + * call location and r2 will have to be
> + * restored in the _mcount function.
> + */
> + return 1;
> + };
> +#endif
Again I'd rather that was in a helper static inline.
And some #defines for the instructions would also help.
> pr_err("%s: Expect noop after relocate, got %08x\n",
> me->name, *instruction);
> return 0;
cheers
[toc] | [prev] | [next] | [standalone]
| From | Torsten Duwe <duwe@lst.de> |
|---|---|
| Date | 2016-01-27 11:50 +0100 |
| Message-ID | <qVvPH-2dw-13@gated-at.bofh.it> |
| In reply to | #1318825 |
On Wed, Jan 27, 2016 at 09:19:27PM +1100, Michael Ellerman wrote:
> Hi Torsten,
>
> > +++ b/arch/powerpc/kernel/entry_64.S
> > @@ -1206,7 +1206,12 @@ _GLOBAL(enter_prom)
> > #ifdef CONFIG_DYNAMIC_FTRACE
> > _GLOBAL(mcount)
> > _GLOBAL(_mcount)
> > - blr
> > + std r0,LRSAVE(r1) /* gcc6 does this _after_ this call _only_ */
> > + mflr r0
> > + mtctr r0
> > + ld r0,LRSAVE(r1)
> > + mtlr r0
> > + bctr
>
> Can we use r11 instead? eg:
>
> _GLOBAL(_mcount)
> mflr r11
> mtctr r11
> mtlr r0
> bctr
>
> Otherwise I worry the std/ld is going to cause a load-hit-store. And it's just
> plain more instructions too.
>
> I don't quite grok the gcc code enough to tell if that's always safe, GCC does
> use r11 sometimes, but I don't think it ever expects it to survive across
> _mcount()?
I used r11 in that area once, and it crashed, but I don't recall the deatils.
We'll see. The performance shouldn't be critical, as the code is only used
during boot-up. With DYNAMIC_FTRACE, The calls will be replaced by
0x600000^W PPC_INST_NOP :)
> >
> > bl prepare_ftrace_return
> > nop
>
> AFAICS these end up being the only instructions shared between the two
> versions. Which I don't think is worth the semantic burden of all the #ifdefs.
> So please just write it as two separate functions, one for
> CC_USING_MPROFILE_KERNEL and one for not.
>
> > index 44d4d8e..080c525 100644
> > --- a/arch/powerpc/kernel/ftrace.c
> > +++ b/arch/powerpc/kernel/ftrace.c
> > @@ -306,11 +306,19 @@ __ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr)
> > * The load offset is different depending on the ABI. For simplicity
> > * just mask it out when doing the compare.
> > */
> > +#ifndef CC_USING_MPROFILE_KERNEL
> > if ((op[0] != 0x48000008) || ((op[1] & 0xffff0000) != 0xe8410000)) {
> > - pr_err("Unexpected call sequence: %x %x\n", op[0], op[1]);
> > + pr_err("Unexpected call sequence at %p: %x %x\n",
> > + ip, op[0], op[1]);
> > return -EINVAL;
> > }
> > -
> > +#else
> > + /* look for patched "NOP" on ppc64 with -mprofile-kernel */
> > + if (op[0] != 0x60000000) {
>
> That is "PPC_INST_NOP".
>
> > + pr_err("Unexpected call at %p: %x\n", ip, op[0]);
> > + return -EINVAL;
> > + }
> > +#endif
>
> Can you please break that out into a static inline, with separate versions for
> the two cases.
>
> We should aim for no #ifdefs inside functions.
Points taken.
Does this set _work_ for you now? That'd be great to hear.
Stay tuned for v7...
Torsten
[toc] | [prev] | [next] | [standalone]
| From | Alan Modra <amodra@gmail.com> |
|---|---|
| Date | 2016-01-27 14:00 +0100 |
| Message-ID | <qVxRw-3BF-13@gated-at.bofh.it> |
| In reply to | #1318825 |
On Wed, Jan 27, 2016 at 09:19:27PM +1100, Michael Ellerman wrote: > Hi Torsten, > > On Mon, 2016-01-25 at 16:26 +0100, Torsten Duwe wrote: > > The gcc switch -mprofile-kernel, available for ppc64 on gcc > 4.8.5, > > allows to call _mcount very early in the function, which low-level > > ASM code and code patching functions need to consider. > > Especially the link register and the parameter registers are still > > alive and not yet saved into a new stack frame. > > > > Signed-off-by: Torsten Duwe <duwe@suse.de> > > --- > > arch/powerpc/kernel/entry_64.S | 45 +++++++++++++++++++++++++++++++++++++++-- > > arch/powerpc/kernel/ftrace.c | 12 +++++++++-- > > arch/powerpc/kernel/module_64.c | 14 +++++++++++++ > > 3 files changed, 67 insertions(+), 4 deletions(-) > > > > diff --git a/arch/powerpc/kernel/entry_64.S b/arch/powerpc/kernel/entry_64.S > > index a94f155..e7cd043 100644 > > --- a/arch/powerpc/kernel/entry_64.S > > +++ b/arch/powerpc/kernel/entry_64.S > > @@ -1206,7 +1206,12 @@ _GLOBAL(enter_prom) > > #ifdef CONFIG_DYNAMIC_FTRACE > > _GLOBAL(mcount) > > _GLOBAL(_mcount) > > - blr > > + std r0,LRSAVE(r1) /* gcc6 does this _after_ this call _only_ */ > > + mflr r0 > > + mtctr r0 > > + ld r0,LRSAVE(r1) > > + mtlr r0 > > + bctr > > Can we use r11 instead? eg: > > _GLOBAL(_mcount) > mflr r11 > mtctr r11 > mtlr r0 > bctr Depends on what you need to support. As Torsten says, the code to call _mcount when -mprofile-kernel is emitted before the prologue of a function (similar to -m32), but after the ELFv2 global entry point code. If you trash r11 here you're killing the static chain pointer, used by C nested functions or other languages that use a static chain, eg. Pascal. r11 has *not* been saved for ELFv2. r12 might be a better choice for a temp reg. -- Alan Modra Australia Development Lab, IBM
[toc] | [prev] | [next] | [standalone]
| From | Torsten Duwe <duwe@lst.de> |
|---|---|
| Date | 2016-01-27 14:50 +0100 |
| Message-ID | <qVyDU-4eI-13@gated-at.bofh.it> |
| In reply to | #1318932 |
On Wed, Jan 27, 2016 at 11:28:09PM +1030, Alan Modra wrote: > On Wed, Jan 27, 2016 at 09:19:27PM +1100, Michael Ellerman wrote: > > > > Can we use r11 instead? eg: > > > > _GLOBAL(_mcount) > > mflr r11 > > mtctr r11 > > mtlr r0 > > bctr > > Depends on what you need to support. As Torsten says, the code to > call _mcount when -mprofile-kernel is emitted before the prologue of a > function (similar to -m32), but after the ELFv2 global entry point > code. If you trash r11 here you're killing the static chain pointer, > used by C nested functions or other languages that use a static chain, > eg. Pascal. r11 has *not* been saved for ELFv2. Even if nested functions aren't supported in the Linux kernel(?), I think it was an earlier version of mcount when r11 usage ruined my day. > r12 might be a better choice for a temp reg. Good idea. r12 holds the function entry point and is used to calculate the new TOC value just _before_ the call. It should be available. I'll try, thanks for the hint. Torsten
[toc] | [prev] | [standalone]
Back to top | Article view | linux.kernel
csiph-web