* Re: [PATCH 1/3] ftrace: Add module to ftrace_make_call() parameters
From: kbuild test robot @ 2018-02-25 11:53 UTC (permalink / raw)
To: Alexander Sverdlin
Cc: kbuild-all, Steven Rostedt, Ingo Molnar, linux-arm-kernel,
linux-kernel, Alexander Sverdlin, Russell King, Catalin Marinas,
Will Deacon, Steven Miao, Tony Luck, Fenghua Yu, James Hogan,
Michal Simek, Ralf Baechle, Benjamin Herrenschmidt,
Paul Mackerras, Michael Ellerman, Martin Schwidefsky,
Heiko Carstens, Yoshinori Sato, Rich Felker, David S. Miller,
Chris Metcalf, Thomas Gleixner, H. Peter Anvin, x86,
adi-buildroot-devel, linux-ia64, linux-metag, linux-mips,
linuxppc-dev, linux-s390, linux-sh, sparclinux
In-Reply-To: <20180223165849.16388-2-alexander.sverdlin@nokia.com>
[-- Attachment #1: Type: text/plain, Size: 8111 bytes --]
Hi Alexander,
I love your patch! Yet something to improve:
[auto build test ERROR on tip/perf/core]
[also build test ERROR on v4.16-rc2 next-20180223]
[if your patch is applied to the wrong git tree, please drop us a note to help improve the system]
url: https://github.com/0day-ci/linux/commits/Alexander-Sverdlin/ARM-Implement-MODULE_PLT-support-in-FTRACE/20180225-191957
config: x86_64-randconfig-x011-201808 (attached as .config)
compiler: gcc-7 (Debian 7.3.0-1) 7.3.0
reproduce:
# save the attached .config to linux build tree
make ARCH=x86_64
All error/warnings (new ones prefixed by >>):
kernel/trace/ftrace.c: In function 'ftrace_module_enable':
>> kernel/trace/ftrace.c:5851:39: error: passing argument 1 of '__ftrace_replace_code' from incompatible pointer type [-Werror=incompatible-pointer-types]
int failed = __ftrace_replace_code(rec, 1);
^~~
kernel/trace/ftrace.c:2424:1: note: expected 'struct module *' but argument is of type 'struct dyn_ftrace *'
__ftrace_replace_code(struct module *mod, struct dyn_ftrace *rec, int enable)
^~~~~~~~~~~~~~~~~~~~~
>> kernel/trace/ftrace.c:5851:44: warning: passing argument 2 of '__ftrace_replace_code' makes pointer from integer without a cast [-Wint-conversion]
int failed = __ftrace_replace_code(rec, 1);
^
kernel/trace/ftrace.c:2424:1: note: expected 'struct dyn_ftrace *' but argument is of type 'int'
__ftrace_replace_code(struct module *mod, struct dyn_ftrace *rec, int enable)
^~~~~~~~~~~~~~~~~~~~~
>> kernel/trace/ftrace.c:5851:17: error: too few arguments to function '__ftrace_replace_code'
int failed = __ftrace_replace_code(rec, 1);
^~~~~~~~~~~~~~~~~~~~~
kernel/trace/ftrace.c:2424:1: note: declared here
__ftrace_replace_code(struct module *mod, struct dyn_ftrace *rec, int enable)
^~~~~~~~~~~~~~~~~~~~~
cc1: some warnings being treated as errors
vim +/__ftrace_replace_code +5851 kernel/trace/ftrace.c
93eb677d Steven Rostedt 2009-04-15 5797
7dcd182b Jessica Yu 2016-02-16 5798 void ftrace_module_enable(struct module *mod)
b7ffffbb Steven Rostedt (Red Hat 2016-01-07 5799) {
b7ffffbb Steven Rostedt (Red Hat 2016-01-07 5800) struct dyn_ftrace *rec;
b7ffffbb Steven Rostedt (Red Hat 2016-01-07 5801) struct ftrace_page *pg;
b7ffffbb Steven Rostedt (Red Hat 2016-01-07 5802)
b7ffffbb Steven Rostedt (Red Hat 2016-01-07 5803) mutex_lock(&ftrace_lock);
b7ffffbb Steven Rostedt (Red Hat 2016-01-07 5804)
b7ffffbb Steven Rostedt (Red Hat 2016-01-07 5805) if (ftrace_disabled)
b7ffffbb Steven Rostedt (Red Hat 2016-01-07 5806) goto out_unlock;
b7ffffbb Steven Rostedt (Red Hat 2016-01-07 5807)
b7ffffbb Steven Rostedt (Red Hat 2016-01-07 5808) /*
b7ffffbb Steven Rostedt (Red Hat 2016-01-07 5809) * If the tracing is enabled, go ahead and enable the record.
b7ffffbb Steven Rostedt (Red Hat 2016-01-07 5810) *
b7ffffbb Steven Rostedt (Red Hat 2016-01-07 5811) * The reason not to enable the record immediatelly is the
b7ffffbb Steven Rostedt (Red Hat 2016-01-07 5812) * inherent check of ftrace_make_nop/ftrace_make_call for
b7ffffbb Steven Rostedt (Red Hat 2016-01-07 5813) * correct previous instructions. Making first the NOP
b7ffffbb Steven Rostedt (Red Hat 2016-01-07 5814) * conversion puts the module to the correct state, thus
b7ffffbb Steven Rostedt (Red Hat 2016-01-07 5815) * passing the ftrace_make_call check.
b7ffffbb Steven Rostedt (Red Hat 2016-01-07 5816) *
b7ffffbb Steven Rostedt (Red Hat 2016-01-07 5817) * We also delay this to after the module code already set the
b7ffffbb Steven Rostedt (Red Hat 2016-01-07 5818) * text to read-only, as we now need to set it back to read-write
b7ffffbb Steven Rostedt (Red Hat 2016-01-07 5819) * so that we can modify the text.
b7ffffbb Steven Rostedt (Red Hat 2016-01-07 5820) */
b7ffffbb Steven Rostedt (Red Hat 2016-01-07 5821) if (ftrace_start_up)
b7ffffbb Steven Rostedt (Red Hat 2016-01-07 5822) ftrace_arch_code_modify_prepare();
b7ffffbb Steven Rostedt (Red Hat 2016-01-07 5823)
b7ffffbb Steven Rostedt (Red Hat 2016-01-07 5824) do_for_each_ftrace_rec(pg, rec) {
b7ffffbb Steven Rostedt (Red Hat 2016-01-07 5825) int cnt;
b7ffffbb Steven Rostedt (Red Hat 2016-01-07 5826) /*
b7ffffbb Steven Rostedt (Red Hat 2016-01-07 5827) * do_for_each_ftrace_rec() is a double loop.
b7ffffbb Steven Rostedt (Red Hat 2016-01-07 5828) * module text shares the pg. If a record is
b7ffffbb Steven Rostedt (Red Hat 2016-01-07 5829) * not part of this module, then skip this pg,
b7ffffbb Steven Rostedt (Red Hat 2016-01-07 5830) * which the "break" will do.
b7ffffbb Steven Rostedt (Red Hat 2016-01-07 5831) */
3e234289 Steven Rostedt (VMware 2017-03-03 5832) if (!within_module_core(rec->ip, mod) &&
3e234289 Steven Rostedt (VMware 2017-03-03 5833) !within_module_init(rec->ip, mod))
b7ffffbb Steven Rostedt (Red Hat 2016-01-07 5834) break;
b7ffffbb Steven Rostedt (Red Hat 2016-01-07 5835)
b7ffffbb Steven Rostedt (Red Hat 2016-01-07 5836) cnt = 0;
b7ffffbb Steven Rostedt (Red Hat 2016-01-07 5837)
b7ffffbb Steven Rostedt (Red Hat 2016-01-07 5838) /*
b7ffffbb Steven Rostedt (Red Hat 2016-01-07 5839) * When adding a module, we need to check if tracers are
b7ffffbb Steven Rostedt (Red Hat 2016-01-07 5840) * currently enabled and if they are, and can trace this record,
b7ffffbb Steven Rostedt (Red Hat 2016-01-07 5841) * we need to enable the module functions as well as update the
b7ffffbb Steven Rostedt (Red Hat 2016-01-07 5842) * reference counts for those function records.
b7ffffbb Steven Rostedt (Red Hat 2016-01-07 5843) */
b7ffffbb Steven Rostedt (Red Hat 2016-01-07 5844) if (ftrace_start_up)
b7ffffbb Steven Rostedt (Red Hat 2016-01-07 5845) cnt += referenced_filters(rec);
b7ffffbb Steven Rostedt (Red Hat 2016-01-07 5846)
b7ffffbb Steven Rostedt (Red Hat 2016-01-07 5847) /* This clears FTRACE_FL_DISABLED */
b7ffffbb Steven Rostedt (Red Hat 2016-01-07 5848) rec->flags = cnt;
b7ffffbb Steven Rostedt (Red Hat 2016-01-07 5849)
b7ffffbb Steven Rostedt (Red Hat 2016-01-07 5850) if (ftrace_start_up && cnt) {
b7ffffbb Steven Rostedt (Red Hat 2016-01-07 @5851) int failed = __ftrace_replace_code(rec, 1);
b7ffffbb Steven Rostedt (Red Hat 2016-01-07 5852) if (failed) {
b7ffffbb Steven Rostedt (Red Hat 2016-01-07 5853) ftrace_bug(failed, rec);
b7ffffbb Steven Rostedt (Red Hat 2016-01-07 5854) goto out_loop;
b7ffffbb Steven Rostedt (Red Hat 2016-01-07 5855) }
b7ffffbb Steven Rostedt (Red Hat 2016-01-07 5856) }
b7ffffbb Steven Rostedt (Red Hat 2016-01-07 5857)
b7ffffbb Steven Rostedt (Red Hat 2016-01-07 5858) } while_for_each_ftrace_rec();
b7ffffbb Steven Rostedt (Red Hat 2016-01-07 5859)
b7ffffbb Steven Rostedt (Red Hat 2016-01-07 5860) out_loop:
b7ffffbb Steven Rostedt (Red Hat 2016-01-07 5861) if (ftrace_start_up)
b7ffffbb Steven Rostedt (Red Hat 2016-01-07 5862) ftrace_arch_code_modify_post_process();
b7ffffbb Steven Rostedt (Red Hat 2016-01-07 5863)
b7ffffbb Steven Rostedt (Red Hat 2016-01-07 5864) out_unlock:
b7ffffbb Steven Rostedt (Red Hat 2016-01-07 5865) mutex_unlock(&ftrace_lock);
d7fbf8df Steven Rostedt (VMware 2017-06-26 5866)
d7fbf8df Steven Rostedt (VMware 2017-06-26 5867) process_cached_mods(mod->name);
b7ffffbb Steven Rostedt (Red Hat 2016-01-07 5868) }
b7ffffbb Steven Rostedt (Red Hat 2016-01-07 5869)
:::::: The code at line 5851 was first introduced by commit
:::::: b7ffffbb46f205e7727a18bcc7a46c3c2b534f7c ftrace: Add infrastructure for delayed enabling of module functions
:::::: TO: Steven Rostedt (Red Hat) <rostedt@goodmis.org>
:::::: CC: Steven Rostedt <rostedt@goodmis.org>
---
0-DAY kernel test infrastructure Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all Intel Corporation
[-- Attachment #2: .config.gz --]
[-- Type: application/gzip, Size: 27148 bytes --]
^ permalink raw reply
* Re: [PATCH 0/5] PPC32/ioremap: Use memblock API to check for RAM
From: Jonathan Neuschäfer @ 2018-02-24 13:48 UTC (permalink / raw)
To: Christophe LEROY
Cc: Jonathan Neuschäfer, linuxppc-dev, linux-kernel,
Michael Ellerman, linux-mm, Joel Stanley
In-Reply-To: <ca471c17-d2a7-e8e6-2d5a-a5a534e7e6d9@c-s.fr>
[-- Attachment #1: Type: text/plain, Size: 950 bytes --]
On Fri, Feb 23, 2018 at 09:01:17AM +0100, Christophe LEROY wrote:
>
>
> Le 22/02/2018 à 13:15, Jonathan Neuschäfer a écrit :
> > This patchset solves the same problem as my previous one[1] but follows
> > a rather different approach. Instead of implementing DISCONTIGMEM for
> > PowerPC32, I simply switched the "is this RAM" check in __ioremap_caller
> > to the existing page_is_ram function, and unified page_is_ram to search
> > memblock.memory on PPC64 and PPC32.
> >
> > The intended result is, as before, that my Wii can allocate the MMIO
> > range of its GPIO controller, which was previously not possible, because
> > the reserved memory hack (__allow_ioremap_reserved) didn't affect the
> > API in kernel/resource.c.
> >
> > Thanks to Christophe Leroy for reviewing the previous patchset.
>
> I tested your new serie, it doesn't break my 8xx so it is OK for me.
Thanks for testing it!
Jonathan Neuschäfer
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 819 bytes --]
^ permalink raw reply
* Re: [PATCH] fix double ;;s in code
From: Shawn Guo @ 2018-02-24 8:56 UTC (permalink / raw)
To: Pavel Machek
Cc: elfring, kernel list, vgupta, linux, oleg, catalin.marinas,
will.deacon, paulus, benh, mpe, ard.biesheuvel, tglx, mingo, hpa,
x86, scott.bauer, jonathan.derrick, axboe, daniel.lezcano,
maxime.ripard, wens, alexander.deucher, christian.koenig,
David1.Zhou, airlied, robdclark, joro, shli, kernel,
fabio.estevam, akpm, Alexey.Brodkin, mhocko, vbabka,
Vladislav.Zakharov, noamca, yamada.masahiro, sboyd, viresh.kumar,
linus.walleij, heiko, aik, ruscur, david, fbarrat, alistair, robh,
joe, harry.wentland, tony.cheng, Wenjing.Liu, airlied, Ding.Wang,
sylvia.tsai, hersenxs.wu, Rex.Zhu, JinHuiEric.Huang,
dan.carpenter, architt, daniel.vetter, narmstrong, ville.syrjala,
jcrouse, aishpant, noralf, andresx7, Monk.Liu, nicolai.haehnle,
Andrey.Grodzovsky, linux-snps-arc, linux-arm-kernel, kvm-ppc,
linuxppc-dev, linux-efi, linux-block, amd-gfx, dri-devel,
linux-arm-msm, freedreno, iommu, linux-raid
In-Reply-To: <20180224085227.GA12996@amd>
On Sat, Feb 24, 2018 at 09:52:27AM +0100, Pavel Machek wrote:
> Hi!
>
> > > diff --git a/drivers/soc/imx/gpc.c b/drivers/soc/imx/gpc.c
> > > index 53f7275..cfb42f5 100644
> > > --- a/drivers/soc/imx/gpc.c
> > > +++ b/drivers/soc/imx/gpc.c
> > > @@ -348,7 +348,7 @@ static int imx_gpc_old_dt_init(struct device *dev, struct regmap *regmap,
> > > if (i == 1) {
> > > domain->supply = devm_regulator_get(dev, "pu");
> > > if (IS_ERR(domain->supply))
> > > - return PTR_ERR(domain->supply);;
> > > + return PTR_ERR(domain->supply);
> > >
> > > ret = imx_pgc_get_clocks(dev, domain);
> > > if (ret)
> > >
> >
> > Considering the controversy how the changes should be merged, I'm going
> > to send a separate patch just for IMX GPC driver with a reported-by-you
> > tag. Thanks for catching this.
>
> That works for me.
>
> Alternatively... Andrew Morton merged the patch to his -mm tree
> (thanks!), so you don't need to take any action, and it will be
> eventually fixed.
Okay, I'm dropping my patch from IMX tree.
Shawn
^ permalink raw reply
* Re: [PATCH] fix double ;;s in code
From: Pavel Machek @ 2018-02-24 8:52 UTC (permalink / raw)
To: Shawn Guo
Cc: elfring, kernel list, vgupta, linux, oleg, catalin.marinas,
will.deacon, paulus, benh, mpe, ard.biesheuvel, tglx, mingo, hpa,
x86, scott.bauer, jonathan.derrick, axboe, daniel.lezcano,
maxime.ripard, wens, alexander.deucher, christian.koenig,
David1.Zhou, airlied, robdclark, joro, shli, kernel,
fabio.estevam, akpm, Alexey.Brodkin, mhocko, vbabka,
Vladislav.Zakharov, noamca, yamada.masahiro, sboyd, viresh.kumar,
linus.walleij, heiko, aik, ruscur, david, fbarrat, alistair, robh,
joe, harry.wentland, tony.cheng, Wenjing.Liu, airlied, Ding.Wang,
sylvia.tsai, hersenxs.wu, Rex.Zhu, JinHuiEric.Huang,
dan.carpenter, architt, daniel.vetter, narmstrong, ville.syrjala,
jcrouse, aishpant, noralf, andresx7, Monk.Liu, nicolai.haehnle,
Andrey.Grodzovsky, linux-snps-arc, linux-arm-kernel, kvm-ppc,
linuxppc-dev, linux-efi, linux-block, amd-gfx, dri-devel,
linux-arm-msm, freedreno, iommu, linux-raid
In-Reply-To: <20180222090932.GJ3217@dragon>
[-- Attachment #1: Type: text/plain, Size: 1190 bytes --]
Hi!
> > diff --git a/drivers/soc/imx/gpc.c b/drivers/soc/imx/gpc.c
> > index 53f7275..cfb42f5 100644
> > --- a/drivers/soc/imx/gpc.c
> > +++ b/drivers/soc/imx/gpc.c
> > @@ -348,7 +348,7 @@ static int imx_gpc_old_dt_init(struct device *dev, struct regmap *regmap,
> > if (i == 1) {
> > domain->supply = devm_regulator_get(dev, "pu");
> > if (IS_ERR(domain->supply))
> > - return PTR_ERR(domain->supply);;
> > + return PTR_ERR(domain->supply);
> >
> > ret = imx_pgc_get_clocks(dev, domain);
> > if (ret)
> >
>
> Considering the controversy how the changes should be merged, I'm going
> to send a separate patch just for IMX GPC driver with a reported-by-you
> tag. Thanks for catching this.
That works for me.
Alternatively... Andrew Morton merged the patch to his -mm tree
(thanks!), so you don't need to take any action, and it will be
eventually fixed.
If you merge your own version of the patch, that's ok, too, since
Andrew will just drop his version.
Best regards,
Pavel
--
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html
[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 181 bytes --]
^ permalink raw reply
* Re: [PATCH v5 3/6] powerpc/mm/slice: Enhance for supporting PPC32
From: Nicholas Piggin @ 2018-02-24 7:47 UTC (permalink / raw)
To: Christophe Leroy
Cc: Benjamin Herrenschmidt, Paul Mackerras, Michael Ellerman,
Scott Wood, aneesh.kumar, linux-kernel, linuxppc-dev
In-Reply-To: <3e9cfc87e78d61310d1b628960a465327c20d895.1519305411.git.christophe.leroy@c-s.fr>
On Thu, 22 Feb 2018 15:27:24 +0100 (CET)
Christophe Leroy <christophe.leroy@c-s.fr> wrote:
> In preparation for the following patch which will fix an issue on
> the 8xx by re-using the 'slices', this patch enhances the
> 'slices' implementation to support 32 bits CPUs.
>
> On PPC32, the address space is limited to 4Gbytes, hence only the low
> slices will be used.
>
> The high slices use bitmaps. As bitmap functions are not prepared to
> handle bitmaps of size 0, this patch ensures that bitmap functions
> are called only when SLICE_NUM_HIGH is not nul.
>
> Signed-off-by: Christophe Leroy <christophe.leroy@c-s.fr>
This looks good to me, thank you for taking my feedback into account.
Is the patch split and naming good? Yes I guess so, this adds support
for ppc32 archs that select PPC_MM_SLICES, and the next one implements
it for 8xx. There looks to be some generic arch/powerpc/mm bits in the
next patch. I wonder if you would move them over? Then the next patch
could be called powerpc/8xx: ?
Anyway it's not a big deal.
Reviewed-by: Nicholas Piggin <npiggin@gmail.com>
^ permalink raw reply
* Re: [PATCH v5 2/6] powerpc/mm/slice: create header files dedicated to slices
From: Nicholas Piggin @ 2018-02-24 7:22 UTC (permalink / raw)
To: Christophe Leroy
Cc: Benjamin Herrenschmidt, Paul Mackerras, Michael Ellerman,
Scott Wood, aneesh.kumar, linux-kernel, linuxppc-dev
In-Reply-To: <d73e104992133e8fd17c798d817687bf2ea8b50a.1519305410.git.christophe.leroy@c-s.fr>
On Thu, 22 Feb 2018 15:27:22 +0100 (CET)
Christophe Leroy <christophe.leroy@c-s.fr> wrote:
> In preparation for the following patch which will enhance 'slices'
> for supporting PPC32 in order to fix an issue on hugepages on 8xx,
> this patch takes out of page*.h all bits related to 'slices' and put
> them into newly created slice.h header files.
> While common parts go into asm/slice.h, subarch specific
> parts go into respective books3s/64/slice.c and nohash/64/slice.c
> 'slices'
>
> Signed-off-by: Christophe Leroy <christophe.leroy@c-s.fr>
I don't see a problem with this. Even by itself it seems like
a good cleanup.
Reviewed-by: Nicholas Piggin <npiggin@gmail.com>
> ---
> v5: new - come from a split of patch 2 of v4
>
> arch/powerpc/include/asm/book3s/64/slice.h | 27 ++++++++++++++
> arch/powerpc/include/asm/nohash/64/slice.h | 12 ++++++
> arch/powerpc/include/asm/page.h | 1 +
> arch/powerpc/include/asm/page_64.h | 59 ------------------------------
> arch/powerpc/include/asm/slice.h | 40 ++++++++++++++++++++
> 5 files changed, 80 insertions(+), 59 deletions(-)
> create mode 100644 arch/powerpc/include/asm/book3s/64/slice.h
> create mode 100644 arch/powerpc/include/asm/nohash/64/slice.h
> create mode 100644 arch/powerpc/include/asm/slice.h
>
> diff --git a/arch/powerpc/include/asm/book3s/64/slice.h b/arch/powerpc/include/asm/book3s/64/slice.h
> new file mode 100644
> index 000000000000..db0dedab65ee
> --- /dev/null
> +++ b/arch/powerpc/include/asm/book3s/64/slice.h
> @@ -0,0 +1,27 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +#ifndef _ASM_POWERPC_BOOK3S_64_SLICE_H
> +#define _ASM_POWERPC_BOOK3S_64_SLICE_H
> +
> +#ifdef CONFIG_PPC_MM_SLICES
> +
> +#define SLICE_LOW_SHIFT 28
> +#define SLICE_LOW_TOP (0x100000000ul)
> +#define SLICE_NUM_LOW (SLICE_LOW_TOP >> SLICE_LOW_SHIFT)
> +#define GET_LOW_SLICE_INDEX(addr) ((addr) >> SLICE_LOW_SHIFT)
> +
> +#define SLICE_HIGH_SHIFT 40
> +#define SLICE_NUM_HIGH (H_PGTABLE_RANGE >> SLICE_HIGH_SHIFT)
> +#define GET_HIGH_SLICE_INDEX(addr) ((addr) >> SLICE_HIGH_SHIFT)
> +
> +#else /* CONFIG_PPC_MM_SLICES */
> +
> +#define get_slice_psize(mm, addr) ((mm)->context.user_psize)
> +#define slice_set_user_psize(mm, psize) \
> +do { \
> + (mm)->context.user_psize = (psize); \
> + (mm)->context.sllp = SLB_VSID_USER | mmu_psize_defs[(psize)].sllp; \
> +} while (0)
> +
> +#endif /* CONFIG_PPC_MM_SLICES */
> +
> +#endif /* _ASM_POWERPC_BOOK3S_64_SLICE_H */
> diff --git a/arch/powerpc/include/asm/nohash/64/slice.h b/arch/powerpc/include/asm/nohash/64/slice.h
> new file mode 100644
> index 000000000000..ad0d6e3cc1c5
> --- /dev/null
> +++ b/arch/powerpc/include/asm/nohash/64/slice.h
> @@ -0,0 +1,12 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +#ifndef _ASM_POWERPC_NOHASH_64_SLICE_H
> +#define _ASM_POWERPC_NOHASH_64_SLICE_H
> +
> +#ifdef CONFIG_PPC_64K_PAGES
> +#define get_slice_psize(mm, addr) MMU_PAGE_64K
> +#else /* CONFIG_PPC_64K_PAGES */
> +#define get_slice_psize(mm, addr) MMU_PAGE_4K
> +#endif /* !CONFIG_PPC_64K_PAGES */
> +#define slice_set_user_psize(mm, psize) do { BUG(); } while (0)
> +
> +#endif /* _ASM_POWERPC_NOHASH_64_SLICE_H */
> diff --git a/arch/powerpc/include/asm/page.h b/arch/powerpc/include/asm/page.h
> index 8da5d4c1cab2..d5f1c41b7dba 100644
> --- a/arch/powerpc/include/asm/page.h
> +++ b/arch/powerpc/include/asm/page.h
> @@ -344,5 +344,6 @@ typedef struct page *pgtable_t;
>
> #include <asm-generic/memory_model.h>
> #endif /* __ASSEMBLY__ */
> +#include <asm/slice.h>
>
> #endif /* _ASM_POWERPC_PAGE_H */
> diff --git a/arch/powerpc/include/asm/page_64.h b/arch/powerpc/include/asm/page_64.h
> index 56234c6fcd61..af04acdb873f 100644
> --- a/arch/powerpc/include/asm/page_64.h
> +++ b/arch/powerpc/include/asm/page_64.h
> @@ -86,65 +86,6 @@ extern u64 ppc64_pft_size;
>
> #endif /* __ASSEMBLY__ */
>
> -#ifdef CONFIG_PPC_MM_SLICES
> -
> -#define SLICE_LOW_SHIFT 28
> -#define SLICE_HIGH_SHIFT 40
> -
> -#define SLICE_LOW_TOP (0x100000000ul)
> -#define SLICE_NUM_LOW (SLICE_LOW_TOP >> SLICE_LOW_SHIFT)
> -#define SLICE_NUM_HIGH (H_PGTABLE_RANGE >> SLICE_HIGH_SHIFT)
> -
> -#define GET_LOW_SLICE_INDEX(addr) ((addr) >> SLICE_LOW_SHIFT)
> -#define GET_HIGH_SLICE_INDEX(addr) ((addr) >> SLICE_HIGH_SHIFT)
> -
> -#ifndef __ASSEMBLY__
> -struct mm_struct;
> -
> -extern unsigned long slice_get_unmapped_area(unsigned long addr,
> - unsigned long len,
> - unsigned long flags,
> - unsigned int psize,
> - int topdown);
> -
> -extern unsigned int get_slice_psize(struct mm_struct *mm,
> - unsigned long addr);
> -
> -extern void slice_set_user_psize(struct mm_struct *mm, unsigned int psize);
> -extern void slice_set_range_psize(struct mm_struct *mm, unsigned long start,
> - unsigned long len, unsigned int psize);
> -
> -#endif /* __ASSEMBLY__ */
> -#else
> -#define slice_init()
> -#ifdef CONFIG_PPC_BOOK3S_64
> -#define get_slice_psize(mm, addr) ((mm)->context.user_psize)
> -#define slice_set_user_psize(mm, psize) \
> -do { \
> - (mm)->context.user_psize = (psize); \
> - (mm)->context.sllp = SLB_VSID_USER | mmu_psize_defs[(psize)].sllp; \
> -} while (0)
> -#else /* !CONFIG_PPC_BOOK3S_64 */
> -#ifdef CONFIG_PPC_64K_PAGES
> -#define get_slice_psize(mm, addr) MMU_PAGE_64K
> -#else /* CONFIG_PPC_64K_PAGES */
> -#define get_slice_psize(mm, addr) MMU_PAGE_4K
> -#endif /* !CONFIG_PPC_64K_PAGES */
> -#define slice_set_user_psize(mm, psize) do { BUG(); } while(0)
> -#endif /* CONFIG_PPC_BOOK3S_64 */
> -
> -#define slice_set_range_psize(mm, start, len, psize) \
> - slice_set_user_psize((mm), (psize))
> -#endif /* CONFIG_PPC_MM_SLICES */
> -
> -#ifdef CONFIG_HUGETLB_PAGE
> -
> -#ifdef CONFIG_PPC_MM_SLICES
> -#define HAVE_ARCH_HUGETLB_UNMAPPED_AREA
> -#endif
> -
> -#endif /* !CONFIG_HUGETLB_PAGE */
> -
> #define VM_DATA_DEFAULT_FLAGS \
> (is_32bit_task() ? \
> VM_DATA_DEFAULT_FLAGS32 : VM_DATA_DEFAULT_FLAGS64)
> diff --git a/arch/powerpc/include/asm/slice.h b/arch/powerpc/include/asm/slice.h
> new file mode 100644
> index 000000000000..17c5a5d8c418
> --- /dev/null
> +++ b/arch/powerpc/include/asm/slice.h
> @@ -0,0 +1,40 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +#ifndef _ASM_POWERPC_SLICE_H
> +#define _ASM_POWERPC_SLICE_H
> +
> +#ifdef CONFIG_PPC_BOOK3S_64
> +#include <asm/book3s/64/slice.h>
> +#else
> +#include <asm/nohash/64/slice.h>
> +#endif
> +
> +#ifdef CONFIG_PPC_MM_SLICES
> +
> +#ifdef CONFIG_HUGETLB_PAGE
> +#define HAVE_ARCH_HUGETLB_UNMAPPED_AREA
> +#endif
> +#define HAVE_ARCH_UNMAPPED_AREA
> +#define HAVE_ARCH_UNMAPPED_AREA_TOPDOWN
> +
> +#ifndef __ASSEMBLY__
> +
> +struct mm_struct;
> +
> +unsigned long slice_get_unmapped_area(unsigned long addr, unsigned long len,
> + unsigned long flags, unsigned int psize,
> + int topdown);
> +
> +unsigned int get_slice_psize(struct mm_struct *mm, unsigned long addr);
> +
> +void slice_set_user_psize(struct mm_struct *mm, unsigned int psize);
> +void slice_set_range_psize(struct mm_struct *mm, unsigned long start,
> + unsigned long len, unsigned int psize);
> +#endif /* __ASSEMBLY__ */
> +
> +#else /* CONFIG_PPC_MM_SLICES */
> +
> +#define slice_set_range_psize(mm, start, len, psize) \
> + slice_set_user_psize((mm), (psize))
> +#endif /* CONFIG_PPC_MM_SLICES */
> +
> +#endif /* _ASM_POWERPC_SLICE_H */
^ permalink raw reply
* [PATCH 3/3] powerpc/64s: micro-optimise __hard_irq_enable() for mtmsrd L=1 support
From: Nicholas Piggin @ 2018-02-24 7:15 UTC (permalink / raw)
To: linuxppc-dev; +Cc: Nicholas Piggin
In-Reply-To: <20180224071527.5053-1-npiggin@gmail.com>
Book3S minimum supported ISA version now requires mtmsrd L=1. This
instruction does not require bits other than RI and EE to be
supplied, so __hard_irq_enable() and __hard_irq_disable() does not
have to read the kernel_msr from paca.
Interrupt entry code already relies on L=1 support.
Signed-off-by: Nicholas Piggin <npiggin@gmail.com>
---
arch/powerpc/include/asm/hw_irq.h | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/arch/powerpc/include/asm/hw_irq.h b/arch/powerpc/include/asm/hw_irq.h
index 8004d7887ff6..fbc2d83808aa 100644
--- a/arch/powerpc/include/asm/hw_irq.h
+++ b/arch/powerpc/include/asm/hw_irq.h
@@ -228,8 +228,8 @@ static inline bool arch_irqs_disabled(void)
#define __hard_irq_enable() asm volatile("wrteei 1" : : : "memory")
#define __hard_irq_disable() asm volatile("wrteei 0" : : : "memory")
#else
-#define __hard_irq_enable() __mtmsrd(local_paca->kernel_msr | MSR_EE, 1)
-#define __hard_irq_disable() __mtmsrd(local_paca->kernel_msr, 1)
+#define __hard_irq_enable() __mtmsrd(MSR_EE|MSR_RI, 1)
+#define __hard_irq_disable() __mtmsrd(MSR_RI, 1)
#endif
#define hard_irq_disable() do { \
--
2.16.1
^ permalink raw reply related
* [PATCH 2/3] powerpc/64s: make PACA_IRQ_HARD_DIS track MSR[EE]
From: Nicholas Piggin @ 2018-02-24 7:15 UTC (permalink / raw)
To: linuxppc-dev; +Cc: Nicholas Piggin
In-Reply-To: <20180224071527.5053-1-npiggin@gmail.com>
When the masked interrupt handler clears MSR[EE] for an interrupt in
the PACA_IRQ_MUST_HARD_MASK set, it does not set PACA_IRQ_HARD_DIS.
This makes them get out of synch.
With that taken into account, it's only low level irq manipulation
(and interrupt entry before reconcile) where they can be out of synch.
This makes the code less surprising.
It also allows the IRQ replay code to rely on the IRQ_HARD_DIS value
and not have to mtmsrd again in this case (e.g., for an external
interrupt that has been masked).
Signed-off-by: Nicholas Piggin <npiggin@gmail.com>
---
arch/powerpc/include/asm/hw_irq.h | 10 ++++++----
arch/powerpc/kernel/exceptions-64s.S | 5 ++++-
arch/powerpc/kernel/irq.c | 14 ++++++--------
3 files changed, 16 insertions(+), 13 deletions(-)
diff --git a/arch/powerpc/include/asm/hw_irq.h b/arch/powerpc/include/asm/hw_irq.h
index 855e17d158b1..8004d7887ff6 100644
--- a/arch/powerpc/include/asm/hw_irq.h
+++ b/arch/powerpc/include/asm/hw_irq.h
@@ -248,14 +248,16 @@ static inline bool lazy_irq_pending(void)
/*
* This is called by asynchronous interrupts to conditionally
- * re-enable hard interrupts when soft-disabled after having
- * cleared the source of the interrupt
+ * re-enable hard interrupts after having cleared the source
+ * of the interrupt. They are kept disabled if there is a different
+ * soft-masked interrupt pending that requires hard masking.
*/
static inline void may_hard_irq_enable(void)
{
- get_paca()->irq_happened &= ~PACA_IRQ_HARD_DIS;
- if (!(get_paca()->irq_happened & PACA_IRQ_MUST_HARD_MASK))
+ if (!(get_paca()->irq_happened & PACA_IRQ_MUST_HARD_MASK)) {
+ get_paca()->irq_happened &= ~PACA_IRQ_HARD_DIS;
__hard_irq_enable();
+ }
}
static inline bool arch_irq_disabled_regs(struct pt_regs *regs)
diff --git a/arch/powerpc/kernel/exceptions-64s.S b/arch/powerpc/kernel/exceptions-64s.S
index 3ac87e53b3da..d1b0b0ef6658 100644
--- a/arch/powerpc/kernel/exceptions-64s.S
+++ b/arch/powerpc/kernel/exceptions-64s.S
@@ -1446,7 +1446,10 @@ masked_##_H##interrupt: \
mfspr r10,SPRN_##_H##SRR1; \
xori r10,r10,MSR_EE; /* clear MSR_EE */ \
mtspr SPRN_##_H##SRR1,r10; \
-2: mtcrf 0x80,r9; \
+ ori r11,r11,PACA_IRQ_HARD_DIS; \
+ stb r11,PACAIRQHAPPENED(r13); \
+2: /* done */ \
+ mtcrf 0x80,r9; \
ld r9,PACA_EXGEN+EX_R9(r13); \
ld r10,PACA_EXGEN+EX_R10(r13); \
ld r11,PACA_EXGEN+EX_R11(r13); \
diff --git a/arch/powerpc/kernel/irq.c b/arch/powerpc/kernel/irq.c
index f88038847790..1c9ed0a3ba3f 100644
--- a/arch/powerpc/kernel/irq.c
+++ b/arch/powerpc/kernel/irq.c
@@ -256,16 +256,14 @@ notrace void arch_local_irq_restore(unsigned long mask)
* __check_irq_replay(). We also need to soft-disable
* again to avoid warnings in there due to the use of
* per-cpu variables.
- *
- * We know that if the value in irq_happened is exactly 0x01
- * then we are already hard disabled (there are other less
- * common cases that we'll ignore for now), so we skip the
- * (expensive) mtmsrd.
*/
- if (unlikely(irq_happened != PACA_IRQ_HARD_DIS))
+ if (!(irq_happened & PACA_IRQ_HARD_DIS)) {
+#ifdef CONFIG_PPC_IRQ_SOFT_MASK_DEBUG
+ WARN_ON(!(mfmsr() & MSR_EE));
+#endif
__hard_irq_disable();
#ifdef CONFIG_PPC_IRQ_SOFT_MASK_DEBUG
- else {
+ } else {
/*
* We should already be hard disabled here. We had bugs
* where that wasn't the case so let's dbl check it and
@@ -274,8 +272,8 @@ notrace void arch_local_irq_restore(unsigned long mask)
*/
if (WARN_ON(mfmsr() & MSR_EE))
__hard_irq_disable();
- }
#endif
+ }
irq_soft_mask_set(IRQS_ALL_DISABLED);
trace_hardirqs_off();
--
2.16.1
^ permalink raw reply related
* [PATCH 1/3] powerpc/pseries: put cede MSR[EE] check under IRQ_SOFT_MASK_DEBUG
From: Nicholas Piggin @ 2018-02-24 7:15 UTC (permalink / raw)
To: linuxppc-dev; +Cc: Nicholas Piggin
In-Reply-To: <20180224071527.5053-1-npiggin@gmail.com>
This check does not catch IRQ soft mask bugs, but this option
is slightly more suitable than TRACE_IRQFLAGS.
Signed-off-by: Nicholas Piggin <npiggin@gmail.com>
---
arch/powerpc/include/asm/plpar_wrappers.h | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/arch/powerpc/include/asm/plpar_wrappers.h b/arch/powerpc/include/asm/plpar_wrappers.h
index 55eddf50d149..86f220110890 100644
--- a/arch/powerpc/include/asm/plpar_wrappers.h
+++ b/arch/powerpc/include/asm/plpar_wrappers.h
@@ -45,10 +45,10 @@ static inline long extended_cede_processor(unsigned long latency_hint)
set_cede_latency_hint(latency_hint);
rc = cede_processor();
-#ifdef CONFIG_TRACE_IRQFLAGS
- /* Ensure that H_CEDE returns with IRQs on */
- if (WARN_ON(!(mfmsr() & MSR_EE)))
- __hard_irq_enable();
+#ifdef CONFIG_PPC_IRQ_SOFT_MASK_DEBUG
+ /* Ensure that H_CEDE returns with IRQs on */
+ if (WARN_ON(!(mfmsr() & MSR_EE)))
+ __hard_irq_enable();
#endif
set_cede_latency_hint(old_latency_hint);
--
2.16.1
^ permalink raw reply related
* [PATCH 0/3] a few small irq improvements
From: Nicholas Piggin @ 2018-02-24 7:15 UTC (permalink / raw)
To: linuxppc-dev; +Cc: Nicholas Piggin
Patch 2 is really the main one. Patch 3 assumes we drop POWER4
support as per https://patchwork.ozlabs.org/patch/875852/
Nicholas Piggin (3):
powerpc/pseries: put cede MSR[EE] check under IRQ_SOFT_MASK_DEBUG
powerpc/64s: make PACA_IRQ_HARD_DIS track MSR[EE]
powerpc/64s: micro-optimise __hard_irq_enable() for mtmsrd L=1 support
arch/powerpc/include/asm/hw_irq.h | 14 ++++++++------
arch/powerpc/include/asm/plpar_wrappers.h | 8 ++++----
arch/powerpc/kernel/exceptions-64s.S | 5 ++++-
arch/powerpc/kernel/irq.c | 14 ++++++--------
4 files changed, 22 insertions(+), 19 deletions(-)
--
2.16.1
^ permalink raw reply
* [GIT PULL] Please pull powerpc/linux.git powerpc-4.16-4 tag
From: Michael Ellerman @ 2018-02-24 3:20 UTC (permalink / raw)
To: Linus Torvalds
Cc: andrew.donnellan, bharata, fbarrat, jjalvare, linux-kernel,
linuxppc-dev, mikey, mlord, mwb, naveen.n.rao
[-- Attachment #1: Type: text/plain, Size: 2482 bytes --]
Hi Linus,
Please pull some more powerpc fixes for 4.16:
The following changes since commit 91ab883eb21325ad80f3473633f794c78ac87f51:
Linux 4.16-rc2 (2018-02-18 17:29:42 -0800)
are available in the git repository at:
https://git.kernel.org/pub/scm/linux/kernel/git/powerpc/linux.git tags/powerpc-4.16-4
for you to fetch changes up to eb0a2d2620ae431c543963c8c7f08f597366fc60:
powerpc/powernv: Support firmware disable of RFI flush (2018-02-23 16:55:42 +1100)
----------------------------------------------------------------
powerpc fixes for 4.16 #4
Add handling for a missing instruction in our 32-bit BPF JIT so that it can be
used for seccomp filtering.
Add a missing NULL pointer check before a function call in new EEH code.
Fix an error path in the new ocxl driver to correctly return EFAULT.
The support for the new ibm,drc-info device tree property turns out to need
several fixes, so for now we just stop advertising to firmware that we support
it until the bugs can be ironed out.
One fix for the new drmem code which was incorrectly modifying the device tree
in place.
Finally two fixes for the RFI flush support, so that firmware can advertise to
us that it should be disabled entirely so as not to affect performance.
Thanks to:
Bharata B Rao, Frederic Barrat, Juan J. Alvarez, Mark Lord, Michael Bringmann.
----------------------------------------------------------------
Bharata B Rao (1):
powerpc/mm/drmem: Fix unexpected flag value in ibm,dynamic-memory-v2
Frederic Barrat (1):
ocxl: Fix potential bad errno on irq allocation
Juan J. Alvarez (1):
powerpc/eeh: Fix crashes in eeh_report_resume()
Mark Lord (1):
powerpc/bpf/jit: Fix 32-bit JIT for seccomp_data access
Michael Bringmann (1):
powerpc/pseries: Revert support for ibm,drc-info devtree property
Michael Ellerman (3):
powerpc/pseries: Fix duplicate firmware feature for DRC_INFO
powerpc/pseries: Support firmware disable of RFI flush
powerpc/powernv: Support firmware disable of RFI flush
arch/powerpc/include/asm/firmware.h | 2 +-
arch/powerpc/kernel/eeh_driver.c | 3 ++-
arch/powerpc/kernel/prom_init.c | 2 +-
arch/powerpc/mm/drmem.c | 6 +++---
arch/powerpc/net/bpf_jit_comp.c | 3 +++
arch/powerpc/platforms/powernv/setup.c | 4 ++++
arch/powerpc/platforms/pseries/setup.c | 3 ++-
drivers/misc/ocxl/file.c | 6 ++++--
8 files changed, 20 insertions(+), 9 deletions(-)
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 800 bytes --]
^ permalink raw reply
* Re: [PATCH v4.4 backport 2/3] powerpc/64s: Simple RFI macro conversions
From: Michael Ellerman @ 2018-02-24 2:51 UTC (permalink / raw)
To: Greg KH; +Cc: stable, npiggin, linuxppc-dev, linux, corsac
In-Reply-To: <20180223125805.GA23233@kroah.com>
Greg KH <greg@kroah.com> writes:
> On Fri, Feb 23, 2018 at 11:11:12PM +1100, Michael Ellerman wrote:
>> Michael Ellerman <mpe@ellerman.id.au> writes:
>> > Subject: [PATCH v4.4 backport 2/3] powerpc/64s: Simple RFI macro conversions
>> ^
>> 4.9
>>
>> Gah, sorry just realised these last two have "v4.4" in the subject, but
>> it should be "4.9".
>
> Ah, good, I was wondering about that :)
Sorry for the confusion, I need to automate generation of the patch
subjects obviously :)
> I'll apply these after lunch...
Thanks.
cheers
^ permalink raw reply
* Re: [PATCH v12 1/3] mm, powerpc, x86: define VM_PKEY_BITx bits if CONFIG_ARCH_HAS_PKEYS is enabled
From: Ram Pai @ 2018-02-24 1:05 UTC (permalink / raw)
To: kbuild test robot
Cc: kbuild-all, mpe, mingo, akpm, linuxppc-dev, linux-mm, x86,
linux-arch, linux-kernel, dave.hansen, benh, paulus, khandual,
aneesh.kumar, bsingharora, hbabu, mhocko, bauerman, ebiederm,
corbet, arnd, fweimer, msuchanek
In-Reply-To: <201802231528.snWZIspR%fengguang.wu@intel.com>
On Fri, Feb 23, 2018 at 03:11:45PM +0800, kbuild test robot wrote:
> Hi Ram,
>
> Thank you for the patch! Yet something to improve:
>
> [auto build test ERROR on linus/master]
> [also build test ERROR on v4.16-rc2 next-20180222]
> [if your patch is applied to the wrong git tree, please drop us a note to help improve the system]
>
> chmod +x ~/bin/make.cross
...snip..
> # save the attached .config to linux build tree
> make.cross ARCH=powerpc
>
> Note: the linux-review/Ram-Pai/mm-x86-powerpc-Enhancements-to-Memory-Protection-Keys/20180223-042743 HEAD c5692bca45543c242ffca15c811923e4c548ed19 builds fine.
> It only hurts bisectibility.
oops, it broke git-bisect on powerpc :-(
The following change will fix it. This should nail it down.
diff --git a/arch/powerpc/include/asm/pkeys.h
b/arch/powerpc/include/asm/pkeys.h
index 0409c80..0b3b669 100644
--- a/arch/powerpc/include/asm/pkeys.h
+++ b/arch/powerpc/include/asm/pkeys.h
@@ -25,6 +25,7 @@
# define VM_PKEY_BIT1 VM_HIGH_ARCH_1
# define VM_PKEY_BIT2 VM_HIGH_ARCH_2
# define VM_PKEY_BIT3 VM_HIGH_ARCH_3
# define VM_PKEY_BIT4 VM_HIGH_ARCH_4
+#elif !defined(VM_PKEY_BIT4)
+# define VM_PKEY_BIT4 VM_HIGH_ARCH_4
#endif
^ permalink raw reply related
* [PATCH] powerpc/boot: Fix random build errors
From: Guenter Roeck @ 2018-02-23 20:55 UTC (permalink / raw)
To: Benjamin Herrenschmidt
Cc: Paul Mackerras, Michael Ellerman, linuxppc-dev, linux-kernel,
Guenter Roeck
Once in a while I see build errors similar to the following
when building images from a clean tree.
Building powerpc:virtex-ml507:44x/virtex5_defconfig ... failed
------------
Error log:
arch/powerpc/boot/treeboot-akebono.c:37:20: fatal error:
libfdt.h: No such file or directory
Building powerpc:bamboo:smpdev:44x/bamboo_defconfig ... failed
------------
Error log:
arch/powerpc/boot/treeboot-akebono.c:37:20: fatal error:
libfdt.h: No such file or directory
arch/powerpc/boot/treeboot-currituck.c:35:20: fatal error:
libfdt.h: No such file or directory
Rebuilds will succeed.
Turns out that several source files in arch/powerpc/boot/ include
libfdt.h, but Makefile dependencies are incomplete. Let's fix that.
Signed-off-by: Guenter Roeck <linux@roeck-us.net>
---
arch/powerpc/boot/Makefile | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/arch/powerpc/boot/Makefile b/arch/powerpc/boot/Makefile
index ef6549e57157..26d5d2a5b8e9 100644
--- a/arch/powerpc/boot/Makefile
+++ b/arch/powerpc/boot/Makefile
@@ -101,7 +101,8 @@ $(addprefix $(obj)/,$(zlib-y)): \
libfdt := fdt.c fdt_ro.c fdt_wip.c fdt_sw.c fdt_rw.c fdt_strerror.c
libfdtheader := fdt.h libfdt.h libfdt_internal.h
-$(addprefix $(obj)/,$(libfdt) libfdt-wrapper.o simpleboot.o epapr.o opal.o): \
+$(addprefix $(obj)/,$(libfdt) libfdt-wrapper.o simpleboot.o epapr.o opal.o \
+ treeboot-akebono.o treeboot-currituck.o treeboot-iss4xx.o): \
$(addprefix $(obj)/,$(libfdtheader))
src-wlib-y := string.S crt0.S stdio.c decompress.c main.c \
--
2.7.4
^ permalink raw reply related
* Re: [PATCH] powerpc/powernv: Turn on SCSI_AACRAID in powernv_defconfig
From: Brian King @ 2018-02-23 19:41 UTC (permalink / raw)
To: Stewart Smith, Michael Ellerman, Guilherme G. Piccoli
Cc: linuxppc-dev, dougmill@us.ibm.com
In-Reply-To: <87inaopnlh.fsf@linux.vnet.ibm.com>
On 02/22/2018 06:16 PM, Stewart Smith wrote:
> Michael Ellerman <mpe@ellerman.id.au> writes:
>> Brian King <brking@linux.vnet.ibm.com> writes:
>>> On 09/03/2017 06:19 PM, Stewart Smith wrote:
>>>> Michael Ellerman <mpe@ellerman.id.au> writes:
>>>>>> 2. On a bare metal machine, if you set ipr.fast_reboot=1 on the skiboot
>>>>>> kernel, then we should also avoid resetting the ipr adapter, so ipr
>>>>>> init on the kernel being kexec booted from skiboot should be extremely fast.
>>>>>
>>>>> OK, I didn't know that was an option, so that might help.
>>>>>
>>>>>> ...
>>>>>> If you've got cases where ipr init is taking a long time, I'd be
>>>>>> interested to know what scenarios are the most annoying to see if there
>>>>>> is any opportunity to improve.
>>>>>
>>>>> Yeah booting bare metal is where I see it (not using ipr.fast_reboot).
>>>>
>>>> Hrm... We should probably enable that by default for petitboot then.
>>>>
>>>> It'd at least cut some time off booting straight through to OS.
>>>
>>> Agreed. I'd be interested to hear if that helps address the issue
>>> Michael is seeing.
>>>
>>> You can easily test this by exiting to a petitboot shell:
>>>
>>> echo 1 > /sys/module/ipr/parameters/fast_reboot
>>>
>>> Then go back to petitboot and boot the OS.
>>
>> Just following up on this (!).
>>
>> This does work, and I've now been running it in my CI for about a month
>> (~1000 boots) with no problems.
>>
>> You can also make it persistent by doing:
>>
>> $ nvram -p ibm,skiboot --update-config bootargs="ipr.fast_reboot=1"
>
> Okay, cool. https://github.com/open-power/op-build/pull/1900 will set it
> in firmware - we may as well run with this and fix any bugs we find.
>
> Any reason why it isn't the default behaviour?
The primary reason this isn't the default setting is because it would cause
undesired behavior on system reboots. On a kexec reboot, since the PCIe slots
don't get power cycled or even hit with PERST, we can simply quiesce devices
and pick them up at the other side of the kexec. On a real reboot where the
firmware or hardware may end up doing a PERST or power cycle, we need to tell the ipr
adapters that is coming and let them shutdown gracefully. If we don't,
we will likely be OK in the single adapter configuration in most scenarios,
but for a dual ipr adapter configuration, we can then end up with undesired
adapter failovers occurring due to the unexpected power offs / resets, which
can then end up extending the next boot.
-Brian
--
Brian King
Power Linux I/O
IBM Linux Technology Center
^ permalink raw reply
* Re: [PATCH 00/38] cxlflash: OpenCXL transport support
From: Uma Krishnan @ 2018-02-23 19:38 UTC (permalink / raw)
To: Andrew Donnellan
Cc: linux-scsi, James Bottomley, Martin K. Petersen, Matthew R. Ochs,
Manoj N. Kumar, linuxppc-dev, Frederic Barrat, Christophe Lombard
In-Reply-To: <2d8f0a69-5fef-d027-1456-1a9088c2333b@au1.ibm.com>
> On Feb 22, 2018, at 10:13 PM, Andrew Donnellan =
<andrew.donnellan@au1.ibm.com> wrote:
>=20
> On 23/02/18 09:20, Uma Krishnan wrote:
>> This patch series adds OpenCXL support to the cxlflash driver. With
>> this support, new devices using the OpenCXL transport will be =
supported
>> by the cxlflash driver along with the existing CXL devices. An effort =
is
>> made to keep this transport specific function independent of the =
existing
>> core driver that communicates with the AFU.
>=20
> It's "OpenCAPI" for the standard, and "ocxl" for the driver - I'd =
rather not add "OpenCXL" to our already somewhat confusing proliferation =
of names :)
I agree. :) I will fix it in V2. Thanks for the feedback.=
^ permalink raw reply
* Re: [PATCH 04/38] cxlflash: Introduce OpenCXL backend
From: Uma Krishnan @ 2018-02-23 19:36 UTC (permalink / raw)
To: Andrew Donnellan
Cc: linux-scsi, James Bottomley, Martin K. Petersen, Matthew R. Ochs,
Manoj N. Kumar, linuxppc-dev, Frederic Barrat, Christophe Lombard
In-Reply-To: <abe97ecd-7162-c812-816d-268321916bff@au1.ibm.com>
> On Feb 22, 2018, at 10:28 PM, Andrew Donnellan =
<andrew.donnellan@au1.ibm.com> wrote:
>=20
> On 23/02/18 09:22, Uma Krishnan wrote:
>> Add initial infrastructure to support a new cxlflash transport, =
OpenCXL.
>> Claim a dependency on OpenCXL (OCXL) and add a new file, ocxl_hw.c, =
which
>> will host the backend routines that are specific to OpenCXL.
>> Signed-off-by: Uma Krishnan <ukrishn@linux.vnet.ibm.com>
>=20
> Is it necessary to depend on OCXL in all cases? IMHO it should be =
possible to build a cxl-only version without ocxl, though I don't feel =
very strongly on this.
I thought through this and did not feel it is necessary to distinguish =
right now. I will look at adding this in the future. Thanks Andrew !=
^ permalink raw reply
* Re: [PATCH 00/38] cxlflash: OpenCXL transport support
From: Uma Krishnan @ 2018-02-23 18:05 UTC (permalink / raw)
To: Andrew Donnellan
Cc: linux-scsi, James Bottomley, Martin K. Petersen, Matthew R. Ochs,
Manoj N. Kumar, linuxppc-dev, Frederic Barrat, Christophe Lombard
In-Reply-To: <2d8f0a69-5fef-d027-1456-1a9088c2333b@au1.ibm.com>
[-- Attachment #1: Type: text/html, Size: 1782 bytes --]
^ permalink raw reply
* Re: [PATCH 2/2] selftests/powerpc: Add core file test for Protection Key registers
From: Ram Pai @ 2018-02-23 18:51 UTC (permalink / raw)
To: Thiago Jung Bauermann
Cc: linuxppc-dev, linux-kselftest, linux-kernel, Michael Ellerman
In-Reply-To: <20180223183344.21038-2-bauerman@linux.vnet.ibm.com>
On Fri, Feb 23, 2018 at 03:33:44PM -0300, Thiago Jung Bauermann wrote:
> This test verifies that the AMR, IAMR and UAMOR are being written to a
> process' core file.
>
Acked-by: Ram Pai <linuxram@us.ibm.com>
Tested-by: Ram Pai <linuxram@us.ibm.com>
> Signed-off-by: Thiago Jung Bauermann <bauerman@linux.vnet.ibm.com>
> ---
> tools/testing/selftests/powerpc/ptrace/Makefile | 5 +-
> tools/testing/selftests/powerpc/ptrace/core-pkey.c | 460 +++++++++++++++++++++
> 2 files changed, 464 insertions(+), 1 deletion(-)
> create mode 100644 tools/testing/selftests/powerpc/ptrace/core-pkey.c
>
.snip...
RP
^ permalink raw reply
* Re: [PATCH 1/2] selftests/powerpc: Add ptrace tests for Protection Key registers
From: Ram Pai @ 2018-02-23 18:50 UTC (permalink / raw)
To: Thiago Jung Bauermann
Cc: linuxppc-dev, linux-kselftest, linux-kernel, Michael Ellerman
In-Reply-To: <20180223183344.21038-1-bauerman@linux.vnet.ibm.com>
On Fri, Feb 23, 2018 at 03:33:43PM -0300, Thiago Jung Bauermann wrote:
> This test exercises read and write access to the AMR, IAMR and UAMOR.
>
Tested-by: Ram Pai <linuxram@us.ibm.com>
Acked-by: Ram Pai <linuxram@us.ibm.com>
> Signed-off-by: Thiago Jung Bauermann <bauerman@linux.vnet.ibm.com>
> ---
> tools/testing/selftests/powerpc/include/reg.h | 1 +
> tools/testing/selftests/powerpc/ptrace/Makefile | 5 +-
> tools/testing/selftests/powerpc/ptrace/child.h | 130 ++++++++
> .../testing/selftests/powerpc/ptrace/ptrace-pkey.c | 326 +++++++++++++++++++++
> tools/testing/selftests/powerpc/ptrace/ptrace.h | 37 +++
> 5 files changed, 498 insertions(+), 1 deletion(-)
> create mode 100644 tools/testing/selftests/powerpc/ptrace/child.h
> create mode 100644 tools/testing/selftests/powerpc/ptrace/ptrace-pkey.c
>
> diff --git a/tools/testing/selftests/powerpc/include/reg.h b/tools/testing/selftests/powerpc/include/reg.h
> index 4afdebcce4cd..7f348c059bc2 100644
> --- a/tools/testing/selftests/powerpc/include/reg.h
> +++ b/tools/testing/selftests/powerpc/include/reg.h
> @@ -54,6 +54,7 @@
> #define SPRN_DSCR_PRIV 0x11 /* Privilege State DSCR */
> #define SPRN_DSCR 0x03 /* Data Stream Control Register */
> #define SPRN_PPR 896 /* Program Priority Register */
> +#define SPRN_AMR 13 /* Authority Mask Register - problem state */
>
> /* TEXASR register bits */
> #define TEXASR_FC 0xFE00000000000000
> diff --git a/tools/testing/selftests/powerpc/ptrace/Makefile b/tools/testing/selftests/powerpc/ptrace/Makefile
> index 480305266504..707ba734faf2 100644
> --- a/tools/testing/selftests/powerpc/ptrace/Makefile
> +++ b/tools/testing/selftests/powerpc/ptrace/Makefile
> @@ -1,7 +1,7 @@
> # SPDX-License-Identifier: GPL-2.0
> TEST_PROGS := ptrace-gpr ptrace-tm-gpr ptrace-tm-spd-gpr \
> ptrace-tar ptrace-tm-tar ptrace-tm-spd-tar ptrace-vsx ptrace-tm-vsx \
> - ptrace-tm-spd-vsx ptrace-tm-spr
> + ptrace-tm-spd-vsx ptrace-tm-spr ptrace-pkey
>
> include ../../lib.mk
>
> @@ -9,6 +9,9 @@ all: $(TEST_PROGS)
>
> CFLAGS += -m64 -I../../../../../usr/include -I../tm -mhtm -fno-pie
>
> +ptrace-pkey: ../harness.c ../utils.c ../lib/reg.S ptrace.h child.h ptrace-pkey.c
> + $(LINK.c) $^ $(LDLIBS) -pthread -o $@
> +
> $(TEST_PROGS): ../harness.c ../utils.c ../lib/reg.S ptrace.h
>
> clean:
> diff --git a/tools/testing/selftests/powerpc/ptrace/child.h b/tools/testing/selftests/powerpc/ptrace/child.h
> new file mode 100644
> index 000000000000..40c1a6d92111
> --- /dev/null
> +++ b/tools/testing/selftests/powerpc/ptrace/child.h
> @@ -0,0 +1,130 @@
> +// SPDX-License-Identifier: GPL-2.0+
> +/*
> + * Helper functions to sync execution between parent and child processes.
> + *
> + * Copyright 2018, Thiago Jung Bauermann, IBM Corporation.
> + */
> +#include <stdio.h>
> +#include <stdbool.h>
> +#include <semaphore.h>
> +
> +/*
> + * Information in a shared memory location for synchronization between child and
> + * parent.
> + */
> +struct child_sync {
> + /* The parent waits on this semaphore. */
> + sem_t sem_parent;
> +
> + /* If true, the child should give up as well. */
> + bool parent_gave_up;
> +
> + /* The child waits on this semaphore. */
> + sem_t sem_child;
> +
> + /* If true, the parent should give up as well. */
> + bool child_gave_up;
> +};
> +
> +#define CHILD_FAIL_IF(x, sync) \
> + do { \
> + if (x) { \
> + fprintf(stderr, \
> + "[FAIL] Test FAILED on line %d\n", __LINE__); \
> + (sync)->child_gave_up = true; \
> + prod_parent(sync); \
> + return 1; \
> + } \
> + } while (0)
> +
> +#define PARENT_FAIL_IF(x, sync) \
> + do { \
> + if (x) { \
> + fprintf(stderr, \
> + "[FAIL] Test FAILED on line %d\n", __LINE__); \
> + (sync)->parent_gave_up = true; \
> + prod_child(sync); \
> + return 1; \
> + } \
> + } while (0)
> +
> +int init_child_sync(struct child_sync *sync)
> +{
> + int ret;
> +
> + ret = sem_init(&sync->sem_parent, 1, 0);
> + if (ret) {
> + perror("Semaphore initialization failed");
> + return 1;
> + }
> +
> + ret = sem_init(&sync->sem_child, 1, 0);
> + if (ret) {
> + perror("Semaphore initialization failed");
> + return 1;
> + }
> +
> + return 0;
> +}
> +
> +void destroy_child_sync(struct child_sync *sync)
> +{
> + sem_destroy(&sync->sem_parent);
> + sem_destroy(&sync->sem_child);
> +}
> +
> +int wait_child(struct child_sync *sync)
> +{
> + int ret;
> +
> + /* Wait until the child prods us. */
> + ret = sem_wait(&sync->sem_parent);
> + if (ret) {
> + perror("Error waiting for child");
> + return 1;
> + }
> +
> + return sync->child_gave_up;
> +}
> +
> +int prod_child(struct child_sync *sync)
> +{
> + int ret;
> +
> + /* Unblock the child now. */
> + ret = sem_post(&sync->sem_child);
> + if (ret) {
> + perror("Error prodding child");
> + return 1;
> + }
> +
> + return 0;
> +}
> +
> +int wait_parent(struct child_sync *sync)
> +{
> + int ret;
> +
> + /* Wait until the parent prods us. */
> + ret = sem_wait(&sync->sem_child);
> + if (ret) {
> + perror("Error waiting for parent");
> + return 1;
> + }
> +
> + return sync->parent_gave_up;
> +}
> +
> +int prod_parent(struct child_sync *sync)
> +{
> + int ret;
> +
> + /* Unblock the parent now. */
> + ret = sem_post(&sync->sem_parent);
> + if (ret) {
> + perror("Error prodding parent");
> + return 1;
> + }
> +
> + return 0;
> +}
> diff --git a/tools/testing/selftests/powerpc/ptrace/ptrace-pkey.c b/tools/testing/selftests/powerpc/ptrace/ptrace-pkey.c
> new file mode 100644
> index 000000000000..8332b9338d39
> --- /dev/null
> +++ b/tools/testing/selftests/powerpc/ptrace/ptrace-pkey.c
> @@ -0,0 +1,326 @@
> +// SPDX-License-Identifier: GPL-2.0+
> +/*
> + * Ptrace test for Memory Protection Key registers
> + *
> + * Copyright (C) 2015 Anshuman Khandual, IBM Corporation.
> + * Copyright (C) 2018 IBM Corporation.
> + */
> +#include "ptrace.h"
> +#include "child.h"
> +
> +#ifndef __NR_pkey_alloc
> +#define __NR_pkey_alloc 384
> +#endif
> +
> +#ifndef __NR_pkey_free
> +#define __NR_pkey_free 385
> +#endif
> +
> +#ifndef NT_PPC_PKEY
> +#define NT_PPC_PKEY 0x110
> +#endif
> +
> +#ifndef PKEY_DISABLE_EXECUTE
> +#define PKEY_DISABLE_EXECUTE 0x4
> +#endif
> +
> +#define AMR_BITS_PER_PKEY 2
> +#define PKEY_REG_BITS (sizeof(u64) * 8)
> +#define pkeyshift(pkey) (PKEY_REG_BITS - ((pkey + 1) * AMR_BITS_PER_PKEY))
> +
> +static const char user_read[] = "[User Read (Running)]";
> +static const char user_write[] = "[User Write (Running)]";
> +static const char ptrace_read_running[] = "[Ptrace Read (Running)]";
> +static const char ptrace_write_running[] = "[Ptrace Write (Running)]";
> +
> +/* Information shared between the parent and the child. */
> +struct shared_info {
> + struct child_sync child_sync;
> +
> + /* AMR value the parent expects to read from the child. */
> + unsigned long amr1;
> +
> + /* AMR value the parent is expected to write to the child. */
> + unsigned long amr2;
> +
> + /* AMR value that ptrace should refuse to write to the child. */
> + unsigned long amr3;
> +
> + /* IAMR value the parent expects to read from the child. */
> + unsigned long expected_iamr;
> +
> + /* UAMOR value the parent expects to read from the child. */
> + unsigned long expected_uamor;
> +
> + /*
> + * IAMR and UAMOR values that ptrace should refuse to write to the child
> + * (even though they're valid ones) because userspace doesn't have
> + * access to those registers.
> + */
> + unsigned long new_iamr;
> + unsigned long new_uamor;
> +};
> +
> +static int sys_pkey_alloc(unsigned long flags, unsigned long init_access_rights)
> +{
> + return syscall(__NR_pkey_alloc, flags, init_access_rights);
> +}
> +
> +static int sys_pkey_free(int pkey)
> +{
> + return syscall(__NR_pkey_free, pkey);
> +}
> +
> +static int child(struct shared_info *info)
> +{
> + unsigned long reg;
> + bool disable_execute = true;
> + int pkey1, pkey2, pkey3;
> + int ret;
> +
> + /* Wait until parent fills out the initial register values. */
> + ret = wait_parent(&info->child_sync);
> + if (ret)
> + return ret;
> +
> + /* Get some pkeys so that we can change their bits in the AMR. */
> + pkey1 = sys_pkey_alloc(0, PKEY_DISABLE_EXECUTE);
> + if (pkey1 < 0) {
> + pkey1 = sys_pkey_alloc(0, 0);
> + CHILD_FAIL_IF(pkey1 < 0, &info->child_sync);
> +
> + disable_execute = false;
> + }
> +
> + pkey2 = sys_pkey_alloc(0, 0);
> + CHILD_FAIL_IF(pkey2 < 0, &info->child_sync);
> +
> + pkey3 = sys_pkey_alloc(0, 0);
> + CHILD_FAIL_IF(pkey3 < 0, &info->child_sync);
> +
> + info->amr1 |= 3ul << pkeyshift(pkey1);
> + info->amr2 |= 3ul << pkeyshift(pkey2);
> + info->amr3 |= info->amr2 | 3ul << pkeyshift(pkey3);
> +
> + if (disable_execute)
> + info->expected_iamr |= 1ul << pkeyshift(pkey1);
> +
> + info->expected_uamor |= 3ul << pkeyshift(pkey1) |
> + 3ul << pkeyshift(pkey2);
> + info->new_iamr |= 1ul << pkeyshift(pkey1) | 1ul << pkeyshift(pkey2);
> + info->new_uamor |= 3ul << pkeyshift(pkey1);
> +
> + /*
> + * We won't use pkey3. We just want a plausible but invalid key to test
> + * whether ptrace will let us write to AMR bits we are not supposed to.
> + *
> + * This also tests whether the kernel restores the UAMOR permissions
> + * after a key is freed.
> + */
> + sys_pkey_free(pkey3);
> +
> + printf("%-30s AMR: %016lx pkey1: %d pkey2: %d pkey3: %d\n",
> + user_write, info->amr1, pkey1, pkey2, pkey3);
> +
> + mtspr(SPRN_AMR, info->amr1);
> +
> + /* Wait for parent to read our AMR value and write a new one. */
> + ret = prod_parent(&info->child_sync);
> + CHILD_FAIL_IF(ret, &info->child_sync);
> +
> + ret = wait_parent(&info->child_sync);
> + if (ret)
> + return ret;
> +
> + reg = mfspr(SPRN_AMR);
> +
> + printf("%-30s AMR: %016lx\n", user_read, reg);
> +
> + CHILD_FAIL_IF(reg != info->amr2, &info->child_sync);
> +
> + /*
> + * Wait for parent to try to write an invalid AMR value.
> + */
> + ret = prod_parent(&info->child_sync);
> + CHILD_FAIL_IF(ret, &info->child_sync);
> +
> + ret = wait_parent(&info->child_sync);
> + if (ret)
> + return ret;
> +
> + reg = mfspr(SPRN_AMR);
> +
> + printf("%-30s AMR: %016lx\n", user_read, reg);
> +
> + CHILD_FAIL_IF(reg != info->amr2, &info->child_sync);
> +
> + /*
> + * Wait for parent to try to write an IAMR and a UAMOR value. We can't
> + * verify them, but we can verify that the AMR didn't change.
> + */
> + ret = prod_parent(&info->child_sync);
> + CHILD_FAIL_IF(ret, &info->child_sync);
> +
> + ret = wait_parent(&info->child_sync);
> + if (ret)
> + return ret;
> +
> + reg = mfspr(SPRN_AMR);
> +
> + printf("%-30s AMR: %016lx\n", user_read, reg);
> +
> + CHILD_FAIL_IF(reg != info->amr2, &info->child_sync);
> +
> + /* Now let parent now that we are finished. */
> +
> + ret = prod_parent(&info->child_sync);
> + CHILD_FAIL_IF(ret, &info->child_sync);
> +
> + return TEST_PASS;
> +}
> +
> +static int parent(struct shared_info *info, pid_t pid)
> +{
> + unsigned long regs[3];
> + int ret, status;
> +
> + /*
> + * Get the initial values for AMR, IAMR and UAMOR and communicate them
> + * to the child.
> + */
> + ret = ptrace_read_regs(pid, NT_PPC_PKEY, regs, 3);
> + PARENT_FAIL_IF(ret, &info->child_sync);
> +
> + info->amr1 = info->amr2 = info->amr3 = regs[0];
> + info->expected_iamr = info->new_iamr = regs[1];
> + info->expected_uamor = info->new_uamor = regs[2];
> +
> + /* Wake up child so that it can set itself up. */
> + ret = prod_child(&info->child_sync);
> + PARENT_FAIL_IF(ret, &info->child_sync);
> +
> + ret = wait_child(&info->child_sync);
> + if (ret)
> + return ret;
> +
> + /* Verify that we can read the pkey registers from the child. */
> + ret = ptrace_read_regs(pid, NT_PPC_PKEY, regs, 3);
> + PARENT_FAIL_IF(ret, &info->child_sync);
> +
> + printf("%-30s AMR: %016lx IAMR: %016lx UAMOR: %016lx\n",
> + ptrace_read_running, regs[0], regs[1], regs[2]);
> +
> + PARENT_FAIL_IF(regs[0] != info->amr1, &info->child_sync);
> + PARENT_FAIL_IF(regs[1] != info->expected_iamr, &info->child_sync);
> + PARENT_FAIL_IF(regs[2] != info->expected_uamor, &info->child_sync);
> +
> + /* Write valid AMR value in child. */
> + ret = ptrace_write_regs(pid, NT_PPC_PKEY, &info->amr2, 1);
> + PARENT_FAIL_IF(ret, &info->child_sync);
> +
> + printf("%-30s AMR: %016lx\n", ptrace_write_running, info->amr2);
> +
> + /* Wake up child so that it can verify it changed. */
> + ret = prod_child(&info->child_sync);
> + PARENT_FAIL_IF(ret, &info->child_sync);
> +
> + ret = wait_child(&info->child_sync);
> + if (ret)
> + return ret;
> +
> + /* Write invalid AMR value in child. */
> + ret = ptrace_write_regs(pid, NT_PPC_PKEY, &info->amr3, 1);
> + PARENT_FAIL_IF(ret, &info->child_sync);
> +
> + printf("%-30s AMR: %016lx\n", ptrace_write_running, info->amr3);
> +
> + /* Wake up child so that it can verify it didn't change. */
> + ret = prod_child(&info->child_sync);
> + PARENT_FAIL_IF(ret, &info->child_sync);
> +
> + ret = wait_child(&info->child_sync);
> + if (ret)
> + return ret;
> +
> + /* Try to write to IAMR. */
> + regs[0] = info->amr1;
> + regs[1] = info->new_iamr;
> + ret = ptrace_write_regs(pid, NT_PPC_PKEY, regs, 2);
> + PARENT_FAIL_IF(!ret, &info->child_sync);
> +
> + printf("%-30s AMR: %016lx IAMR: %016lx\n",
> + ptrace_write_running, regs[0], regs[1]);
> +
> + /* Try to write to IAMR and UAMOR. */
> + regs[2] = info->new_uamor;
> + ret = ptrace_write_regs(pid, NT_PPC_PKEY, regs, 3);
> + PARENT_FAIL_IF(!ret, &info->child_sync);
> +
> + printf("%-30s AMR: %016lx IAMR: %016lx UAMOR: %016lx\n",
> + ptrace_write_running, regs[0], regs[1], regs[2]);
> +
> + /* Verify that all registers still have their expected values. */
> + ret = ptrace_read_regs(pid, NT_PPC_PKEY, regs, 3);
> + PARENT_FAIL_IF(ret, &info->child_sync);
> +
> + printf("%-30s AMR: %016lx IAMR: %016lx UAMOR: %016lx\n",
> + ptrace_read_running, regs[0], regs[1], regs[2]);
> +
> + PARENT_FAIL_IF(regs[0] != info->amr2, &info->child_sync);
> + PARENT_FAIL_IF(regs[1] != info->expected_iamr, &info->child_sync);
> + PARENT_FAIL_IF(regs[2] != info->expected_uamor, &info->child_sync);
> +
> + /* Wake up child so that it can verify AMR didn't change and wrap up. */
> + ret = prod_child(&info->child_sync);
> + PARENT_FAIL_IF(ret, &info->child_sync);
> +
> + ret = wait(&status);
> + if (ret != pid) {
> + printf("Child's exit status not captured\n");
> + ret = TEST_PASS;
> + } else if (!WIFEXITED(status)) {
> + printf("Child exited abnormally\n");
> + ret = TEST_FAIL;
> + } else
> + ret = WEXITSTATUS(status) ? TEST_FAIL : TEST_PASS;
> +
> + return ret;
> +}
> +
> +static int ptrace_pkey(void)
> +{
> + struct shared_info *info;
> + int shm_id;
> + int ret;
> + pid_t pid;
> +
> + shm_id = shmget(IPC_PRIVATE, sizeof(*info), 0777 | IPC_CREAT);
> + info = shmat(shm_id, NULL, 0);
> +
> + ret = init_child_sync(&info->child_sync);
> + if (ret)
> + return ret;
> +
> + pid = fork();
> + if (pid < 0) {
> + perror("fork() failed");
> + ret = TEST_FAIL;
> + } else if (pid == 0)
> + ret = child(info);
> + else
> + ret = parent(info, pid);
> +
> + shmdt(info);
> +
> + if (pid) {
> + destroy_child_sync(&info->child_sync);
> + shmctl(shm_id, IPC_RMID, NULL);
> + }
> +
> + return ret;
> +}
> +
> +int main(int argc, char *argv[])
> +{
> + return test_harness(ptrace_pkey, "ptrace_pkey");
> +}
> diff --git a/tools/testing/selftests/powerpc/ptrace/ptrace.h b/tools/testing/selftests/powerpc/ptrace/ptrace.h
> index 19fb825270a1..d2c9c4c2b5ee 100644
> --- a/tools/testing/selftests/powerpc/ptrace/ptrace.h
> +++ b/tools/testing/selftests/powerpc/ptrace/ptrace.h
> @@ -102,6 +102,43 @@ int cont_trace(pid_t child)
> return TEST_PASS;
> }
>
> +int ptrace_read_regs(pid_t child, unsigned long type, unsigned long regs[],
> + int n)
> +{
> + struct iovec iov;
> + long ret;
> +
> + FAIL_IF(start_trace(child));
> +
> + iov.iov_base = regs;
> + iov.iov_len = n * sizeof(unsigned long);
> +
> + ret = ptrace(PTRACE_GETREGSET, child, type, &iov);
> + FAIL_IF(ret != 0);
> +
> + FAIL_IF(stop_trace(child));
> +
> + return TEST_PASS;
> +}
> +
> +long ptrace_write_regs(pid_t child, unsigned long type, unsigned long regs[],
> + int n)
> +{
> + struct iovec iov;
> + long ret;
> +
> + FAIL_IF(start_trace(child));
> +
> + iov.iov_base = regs;
> + iov.iov_len = n * sizeof(unsigned long);
> +
> + ret = ptrace(PTRACE_SETREGSET, child, type, &iov);
> +
> + FAIL_IF(stop_trace(child));
> +
> + return ret;
> +}
> +
> /* TAR, PPR, DSCR */
> int show_tar_registers(pid_t child, unsigned long *out)
> {
--
Ram Pai
^ permalink raw reply
* [PATCH 2/2] selftests/powerpc: Add core file test for Protection Key registers
From: Thiago Jung Bauermann @ 2018-02-23 18:33 UTC (permalink / raw)
To: linuxppc-dev
Cc: linux-kselftest, linux-kernel, Michael Ellerman, Ram Pai,
Thiago Jung Bauermann
In-Reply-To: <20180223183344.21038-1-bauerman@linux.vnet.ibm.com>
This test verifies that the AMR, IAMR and UAMOR are being written to a
process' core file.
Signed-off-by: Thiago Jung Bauermann <bauerman@linux.vnet.ibm.com>
---
tools/testing/selftests/powerpc/ptrace/Makefile | 5 +-
tools/testing/selftests/powerpc/ptrace/core-pkey.c | 460 +++++++++++++++++++++
2 files changed, 464 insertions(+), 1 deletion(-)
create mode 100644 tools/testing/selftests/powerpc/ptrace/core-pkey.c
diff --git a/tools/testing/selftests/powerpc/ptrace/Makefile b/tools/testing/selftests/powerpc/ptrace/Makefile
index 707ba734faf2..a10916c3f3e1 100644
--- a/tools/testing/selftests/powerpc/ptrace/Makefile
+++ b/tools/testing/selftests/powerpc/ptrace/Makefile
@@ -1,7 +1,7 @@
# SPDX-License-Identifier: GPL-2.0
TEST_PROGS := ptrace-gpr ptrace-tm-gpr ptrace-tm-spd-gpr \
ptrace-tar ptrace-tm-tar ptrace-tm-spd-tar ptrace-vsx ptrace-tm-vsx \
- ptrace-tm-spd-vsx ptrace-tm-spr ptrace-pkey
+ ptrace-tm-spd-vsx ptrace-tm-spr ptrace-pkey core-pkey
include ../../lib.mk
@@ -12,6 +12,9 @@ CFLAGS += -m64 -I../../../../../usr/include -I../tm -mhtm -fno-pie
ptrace-pkey: ../harness.c ../utils.c ../lib/reg.S ptrace.h child.h ptrace-pkey.c
$(LINK.c) $^ $(LDLIBS) -pthread -o $@
+core-pkey: ../harness.c ../utils.c ../lib/reg.S ptrace.h child.h core-pkey.c
+ $(LINK.c) $^ $(LDLIBS) -pthread -o $@
+
$(TEST_PROGS): ../harness.c ../utils.c ../lib/reg.S ptrace.h
clean:
diff --git a/tools/testing/selftests/powerpc/ptrace/core-pkey.c b/tools/testing/selftests/powerpc/ptrace/core-pkey.c
new file mode 100644
index 000000000000..ddbe0f2caf70
--- /dev/null
+++ b/tools/testing/selftests/powerpc/ptrace/core-pkey.c
@@ -0,0 +1,460 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Ptrace test for Memory Protection Key registers
+ *
+ * Copyright (C) 2015 Anshuman Khandual, IBM Corporation.
+ * Copyright (C) 2018 IBM Corporation.
+ */
+#include <limits.h>
+#include <linux/kernel.h>
+#include <sys/mman.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include "ptrace.h"
+#include "child.h"
+
+#ifndef __NR_pkey_alloc
+#define __NR_pkey_alloc 384
+#endif
+
+#ifndef __NR_pkey_free
+#define __NR_pkey_free 385
+#endif
+
+#ifndef NT_PPC_PKEY
+#define NT_PPC_PKEY 0x110
+#endif
+
+#ifndef PKEY_DISABLE_EXECUTE
+#define PKEY_DISABLE_EXECUTE 0x4
+#endif
+
+#define AMR_BITS_PER_PKEY 2
+#define PKEY_REG_BITS (sizeof(u64) * 8)
+#define pkeyshift(pkey) (PKEY_REG_BITS - ((pkey + 1) * AMR_BITS_PER_PKEY))
+
+#define CORE_FILE_LIMIT (5 * 1024 * 1024) /* 5 MB should be enough */
+
+static const char core_pattern_file[] = "/proc/sys/kernel/core_pattern";
+
+static const char user_write[] = "[User Write (Running)]";
+static const char core_read_running[] = "[Core Read (Running)]";
+
+/* Information shared between the parent and the child. */
+struct shared_info {
+ struct child_sync child_sync;
+
+ /* AMR value the parent expects to read in the core file. */
+ unsigned long amr;
+
+ /* IAMR value the parent expects to read in the core file. */
+ unsigned long iamr;
+
+ /* UAMOR value the parent expects to read in the core file. */
+ unsigned long uamor;
+
+ /* When the child crashed. */
+ time_t core_time;
+};
+
+static int sys_pkey_alloc(unsigned long flags, unsigned long init_access_rights)
+{
+ return syscall(__NR_pkey_alloc, flags, init_access_rights);
+}
+
+static int sys_pkey_free(int pkey)
+{
+ return syscall(__NR_pkey_free, pkey);
+}
+
+static int increase_core_file_limit(void)
+{
+ struct rlimit rlim;
+ int ret;
+
+ ret = getrlimit(RLIMIT_CORE, &rlim);
+ FAIL_IF(ret);
+
+ if (rlim.rlim_cur != RLIM_INFINITY && rlim.rlim_cur < CORE_FILE_LIMIT) {
+ rlim.rlim_cur = CORE_FILE_LIMIT;
+
+ if (rlim.rlim_max != RLIM_INFINITY &&
+ rlim.rlim_max < CORE_FILE_LIMIT)
+ rlim.rlim_max = CORE_FILE_LIMIT;
+
+ ret = setrlimit(RLIMIT_CORE, &rlim);
+ FAIL_IF(ret);
+ }
+
+ ret = getrlimit(RLIMIT_FSIZE, &rlim);
+ FAIL_IF(ret);
+
+ if (rlim.rlim_cur != RLIM_INFINITY && rlim.rlim_cur < CORE_FILE_LIMIT) {
+ rlim.rlim_cur = CORE_FILE_LIMIT;
+
+ if (rlim.rlim_max != RLIM_INFINITY &&
+ rlim.rlim_max < CORE_FILE_LIMIT)
+ rlim.rlim_max = CORE_FILE_LIMIT;
+
+ ret = setrlimit(RLIMIT_FSIZE, &rlim);
+ FAIL_IF(ret);
+ }
+
+ return TEST_PASS;
+}
+
+static int child(struct shared_info *info)
+{
+ bool disable_execute = true;
+ int pkey1, pkey2, pkey3;
+ int *ptr, ret;
+
+ /* Wait until parent fills out the initial register values. */
+ ret = wait_parent(&info->child_sync);
+ if (ret)
+ return ret;
+
+ ret = increase_core_file_limit();
+ FAIL_IF(ret);
+
+ /* Get some pkeys so that we can change their bits in the AMR. */
+ pkey1 = sys_pkey_alloc(0, PKEY_DISABLE_EXECUTE);
+ if (pkey1 < 0) {
+ pkey1 = sys_pkey_alloc(0, 0);
+ FAIL_IF(pkey1 < 0);
+
+ disable_execute = false;
+ }
+
+ pkey2 = sys_pkey_alloc(0, 0);
+ FAIL_IF(pkey2 < 0);
+
+ pkey3 = sys_pkey_alloc(0, 0);
+ FAIL_IF(pkey3 < 0);
+
+ info->amr |= 3ul << pkeyshift(pkey1) | 2ul << pkeyshift(pkey2);
+
+ if (disable_execute)
+ info->iamr |= 1ul << pkeyshift(pkey1);
+
+ info->uamor |= 3ul << pkeyshift(pkey1) | 3ul << pkeyshift(pkey2);
+
+ printf("%-30s AMR: %016lx pkey1: %d pkey2: %d pkey3: %d\n",
+ user_write, info->amr, pkey1, pkey2, pkey3);
+
+ mtspr(SPRN_AMR, info->amr);
+
+ /*
+ * We won't use pkey3. This tests whether the kernel restores the UAMOR
+ * permissions after a key is freed.
+ */
+ sys_pkey_free(pkey3);
+
+ info->core_time = time(NULL);
+
+ /* Crash. */
+ ptr = 0;
+ *ptr = 1;
+
+ /* Shouldn't get here. */
+ FAIL_IF(true);
+
+ return TEST_FAIL;
+}
+
+/* Return file size if filename exists and pass sanity check, or zero if not. */
+static off_t try_core_file(const char *filename, struct shared_info *info,
+ pid_t pid)
+{
+ struct stat buf;
+ int ret;
+
+ ret = stat(filename, &buf);
+ if (ret == -1)
+ return TEST_FAIL;
+
+ /* Make sure we're not using a stale core file. */
+ return buf.st_mtime >= info->core_time ? buf.st_size : TEST_FAIL;
+}
+
+static Elf64_Nhdr *next_note(Elf64_Nhdr *nhdr)
+{
+ return (void *) nhdr + sizeof(*nhdr) +
+ __ALIGN_KERNEL(nhdr->n_namesz, 4) +
+ __ALIGN_KERNEL(nhdr->n_descsz, 4);
+}
+
+static int check_core_file(struct shared_info *info, Elf64_Ehdr *ehdr,
+ off_t core_size)
+{
+ unsigned long *regs;
+ Elf64_Phdr *phdr;
+ Elf64_Nhdr *nhdr;
+ size_t phdr_size;
+ void *p = ehdr, *note;
+ int ret;
+
+ ret = memcmp(ehdr->e_ident, ELFMAG, SELFMAG);
+ FAIL_IF(ret);
+
+ FAIL_IF(ehdr->e_type != ET_CORE);
+ FAIL_IF(ehdr->e_machine != EM_PPC64);
+ FAIL_IF(ehdr->e_phoff == 0 || ehdr->e_phnum == 0);
+
+ /*
+ * e_phnum is at most 65535 so calculating the size of the
+ * program header cannot overflow.
+ */
+ phdr_size = sizeof(*phdr) * ehdr->e_phnum;
+
+ /* Sanity check the program header table location. */
+ FAIL_IF(ehdr->e_phoff + phdr_size < ehdr->e_phoff);
+ FAIL_IF(ehdr->e_phoff + phdr_size > core_size);
+
+ /* Find the PT_NOTE segment. */
+ for (phdr = p + ehdr->e_phoff;
+ (void *) phdr < p + ehdr->e_phoff + phdr_size;
+ phdr += ehdr->e_phentsize)
+ if (phdr->p_type == PT_NOTE)
+ break;
+
+ FAIL_IF((void *) phdr >= p + ehdr->e_phoff + phdr_size);
+
+ /* Find the NT_PPC_PKEY note. */
+ for (nhdr = p + phdr->p_offset;
+ (void *) nhdr < p + phdr->p_offset + phdr->p_filesz;
+ nhdr = next_note(nhdr))
+ if (nhdr->n_type == NT_PPC_PKEY)
+ break;
+
+ FAIL_IF((void *) nhdr >= p + phdr->p_offset + phdr->p_filesz);
+ FAIL_IF(nhdr->n_descsz == 0);
+
+ p = nhdr;
+ note = p + sizeof(*nhdr) + __ALIGN_KERNEL(nhdr->n_namesz, 4);
+
+ regs = (unsigned long *) note;
+
+ printf("%-30s AMR: %016lx IAMR: %016lx UAMOR: %016lx\n",
+ core_read_running, regs[0], regs[1], regs[2]);
+
+ FAIL_IF(regs[0] != info->amr);
+ FAIL_IF(regs[1] != info->iamr);
+ FAIL_IF(regs[2] != info->uamor);
+
+ return TEST_PASS;
+}
+
+static int parent(struct shared_info *info, pid_t pid)
+{
+ char *filenames, *filename[3];
+ int fd, i, ret, status;
+ unsigned long regs[3];
+ off_t core_size;
+ void *core;
+
+ /*
+ * Get the initial values for AMR, IAMR and UAMOR and communicate them
+ * to the child.
+ */
+ ret = ptrace_read_regs(pid, NT_PPC_PKEY, regs, 3);
+ PARENT_FAIL_IF(ret, &info->child_sync);
+
+ info->amr = regs[0];
+ info->iamr = regs[1];
+ info->uamor = regs[2];
+
+ /* Wake up child so that it can set itself up. */
+ ret = prod_child(&info->child_sync);
+ PARENT_FAIL_IF(ret, &info->child_sync);
+
+ ret = wait(&status);
+ if (ret != pid) {
+ printf("Child's exit status not captured\n");
+ return TEST_FAIL;
+ } else if (!WIFSIGNALED(status) || !WCOREDUMP(status)) {
+ printf("Child didn't dump core\n");
+ return TEST_FAIL;
+ }
+
+ /* Construct array of core file names to try. */
+
+ filename[0] = filenames = malloc(PATH_MAX);
+ if (!filenames) {
+ perror("Error allocating memory");
+ return TEST_FAIL;
+ }
+
+ ret = snprintf(filename[0], PATH_MAX, "core-pkey.%d", pid);
+ if (ret < 0 || ret >= PATH_MAX) {
+ ret = TEST_FAIL;
+ goto out;
+ }
+
+ filename[1] = filename[0] + ret + 1;
+ ret = snprintf(filename[1], PATH_MAX - ret - 1, "core.%d", pid);
+ if (ret < 0 || ret >= PATH_MAX - ret - 1) {
+ ret = TEST_FAIL;
+ goto out;
+ }
+ filename[2] = "core";
+
+ for (i = 0; i < 3; i++) {
+ core_size = try_core_file(filename[i], info, pid);
+ if (core_size != TEST_FAIL)
+ break;
+ }
+
+ if (i == 3) {
+ printf("Couldn't find core file\n");
+ ret = TEST_FAIL;
+ goto out;
+ }
+
+ fd = open(filename[i], O_RDONLY);
+ if (fd == -1) {
+ perror("Error opening core file");
+ ret = TEST_FAIL;
+ goto out;
+ }
+
+ core = mmap(NULL, core_size, PROT_READ, MAP_PRIVATE, fd, 0);
+ if (core == (void *) -1) {
+ perror("Error mmaping core file");
+ ret = TEST_FAIL;
+ goto out;
+ }
+
+ ret = check_core_file(info, core, core_size);
+
+ munmap(core, core_size);
+ close(fd);
+ unlink(filename[i]);
+
+ out:
+ free(filenames);
+
+ return ret;
+}
+
+static int write_core_pattern(const char *core_pattern)
+{
+ size_t len = strlen(core_pattern), ret;
+ FILE *f;
+
+ f = fopen(core_pattern_file, "w");
+ if (!f) {
+ perror("Error writing to core_pattern file");
+ return TEST_FAIL;
+ }
+
+ ret = fwrite(core_pattern, 1, len, f);
+ fclose(f);
+ if (ret != len) {
+ perror("Error writing to core_pattern file");
+ return TEST_FAIL;
+ }
+
+ return TEST_PASS;
+}
+
+static int setup_core_pattern(char **core_pattern_, bool *changed_)
+{
+ FILE *f;
+ char *core_pattern;
+ int ret;
+
+ core_pattern = malloc(PATH_MAX);
+ if (!core_pattern) {
+ perror("Error allocating memory");
+ return TEST_FAIL;
+ }
+
+ f = fopen(core_pattern_file, "r");
+ if (!f) {
+ perror("Error opening core_pattern file");
+ ret = TEST_FAIL;
+ goto out;
+ }
+
+ ret = fread(core_pattern, 1, PATH_MAX, f);
+ fclose(f);
+ if (!ret) {
+ perror("Error reading core_pattern file");
+ ret = TEST_FAIL;
+ goto out;
+ }
+
+ /* Check whether we can predict the name of the core file. */
+ if (!strcmp(core_pattern, "core") || !strcmp(core_pattern, "core.%p"))
+ *changed_ = false;
+ else {
+ ret = write_core_pattern("core-pkey.%p");
+ if (ret)
+ goto out;
+
+ *changed_ = true;
+ }
+
+ *core_pattern_ = core_pattern;
+ ret = TEST_PASS;
+
+ out:
+ if (ret)
+ free(core_pattern);
+
+ return ret;
+}
+
+static int core_pkey(void)
+{
+ char *core_pattern;
+ bool changed_core_pattern;
+ struct shared_info *info;
+ int shm_id;
+ int ret;
+ pid_t pid;
+
+ ret = setup_core_pattern(&core_pattern, &changed_core_pattern);
+ if (ret)
+ return ret;
+
+ shm_id = shmget(IPC_PRIVATE, sizeof(*info), 0777 | IPC_CREAT);
+ info = shmat(shm_id, NULL, 0);
+
+ ret = init_child_sync(&info->child_sync);
+ if (ret)
+ return ret;
+
+ pid = fork();
+ if (pid < 0) {
+ perror("fork() failed");
+ ret = TEST_FAIL;
+ } else if (pid == 0)
+ ret = child(info);
+ else
+ ret = parent(info, pid);
+
+ shmdt(info);
+
+ if (pid) {
+ destroy_child_sync(&info->child_sync);
+ shmctl(shm_id, IPC_RMID, NULL);
+
+ if (changed_core_pattern)
+ write_core_pattern(core_pattern);
+ }
+
+ free(core_pattern);
+
+ return ret;
+}
+
+int main(int argc, char *argv[])
+{
+ return test_harness(core_pkey, "core_pkey");
+}
^ permalink raw reply related
* [PATCH 1/2] selftests/powerpc: Add ptrace tests for Protection Key registers
From: Thiago Jung Bauermann @ 2018-02-23 18:33 UTC (permalink / raw)
To: linuxppc-dev
Cc: linux-kselftest, linux-kernel, Michael Ellerman, Ram Pai,
Thiago Jung Bauermann
This test exercises read and write access to the AMR, IAMR and UAMOR.
Signed-off-by: Thiago Jung Bauermann <bauerman@linux.vnet.ibm.com>
---
tools/testing/selftests/powerpc/include/reg.h | 1 +
tools/testing/selftests/powerpc/ptrace/Makefile | 5 +-
tools/testing/selftests/powerpc/ptrace/child.h | 130 ++++++++
.../testing/selftests/powerpc/ptrace/ptrace-pkey.c | 326 +++++++++++++++++++++
tools/testing/selftests/powerpc/ptrace/ptrace.h | 37 +++
5 files changed, 498 insertions(+), 1 deletion(-)
create mode 100644 tools/testing/selftests/powerpc/ptrace/child.h
create mode 100644 tools/testing/selftests/powerpc/ptrace/ptrace-pkey.c
diff --git a/tools/testing/selftests/powerpc/include/reg.h b/tools/testing/selftests/powerpc/include/reg.h
index 4afdebcce4cd..7f348c059bc2 100644
--- a/tools/testing/selftests/powerpc/include/reg.h
+++ b/tools/testing/selftests/powerpc/include/reg.h
@@ -54,6 +54,7 @@
#define SPRN_DSCR_PRIV 0x11 /* Privilege State DSCR */
#define SPRN_DSCR 0x03 /* Data Stream Control Register */
#define SPRN_PPR 896 /* Program Priority Register */
+#define SPRN_AMR 13 /* Authority Mask Register - problem state */
/* TEXASR register bits */
#define TEXASR_FC 0xFE00000000000000
diff --git a/tools/testing/selftests/powerpc/ptrace/Makefile b/tools/testing/selftests/powerpc/ptrace/Makefile
index 480305266504..707ba734faf2 100644
--- a/tools/testing/selftests/powerpc/ptrace/Makefile
+++ b/tools/testing/selftests/powerpc/ptrace/Makefile
@@ -1,7 +1,7 @@
# SPDX-License-Identifier: GPL-2.0
TEST_PROGS := ptrace-gpr ptrace-tm-gpr ptrace-tm-spd-gpr \
ptrace-tar ptrace-tm-tar ptrace-tm-spd-tar ptrace-vsx ptrace-tm-vsx \
- ptrace-tm-spd-vsx ptrace-tm-spr
+ ptrace-tm-spd-vsx ptrace-tm-spr ptrace-pkey
include ../../lib.mk
@@ -9,6 +9,9 @@ all: $(TEST_PROGS)
CFLAGS += -m64 -I../../../../../usr/include -I../tm -mhtm -fno-pie
+ptrace-pkey: ../harness.c ../utils.c ../lib/reg.S ptrace.h child.h ptrace-pkey.c
+ $(LINK.c) $^ $(LDLIBS) -pthread -o $@
+
$(TEST_PROGS): ../harness.c ../utils.c ../lib/reg.S ptrace.h
clean:
diff --git a/tools/testing/selftests/powerpc/ptrace/child.h b/tools/testing/selftests/powerpc/ptrace/child.h
new file mode 100644
index 000000000000..40c1a6d92111
--- /dev/null
+++ b/tools/testing/selftests/powerpc/ptrace/child.h
@@ -0,0 +1,130 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Helper functions to sync execution between parent and child processes.
+ *
+ * Copyright 2018, Thiago Jung Bauermann, IBM Corporation.
+ */
+#include <stdio.h>
+#include <stdbool.h>
+#include <semaphore.h>
+
+/*
+ * Information in a shared memory location for synchronization between child and
+ * parent.
+ */
+struct child_sync {
+ /* The parent waits on this semaphore. */
+ sem_t sem_parent;
+
+ /* If true, the child should give up as well. */
+ bool parent_gave_up;
+
+ /* The child waits on this semaphore. */
+ sem_t sem_child;
+
+ /* If true, the parent should give up as well. */
+ bool child_gave_up;
+};
+
+#define CHILD_FAIL_IF(x, sync) \
+ do { \
+ if (x) { \
+ fprintf(stderr, \
+ "[FAIL] Test FAILED on line %d\n", __LINE__); \
+ (sync)->child_gave_up = true; \
+ prod_parent(sync); \
+ return 1; \
+ } \
+ } while (0)
+
+#define PARENT_FAIL_IF(x, sync) \
+ do { \
+ if (x) { \
+ fprintf(stderr, \
+ "[FAIL] Test FAILED on line %d\n", __LINE__); \
+ (sync)->parent_gave_up = true; \
+ prod_child(sync); \
+ return 1; \
+ } \
+ } while (0)
+
+int init_child_sync(struct child_sync *sync)
+{
+ int ret;
+
+ ret = sem_init(&sync->sem_parent, 1, 0);
+ if (ret) {
+ perror("Semaphore initialization failed");
+ return 1;
+ }
+
+ ret = sem_init(&sync->sem_child, 1, 0);
+ if (ret) {
+ perror("Semaphore initialization failed");
+ return 1;
+ }
+
+ return 0;
+}
+
+void destroy_child_sync(struct child_sync *sync)
+{
+ sem_destroy(&sync->sem_parent);
+ sem_destroy(&sync->sem_child);
+}
+
+int wait_child(struct child_sync *sync)
+{
+ int ret;
+
+ /* Wait until the child prods us. */
+ ret = sem_wait(&sync->sem_parent);
+ if (ret) {
+ perror("Error waiting for child");
+ return 1;
+ }
+
+ return sync->child_gave_up;
+}
+
+int prod_child(struct child_sync *sync)
+{
+ int ret;
+
+ /* Unblock the child now. */
+ ret = sem_post(&sync->sem_child);
+ if (ret) {
+ perror("Error prodding child");
+ return 1;
+ }
+
+ return 0;
+}
+
+int wait_parent(struct child_sync *sync)
+{
+ int ret;
+
+ /* Wait until the parent prods us. */
+ ret = sem_wait(&sync->sem_child);
+ if (ret) {
+ perror("Error waiting for parent");
+ return 1;
+ }
+
+ return sync->parent_gave_up;
+}
+
+int prod_parent(struct child_sync *sync)
+{
+ int ret;
+
+ /* Unblock the parent now. */
+ ret = sem_post(&sync->sem_parent);
+ if (ret) {
+ perror("Error prodding parent");
+ return 1;
+ }
+
+ return 0;
+}
diff --git a/tools/testing/selftests/powerpc/ptrace/ptrace-pkey.c b/tools/testing/selftests/powerpc/ptrace/ptrace-pkey.c
new file mode 100644
index 000000000000..8332b9338d39
--- /dev/null
+++ b/tools/testing/selftests/powerpc/ptrace/ptrace-pkey.c
@@ -0,0 +1,326 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Ptrace test for Memory Protection Key registers
+ *
+ * Copyright (C) 2015 Anshuman Khandual, IBM Corporation.
+ * Copyright (C) 2018 IBM Corporation.
+ */
+#include "ptrace.h"
+#include "child.h"
+
+#ifndef __NR_pkey_alloc
+#define __NR_pkey_alloc 384
+#endif
+
+#ifndef __NR_pkey_free
+#define __NR_pkey_free 385
+#endif
+
+#ifndef NT_PPC_PKEY
+#define NT_PPC_PKEY 0x110
+#endif
+
+#ifndef PKEY_DISABLE_EXECUTE
+#define PKEY_DISABLE_EXECUTE 0x4
+#endif
+
+#define AMR_BITS_PER_PKEY 2
+#define PKEY_REG_BITS (sizeof(u64) * 8)
+#define pkeyshift(pkey) (PKEY_REG_BITS - ((pkey + 1) * AMR_BITS_PER_PKEY))
+
+static const char user_read[] = "[User Read (Running)]";
+static const char user_write[] = "[User Write (Running)]";
+static const char ptrace_read_running[] = "[Ptrace Read (Running)]";
+static const char ptrace_write_running[] = "[Ptrace Write (Running)]";
+
+/* Information shared between the parent and the child. */
+struct shared_info {
+ struct child_sync child_sync;
+
+ /* AMR value the parent expects to read from the child. */
+ unsigned long amr1;
+
+ /* AMR value the parent is expected to write to the child. */
+ unsigned long amr2;
+
+ /* AMR value that ptrace should refuse to write to the child. */
+ unsigned long amr3;
+
+ /* IAMR value the parent expects to read from the child. */
+ unsigned long expected_iamr;
+
+ /* UAMOR value the parent expects to read from the child. */
+ unsigned long expected_uamor;
+
+ /*
+ * IAMR and UAMOR values that ptrace should refuse to write to the child
+ * (even though they're valid ones) because userspace doesn't have
+ * access to those registers.
+ */
+ unsigned long new_iamr;
+ unsigned long new_uamor;
+};
+
+static int sys_pkey_alloc(unsigned long flags, unsigned long init_access_rights)
+{
+ return syscall(__NR_pkey_alloc, flags, init_access_rights);
+}
+
+static int sys_pkey_free(int pkey)
+{
+ return syscall(__NR_pkey_free, pkey);
+}
+
+static int child(struct shared_info *info)
+{
+ unsigned long reg;
+ bool disable_execute = true;
+ int pkey1, pkey2, pkey3;
+ int ret;
+
+ /* Wait until parent fills out the initial register values. */
+ ret = wait_parent(&info->child_sync);
+ if (ret)
+ return ret;
+
+ /* Get some pkeys so that we can change their bits in the AMR. */
+ pkey1 = sys_pkey_alloc(0, PKEY_DISABLE_EXECUTE);
+ if (pkey1 < 0) {
+ pkey1 = sys_pkey_alloc(0, 0);
+ CHILD_FAIL_IF(pkey1 < 0, &info->child_sync);
+
+ disable_execute = false;
+ }
+
+ pkey2 = sys_pkey_alloc(0, 0);
+ CHILD_FAIL_IF(pkey2 < 0, &info->child_sync);
+
+ pkey3 = sys_pkey_alloc(0, 0);
+ CHILD_FAIL_IF(pkey3 < 0, &info->child_sync);
+
+ info->amr1 |= 3ul << pkeyshift(pkey1);
+ info->amr2 |= 3ul << pkeyshift(pkey2);
+ info->amr3 |= info->amr2 | 3ul << pkeyshift(pkey3);
+
+ if (disable_execute)
+ info->expected_iamr |= 1ul << pkeyshift(pkey1);
+
+ info->expected_uamor |= 3ul << pkeyshift(pkey1) |
+ 3ul << pkeyshift(pkey2);
+ info->new_iamr |= 1ul << pkeyshift(pkey1) | 1ul << pkeyshift(pkey2);
+ info->new_uamor |= 3ul << pkeyshift(pkey1);
+
+ /*
+ * We won't use pkey3. We just want a plausible but invalid key to test
+ * whether ptrace will let us write to AMR bits we are not supposed to.
+ *
+ * This also tests whether the kernel restores the UAMOR permissions
+ * after a key is freed.
+ */
+ sys_pkey_free(pkey3);
+
+ printf("%-30s AMR: %016lx pkey1: %d pkey2: %d pkey3: %d\n",
+ user_write, info->amr1, pkey1, pkey2, pkey3);
+
+ mtspr(SPRN_AMR, info->amr1);
+
+ /* Wait for parent to read our AMR value and write a new one. */
+ ret = prod_parent(&info->child_sync);
+ CHILD_FAIL_IF(ret, &info->child_sync);
+
+ ret = wait_parent(&info->child_sync);
+ if (ret)
+ return ret;
+
+ reg = mfspr(SPRN_AMR);
+
+ printf("%-30s AMR: %016lx\n", user_read, reg);
+
+ CHILD_FAIL_IF(reg != info->amr2, &info->child_sync);
+
+ /*
+ * Wait for parent to try to write an invalid AMR value.
+ */
+ ret = prod_parent(&info->child_sync);
+ CHILD_FAIL_IF(ret, &info->child_sync);
+
+ ret = wait_parent(&info->child_sync);
+ if (ret)
+ return ret;
+
+ reg = mfspr(SPRN_AMR);
+
+ printf("%-30s AMR: %016lx\n", user_read, reg);
+
+ CHILD_FAIL_IF(reg != info->amr2, &info->child_sync);
+
+ /*
+ * Wait for parent to try to write an IAMR and a UAMOR value. We can't
+ * verify them, but we can verify that the AMR didn't change.
+ */
+ ret = prod_parent(&info->child_sync);
+ CHILD_FAIL_IF(ret, &info->child_sync);
+
+ ret = wait_parent(&info->child_sync);
+ if (ret)
+ return ret;
+
+ reg = mfspr(SPRN_AMR);
+
+ printf("%-30s AMR: %016lx\n", user_read, reg);
+
+ CHILD_FAIL_IF(reg != info->amr2, &info->child_sync);
+
+ /* Now let parent now that we are finished. */
+
+ ret = prod_parent(&info->child_sync);
+ CHILD_FAIL_IF(ret, &info->child_sync);
+
+ return TEST_PASS;
+}
+
+static int parent(struct shared_info *info, pid_t pid)
+{
+ unsigned long regs[3];
+ int ret, status;
+
+ /*
+ * Get the initial values for AMR, IAMR and UAMOR and communicate them
+ * to the child.
+ */
+ ret = ptrace_read_regs(pid, NT_PPC_PKEY, regs, 3);
+ PARENT_FAIL_IF(ret, &info->child_sync);
+
+ info->amr1 = info->amr2 = info->amr3 = regs[0];
+ info->expected_iamr = info->new_iamr = regs[1];
+ info->expected_uamor = info->new_uamor = regs[2];
+
+ /* Wake up child so that it can set itself up. */
+ ret = prod_child(&info->child_sync);
+ PARENT_FAIL_IF(ret, &info->child_sync);
+
+ ret = wait_child(&info->child_sync);
+ if (ret)
+ return ret;
+
+ /* Verify that we can read the pkey registers from the child. */
+ ret = ptrace_read_regs(pid, NT_PPC_PKEY, regs, 3);
+ PARENT_FAIL_IF(ret, &info->child_sync);
+
+ printf("%-30s AMR: %016lx IAMR: %016lx UAMOR: %016lx\n",
+ ptrace_read_running, regs[0], regs[1], regs[2]);
+
+ PARENT_FAIL_IF(regs[0] != info->amr1, &info->child_sync);
+ PARENT_FAIL_IF(regs[1] != info->expected_iamr, &info->child_sync);
+ PARENT_FAIL_IF(regs[2] != info->expected_uamor, &info->child_sync);
+
+ /* Write valid AMR value in child. */
+ ret = ptrace_write_regs(pid, NT_PPC_PKEY, &info->amr2, 1);
+ PARENT_FAIL_IF(ret, &info->child_sync);
+
+ printf("%-30s AMR: %016lx\n", ptrace_write_running, info->amr2);
+
+ /* Wake up child so that it can verify it changed. */
+ ret = prod_child(&info->child_sync);
+ PARENT_FAIL_IF(ret, &info->child_sync);
+
+ ret = wait_child(&info->child_sync);
+ if (ret)
+ return ret;
+
+ /* Write invalid AMR value in child. */
+ ret = ptrace_write_regs(pid, NT_PPC_PKEY, &info->amr3, 1);
+ PARENT_FAIL_IF(ret, &info->child_sync);
+
+ printf("%-30s AMR: %016lx\n", ptrace_write_running, info->amr3);
+
+ /* Wake up child so that it can verify it didn't change. */
+ ret = prod_child(&info->child_sync);
+ PARENT_FAIL_IF(ret, &info->child_sync);
+
+ ret = wait_child(&info->child_sync);
+ if (ret)
+ return ret;
+
+ /* Try to write to IAMR. */
+ regs[0] = info->amr1;
+ regs[1] = info->new_iamr;
+ ret = ptrace_write_regs(pid, NT_PPC_PKEY, regs, 2);
+ PARENT_FAIL_IF(!ret, &info->child_sync);
+
+ printf("%-30s AMR: %016lx IAMR: %016lx\n",
+ ptrace_write_running, regs[0], regs[1]);
+
+ /* Try to write to IAMR and UAMOR. */
+ regs[2] = info->new_uamor;
+ ret = ptrace_write_regs(pid, NT_PPC_PKEY, regs, 3);
+ PARENT_FAIL_IF(!ret, &info->child_sync);
+
+ printf("%-30s AMR: %016lx IAMR: %016lx UAMOR: %016lx\n",
+ ptrace_write_running, regs[0], regs[1], regs[2]);
+
+ /* Verify that all registers still have their expected values. */
+ ret = ptrace_read_regs(pid, NT_PPC_PKEY, regs, 3);
+ PARENT_FAIL_IF(ret, &info->child_sync);
+
+ printf("%-30s AMR: %016lx IAMR: %016lx UAMOR: %016lx\n",
+ ptrace_read_running, regs[0], regs[1], regs[2]);
+
+ PARENT_FAIL_IF(regs[0] != info->amr2, &info->child_sync);
+ PARENT_FAIL_IF(regs[1] != info->expected_iamr, &info->child_sync);
+ PARENT_FAIL_IF(regs[2] != info->expected_uamor, &info->child_sync);
+
+ /* Wake up child so that it can verify AMR didn't change and wrap up. */
+ ret = prod_child(&info->child_sync);
+ PARENT_FAIL_IF(ret, &info->child_sync);
+
+ ret = wait(&status);
+ if (ret != pid) {
+ printf("Child's exit status not captured\n");
+ ret = TEST_PASS;
+ } else if (!WIFEXITED(status)) {
+ printf("Child exited abnormally\n");
+ ret = TEST_FAIL;
+ } else
+ ret = WEXITSTATUS(status) ? TEST_FAIL : TEST_PASS;
+
+ return ret;
+}
+
+static int ptrace_pkey(void)
+{
+ struct shared_info *info;
+ int shm_id;
+ int ret;
+ pid_t pid;
+
+ shm_id = shmget(IPC_PRIVATE, sizeof(*info), 0777 | IPC_CREAT);
+ info = shmat(shm_id, NULL, 0);
+
+ ret = init_child_sync(&info->child_sync);
+ if (ret)
+ return ret;
+
+ pid = fork();
+ if (pid < 0) {
+ perror("fork() failed");
+ ret = TEST_FAIL;
+ } else if (pid == 0)
+ ret = child(info);
+ else
+ ret = parent(info, pid);
+
+ shmdt(info);
+
+ if (pid) {
+ destroy_child_sync(&info->child_sync);
+ shmctl(shm_id, IPC_RMID, NULL);
+ }
+
+ return ret;
+}
+
+int main(int argc, char *argv[])
+{
+ return test_harness(ptrace_pkey, "ptrace_pkey");
+}
diff --git a/tools/testing/selftests/powerpc/ptrace/ptrace.h b/tools/testing/selftests/powerpc/ptrace/ptrace.h
index 19fb825270a1..d2c9c4c2b5ee 100644
--- a/tools/testing/selftests/powerpc/ptrace/ptrace.h
+++ b/tools/testing/selftests/powerpc/ptrace/ptrace.h
@@ -102,6 +102,43 @@ int cont_trace(pid_t child)
return TEST_PASS;
}
+int ptrace_read_regs(pid_t child, unsigned long type, unsigned long regs[],
+ int n)
+{
+ struct iovec iov;
+ long ret;
+
+ FAIL_IF(start_trace(child));
+
+ iov.iov_base = regs;
+ iov.iov_len = n * sizeof(unsigned long);
+
+ ret = ptrace(PTRACE_GETREGSET, child, type, &iov);
+ FAIL_IF(ret != 0);
+
+ FAIL_IF(stop_trace(child));
+
+ return TEST_PASS;
+}
+
+long ptrace_write_regs(pid_t child, unsigned long type, unsigned long regs[],
+ int n)
+{
+ struct iovec iov;
+ long ret;
+
+ FAIL_IF(start_trace(child));
+
+ iov.iov_base = regs;
+ iov.iov_len = n * sizeof(unsigned long);
+
+ ret = ptrace(PTRACE_SETREGSET, child, type, &iov);
+
+ FAIL_IF(stop_trace(child));
+
+ return ret;
+}
+
/* TAR, PPR, DSCR */
int show_tar_registers(pid_t child, unsigned long *out)
{
^ permalink raw reply related
* [PATCH 3/3] ftrace: Add MODULE_PLTS support
From: Alexander Sverdlin @ 2018-02-23 16:58 UTC (permalink / raw)
To: Steven Rostedt, Ingo Molnar, linux-arm-kernel, linux-kernel
Cc: Alexander Sverdlin, Russell King, Catalin Marinas, Will Deacon,
Steven Miao, Tony Luck, Fenghua Yu, James Hogan, Michal Simek,
Ralf Baechle, Benjamin Herrenschmidt, Paul Mackerras,
Michael Ellerman, Martin Schwidefsky, Heiko Carstens,
Yoshinori Sato, Rich Felker, David S. Miller, Chris Metcalf,
Thomas Gleixner, H. Peter Anvin, x86, adi-buildroot-devel,
linux-ia64, linux-metag, linux-mips, linuxppc-dev, linux-s390,
linux-sh, sparclinux
In-Reply-To: <20180223165849.16388-1-alexander.sverdlin@nokia.com>
Teach ftrace_make_call() and ftrace_make_nop() about PLTs.
Teach PLT code about FTRACE and all its callbacks.
Otherwise the following might happen:
------------[ cut here ]------------
WARNING: CPU: 14 PID: 2265 at .../arch/arm/kernel/insn.c:14 __arm_gen_branch+0x83/0x8c()
...
Hardware name: LSI Axxia AXM55XX
[<c0314a49>] (unwind_backtrace) from [<c03115e9>] (show_stack+0x11/0x14)
[<c03115e9>] (show_stack) from [<c0519f51>] (dump_stack+0x81/0xa8)
[<c0519f51>] (dump_stack) from [<c032185d>] (warn_slowpath_common+0x69/0x90)
[<c032185d>] (warn_slowpath_common) from [<c03218f3>] (warn_slowpath_null+0x17/0x1c)
[<c03218f3>] (warn_slowpath_null) from [<c03143cf>] (__arm_gen_branch+0x83/0x8c)
[<c03143cf>] (__arm_gen_branch) from [<c0314337>] (ftrace_make_nop+0xf/0x24)
[<c0314337>] (ftrace_make_nop) from [<c038ebcb>] (ftrace_process_locs+0x27b/0x3e8)
[<c038ebcb>] (ftrace_process_locs) from [<c0378d79>] (load_module+0x11e9/0x1a44)
[<c0378d79>] (load_module) from [<c037974d>] (SyS_finit_module+0x59/0x84)
[<c037974d>] (SyS_finit_module) from [<c030e981>] (ret_fast_syscall+0x1/0x18)
---[ end trace e1b64ced7a89adcc ]---
------------[ cut here ]------------
WARNING: CPU: 14 PID: 2265 at .../kernel/trace/ftrace.c:1979 ftrace_bug+0x1b1/0x234()
...
Hardware name: LSI Axxia AXM55XX
[<c0314a49>] (unwind_backtrace) from [<c03115e9>] (show_stack+0x11/0x14)
[<c03115e9>] (show_stack) from [<c0519f51>] (dump_stack+0x81/0xa8)
[<c0519f51>] (dump_stack) from [<c032185d>] (warn_slowpath_common+0x69/0x90)
[<c032185d>] (warn_slowpath_common) from [<c03218f3>] (warn_slowpath_null+0x17/0x1c)
[<c03218f3>] (warn_slowpath_null) from [<c038e87d>] (ftrace_bug+0x1b1/0x234)
[<c038e87d>] (ftrace_bug) from [<c038ebd5>] (ftrace_process_locs+0x285/0x3e8)
[<c038ebd5>] (ftrace_process_locs) from [<c0378d79>] (load_module+0x11e9/0x1a44)
[<c0378d79>] (load_module) from [<c037974d>] (SyS_finit_module+0x59/0x84)
[<c037974d>] (SyS_finit_module) from [<c030e981>] (ret_fast_syscall+0x1/0x18)
---[ end trace e1b64ced7a89adcd ]---
ftrace failed to modify [<e9ef7006>] 0xe9ef7006
actual: 02:f0:3b:fa
ftrace record flags: 0
(0) expected tramp: c0314265
Signed-off-by: Alexander Sverdlin <alexander.sverdlin@nokia.com>
---
arch/arm/include/asm/module.h | 1 +
arch/arm/kernel/ftrace.c | 70 ++++++++++++++++++++++++++++++++++++-------
arch/arm/kernel/module-plts.c | 53 ++++++++++++++++++++++++--------
3 files changed, 101 insertions(+), 23 deletions(-)
diff --git a/arch/arm/include/asm/module.h b/arch/arm/include/asm/module.h
index 6996405..e3d7a51 100644
--- a/arch/arm/include/asm/module.h
+++ b/arch/arm/include/asm/module.h
@@ -30,6 +30,7 @@ struct plt_entries {
struct mod_plt_sec {
struct elf32_shdr *plt;
+ struct plt_entries *plt_ent;
int plt_count;
};
diff --git a/arch/arm/kernel/ftrace.c b/arch/arm/kernel/ftrace.c
index be20adc..0a0da25 100644
--- a/arch/arm/kernel/ftrace.c
+++ b/arch/arm/kernel/ftrace.c
@@ -98,6 +98,19 @@ int ftrace_arch_code_modify_post_process(void)
static unsigned long ftrace_call_replace(unsigned long pc, unsigned long addr)
{
+ s32 offset = addr - pc;
+ s32 blim = 0xfe000008;
+ s32 flim = 0x02000004;
+
+ if (IS_ENABLED(CONFIG_THUMB2_KERNEL)) {
+ blim = 0xff000004;
+ flim = 0x01000002;
+ }
+
+ if (IS_ENABLED(CONFIG_ARM_MODULE_PLTS) &&
+ (offset < blim || offset > flim))
+ return 0;
+
return arm_gen_branch_link(pc, addr);
}
@@ -167,10 +180,27 @@ int ftrace_make_call(struct module *mod, struct dyn_ftrace *rec,
{
unsigned long new, old;
unsigned long ip = rec->ip;
+ unsigned long aaddr = adjust_address(rec, addr);
old = ftrace_nop_replace(rec);
- new = ftrace_call_replace(ip, adjust_address(rec, addr));
+ new = ftrace_call_replace(ip, aaddr);
+
+#ifdef CONFIG_ARM_MODULE_PLTS
+ if (!new) {
+ /*
+ * mod is only supplied during module loading, later we have to
+ * search for it
+ */
+ if (!mod)
+ mod = __module_address(ip);
+
+ if (mod) {
+ aaddr = get_module_plt(mod, ip, aaddr);
+ new = ftrace_call_replace(ip, aaddr);
+ }
+ }
+#endif
return ftrace_modify_code(rec->ip, old, new, true);
}
@@ -200,20 +230,40 @@ int ftrace_make_nop(struct module *mod,
unsigned long new;
int ret;
- old = ftrace_call_replace(ip, adjust_address(rec, addr));
- new = ftrace_nop_replace(rec);
- ret = ftrace_modify_code(ip, old, new, true);
-
-#ifdef CONFIG_OLD_MCOUNT
- if (ret == -EINVAL && addr == MCOUNT_ADDR) {
- rec->arch.old_mcount = true;
+ for (;;) {
+ unsigned long aaddr = adjust_address(rec, addr);
+
+ old = ftrace_call_replace(ip, aaddr);
+
+#ifdef CONFIG_ARM_MODULE_PLTS
+ if (!old) {
+ /*
+ * mod is only supplied during module loading, later we
+ * have to search for it
+ */
+ if (!mod)
+ mod = __module_address(ip);
+
+ if (mod) {
+ aaddr = get_module_plt(mod, ip, aaddr);
+ old = ftrace_call_replace(ip, aaddr);
+ }
+ }
+#endif
- old = ftrace_call_replace(ip, adjust_address(rec, addr));
new = ftrace_nop_replace(rec);
ret = ftrace_modify_code(ip, old, new, true);
- }
+
+#ifdef CONFIG_OLD_MCOUNT
+ if (ret == -EINVAL && !rec->arch.old_mcount) {
+ rec->arch.old_mcount = true;
+ continue;
+ }
#endif
+ break;
+ }
+
return ret;
}
diff --git a/arch/arm/kernel/module-plts.c b/arch/arm/kernel/module-plts.c
index f272711..a216256 100644
--- a/arch/arm/kernel/module-plts.c
+++ b/arch/arm/kernel/module-plts.c
@@ -7,6 +7,7 @@
*/
#include <linux/elf.h>
+#include <linux/ftrace.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/sort.h>
@@ -22,6 +23,15 @@
(PLT_ENT_STRIDE - 8))
#endif
+static u32 fixed_plts[] = {
+ FTRACE_ADDR,
+ MCOUNT_ADDR,
+#ifdef CONFIG_OLD_MCOUNT
+ (unsigned long)ftrace_caller_old,
+ (unsigned long)mcount,
+#endif
+};
+
static bool in_init(const struct module *mod, unsigned long loc)
{
return loc - (u32)mod->init_layout.base < mod->init_layout.size;
@@ -31,26 +41,43 @@ u32 get_module_plt(struct module *mod, unsigned long loc, Elf32_Addr val)
{
struct mod_plt_sec *pltsec = !in_init(mod, loc) ? &mod->arch.core :
&mod->arch.init;
+ int idx;
+ struct plt_entries *plt;
+
+ /* Pre-allocate entries in the first plt */
+ if (!pltsec->plt_count) {
+ plt = (struct plt_entries *)pltsec->plt->sh_addr;
+ for (idx = 0; idx < ARRAY_SIZE(plt->ldr); ++idx)
+ plt->ldr[idx] = PLT_ENT_LDR;
+ memcpy(plt->lit, fixed_plts, sizeof(fixed_plts));
+ pltsec->plt_count = ARRAY_SIZE(fixed_plts);
+ /*
+ * cache the address,
+ * ELF header is available only during module load
+ */
+ pltsec->plt_ent = plt;
+ }
+ plt = pltsec->plt_ent;
- struct plt_entries *plt = (struct plt_entries *)pltsec->plt->sh_addr;
- int idx = 0;
+ idx = ARRAY_SIZE(fixed_plts);
+ while (idx)
+ if (plt->lit[--idx] == val)
+ return (u32)&plt->ldr[idx];
/*
* Look for an existing entry pointing to 'val'. Given that the
* relocations are sorted, this will be the last entry we allocated.
* (if one exists).
*/
- if (pltsec->plt_count > 0) {
- plt += (pltsec->plt_count - 1) / PLT_ENT_COUNT;
- idx = (pltsec->plt_count - 1) % PLT_ENT_COUNT;
+ plt += (pltsec->plt_count - 1) / PLT_ENT_COUNT;
+ idx = (pltsec->plt_count - 1) % PLT_ENT_COUNT;
- if (plt->lit[idx] == val)
- return (u32)&plt->ldr[idx];
+ if (plt->lit[idx] == val)
+ return (u32)&plt->ldr[idx];
- idx = (idx + 1) % PLT_ENT_COUNT;
- if (!idx)
- plt++;
- }
+ idx = (idx + 1) % PLT_ENT_COUNT;
+ if (!idx)
+ plt++;
pltsec->plt_count++;
BUG_ON(pltsec->plt_count * PLT_ENT_SIZE > pltsec->plt->sh_size);
@@ -182,8 +209,8 @@ static unsigned int count_plts(const Elf32_Sym *syms, Elf32_Addr base,
int module_frob_arch_sections(Elf_Ehdr *ehdr, Elf_Shdr *sechdrs,
char *secstrings, struct module *mod)
{
- unsigned long core_plts = 0;
- unsigned long init_plts = 0;
+ unsigned long core_plts = ARRAY_SIZE(fixed_plts);
+ unsigned long init_plts = ARRAY_SIZE(fixed_plts);
Elf32_Shdr *s, *sechdrs_end = sechdrs + ehdr->e_shnum;
Elf32_Sym *syms = NULL;
--
2.4.6
^ permalink raw reply related
* [PATCH 2/3] ARM: PLT: Move struct plt_entries definition to header
From: Alexander Sverdlin @ 2018-02-23 16:58 UTC (permalink / raw)
To: Steven Rostedt, Ingo Molnar, linux-arm-kernel, linux-kernel
Cc: Alexander Sverdlin, Russell King, Catalin Marinas, Will Deacon,
Steven Miao, Tony Luck, Fenghua Yu, James Hogan, Michal Simek,
Ralf Baechle, Benjamin Herrenschmidt, Paul Mackerras,
Michael Ellerman, Martin Schwidefsky, Heiko Carstens,
Yoshinori Sato, Rich Felker, David S. Miller, Chris Metcalf,
Thomas Gleixner, H. Peter Anvin, x86, adi-buildroot-devel,
linux-ia64, linux-metag, linux-mips, linuxppc-dev, linux-s390,
linux-sh, sparclinux
In-Reply-To: <20180223165849.16388-1-alexander.sverdlin@nokia.com>
No functional change, later it will be re-used in several files.
Signed-off-by: Alexander Sverdlin <alexander.sverdlin@nokia.com>
---
arch/arm/include/asm/module.h | 9 +++++++++
arch/arm/kernel/module-plts.c | 9 ---------
2 files changed, 9 insertions(+), 9 deletions(-)
diff --git a/arch/arm/include/asm/module.h b/arch/arm/include/asm/module.h
index 89ad059..6996405 100644
--- a/arch/arm/include/asm/module.h
+++ b/arch/arm/include/asm/module.h
@@ -19,6 +19,15 @@ enum {
};
#endif
+#define PLT_ENT_STRIDE L1_CACHE_BYTES
+#define PLT_ENT_COUNT (PLT_ENT_STRIDE / sizeof(u32))
+#define PLT_ENT_SIZE (sizeof(struct plt_entries) / PLT_ENT_COUNT)
+
+struct plt_entries {
+ u32 ldr[PLT_ENT_COUNT];
+ u32 lit[PLT_ENT_COUNT];
+};
+
struct mod_plt_sec {
struct elf32_shdr *plt;
int plt_count;
diff --git a/arch/arm/kernel/module-plts.c b/arch/arm/kernel/module-plts.c
index 3d0c2e4..f272711 100644
--- a/arch/arm/kernel/module-plts.c
+++ b/arch/arm/kernel/module-plts.c
@@ -14,10 +14,6 @@
#include <asm/cache.h>
#include <asm/opcodes.h>
-#define PLT_ENT_STRIDE L1_CACHE_BYTES
-#define PLT_ENT_COUNT (PLT_ENT_STRIDE / sizeof(u32))
-#define PLT_ENT_SIZE (sizeof(struct plt_entries) / PLT_ENT_COUNT)
-
#ifdef CONFIG_THUMB2_KERNEL
#define PLT_ENT_LDR __opcode_to_mem_thumb32(0xf8dff000 | \
(PLT_ENT_STRIDE - 4))
@@ -26,11 +22,6 @@
(PLT_ENT_STRIDE - 8))
#endif
-struct plt_entries {
- u32 ldr[PLT_ENT_COUNT];
- u32 lit[PLT_ENT_COUNT];
-};
-
static bool in_init(const struct module *mod, unsigned long loc)
{
return loc - (u32)mod->init_layout.base < mod->init_layout.size;
--
2.4.6
^ permalink raw reply related
* [PATCH 1/3] ftrace: Add module to ftrace_make_call() parameters
From: Alexander Sverdlin @ 2018-02-23 16:58 UTC (permalink / raw)
To: Steven Rostedt, Ingo Molnar, linux-arm-kernel, linux-kernel
Cc: Alexander Sverdlin, Russell King, Catalin Marinas, Will Deacon,
Steven Miao, Tony Luck, Fenghua Yu, James Hogan, Michal Simek,
Ralf Baechle, Benjamin Herrenschmidt, Paul Mackerras,
Michael Ellerman, Martin Schwidefsky, Heiko Carstens,
Yoshinori Sato, Rich Felker, David S. Miller, Chris Metcalf,
Thomas Gleixner, H. Peter Anvin, x86, adi-buildroot-devel,
linux-ia64, linux-metag, linux-mips, linuxppc-dev, linux-s390,
linux-sh, sparclinux
In-Reply-To: <20180223165849.16388-1-alexander.sverdlin@nokia.com>
ARM support for modules' PLTs will require a module pointer in
ftrace_make_call() exactly as ftrace_make_nop() has it. Change the function
signature without functional change for now.
Signed-off-by: Alexander Sverdlin <alexander.sverdlin@nokia.com>
---
arch/arm/kernel/ftrace.c | 3 ++-
arch/arm64/kernel/ftrace.c | 3 ++-
arch/blackfin/kernel/ftrace.c | 3 ++-
arch/ia64/kernel/ftrace.c | 3 ++-
arch/metag/kernel/ftrace.c | 3 ++-
arch/microblaze/kernel/ftrace.c | 3 ++-
arch/mips/kernel/ftrace.c | 3 ++-
arch/powerpc/kernel/trace/ftrace.c | 3 ++-
arch/s390/kernel/ftrace.c | 3 ++-
arch/sh/kernel/ftrace.c | 3 ++-
arch/sparc/kernel/ftrace.c | 3 ++-
arch/tile/kernel/ftrace.c | 3 ++-
arch/x86/kernel/ftrace.c | 3 ++-
include/linux/ftrace.h | 4 +++-
kernel/trace/ftrace.c | 6 +++---
15 files changed, 32 insertions(+), 17 deletions(-)
diff --git a/arch/arm/kernel/ftrace.c b/arch/arm/kernel/ftrace.c
index 5617932..be20adc 100644
--- a/arch/arm/kernel/ftrace.c
+++ b/arch/arm/kernel/ftrace.c
@@ -162,7 +162,8 @@ int ftrace_update_ftrace_func(ftrace_func_t func)
return ret;
}
-int ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr)
+int ftrace_make_call(struct module *mod, struct dyn_ftrace *rec,
+ unsigned long addr)
{
unsigned long new, old;
unsigned long ip = rec->ip;
diff --git a/arch/arm64/kernel/ftrace.c b/arch/arm64/kernel/ftrace.c
index 50986e3..e3a95d3 100644
--- a/arch/arm64/kernel/ftrace.c
+++ b/arch/arm64/kernel/ftrace.c
@@ -68,7 +68,8 @@ int ftrace_update_ftrace_func(ftrace_func_t func)
/*
* Turn on the call to ftrace_caller() in instrumented function
*/
-int ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr)
+int ftrace_make_call(struct module *mod, struct dyn_ftrace *rec,
+ unsigned long addr)
{
unsigned long pc = rec->ip;
u32 old, new;
diff --git a/arch/blackfin/kernel/ftrace.c b/arch/blackfin/kernel/ftrace.c
index 8dad758..61ffc99 100644
--- a/arch/blackfin/kernel/ftrace.c
+++ b/arch/blackfin/kernel/ftrace.c
@@ -45,7 +45,8 @@ int ftrace_make_nop(struct module *mod, struct dyn_ftrace *rec,
return ftrace_modify_code(rec->ip, mnop, sizeof(mnop));
}
-int ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr)
+int ftrace_make_call(struct module *mod, struct dyn_ftrace *rec,
+ unsigned long addr)
{
/* Restore the mcount call site */
unsigned char call[8];
diff --git a/arch/ia64/kernel/ftrace.c b/arch/ia64/kernel/ftrace.c
index cee411e..658a011 100644
--- a/arch/ia64/kernel/ftrace.c
+++ b/arch/ia64/kernel/ftrace.c
@@ -169,7 +169,8 @@ int ftrace_make_nop(struct module *mod,
return ftrace_modify_code(rec->ip, NULL, new, 0);
}
-int ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr)
+int ftrace_make_call(struct module *mod, struct dyn_ftrace *rec,
+ unsigned long addr)
{
unsigned long ip = rec->ip;
unsigned char *old, *new;
diff --git a/arch/metag/kernel/ftrace.c b/arch/metag/kernel/ftrace.c
index f7b23d3..635652a 100644
--- a/arch/metag/kernel/ftrace.c
+++ b/arch/metag/kernel/ftrace.c
@@ -104,7 +104,8 @@ int ftrace_make_nop(struct module *mod,
return ftrace_modify_code(ip, old, new);
}
-int ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr)
+int ftrace_make_call(struct module *mod, struct dyn_ftrace *rec,
+ unsigned long addr)
{
unsigned char *new, *old;
unsigned long ip = rec->ip;
diff --git a/arch/microblaze/kernel/ftrace.c b/arch/microblaze/kernel/ftrace.c
index d57563c..01b314a 100644
--- a/arch/microblaze/kernel/ftrace.c
+++ b/arch/microblaze/kernel/ftrace.c
@@ -161,7 +161,8 @@ int ftrace_make_nop(struct module *mod,
}
/* I believe that first is called ftrace_make_nop before this function */
-int ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr)
+int ftrace_make_call(struct module *mod, struct dyn_ftrace *rec,
+ unsigned long addr)
{
int ret;
pr_debug("%s: addr:0x%x, rec->ip: 0x%x, imm:0x%x\n",
diff --git a/arch/mips/kernel/ftrace.c b/arch/mips/kernel/ftrace.c
index 7f3dfdb..9dcec19 100644
--- a/arch/mips/kernel/ftrace.c
+++ b/arch/mips/kernel/ftrace.c
@@ -200,7 +200,8 @@ int ftrace_make_nop(struct module *mod,
#endif
}
-int ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr)
+int ftrace_make_call(struct module *mod, struct dyn_ftrace *rec,
+ unsigned long addr)
{
unsigned int new;
unsigned long ip = rec->ip;
diff --git a/arch/powerpc/kernel/trace/ftrace.c b/arch/powerpc/kernel/trace/ftrace.c
index 4741fe1..b198433 100644
--- a/arch/powerpc/kernel/trace/ftrace.c
+++ b/arch/powerpc/kernel/trace/ftrace.c
@@ -437,7 +437,8 @@ __ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr)
#endif /* CONFIG_PPC64 */
#endif /* CONFIG_MODULES */
-int ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr)
+int ftrace_make_call(struct module *mod, struct dyn_ftrace *rec,
+ unsigned long addr)
{
unsigned long ip = rec->ip;
unsigned int old, new;
diff --git a/arch/s390/kernel/ftrace.c b/arch/s390/kernel/ftrace.c
index dc76d81..1691d53 100644
--- a/arch/s390/kernel/ftrace.c
+++ b/arch/s390/kernel/ftrace.c
@@ -136,7 +136,8 @@ int ftrace_make_nop(struct module *mod, struct dyn_ftrace *rec,
return 0;
}
-int ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr)
+int ftrace_make_call(struct module *mod, struct dyn_ftrace *rec,
+ unsigned long addr)
{
struct ftrace_insn orig, new, old;
diff --git a/arch/sh/kernel/ftrace.c b/arch/sh/kernel/ftrace.c
index 96dd9f7..2d3cacd 100644
--- a/arch/sh/kernel/ftrace.c
+++ b/arch/sh/kernel/ftrace.c
@@ -242,7 +242,8 @@ int ftrace_make_nop(struct module *mod,
return ftrace_modify_code(rec->ip, old, new);
}
-int ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr)
+int ftrace_make_call(struct module *mod, struct dyn_ftrace *rec,
+ unsigned long addr)
{
unsigned char *new, *old;
unsigned long ip = rec->ip;
diff --git a/arch/sparc/kernel/ftrace.c b/arch/sparc/kernel/ftrace.c
index 915dda4..36117b5 100644
--- a/arch/sparc/kernel/ftrace.c
+++ b/arch/sparc/kernel/ftrace.c
@@ -63,7 +63,8 @@ int ftrace_make_nop(struct module *mod, struct dyn_ftrace *rec, unsigned long ad
return ftrace_modify_code(ip, old, new);
}
-int ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr)
+int ftrace_make_call(struct module *mod, struct dyn_ftrace *rec,
+ unsigned long addr)
{
unsigned long ip = rec->ip;
u32 old, new;
diff --git a/arch/tile/kernel/ftrace.c b/arch/tile/kernel/ftrace.c
index b827a41..749e50f 100644
--- a/arch/tile/kernel/ftrace.c
+++ b/arch/tile/kernel/ftrace.c
@@ -136,7 +136,8 @@ int ftrace_update_ftrace_func(ftrace_func_t func)
return ret;
}
-int ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr)
+int ftrace_make_call(struct module *mod, struct dyn_ftrace *rec,
+ unsigned long addr)
{
unsigned long new, old;
unsigned long ip = rec->ip;
diff --git a/arch/x86/kernel/ftrace.c b/arch/x86/kernel/ftrace.c
index 01ebcb6..389f15c 100644
--- a/arch/x86/kernel/ftrace.c
+++ b/arch/x86/kernel/ftrace.c
@@ -162,7 +162,8 @@ int ftrace_make_nop(struct module *mod,
return -EINVAL;
}
-int ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr)
+int ftrace_make_call(struct module *mod, struct dyn_ftrace *rec,
+ unsigned long addr)
{
unsigned const char *new, *old;
unsigned long ip = rec->ip;
diff --git a/include/linux/ftrace.h b/include/linux/ftrace.h
index 9c3c9a3..1e8c421 100644
--- a/include/linux/ftrace.h
+++ b/include/linux/ftrace.h
@@ -536,6 +536,7 @@ extern int ftrace_make_nop(struct module *mod,
/**
* ftrace_make_call - convert a nop call site into a call to addr
+ * @mod: module structure if called by module load initialization
* @rec: the mcount call site record
* @addr: the address that the call site should call
*
@@ -554,7 +555,8 @@ extern int ftrace_make_nop(struct module *mod,
* -EPERM on error writing to the location
* Any other value will be considered a failure.
*/
-extern int ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr);
+extern int ftrace_make_call(struct module *mod, struct dyn_ftrace *rec,
+ unsigned long addr);
#ifdef CONFIG_DYNAMIC_FTRACE_WITH_REGS
/**
diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c
index eac9ce2..d32f2f5 100644
--- a/kernel/trace/ftrace.c
+++ b/kernel/trace/ftrace.c
@@ -2421,7 +2421,7 @@ unsigned long ftrace_get_addr_curr(struct dyn_ftrace *rec)
}
static int
-__ftrace_replace_code(struct dyn_ftrace *rec, int enable)
+__ftrace_replace_code(struct module *mod, struct dyn_ftrace *rec, int enable)
{
unsigned long ftrace_old_addr;
unsigned long ftrace_addr;
@@ -2442,7 +2442,7 @@ __ftrace_replace_code(struct dyn_ftrace *rec, int enable)
case FTRACE_UPDATE_MAKE_CALL:
ftrace_bug_type = FTRACE_BUG_CALL;
- return ftrace_make_call(rec, ftrace_addr);
+ return ftrace_make_call(mod, rec, ftrace_addr);
case FTRACE_UPDATE_MAKE_NOP:
ftrace_bug_type = FTRACE_BUG_NOP;
@@ -2470,7 +2470,7 @@ void __weak ftrace_replace_code(int enable)
if (rec->flags & FTRACE_FL_DISABLED)
continue;
- failed = __ftrace_replace_code(rec, enable);
+ failed = __ftrace_replace_code(NULL, rec, enable);
if (failed) {
ftrace_bug(failed, rec);
/* Stop processing */
--
2.4.6
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox