linuxppc-dev.lists.ozlabs.org archive mirror
 help / color / mirror / Atom feed
From: Balbir Singh <bsingharora@gmail.com>
To: Torsten Duwe <duwe@lst.de>, Michael Ellerman <mpe@ellerman.id.au>
Cc: Petr Mladek <pmladek@suse.com>, Jessica Yu <jeyu@redhat.com>,
	Jiri Kosina <jkosina@suse.cz>,
	linux-kernel@vger.kernel.org,
	Steven Rostedt <rostedt@goodmis.org>,
	Kamalesh Babulal <kamalesh@linux.vnet.ibm.com>,
	live-patching@vger.kernel.org, Miroslav Benes <mbenes@suse.cz>,
	linuxppc-dev@lists.ozlabs.org
Subject: Re: [PATCH v8 8/8] livepatch: Detect offset for the ftrace location during build
Date: Wed, 24 Feb 2016 17:37:20 +1100	[thread overview]
Message-ID: <56CD4FA0.4090109@gmail.com> (raw)
In-Reply-To: <20160223170017.GB21932@lst.de>



On 24/02/16 04:00, Torsten Duwe wrote:
> On Wed, Feb 17, 2016 at 02:08:41PM +1100, Michael Ellerman wrote:
>> That stub uses r2 to find the location of itself, but it only works if r2 holds
>> the TOC for scsi_mod.ko. In this case r2 still contains ibmvscsi.ko's TOC.
> Here's my solution, a bit rough still. This replaces the module_64.c change
> from patch 2/8:
>
> I shuffle the trampoline instructions so the R2-save-to-stack comes first.
> This allows me to construct a profiling trampoline code that
> looks very similar. The first instruction, harmful to -mprofile-kernel
> can now be replaced with a load of the *kernel* TOC value via paca.
> Arithmetic is done in r11, to keep it bitwise identical where possible.
> Likewise the result is "moved" to r12 via an addi.
Michael has a similar change that he intends to post. I gave this a run but
the system crashes on boot.

>
> What do you think?
>
> 	Torsten
>
>
> --- a/arch/powerpc/kernel/module_64.c
> +++ b/arch/powerpc/kernel/module_64.c
> @@ -27,6 +27,7 @@
>  #include <linux/bug.h>
>  #include <linux/uaccess.h>
>  #include <asm/module.h>
> +#include <asm/asm-offsets.h>
Creates an include conflict for me. NMI_MASK, PGD_TABLE_SIZE, etc
are already defined elsewhere.
>  #include <asm/firmware.h>
>  #include <asm/code-patching.h>
>  #include <linux/sort.h>
> @@ -123,10 +124,10 @@ struct ppc64_stub_entry
>   */
>  
>  static u32 ppc64_stub_insns[] = {
> -	0x3d620000,			/* addis   r11,r2, <high> */
> -	0x396b0000,			/* addi    r11,r11, <low> */
>  	/* Save current r2 value in magic place on the stack. */
>  	0xf8410000|R2_STACK_OFFSET,	/* std     r2,R2_STACK_OFFSET(r1) */
> +	0x3d620000,			/* addis   r11,r2, <high> */
> +	0x396b0000,			/* addi    r11,r11, <low> */
>  	0xe98b0020,			/* ld      r12,32(r11) */
>  #if !defined(_CALL_ELF) || _CALL_ELF != 2
>  	/* Set up new r2 from function descriptor */
> @@ -136,13 +137,30 @@ static u32 ppc64_stub_insns[] = {
>  	0x4e800420			/* bctr */
>  };
>  
> +/* In case of _mcount calls or dynamic ftracing with -mprofile-kernel,
> + * the stack frame already holds the TOC value of the original
> + * caller. And even worse, for a leaf function without global data
> + * references, R2 holds the TOC of the caller's caller, e.g. is
> + * completely undefined. So: do not dare to write r2 anywhere, and use
> + * the kernel's TOC to find _mcount / ftrace_caller.  Mcount and
> + * ftrace_caller will then take care of the r2 value themselves.
> + */
> +static u32 ppc64_profile_stub_insns[] = {
> +	0xe98d0000|PACATOC,		/* ld	   r12,PACATOC(r13) */
> +	0x3d6c0000,			/* addis   r11,r12, <high> */
> +	0x396b0000,			/* addi    r11,r11, <low> */
> +	0x398b0000,			/* addi    r12,r11,0 */
> +	0x7d8903a6,			/* mtctr   r12 */
> +	0x4e800420			/* bctr */
> +};
> +
>  #ifdef CONFIG_DYNAMIC_FTRACE
>  
>  static u32 ppc64_stub_mask[] = {
> +	0xee330000,
> +	0xfff10000,
>  	0xffff0000,
> -	0xffff0000,
> -	0xffffffff,
> -	0xffffffff,
> +	0x2fffffdf,
>  #if !defined(_CALL_ELF) || _CALL_ELF != 2
>  	0xffffffff,
>  #endif
> @@ -168,10 +186,15 @@ bool is_module_trampoline(u32 *p)
>  		if ((insna & mask) != (insnb & mask))
>  			return false;
>  	}
> +	if (insns[0] != ppc64_stub_insns[0] &&
> +	    insns[0] != ppc64_profile_stub_insns[0])
> +		return false;
>  
Michael was mentioning a better way of doing this, we can simplify the
checking bits

>  	return true;
>  }
>  
> +extern unsigned long __toc_start;
> +
>  int module_trampoline_target(struct module *mod, u32 *trampoline,
>  			     unsigned long *target)
>  {
> @@ -180,7 +203,7 @@ int module_trampoline_target(struct modu
>  	long offset;
>  	void *toc_entry;
>  
> -	if (probe_kernel_read(buf, trampoline, sizeof(buf)))
> +	if (probe_kernel_read(buf, trampoline+1, sizeof(buf)))
>  		return -EFAULT;
>  
>  	upper = buf[0] & 0xffff;
> @@ -189,6 +212,13 @@ int module_trampoline_target(struct modu
>  	/* perform the addis/addi, both signed */
>  	offset = ((short)upper << 16) + (short)lower;
>  
> +	/* profiling trampolines work differently */
> +	if ((buf[0] & 0xFFFF0000) == 0x3D6C0000)
> +	  {
> +	    *target = offset + (unsigned long)(&__toc_start) + 0x8000UL;
> +	    return 0;
> +	  }
> +
>  	/*
>  	 * Now get the address this trampoline jumps to. This
>  	 * is always 32 bytes into our trampoline stub.
> @@ -427,14 +457,24 @@ static inline unsigned long my_r2(Elf64_
>  static inline int create_stub(Elf64_Shdr *sechdrs,
>  			      struct ppc64_stub_entry *entry,
>  			      unsigned long addr,
> -			      struct module *me)
> +			      struct module *me,
> +			      bool prof)
>  {
>  	long reladdr;
>  
> -	memcpy(entry->jump, ppc64_stub_insns, sizeof(ppc64_stub_insns));
> +	if (prof)
> +	{
> +		memcpy(entry->jump, ppc64_profile_stub_insns,
> +		       sizeof(ppc64_stub_insns));
>  
> -	/* Stub uses address relative to r2. */
> -	reladdr = (unsigned long)entry - my_r2(sechdrs, me);
> +		/* Stub uses address relative to kernel TOC. */
> +		reladdr = addr - ((unsigned long)(&__toc_start) + 0x8000UL);
> +	} else {
> +		memcpy(entry->jump, ppc64_stub_insns, sizeof(ppc64_stub_insns));
> +
> +		/* Stub uses address relative to r2. */
> +		reladdr = (unsigned long)entry - my_r2(sechdrs, me);
> +	}
>  	if (reladdr > 0x7FFFFFFF || reladdr < -(0x80000000L)) {
>  		pr_err("%s: Address %p of stub out of range of %p.\n",
>  		       me->name, (void *)reladdr, (void *)my_r2);
> @@ -442,8 +482,8 @@ static inline int create_stub(Elf64_Shdr
>  	}
>  	pr_debug("Stub %p get data from reladdr %li\n", entry, reladdr);
>  
> -	entry->jump[0] |= PPC_HA(reladdr);
> -	entry->jump[1] |= PPC_LO(reladdr);
> +	entry->jump[1] |= PPC_HA(reladdr);
> +	entry->jump[2] |= PPC_LO(reladdr);
>  	entry->funcdata = func_desc(addr);
>  	return 1;
>  }
> @@ -452,7 +492,8 @@ static inline int create_stub(Elf64_Shdr
>     stub to set up the TOC ptr (r2) for the function. */
>  static unsigned long stub_for_addr(Elf64_Shdr *sechdrs,
>  				   unsigned long addr,
> -				   struct module *me)
> +				   struct module *me,
> +				   bool prof)
>  {
>  	struct ppc64_stub_entry *stubs;
>  	unsigned int i, num_stubs;
> @@ -468,44 +509,17 @@ static unsigned long stub_for_addr(Elf64
>  			return (unsigned long)&stubs[i];
>  	}
>  
> -	if (!create_stub(sechdrs, &stubs[i], addr, me))
> +	if (!create_stub(sechdrs, &stubs[i], addr, me, prof))
>  		return 0;
>  
>  	return (unsigned long)&stubs[i];
>  }
>  
> -#ifdef CC_USING_MPROFILE_KERNEL
> -static int is_early_mcount_callsite(u32 *instruction)
> -{
> -	/* -mprofile-kernel sequence starting with
> -	 * mflr r0 and maybe std r0, LRSAVE(r1).
> -	 */
> -	if ((instruction[-3] == PPC_INST_MFLR &&
> -	     instruction[-2] == PPC_INST_STD_LR) ||
> -	    instruction[-2] == PPC_INST_MFLR) {
> -		/* Nothing to be done here, it's an _mcount
> -		 * call location and r2 will have to be
> -		 * restored in the _mcount function.
> -		 */
> -		return 1;
> -	}
> -	return 0;
> -}
> -#else
> -/* without -mprofile-kernel, mcount calls are never early */
> -static int is_early_mcount_callsite(u32 *instruction)
> -{
> -	return 0;
> -}
> -#endif
> -

We need to remove the SQUASH_TOC_SAVE_INSNS bits as well, now
that the ppc64_profile_stub_insns does not save r2
>  /* We expect a noop next: if it is, replace it with instruction to
>     restore r2. */
>  static int restore_r2(u32 *instruction, struct module *me)
>  {
>  	if (*instruction != PPC_INST_NOP) {
> -		if (is_early_mcount_callsite(instruction))
> -			return 1;
>  		pr_err("%s: Expect noop after relocate, got %08x\n",
>  		       me->name, *instruction);
>  		return 0;
> @@ -515,6 +529,12 @@ static int restore_r2(u32 *instruction,
>  	return 1;
>  }
>  
> +#ifdef CC_USING_MPROFILE_KERNEL
> +#define IS_KERNEL_PROFILING_CALL (!strcmp("_mcount", strtab+sym->st_name))
> +#else
> +#define IS_KERNEL_PROFILING_CALL 0
> +#endif
> +
>  int apply_relocate_add(Elf64_Shdr *sechdrs,
>  		       const char *strtab,
>  		       unsigned int symindex,
> @@ -630,11 +650,15 @@ int apply_relocate_add(Elf64_Shdr *sechd
>  		case R_PPC_REL24:
>  			/* FIXME: Handle weak symbols here --RR */
>  			if (sym->st_shndx == SHN_UNDEF) {
> +				bool prof = false;
> +				if (IS_KERNEL_PROFILING_CALL)
> +					prof = true;
>  				/* External: go via stub */
> -				value = stub_for_addr(sechdrs, value, me);
> +				value = stub_for_addr(sechdrs, value, me, prof);
>  				if (!value)
>  					return -ENOENT;
> -				if (!restore_r2((u32 *)location + 1, me))
> +				if (!prof &&
> +				    !restore_r2((u32 *)location + 1, me))
>  					return -ENOEXEC;
>  			} else
>  				value += local_entry_offset(sym);
> @@ -722,7 +746,7 @@ int apply_relocate_add(Elf64_Shdr *sechd
>  	me->arch.toc = my_r2(sechdrs, me);
>  	me->arch.tramp = stub_for_addr(sechdrs,
>  				       (unsigned long)ftrace_caller,
> -				       me);
> +				       me, true);
>  #endif
>  
>  	return 0;

Looks like we are getting closer to the final solution

Thanks,
Balbir

  reply	other threads:[~2016-02-24  6:37 UTC|newest]

Thread overview: 44+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2016-02-10 17:29 [PATCH v8 0/8] ftrace with regs + live patching for ppc64 LE (ABI v2) Torsten Duwe
2016-01-28 15:32 ` [PATCH v8 8/8] livepatch: Detect offset for the ftrace location during build Torsten Duwe
2016-02-12 16:13   ` Balbir Singh
2016-02-12 16:45     ` Petr Mladek
2016-02-13  1:33       ` Balbir Singh
2016-02-16  5:47       ` Kamalesh Babulal
2016-02-16  8:23         ` Torsten Duwe
2016-02-16 10:30           ` Kamalesh Babulal
2016-02-16 10:39             ` Torsten Duwe
2016-02-16 13:57               ` Petr Mladek
2016-02-17  3:08                 ` Michael Ellerman
2016-02-23 17:00                   ` Torsten Duwe
2016-02-24  6:37                     ` Balbir Singh [this message]
2016-02-24  6:55                       ` Balbir Singh
2016-02-24  9:23                         ` Torsten Duwe
2016-02-24 11:22                           ` Balbir Singh
2016-02-24  7:51                     ` Kamalesh Babulal
2016-02-10 16:21 ` [PATCH v8 1/8] ppc64 (le): prepare for -mprofile-kernel Torsten Duwe
2016-02-17 10:55   ` Michael Ellerman
2016-02-17 11:30     ` Torsten Duwe
2016-02-17 11:39       ` Michael Ellerman
2016-02-10 16:22 ` [PATCH v8 2/8] ppc64le FTRACE_WITH_REGS implementation Torsten Duwe
2016-02-10 16:22 ` [PATCH v8 3/8] ppc use ftrace_modify_all_code default Torsten Duwe
2016-02-10 16:25 ` [PATCH v8 4/8] ppc64 ftrace_with_regs configuration variables Torsten Duwe
2016-02-11  7:48   ` Balbir Singh
2016-02-11  8:39     ` Kamalesh Babulal
2016-02-11  9:35       ` Balbir Singh
2016-02-11 13:00         ` Murali Sampath
2016-02-11 13:00         ` Murali Sampath
2016-02-11  8:42     ` Torsten Duwe
2016-02-11  9:34       ` Balbir Singh
2016-02-15 10:27       ` Michael Ellerman
2016-02-15 12:56         ` Jiri Kosina
2016-02-15 14:04         ` Torsten Duwe
2016-02-15 22:21           ` Torsten Duwe
2016-02-16  4:53             ` Balbir Singh
2016-02-16 10:09           ` Michael Ellerman
2016-02-16 10:35             ` Torsten Duwe
2016-02-10 16:27 ` [PATCH v8 5/8] ppc64 ftrace_with_regs: disable profiling for some files Torsten Duwe
2016-02-10 16:34 ` [PATCH v8 6/8] Implement kernel live patching for ppc64le (ABIv2) Torsten Duwe
2016-02-11  9:01   ` Miroslav Benes
2016-02-10 16:36 ` [PATCH v8 7/8] Enable LIVEPATCH to be configured on ppc64le and add livepatch.o if it is selected Torsten Duwe
2016-02-11  6:18 ` [PATCH v8 0/8] ftrace with regs + live patching for ppc64 LE (ABI v2) Balbir Singh
2016-02-11  8:38   ` Torsten Duwe

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=56CD4FA0.4090109@gmail.com \
    --to=bsingharora@gmail.com \
    --cc=duwe@lst.de \
    --cc=jeyu@redhat.com \
    --cc=jkosina@suse.cz \
    --cc=kamalesh@linux.vnet.ibm.com \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linuxppc-dev@lists.ozlabs.org \
    --cc=live-patching@vger.kernel.org \
    --cc=mbenes@suse.cz \
    --cc=mpe@ellerman.id.au \
    --cc=pmladek@suse.com \
    --cc=rostedt@goodmis.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).